diff --git a/.gitignore b/.gitignore
index 3cfe279..db863ac 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ neo4j/
caddy/
opencode/*
!opencode/opencode.jsonc
+!opencode/run_opencode_docker.py
open-webui/functions/
open-webui/piplines/
open-webui/tools/
diff --git a/README.md b/README.md
index 616aa9e..225561d 100644
--- a/README.md
+++ b/README.md
@@ -1977,6 +1977,9 @@ Use the following settings to confirm or upate n8n Credentials.
To open **n8n**, visit from your browser.
To open **Open WebUI**, visit from your browser.
+To open **OpenCode** run `./opencode/run_opencode_docker.py` from a new terminal.
+
+## Additional Configuration
With n8n, you have access to over 400 integrations and a suite of basic and
advanced AI nodes such as:
@@ -2131,11 +2134,47 @@ as your vector store.
### Open Code
-- **opencode.jsonc**.
+- **run_opencode_docker.py**
+
+ - Copy `./opencode/run_opencode_docker.py` to or run it from your current work
+ project.
+
+- **opencode.jsonc**
- Using the config file at [./opencode/opencode.jsonc](./opencode/opencode.jsonc)
- Set additional configuration settings as desired.
+- **PROJECT_PATH environment variable**
+
+ - Set the `PROJECT_PATH` env variable to your working project directory before
+ running OpenCode if you wish to set the work path to your current project but
+ you will _NOT_ launch OpenCode from the root of your working project.
+ If the `PROJECT_PATH` var is not defined, the currend working directory from
+ which OpenCode was launched is assumed.
+
+- **project_path argument**
+
+ - You can also pass a _project_path_ argument to `./opencode/run_opencode_docker.py`
+ with `-p`, `--project_path` so an example command would be:
+
+ ```powershell
+ python run_opencode_docker.py --project_path 'opencode'
+ ```
+
+> [!NOTE]
+> It is recommended that your working project directory be within and relative to
+> the path set for `PROJECTS_PATH` in the AI-Suite .env file - see
+> **PROJECTS_PATH environment variable** described below.
+>
+> **Important**: The format of the `PROJECT_PATH` entry must be the portion of
+> your project path that is relative to the entry specified in `PROJECTS_PATH`.
+> For example, if the _full path_ to your project is `~/projects/ai-suite/opencode`
+> , your `PROJECT_PATH` entry must be `ai-suite/opencode`, if your `PROJECTS_PATH`
+> entry is `~/projects`.
+>
+> When set, `PROJECT_PATH` is appended to the OpenCode container bind mounted
+> path `/root/projects` and the resulting path is set as _work_dir_ to form the
+> OpenCode Docker exec command's _workdir=work_dir_ keyword argument.
## Upgrading
diff --git a/docker-compose.yml b/docker-compose.yml
index efba2ec..ebec53b 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -190,6 +190,8 @@ services:
- opencode_data:/root/.config/opencode
- ./opencode/opencode.jsonc:/root/.config/opencode/opencode.jsonc
- ${PROJECTS_PATH:-./opencode}:/root/projects
+ environment:
+ - PROJECTS_PATH
flowise:
profiles: ["flowise", "ai-all"]
diff --git a/opencode/run_opencode_docker.py b/opencode/run_opencode_docker.py
new file mode 100644
index 0000000..26ce2bf
--- /dev/null
+++ b/opencode/run_opencode_docker.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python3
+"""
+Trevor SANDY
+
+This script will verify the status of a OpenCode Docker container by it's name
+to determine if the container is running. If the container is running, it will
+attempt to connect and run OpenCode.
+
+Set the PROJECT_PATH env variable to your working project directory before
+running OpenCode if you wish to set the work path to your current project but
+you will NOT launch OpenCode from the root of your working project.
+
+If the PROJECT_PATH var is not defined, the currend working directory from
+which OpenCode was launched is assumed.
+
+You can also pass the project_path entry to ./opencode/run_opencode_docker.py
+as an anargument with -p, --project_path.
+
+See 'PROJECT_PATH environment variable' and 'PROJECTS_PATH environment variable'
+sections in README.md
+
+"""
+
+import os
+import pathlib
+import argparse
+import subprocess
+
+CONTAINER = 'opencode'
+FAIL = -1
+
+def run_command(cmd, cwd=None):
+ """Run a shell command and print it."""
+ print("Running command:", " ".join(cmd))
+ subprocess.run(cmd, cwd=cwd, check=True)
+
+def container_is_running():
+ """:return: True if container name found in output check, else False."""
+ cmd = " ".join(['docker', 'ps', '-a', '--format', '"{{.Names}}"', '--filter',
+ f'name=^/{CONTAINER}$'])
+ print("Running command:", cmd)
+ bytes = subprocess.check_output(cmd, shell=True)
+ running = bytes.find(CONTAINER.encode()) != FAIL
+ insert = ('is', '...') if running else ('is not', '- exiting...')
+ print("Container", " ".join([CONTAINER, insert[0], 'running', insert[1]]))
+ return running
+
+def container_env_var(env_var):
+ """:return: container environment variable."""
+ cmd = " ".join(['docker', 'exec', CONTAINER, 'printenv', env_var])
+ print("Running command:", cmd)
+ try:
+ bytes = subprocess.check_output(cmd, shell=True)
+ print(f"Container env var: {env_var} = {bytes.decode().strip()}")
+ return bytes.decode().strip()
+ except Exception as e:
+ print(f"Container env var: {env_var} not found: {e}")
+ return ""
+
+def container_work_dir(project_path):
+ """:return: current work path converted to container bind mounted child path """
+ if project_path is None:
+ project_path = os.environ.get('PROJECT_PATH')
+ if project_path is None:
+ project_path = os.getcwd()
+ work_path = pathlib.Path('/root', 'projects').as_posix()
+ projects_path = os.path.normcase(container_env_var('PROJECTS_PATH'))
+ if projects_path != "":
+ abs_project_path = os.path.normcase(os.path.abspath(project_path))
+ rel_project_path = os.path.normcase(os.path.relpath(project_path, start=projects_path))
+ if abs_project_path.startswith(projects_path):
+ work_path = pathlib.Path('/root', 'projects', rel_project_path).as_posix()
+ else:
+ print(f"Warning: project path does not start with container projects path...")
+ else:
+ print(f"Warning: container projects path not defined...")
+ print(f"Posix work path: {work_path}")
+ return work_path
+
+def main():
+ print("Launching OpenCode...")
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-p', '--project_path', type=str,
+ help='Current project path which is racommended to be '
+ 'within and relative to PROJECTS_PATH defined in '
+ 'the AI-Suite .env file.')
+ args = parser.parse_args()
+
+ if not container_is_running():
+ exit(FAIL)
+
+ print(f"Connecting to container {CONTAINER}...")
+ work_dir = container_work_dir(args.project_path)
+ cmd = ['docker', 'exec', '-it', '-w', work_dir, CONTAINER, '/bin/sh', '-c',
+ '/usr/local/bin/opencode', '.']
+ run_command(cmd)
+
+if __name__ == "__main__":
+ main()
diff --git a/suite_services.py b/suite_services.py
index e248f90..4ef4565 100644
--- a/suite_services.py
+++ b/suite_services.py
@@ -278,6 +278,8 @@ def prepare_open_webui_tools_filesystem_env():
- host.docker.internal:host-gateway
volumes:
- ${PROJECTS_PATH:-../shared}:/nonexistent/tmp
+ environment:
+ - PROJECTS_PATH
"""))
def destroy_ai_suite(profile=None, upgrade=False):