From fa07a6396a9ee6522654e3f131ec3df20a2e848a Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Fri, 24 Oct 2025 14:35:46 +0530 Subject: [PATCH 01/17] feat: opencode module --- .../coder-labs/modules/opencode/README.md | 123 ++++++ .../coder-labs/modules/opencode/main.test.ts | 372 ++++++++++++++++++ registry/coder-labs/modules/opencode/main.tf | 214 ++++++++++ .../modules/opencode/main.tftest.hcl | 366 +++++++++++++++++ .../modules/opencode/scripts/install.sh | 143 +++++++ .../modules/opencode/scripts/start.sh | 81 ++++ .../opencode/testdata/opencode-mock.sh | 25 ++ 7 files changed, 1324 insertions(+) create mode 100644 registry/coder-labs/modules/opencode/README.md create mode 100644 registry/coder-labs/modules/opencode/main.test.ts create mode 100644 registry/coder-labs/modules/opencode/main.tf create mode 100644 registry/coder-labs/modules/opencode/main.tftest.hcl create mode 100755 registry/coder-labs/modules/opencode/scripts/install.sh create mode 100755 registry/coder-labs/modules/opencode/scripts/start.sh create mode 100644 registry/coder-labs/modules/opencode/testdata/opencode-mock.sh diff --git a/registry/coder-labs/modules/opencode/README.md b/registry/coder-labs/modules/opencode/README.md new file mode 100644 index 000000000..6d981a1f1 --- /dev/null +++ b/registry/coder-labs/modules/opencode/README.md @@ -0,0 +1,123 @@ +--- +display_name: OpenCode +icon: ../../../../.icons/opencode.svg +description: Run OpenCode AI coding assistant for AI-powered terminal assistance +verified: false +tags: [agent, opencode, ai, tasks] +--- + +# OpenCode + +Run [OpenCode](https://opencode.ai) AI coding assistant in your workspace for intelligent code generation, analysis, and development assistance. This module integrates with [AgentAPI](https://github.com/coder/agentapi) for seamless task reporting in the Coder UI. + +```tf +module "opencode" { + source = "registry.coder.com/coder-labs/opencode/coder" + version = "0.1.0" + agent_id = coder_agent.example.id + workdir = "/home/coder/project" +} +``` + +## Prerequisites + +- **Authentication credentials** - OpenCode auth.json file is required while running tasks, you can find this file on your system: `$HOME/.local/share/opencode/auth.json` + +## Examples + +### Basic Usage with Tasks + +```tf +data "coder_parameter" "ai_prompt" { + type = "string" + name = "AI Task" + default = "" + description = "Initial task prompt for OpenCode AI assistant" + mutable = true +} + +module "coder-login" { + count = data.coder_workspace.me.start_count + source = "registry.coder.com/coder/coder-login/coder" + version = "1.0.31" + agent_id = coder_agent.example.id +} + +module "opencode" { + source = "registry.coder.com/coder-labs/opencode/coder" + version = "0.1.0" + agent_id = coder_agent.example.id + workdir = "/home/coder/project" + + ai_prompt = data.coder_parameter.ai_prompt.value + model = "anthropic/claude-sonnet-4-20250514" + + # Authentication (required for tasks) + auth_json = <<-EOT +{ + "google": { + "type": "api", + "key": "gem-xxx-xxxx" + }, + "anthropic": { + "type": "api", + "key": "sk-ant-api03-xxx-xxxxxxx" + } +} +EOT + + mcp = <<-EOT + { + "$schema": "https://opencode.ai/config.json", + "mcp": { + "test-mcp": { + "type": "local", + "command": [ + "uv", + "--directory", + "/Users/jkmr/Documents/work/test-mcp", + "run", + "test-mcp.py" + ], + "enabled": true, + "environment": { + "a": "A" + } + } + } +} +EOT + pre_install_script = <<-EOT + cd test-mcp + curl -LsSf https://astral.sh/uv/install.sh | sh + source "$HOME"/.bashrc + /home/coder/.local/bin/uv sync +EOT +} +``` + +### Standalone CLI Mode + +Run OpenCode as a command-line tool without web interface or task reporting: + +```tf +module "opencode" { + source = "registry.coder.com/coder-labs/opencode/coder" + version = "0.1.0" + agent_id = coder_agent.example.id + workdir = "/home/coder" + report_tasks = false + cli_app = true +} +``` + +## Troubleshooting + +If you encounter any issues, check the log files in the `~/.opencode-module` directory within your workspace for detailed information. + + +## References + +- [OpenCode Documentation](https://opencode.ai/docs) +- [AgentAPI Documentation](https://github.com/coder/agentapi) +- [Coder AI Agents Guide](https://coder.com/docs/tutorials/ai-agents) \ No newline at end of file diff --git a/registry/coder-labs/modules/opencode/main.test.ts b/registry/coder-labs/modules/opencode/main.test.ts new file mode 100644 index 000000000..14676e411 --- /dev/null +++ b/registry/coder-labs/modules/opencode/main.test.ts @@ -0,0 +1,372 @@ +import { + test, + afterEach, + describe, + setDefaultTimeout, + beforeAll, + expect, +} from "bun:test"; +import { execContainer, readFileContainer, runTerraformInit } from "~test"; +import { + loadTestFile, + writeExecutable, + setup as setupUtil, + execModuleScript, + expectAgentAPIStarted, +} from "../../../coder/modules/agentapi/test-util"; +import dedent from "dedent"; + +let cleanupFunctions: (() => Promise)[] = []; +const registerCleanup = (cleanup: () => Promise) => { + cleanupFunctions.push(cleanup); +}; +afterEach(async () => { + const cleanupFnsCopy = cleanupFunctions.slice().reverse(); + cleanupFunctions = []; + for (const cleanup of cleanupFnsCopy) { + try { + await cleanup(); + } catch (error) { + console.error("Error during cleanup:", error); + } + } +}); + +interface SetupProps { + skipAgentAPIMock?: boolean; + skipOpencodeMock?: boolean; + moduleVariables?: Record; + agentapiMockScript?: string; +} + +const setup = async (props?: SetupProps): Promise<{ id: string }> => { + const projectDir = "/home/coder/project"; + const { id } = await setupUtil({ + moduleDir: import.meta.dir, + moduleVariables: { + install_opencode: props?.skipOpencodeMock ? "true" : "false", + install_agentapi: props?.skipAgentAPIMock ? "true" : "false", + workdir: projectDir, + ...props?.moduleVariables, + }, + registerCleanup, + projectDir, + skipAgentAPIMock: props?.skipAgentAPIMock, + agentapiMockScript: props?.agentapiMockScript, + }); + if (!props?.skipOpencodeMock) { + await writeExecutable({ + containerId: id, + filePath: "/usr/bin/opencode", + content: await loadTestFile(import.meta.dir, "opencode-mock.sh"), + }); + } + return { id }; +}; + +setDefaultTimeout(60 * 1000); + +describe("opencode", async () => { + beforeAll(async () => { + await runTerraformInit(import.meta.dir); + }); + + test("happy-path", async () => { + const { id } = await setup(); + await execModuleScript(id); + await expectAgentAPIStarted(id); + }); + + test("install-opencode-version", async () => { + const version_to_install = "0.1.0"; + const { id } = await setup({ + skipOpencodeMock: true, + moduleVariables: { + install_opencode: "true", + opencode_version: version_to_install, + pre_install_script: dedent` + #!/usr/bin/env bash + set -euo pipefail + + # Mock the opencode install for testing + mkdir -p /home/coder/.opencode/bin + echo '#!/bin/bash\necho "opencode mock version ${version_to_install}"' > /home/coder/.opencode/bin/opencode + chmod +x /home/coder/.opencode/bin/opencode + `, + }, + }); + await execModuleScript(id); + const resp = await execContainer(id, [ + "bash", + "-c", + `cat /home/coder/.opencode-module/install.log`, + ]); + expect(resp.stdout).toContain(version_to_install); + }); + + test("check-latest-opencode-version-works", async () => { + const { id } = await setup({ + skipOpencodeMock: true, + skipAgentAPIMock: true, + moduleVariables: { + install_opencode: "true", + pre_install_script: dedent` + #!/usr/bin/env bash + set -euo pipefail + + # Mock the opencode install for testing + mkdir -p /home/coder/.opencode/bin + echo '#!/bin/bash\necho "opencode mock latest version"' > /home/coder/.opencode/bin/opencode + chmod +x /home/coder/.opencode/bin/opencode + `, + }, + }); + await execModuleScript(id); + await expectAgentAPIStarted(id); + }); + + test("opencode-auth-json", async () => { + const authJson = JSON.stringify({ + token: "test-auth-token-123", + user: "test-user", + }); + const { id } = await setup({ + moduleVariables: { + auth_json: authJson, + }, + }); + await execModuleScript(id); + + const authFile = await readFileContainer( + id, + "/home/coder/.local/share/opencode/auth.json", + ); + + expect(authFile).toContain("test-auth-token-123"); + expect(authFile).toContain("test-user"); + }); + + test("opencode-mcp-config", async () => { + const mcpConfig = JSON.stringify({ + mcp: { + test: { + command: ["test-cmd"], + type: "local", + }, + }, + }); + const { id } = await setup({ + moduleVariables: { + mcp: mcpConfig, + }, + }); + await execModuleScript(id); + + const configFile = await readFileContainer( + id, + "/home/coder/project/opencode.json", + ); + expect(configFile).toContain("test-cmd"); + }); + + test("opencode-ai-prompt", async () => { + const prompt = "This is a task prompt for OpenCode."; + const { id } = await setup({ + moduleVariables: { + ai_prompt: prompt, + }, + }); + await execModuleScript(id); + + const resp = await execContainer(id, [ + "bash", + "-c", + `cat /home/coder/.opencode-module/agentapi-start.log`, + ]); + expect(resp.stdout).toContain(prompt); + }); + + test("opencode-model", async () => { + const model = "gpt-4"; + const { id } = await setup({ + moduleVariables: { + model: model, + ai_prompt: "test prompt", + }, + }); + await execModuleScript(id); + + const startLog = await execContainer(id, [ + "bash", + "-c", + "cat /home/coder/.opencode-module/agentapi-start.log", + ]); + expect(startLog.stdout).toContain(`--model ${model}`); + }); + + test("opencode-agent", async () => { + const agent = "test-agent"; + const { id } = await setup({ + moduleVariables: { + agent: agent, + ai_prompt: "test prompt", + }, + }); + await execModuleScript(id); + + const startLog = await execContainer(id, [ + "bash", + "-c", + "cat /home/coder/.opencode-module/agentapi-start.log", + ]); + expect(startLog.stdout).toContain(`--agent ${agent}`); + }); + + test("opencode-session-id", async () => { + const sessionId = "session-123"; + const { id } = await setup({ + moduleVariables: { + session_id: sessionId, + ai_prompt: "test prompt", + }, + }); + await execModuleScript(id); + + const startLog = await execContainer(id, [ + "bash", + "-c", + "cat /home/coder/.opencode-module/agentapi-start.log", + ]); + expect(startLog.stdout).toContain(`--session ${sessionId}`); + }); + + test("opencode-report-tasks-enabled", async () => { + const { id } = await setup({ + moduleVariables: { + report_tasks: "true", + ai_prompt: "test prompt", + }, + }); + await execModuleScript(id); + + const startLog = await execContainer(id, [ + "bash", + "-c", + "cat /home/coder/.opencode-module/agentapi-start.log", + ]); + expect(startLog.stdout).toContain("report your progress using coder_report_task"); + }); + + test("opencode-report-tasks-disabled", async () => { + const { id } = await setup({ + moduleVariables: { + report_tasks: "false", + ai_prompt: "test prompt", + }, + }); + await execModuleScript(id); + + const startLog = await execContainer(id, [ + "bash", + "-c", + "cat /home/coder/.opencode-module/agentapi-start.log", + ]); + expect(startLog.stdout).not.toContain("report your progress using coder_report_task"); + }); + + test("cli-app-creation", async () => { + const { id } = await setup({ + moduleVariables: { + cli_app: "true", + cli_app_display_name: "OpenCode Terminal", + }, + }); + await execModuleScript(id); + // CLI app creation is handled by the agentapi module + // We just verify the setup completed successfully + await expectAgentAPIStarted(id); + }); + + test("pre-post-install-scripts", async () => { + const { id } = await setup({ + moduleVariables: { + pre_install_script: "#!/bin/bash\necho 'opencode-pre-install-script'", + post_install_script: "#!/bin/bash\necho 'opencode-post-install-script'", + }, + }); + await execModuleScript(id); + + const preInstallLog = await readFileContainer( + id, + "/home/coder/.opencode-module/pre_install.log", + ); + expect(preInstallLog).toContain("opencode-pre-install-script"); + + const postInstallLog = await readFileContainer( + id, + "/home/coder/.opencode-module/post_install.log", + ); + expect(postInstallLog).toContain("opencode-post-install-script"); + }); + + test("workdir-variable", async () => { + const workdir = "/home/coder/opencode-test-folder"; + const { id } = await setup({ + skipOpencodeMock: false, + moduleVariables: { + workdir, + }, + }); + await execModuleScript(id); + + const resp = await readFileContainer( + id, + "/home/coder/.opencode-module/agentapi-start.log", + ); + expect(resp).toContain(workdir); + }); + + test("coder-mcp-config-created", async () => { + const { id } = await setup({ + moduleVariables: { + install_opencode: "false", // Don't need to install opencode to test MCP config creation + }, + }); + await execModuleScript(id); + + const mcpConfig = await readFileContainer( + id, + "/home/coder/project/opencode.json", + ); + expect(mcpConfig).toContain("mcp"); + expect(mcpConfig).toContain("coder"); + expect(mcpConfig).toContain("CODER_MCP_APP_STATUS_SLUG"); + expect(mcpConfig).toContain("CODER_MCP_AI_AGENTAPI_URL"); + }); + + test("subdomain-enabled", async () => { + const { id } = await setup({ + moduleVariables: { + subdomain: "true", + }, + }); + await execModuleScript(id); + // Subdomain configuration is handled by the agentapi module + // We just verify the setup completed successfully + await expectAgentAPIStarted(id); + }); + + test("custom-display-names", async () => { + const { id } = await setup({ + moduleVariables: { + web_app_display_name: "Custom OpenCode Web", + cli_app_display_name: "Custom OpenCode CLI", + cli_app: "true", + }, + }); + await execModuleScript(id); + // Display names are handled by the agentapi module + // We just verify the setup completed successfully + await expectAgentAPIStarted(id); + }); +}); \ No newline at end of file diff --git a/registry/coder-labs/modules/opencode/main.tf b/registry/coder-labs/modules/opencode/main.tf new file mode 100644 index 000000000..8e54c0b45 --- /dev/null +++ b/registry/coder-labs/modules/opencode/main.tf @@ -0,0 +1,214 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 2.7" + } + } +} + +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +data "coder_workspace" "me" {} + +data "coder_workspace_owner" "me" {} + +variable "order" { + type = number + description = "The order determines the position of app in the UI presentation. The lowest order is shown first and apps with equal order are sorted by name (ascending order)." + default = null +} + +variable "group" { + type = string + description = "The name of a group that this app belongs to." + default = null +} + +variable "icon" { + type = string + description = "The icon to use for the app." + default = "/icon/opencode.svg" +} + +variable "workdir" { + type = string + description = "The folder to run OpenCode in." +} + +variable "report_tasks" { + type = bool + description = "Whether to enable task reporting to Coder UI via AgentAPI" + default = true +} + +variable "cli_app" { + type = bool + description = "Whether to create a CLI app for OpenCode" + default = false +} + +variable "web_app_display_name" { + type = string + description = "Display name for the web app" + default = "OpenCode" +} + +variable "cli_app_display_name" { + type = string + description = "Display name for the CLI app" + default = "OpenCode CLI" +} + +variable "pre_install_script" { + type = string + description = "Custom script to run before installing OpenCode." + default = null +} + +variable "post_install_script" { + type = string + description = "Custom script to run after installing OpenCode." + default = null +} + +variable "install_agentapi" { + type = bool + description = "Whether to install AgentAPI." + default = true +} + +variable "agentapi_version" { + type = string + description = "The version of AgentAPI to install." + default = "v0.10.0" +} + +variable "ai_prompt" { + type = string + description = "Initial task prompt for OpenCode." + default = "" +} + +variable "subdomain" { + type = bool + description = "Whether to use a subdomain for AgentAPI." + default = false +} + +variable "install_opencode" { + type = bool + description = "Whether to install OpenCode." + default = true +} + +variable "opencode_version" { + type = string + description = "The version of OpenCode to install." + default = "latest" +} + +variable "continue" { + type = bool + description = "continue the last session. Uses the --continue flag" + default = false +} + +variable "model" { + type = string + description = "The default AI model to use. Passwd via --agent" + default = "" +} + +variable "agent" { + type = string + description = "Agent to use. Passed via --agent" + default = "" +} + +variable "session_id" { + type = string + description = "Session id to continue. Passed via --session" + default = "" +} + +variable "auth_json" { + type = string + description = "Your auth.json from $HOME/.local/share/opencode/auth.json, Required while running tasks." + default = "" +} + +variable "mcp" { + type = string + description = "MCP configuration as a JSON string" + default = "" +} + + +locals { + workdir = trimsuffix(var.workdir, "/") + app_slug = "opencode" + install_script = file("${path.module}/scripts/install.sh") + start_script = file("${path.module}/scripts/start.sh") + module_dir_name = ".opencode-module" +} + +module "agentapi" { + source = "registry.coder.com/coder/agentapi/coder" + version = "1.2.0" + + agent_id = var.agent_id + web_app_slug = local.app_slug + web_app_order = var.order + web_app_group = var.group + web_app_icon = var.icon + web_app_display_name = var.web_app_display_name + cli_app = var.cli_app + cli_app_slug = var.cli_app ? "${local.app_slug}-cli" : null + cli_app_display_name = var.cli_app ? var.cli_app_display_name : null + agentapi_subdomain = var.subdomain + folder = local.workdir + module_dir_name = local.module_dir_name + install_agentapi = var.install_agentapi + agentapi_version = var.agentapi_version + pre_install_script = var.pre_install_script + post_install_script = var.post_install_script + start_script = <<-EOT + #!/bin/bash + set -o errexit + set -o pipefail + echo -n '${base64encode(local.start_script)}' | base64 -d > /tmp/start.sh + chmod +x /tmp/start.sh + + ARG_WORKDIR='${local.workdir}' \ + ARG_AI_PROMPT='${base64encode(var.ai_prompt)}' \ + ARG_MODEL='${var.model}' \ + ARG_AGENT='${var.agent}' \ + ARG_SESSION_ID='${var.session_id}' \ + ARG_REPORT_TASKS='${var.report_tasks}' \ + ARG_CONTINUE='${var.continue}' \ + /tmp/start.sh + EOT + + install_script = <<-EOT + #!/bin/bash + set -o errexit + set -o pipefail + + echo -n '${base64encode(local.install_script)}' | base64 -d > /tmp/install.sh + chmod +x /tmp/install.sh + ARG_OPENCODE_VERSION='${var.opencode_version}' \ + ARG_MCP_APP_STATUS_SLUG='${local.app_slug}' \ + ARG_INSTALL_OPENCODE='${var.install_opencode}' \ + ARG_REPORT_TASKS='${var.report_tasks}' \ + ARG_WORKDIR='${local.workdir}' \ + ARG_AUTH_JSON='${var.auth_json != null ? base64encode(replace(var.auth_json, "'", "'\\''")) : ""}' \ + ARG_MCP_CONFIG='${var.mcp != null ? base64encode(replace(var.mcp, "'", "'\\''")) : ""}' \ + /tmp/install.sh + EOT +} diff --git a/registry/coder-labs/modules/opencode/main.tftest.hcl b/registry/coder-labs/modules/opencode/main.tftest.hcl new file mode 100644 index 000000000..6229dd629 --- /dev/null +++ b/registry/coder-labs/modules/opencode/main.tftest.hcl @@ -0,0 +1,366 @@ +run "defaults_are_correct" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + } + + assert { + condition = var.install_opencode == true + error_message = "OpenCode installation should be enabled by default" + } + + assert { + condition = var.install_agentapi == true + error_message = "AgentAPI installation should be enabled by default" + } + + assert { + condition = var.agentapi_version == "v0.10.0" + error_message = "Default AgentAPI version should be 'v0.10.0'" + } + + assert { + condition = var.opencode_version == "latest" + error_message = "Default OpenCode version should be 'latest'" + } + + assert { + condition = var.report_tasks == true + error_message = "Task reporting should be enabled by default" + } + + assert { + condition = var.cli_app == false + error_message = "CLI app should be disabled by default" + } + + assert { + condition = var.subdomain == false + error_message = "Subdomain should be disabled by default" + } + + assert { + condition = var.web_app_display_name == "OpenCode" + error_message = "Default web app display name should be 'OpenCode'" + } + + assert { + condition = var.cli_app_display_name == "OpenCode CLI" + error_message = "Default CLI app display name should be 'OpenCode CLI'" + } + + assert { + condition = local.app_slug == "opencode" + error_message = "App slug should be 'opencode'" + } + + assert { + condition = local.module_dir_name == ".opencode-module" + error_message = "Module dir name should be '.opencode-module'" + } + + assert { + condition = local.workdir == "/home/coder/project" + error_message = "Workdir should be trimmed of trailing slash" + } +} + +run "workdir_trailing_slash_trimmed" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project/" + } + + assert { + condition = local.workdir == "/home/coder/project" + error_message = "Workdir should be trimmed of trailing slash" + } +} + +run "opencode_version_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + opencode_version = "v1.0.0" + } + + assert { + condition = var.opencode_version == "v1.0.0" + error_message = "OpenCode version should be set correctly" + } +} + +run "agentapi_version_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + agentapi_version = "v0.9.0" + } + + assert { + condition = var.agentapi_version == "v0.9.0" + error_message = "AgentAPI version should be set correctly" + } +} + +run "cli_app_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + cli_app = true + cli_app_display_name = "Custom OpenCode CLI" + } + + assert { + condition = var.cli_app == true + error_message = "CLI app should be enabled when specified" + } + + assert { + condition = var.cli_app_display_name == "Custom OpenCode CLI" + error_message = "Custom CLI app display name should be set" + } +} + +run "web_app_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + web_app_display_name = "Custom OpenCode Web" + order = 5 + group = "AI Tools" + icon = "/custom/icon.svg" + } + + assert { + condition = var.web_app_display_name == "Custom OpenCode Web" + error_message = "Custom web app display name should be set" + } + + assert { + condition = var.order == 5 + error_message = "Custom order should be set" + } + + assert { + condition = var.group == "AI Tools" + error_message = "Custom group should be set" + } + + assert { + condition = var.icon == "/custom/icon.svg" + error_message = "Custom icon should be set" + } +} + +run "ai_configuration_variables" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + ai_prompt = "This is a test prompt" + model = "gpt-4" + agent = "test-agent-name" + session_id = "session-123" + } + + assert { + condition = var.ai_prompt == "This is a test prompt" + error_message = "AI prompt should be set correctly" + } + + assert { + condition = var.model == "gpt-4" + error_message = "Model should be set correctly" + } + + assert { + condition = var.agent == "test-agent-name" + error_message = "Agent should be set correctly" + } + + assert { + condition = var.session_id == "session-123" + error_message = "Session ID should be set correctly" + } +} + +run "auth_json_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + auth_json = "{\"token\": \"test-token\", \"user\": \"test-user\"}" + } + + assert { + condition = var.auth_json != "" + error_message = "Auth JSON should be set" + } + + assert { + condition = can(jsondecode(var.auth_json)) + error_message = "Auth JSON should be valid JSON" + } +} + +run "mcp_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + mcp = "{\"mcp\": {\"test\": {\"command\": \"test-cmd\", \"type\": \"local\"}}}" + } + + assert { + condition = var.mcp != "" + error_message = "MCP configuration should be set" + } + + assert { + condition = can(jsondecode(var.mcp)) + error_message = "MCP configuration should be valid JSON" + } +} + +run "task_reporting_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + report_tasks = false + } + + assert { + condition = var.report_tasks == false + error_message = "Task reporting should be disabled when specified" + } +} + +run "subdomain_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + subdomain = true + } + + assert { + condition = var.subdomain == true + error_message = "Subdomain should be enabled when specified" + } +} + +run "install_flags_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + install_opencode = false + install_agentapi = false + } + + assert { + condition = var.install_opencode == false + error_message = "OpenCode installation should be disabled when specified" + } + + assert { + condition = var.install_agentapi == false + error_message = "AgentAPI installation should be disabled when specified" + } +} + +run "custom_scripts_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + pre_install_script = "#!/bin/bash\necho 'pre-install'" + post_install_script = "#!/bin/bash\necho 'post-install'" + } + + assert { + condition = var.pre_install_script != null + error_message = "Pre-install script should be set" + } + + assert { + condition = var.post_install_script != null + error_message = "Post-install script should be set" + } + + assert { + condition = can(regex("pre-install", var.pre_install_script)) + error_message = "Pre-install script should contain expected content" + } + + assert { + condition = can(regex("post-install", var.post_install_script)) + error_message = "Post-install script should contain expected content" + } +} + +run "empty_variables_handled_correctly" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + ai_prompt = "" + model = "" + agent = "" + session_id = "" + auth_json = "" + mcp = "" + } + + assert { + condition = var.ai_prompt == "" + error_message = "Empty AI prompt should be handled correctly" + } + + assert { + condition = var.model == "" + error_message = "Empty model should be handled correctly" + } + + assert { + condition = var.agent == "" + error_message = "Empty agent should be handled correctly" + } + + assert { + condition = var.session_id == "" + error_message = "Empty session ID should be handled correctly" + } + + assert { + condition = var.auth_json == "" + error_message = "Empty auth JSON should be handled correctly" + } + + assert { + condition = var.mcp == "" + error_message = "Empty MCP config should be handled correctly" + } +} \ No newline at end of file diff --git a/registry/coder-labs/modules/opencode/scripts/install.sh b/registry/coder-labs/modules/opencode/scripts/install.sh new file mode 100755 index 000000000..8a32c27e5 --- /dev/null +++ b/registry/coder-labs/modules/opencode/scripts/install.sh @@ -0,0 +1,143 @@ +#!/bin/bash +set -euo pipefail + +command_exists() { + command -v "$1" > /dev/null 2>&1 +} + +ARG_WORKDIR=${ARG_WORKDIR:-"$HOME"} +ARG_REPORT_TASKS=${ARG_REPORT_TASKS:-true} +ARG_MCP_APP_STATUS_SLUG=${ARG_MCP_APP_STATUS_SLUG:-} +ARG_OPENCODE_VERSION=${ARG_OPENCODE_VERSION:-latest} +ARG_INSTALL_OPENCODE=${ARG_INSTALL_OPENCODE:-true} +ARG_AUTH_JSON=$(echo -n "$ARG_AUTH_JSON" | base64 -d 2> /dev/null || echo "") +ARG_MCP_CONFIG=$(echo -n "$ARG_MCP_CONFIG" | base64 -d 2> /dev/null || echo "") + + +# Print all received environment variables +printf "=== INSTALL CONFIG ===\n" +printf "ARG_WORKDIR: %s\n" "$ARG_WORKDIR" +printf "ARG_REPORT_TASKS: %s\n" "$ARG_REPORT_TASKS" +printf "ARG_MCP_APP_STATUS_SLUG: %s\n" "$ARG_MCP_APP_STATUS_SLUG" +printf "ARG_OPENCODE_VERSION: %s\n" "$ARG_OPENCODE_VERSION" +printf "ARG_INSTALL_OPENCODE: %s\n" "$ARG_INSTALL_OPENCODE" +if [ -n "$ARG_AUTH_JSON" ]; then + printf "ARG_AUTH_JSON: [AUTH DATA RECEIVED]\n" +else + printf "ARG_AUTH_JSON: [NOT PROVIDED]\n" +fi +if [ -n "$ARG_MCP_CONFIG" ]; then + printf "ARG_MCP_CONFIG: [MCP CONFIG RECEIVED]\n" +else + printf "ARG_MCP_CONFIG: [NOT PROVIDED]\n" +fi +printf "==================================\n" + + +install_opencode() { + if [ "$ARG_INSTALL_OPENCODE" = "true" ]; then + if ! command_exists opencode; then + echo "Installing OpenCode (version: ${ARG_OPENCODE_VERSION})..." + if [ "$ARG_OPENCODE_VERSION" = "latest" ]; then + curl -fsSL https://opencode.ai/install | bash + else + VERSION=$ARG_OPENCODE_VERSION curl -fsSL https://opencode.ai/install | bash + fi + export PATH=/home/coder/.opencode/bin:$PATH + printf "Opencode location: %s\n" "$(which opencode)" + if ! command_exists opencode; then + echo "ERROR: Failed to install OpenCode" + exit 1 + fi + echo "OpenCode installed successfully" + else + echo "OpenCode already installed" + fi + else + echo "OpenCode installation skipped (ARG_INSTALL_OPENCODE=false)" + fi +} + +setup_opencode_config() { + local mcp_config_file="$ARG_WORKDIR/opencode.json" + local auth_json_file="$HOME/.local/share/opencode/auth.json" + + mkdir -p "$(dirname "$auth_json_file")" + mkdir -p "$(dirname "$mcp_config_file")" + + setup_opencode_auth "$auth_json_file" + setup_mcp_config "$mcp_config_file" +} + +setup_opencode_auth() { + local auth_json_file="$1" + + if [ -n "$ARG_AUTH_JSON" ]; then + echo "$ARG_AUTH_JSON" > "$auth_json_file" + printf "added auth json to %s" "$auth_json_file" + else + printf "auth json not provided" + fi +} + +setup_mcp_config() { + local mcp_config_file="$1" + + echo '{"$schema": "https://opencode.ai/config.json", "mcp": {}}' > "$mcp_config_file" + + if [ -n "$ARG_MCP_CONFIG" ]; then + echo "Adding custom MCP servers..." + echo "$ARG_MCP_CONFIG" > "$mcp_config_file" + fi + + setup_coder_mcp_server "$mcp_config_file" + + echo "MCP configuration completed: $mcp_config_file" +} + +setup_coder_mcp_server() { + local mcp_config_file="$1" + + # Set environment variables based on task reporting setting + if [ "$ARG_REPORT_TASKS" = "true" ]; then + echo "Configuring OpenCode task reporting" + export CODER_MCP_APP_STATUS_SLUG="$ARG_MCP_APP_STATUS_SLUG" + export CODER_MCP_AI_AGENTAPI_URL="http://localhost:3284" + echo "Coder integration configured for task reporting" + else + echo "Task reporting disabled or no app status slug provided." + export CODER_MCP_APP_STATUS_SLUG="" + export CODER_MCP_AI_AGENTAPI_URL="" + fi + + # Add coder MCP server configuration to the JSON file + echo "Adding Coder MCP server configuration" + + # Create the coder server configuration JSON + coder_config=$(cat < "$temp_file" + mv "$temp_file" "$mcp_config_file" + echo "Coder MCP server configuration added" + +} + +install_opencode +setup_opencode_config + + +echo "OpenCode module setup completed." \ No newline at end of file diff --git a/registry/coder-labs/modules/opencode/scripts/start.sh b/registry/coder-labs/modules/opencode/scripts/start.sh new file mode 100755 index 000000000..25ced3560 --- /dev/null +++ b/registry/coder-labs/modules/opencode/scripts/start.sh @@ -0,0 +1,81 @@ +#!/bin/bash +set -euo pipefail + +export PATH=/home/coder/.opencode/bin:$PATH + +command_exists() { + command -v "$1" > /dev/null 2>&1 +} + +ARG_WORKDIR=${ARG_WORKDIR:-"$HOME"} +ARG_AI_PROMPT=$(echo -n "${ARG_AI_PROMPT:-}" | base64 -d 2> /dev/null || echo "") +ARG_REPORT_TASKS=${ARG_REPORT_TASKS:-true} +ARG_MODEL=${ARG_MODEL:-} +ARG_AGENT=${ARG_AGENT:-} +ARG_SESSION_ID=${ARG_SESSION_ID:-} +ARG_CONTINUE=${ARG_CONTINUE:-false} + +# Print all received environment variables +printf "=== START CONFIG ===\n" +printf "ARG_WORKDIR: %s\n" "$ARG_WORKDIR" +printf "ARG_REPORT_TASKS: %s\n" "$ARG_REPORT_TASKS" +printf "ARG_MODEL: %s\n" "$ARG_MODEL" +printf "ARG_AGENT: %s\n" "$ARG_AGENT" +printf "ARG_CONTINUE: %s\n" "$ARG_CONTINUE" +printf "ARG_SESSION_ID: %s\n" "$ARG_SESSION_ID" +if [ -n "$ARG_AI_PROMPT" ]; then + printf "ARG_AI_PROMPT: [AI PROMPT RECEIVED]\n" +else + printf "ARG_AI_PROMPT: [NOT PROVIDED]\n" +fi +printf "==================================\n" + +OPENCODE_ARGS=() + + +validate_opencode_installation() { + if ! command_exists opencode; then + printf "ERROR: OpenCode not installed. Set install_opencode to true\n" + exit 1 + fi +} + +build_opencode_args() { + if [ -n "$ARG_MODEL" ]; then + OPENCODE_ARGS+=(--model "$ARG_MODEL") + fi + + if [ -n "$ARG_AGENT" ]; then + OPENCODE_ARGS+=(--agent "$ARG_AGENT") + fi + + if [ -n "$ARG_SESSION_ID" ]; then + OPENCODE_ARGS+=(--session "$ARG_SESSION_ID") + fi + + if [ "$ARG_CONTINUE" = "true" ]; then + OPENCODE_ARGS+=(--continue) + fi + + if [ -n "$ARG_AI_PROMPT" ]; then + if [ "$ARG_REPORT_TASKS" = "true" ]; then + PROMPT="Every step of the way, report your progress using coder_report_task tool with proper summary and statuses. Your task at hand: $ARG_AI_PROMPT" + else + PROMPT="$ARG_AI_PROMPT" + fi + OPENCODE_ARGS+=(--prompt "$PROMPT") + fi +} + +start_agentapi() { + printf "Starting in directory: %s\n" "$ARG_WORKDIR" + cd "$ARG_WORKDIR" + + build_opencode_args + + printf "Running OpenCode with args: %s\n" "${OPENCODE_ARGS[*]}" + agentapi server --type opencode --term-width 67 --term-height 1190 -- opencode "${OPENCODE_ARGS[@]}" +} + +validate_opencode_installation +start_agentapi \ No newline at end of file diff --git a/registry/coder-labs/modules/opencode/testdata/opencode-mock.sh b/registry/coder-labs/modules/opencode/testdata/opencode-mock.sh new file mode 100644 index 000000000..67017fccb --- /dev/null +++ b/registry/coder-labs/modules/opencode/testdata/opencode-mock.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Mock OpenCode CLI for testing purposes +# This script simulates the OpenCode command-line interface + +echo "OpenCode Mock CLI - Test Version" +echo "Args received: $*" + +# Simulate opencode behavior based on arguments +case "$1" in + --version|-v) + echo "opencode mock version 0.1.0-test" + ;; + --help|-h) + echo "OpenCode Mock Help" + echo "Usage: opencode [options] [command]" + echo "This is a mock version for testing" + ;; + *) + echo "Running OpenCode mock with arguments: $*" + echo "Mock execution completed successfully" + ;; +esac + +exit 0 \ No newline at end of file From e29cdb9c7969a8369c68770ec57584acca6fea3e Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Sat, 25 Oct 2025 11:25:01 +0530 Subject: [PATCH 02/17] chore: update version --- registry/coder-labs/modules/opencode/main.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/registry/coder-labs/modules/opencode/main.tf b/registry/coder-labs/modules/opencode/main.tf index 8e54c0b45..ad8bda35d 100644 --- a/registry/coder-labs/modules/opencode/main.tf +++ b/registry/coder-labs/modules/opencode/main.tf @@ -4,7 +4,7 @@ terraform { required_providers { coder = { source = "coder/coder" - version = ">= 2.7" + version = ">= 2.12" } } } @@ -160,7 +160,7 @@ locals { module "agentapi" { source = "registry.coder.com/coder/agentapi/coder" - version = "1.2.0" + version = "2.0.0" agent_id = var.agent_id web_app_slug = local.app_slug From e7de712034a98862943e46b1f272962d023a2ba1 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Tue, 28 Oct 2025 20:47:10 +0530 Subject: [PATCH 03/17] chore: add output --- registry/coder-labs/modules/opencode/main.tf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/registry/coder-labs/modules/opencode/main.tf b/registry/coder-labs/modules/opencode/main.tf index ad8bda35d..e5e59a7ba 100644 --- a/registry/coder-labs/modules/opencode/main.tf +++ b/registry/coder-labs/modules/opencode/main.tf @@ -212,3 +212,7 @@ module "agentapi" { /tmp/install.sh EOT } + +output "task_app_id" { + value = module.agentapi.task_app_id +} From a28c050565ddb8fd5990c7f75bfc56e6f796042e Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Tue, 28 Oct 2025 21:23:13 +0530 Subject: [PATCH 04/17] chore: format --- .../coder-labs/modules/opencode/README.md | 17 +++++++------ .../coder-labs/modules/opencode/main.test.ts | 10 +++++--- .../modules/opencode/scripts/install.sh | 24 +++++++++---------- .../modules/opencode/scripts/start.sh | 3 +-- .../opencode/testdata/opencode-mock.sh | 6 ++--- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/registry/coder-labs/modules/opencode/README.md b/registry/coder-labs/modules/opencode/README.md index 6d981a1f1..be947491c 100644 --- a/registry/coder-labs/modules/opencode/README.md +++ b/registry/coder-labs/modules/opencode/README.md @@ -48,9 +48,9 @@ module "opencode" { version = "0.1.0" agent_id = coder_agent.example.id workdir = "/home/coder/project" - + ai_prompt = data.coder_parameter.ai_prompt.value - model = "anthropic/claude-sonnet-4-20250514" + model = "anthropic/claude-sonnet-4-20250514" # Authentication (required for tasks) auth_json = <<-EOT @@ -65,8 +65,8 @@ module "opencode" { } } EOT - - mcp = <<-EOT + + mcp = <<-EOT { "$schema": "https://opencode.ai/config.json", "mcp": { @@ -102,9 +102,9 @@ Run OpenCode as a command-line tool without web interface or task reporting: ```tf module "opencode" { - source = "registry.coder.com/coder-labs/opencode/coder" - version = "0.1.0" - agent_id = coder_agent.example.id + source = "registry.coder.com/coder-labs/opencode/coder" + version = "0.1.0" + agent_id = coder_agent.example.id workdir = "/home/coder" report_tasks = false cli_app = true @@ -115,9 +115,8 @@ module "opencode" { If you encounter any issues, check the log files in the `~/.opencode-module` directory within your workspace for detailed information. - ## References - [OpenCode Documentation](https://opencode.ai/docs) - [AgentAPI Documentation](https://github.com/coder/agentapi) -- [Coder AI Agents Guide](https://coder.com/docs/tutorials/ai-agents) \ No newline at end of file +- [Coder AI Agents Guide](https://coder.com/docs/tutorials/ai-agents) diff --git a/registry/coder-labs/modules/opencode/main.test.ts b/registry/coder-labs/modules/opencode/main.test.ts index 14676e411..07dc65831 100644 --- a/registry/coder-labs/modules/opencode/main.test.ts +++ b/registry/coder-labs/modules/opencode/main.test.ts @@ -254,7 +254,9 @@ describe("opencode", async () => { "-c", "cat /home/coder/.opencode-module/agentapi-start.log", ]); - expect(startLog.stdout).toContain("report your progress using coder_report_task"); + expect(startLog.stdout).toContain( + "report your progress using coder_report_task", + ); }); test("opencode-report-tasks-disabled", async () => { @@ -271,7 +273,9 @@ describe("opencode", async () => { "-c", "cat /home/coder/.opencode-module/agentapi-start.log", ]); - expect(startLog.stdout).not.toContain("report your progress using coder_report_task"); + expect(startLog.stdout).not.toContain( + "report your progress using coder_report_task", + ); }); test("cli-app-creation", async () => { @@ -369,4 +373,4 @@ describe("opencode", async () => { // We just verify the setup completed successfully await expectAgentAPIStarted(id); }); -}); \ No newline at end of file +}); diff --git a/registry/coder-labs/modules/opencode/scripts/install.sh b/registry/coder-labs/modules/opencode/scripts/install.sh index 8a32c27e5..3a58881ef 100755 --- a/registry/coder-labs/modules/opencode/scripts/install.sh +++ b/registry/coder-labs/modules/opencode/scripts/install.sh @@ -13,7 +13,6 @@ ARG_INSTALL_OPENCODE=${ARG_INSTALL_OPENCODE:-true} ARG_AUTH_JSON=$(echo -n "$ARG_AUTH_JSON" | base64 -d 2> /dev/null || echo "") ARG_MCP_CONFIG=$(echo -n "$ARG_MCP_CONFIG" | base64 -d 2> /dev/null || echo "") - # Print all received environment variables printf "=== INSTALL CONFIG ===\n" printf "ARG_WORKDIR: %s\n" "$ARG_WORKDIR" @@ -33,7 +32,6 @@ else fi printf "==================================\n" - install_opencode() { if [ "$ARG_INSTALL_OPENCODE" = "true" ]; then if ! command_exists opencode; then @@ -73,10 +71,10 @@ setup_opencode_auth() { local auth_json_file="$1" if [ -n "$ARG_AUTH_JSON" ]; then - echo "$ARG_AUTH_JSON" > "$auth_json_file" - printf "added auth json to %s" "$auth_json_file" + echo "$ARG_AUTH_JSON" > "$auth_json_file" + printf "added auth json to %s" "$auth_json_file" else - printf "auth json not provided" + printf "auth json not provided" fi } @@ -85,10 +83,10 @@ setup_mcp_config() { echo '{"$schema": "https://opencode.ai/config.json", "mcp": {}}' > "$mcp_config_file" - if [ -n "$ARG_MCP_CONFIG" ]; then - echo "Adding custom MCP servers..." - echo "$ARG_MCP_CONFIG" > "$mcp_config_file" - fi + if [ -n "$ARG_MCP_CONFIG" ]; then + echo "Adding custom MCP servers..." + echo "$ARG_MCP_CONFIG" > "$mcp_config_file" + fi setup_coder_mcp_server "$mcp_config_file" @@ -114,7 +112,8 @@ setup_coder_mcp_server() { echo "Adding Coder MCP server configuration" # Create the coder server configuration JSON - coder_config=$(cat < "$temp_file" @@ -139,5 +138,4 @@ EOF install_opencode setup_opencode_config - -echo "OpenCode module setup completed." \ No newline at end of file +echo "OpenCode module setup completed." diff --git a/registry/coder-labs/modules/opencode/scripts/start.sh b/registry/coder-labs/modules/opencode/scripts/start.sh index 25ced3560..0c107a668 100755 --- a/registry/coder-labs/modules/opencode/scripts/start.sh +++ b/registry/coder-labs/modules/opencode/scripts/start.sh @@ -32,7 +32,6 @@ printf "==================================\n" OPENCODE_ARGS=() - validate_opencode_installation() { if ! command_exists opencode; then printf "ERROR: OpenCode not installed. Set install_opencode to true\n" @@ -78,4 +77,4 @@ start_agentapi() { } validate_opencode_installation -start_agentapi \ No newline at end of file +start_agentapi diff --git a/registry/coder-labs/modules/opencode/testdata/opencode-mock.sh b/registry/coder-labs/modules/opencode/testdata/opencode-mock.sh index 67017fccb..dcde8756c 100644 --- a/registry/coder-labs/modules/opencode/testdata/opencode-mock.sh +++ b/registry/coder-labs/modules/opencode/testdata/opencode-mock.sh @@ -8,10 +8,10 @@ echo "Args received: $*" # Simulate opencode behavior based on arguments case "$1" in - --version|-v) + --version | -v) echo "opencode mock version 0.1.0-test" ;; - --help|-h) + --help | -h) echo "OpenCode Mock Help" echo "Usage: opencode [options] [command]" echo "This is a mock version for testing" @@ -22,4 +22,4 @@ case "$1" in ;; esac -exit 0 \ No newline at end of file +exit 0 From 248a5cf855e0ac97466e8c01aaad6600f2fa8874 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Wed, 29 Oct 2025 06:51:52 +0530 Subject: [PATCH 05/17] chore: format --- .../modules/opencode/main.tftest.hcl | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/registry/coder-labs/modules/opencode/main.tftest.hcl b/registry/coder-labs/modules/opencode/main.tftest.hcl index 6229dd629..5d2485ff0 100644 --- a/registry/coder-labs/modules/opencode/main.tftest.hcl +++ b/registry/coder-labs/modules/opencode/main.tftest.hcl @@ -115,10 +115,10 @@ run "cli_app_configuration" { command = plan variables { - agent_id = "test-agent" - workdir = "/home/coder/project" - cli_app = true - cli_app_display_name = "Custom OpenCode CLI" + agent_id = "test-agent" + workdir = "/home/coder/project" + cli_app = true + cli_app_display_name = "Custom OpenCode CLI" } assert { @@ -136,12 +136,12 @@ run "web_app_configuration" { command = plan variables { - agent_id = "test-agent" - workdir = "/home/coder/project" - web_app_display_name = "Custom OpenCode Web" - order = 5 - group = "AI Tools" - icon = "/custom/icon.svg" + agent_id = "test-agent" + workdir = "/home/coder/project" + web_app_display_name = "Custom OpenCode Web" + order = 5 + group = "AI Tools" + icon = "/custom/icon.svg" } assert { From 8691b912492d53b5ae675bb1ae53084f79da438f Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Wed, 29 Oct 2025 06:56:37 +0530 Subject: [PATCH 06/17] feat: update README.md --- registry/coder-labs/modules/opencode/README.md | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/registry/coder-labs/modules/opencode/README.md b/registry/coder-labs/modules/opencode/README.md index be947491c..224131d70 100644 --- a/registry/coder-labs/modules/opencode/README.md +++ b/registry/coder-labs/modules/opencode/README.md @@ -28,19 +28,8 @@ module "opencode" { ### Basic Usage with Tasks ```tf -data "coder_parameter" "ai_prompt" { - type = "string" - name = "AI Task" - default = "" - description = "Initial task prompt for OpenCode AI assistant" - mutable = true -} - -module "coder-login" { - count = data.coder_workspace.me.start_count - source = "registry.coder.com/coder/coder-login/coder" - version = "1.0.31" - agent_id = coder_agent.example.id +resource "coder_ai_task" "task" { + app_id = module.opencode.task_app_id } module "opencode" { @@ -49,7 +38,7 @@ module "opencode" { agent_id = coder_agent.example.id workdir = "/home/coder/project" - ai_prompt = data.coder_parameter.ai_prompt.value + ai_prompt = coder_ai_task.task.prompt model = "anthropic/claude-sonnet-4-20250514" # Authentication (required for tasks) From 875bdda025fc43c82e4bed6e406345787d6959cb Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Wed, 29 Oct 2025 20:36:59 +0530 Subject: [PATCH 07/17] feat: update README.md --- .../coder-labs/modules/opencode/README.md | 56 ++++++++++--------- registry/coder-labs/modules/opencode/main.tf | 2 +- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/registry/coder-labs/modules/opencode/README.md b/registry/coder-labs/modules/opencode/README.md index 224131d70..cca429d73 100644 --- a/registry/coder-labs/modules/opencode/README.md +++ b/registry/coder-labs/modules/opencode/README.md @@ -21,7 +21,7 @@ module "opencode" { ## Prerequisites -- **Authentication credentials** - OpenCode auth.json file is required while running tasks, you can find this file on your system: `$HOME/.local/share/opencode/auth.json` +- **Authentication credentials** - OpenCode auth.json file is required for non-interactive authentication, you can find this file on your system: `$HOME/.local/share/opencode/auth.json` ## Examples @@ -40,8 +40,7 @@ module "opencode" { ai_prompt = coder_ai_task.task.prompt model = "anthropic/claude-sonnet-4-20250514" - - # Authentication (required for tasks) + auth_json = <<-EOT { "google": { @@ -55,33 +54,36 @@ module "opencode" { } EOT - mcp = <<-EOT - { - "$schema": "https://opencode.ai/config.json", - "mcp": { - "test-mcp": { - "type": "local", - "command": [ - "uv", - "--directory", - "/Users/jkmr/Documents/work/test-mcp", - "run", - "test-mcp.py" - ], - "enabled": true, - "environment": { - "a": "A" + mcp = jsonencode({ + mcpServers = { + filesystem = { + command = "npx" + args = ["-y", "@modelcontextprotocol/server-filesystem", "/home/coder/projects"] + description = "Provides file system access to the workspace" + name = "Filesystem" + timeout = 3000 + type = "local" + tools = ["*"] + trust = true + } + playwright = { + command = "npx" + args = ["-y", "@playwright/mcp@latest", "--headless", "--isolated"] + description = "Browser automation for testing and previewing changes" + name = "Playwright" + timeout = 5000 + type = "local" + tools = ["*"] + trust = false } } - } -} -EOT + }) + pre_install_script = <<-EOT - cd test-mcp - curl -LsSf https://astral.sh/uv/install.sh | sh - source "$HOME"/.bashrc - /home/coder/.local/bin/uv sync -EOT + #!/bin/bash + curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - + sudo apt-get install -y nodejs + EOT } ``` diff --git a/registry/coder-labs/modules/opencode/main.tf b/registry/coder-labs/modules/opencode/main.tf index e5e59a7ba..a3d56ee8e 100644 --- a/registry/coder-labs/modules/opencode/main.tf +++ b/registry/coder-labs/modules/opencode/main.tf @@ -139,7 +139,7 @@ variable "session_id" { variable "auth_json" { type = string - description = "Your auth.json from $HOME/.local/share/opencode/auth.json, Required while running tasks." + description = "Your auth.json from $HOME/.local/share/opencode/auth.json, Required for non-interactive authentication" default = "" } From 8efdd3748ef4cf10dd7353fc03327614523a62d4 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Wed, 29 Oct 2025 21:02:29 +0530 Subject: [PATCH 08/17] feat: migrate to opencode config --- registry/coder-labs/modules/opencode/main.tf | 21 ++------- .../modules/opencode/scripts/install.sh | 43 ++++++++----------- .../modules/opencode/scripts/start.sh | 11 ----- 3 files changed, 21 insertions(+), 54 deletions(-) diff --git a/registry/coder-labs/modules/opencode/main.tf b/registry/coder-labs/modules/opencode/main.tf index a3d56ee8e..cedf3da9b 100644 --- a/registry/coder-labs/modules/opencode/main.tf +++ b/registry/coder-labs/modules/opencode/main.tf @@ -119,18 +119,6 @@ variable "continue" { default = false } -variable "model" { - type = string - description = "The default AI model to use. Passwd via --agent" - default = "" -} - -variable "agent" { - type = string - description = "Agent to use. Passed via --agent" - default = "" -} - variable "session_id" { type = string description = "Session id to continue. Passed via --session" @@ -143,13 +131,12 @@ variable "auth_json" { default = "" } -variable "mcp" { +variable "config_json" { type = string - description = "MCP configuration as a JSON string" + description = "OpenCode JSON config. https://opencode.ai/docs/config/" default = "" } - locals { workdir = trimsuffix(var.workdir, "/") app_slug = "opencode" @@ -187,8 +174,6 @@ module "agentapi" { ARG_WORKDIR='${local.workdir}' \ ARG_AI_PROMPT='${base64encode(var.ai_prompt)}' \ - ARG_MODEL='${var.model}' \ - ARG_AGENT='${var.agent}' \ ARG_SESSION_ID='${var.session_id}' \ ARG_REPORT_TASKS='${var.report_tasks}' \ ARG_CONTINUE='${var.continue}' \ @@ -208,7 +193,7 @@ module "agentapi" { ARG_REPORT_TASKS='${var.report_tasks}' \ ARG_WORKDIR='${local.workdir}' \ ARG_AUTH_JSON='${var.auth_json != null ? base64encode(replace(var.auth_json, "'", "'\\''")) : ""}' \ - ARG_MCP_CONFIG='${var.mcp != null ? base64encode(replace(var.mcp, "'", "'\\''")) : ""}' \ + ARG_OPENCODE_CONFIG='${var.config_json != null ? base64encode(replace(var.config_json, "'", "'\\''")) : ""}' \ /tmp/install.sh EOT } diff --git a/registry/coder-labs/modules/opencode/scripts/install.sh b/registry/coder-labs/modules/opencode/scripts/install.sh index 3a58881ef..8ef21e74a 100755 --- a/registry/coder-labs/modules/opencode/scripts/install.sh +++ b/registry/coder-labs/modules/opencode/scripts/install.sh @@ -11,7 +11,7 @@ ARG_MCP_APP_STATUS_SLUG=${ARG_MCP_APP_STATUS_SLUG:-} ARG_OPENCODE_VERSION=${ARG_OPENCODE_VERSION:-latest} ARG_INSTALL_OPENCODE=${ARG_INSTALL_OPENCODE:-true} ARG_AUTH_JSON=$(echo -n "$ARG_AUTH_JSON" | base64 -d 2> /dev/null || echo "") -ARG_MCP_CONFIG=$(echo -n "$ARG_MCP_CONFIG" | base64 -d 2> /dev/null || echo "") +ARG_OPENCODE_CONFIG=$(echo -n "$ARG_OPENCODE_CONFIG" | base64 -d 2> /dev/null || echo "") # Print all received environment variables printf "=== INSTALL CONFIG ===\n" @@ -25,10 +25,10 @@ if [ -n "$ARG_AUTH_JSON" ]; then else printf "ARG_AUTH_JSON: [NOT PROVIDED]\n" fi -if [ -n "$ARG_MCP_CONFIG" ]; then - printf "ARG_MCP_CONFIG: [MCP CONFIG RECEIVED]\n" +if [ -n "$ARG_OPENCODE_CONFIG" ]; then + printf "ARG_OPENCODE_CONFIG: [RECEIVED]\n" else - printf "ARG_MCP_CONFIG: [NOT PROVIDED]\n" + printf "ARG_OPENCODE_CONFIG: [NOT PROVIDED]\n" fi printf "==================================\n" @@ -57,14 +57,22 @@ install_opencode() { } setup_opencode_config() { - local mcp_config_file="$ARG_WORKDIR/opencode.json" + local opencode_config_file="$ARG_WORKDIR/opencode.json" local auth_json_file="$HOME/.local/share/opencode/auth.json" mkdir -p "$(dirname "$auth_json_file")" - mkdir -p "$(dirname "$mcp_config_file")" + mkdir -p "$(dirname "$opencode_config_file")" setup_opencode_auth "$auth_json_file" - setup_mcp_config "$mcp_config_file" + + if [ -n "$ARG_OPENCODE_CONFIG" ]; then + echo "Writing to the config file" + echo "$ARG_OPENCODE_CONFIG" > "$opencode_config_file" + fi + + setup_coder_mcp_server "$opencode_config_file" + + echo "MCP configuration completed: $opencode_config_file" } setup_opencode_auth() { @@ -78,23 +86,8 @@ setup_opencode_auth() { fi } -setup_mcp_config() { - local mcp_config_file="$1" - - echo '{"$schema": "https://opencode.ai/config.json", "mcp": {}}' > "$mcp_config_file" - - if [ -n "$ARG_MCP_CONFIG" ]; then - echo "Adding custom MCP servers..." - echo "$ARG_MCP_CONFIG" > "$mcp_config_file" - fi - - setup_coder_mcp_server "$mcp_config_file" - - echo "MCP configuration completed: $mcp_config_file" -} - setup_coder_mcp_server() { - local mcp_config_file="$1" + local opencode_config_file="$1" # Set environment variables based on task reporting setting if [ "$ARG_REPORT_TASKS" = "true" ]; then @@ -129,8 +122,8 @@ EOF ) temp_file=$(mktemp) - jq --argjson coder_config "$coder_config" '.mcp.coder = $coder_config' "$mcp_config_file" > "$temp_file" - mv "$temp_file" "$mcp_config_file" + jq --argjson coder_config "$coder_config" '.mcp.coder = $coder_config' "$opencode_config_file" > "$temp_file" + mv "$temp_file" "$opencode_config_file" echo "Coder MCP server configuration added" } diff --git a/registry/coder-labs/modules/opencode/scripts/start.sh b/registry/coder-labs/modules/opencode/scripts/start.sh index 0c107a668..42385c6d0 100755 --- a/registry/coder-labs/modules/opencode/scripts/start.sh +++ b/registry/coder-labs/modules/opencode/scripts/start.sh @@ -10,8 +10,6 @@ command_exists() { ARG_WORKDIR=${ARG_WORKDIR:-"$HOME"} ARG_AI_PROMPT=$(echo -n "${ARG_AI_PROMPT:-}" | base64 -d 2> /dev/null || echo "") ARG_REPORT_TASKS=${ARG_REPORT_TASKS:-true} -ARG_MODEL=${ARG_MODEL:-} -ARG_AGENT=${ARG_AGENT:-} ARG_SESSION_ID=${ARG_SESSION_ID:-} ARG_CONTINUE=${ARG_CONTINUE:-false} @@ -19,8 +17,6 @@ ARG_CONTINUE=${ARG_CONTINUE:-false} printf "=== START CONFIG ===\n" printf "ARG_WORKDIR: %s\n" "$ARG_WORKDIR" printf "ARG_REPORT_TASKS: %s\n" "$ARG_REPORT_TASKS" -printf "ARG_MODEL: %s\n" "$ARG_MODEL" -printf "ARG_AGENT: %s\n" "$ARG_AGENT" printf "ARG_CONTINUE: %s\n" "$ARG_CONTINUE" printf "ARG_SESSION_ID: %s\n" "$ARG_SESSION_ID" if [ -n "$ARG_AI_PROMPT" ]; then @@ -40,13 +36,6 @@ validate_opencode_installation() { } build_opencode_args() { - if [ -n "$ARG_MODEL" ]; then - OPENCODE_ARGS+=(--model "$ARG_MODEL") - fi - - if [ -n "$ARG_AGENT" ]; then - OPENCODE_ARGS+=(--agent "$ARG_AGENT") - fi if [ -n "$ARG_SESSION_ID" ]; then OPENCODE_ARGS+=(--session "$ARG_SESSION_ID") From 5493134107a52ad6f1400e2737db7f5ec2132646 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Wed, 29 Oct 2025 21:50:52 +0530 Subject: [PATCH 09/17] feat: make config global --- .../coder-labs/modules/opencode/README.md | 29 ++++++++----------- .../modules/opencode/scripts/install.sh | 2 +- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/registry/coder-labs/modules/opencode/README.md b/registry/coder-labs/modules/opencode/README.md index cca429d73..68dfe669c 100644 --- a/registry/coder-labs/modules/opencode/README.md +++ b/registry/coder-labs/modules/opencode/README.md @@ -39,7 +39,6 @@ module "opencode" { workdir = "/home/coder/project" ai_prompt = coder_ai_task.task.prompt - model = "anthropic/claude-sonnet-4-20250514" auth_json = <<-EOT { @@ -54,29 +53,24 @@ module "opencode" { } EOT - mcp = jsonencode({ - mcpServers = { + config_json = jsonencode({ + "$schema" = "https://opencode.ai/config.json" + mcp = { filesystem = { - command = "npx" - args = ["-y", "@modelcontextprotocol/server-filesystem", "/home/coder/projects"] - description = "Provides file system access to the workspace" - name = "Filesystem" - timeout = 3000 + command = ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/home/coder/projects"] + enabled = true type = "local" - tools = ["*"] - trust = true + environment = { + SOME_VARIABLE_X = "value" + } } playwright = { - command = "npx" - args = ["-y", "@playwright/mcp@latest", "--headless", "--isolated"] - description = "Browser automation for testing and previewing changes" - name = "Playwright" - timeout = 5000 + command = ["npx", "-y", "@playwright/mcp@latest", "--headless", "--isolated"] + enabled = true type = "local" - tools = ["*"] - trust = false } } + model = "anthropic/claude-sonnet-4-20250514" }) pre_install_script = <<-EOT @@ -108,6 +102,7 @@ If you encounter any issues, check the log files in the `~/.opencode-module` dir ## References +- [Opencode JSON Config](https://opencode.ai/docs/config/) - [OpenCode Documentation](https://opencode.ai/docs) - [AgentAPI Documentation](https://github.com/coder/agentapi) - [Coder AI Agents Guide](https://coder.com/docs/tutorials/ai-agents) diff --git a/registry/coder-labs/modules/opencode/scripts/install.sh b/registry/coder-labs/modules/opencode/scripts/install.sh index 8ef21e74a..c9d78ce20 100755 --- a/registry/coder-labs/modules/opencode/scripts/install.sh +++ b/registry/coder-labs/modules/opencode/scripts/install.sh @@ -57,7 +57,7 @@ install_opencode() { } setup_opencode_config() { - local opencode_config_file="$ARG_WORKDIR/opencode.json" + local opencode_config_file="$HOME/.config/opencode/opencode.json" local auth_json_file="$HOME/.local/share/opencode/auth.json" mkdir -p "$(dirname "$auth_json_file")" From 6a5f539b8285f845014b8fc9015e31a87d992bf9 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Wed, 29 Oct 2025 22:16:32 +0530 Subject: [PATCH 10/17] chore --- .../coder-labs/modules/opencode/README.md | 16 ++-- .../coder-labs/modules/opencode/main.test.ts | 46 ++++------- .../modules/opencode/main.tftest.hcl | 82 ++++++++++--------- 3 files changed, 69 insertions(+), 75 deletions(-) diff --git a/registry/coder-labs/modules/opencode/README.md b/registry/coder-labs/modules/opencode/README.md index 68dfe669c..c06c12715 100644 --- a/registry/coder-labs/modules/opencode/README.md +++ b/registry/coder-labs/modules/opencode/README.md @@ -39,7 +39,7 @@ module "opencode" { workdir = "/home/coder/project" ai_prompt = coder_ai_task.task.prompt - + auth_json = <<-EOT { "google": { @@ -57,22 +57,22 @@ EOT "$schema" = "https://opencode.ai/config.json" mcp = { filesystem = { - command = ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/home/coder/projects"] - enabled = true - type = "local" + command = ["npx", "-y", "@modelcontextprotocol/server-filesystem", "/home/coder/projects"] + enabled = true + type = "local" environment = { SOME_VARIABLE_X = "value" } } playwright = { - command = ["npx", "-y", "@playwright/mcp@latest", "--headless", "--isolated"] - enabled = true - type = "local" + command = ["npx", "-y", "@playwright/mcp@latest", "--headless", "--isolated"] + enabled = true + type = "local" } } model = "anthropic/claude-sonnet-4-20250514" }) - + pre_install_script = <<-EOT #!/bin/bash curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - diff --git a/registry/coder-labs/modules/opencode/main.test.ts b/registry/coder-labs/modules/opencode/main.test.ts index 07dc65831..dec42a592 100644 --- a/registry/coder-labs/modules/opencode/main.test.ts +++ b/registry/coder-labs/modules/opencode/main.test.ts @@ -146,27 +146,30 @@ describe("opencode", async () => { expect(authFile).toContain("test-user"); }); - test("opencode-mcp-config", async () => { - const mcpConfig = JSON.stringify({ + test("opencode-config-json", async () => { + const configJson = JSON.stringify({ + $schema: "https://opencode.ai/config.json", mcp: { test: { command: ["test-cmd"], type: "local", }, }, + model: "anthropic/claude-sonnet-4-20250514", }); const { id } = await setup({ moduleVariables: { - mcp: mcpConfig, + config_json: configJson, }, }); await execModuleScript(id); const configFile = await readFileContainer( id, - "/home/coder/project/opencode.json", + "/home/coder/.config/opencode/opencode.json", ); expect(configFile).toContain("test-cmd"); + expect(configFile).toContain("anthropic/claude-sonnet-4-20250514"); }); test("opencode-ai-prompt", async () => { @@ -186,11 +189,10 @@ describe("opencode", async () => { expect(resp.stdout).toContain(prompt); }); - test("opencode-model", async () => { - const model = "gpt-4"; + test("opencode-continue-flag", async () => { const { id } = await setup({ moduleVariables: { - model: model, + continue: "true", ai_prompt: "test prompt", }, }); @@ -201,14 +203,15 @@ describe("opencode", async () => { "-c", "cat /home/coder/.opencode-module/agentapi-start.log", ]); - expect(startLog.stdout).toContain(`--model ${model}`); + expect(startLog.stdout).toContain("--continue"); }); - test("opencode-agent", async () => { - const agent = "test-agent"; + test("opencode-continue-with-session-id", async () => { + const sessionId = "session-123"; const { id } = await setup({ moduleVariables: { - agent: agent, + continue: "true", + session_id: sessionId, ai_prompt: "test prompt", }, }); @@ -219,7 +222,8 @@ describe("opencode", async () => { "-c", "cat /home/coder/.opencode-module/agentapi-start.log", ]); - expect(startLog.stdout).toContain(`--agent ${agent}`); + expect(startLog.stdout).toContain("--continue"); + expect(startLog.stdout).toContain(`--session ${sessionId}`); }); test("opencode-session-id", async () => { @@ -330,24 +334,6 @@ describe("opencode", async () => { expect(resp).toContain(workdir); }); - test("coder-mcp-config-created", async () => { - const { id } = await setup({ - moduleVariables: { - install_opencode: "false", // Don't need to install opencode to test MCP config creation - }, - }); - await execModuleScript(id); - - const mcpConfig = await readFileContainer( - id, - "/home/coder/project/opencode.json", - ); - expect(mcpConfig).toContain("mcp"); - expect(mcpConfig).toContain("coder"); - expect(mcpConfig).toContain("CODER_MCP_APP_STATUS_SLUG"); - expect(mcpConfig).toContain("CODER_MCP_AI_AGENTAPI_URL"); - }); - test("subdomain-enabled", async () => { const { id } = await setup({ moduleVariables: { diff --git a/registry/coder-labs/modules/opencode/main.tftest.hcl b/registry/coder-labs/modules/opencode/main.tftest.hcl index 5d2485ff0..c0b4b4d61 100644 --- a/registry/coder-labs/modules/opencode/main.tftest.hcl +++ b/registry/coder-labs/modules/opencode/main.tftest.hcl @@ -65,6 +65,11 @@ run "defaults_are_correct" { condition = local.workdir == "/home/coder/project" error_message = "Workdir should be trimmed of trailing slash" } + + assert { + condition = var.continue == false + error_message = "Continue flag should be disabled by default" + } } run "workdir_trailing_slash_trimmed" { @@ -172,9 +177,8 @@ run "ai_configuration_variables" { agent_id = "test-agent" workdir = "/home/coder/project" ai_prompt = "This is a test prompt" - model = "gpt-4" - agent = "test-agent-name" session_id = "session-123" + continue = true } assert { @@ -183,18 +187,13 @@ run "ai_configuration_variables" { } assert { - condition = var.model == "gpt-4" - error_message = "Model should be set correctly" + condition = var.session_id == "session-123" + error_message = "Session ID should be set correctly" } assert { - condition = var.agent == "test-agent-name" - error_message = "Agent should be set correctly" - } - - assert { - condition = var.session_id == "session-123" - error_message = "Session ID should be set correctly" + condition = var.continue == true + error_message = "Continue flag should be set correctly" } } @@ -218,23 +217,23 @@ run "auth_json_configuration" { } } -run "mcp_configuration" { +run "config_json_configuration" { command = plan variables { - agent_id = "test-agent" - workdir = "/home/coder/project" - mcp = "{\"mcp\": {\"test\": {\"command\": \"test-cmd\", \"type\": \"local\"}}}" + agent_id = "test-agent" + workdir = "/home/coder/project" + config_json = "{\"$schema\": \"https://opencode.ai/config.json\", \"mcp\": {\"test\": {\"command\": [\"test-cmd\"], \"type\": \"local\"}}, \"model\": \"anthropic/claude-sonnet-4-20250514\"}" } assert { - condition = var.mcp != "" - error_message = "MCP configuration should be set" + condition = var.config_json != "" + error_message = "OpenCode JSON configuration should be set" } assert { - condition = can(jsondecode(var.mcp)) - error_message = "MCP configuration should be valid JSON" + condition = can(jsondecode(var.config_json)) + error_message = "OpenCode JSON configuration should be valid JSON" } } @@ -324,14 +323,13 @@ run "empty_variables_handled_correctly" { command = plan variables { - agent_id = "test-agent" - workdir = "/home/coder/project" - ai_prompt = "" - model = "" - agent = "" - session_id = "" - auth_json = "" - mcp = "" + agent_id = "test-agent" + workdir = "/home/coder/project" + ai_prompt = "" + session_id = "" + auth_json = "" + config_json = "" + continue = false } assert { @@ -340,27 +338,37 @@ run "empty_variables_handled_correctly" { } assert { - condition = var.model == "" - error_message = "Empty model should be handled correctly" + condition = var.session_id == "" + error_message = "Empty session ID should be handled correctly" } assert { - condition = var.agent == "" - error_message = "Empty agent should be handled correctly" + condition = var.auth_json == "" + error_message = "Empty auth JSON should be handled correctly" } assert { - condition = var.session_id == "" - error_message = "Empty session ID should be handled correctly" + condition = var.config_json == "" + error_message = "Empty config JSON should be handled correctly" } assert { - condition = var.auth_json == "" - error_message = "Empty auth JSON should be handled correctly" + condition = var.continue == false + error_message = "Continue flag default should be handled correctly" + } +} + +run "continue_flag_configuration" { + command = plan + + variables { + agent_id = "test-agent" + workdir = "/home/coder/project" + continue = true } assert { - condition = var.mcp == "" - error_message = "Empty MCP config should be handled correctly" + condition = var.continue == true + error_message = "Continue flag should be enabled when specified" } } \ No newline at end of file From c157295ef1208f0f0ada33c635d76f23044c5ebe Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Thu, 30 Oct 2025 15:27:15 +0530 Subject: [PATCH 11/17] chore --- registry/coder-labs/modules/opencode/scripts/start.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/registry/coder-labs/modules/opencode/scripts/start.sh b/registry/coder-labs/modules/opencode/scripts/start.sh index 42385c6d0..5f65eb23f 100755 --- a/registry/coder-labs/modules/opencode/scripts/start.sh +++ b/registry/coder-labs/modules/opencode/scripts/start.sh @@ -27,6 +27,7 @@ fi printf "==================================\n" OPENCODE_ARGS=() +AGENTAPI_ARGS=() validate_opencode_installation() { if ! command_exists opencode; then @@ -51,7 +52,7 @@ build_opencode_args() { else PROMPT="$ARG_AI_PROMPT" fi - OPENCODE_ARGS+=(--prompt "$PROMPT") + AGENTAPI_ARGS+=(--I "$PROMPT") fi } @@ -62,7 +63,7 @@ start_agentapi() { build_opencode_args printf "Running OpenCode with args: %s\n" "${OPENCODE_ARGS[*]}" - agentapi server --type opencode --term-width 67 --term-height 1190 -- opencode "${OPENCODE_ARGS[@]}" + agentapi server "${AGENTAPI_ARGS[@]}" --type opencode --term-width 67 --term-height 1190 -- opencode "${OPENCODE_ARGS[@]}" } validate_opencode_installation From 8b560e0f19c62862edefd5297fb1f1e71a5be640 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Thu, 30 Oct 2025 15:31:26 +0530 Subject: [PATCH 12/17] chore --- registry/coder-labs/modules/opencode/scripts/start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder-labs/modules/opencode/scripts/start.sh b/registry/coder-labs/modules/opencode/scripts/start.sh index 5f65eb23f..113ee0354 100755 --- a/registry/coder-labs/modules/opencode/scripts/start.sh +++ b/registry/coder-labs/modules/opencode/scripts/start.sh @@ -52,7 +52,7 @@ build_opencode_args() { else PROMPT="$ARG_AI_PROMPT" fi - AGENTAPI_ARGS+=(--I "$PROMPT") + AGENTAPI_ARGS+=(-I "$PROMPT") fi } From c4018ec79733c05473917c08a4316c656c35f0ec Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Thu, 30 Oct 2025 15:38:07 +0530 Subject: [PATCH 13/17] revert --- registry/coder-labs/modules/opencode/scripts/start.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/registry/coder-labs/modules/opencode/scripts/start.sh b/registry/coder-labs/modules/opencode/scripts/start.sh index 113ee0354..42385c6d0 100755 --- a/registry/coder-labs/modules/opencode/scripts/start.sh +++ b/registry/coder-labs/modules/opencode/scripts/start.sh @@ -27,7 +27,6 @@ fi printf "==================================\n" OPENCODE_ARGS=() -AGENTAPI_ARGS=() validate_opencode_installation() { if ! command_exists opencode; then @@ -52,7 +51,7 @@ build_opencode_args() { else PROMPT="$ARG_AI_PROMPT" fi - AGENTAPI_ARGS+=(-I "$PROMPT") + OPENCODE_ARGS+=(--prompt "$PROMPT") fi } @@ -63,7 +62,7 @@ start_agentapi() { build_opencode_args printf "Running OpenCode with args: %s\n" "${OPENCODE_ARGS[*]}" - agentapi server "${AGENTAPI_ARGS[@]}" --type opencode --term-width 67 --term-height 1190 -- opencode "${OPENCODE_ARGS[@]}" + agentapi server --type opencode --term-width 67 --term-height 1190 -- opencode "${OPENCODE_ARGS[@]}" } validate_opencode_installation From fbb9647112cc206e1b2c6f9607414ab77c1d7a32 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Thu, 30 Oct 2025 22:24:55 +0530 Subject: [PATCH 14/17] feat: install only --- .../modules/opencode/scripts/install.sh | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/registry/coder-labs/modules/opencode/scripts/install.sh b/registry/coder-labs/modules/opencode/scripts/install.sh index c9d78ce20..63cd83260 100755 --- a/registry/coder-labs/modules/opencode/scripts/install.sh +++ b/registry/coder-labs/modules/opencode/scripts/install.sh @@ -70,7 +70,9 @@ setup_opencode_config() { echo "$ARG_OPENCODE_CONFIG" > "$opencode_config_file" fi - setup_coder_mcp_server "$opencode_config_file" + if [ "$ARG_REPORT_TASKS" = "true" ]; then + setup_coder_mcp_server "$opencode_config_file" + fi echo "MCP configuration completed: $opencode_config_file" } @@ -90,16 +92,10 @@ setup_coder_mcp_server() { local opencode_config_file="$1" # Set environment variables based on task reporting setting - if [ "$ARG_REPORT_TASKS" = "true" ]; then - echo "Configuring OpenCode task reporting" - export CODER_MCP_APP_STATUS_SLUG="$ARG_MCP_APP_STATUS_SLUG" - export CODER_MCP_AI_AGENTAPI_URL="http://localhost:3284" - echo "Coder integration configured for task reporting" - else - echo "Task reporting disabled or no app status slug provided." - export CODER_MCP_APP_STATUS_SLUG="" - export CODER_MCP_AI_AGENTAPI_URL="" - fi + echo "Configuring OpenCode task reporting" + export CODER_MCP_APP_STATUS_SLUG="$ARG_MCP_APP_STATUS_SLUG" + export CODER_MCP_AI_AGENTAPI_URL="http://localhost:3284" + echo "Coder integration configured for task reporting" # Add coder MCP server configuration to the JSON file echo "Adding Coder MCP server configuration" @@ -116,6 +112,7 @@ setup_coder_mcp_server() { "CODER_MCP_AI_AGENTAPI_URL": "${CODER_MCP_AI_AGENTAPI_URL:-}", "CODER_AGENT_URL": "${CODER_AGENT_URL:-}", "CODER_AGENT_TOKEN": "${CODER_AGENT_TOKEN:-}" + "CODER_MCP_ALLOWED_TOOLS": "coder_report_task" } } EOF From 3c99534a826e94b2a943cb7e41f78e65755da9ea Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Mon, 3 Nov 2025 07:37:36 +0530 Subject: [PATCH 15/17] chore: fix json --- registry/coder-labs/modules/opencode/scripts/install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/registry/coder-labs/modules/opencode/scripts/install.sh b/registry/coder-labs/modules/opencode/scripts/install.sh index 63cd83260..6d5531082 100755 --- a/registry/coder-labs/modules/opencode/scripts/install.sh +++ b/registry/coder-labs/modules/opencode/scripts/install.sh @@ -111,7 +111,7 @@ setup_coder_mcp_server() { "CODER_MCP_APP_STATUS_SLUG": "${CODER_MCP_APP_STATUS_SLUG:-}", "CODER_MCP_AI_AGENTAPI_URL": "${CODER_MCP_AI_AGENTAPI_URL:-}", "CODER_AGENT_URL": "${CODER_AGENT_URL:-}", - "CODER_AGENT_TOKEN": "${CODER_AGENT_TOKEN:-}" + "CODER_AGENT_TOKEN": "${CODER_AGENT_TOKEN:-}", "CODER_MCP_ALLOWED_TOOLS": "coder_report_task" } } From 24120e433c540c2f4e56cdd31edc24d78046d968 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Mon, 3 Nov 2025 07:57:05 +0530 Subject: [PATCH 16/17] chore: use -I flag --- registry/coder-labs/modules/opencode/scripts/start.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/registry/coder-labs/modules/opencode/scripts/start.sh b/registry/coder-labs/modules/opencode/scripts/start.sh index 42385c6d0..113ee0354 100755 --- a/registry/coder-labs/modules/opencode/scripts/start.sh +++ b/registry/coder-labs/modules/opencode/scripts/start.sh @@ -27,6 +27,7 @@ fi printf "==================================\n" OPENCODE_ARGS=() +AGENTAPI_ARGS=() validate_opencode_installation() { if ! command_exists opencode; then @@ -51,7 +52,7 @@ build_opencode_args() { else PROMPT="$ARG_AI_PROMPT" fi - OPENCODE_ARGS+=(--prompt "$PROMPT") + AGENTAPI_ARGS+=(-I "$PROMPT") fi } @@ -62,7 +63,7 @@ start_agentapi() { build_opencode_args printf "Running OpenCode with args: %s\n" "${OPENCODE_ARGS[*]}" - agentapi server --type opencode --term-width 67 --term-height 1190 -- opencode "${OPENCODE_ARGS[@]}" + agentapi server "${AGENTAPI_ARGS[@]}" --type opencode --term-width 67 --term-height 1190 -- opencode "${OPENCODE_ARGS[@]}" } validate_opencode_installation From e92f2685c829345850150d6f0a8937f50624ed63 Mon Sep 17 00:00:00 2001 From: 35C4n0r Date: Mon, 3 Nov 2025 22:57:03 +0530 Subject: [PATCH 17/17] wip --- registry/coder-labs/modules/opencode/scripts/start.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/registry/coder-labs/modules/opencode/scripts/start.sh b/registry/coder-labs/modules/opencode/scripts/start.sh index 113ee0354..c3c51beb3 100755 --- a/registry/coder-labs/modules/opencode/scripts/start.sh +++ b/registry/coder-labs/modules/opencode/scripts/start.sh @@ -63,6 +63,7 @@ start_agentapi() { build_opencode_args printf "Running OpenCode with args: %s\n" "${OPENCODE_ARGS[*]}" + echo agentapi server "${AGENTAPI_ARGS[@]}" --type opencode --term-width 67 --term-height 1190 -- opencode "${OPENCODE_ARGS[@]}" agentapi server "${AGENTAPI_ARGS[@]}" --type opencode --term-width 67 --term-height 1190 -- opencode "${OPENCODE_ARGS[@]}" }