synapsexcoder 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.opencode/opencode.jsonc +102 -0
- package/README.md +353 -0
- package/dist/agents/agent-config-manager.d.ts +58 -0
- package/dist/agents/agent-config-manager.d.ts.map +1 -0
- package/dist/agents/agent-config-manager.js +313 -0
- package/dist/agents/agent-config-manager.js.map +1 -0
- package/dist/agents/base-agents.d.ts +352 -0
- package/dist/agents/base-agents.d.ts.map +1 -0
- package/dist/agents/base-agents.js +3961 -0
- package/dist/agents/base-agents.js.map +1 -0
- package/dist/agents/gated-subagent.d.ts +126 -0
- package/dist/agents/gated-subagent.d.ts.map +1 -0
- package/dist/agents/gated-subagent.js +591 -0
- package/dist/agents/gated-subagent.js.map +1 -0
- package/dist/agents/gated-subagents.d.ts +130 -0
- package/dist/agents/gated-subagents.d.ts.map +1 -0
- package/dist/agents/gated-subagents.js +2014 -0
- package/dist/agents/gated-subagents.js.map +1 -0
- package/dist/agents/internal-gatekeeper.d.ts +167 -0
- package/dist/agents/internal-gatekeeper.d.ts.map +1 -0
- package/dist/agents/internal-gatekeeper.js +1130 -0
- package/dist/agents/internal-gatekeeper.js.map +1 -0
- package/dist/agents/verification-agent.d.ts +86 -0
- package/dist/agents/verification-agent.d.ts.map +1 -0
- package/dist/agents/verification-agent.js +211 -0
- package/dist/agents/verification-agent.js.map +1 -0
- package/dist/analytics/analytics-types.d.ts +113 -0
- package/dist/analytics/analytics-types.d.ts.map +1 -0
- package/dist/analytics/analytics-types.js +8 -0
- package/dist/analytics/analytics-types.js.map +1 -0
- package/dist/analytics/dashboard-generator.d.ts +35 -0
- package/dist/analytics/dashboard-generator.d.ts.map +1 -0
- package/dist/analytics/dashboard-generator.js +365 -0
- package/dist/analytics/dashboard-generator.js.map +1 -0
- package/dist/analytics/index.d.ts +12 -0
- package/dist/analytics/index.d.ts.map +1 -0
- package/dist/analytics/index.js +12 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics/metrics-aggregator.d.ts +88 -0
- package/dist/analytics/metrics-aggregator.d.ts.map +1 -0
- package/dist/analytics/metrics-aggregator.js +280 -0
- package/dist/analytics/metrics-aggregator.js.map +1 -0
- package/dist/cli/index.d.ts +36 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +2677 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/normalize_patch.d.ts +3 -0
- package/dist/cli/normalize_patch.d.ts.map +1 -0
- package/dist/cli/normalize_patch.js +34 -0
- package/dist/cli/normalize_patch.js.map +1 -0
- package/dist/commands/command-processor.d.ts +58 -0
- package/dist/commands/command-processor.d.ts.map +1 -0
- package/dist/commands/command-processor.js +796 -0
- package/dist/commands/command-processor.js.map +1 -0
- package/dist/config/compliance-checker.d.ts +93 -0
- package/dist/config/compliance-checker.d.ts.map +1 -0
- package/dist/config/compliance-checker.js +424 -0
- package/dist/config/compliance-checker.js.map +1 -0
- package/dist/config/enterprise-config.d.ts +173 -0
- package/dist/config/enterprise-config.d.ts.map +1 -0
- package/dist/config/enterprise-config.js +190 -0
- package/dist/config/enterprise-config.js.map +1 -0
- package/dist/config/index.d.ts +13 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +11 -0
- package/dist/config/index.js.map +1 -0
- package/dist/context/context-system.d.ts +97 -0
- package/dist/context/context-system.d.ts.map +1 -0
- package/dist/context/context-system.js +880 -0
- package/dist/context/context-system.js.map +1 -0
- package/dist/context/store.d.ts +123 -0
- package/dist/context/store.d.ts.map +1 -0
- package/dist/context/store.js +281 -0
- package/dist/context/store.js.map +1 -0
- package/dist/dasp/dasp-controller.d.ts +83 -0
- package/dist/dasp/dasp-controller.d.ts.map +1 -0
- package/dist/dasp/dasp-controller.js +190 -0
- package/dist/dasp/dasp-controller.js.map +1 -0
- package/dist/dasp/feedback-adapter.d.ts +56 -0
- package/dist/dasp/feedback-adapter.d.ts.map +1 -0
- package/dist/dasp/feedback-adapter.js +158 -0
- package/dist/dasp/feedback-adapter.js.map +1 -0
- package/dist/dasp/index.d.ts +14 -0
- package/dist/dasp/index.d.ts.map +1 -0
- package/dist/dasp/index.js +10 -0
- package/dist/dasp/index.js.map +1 -0
- package/dist/dasp/prompt-templates.d.ts +38 -0
- package/dist/dasp/prompt-templates.d.ts.map +1 -0
- package/dist/dasp/prompt-templates.js +406 -0
- package/dist/dasp/prompt-templates.js.map +1 -0
- package/dist/dasp/vault-rag-provider.d.ts +51 -0
- package/dist/dasp/vault-rag-provider.d.ts.map +1 -0
- package/dist/dasp/vault-rag-provider.js +125 -0
- package/dist/dasp/vault-rag-provider.js.map +1 -0
- package/dist/distribution/cli-distribution.d.ts +68 -0
- package/dist/distribution/cli-distribution.d.ts.map +1 -0
- package/dist/distribution/cli-distribution.js +941 -0
- package/dist/distribution/cli-distribution.js.map +1 -0
- package/dist/docs/doc-generator.d.ts +78 -0
- package/dist/docs/doc-generator.d.ts.map +1 -0
- package/dist/docs/doc-generator.js +297 -0
- package/dist/docs/doc-generator.js.map +1 -0
- package/dist/docs/index.d.ts +13 -0
- package/dist/docs/index.d.ts.map +1 -0
- package/dist/docs/index.js +11 -0
- package/dist/docs/index.js.map +1 -0
- package/dist/docs/site-builder.d.ts +58 -0
- package/dist/docs/site-builder.d.ts.map +1 -0
- package/dist/docs/site-builder.js +229 -0
- package/dist/docs/site-builder.js.map +1 -0
- package/dist/ecosystem/adapters/claude-adapter.d.ts +29 -0
- package/dist/ecosystem/adapters/claude-adapter.d.ts.map +1 -0
- package/dist/ecosystem/adapters/claude-adapter.js +116 -0
- package/dist/ecosystem/adapters/claude-adapter.js.map +1 -0
- package/dist/ecosystem/adapters/cursor-adapter.d.ts +27 -0
- package/dist/ecosystem/adapters/cursor-adapter.d.ts.map +1 -0
- package/dist/ecosystem/adapters/cursor-adapter.js +93 -0
- package/dist/ecosystem/adapters/cursor-adapter.js.map +1 -0
- package/dist/ecosystem/adapters/v0-adapter.d.ts +30 -0
- package/dist/ecosystem/adapters/v0-adapter.d.ts.map +1 -0
- package/dist/ecosystem/adapters/v0-adapter.js +112 -0
- package/dist/ecosystem/adapters/v0-adapter.js.map +1 -0
- package/dist/ecosystem/ecosystem-router.d.ts +80 -0
- package/dist/ecosystem/ecosystem-router.d.ts.map +1 -0
- package/dist/ecosystem/ecosystem-router.js +241 -0
- package/dist/ecosystem/ecosystem-router.js.map +1 -0
- package/dist/ecosystem/ecosystem-types.d.ts +94 -0
- package/dist/ecosystem/ecosystem-types.d.ts.map +1 -0
- package/dist/ecosystem/ecosystem-types.js +27 -0
- package/dist/ecosystem/ecosystem-types.js.map +1 -0
- package/dist/ecosystem/index.d.ts +10 -0
- package/dist/ecosystem/index.d.ts.map +1 -0
- package/dist/ecosystem/index.js +9 -0
- package/dist/ecosystem/index.js.map +1 -0
- package/dist/integration/agentic-integration.d.ts +73 -0
- package/dist/integration/agentic-integration.d.ts.map +1 -0
- package/dist/integration/agentic-integration.js +253 -0
- package/dist/integration/agentic-integration.js.map +1 -0
- package/dist/integration/background-agents-integration.d.ts +54 -0
- package/dist/integration/background-agents-integration.d.ts.map +1 -0
- package/dist/integration/background-agents-integration.js +225 -0
- package/dist/integration/background-agents-integration.js.map +1 -0
- package/dist/integration/dcp-integration.d.ts +81 -0
- package/dist/integration/dcp-integration.d.ts.map +1 -0
- package/dist/integration/dcp-integration.js +189 -0
- package/dist/integration/dcp-integration.js.map +1 -0
- package/dist/integration/firecrawl-integration.d.ts +61 -0
- package/dist/integration/firecrawl-integration.d.ts.map +1 -0
- package/dist/integration/firecrawl-integration.js +246 -0
- package/dist/integration/firecrawl-integration.js.map +1 -0
- package/dist/integration/index.d.ts +40 -0
- package/dist/integration/index.d.ts.map +1 -0
- package/dist/integration/index.js +43 -0
- package/dist/integration/index.js.map +1 -0
- package/dist/integration/integration-hub.d.ts +43 -0
- package/dist/integration/integration-hub.d.ts.map +1 -0
- package/dist/integration/integration-hub.js +507 -0
- package/dist/integration/integration-hub.js.map +1 -0
- package/dist/integration/integration-loader.d.ts +42 -0
- package/dist/integration/integration-loader.d.ts.map +1 -0
- package/dist/integration/integration-loader.js +240 -0
- package/dist/integration/integration-loader.js.map +1 -0
- package/dist/integration/md-table-formatter-integration.d.ts +41 -0
- package/dist/integration/md-table-formatter-integration.d.ts.map +1 -0
- package/dist/integration/md-table-formatter-integration.js +183 -0
- package/dist/integration/md-table-formatter-integration.js.map +1 -0
- package/dist/integration/native/agentic/agentic-engine.d.ts +52 -0
- package/dist/integration/native/agentic/agentic-engine.d.ts.map +1 -0
- package/dist/integration/native/agentic/agentic-engine.js +267 -0
- package/dist/integration/native/agentic/agentic-engine.js.map +1 -0
- package/dist/integration/native/background/background-engine.d.ts +62 -0
- package/dist/integration/native/background/background-engine.d.ts.map +1 -0
- package/dist/integration/native/background/background-engine.js +167 -0
- package/dist/integration/native/background/background-engine.js.map +1 -0
- package/dist/integration/native/dcp/dcp-engine.d.ts +55 -0
- package/dist/integration/native/dcp/dcp-engine.d.ts.map +1 -0
- package/dist/integration/native/dcp/dcp-engine.js +168 -0
- package/dist/integration/native/dcp/dcp-engine.js.map +1 -0
- package/dist/integration/native/firecrawl/firecrawl-engine.d.ts +66 -0
- package/dist/integration/native/firecrawl/firecrawl-engine.d.ts.map +1 -0
- package/dist/integration/native/firecrawl/firecrawl-engine.js +221 -0
- package/dist/integration/native/firecrawl/firecrawl-engine.js.map +1 -0
- package/dist/integration/native/formatter/formatter-engine.d.ts +47 -0
- package/dist/integration/native/formatter/formatter-engine.d.ts.map +1 -0
- package/dist/integration/native/formatter/formatter-engine.js +130 -0
- package/dist/integration/native/formatter/formatter-engine.js.map +1 -0
- package/dist/integration/native/index.d.ts +41 -0
- package/dist/integration/native/index.d.ts.map +1 -0
- package/dist/integration/native/index.js +80 -0
- package/dist/integration/native/index.js.map +1 -0
- package/dist/integration/native/orchestration/orchestration-engine.d.ts +62 -0
- package/dist/integration/native/orchestration/orchestration-engine.d.ts.map +1 -0
- package/dist/integration/native/orchestration/orchestration-engine.js +177 -0
- package/dist/integration/native/orchestration/orchestration-engine.js.map +1 -0
- package/dist/integration/native/pty/pty-engine.d.ts +45 -0
- package/dist/integration/native/pty/pty-engine.d.ts.map +1 -0
- package/dist/integration/native/pty/pty-engine.js +103 -0
- package/dist/integration/native/pty/pty-engine.js.map +1 -0
- package/dist/integration/native/shell-strategy.d.ts +60 -0
- package/dist/integration/native/shell-strategy.d.ts.map +1 -0
- package/dist/integration/native/shell-strategy.js +131 -0
- package/dist/integration/native/shell-strategy.js.map +1 -0
- package/dist/integration/native/skillful/skillful-engine.d.ts +53 -0
- package/dist/integration/native/skillful/skillful-engine.d.ts.map +1 -0
- package/dist/integration/native/skillful/skillful-engine.js +127 -0
- package/dist/integration/native/skillful/skillful-engine.js.map +1 -0
- package/dist/integration/native/subtask2/subtask2-engine.d.ts +50 -0
- package/dist/integration/native/subtask2/subtask2-engine.d.ts.map +1 -0
- package/dist/integration/native/subtask2/subtask2-engine.js +158 -0
- package/dist/integration/native/subtask2/subtask2-engine.js.map +1 -0
- package/dist/integration/native/supermemory/supermemory-engine.d.ts +63 -0
- package/dist/integration/native/supermemory/supermemory-engine.d.ts.map +1 -0
- package/dist/integration/native/supermemory/supermemory-engine.js +127 -0
- package/dist/integration/native/supermemory/supermemory-engine.js.map +1 -0
- package/dist/integration/native/workspace/workspace-engine.d.ts +75 -0
- package/dist/integration/native/workspace/workspace-engine.d.ts.map +1 -0
- package/dist/integration/native/workspace/workspace-engine.js +216 -0
- package/dist/integration/native/workspace/workspace-engine.js.map +1 -0
- package/dist/integration/oh-my-opencode-integration.d.ts +59 -0
- package/dist/integration/oh-my-opencode-integration.d.ts.map +1 -0
- package/dist/integration/oh-my-opencode-integration.js +180 -0
- package/dist/integration/oh-my-opencode-integration.js.map +1 -0
- package/dist/integration/openagents-control-integration.d.ts +81 -0
- package/dist/integration/openagents-control-integration.d.ts.map +1 -0
- package/dist/integration/openagents-control-integration.js +273 -0
- package/dist/integration/openagents-control-integration.js.map +1 -0
- package/dist/integration/pty-integration.d.ts +64 -0
- package/dist/integration/pty-integration.d.ts.map +1 -0
- package/dist/integration/pty-integration.js +180 -0
- package/dist/integration/pty-integration.js.map +1 -0
- package/dist/integration/shell-strategy-integration.d.ts +26 -0
- package/dist/integration/shell-strategy-integration.d.ts.map +1 -0
- package/dist/integration/shell-strategy-integration.js +110 -0
- package/dist/integration/shell-strategy-integration.js.map +1 -0
- package/dist/integration/skillful-integration.d.ts +74 -0
- package/dist/integration/skillful-integration.d.ts.map +1 -0
- package/dist/integration/skillful-integration.js +317 -0
- package/dist/integration/skillful-integration.js.map +1 -0
- package/dist/integration/subtask2-integration.d.ts +71 -0
- package/dist/integration/subtask2-integration.d.ts.map +1 -0
- package/dist/integration/subtask2-integration.js +240 -0
- package/dist/integration/subtask2-integration.js.map +1 -0
- package/dist/integration/supermemory-integration.d.ts +82 -0
- package/dist/integration/supermemory-integration.d.ts.map +1 -0
- package/dist/integration/supermemory-integration.js +252 -0
- package/dist/integration/supermemory-integration.js.map +1 -0
- package/dist/integration/types.d.ts +218 -0
- package/dist/integration/types.d.ts.map +1 -0
- package/dist/integration/types.js +5 -0
- package/dist/integration/types.js.map +1 -0
- package/dist/integration/workspace-integration.d.ts +46 -0
- package/dist/integration/workspace-integration.d.ts.map +1 -0
- package/dist/integration/workspace-integration.js +181 -0
- package/dist/integration/workspace-integration.js.map +1 -0
- package/dist/knowledge-vault/deepwiki-sync.d.ts +99 -0
- package/dist/knowledge-vault/deepwiki-sync.d.ts.map +1 -0
- package/dist/knowledge-vault/deepwiki-sync.js +381 -0
- package/dist/knowledge-vault/deepwiki-sync.js.map +1 -0
- package/dist/knowledge-vault/index.d.ts +11 -0
- package/dist/knowledge-vault/index.d.ts.map +1 -0
- package/dist/knowledge-vault/index.js +8 -0
- package/dist/knowledge-vault/index.js.map +1 -0
- package/dist/knowledge-vault/knowledge-vault.d.ts +38 -0
- package/dist/knowledge-vault/knowledge-vault.d.ts.map +1 -0
- package/dist/knowledge-vault/knowledge-vault.js +284 -0
- package/dist/knowledge-vault/knowledge-vault.js.map +1 -0
- package/dist/knowledge-vault/opencode-doc-ingest.d.ts +23 -0
- package/dist/knowledge-vault/opencode-doc-ingest.d.ts.map +1 -0
- package/dist/knowledge-vault/opencode-doc-ingest.js +48 -0
- package/dist/knowledge-vault/opencode-doc-ingest.js.map +1 -0
- package/dist/knowledge-vault/types.d.ts +61 -0
- package/dist/knowledge-vault/types.d.ts.map +1 -0
- package/dist/knowledge-vault/types.js +5 -0
- package/dist/knowledge-vault/types.js.map +1 -0
- package/dist/knowledge-vault/vault-config.d.ts +12 -0
- package/dist/knowledge-vault/vault-config.d.ts.map +1 -0
- package/dist/knowledge-vault/vault-config.js +24 -0
- package/dist/knowledge-vault/vault-config.js.map +1 -0
- package/dist/mcp/index.d.ts +28 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +29 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/mcp-manager.d.ts +181 -0
- package/dist/mcp/mcp-manager.d.ts.map +1 -0
- package/dist/mcp/mcp-manager.js +621 -0
- package/dist/mcp/mcp-manager.js.map +1 -0
- package/dist/mcp/mcp-types.d.ts +199 -0
- package/dist/mcp/mcp-types.d.ts.map +1 -0
- package/dist/mcp/mcp-types.js +152 -0
- package/dist/mcp/mcp-types.js.map +1 -0
- package/dist/mcp/servers/mcp-server-bridge.d.ts +64 -0
- package/dist/mcp/servers/mcp-server-bridge.d.ts.map +1 -0
- package/dist/mcp/servers/mcp-server-bridge.js +189 -0
- package/dist/mcp/servers/mcp-server-bridge.js.map +1 -0
- package/dist/messages/message-bus.d.ts +148 -0
- package/dist/messages/message-bus.d.ts.map +1 -0
- package/dist/messages/message-bus.js +432 -0
- package/dist/messages/message-bus.js.map +1 -0
- package/dist/modes/custom-mode-registry.d.ts +121 -0
- package/dist/modes/custom-mode-registry.d.ts.map +1 -0
- package/dist/modes/custom-mode-registry.js +306 -0
- package/dist/modes/custom-mode-registry.js.map +1 -0
- package/dist/modes/index.d.ts +10 -0
- package/dist/modes/index.d.ts.map +1 -0
- package/dist/modes/index.js +8 -0
- package/dist/modes/index.js.map +1 -0
- package/dist/modes/mode-designer.d.ts +89 -0
- package/dist/modes/mode-designer.d.ts.map +1 -0
- package/dist/modes/mode-designer.js +485 -0
- package/dist/modes/mode-designer.js.map +1 -0
- package/dist/modes/mode-manager.d.ts +27 -0
- package/dist/modes/mode-manager.d.ts.map +1 -0
- package/dist/modes/mode-manager.js +68 -0
- package/dist/modes/mode-manager.js.map +1 -0
- package/dist/modes/synapse-modes.d.ts +26 -0
- package/dist/modes/synapse-modes.d.ts.map +1 -0
- package/dist/modes/synapse-modes.js +69 -0
- package/dist/modes/synapse-modes.js.map +1 -0
- package/dist/opencode/agent-delegate.d.ts +3 -0
- package/dist/opencode/agent-delegate.d.ts.map +1 -0
- package/dist/opencode/agent-delegate.js +3 -0
- package/dist/opencode/agent-delegate.js.map +1 -0
- package/dist/opencode/tool-bridge.d.ts +3 -0
- package/dist/opencode/tool-bridge.d.ts.map +1 -0
- package/dist/opencode/tool-bridge.js +3 -0
- package/dist/opencode/tool-bridge.js.map +1 -0
- package/dist/optimization/token-optimizer-v2.d.ts +18 -0
- package/dist/optimization/token-optimizer-v2.d.ts.map +1 -0
- package/dist/optimization/token-optimizer-v2.js +23 -0
- package/dist/optimization/token-optimizer-v2.js.map +1 -0
- package/dist/optimization/token-optimizer.d.ts +90 -0
- package/dist/optimization/token-optimizer.d.ts.map +1 -0
- package/dist/optimization/token-optimizer.js +399 -0
- package/dist/optimization/token-optimizer.js.map +1 -0
- package/dist/parallel/agent-farm.d.ts +123 -0
- package/dist/parallel/agent-farm.d.ts.map +1 -0
- package/dist/parallel/agent-farm.js +501 -0
- package/dist/parallel/agent-farm.js.map +1 -0
- package/dist/parallel/farm-scheduler.d.ts +115 -0
- package/dist/parallel/farm-scheduler.d.ts.map +1 -0
- package/dist/parallel/farm-scheduler.js +356 -0
- package/dist/parallel/farm-scheduler.js.map +1 -0
- package/dist/parallel/farm-types.d.ts +104 -0
- package/dist/parallel/farm-types.d.ts.map +1 -0
- package/dist/parallel/farm-types.js +9 -0
- package/dist/parallel/farm-types.js.map +1 -0
- package/dist/parallel/farm-worker.d.ts +62 -0
- package/dist/parallel/farm-worker.d.ts.map +1 -0
- package/dist/parallel/farm-worker.js +268 -0
- package/dist/parallel/farm-worker.js.map +1 -0
- package/dist/parallel/index.d.ts +14 -0
- package/dist/parallel/index.d.ts.map +1 -0
- package/dist/parallel/index.js +14 -0
- package/dist/parallel/index.js.map +1 -0
- package/dist/plugin/native-tools.d.ts +8 -0
- package/dist/plugin/native-tools.d.ts.map +1 -0
- package/dist/plugin/native-tools.js +147 -0
- package/dist/plugin/native-tools.js.map +1 -0
- package/dist/plugin/opencode-plugin.d.ts +32 -0
- package/dist/plugin/opencode-plugin.d.ts.map +1 -0
- package/dist/plugin/opencode-plugin.js +119 -0
- package/dist/plugin/opencode-plugin.js.map +1 -0
- package/dist/plugins/plugin-system.d.ts +108 -0
- package/dist/plugins/plugin-system.d.ts.map +1 -0
- package/dist/plugins/plugin-system.js +707 -0
- package/dist/plugins/plugin-system.js.map +1 -0
- package/dist/profiler/cpu-profiler.d.ts +53 -0
- package/dist/profiler/cpu-profiler.d.ts.map +1 -0
- package/dist/profiler/cpu-profiler.js +233 -0
- package/dist/profiler/cpu-profiler.js.map +1 -0
- package/dist/profiler/index.d.ts +36 -0
- package/dist/profiler/index.d.ts.map +1 -0
- package/dist/profiler/index.js +122 -0
- package/dist/profiler/index.js.map +1 -0
- package/dist/profiler/memory-profiler.d.ts +45 -0
- package/dist/profiler/memory-profiler.d.ts.map +1 -0
- package/dist/profiler/memory-profiler.js +211 -0
- package/dist/profiler/memory-profiler.js.map +1 -0
- package/dist/profiler/profiler-types.d.ts +234 -0
- package/dist/profiler/profiler-types.d.ts.map +1 -0
- package/dist/profiler/profiler-types.js +89 -0
- package/dist/profiler/profiler-types.js.map +1 -0
- package/dist/profiler/query-profiler.d.ts +48 -0
- package/dist/profiler/query-profiler.d.ts.map +1 -0
- package/dist/profiler/query-profiler.js +210 -0
- package/dist/profiler/query-profiler.js.map +1 -0
- package/dist/profiler/report-generator.d.ts +17 -0
- package/dist/profiler/report-generator.d.ts.map +1 -0
- package/dist/profiler/report-generator.js +329 -0
- package/dist/profiler/report-generator.js.map +1 -0
- package/dist/sdk/api.d.ts +85 -0
- package/dist/sdk/api.d.ts.map +1 -0
- package/dist/sdk/api.js +155 -0
- package/dist/sdk/api.js.map +1 -0
- package/dist/sdk/hooks.d.ts +58 -0
- package/dist/sdk/hooks.d.ts.map +1 -0
- package/dist/sdk/hooks.js +115 -0
- package/dist/sdk/hooks.js.map +1 -0
- package/dist/sdk/index.d.ts +17 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +14 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/plugin-base.d.ts +198 -0
- package/dist/sdk/plugin-base.d.ts.map +1 -0
- package/dist/sdk/plugin-base.js +227 -0
- package/dist/sdk/plugin-base.js.map +1 -0
- package/dist/security/audit-rules.d.ts +12 -0
- package/dist/security/audit-rules.d.ts.map +1 -0
- package/dist/security/audit-rules.js +214 -0
- package/dist/security/audit-rules.js.map +1 -0
- package/dist/security/index.d.ts +13 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +13 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/sarif-exporter.d.ts +36 -0
- package/dist/security/sarif-exporter.d.ts.map +1 -0
- package/dist/security/sarif-exporter.js +216 -0
- package/dist/security/sarif-exporter.js.map +1 -0
- package/dist/security/security-auditor.d.ts +30 -0
- package/dist/security/security-auditor.d.ts.map +1 -0
- package/dist/security/security-auditor.js +295 -0
- package/dist/security/security-auditor.js.map +1 -0
- package/dist/security/security-types.d.ts +132 -0
- package/dist/security/security-types.d.ts.map +1 -0
- package/dist/security/security-types.js +7 -0
- package/dist/security/security-types.js.map +1 -0
- package/dist/synapsexcoder/agent-delegate.d.ts +128 -0
- package/dist/synapsexcoder/agent-delegate.d.ts.map +1 -0
- package/dist/synapsexcoder/agent-delegate.js +837 -0
- package/dist/synapsexcoder/agent-delegate.js.map +1 -0
- package/dist/synapsexcoder/agent-mailbox.d.ts +26 -0
- package/dist/synapsexcoder/agent-mailbox.d.ts.map +1 -0
- package/dist/synapsexcoder/agent-mailbox.js +64 -0
- package/dist/synapsexcoder/agent-mailbox.js.map +1 -0
- package/dist/synapsexcoder/ast-grep/ast-grep-api.d.ts +62 -0
- package/dist/synapsexcoder/ast-grep/ast-grep-api.d.ts.map +1 -0
- package/dist/synapsexcoder/ast-grep/ast-grep-api.js +223 -0
- package/dist/synapsexcoder/ast-grep/ast-grep-api.js.map +1 -0
- package/dist/synapsexcoder/cited-search.d.ts +32 -0
- package/dist/synapsexcoder/cited-search.d.ts.map +1 -0
- package/dist/synapsexcoder/cited-search.js +141 -0
- package/dist/synapsexcoder/cited-search.js.map +1 -0
- package/dist/synapsexcoder/credential-store.d.ts +42 -0
- package/dist/synapsexcoder/credential-store.d.ts.map +1 -0
- package/dist/synapsexcoder/credential-store.js +165 -0
- package/dist/synapsexcoder/credential-store.js.map +1 -0
- package/dist/synapsexcoder/devcontainer-awareness.d.ts +35 -0
- package/dist/synapsexcoder/devcontainer-awareness.d.ts.map +1 -0
- package/dist/synapsexcoder/devcontainer-awareness.js +133 -0
- package/dist/synapsexcoder/devcontainer-awareness.js.map +1 -0
- package/dist/synapsexcoder/execution-loops/helix-loop.d.ts +31 -0
- package/dist/synapsexcoder/execution-loops/helix-loop.d.ts.map +1 -0
- package/dist/synapsexcoder/execution-loops/helix-loop.js +93 -0
- package/dist/synapsexcoder/execution-loops/helix-loop.js.map +1 -0
- package/dist/synapsexcoder/execution-loops/ralp-loop.d.ts +28 -0
- package/dist/synapsexcoder/execution-loops/ralp-loop.d.ts.map +1 -0
- package/dist/synapsexcoder/execution-loops/ralp-loop.js +77 -0
- package/dist/synapsexcoder/execution-loops/ralp-loop.js.map +1 -0
- package/dist/synapsexcoder/feature-names.d.ts +27 -0
- package/dist/synapsexcoder/feature-names.d.ts.map +1 -0
- package/dist/synapsexcoder/feature-names.js +40 -0
- package/dist/synapsexcoder/feature-names.js.map +1 -0
- package/dist/synapsexcoder/index.d.ts +39 -0
- package/dist/synapsexcoder/index.d.ts.map +1 -0
- package/dist/synapsexcoder/index.js +23 -0
- package/dist/synapsexcoder/index.js.map +1 -0
- package/dist/synapsexcoder/knowledge-provider.d.ts +44 -0
- package/dist/synapsexcoder/knowledge-provider.d.ts.map +1 -0
- package/dist/synapsexcoder/knowledge-provider.js +107 -0
- package/dist/synapsexcoder/knowledge-provider.js.map +1 -0
- package/dist/synapsexcoder/lsp/lsp-layer.d.ts +51 -0
- package/dist/synapsexcoder/lsp/lsp-layer.d.ts.map +1 -0
- package/dist/synapsexcoder/lsp/lsp-layer.js +302 -0
- package/dist/synapsexcoder/lsp/lsp-layer.js.map +1 -0
- package/dist/synapsexcoder/migration/opencode-config-migrator.d.ts +37 -0
- package/dist/synapsexcoder/migration/opencode-config-migrator.d.ts.map +1 -0
- package/dist/synapsexcoder/migration/opencode-config-migrator.js +100 -0
- package/dist/synapsexcoder/migration/opencode-config-migrator.js.map +1 -0
- package/dist/synapsexcoder/runtime-environment.d.ts +35 -0
- package/dist/synapsexcoder/runtime-environment.d.ts.map +1 -0
- package/dist/synapsexcoder/runtime-environment.js +108 -0
- package/dist/synapsexcoder/runtime-environment.js.map +1 -0
- package/dist/synapsexcoder/secret-guard.d.ts +18 -0
- package/dist/synapsexcoder/secret-guard.d.ts.map +1 -0
- package/dist/synapsexcoder/secret-guard.js +69 -0
- package/dist/synapsexcoder/secret-guard.js.map +1 -0
- package/dist/synapsexcoder/self-prompt-engine.d.ts +15 -0
- package/dist/synapsexcoder/self-prompt-engine.d.ts.map +1 -0
- package/dist/synapsexcoder/self-prompt-engine.js +11 -0
- package/dist/synapsexcoder/self-prompt-engine.js.map +1 -0
- package/dist/synapsexcoder/session-observability.d.ts +44 -0
- package/dist/synapsexcoder/session-observability.d.ts.map +1 -0
- package/dist/synapsexcoder/session-observability.js +115 -0
- package/dist/synapsexcoder/session-observability.js.map +1 -0
- package/dist/synapsexcoder/specialist-agents.d.ts +38 -0
- package/dist/synapsexcoder/specialist-agents.d.ts.map +1 -0
- package/dist/synapsexcoder/specialist-agents.js +192 -0
- package/dist/synapsexcoder/specialist-agents.js.map +1 -0
- package/dist/synapsexcoder/swarm/kanban-board.d.ts +34 -0
- package/dist/synapsexcoder/swarm/kanban-board.d.ts.map +1 -0
- package/dist/synapsexcoder/swarm/kanban-board.js +85 -0
- package/dist/synapsexcoder/swarm/kanban-board.js.map +1 -0
- package/dist/synapsexcoder/swarm/swarm-mailbox.d.ts +38 -0
- package/dist/synapsexcoder/swarm/swarm-mailbox.d.ts.map +1 -0
- package/dist/synapsexcoder/swarm/swarm-mailbox.js +93 -0
- package/dist/synapsexcoder/swarm/swarm-mailbox.js.map +1 -0
- package/dist/synapsexcoder/tool-bridge.d.ts +277 -0
- package/dist/synapsexcoder/tool-bridge.d.ts.map +1 -0
- package/dist/synapsexcoder/tool-bridge.js +1356 -0
- package/dist/synapsexcoder/tool-bridge.js.map +1 -0
- package/dist/synapsexcoder/tool-routing.d.ts +28 -0
- package/dist/synapsexcoder/tool-routing.d.ts.map +1 -0
- package/dist/synapsexcoder/tool-routing.js +79 -0
- package/dist/synapsexcoder/tool-routing.js.map +1 -0
- package/dist/synapsexcoder/type-injector.d.ts +26 -0
- package/dist/synapsexcoder/type-injector.d.ts.map +1 -0
- package/dist/synapsexcoder/type-injector.js +124 -0
- package/dist/synapsexcoder/type-injector.js.map +1 -0
- package/dist/synapsexcoder/utils/fuzzy-match.d.ts +25 -0
- package/dist/synapsexcoder/utils/fuzzy-match.d.ts.map +1 -0
- package/dist/synapsexcoder/utils/fuzzy-match.js +83 -0
- package/dist/synapsexcoder/utils/fuzzy-match.js.map +1 -0
- package/dist/synapsexcoder/vault-crawl.d.ts +29 -0
- package/dist/synapsexcoder/vault-crawl.d.ts.map +1 -0
- package/dist/synapsexcoder/vault-crawl.js +103 -0
- package/dist/synapsexcoder/vault-crawl.js.map +1 -0
- package/dist/synapsexcoder/verified-apply.d.ts +39 -0
- package/dist/synapsexcoder/verified-apply.d.ts.map +1 -0
- package/dist/synapsexcoder/verified-apply.js +81 -0
- package/dist/synapsexcoder/verified-apply.js.map +1 -0
- package/dist/synapsexcoder/verified-context-editing.d.ts +34 -0
- package/dist/synapsexcoder/verified-context-editing.d.ts.map +1 -0
- package/dist/synapsexcoder/verified-context-editing.js +80 -0
- package/dist/synapsexcoder/verified-context-editing.js.map +1 -0
- package/dist/synapsexcoder/worker-pool.d.ts +47 -0
- package/dist/synapsexcoder/worker-pool.d.ts.map +1 -0
- package/dist/synapsexcoder/worker-pool.js +120 -0
- package/dist/synapsexcoder/worker-pool.js.map +1 -0
- package/dist/synapsexcoder/workspace-intelligence.d.ts +35 -0
- package/dist/synapsexcoder/workspace-intelligence.d.ts.map +1 -0
- package/dist/synapsexcoder/workspace-intelligence.js +126 -0
- package/dist/synapsexcoder/workspace-intelligence.js.map +1 -0
- package/dist/synapsexcoder/worktree-manager.d.ts +31 -0
- package/dist/synapsexcoder/worktree-manager.d.ts.map +1 -0
- package/dist/synapsexcoder/worktree-manager.js +100 -0
- package/dist/synapsexcoder/worktree-manager.js.map +1 -0
- package/dist/team/index.d.ts +17 -0
- package/dist/team/index.d.ts.map +1 -0
- package/dist/team/index.js +13 -0
- package/dist/team/index.js.map +1 -0
- package/dist/team/team-audit.d.ts +120 -0
- package/dist/team/team-audit.d.ts.map +1 -0
- package/dist/team/team-audit.js +357 -0
- package/dist/team/team-audit.js.map +1 -0
- package/dist/team/team-collaboration.d.ts +150 -0
- package/dist/team/team-collaboration.d.ts.map +1 -0
- package/dist/team/team-collaboration.js +495 -0
- package/dist/team/team-collaboration.js.map +1 -0
- package/dist/team/team-rbac.d.ts +84 -0
- package/dist/team/team-rbac.d.ts.map +1 -0
- package/dist/team/team-rbac.js +259 -0
- package/dist/team/team-rbac.js.map +1 -0
- package/dist/team/team-session-manager.d.ts +100 -0
- package/dist/team/team-session-manager.d.ts.map +1 -0
- package/dist/team/team-session-manager.js +255 -0
- package/dist/team/team-session-manager.js.map +1 -0
- package/dist/thoughts/thoughts-manager.d.ts +52 -0
- package/dist/thoughts/thoughts-manager.d.ts.map +1 -0
- package/dist/thoughts/thoughts-manager.js +271 -0
- package/dist/thoughts/thoughts-manager.js.map +1 -0
- package/dist/tools/api-validator/index.d.ts +97 -0
- package/dist/tools/api-validator/index.d.ts.map +1 -0
- package/dist/tools/api-validator/index.js +312 -0
- package/dist/tools/api-validator/index.js.map +1 -0
- package/dist/tools/code-archaeology/index.d.ts +193 -0
- package/dist/tools/code-archaeology/index.d.ts.map +1 -0
- package/dist/tools/code-archaeology/index.js +468 -0
- package/dist/tools/code-archaeology/index.js.map +1 -0
- package/dist/tools/codebase-search/index.d.ts +126 -0
- package/dist/tools/codebase-search/index.d.ts.map +1 -0
- package/dist/tools/codebase-search/index.js +437 -0
- package/dist/tools/codebase-search/index.js.map +1 -0
- package/dist/tools/context/index.d.ts +162 -0
- package/dist/tools/context/index.d.ts.map +1 -0
- package/dist/tools/context/index.js +332 -0
- package/dist/tools/context/index.js.map +1 -0
- package/dist/tools/deepwiki/analyzer.d.ts +167 -0
- package/dist/tools/deepwiki/analyzer.d.ts.map +1 -0
- package/dist/tools/deepwiki/analyzer.js +925 -0
- package/dist/tools/deepwiki/analyzer.js.map +1 -0
- package/dist/tools/deepwiki/extractor.d.ts +151 -0
- package/dist/tools/deepwiki/extractor.d.ts.map +1 -0
- package/dist/tools/deepwiki/extractor.js +923 -0
- package/dist/tools/deepwiki/extractor.js.map +1 -0
- package/dist/tools/deepwiki/generator.d.ts +89 -0
- package/dist/tools/deepwiki/generator.d.ts.map +1 -0
- package/dist/tools/deepwiki/generator.js +638 -0
- package/dist/tools/deepwiki/generator.js.map +1 -0
- package/dist/tools/deepwiki/index.d.ts +96 -0
- package/dist/tools/deepwiki/index.d.ts.map +1 -0
- package/dist/tools/deepwiki/index.js +282 -0
- package/dist/tools/deepwiki/index.js.map +1 -0
- package/dist/tools/deepwiki/types.d.ts +370 -0
- package/dist/tools/deepwiki/types.d.ts.map +1 -0
- package/dist/tools/deepwiki/types.js +21 -0
- package/dist/tools/deepwiki/types.js.map +1 -0
- package/dist/tools/dependency-mapper/index.d.ts +212 -0
- package/dist/tools/dependency-mapper/index.d.ts.map +1 -0
- package/dist/tools/dependency-mapper/index.js +592 -0
- package/dist/tools/dependency-mapper/index.js.map +1 -0
- package/dist/tools/memory/index.d.ts +120 -0
- package/dist/tools/memory/index.d.ts.map +1 -0
- package/dist/tools/memory/index.js +275 -0
- package/dist/tools/memory/index.js.map +1 -0
- package/dist/tools/normalize_patch.d.ts +3 -0
- package/dist/tools/normalize_patch.d.ts.map +1 -0
- package/dist/tools/normalize_patch.js +22 -0
- package/dist/tools/normalize_patch.js.map +1 -0
- package/dist/tools/pattern-detector/index.d.ts +105 -0
- package/dist/tools/pattern-detector/index.d.ts.map +1 -0
- package/dist/tools/pattern-detector/index.js +526 -0
- package/dist/tools/pattern-detector/index.js.map +1 -0
- package/dist/tools/performance-profiler/index.d.ts +50 -0
- package/dist/tools/performance-profiler/index.d.ts.map +1 -0
- package/dist/tools/performance-profiler/index.js +164 -0
- package/dist/tools/performance-profiler/index.js.map +1 -0
- package/dist/tools/refactoring-engine/index.d.ts +63 -0
- package/dist/tools/refactoring-engine/index.d.ts.map +1 -0
- package/dist/tools/refactoring-engine/index.js +270 -0
- package/dist/tools/refactoring-engine/index.js.map +1 -0
- package/dist/tools/registry.d.ts +36 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +499 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/test-generator/index.d.ts +152 -0
- package/dist/tools/test-generator/index.d.ts.map +1 -0
- package/dist/tools/test-generator/index.js +448 -0
- package/dist/tools/test-generator/index.js.map +1 -0
- package/dist/types/index.d.ts +565 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/path-validator.d.ts +94 -0
- package/dist/utils/path-validator.d.ts.map +1 -0
- package/dist/utils/path-validator.js +192 -0
- package/dist/utils/path-validator.js.map +1 -0
- package/dist/utils/secure-exec.d.ts +92 -0
- package/dist/utils/secure-exec.d.ts.map +1 -0
- package/dist/utils/secure-exec.js +230 -0
- package/dist/utils/secure-exec.js.map +1 -0
- package/dist/verification/claim-parser.d.ts +37 -0
- package/dist/verification/claim-parser.d.ts.map +1 -0
- package/dist/verification/claim-parser.js +231 -0
- package/dist/verification/claim-parser.js.map +1 -0
- package/dist/verification/cross-reference-engine.d.ts +55 -0
- package/dist/verification/cross-reference-engine.d.ts.map +1 -0
- package/dist/verification/cross-reference-engine.js +149 -0
- package/dist/verification/cross-reference-engine.js.map +1 -0
- package/dist/verification/discrepancy-tracker.d.ts +73 -0
- package/dist/verification/discrepancy-tracker.d.ts.map +1 -0
- package/dist/verification/discrepancy-tracker.js +196 -0
- package/dist/verification/discrepancy-tracker.js.map +1 -0
- package/dist/verification/feature-reconciler.d.ts +90 -0
- package/dist/verification/feature-reconciler.d.ts.map +1 -0
- package/dist/verification/feature-reconciler.js +264 -0
- package/dist/verification/feature-reconciler.js.map +1 -0
- package/dist/verification/index.d.ts +16 -0
- package/dist/verification/index.d.ts.map +1 -0
- package/dist/verification/index.js +19 -0
- package/dist/verification/index.js.map +1 -0
- package/dist/verification/integration-verifier.d.ts +66 -0
- package/dist/verification/integration-verifier.d.ts.map +1 -0
- package/dist/verification/integration-verifier.js +210 -0
- package/dist/verification/integration-verifier.js.map +1 -0
- package/dist/verification/recursive-audit-loop.d.ts +56 -0
- package/dist/verification/recursive-audit-loop.d.ts.map +1 -0
- package/dist/verification/recursive-audit-loop.js +136 -0
- package/dist/verification/recursive-audit-loop.js.map +1 -0
- package/dist/verification/runtime-verifier.d.ts +37 -0
- package/dist/verification/runtime-verifier.d.ts.map +1 -0
- package/dist/verification/runtime-verifier.js +221 -0
- package/dist/verification/runtime-verifier.js.map +1 -0
- package/dist/verification/types.d.ts +88 -0
- package/dist/verification/types.d.ts.map +1 -0
- package/dist/verification/types.js +5 -0
- package/dist/verification/types.js.map +1 -0
- package/dist/verification/verification-engine.d.ts +48 -0
- package/dist/verification/verification-engine.d.ts.map +1 -0
- package/dist/verification/verification-engine.js +203 -0
- package/dist/verification/verification-engine.js.map +1 -0
- package/opencode-agents/synapse-analyzer.md +64 -0
- package/opencode-agents/synapse-debugger.md +43 -0
- package/opencode-agents/synapse-diff-validator.md +42 -0
- package/opencode-agents/synapse-gatekeeper.md +273 -0
- package/opencode-agents/synapse-master.md +167 -0
- package/opencode-agents/synapse-planner.md +55 -0
- package/opencode-agents/synapse-researcher.md +61 -0
- package/opencode-agents/synapse-reviewer.md +64 -0
- package/opencode-agents/synapse-rewriter.md +62 -0
- package/opencode-agents/synapse-strategist.md +50 -0
- package/opencode-agents/synapse-test-runner.md +43 -0
- package/opencode-agents/synapse-ui-designer.md +61 -0
- package/opencode-agents/synapse-verifier.md +544 -0
- package/package.json +108 -0
- package/src/plugin/opencode-plugin.ts +141 -0
|
@@ -0,0 +1,1356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode CLI Tool Bridge
|
|
3
|
+
*
|
|
4
|
+
* Provides a unified interface for all OpenCode CLI tool operations.
|
|
5
|
+
* All file operations use native Node.js APIs (NOT opencode read/write/edit/ls/grep/find).
|
|
6
|
+
* Web and search operations use global fetch() or valid `opencode run` commands.
|
|
7
|
+
* Verification methods delegate to opencode run with appropriate agents.
|
|
8
|
+
*
|
|
9
|
+
* Supported opencode subcommands used: run, serve, mcp, version, session
|
|
10
|
+
* INVALID subcommands NOT used: read, write, edit, ls, grep, find, search, fetch, ask, verify, audit
|
|
11
|
+
*/
|
|
12
|
+
import { spawn } from "child_process";
|
|
13
|
+
import fs from "fs/promises";
|
|
14
|
+
import path from "path";
|
|
15
|
+
import { EventEmitter } from "events";
|
|
16
|
+
import { v4 as uuidv4 } from "uuid";
|
|
17
|
+
import { validateAndResolve, validateCommandArg, } from "../utils/path-validator.js";
|
|
18
|
+
import { suggestOldString } from "./utils/fuzzy-match.js";
|
|
19
|
+
import { validateCommandString } from "../utils/secure-exec.js";
|
|
20
|
+
// Optional PluginInput import — only available when running as an OpenCode plugin
|
|
21
|
+
// In standalone mode (CLI), this will be null and tool-bridge uses spawn instead.
|
|
22
|
+
let _pluginInput = null;
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Configuration
|
|
25
|
+
// ============================================================================
|
|
26
|
+
const DEFAULT_CONFIG = {
|
|
27
|
+
mode: "embedded",
|
|
28
|
+
serverUrl: "http://localhost:4096",
|
|
29
|
+
configPath: "~/.config/opencode",
|
|
30
|
+
tools: {
|
|
31
|
+
readFile: "allow",
|
|
32
|
+
writeFile: "ask",
|
|
33
|
+
editFile: "ask",
|
|
34
|
+
runBash: "ask",
|
|
35
|
+
webSearch: "allow",
|
|
36
|
+
fetchUrl: "allow",
|
|
37
|
+
mcp: "ask",
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
// ============================================================================
|
|
41
|
+
// OpenCode Process Manager
|
|
42
|
+
// ============================================================================
|
|
43
|
+
export class OpenCodeProcessManager {
|
|
44
|
+
config;
|
|
45
|
+
processes = new Map();
|
|
46
|
+
sessionId = uuidv4();
|
|
47
|
+
constructor(config) {
|
|
48
|
+
this.config = config;
|
|
49
|
+
}
|
|
50
|
+
async startSession(cwd) {
|
|
51
|
+
if (this.config.mode !== "embedded") {
|
|
52
|
+
throw new Error("Can only start sessions in embedded mode");
|
|
53
|
+
}
|
|
54
|
+
const args = ["--session", this.sessionId];
|
|
55
|
+
if (cwd)
|
|
56
|
+
args.push("--directory", cwd);
|
|
57
|
+
const proc = spawn("opencode", args, {
|
|
58
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
59
|
+
env: process.env,
|
|
60
|
+
cwd: cwd || process.cwd(),
|
|
61
|
+
});
|
|
62
|
+
this.processes.set(this.sessionId, proc);
|
|
63
|
+
return this.sessionId;
|
|
64
|
+
}
|
|
65
|
+
async stopSession(sessionId) {
|
|
66
|
+
const proc = this.processes.get(sessionId);
|
|
67
|
+
if (proc) {
|
|
68
|
+
proc.kill("SIGTERM");
|
|
69
|
+
this.processes.delete(sessionId);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
getSessionProcess(sessionId) {
|
|
73
|
+
return this.processes.get(sessionId);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// ============================================================================
|
|
77
|
+
// Tool Calling Bridge
|
|
78
|
+
// ============================================================================
|
|
79
|
+
export class OpenCodeToolBridge extends EventEmitter {
|
|
80
|
+
_processManager;
|
|
81
|
+
config;
|
|
82
|
+
toolHistory = [];
|
|
83
|
+
permissionCache = new Map();
|
|
84
|
+
projectRoot;
|
|
85
|
+
constructor(config = {}, projectRoot) {
|
|
86
|
+
super();
|
|
87
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
88
|
+
this._processManager = new OpenCodeProcessManager(this.config);
|
|
89
|
+
this.projectRoot = projectRoot || process.cwd();
|
|
90
|
+
this.initializePermissions();
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Set the global PluginInput reference for all tool-bridge instances.
|
|
94
|
+
* Called by the plugin entry point when it initializes. When set,
|
|
95
|
+
* tool-bridge operations may use BunShell ($) for shell execution and
|
|
96
|
+
* the SDK client for API calls instead of spawning opencode as a subprocess.
|
|
97
|
+
* Pass null to revert to standalone/spawn mode.
|
|
98
|
+
*/
|
|
99
|
+
static setPluginInput(input) {
|
|
100
|
+
_pluginInput = input;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Validates a file path against the project root to prevent path traversal.
|
|
104
|
+
* @param filePath - The file path to validate
|
|
105
|
+
* @returns The validated and resolved absolute path
|
|
106
|
+
* @throws Error if path traversal is detected
|
|
107
|
+
*/
|
|
108
|
+
validateFilePath(filePath) {
|
|
109
|
+
return validateAndResolve(filePath, this.projectRoot);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Validates a command string for dangerous patterns.
|
|
113
|
+
* @param command - The command to validate
|
|
114
|
+
* @throws Error if dangerous patterns are detected
|
|
115
|
+
*/
|
|
116
|
+
validateCommand(command) {
|
|
117
|
+
validateCommandString(command);
|
|
118
|
+
validateCommandArg(command);
|
|
119
|
+
}
|
|
120
|
+
/** Validate and normalize a ToolPermission to PermissionState at the boundary (Law 3). */
|
|
121
|
+
toPermissionState(value) {
|
|
122
|
+
if (value === "allow" || value === "deny" || value === "ask")
|
|
123
|
+
return value;
|
|
124
|
+
// ToolCapability values are not valid cache states; default to "ask" for safety
|
|
125
|
+
return "ask";
|
|
126
|
+
}
|
|
127
|
+
initializePermissions() {
|
|
128
|
+
const tools = this.config.tools;
|
|
129
|
+
if (tools) {
|
|
130
|
+
if (tools.readFile)
|
|
131
|
+
this.permissionCache.set("read_file", this.toPermissionState(tools.readFile));
|
|
132
|
+
if (tools.writeFile)
|
|
133
|
+
this.permissionCache.set("write_file", this.toPermissionState(tools.writeFile));
|
|
134
|
+
if (tools.editFile)
|
|
135
|
+
this.permissionCache.set("edit_file", this.toPermissionState(tools.editFile));
|
|
136
|
+
if (tools.runBash)
|
|
137
|
+
this.permissionCache.set("run_bash", this.toPermissionState(tools.runBash));
|
|
138
|
+
if (tools.webSearch)
|
|
139
|
+
this.permissionCache.set("web_search", this.toPermissionState(tools.webSearch));
|
|
140
|
+
if (tools.fetchUrl)
|
|
141
|
+
this.permissionCache.set("fetch_url", this.toPermissionState(tools.fetchUrl));
|
|
142
|
+
if (tools.mcp)
|
|
143
|
+
this.permissionCache.set("call_mcp", this.toPermissionState(tools.mcp));
|
|
144
|
+
if (tools.verifyRepository)
|
|
145
|
+
this.permissionCache.set("verify_repository", this.toPermissionState(tools.verifyRepository));
|
|
146
|
+
if (tools.verifyFile)
|
|
147
|
+
this.permissionCache.set("verify_file", this.toPermissionState(tools.verifyFile));
|
|
148
|
+
if (tools.verifyClaim)
|
|
149
|
+
this.permissionCache.set("verify_claim", this.toPermissionState(tools.verifyClaim));
|
|
150
|
+
if (tools.auditRecursive)
|
|
151
|
+
this.permissionCache.set("audit_recursive", this.toPermissionState(tools.auditRecursive));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
checkPermission(tool, action) {
|
|
155
|
+
const key = action ? `${tool}_${action}` : tool;
|
|
156
|
+
return this.permissionCache.get(key) || "ask";
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Execute a native CLI command via spawn or BunShell (when running as a plugin).
|
|
160
|
+
* Uses PluginInput.$ (BunShell) when available, falls back to spawn otherwise.
|
|
161
|
+
*/
|
|
162
|
+
async executeCommand(command, args, options = {}) {
|
|
163
|
+
const startTime = Date.now();
|
|
164
|
+
const toolName = command;
|
|
165
|
+
// When running as an OpenCode plugin, use BunShell for simple commands
|
|
166
|
+
if (_pluginInput?.$ && command !== "opencode") {
|
|
167
|
+
try {
|
|
168
|
+
const cmdStr = `${command} ${args.map(a => a.includes(" ") ? `"${a}"` : a).join(" ")}`;
|
|
169
|
+
const workdir = options.cwd || _pluginInput.directory || process.cwd();
|
|
170
|
+
const shellResult = await _pluginInput.$ `cd ${workdir} && ${cmdStr}`;
|
|
171
|
+
const output = await shellResult.quiet().text();
|
|
172
|
+
return {
|
|
173
|
+
success: true,
|
|
174
|
+
output,
|
|
175
|
+
metadata: {
|
|
176
|
+
executionTime: Date.now() - startTime,
|
|
177
|
+
toolName,
|
|
178
|
+
agentId: "bridge",
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
return {
|
|
184
|
+
success: false,
|
|
185
|
+
error: error instanceof Error ? error.message : String(error),
|
|
186
|
+
metadata: {
|
|
187
|
+
executionTime: Date.now() - startTime,
|
|
188
|
+
toolName,
|
|
189
|
+
agentId: "bridge",
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const result = await new Promise((resolve, reject) => {
|
|
196
|
+
// Use AbortSignal.timeout() for reliable timeout (Node 20+)
|
|
197
|
+
const signal = options.timeout
|
|
198
|
+
? AbortSignal.timeout(options.timeout)
|
|
199
|
+
: undefined;
|
|
200
|
+
let settled = false;
|
|
201
|
+
const proc = spawn(command, args, {
|
|
202
|
+
cwd: options.cwd || process.cwd(),
|
|
203
|
+
env: { ...process.env, ...options.env },
|
|
204
|
+
signal,
|
|
205
|
+
});
|
|
206
|
+
let stdout = "";
|
|
207
|
+
let stderr = "";
|
|
208
|
+
proc.stdout?.on("data", (data) => {
|
|
209
|
+
stdout += data.toString();
|
|
210
|
+
});
|
|
211
|
+
proc.stderr?.on("data", (data) => {
|
|
212
|
+
stderr += data.toString();
|
|
213
|
+
});
|
|
214
|
+
const settle = (resolveFn, value) => {
|
|
215
|
+
if (!settled) {
|
|
216
|
+
settled = true;
|
|
217
|
+
resolveFn(value);
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
proc.on("close", (code) => {
|
|
221
|
+
settle(resolve, {
|
|
222
|
+
stdout,
|
|
223
|
+
stderr,
|
|
224
|
+
exitCode: code ?? 1,
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
proc.on("error", (err) => {
|
|
228
|
+
settle(reject, err);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
const toolCall = {
|
|
232
|
+
tool: toolName,
|
|
233
|
+
args: { command, args, ...options },
|
|
234
|
+
timestamp: startTime,
|
|
235
|
+
agentId: "bridge",
|
|
236
|
+
};
|
|
237
|
+
this.toolHistory.push(toolCall);
|
|
238
|
+
return {
|
|
239
|
+
success: result.exitCode === 0,
|
|
240
|
+
output: result.stdout,
|
|
241
|
+
error: result.stderr || undefined,
|
|
242
|
+
metadata: {
|
|
243
|
+
executionTime: Date.now() - startTime,
|
|
244
|
+
toolName,
|
|
245
|
+
agentId: "bridge",
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
return {
|
|
251
|
+
success: false,
|
|
252
|
+
error: error instanceof Error ? error.message : String(error),
|
|
253
|
+
metadata: {
|
|
254
|
+
executionTime: Date.now() - startTime,
|
|
255
|
+
toolName,
|
|
256
|
+
agentId: "bridge",
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// ========================================================================
|
|
262
|
+
// File Operations — Native fs.promises (NOT opencode read/write/edit)
|
|
263
|
+
// ========================================================================
|
|
264
|
+
/**
|
|
265
|
+
* Read file contents with optional line range.
|
|
266
|
+
* Uses native fs.promises — no CLI delegation.
|
|
267
|
+
*/
|
|
268
|
+
async readFile(filePath, options = {}) {
|
|
269
|
+
const permission = this.checkPermission("read_file");
|
|
270
|
+
if (permission === "deny") {
|
|
271
|
+
return { success: false, error: "Permission denied: read_file" };
|
|
272
|
+
}
|
|
273
|
+
// Validate path to prevent traversal attacks
|
|
274
|
+
let validatedPath;
|
|
275
|
+
try {
|
|
276
|
+
validatedPath = this.validateFilePath(filePath);
|
|
277
|
+
}
|
|
278
|
+
catch (error) {
|
|
279
|
+
return {
|
|
280
|
+
success: false,
|
|
281
|
+
error: `Path validation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
const encoding = options.encoding || "utf8";
|
|
286
|
+
const fullContent = await fs.readFile(validatedPath, { encoding });
|
|
287
|
+
let output;
|
|
288
|
+
if (options.startLine !== undefined) {
|
|
289
|
+
const lines = fullContent.split("\n");
|
|
290
|
+
const start = Math.max(0, options.startLine - 1);
|
|
291
|
+
const end = options.endLine !== undefined
|
|
292
|
+
? Math.min(lines.length, options.endLine)
|
|
293
|
+
: lines.length;
|
|
294
|
+
output = lines.slice(start, end).join("\n");
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
output = fullContent;
|
|
298
|
+
}
|
|
299
|
+
const result = {
|
|
300
|
+
success: true,
|
|
301
|
+
output,
|
|
302
|
+
metadata: {
|
|
303
|
+
executionTime: 0,
|
|
304
|
+
toolName: "read_file",
|
|
305
|
+
agentId: "bridge",
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
this.emit("tool-executed", {
|
|
309
|
+
tool: "read_file",
|
|
310
|
+
filePath: validatedPath,
|
|
311
|
+
timestamp: Date.now(),
|
|
312
|
+
});
|
|
313
|
+
return result;
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
return {
|
|
317
|
+
success: false,
|
|
318
|
+
error: error instanceof Error ? error.message : String(error),
|
|
319
|
+
metadata: {
|
|
320
|
+
executionTime: 0,
|
|
321
|
+
toolName: "read_file",
|
|
322
|
+
agentId: "bridge",
|
|
323
|
+
},
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Read file and return structured content
|
|
329
|
+
*/
|
|
330
|
+
async readFileContent(filePath) {
|
|
331
|
+
// Validate path to prevent traversal attacks
|
|
332
|
+
let validatedPath;
|
|
333
|
+
try {
|
|
334
|
+
validatedPath = this.validateFilePath(filePath);
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
return null;
|
|
338
|
+
}
|
|
339
|
+
try {
|
|
340
|
+
const content = await fs.readFile(validatedPath, { encoding: "utf8" });
|
|
341
|
+
return {
|
|
342
|
+
path: validatedPath,
|
|
343
|
+
content,
|
|
344
|
+
metadata: {
|
|
345
|
+
size: content.length,
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
return null;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Write content to file.
|
|
355
|
+
* Uses native fs.promises — no CLI delegation.
|
|
356
|
+
*/
|
|
357
|
+
async writeFile(filePath, content, options = {}) {
|
|
358
|
+
const permission = this.checkPermission("write_file");
|
|
359
|
+
if (permission === "deny") {
|
|
360
|
+
return { success: false, error: "Permission denied: write_file" };
|
|
361
|
+
}
|
|
362
|
+
// Validate path to prevent traversal attacks
|
|
363
|
+
let validatedPath;
|
|
364
|
+
try {
|
|
365
|
+
validatedPath = this.validateFilePath(filePath);
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
return {
|
|
369
|
+
success: false,
|
|
370
|
+
error: `Path validation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
try {
|
|
374
|
+
// Create parent directories if requested
|
|
375
|
+
if (options.createDirectories) {
|
|
376
|
+
await fs.mkdir(path.dirname(validatedPath), { recursive: true });
|
|
377
|
+
}
|
|
378
|
+
await fs.writeFile(validatedPath, content, { encoding: "utf8" });
|
|
379
|
+
const result = {
|
|
380
|
+
success: true,
|
|
381
|
+
output: `Written ${content.length} bytes to ${validatedPath}`,
|
|
382
|
+
metadata: {
|
|
383
|
+
executionTime: 0,
|
|
384
|
+
toolName: "write_file",
|
|
385
|
+
agentId: "bridge",
|
|
386
|
+
},
|
|
387
|
+
};
|
|
388
|
+
this.emit("tool-executed", {
|
|
389
|
+
tool: "write_file",
|
|
390
|
+
filePath: validatedPath,
|
|
391
|
+
timestamp: Date.now(),
|
|
392
|
+
});
|
|
393
|
+
return result;
|
|
394
|
+
}
|
|
395
|
+
catch (error) {
|
|
396
|
+
return {
|
|
397
|
+
success: false,
|
|
398
|
+
error: error instanceof Error ? error.message : String(error),
|
|
399
|
+
metadata: {
|
|
400
|
+
executionTime: 0,
|
|
401
|
+
toolName: "write_file",
|
|
402
|
+
agentId: "bridge",
|
|
403
|
+
},
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Edit specific parts of a file using search-and-replace.
|
|
409
|
+
* Uses native fs.promises — no CLI delegation.
|
|
410
|
+
*/
|
|
411
|
+
async editFile(filePath, oldString, newString) {
|
|
412
|
+
const permission = this.checkPermission("edit_file");
|
|
413
|
+
if (permission === "deny") {
|
|
414
|
+
return { success: false, error: "Permission denied: edit_file" };
|
|
415
|
+
}
|
|
416
|
+
// Validate path to prevent traversal attacks
|
|
417
|
+
let validatedPath;
|
|
418
|
+
try {
|
|
419
|
+
validatedPath = this.validateFilePath(filePath);
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
return {
|
|
423
|
+
success: false,
|
|
424
|
+
error: `Path validation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
try {
|
|
428
|
+
const content = await fs.readFile(validatedPath, { encoding: "utf8" });
|
|
429
|
+
// Check if oldString exists in the file
|
|
430
|
+
if (!content.includes(oldString)) {
|
|
431
|
+
const suggestion = suggestOldString(content, oldString);
|
|
432
|
+
const hint = suggestion
|
|
433
|
+
? ` Did you mean (line ${suggestion.line}, score ${suggestion.score.toFixed(2)}): ${JSON.stringify(suggestion.suggestion.slice(0, 80))}...`
|
|
434
|
+
: "";
|
|
435
|
+
return {
|
|
436
|
+
success: false,
|
|
437
|
+
error: `oldString not found in ${validatedPath}.${hint}`,
|
|
438
|
+
metadata: {
|
|
439
|
+
executionTime: 0,
|
|
440
|
+
toolName: "edit_file",
|
|
441
|
+
agentId: "bridge",
|
|
442
|
+
fuzzySuggestion: suggestion ?? undefined,
|
|
443
|
+
},
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
const newContent = content.replace(oldString, newString);
|
|
447
|
+
// Verify something actually changed
|
|
448
|
+
if (newContent === content) {
|
|
449
|
+
return {
|
|
450
|
+
success: false,
|
|
451
|
+
error: `No changes made — oldString and newString are identical`,
|
|
452
|
+
metadata: {
|
|
453
|
+
executionTime: 0,
|
|
454
|
+
toolName: "edit_file",
|
|
455
|
+
agentId: "bridge",
|
|
456
|
+
},
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
await fs.writeFile(validatedPath, newContent, { encoding: "utf8" });
|
|
460
|
+
const result = {
|
|
461
|
+
success: true,
|
|
462
|
+
output: `Edited ${validatedPath}`,
|
|
463
|
+
metadata: {
|
|
464
|
+
executionTime: 0,
|
|
465
|
+
toolName: "edit_file",
|
|
466
|
+
agentId: "bridge",
|
|
467
|
+
},
|
|
468
|
+
};
|
|
469
|
+
this.emit("tool-executed", {
|
|
470
|
+
tool: "edit_file",
|
|
471
|
+
filePath: validatedPath,
|
|
472
|
+
timestamp: Date.now(),
|
|
473
|
+
});
|
|
474
|
+
return result;
|
|
475
|
+
}
|
|
476
|
+
catch (error) {
|
|
477
|
+
return {
|
|
478
|
+
success: false,
|
|
479
|
+
error: error instanceof Error ? error.message : String(error),
|
|
480
|
+
metadata: {
|
|
481
|
+
executionTime: 0,
|
|
482
|
+
toolName: "edit_file",
|
|
483
|
+
agentId: "bridge",
|
|
484
|
+
},
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Edit file using search and replace (alias for editFile).
|
|
490
|
+
*/
|
|
491
|
+
async searchReplace(filePath, oldString, newString) {
|
|
492
|
+
return this.editFile(filePath, oldString, newString);
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* List directory contents.
|
|
496
|
+
* Uses native fs.promises — no CLI delegation.
|
|
497
|
+
*/
|
|
498
|
+
async listDir(dirPath, options = {}) {
|
|
499
|
+
const permission = this.checkPermission("read_file");
|
|
500
|
+
if (permission === "deny") {
|
|
501
|
+
return { success: false, error: "Permission denied: list_dir" };
|
|
502
|
+
}
|
|
503
|
+
// Validate path to prevent traversal attacks
|
|
504
|
+
let validatedPath;
|
|
505
|
+
try {
|
|
506
|
+
validatedPath = this.validateFilePath(dirPath);
|
|
507
|
+
}
|
|
508
|
+
catch (error) {
|
|
509
|
+
return {
|
|
510
|
+
success: false,
|
|
511
|
+
error: `Path validation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
try {
|
|
515
|
+
let entries;
|
|
516
|
+
const dirEntries = await fs.readdir(validatedPath, { withFileTypes: true });
|
|
517
|
+
entries = dirEntries
|
|
518
|
+
.filter((entry) => {
|
|
519
|
+
if (options.ignore) {
|
|
520
|
+
for (const ign of options.ignore) {
|
|
521
|
+
if (entry.name.includes(ign) || entry.name.match(ign))
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
if (options.glob) {
|
|
526
|
+
return simpleGlobMatch(entry.name, options.glob);
|
|
527
|
+
}
|
|
528
|
+
return true;
|
|
529
|
+
})
|
|
530
|
+
.map((entry) => (entry.isDirectory() ? entry.name + "/" : entry.name));
|
|
531
|
+
entries.sort();
|
|
532
|
+
return {
|
|
533
|
+
success: true,
|
|
534
|
+
output: entries.join("\n"),
|
|
535
|
+
metadata: {
|
|
536
|
+
executionTime: 0,
|
|
537
|
+
toolName: "list_dir",
|
|
538
|
+
agentId: "bridge",
|
|
539
|
+
},
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
catch (error) {
|
|
543
|
+
return {
|
|
544
|
+
success: false,
|
|
545
|
+
error: error instanceof Error ? error.message : String(error),
|
|
546
|
+
metadata: {
|
|
547
|
+
executionTime: 0,
|
|
548
|
+
toolName: "list_dir",
|
|
549
|
+
agentId: "bridge",
|
|
550
|
+
},
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Search for regex patterns in file contents.
|
|
556
|
+
* Uses native fs.promises with recursive file walk — no CLI delegation.
|
|
557
|
+
*/
|
|
558
|
+
async searchFiles(pattern, options = {}) {
|
|
559
|
+
const permission = this.checkPermission("read_file");
|
|
560
|
+
if (permission === "deny") {
|
|
561
|
+
return { success: false, error: "Permission denied: search_files" };
|
|
562
|
+
}
|
|
563
|
+
// Determine search root
|
|
564
|
+
let searchRoot = this.projectRoot;
|
|
565
|
+
if (options.path) {
|
|
566
|
+
try {
|
|
567
|
+
searchRoot = this.validateFilePath(options.path);
|
|
568
|
+
}
|
|
569
|
+
catch (error) {
|
|
570
|
+
return {
|
|
571
|
+
success: false,
|
|
572
|
+
error: `Path validation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
try {
|
|
577
|
+
const regex = options.caseSensitive
|
|
578
|
+
? new RegExp(pattern)
|
|
579
|
+
: new RegExp(pattern, "i");
|
|
580
|
+
const results = [];
|
|
581
|
+
const includeFilter = options.include
|
|
582
|
+
? new RegExp(options.include.replace(/\*/g, ".*"))
|
|
583
|
+
: null;
|
|
584
|
+
const excludeFilter = options.exclude
|
|
585
|
+
? new RegExp(options.exclude.replace(/\*/g, ".*"))
|
|
586
|
+
: null;
|
|
587
|
+
// Recursively walk the directory
|
|
588
|
+
await walkDirectory(searchRoot, async (filePath) => {
|
|
589
|
+
if (results.length >= (options.maxResults || 1000))
|
|
590
|
+
return;
|
|
591
|
+
// Apply include/exclude filters
|
|
592
|
+
const relativePath = path.relative(searchRoot, filePath);
|
|
593
|
+
if (includeFilter && !includeFilter.test(relativePath))
|
|
594
|
+
return;
|
|
595
|
+
if (excludeFilter && excludeFilter.test(relativePath))
|
|
596
|
+
return;
|
|
597
|
+
try {
|
|
598
|
+
const content = await fs.readFile(filePath, { encoding: "utf8" });
|
|
599
|
+
const lines = content.split("\n");
|
|
600
|
+
for (let i = 0; i < lines.length; i++) {
|
|
601
|
+
if (regex.test(lines[i])) {
|
|
602
|
+
results.push(`${filePath}:${i + 1}:${lines[i].trim()}`);
|
|
603
|
+
if (results.length >= (options.maxResults || 1000))
|
|
604
|
+
break;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
catch {
|
|
609
|
+
// Skip binary or unreadable files
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
return {
|
|
613
|
+
success: true,
|
|
614
|
+
output: results.join("\n"),
|
|
615
|
+
metadata: {
|
|
616
|
+
executionTime: 0,
|
|
617
|
+
toolName: "search_files",
|
|
618
|
+
agentId: "bridge",
|
|
619
|
+
},
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
catch (error) {
|
|
623
|
+
return {
|
|
624
|
+
success: false,
|
|
625
|
+
error: error instanceof Error ? error.message : String(error),
|
|
626
|
+
metadata: {
|
|
627
|
+
executionTime: 0,
|
|
628
|
+
toolName: "search_files",
|
|
629
|
+
agentId: "bridge",
|
|
630
|
+
},
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Find files by pattern (glob-like name matching).
|
|
636
|
+
* Uses native fs.promises — no CLI delegation.
|
|
637
|
+
*/
|
|
638
|
+
async fileSearch(pattern, options = {}) {
|
|
639
|
+
// Determine search root
|
|
640
|
+
let searchRoot = this.projectRoot;
|
|
641
|
+
if (options.path) {
|
|
642
|
+
try {
|
|
643
|
+
searchRoot = this.validateFilePath(options.path);
|
|
644
|
+
}
|
|
645
|
+
catch (error) {
|
|
646
|
+
return {
|
|
647
|
+
success: false,
|
|
648
|
+
error: `Path validation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
try {
|
|
653
|
+
const results = [];
|
|
654
|
+
await walkDirectory(searchRoot, async (filePath) => {
|
|
655
|
+
const relativePath = path.relative(searchRoot, filePath);
|
|
656
|
+
// Match against the pattern (simple globe-like matching on filename or path)
|
|
657
|
+
if (simpleGlobMatch(path.basename(filePath), pattern) ||
|
|
658
|
+
simpleGlobMatch(relativePath, pattern)) {
|
|
659
|
+
results.push(relativePath);
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
results.sort();
|
|
663
|
+
return {
|
|
664
|
+
success: true,
|
|
665
|
+
output: results.join("\n"),
|
|
666
|
+
metadata: {
|
|
667
|
+
executionTime: 0,
|
|
668
|
+
toolName: "file_search",
|
|
669
|
+
agentId: "bridge",
|
|
670
|
+
},
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
catch (error) {
|
|
674
|
+
return {
|
|
675
|
+
success: false,
|
|
676
|
+
error: error instanceof Error ? error.message : String(error),
|
|
677
|
+
metadata: {
|
|
678
|
+
executionTime: 0,
|
|
679
|
+
toolName: "file_search",
|
|
680
|
+
agentId: "bridge",
|
|
681
|
+
},
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
// ========================================================================
|
|
686
|
+
// Bash Operations
|
|
687
|
+
// ========================================================================
|
|
688
|
+
/**
|
|
689
|
+
* Execute bash command.
|
|
690
|
+
* Uses BunShell ($) when running as a plugin, falls back to spawn otherwise.
|
|
691
|
+
*/
|
|
692
|
+
async runBash(command, options = {}) {
|
|
693
|
+
const permission = this.checkPermission("run_bash");
|
|
694
|
+
if (permission === "deny") {
|
|
695
|
+
return { success: false, error: "Permission denied: run_bash" };
|
|
696
|
+
}
|
|
697
|
+
// Validate command for dangerous patterns
|
|
698
|
+
try {
|
|
699
|
+
this.validateCommand(command);
|
|
700
|
+
}
|
|
701
|
+
catch (error) {
|
|
702
|
+
return {
|
|
703
|
+
success: false,
|
|
704
|
+
error: `Command validation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
// When running as an OpenCode plugin, use BunShell instead of spawn.
|
|
708
|
+
// BunShell is non-interactive by default and provides text()/json() output.
|
|
709
|
+
if (_pluginInput?.$) {
|
|
710
|
+
const startTime = Date.now();
|
|
711
|
+
try {
|
|
712
|
+
const workdir = options.cwd || _pluginInput.directory || process.cwd();
|
|
713
|
+
if (workdir !== process.cwd()) {
|
|
714
|
+
// BunShell doesn't auto-cd; we use the shell's chaining mechanism
|
|
715
|
+
// by prepending cd to the command
|
|
716
|
+
const shellResult = await _pluginInput.$ `cd ${workdir} && ${command}`;
|
|
717
|
+
const text = await shellResult.quiet().text();
|
|
718
|
+
return {
|
|
719
|
+
success: true,
|
|
720
|
+
output: text,
|
|
721
|
+
metadata: {
|
|
722
|
+
executionTime: Date.now() - startTime,
|
|
723
|
+
toolName: "run_bash",
|
|
724
|
+
agentId: "bridge",
|
|
725
|
+
},
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
const result = await _pluginInput.$ `${command}`;
|
|
729
|
+
const output = await result.quiet().text();
|
|
730
|
+
return {
|
|
731
|
+
success: true,
|
|
732
|
+
output,
|
|
733
|
+
metadata: {
|
|
734
|
+
executionTime: Date.now() - startTime,
|
|
735
|
+
toolName: "run_bash",
|
|
736
|
+
agentId: "bridge",
|
|
737
|
+
},
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
catch (error) {
|
|
741
|
+
return {
|
|
742
|
+
success: false,
|
|
743
|
+
error: error instanceof Error ? error.message : String(error),
|
|
744
|
+
metadata: {
|
|
745
|
+
executionTime: Date.now() - startTime,
|
|
746
|
+
toolName: "run_bash",
|
|
747
|
+
agentId: "bridge",
|
|
748
|
+
},
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
// Standalone mode: use spawn
|
|
753
|
+
return this.executeCommand("bash", ["-c", command], {
|
|
754
|
+
cwd: options.cwd,
|
|
755
|
+
timeout: options.timeout,
|
|
756
|
+
env: options.env,
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
/**
|
|
760
|
+
* Run npm command securely using spawn with array arguments
|
|
761
|
+
*/
|
|
762
|
+
async runNpm(command, args = []) {
|
|
763
|
+
const permission = this.checkPermission("run_bash");
|
|
764
|
+
if (permission === "deny") {
|
|
765
|
+
return { success: false, error: "Permission denied: run_bash" };
|
|
766
|
+
}
|
|
767
|
+
// Validate all arguments
|
|
768
|
+
try {
|
|
769
|
+
for (const arg of args) {
|
|
770
|
+
validateCommandArg(arg);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
catch (error) {
|
|
774
|
+
return {
|
|
775
|
+
success: false,
|
|
776
|
+
error: `Argument validation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
// Use spawn with array arguments instead of string interpolation
|
|
780
|
+
return this.executeCommand("npm", [command, ...args], { timeout: 120000 });
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* Run git command securely using spawn with array arguments
|
|
784
|
+
*/
|
|
785
|
+
async runGit(args) {
|
|
786
|
+
const permission = this.checkPermission("run_bash");
|
|
787
|
+
if (permission === "deny") {
|
|
788
|
+
return { success: false, error: "Permission denied: run_bash" };
|
|
789
|
+
}
|
|
790
|
+
// Validate all arguments
|
|
791
|
+
try {
|
|
792
|
+
for (const arg of args) {
|
|
793
|
+
validateCommandArg(arg);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
catch (error) {
|
|
797
|
+
return {
|
|
798
|
+
success: false,
|
|
799
|
+
error: `Argument validation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
// Use spawn with array arguments instead of string interpolation
|
|
803
|
+
return this.executeCommand("git", args, { timeout: 60000 });
|
|
804
|
+
}
|
|
805
|
+
// ========================================================================
|
|
806
|
+
// Web Operations — Native fetch() + opencode run (NOT opencode search/fetch)
|
|
807
|
+
// ========================================================================
|
|
808
|
+
/**
|
|
809
|
+
* Search the web.
|
|
810
|
+
* Delegates to `opencode run` (valid subcommand) with search prompt.
|
|
811
|
+
*/
|
|
812
|
+
async webSearch(query, options = {}) {
|
|
813
|
+
const permission = this.checkPermission("web_search");
|
|
814
|
+
if (permission === "deny") {
|
|
815
|
+
return { success: false, error: "Permission denied: web_search" };
|
|
816
|
+
}
|
|
817
|
+
const searchPrompt = `Search the web for: ${query}`;
|
|
818
|
+
const args = ["run", searchPrompt, "--format", "json"];
|
|
819
|
+
if (options.numResults)
|
|
820
|
+
args.push("--max-results", String(options.numResults));
|
|
821
|
+
return this.executeCommand("opencode", args, { timeout: 60000 });
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Fetch URL content.
|
|
825
|
+
* Uses global fetch() (available in Node.js 20+) — no CLI delegation.
|
|
826
|
+
*/
|
|
827
|
+
async fetchUrl(url, options = {}) {
|
|
828
|
+
const permission = this.checkPermission("fetch_url");
|
|
829
|
+
if (permission === "deny") {
|
|
830
|
+
return { success: false, error: "Permission denied: fetch_url" };
|
|
831
|
+
}
|
|
832
|
+
const startTime = Date.now();
|
|
833
|
+
try {
|
|
834
|
+
const response = await fetch(url);
|
|
835
|
+
if (!response.ok) {
|
|
836
|
+
return {
|
|
837
|
+
success: false,
|
|
838
|
+
error: `HTTP ${response.status}: ${response.statusText}`,
|
|
839
|
+
metadata: {
|
|
840
|
+
executionTime: Date.now() - startTime,
|
|
841
|
+
toolName: "fetch_url",
|
|
842
|
+
agentId: "bridge",
|
|
843
|
+
},
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
let output;
|
|
847
|
+
const contentType = response.headers.get("content-type") || "";
|
|
848
|
+
if (options.format === "html" || contentType.includes("text/html")) {
|
|
849
|
+
output = await response.text();
|
|
850
|
+
}
|
|
851
|
+
else if (options.format === "markdown") {
|
|
852
|
+
// Simple markdown-ish conversion: strip HTML tags, keep text
|
|
853
|
+
const text = await response.text();
|
|
854
|
+
output = text
|
|
855
|
+
.replace(/<[^>]+>/g, "")
|
|
856
|
+
.replace(/\n{3,}/g, "\n\n")
|
|
857
|
+
.trim();
|
|
858
|
+
}
|
|
859
|
+
else {
|
|
860
|
+
output = await response.text();
|
|
861
|
+
}
|
|
862
|
+
return {
|
|
863
|
+
success: true,
|
|
864
|
+
output,
|
|
865
|
+
metadata: {
|
|
866
|
+
executionTime: Date.now() - startTime,
|
|
867
|
+
toolName: "fetch_url",
|
|
868
|
+
agentId: "bridge",
|
|
869
|
+
},
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
catch (error) {
|
|
873
|
+
return {
|
|
874
|
+
success: false,
|
|
875
|
+
error: error instanceof Error ? error.message : String(error),
|
|
876
|
+
metadata: {
|
|
877
|
+
executionTime: Date.now() - startTime,
|
|
878
|
+
toolName: "fetch_url",
|
|
879
|
+
agentId: "bridge",
|
|
880
|
+
},
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
/**
|
|
885
|
+
* Call the configured model with a prompt.
|
|
886
|
+
* Uses valid `opencode run --model ... --format json` — NOT opencode ask.
|
|
887
|
+
*/
|
|
888
|
+
async callModel(prompt, options = {}) {
|
|
889
|
+
const model = options.model || "default";
|
|
890
|
+
// Build the prompt to include configuration in the message
|
|
891
|
+
let fullPrompt = prompt;
|
|
892
|
+
if (options.temperature !== undefined) {
|
|
893
|
+
fullPrompt = `[temperature=${options.temperature}] ${fullPrompt}`;
|
|
894
|
+
}
|
|
895
|
+
if (options.maxTokens !== undefined) {
|
|
896
|
+
fullPrompt = `[max_tokens=${options.maxTokens}] ${fullPrompt}`;
|
|
897
|
+
}
|
|
898
|
+
const args = ["run", fullPrompt, "--model", model, "--format", "json"];
|
|
899
|
+
return this.executeCommand("opencode", args, { timeout: 120000 });
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Call MCP server tool.
|
|
903
|
+
* Uses valid `opencode mcp` subcommands.
|
|
904
|
+
* Note: `opencode mcp call` is not a valid subcommand — MCP tool calling
|
|
905
|
+
* happens internally via OpenCode's agent runtime. This method provides
|
|
906
|
+
* best-effort delegation via `opencode run`.
|
|
907
|
+
*
|
|
908
|
+
* Valid opencode mcp subcommands: add, list, auth, logout, debug
|
|
909
|
+
* MCP tool invocation is handled via OpenCode agent sessions.
|
|
910
|
+
*/
|
|
911
|
+
async callMCP(serverName, toolName, args) {
|
|
912
|
+
const permission = this.checkPermission("call_mcp");
|
|
913
|
+
if (permission === "deny") {
|
|
914
|
+
return { success: false, error: "Permission denied: call_mcp" };
|
|
915
|
+
}
|
|
916
|
+
// Delegate to opencode run with MCP context prompt
|
|
917
|
+
const argsString = JSON.stringify({ tool: toolName, args });
|
|
918
|
+
const mcpPrompt = `Call MCP tool "${toolName}" on server "${serverName}" with arguments: ${argsString}. Execute the tool and return the result.`;
|
|
919
|
+
const runArgs = ["run", mcpPrompt, "--format", "json"];
|
|
920
|
+
return this.executeCommand("opencode", runArgs, { timeout: 60000 });
|
|
921
|
+
}
|
|
922
|
+
// ========================================================================
|
|
923
|
+
// Utility Methods
|
|
924
|
+
// ========================================================================
|
|
925
|
+
/**
|
|
926
|
+
* Get the underlying process manager
|
|
927
|
+
*/
|
|
928
|
+
getProcessManager() {
|
|
929
|
+
return this._processManager;
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* Get tool call history
|
|
933
|
+
*/
|
|
934
|
+
getHistory() {
|
|
935
|
+
return [...this.toolHistory];
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* Clear tool call history
|
|
939
|
+
*/
|
|
940
|
+
clearHistory() {
|
|
941
|
+
this.toolHistory = [];
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Update permission for a tool
|
|
945
|
+
*/
|
|
946
|
+
setPermission(tool, permission) {
|
|
947
|
+
this.permissionCache.set(tool, permission);
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Check if OpenCode CLI is available by checking its version.
|
|
951
|
+
*/
|
|
952
|
+
async checkAvailability() {
|
|
953
|
+
try {
|
|
954
|
+
const result = await this.runBash("opencode --version", {
|
|
955
|
+
timeout: 5000,
|
|
956
|
+
});
|
|
957
|
+
return result.success;
|
|
958
|
+
}
|
|
959
|
+
catch {
|
|
960
|
+
return false;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* Get OpenCode version
|
|
965
|
+
*/
|
|
966
|
+
async getVersion() {
|
|
967
|
+
try {
|
|
968
|
+
const result = await this.runBash("opencode --version", {
|
|
969
|
+
timeout: 5000,
|
|
970
|
+
});
|
|
971
|
+
if (result.success && typeof result.output === "string") {
|
|
972
|
+
return result.output.trim();
|
|
973
|
+
}
|
|
974
|
+
return null;
|
|
975
|
+
}
|
|
976
|
+
catch {
|
|
977
|
+
return null;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
// ========================================================================
|
|
981
|
+
// Verification Operations (Synapse v4) — Native + opencode run delegation
|
|
982
|
+
// ========================================================================
|
|
983
|
+
/**
|
|
984
|
+
* Verify entire repository.
|
|
985
|
+
* Delegates to `opencode run` with synapse-analyzer agent.
|
|
986
|
+
*/
|
|
987
|
+
async verifyRepository(repositoryRoot, options = {}) {
|
|
988
|
+
const permission = this.checkPermission("verify_repository");
|
|
989
|
+
if (permission === "deny") {
|
|
990
|
+
return { success: false, error: "Permission denied: verify_repository" };
|
|
991
|
+
}
|
|
992
|
+
let depthInfo = "";
|
|
993
|
+
if (options.maxAuditDepth)
|
|
994
|
+
depthInfo = ` (max depth: ${options.maxAuditDepth})`;
|
|
995
|
+
let failFastInfo = options.failFast ? " — stop on first critical issue" : "";
|
|
996
|
+
let severityInfo = options.severityThreshold
|
|
997
|
+
? ` severity threshold: ${options.severityThreshold}`
|
|
998
|
+
: "";
|
|
999
|
+
const verifyPrompt = `Verify the repository at ${repositoryRoot} for correctness, completeness, and security issues.` +
|
|
1000
|
+
`${depthInfo}${severityInfo}${failFastInfo ? ". " + failFastInfo : ""}. ` +
|
|
1001
|
+
`Analyze all source files, check for common bugs, type errors, and logic issues.` +
|
|
1002
|
+
` Return a structured report of findings.`;
|
|
1003
|
+
const args = ["run", verifyPrompt, "--format", "json"];
|
|
1004
|
+
return this.executeCommand("opencode", args, { timeout: 600000 }); // 10 min
|
|
1005
|
+
}
|
|
1006
|
+
/**
|
|
1007
|
+
* Verify a specific file.
|
|
1008
|
+
* Uses native fs.promises to read and do basic file validation,
|
|
1009
|
+
* then delegates additional analysis to opencode run.
|
|
1010
|
+
*/
|
|
1011
|
+
async verifyFile(filePath, options = {}) {
|
|
1012
|
+
const permission = this.checkPermission("verify_file");
|
|
1013
|
+
if (permission === "deny") {
|
|
1014
|
+
return { success: false, error: "Permission denied: verify_file" };
|
|
1015
|
+
}
|
|
1016
|
+
let validatedPath;
|
|
1017
|
+
try {
|
|
1018
|
+
validatedPath = this.validateFilePath(filePath);
|
|
1019
|
+
}
|
|
1020
|
+
catch (error) {
|
|
1021
|
+
return {
|
|
1022
|
+
success: false,
|
|
1023
|
+
error: `Path validation failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
// Basic native validation
|
|
1027
|
+
try {
|
|
1028
|
+
const stats = await fs.stat(validatedPath);
|
|
1029
|
+
const content = await fs.readFile(validatedPath, { encoding: "utf8" });
|
|
1030
|
+
const issues = [];
|
|
1031
|
+
// Check file size
|
|
1032
|
+
if (stats.size > 1000000) {
|
|
1033
|
+
issues.push(`File size (${(stats.size / 1024 / 1024).toFixed(1)}MB) exceeds 1MB`);
|
|
1034
|
+
}
|
|
1035
|
+
// Check for common issues
|
|
1036
|
+
if (content.length === 0) {
|
|
1037
|
+
issues.push("File is empty");
|
|
1038
|
+
}
|
|
1039
|
+
// Build verification context
|
|
1040
|
+
let checkContext = "";
|
|
1041
|
+
if (options.checkRuntime)
|
|
1042
|
+
checkContext += " Check runtime wiring and correctness.";
|
|
1043
|
+
if (options.checkIntegration)
|
|
1044
|
+
checkContext += " Check integration with other modules.";
|
|
1045
|
+
if (options.checkSecurity)
|
|
1046
|
+
checkContext += " Check for security vulnerabilities.";
|
|
1047
|
+
const verifyPrompt = `Analyze the file at ${validatedPath} for issues.${checkContext} Content:\n\n${content.slice(0, 5000)}`;
|
|
1048
|
+
const args = ["run", verifyPrompt, "--format", "json"];
|
|
1049
|
+
return this.executeCommand("opencode", args, { timeout: 120000 });
|
|
1050
|
+
}
|
|
1051
|
+
catch (error) {
|
|
1052
|
+
return {
|
|
1053
|
+
success: false,
|
|
1054
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1055
|
+
metadata: {
|
|
1056
|
+
executionTime: 0,
|
|
1057
|
+
toolName: "verify_file",
|
|
1058
|
+
agentId: "bridge",
|
|
1059
|
+
},
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
/**
|
|
1064
|
+
* Verify specific claims.
|
|
1065
|
+
* Delegates to opencode run with synapse-verifier agent.
|
|
1066
|
+
*/
|
|
1067
|
+
async verifyClaim(claims, options = {}) {
|
|
1068
|
+
const permission = this.checkPermission("verify_claim");
|
|
1069
|
+
if (permission === "deny") {
|
|
1070
|
+
return { success: false, error: "Permission denied: verify_claim" };
|
|
1071
|
+
}
|
|
1072
|
+
const claimsList = claims.map((c, i) => `${i + 1}. ${c}`).join("\n");
|
|
1073
|
+
let sourceInfo = options.source
|
|
1074
|
+
? ` Reference source: ${options.source}.`
|
|
1075
|
+
: "";
|
|
1076
|
+
let crossRefInfo = options.crossReference
|
|
1077
|
+
? " Cross-reference each claim against the implementation in the codebase."
|
|
1078
|
+
: "";
|
|
1079
|
+
const verifyPrompt = `I need to verify the following claims:${sourceInfo}${crossRefInfo}\n\n${claimsList}\n\n` +
|
|
1080
|
+
`For each claim, check if it is true, partially true, or false. ` +
|
|
1081
|
+
`Provide evidence for your determination.`;
|
|
1082
|
+
const args = ["run", verifyPrompt, "--format", "json"];
|
|
1083
|
+
return this.executeCommand("opencode", args, { timeout: 120000 });
|
|
1084
|
+
}
|
|
1085
|
+
/**
|
|
1086
|
+
* Run recursive audit loop.
|
|
1087
|
+
* Delegates to opencode run for iterative analysis.
|
|
1088
|
+
*/
|
|
1089
|
+
async auditRecursive(repositoryRoot, options = {}) {
|
|
1090
|
+
const permission = this.checkPermission("audit_recursive");
|
|
1091
|
+
if (permission === "deny") {
|
|
1092
|
+
return { success: false, error: "Permission denied: audit_recursive" };
|
|
1093
|
+
}
|
|
1094
|
+
let maxPassesInfo = options.maxPasses
|
|
1095
|
+
? ` maximum ${options.maxPasses} audit passes.`
|
|
1096
|
+
: "";
|
|
1097
|
+
let stopCriticalInfo = options.stopOnCritical
|
|
1098
|
+
? " Stop immediately if a critical issue is found."
|
|
1099
|
+
: "";
|
|
1100
|
+
const auditPrompt = `Perform a recursive audit of the repository at ${repositoryRoot}.` +
|
|
1101
|
+
`${maxPassesInfo}${stopCriticalInfo} ` +
|
|
1102
|
+
`Scan all source files for bugs, security vulnerabilities, type errors, logic errors, ` +
|
|
1103
|
+
`and violations of best practices. After each pass, fix any issues found and re-audit. ` +
|
|
1104
|
+
`Continue until no issues remain or the maximum pass count is reached.`;
|
|
1105
|
+
const args = ["run", auditPrompt, "--format", "json"];
|
|
1106
|
+
return this.executeCommand("opencode", args, { timeout: 600000 });
|
|
1107
|
+
}
|
|
1108
|
+
/**
|
|
1109
|
+
* Call an OpenCode tool by name with parameters.
|
|
1110
|
+
* Delegates to `opencode run` with the tool name in context.
|
|
1111
|
+
*/
|
|
1112
|
+
async callTool(toolCall) {
|
|
1113
|
+
const permission = this.checkPermission(toolCall.tool);
|
|
1114
|
+
if (permission === "deny") {
|
|
1115
|
+
return { success: false, error: `Permission denied: ${toolCall.tool}` };
|
|
1116
|
+
}
|
|
1117
|
+
const startTime = Date.now();
|
|
1118
|
+
const toolName = toolCall.tool;
|
|
1119
|
+
try {
|
|
1120
|
+
const argsString = toolCall.args
|
|
1121
|
+
? JSON.stringify(toolCall.args)
|
|
1122
|
+
: "{}";
|
|
1123
|
+
const toolPrompt = `Execute tool "${toolName}" with these arguments: ${argsString}. ` +
|
|
1124
|
+
`Return the result in JSON format.`;
|
|
1125
|
+
const result = await new Promise((resolve, reject) => {
|
|
1126
|
+
const proc = spawn("opencode", ["run", toolPrompt, "--format", "json"], {
|
|
1127
|
+
cwd: this.projectRoot,
|
|
1128
|
+
env: { ...process.env },
|
|
1129
|
+
timeout: 300000,
|
|
1130
|
+
});
|
|
1131
|
+
let stdout = "";
|
|
1132
|
+
let stderr = "";
|
|
1133
|
+
proc.stdout?.on("data", (data) => {
|
|
1134
|
+
stdout += data.toString();
|
|
1135
|
+
});
|
|
1136
|
+
proc.stderr?.on("data", (data) => {
|
|
1137
|
+
stderr += data.toString();
|
|
1138
|
+
});
|
|
1139
|
+
proc.on("close", (code) => {
|
|
1140
|
+
resolve({ stdout, stderr, exitCode: code || 0 });
|
|
1141
|
+
});
|
|
1142
|
+
proc.on("error", reject);
|
|
1143
|
+
});
|
|
1144
|
+
const toolCallRecord = {
|
|
1145
|
+
tool: toolName,
|
|
1146
|
+
args: toolCall.args || {},
|
|
1147
|
+
timestamp: startTime,
|
|
1148
|
+
agentId: "bridge",
|
|
1149
|
+
};
|
|
1150
|
+
this.toolHistory.push(toolCallRecord);
|
|
1151
|
+
return {
|
|
1152
|
+
success: result.exitCode === 0,
|
|
1153
|
+
output: result.stdout,
|
|
1154
|
+
error: result.stderr || undefined,
|
|
1155
|
+
metadata: {
|
|
1156
|
+
executionTime: Date.now() - startTime,
|
|
1157
|
+
toolName,
|
|
1158
|
+
agentId: "bridge",
|
|
1159
|
+
},
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
catch (error) {
|
|
1163
|
+
return {
|
|
1164
|
+
success: false,
|
|
1165
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1166
|
+
metadata: {
|
|
1167
|
+
executionTime: Date.now() - startTime,
|
|
1168
|
+
toolName,
|
|
1169
|
+
agentId: "bridge",
|
|
1170
|
+
},
|
|
1171
|
+
};
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
/**
|
|
1175
|
+
* Get verification report.
|
|
1176
|
+
* Generates report from native data — no CLI delegation.
|
|
1177
|
+
*/
|
|
1178
|
+
async getVerificationReport(reportPath) {
|
|
1179
|
+
try {
|
|
1180
|
+
if (reportPath) {
|
|
1181
|
+
const validatedPath = this.validateFilePath(reportPath);
|
|
1182
|
+
const content = await fs.readFile(validatedPath, { encoding: "utf8" });
|
|
1183
|
+
return {
|
|
1184
|
+
success: true,
|
|
1185
|
+
output: content,
|
|
1186
|
+
metadata: {
|
|
1187
|
+
executionTime: 0,
|
|
1188
|
+
toolName: "get_verification_report",
|
|
1189
|
+
agentId: "bridge",
|
|
1190
|
+
},
|
|
1191
|
+
};
|
|
1192
|
+
}
|
|
1193
|
+
// Generate a summary report from recent tool history
|
|
1194
|
+
const recentTools = this.toolHistory.slice(-20);
|
|
1195
|
+
const report = {
|
|
1196
|
+
generatedAt: new Date().toISOString(),
|
|
1197
|
+
toolCalls: recentTools.length,
|
|
1198
|
+
recentOperations: recentTools.map((t) => ({
|
|
1199
|
+
tool: t.tool,
|
|
1200
|
+
timestamp: new Date(t.timestamp).toISOString(),
|
|
1201
|
+
})),
|
|
1202
|
+
};
|
|
1203
|
+
return {
|
|
1204
|
+
success: true,
|
|
1205
|
+
output: JSON.stringify(report, null, 2),
|
|
1206
|
+
metadata: {
|
|
1207
|
+
executionTime: 0,
|
|
1208
|
+
toolName: "get_verification_report",
|
|
1209
|
+
agentId: "bridge",
|
|
1210
|
+
},
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
catch (error) {
|
|
1214
|
+
return {
|
|
1215
|
+
success: false,
|
|
1216
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1217
|
+
metadata: {
|
|
1218
|
+
executionTime: 0,
|
|
1219
|
+
toolName: "get_verification_report",
|
|
1220
|
+
agentId: "bridge",
|
|
1221
|
+
},
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
/**
|
|
1226
|
+
* Cross-reference claims with implementation.
|
|
1227
|
+
* Delegates to opencode run for analysis.
|
|
1228
|
+
*/
|
|
1229
|
+
async crossReference(source, target) {
|
|
1230
|
+
const xrefPrompt = `Cross-reference the following source against the target to check consistency:\n\n` +
|
|
1231
|
+
`Source: ${source}\n\nTarget: ${target}\n\n` +
|
|
1232
|
+
`Check if the source claims are implemented in the target. ` +
|
|
1233
|
+
`Report any discrepancies, missing implementations, or inconsistencies.`;
|
|
1234
|
+
const args = ["run", xrefPrompt, "--format", "json"];
|
|
1235
|
+
return this.executeCommand("opencode", args, { timeout: 60000 });
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
// ============================================================================
|
|
1239
|
+
// Helper Functions
|
|
1240
|
+
// ============================================================================
|
|
1241
|
+
/**
|
|
1242
|
+
* Simple glob pattern matching (supports * and ? wildcards).
|
|
1243
|
+
*/
|
|
1244
|
+
function simpleGlobMatch(name, pattern) {
|
|
1245
|
+
// Convert glob pattern to regex
|
|
1246
|
+
const regexStr = pattern
|
|
1247
|
+
.replace(/\./g, "\\.")
|
|
1248
|
+
.replace(/\*/g, ".*")
|
|
1249
|
+
.replace(/\?/g, ".");
|
|
1250
|
+
try {
|
|
1251
|
+
return new RegExp(`^${regexStr}$`).test(name);
|
|
1252
|
+
}
|
|
1253
|
+
catch {
|
|
1254
|
+
return name.includes(pattern);
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
/**
|
|
1258
|
+
* Recursively walk a directory tree, calling callback for each file.
|
|
1259
|
+
* Skips node_modules, .git, dist, and other common excluded dirs.
|
|
1260
|
+
*/
|
|
1261
|
+
async function walkDirectory(dirPath, callback) {
|
|
1262
|
+
const excludeDirs = new Set([
|
|
1263
|
+
"node_modules",
|
|
1264
|
+
".git",
|
|
1265
|
+
"dist",
|
|
1266
|
+
".next",
|
|
1267
|
+
"build",
|
|
1268
|
+
"coverage",
|
|
1269
|
+
".cache",
|
|
1270
|
+
"target",
|
|
1271
|
+
"__pycache__",
|
|
1272
|
+
".opencode",
|
|
1273
|
+
]);
|
|
1274
|
+
try {
|
|
1275
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
1276
|
+
for (const entry of entries) {
|
|
1277
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
1278
|
+
if (entry.isDirectory()) {
|
|
1279
|
+
if (!excludeDirs.has(entry.name)) {
|
|
1280
|
+
await walkDirectory(fullPath, callback);
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
else if (entry.isFile()) {
|
|
1284
|
+
await callback(fullPath);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
catch {
|
|
1289
|
+
// Skip directories we can't read
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
// ============================================================================
|
|
1293
|
+
// Factory Function
|
|
1294
|
+
// ============================================================================
|
|
1295
|
+
export function createToolBridge(config) {
|
|
1296
|
+
return new OpenCodeToolBridge(config);
|
|
1297
|
+
}
|
|
1298
|
+
// ============================================================================
|
|
1299
|
+
// Standalone Tool Functions (for use by verification modules)
|
|
1300
|
+
//
|
|
1301
|
+
// These are convenience wrappers that delegate to a default bridge instance.
|
|
1302
|
+
// The bridge instance is lazily created on first use.
|
|
1303
|
+
// ============================================================================
|
|
1304
|
+
let defaultToolBridge = null;
|
|
1305
|
+
function getDefaultBridge() {
|
|
1306
|
+
if (!defaultToolBridge) {
|
|
1307
|
+
defaultToolBridge = createToolBridge();
|
|
1308
|
+
}
|
|
1309
|
+
return defaultToolBridge;
|
|
1310
|
+
}
|
|
1311
|
+
export async function readFile(filePath, options) {
|
|
1312
|
+
return getDefaultBridge().readFile(filePath, options);
|
|
1313
|
+
}
|
|
1314
|
+
export async function readFileContent(filePath) {
|
|
1315
|
+
return getDefaultBridge().readFileContent(filePath);
|
|
1316
|
+
}
|
|
1317
|
+
export async function writeFile(filePath, content, options) {
|
|
1318
|
+
return getDefaultBridge().writeFile(filePath, content, options);
|
|
1319
|
+
}
|
|
1320
|
+
export async function editFile(filePath, oldString, newString) {
|
|
1321
|
+
return getDefaultBridge().editFile(filePath, oldString, newString);
|
|
1322
|
+
}
|
|
1323
|
+
export async function listDir(dirPath, options) {
|
|
1324
|
+
return getDefaultBridge().listDir(dirPath, options);
|
|
1325
|
+
}
|
|
1326
|
+
export async function searchFiles(pattern, options) {
|
|
1327
|
+
return getDefaultBridge().searchFiles(pattern, options);
|
|
1328
|
+
}
|
|
1329
|
+
export async function fileSearch(pattern, options) {
|
|
1330
|
+
return getDefaultBridge().fileSearch(pattern, options);
|
|
1331
|
+
}
|
|
1332
|
+
export async function runBash(command, options) {
|
|
1333
|
+
return getDefaultBridge().runBash(command, options);
|
|
1334
|
+
}
|
|
1335
|
+
export async function webSearch(query, options) {
|
|
1336
|
+
return getDefaultBridge().webSearch(query, options);
|
|
1337
|
+
}
|
|
1338
|
+
export async function grep(pattern, options) {
|
|
1339
|
+
const result = await getDefaultBridge().searchFiles(pattern, options);
|
|
1340
|
+
if (result.success && typeof result.output === "string") {
|
|
1341
|
+
return result.output.split("\n").filter(line => line.trim());
|
|
1342
|
+
}
|
|
1343
|
+
return [];
|
|
1344
|
+
}
|
|
1345
|
+
export async function glob(options) {
|
|
1346
|
+
const result = await getDefaultBridge().fileSearch(options.pattern, { path: options.path });
|
|
1347
|
+
if (result.success && typeof result.output === "string") {
|
|
1348
|
+
return result.output.split("\n").filter(line => line.trim());
|
|
1349
|
+
}
|
|
1350
|
+
return [];
|
|
1351
|
+
}
|
|
1352
|
+
// ============================================================================
|
|
1353
|
+
// Default Export
|
|
1354
|
+
// ============================================================================
|
|
1355
|
+
export default OpenCodeToolBridge;
|
|
1356
|
+
//# sourceMappingURL=tool-bridge.js.map
|