From 3faffba3dfaaaabeeafb885b2f9be954760503fa Mon Sep 17 00:00:00 2001 From: Trevor SANDY Date: Wed, 31 Dec 2025 19:11:36 +0100 Subject: [PATCH] Add run_opencode_docker.py --- .gitignore | 1 + README.md | 41 +++++++++++++- docker-compose.yml | 2 + opencode/run_opencode_docker.py | 99 +++++++++++++++++++++++++++++++++ suite_services.py | 2 + 5 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 opencode/run_opencode_docker.py 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):