opencode-dux 1.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/LICENSE +21 -0
- package/README.md +452 -0
- package/dist/agents/descriptions.d.ts +6 -0
- package/dist/agents/designer.d.ts +2 -0
- package/dist/agents/explorer.d.ts +2 -0
- package/dist/agents/fixer.d.ts +2 -0
- package/dist/agents/index.d.ts +22 -0
- package/dist/agents/interpreter.d.ts +2 -0
- package/dist/agents/librarian.d.ts +2 -0
- package/dist/agents/oracle.d.ts +2 -0
- package/dist/agents/orchestrator.d.ts +27 -0
- package/dist/agents/overrides.d.ts +18 -0
- package/dist/agents/prompt-blocks.d.ts +97 -0
- package/dist/agents/steward.d.ts +3 -0
- package/dist/cli/config-io.d.ts +24 -0
- package/dist/cli/config-manager.d.ts +4 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +1006 -0
- package/dist/cli/install.d.ts +2 -0
- package/dist/cli/mcps.d.ts +13 -0
- package/dist/cli/model-key-normalization.d.ts +1 -0
- package/dist/cli/paths.d.ts +35 -0
- package/dist/cli/providers.d.ts +137 -0
- package/dist/cli/skills.d.ts +22 -0
- package/dist/cli/system.d.ts +5 -0
- package/dist/cli/types.d.ts +38 -0
- package/dist/config/constants.d.ts +12 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/loader.d.ts +40 -0
- package/dist/config/runtime-preset.d.ts +12 -0
- package/dist/config/schema.d.ts +281 -0
- package/dist/config/utils.d.ts +10 -0
- package/dist/discovery/local/types.d.ts +79 -0
- package/dist/discovery/local.d.ts +73 -0
- package/dist/discovery/mcp-servers.d.ts +88 -0
- package/dist/discovery/skills.d.ts +94 -0
- package/dist/hooks/apply-patch/codec.d.ts +7 -0
- package/dist/hooks/apply-patch/errors.d.ts +25 -0
- package/dist/hooks/apply-patch/execution-context.d.ts +27 -0
- package/dist/hooks/apply-patch/index.d.ts +15 -0
- package/dist/hooks/apply-patch/matching.d.ts +26 -0
- package/dist/hooks/apply-patch/operations.d.ts +3 -0
- package/dist/hooks/apply-patch/patch.d.ts +2 -0
- package/dist/hooks/apply-patch/prepared-changes.d.ts +17 -0
- package/dist/hooks/apply-patch/resolution.d.ts +19 -0
- package/dist/hooks/apply-patch/rewrite.d.ts +7 -0
- package/dist/hooks/apply-patch/test-helpers.d.ts +6 -0
- package/dist/hooks/apply-patch/types.d.ts +80 -0
- package/dist/hooks/auto-update-checker/cache.d.ts +11 -0
- package/dist/hooks/auto-update-checker/checker.d.ts +32 -0
- package/dist/hooks/auto-update-checker/constants.d.ts +11 -0
- package/dist/hooks/auto-update-checker/index.d.ts +18 -0
- package/dist/hooks/auto-update-checker/types.d.ts +22 -0
- package/dist/hooks/chat-headers.d.ts +16 -0
- package/dist/hooks/context-pressure-reminder/index.d.ts +33 -0
- package/dist/hooks/delegate-task-retry/guidance.d.ts +2 -0
- package/dist/hooks/delegate-task-retry/hook.d.ts +8 -0
- package/dist/hooks/delegate-task-retry/index.d.ts +4 -0
- package/dist/hooks/delegate-task-retry/patterns.d.ts +11 -0
- package/dist/hooks/filter-available-skills/index.d.ts +32 -0
- package/dist/hooks/foreground-fallback/index.d.ts +72 -0
- package/dist/hooks/image-hook.d.ts +5 -0
- package/dist/hooks/index.d.ts +14 -0
- package/dist/hooks/json-error-recovery/hook.d.ts +18 -0
- package/dist/hooks/json-error-recovery/index.d.ts +1 -0
- package/dist/hooks/phase-reminder/index.d.ts +26 -0
- package/dist/hooks/post-file-tool-nudge/index.d.ts +19 -0
- package/dist/hooks/task-session-manager/index.d.ts +52 -0
- package/dist/hooks/todo-continuation/index.d.ts +53 -0
- package/dist/hooks/todo-continuation/todo-hygiene.d.ts +35 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +31782 -0
- package/dist/mcp/context7.d.ts +6 -0
- package/dist/mcp/grep-app.d.ts +6 -0
- package/dist/mcp/index.d.ts +13 -0
- package/dist/mcp/types.d.ts +12 -0
- package/dist/mcp/websearch.d.ts +9 -0
- package/dist/skills/registry.d.ts +29 -0
- package/dist/subscriptions/accounts-store.d.ts +57 -0
- package/dist/subscriptions/index.d.ts +13 -0
- package/dist/subscriptions/neuralwatt-scraper.d.ts +14 -0
- package/dist/subscriptions/opencode-go-scraper.d.ts +27 -0
- package/dist/subscriptions/types.d.ts +115 -0
- package/dist/subscriptions/usage-service.d.ts +74 -0
- package/dist/tools/ast-grep/cli.d.ts +15 -0
- package/dist/tools/ast-grep/constants.d.ts +25 -0
- package/dist/tools/ast-grep/downloader.d.ts +5 -0
- package/dist/tools/ast-grep/index.d.ts +10 -0
- package/dist/tools/ast-grep/tools.d.ts +3 -0
- package/dist/tools/ast-grep/types.d.ts +30 -0
- package/dist/tools/ast-grep/utils.d.ts +4 -0
- package/dist/tools/delegate.d.ts +14 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/preset-manager.d.ts +27 -0
- package/dist/tools/smartfetch/binary.d.ts +3 -0
- package/dist/tools/smartfetch/cache.d.ts +6 -0
- package/dist/tools/smartfetch/constants.d.ts +12 -0
- package/dist/tools/smartfetch/index.d.ts +3 -0
- package/dist/tools/smartfetch/network.d.ts +38 -0
- package/dist/tools/smartfetch/secondary-model.d.ts +28 -0
- package/dist/tools/smartfetch/tool.d.ts +3 -0
- package/dist/tools/smartfetch/types.d.ts +122 -0
- package/dist/tools/smartfetch/utils.d.ts +18 -0
- package/dist/tui-state.d.ts +168 -0
- package/dist/tui.d.ts +37 -0
- package/dist/tui.js +1896 -0
- package/dist/utils/agent-variant.d.ts +63 -0
- package/dist/utils/compat.d.ts +30 -0
- package/dist/utils/env.d.ts +1 -0
- package/dist/utils/index.d.ts +9 -0
- package/dist/utils/internal-initiator.d.ts +6 -0
- package/dist/utils/logger.d.ts +8 -0
- package/dist/utils/polling.d.ts +21 -0
- package/dist/utils/session-manager.d.ts +55 -0
- package/dist/utils/session.d.ts +90 -0
- package/dist/utils/subagent-depth.d.ts +35 -0
- package/dist/utils/system-collapse.d.ts +6 -0
- package/dist/utils/task.d.ts +4 -0
- package/dist/utils/zip-extractor.d.ts +1 -0
- package/index.ts +1 -0
- package/opencode-dux.schema.json +634 -0
- package/package.json +103 -0
- package/src/agents/descriptions.ts +55 -0
- package/src/agents/designer.test.ts +86 -0
- package/src/agents/designer.ts +154 -0
- package/src/agents/display-name.test.ts +186 -0
- package/src/agents/explorer.test.ts +79 -0
- package/src/agents/explorer.ts +144 -0
- package/src/agents/fixer.test.ts +79 -0
- package/src/agents/fixer.ts +145 -0
- package/src/agents/index.test.ts +472 -0
- package/src/agents/index.ts +248 -0
- package/src/agents/interpreter.ts +136 -0
- package/src/agents/librarian.test.ts +80 -0
- package/src/agents/librarian.ts +145 -0
- package/src/agents/oracle.test.ts +89 -0
- package/src/agents/oracle.ts +184 -0
- package/src/agents/orchestrator.test.ts +116 -0
- package/src/agents/orchestrator.ts +574 -0
- package/src/agents/overrides.ts +95 -0
- package/src/agents/prompt-blocks.test.ts +114 -0
- package/src/agents/prompt-blocks.ts +640 -0
- package/src/agents/steward.ts +146 -0
- package/src/cli/config-io.test.ts +536 -0
- package/src/cli/config-io.ts +473 -0
- package/src/cli/config-manager.test.ts +141 -0
- package/src/cli/config-manager.ts +4 -0
- package/src/cli/index.ts +88 -0
- package/src/cli/install.ts +282 -0
- package/src/cli/mcps.test.ts +62 -0
- package/src/cli/mcps.ts +39 -0
- package/src/cli/model-key-normalization.test.ts +21 -0
- package/src/cli/model-key-normalization.ts +60 -0
- package/src/cli/paths.test.ts +167 -0
- package/src/cli/paths.ts +144 -0
- package/src/cli/providers.test.ts +118 -0
- package/src/cli/providers.ts +141 -0
- package/src/cli/skills.test.ts +111 -0
- package/src/cli/skills.ts +103 -0
- package/src/cli/system.test.ts +91 -0
- package/src/cli/system.ts +180 -0
- package/src/cli/types.ts +43 -0
- package/src/config/constants.ts +58 -0
- package/src/config/index.ts +4 -0
- package/src/config/loader.test.ts +1194 -0
- package/src/config/loader.ts +269 -0
- package/src/config/model-resolution.test.ts +176 -0
- package/src/config/runtime-preset.test.ts +61 -0
- package/src/config/runtime-preset.ts +37 -0
- package/src/config/schema.ts +248 -0
- package/src/config/utils.test.ts +41 -0
- package/src/config/utils.ts +23 -0
- package/src/discovery/local/types.ts +85 -0
- package/src/discovery/local.ts +322 -0
- package/src/discovery/mcp-servers.ts +804 -0
- package/src/discovery/skills.ts +959 -0
- package/src/hooks/apply-patch/codec.test.ts +184 -0
- package/src/hooks/apply-patch/codec.ts +352 -0
- package/src/hooks/apply-patch/errors.ts +117 -0
- package/src/hooks/apply-patch/execution-context.ts +432 -0
- package/src/hooks/apply-patch/hook.test.ts +768 -0
- package/src/hooks/apply-patch/index.ts +126 -0
- package/src/hooks/apply-patch/matching.test.ts +215 -0
- package/src/hooks/apply-patch/matching.ts +586 -0
- package/src/hooks/apply-patch/operations.test.ts +1535 -0
- package/src/hooks/apply-patch/operations.ts +3 -0
- package/src/hooks/apply-patch/patch.ts +9 -0
- package/src/hooks/apply-patch/prepared-changes.ts +400 -0
- package/src/hooks/apply-patch/resolution.test.ts +420 -0
- package/src/hooks/apply-patch/resolution.ts +437 -0
- package/src/hooks/apply-patch/rewrite.ts +496 -0
- package/src/hooks/apply-patch/test-helpers.ts +52 -0
- package/src/hooks/apply-patch/types.ts +111 -0
- package/src/hooks/auto-update-checker/cache.test.ts +179 -0
- package/src/hooks/auto-update-checker/cache.ts +188 -0
- package/src/hooks/auto-update-checker/checker.test.ts +159 -0
- package/src/hooks/auto-update-checker/checker.ts +308 -0
- package/src/hooks/auto-update-checker/constants.ts +33 -0
- package/src/hooks/auto-update-checker/index.test.ts +282 -0
- package/src/hooks/auto-update-checker/index.ts +225 -0
- package/src/hooks/auto-update-checker/types.ts +26 -0
- package/src/hooks/chat-headers.test.ts +236 -0
- package/src/hooks/chat-headers.ts +97 -0
- package/src/hooks/context-pressure-reminder/index.test.ts +179 -0
- package/src/hooks/context-pressure-reminder/index.ts +137 -0
- package/src/hooks/delegate-task-retry/guidance.ts +41 -0
- package/src/hooks/delegate-task-retry/hook.ts +23 -0
- package/src/hooks/delegate-task-retry/index.test.ts +38 -0
- package/src/hooks/delegate-task-retry/index.ts +7 -0
- package/src/hooks/delegate-task-retry/patterns.ts +79 -0
- package/src/hooks/filter-available-skills/index.test.ts +297 -0
- package/src/hooks/filter-available-skills/index.ts +160 -0
- package/src/hooks/foreground-fallback/index.test.ts +624 -0
- package/src/hooks/foreground-fallback/index.ts +374 -0
- package/src/hooks/image-hook.ts +6 -0
- package/src/hooks/index.ts +17 -0
- package/src/hooks/json-error-recovery/hook.ts +73 -0
- package/src/hooks/json-error-recovery/index.test.ts +111 -0
- package/src/hooks/json-error-recovery/index.ts +6 -0
- package/src/hooks/phase-reminder/index.test.ts +74 -0
- package/src/hooks/phase-reminder/index.ts +85 -0
- package/src/hooks/post-file-tool-nudge/index.test.ts +94 -0
- package/src/hooks/post-file-tool-nudge/index.ts +63 -0
- package/src/hooks/task-session-manager/index.test.ts +833 -0
- package/src/hooks/task-session-manager/index.ts +434 -0
- package/src/hooks/todo-continuation/index.test.ts +3026 -0
- package/src/hooks/todo-continuation/index.ts +878 -0
- package/src/hooks/todo-continuation/todo-hygiene.test.ts +204 -0
- package/src/hooks/todo-continuation/todo-hygiene.ts +207 -0
- package/src/index.ts +1672 -0
- package/src/mcp/context7.ts +14 -0
- package/src/mcp/grep-app.ts +11 -0
- package/src/mcp/index.test.ts +96 -0
- package/src/mcp/index.ts +66 -0
- package/src/mcp/types.ts +16 -0
- package/src/mcp/websearch.ts +47 -0
- package/src/skills/codemap/README.md +60 -0
- package/src/skills/codemap/SKILL.md +174 -0
- package/src/skills/codemap/scripts/codemap.mjs +483 -0
- package/src/skills/codemap/scripts/codemap.test.ts +129 -0
- package/src/skills/registry.ts +218 -0
- package/src/skills/simplify/README.md +19 -0
- package/src/skills/simplify/SKILL.md +138 -0
- package/src/subscriptions/accounts-store.test.ts +236 -0
- package/src/subscriptions/accounts-store.ts +184 -0
- package/src/subscriptions/index.ts +30 -0
- package/src/subscriptions/neuralwatt-scraper.ts +108 -0
- package/src/subscriptions/opencode-go-scraper.ts +301 -0
- package/src/subscriptions/types.ts +145 -0
- package/src/subscriptions/usage-service.test.ts +202 -0
- package/src/subscriptions/usage-service.ts +651 -0
- package/src/tools/ast-grep/cli.ts +257 -0
- package/src/tools/ast-grep/constants.ts +214 -0
- package/src/tools/ast-grep/downloader.ts +131 -0
- package/src/tools/ast-grep/index.ts +24 -0
- package/src/tools/ast-grep/tools.ts +117 -0
- package/src/tools/ast-grep/types.ts +51 -0
- package/src/tools/ast-grep/utils.ts +126 -0
- package/src/tools/delegate-handoff.test.ts +18 -0
- package/src/tools/delegate.ts +508 -0
- package/src/tools/index.ts +8 -0
- package/src/tools/preset-manager.test.ts +795 -0
- package/src/tools/preset-manager.ts +332 -0
- package/src/tools/smartfetch/binary.ts +58 -0
- package/src/tools/smartfetch/cache.test.ts +34 -0
- package/src/tools/smartfetch/cache.ts +112 -0
- package/src/tools/smartfetch/constants.ts +29 -0
- package/src/tools/smartfetch/index.ts +8 -0
- package/src/tools/smartfetch/network.test.ts +178 -0
- package/src/tools/smartfetch/network.ts +614 -0
- package/src/tools/smartfetch/secondary-model.test.ts +85 -0
- package/src/tools/smartfetch/secondary-model.ts +276 -0
- package/src/tools/smartfetch/tool.test.ts +60 -0
- package/src/tools/smartfetch/tool.ts +832 -0
- package/src/tools/smartfetch/types.ts +135 -0
- package/src/tools/smartfetch/utils.test.ts +24 -0
- package/src/tools/smartfetch/utils.ts +456 -0
- package/src/tui-state.test.ts +867 -0
- package/src/tui-state.ts +1255 -0
- package/src/tui.test.ts +336 -0
- package/src/tui.ts +1539 -0
- package/src/utils/agent-variant.test.ts +244 -0
- package/src/utils/agent-variant.ts +187 -0
- package/src/utils/compat.ts +91 -0
- package/src/utils/env.ts +12 -0
- package/src/utils/index.ts +9 -0
- package/src/utils/internal-initiator.ts +28 -0
- package/src/utils/logger.test.ts +220 -0
- package/src/utils/logger.ts +136 -0
- package/src/utils/polling.test.ts +191 -0
- package/src/utils/polling.ts +67 -0
- package/src/utils/session-manager.test.ts +173 -0
- package/src/utils/session-manager.ts +356 -0
- package/src/utils/session.test.ts +110 -0
- package/src/utils/session.ts +389 -0
- package/src/utils/subagent-depth.test.ts +170 -0
- package/src/utils/subagent-depth.ts +75 -0
- package/src/utils/system-collapse.test.ts +86 -0
- package/src/utils/system-collapse.ts +24 -0
- package/src/utils/task.test.ts +24 -0
- package/src/utils/task.ts +20 -0
- package/src/utils/zip-extractor.ts +102 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import type { PluginInput } from '@opencode-ai/plugin';
|
|
2
|
+
import { log } from '../utils/logger';
|
|
3
|
+
import { SDK_DISCOVERY_TIMEOUT_MS } from '../config/constants';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A single MCP server discovered via the OpenCode SDK.
|
|
7
|
+
*/
|
|
8
|
+
export interface DiscoveredMcp {
|
|
9
|
+
/** Unique name used as the config key (e.g., 'playwright', 'github'). */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Current connection status reported by OpenCode. */
|
|
12
|
+
status:
|
|
13
|
+
| 'connected'
|
|
14
|
+
| 'disabled'
|
|
15
|
+
| 'failed'
|
|
16
|
+
| 'needs_auth'
|
|
17
|
+
| 'needs_client_registration';
|
|
18
|
+
/** Human-readable description, may include error details when status is 'failed'. */
|
|
19
|
+
description?: string;
|
|
20
|
+
/** Categorization tags derived from the MCP name. */
|
|
21
|
+
tags: string[];
|
|
22
|
+
/** Agents that benefit most from this MCP based on defaults. */
|
|
23
|
+
recommendedAgents: string[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* A single skill discovered via the OpenCode SDK.
|
|
28
|
+
*/
|
|
29
|
+
export interface DiscoveredSkill {
|
|
30
|
+
/** Unique skill name. */
|
|
31
|
+
name: string;
|
|
32
|
+
/** Human-readable description. */
|
|
33
|
+
description?: string;
|
|
34
|
+
/** Filesystem location of the skill (SKILL.md path). */
|
|
35
|
+
location: string;
|
|
36
|
+
/** Categorization tags derived from the skill name. */
|
|
37
|
+
tags: string[];
|
|
38
|
+
/** Agents that benefit most from this skill based on defaults. */
|
|
39
|
+
recommendedAgents: string[];
|
|
40
|
+
/** Whether the skill ships with the plugin or was added by the user. */
|
|
41
|
+
source: 'bundled' | 'user';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Complete result of an SDK-based local discovery scan.
|
|
46
|
+
*/
|
|
47
|
+
export interface LocalDiscoveryResult {
|
|
48
|
+
/** Discovered skills. */
|
|
49
|
+
skills: DiscoveredSkill[];
|
|
50
|
+
/** Discovered MCP servers. */
|
|
51
|
+
mcps: DiscoveredMcp[];
|
|
52
|
+
/** Unix timestamp (ms) when the scan was performed. */
|
|
53
|
+
scannedAt: number;
|
|
54
|
+
/** How long the scan took in milliseconds. */
|
|
55
|
+
scanDurationMs: number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ── Tag derivation ──────────────────────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Known MCP/skill name patterns mapped to tags.
|
|
62
|
+
* Used to derive tags from names dynamically at scan time.
|
|
63
|
+
*/
|
|
64
|
+
const NAME_TAG_MAP: Record<string, string[]> = {
|
|
65
|
+
playwright: ['browser', 'ui', 'testing'],
|
|
66
|
+
github: ['github', 'git'],
|
|
67
|
+
filesystem: ['filesystem', 'files'],
|
|
68
|
+
websearch: ['web', 'search'],
|
|
69
|
+
context7: ['docs', 'search'],
|
|
70
|
+
grep_app: ['search', 'code'],
|
|
71
|
+
ast_grep: ['search', 'code'],
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Derive tags from a name string (MCP or skill name).
|
|
76
|
+
*
|
|
77
|
+
* Checks known patterns in a case-insensitive manner and returns the first
|
|
78
|
+
* matching tag set. Falls back to an empty array when no pattern matches.
|
|
79
|
+
*
|
|
80
|
+
* @param name - The MCP or skill name to derive tags from
|
|
81
|
+
* @returns Array of tag strings
|
|
82
|
+
*/
|
|
83
|
+
function deriveTags(name: string): string[] {
|
|
84
|
+
const lower = name.toLowerCase();
|
|
85
|
+
for (const [key, tags] of Object.entries(NAME_TAG_MAP)) {
|
|
86
|
+
if (lower.includes(key)) {
|
|
87
|
+
return [...tags];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return [];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ── Recommended agents derivation ───────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Derive recommended agent names for a given MCP or skill name.
|
|
97
|
+
*
|
|
98
|
+
* Agent-MCP recommendations have been removed; always returns an empty
|
|
99
|
+
* array. MCPs are auto-managed by the plugin with no user config control.
|
|
100
|
+
*
|
|
101
|
+
* @returns Empty array
|
|
102
|
+
*/
|
|
103
|
+
function deriveRecommendedAgents(_name: string): string[] {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// ── Skill source determination ──────────────────────────────────────────────
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Determine whether a skill is bundled or user-added based on its location.
|
|
111
|
+
*
|
|
112
|
+
* Skills located within the plugin's own `src/skills` directory are considered
|
|
113
|
+
* bundled; all others are treated as user-added.
|
|
114
|
+
*
|
|
115
|
+
* @param location - The filesystem location of the skill
|
|
116
|
+
* @returns `'bundled'` if the skill ships with the plugin, `'user'` otherwise
|
|
117
|
+
*/
|
|
118
|
+
function determineSource(location: string): 'bundled' | 'user' {
|
|
119
|
+
// Normalise path separators before checking
|
|
120
|
+
const normalised = location.replace(/\\/g, '/');
|
|
121
|
+
return normalised.includes('src/skills') ? 'bundled' : 'user';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ── Timeout helper ──────────────────────────────────────────────────────────
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Race a promise against a configurable timeout.
|
|
128
|
+
* If the timeout fires first, the returned promise rejects with an error
|
|
129
|
+
* that includes the label, giving downstream try/catch a clear indication
|
|
130
|
+
* of which SDK call hung.
|
|
131
|
+
*
|
|
132
|
+
* @param promise - The async operation to protect
|
|
133
|
+
* @param ms - Timeout in milliseconds
|
|
134
|
+
* @param label - Human-readable label for error messages
|
|
135
|
+
*/
|
|
136
|
+
function withTimeout<T>(
|
|
137
|
+
promise: Promise<T>,
|
|
138
|
+
ms: number,
|
|
139
|
+
label: string,
|
|
140
|
+
): Promise<T> {
|
|
141
|
+
return Promise.race([
|
|
142
|
+
promise,
|
|
143
|
+
new Promise<T>((_, reject) =>
|
|
144
|
+
setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms),
|
|
145
|
+
),
|
|
146
|
+
]);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ── Internal SDK call helpers ───────────────────────────────────────────────
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Scan MCP servers via `ctx.client.mcp.status()`.
|
|
153
|
+
*
|
|
154
|
+
* Maps each entry's status value from the SDK's format to the
|
|
155
|
+
* `DiscoveredMcp.status` union, derives tags and recommended agents from
|
|
156
|
+
* the server name.
|
|
157
|
+
*
|
|
158
|
+
* @param ctx - OpenCode plugin input
|
|
159
|
+
* @returns Array of discovered MCPs (empty on failure)
|
|
160
|
+
*/
|
|
161
|
+
async function scanMcpStatuses(ctx: PluginInput): Promise<DiscoveredMcp[]> {
|
|
162
|
+
const response = await withTimeout(
|
|
163
|
+
ctx.client.mcp.status(),
|
|
164
|
+
SDK_DISCOVERY_TIMEOUT_MS,
|
|
165
|
+
'MCP status scan',
|
|
166
|
+
);
|
|
167
|
+
// McpStatusResponses returns { [key: string]: McpStatus } inside `data`
|
|
168
|
+
const data = response.data as
|
|
169
|
+
| Record<string, { status: string; error?: string }>
|
|
170
|
+
| undefined;
|
|
171
|
+
|
|
172
|
+
if (!data) {
|
|
173
|
+
return [];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return Object.entries(data).map(([name, statusInfo]) => ({
|
|
177
|
+
name,
|
|
178
|
+
status: statusInfo.status as DiscoveredMcp['status'],
|
|
179
|
+
description: statusInfo.error,
|
|
180
|
+
tags: deriveTags(name),
|
|
181
|
+
recommendedAgents: deriveRecommendedAgents(name),
|
|
182
|
+
}));
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Scan skills via `ctx.client.instance.skill()`.
|
|
187
|
+
*
|
|
188
|
+
* Uses a type-asserted call because `instance.skill()` may not be reflected
|
|
189
|
+
* in the published SDK type definitions yet. Returns an empty array when the
|
|
190
|
+
* method is unavailable or the call fails.
|
|
191
|
+
*
|
|
192
|
+
* @param ctx - OpenCode plugin input
|
|
193
|
+
* @returns Array of discovered skills (empty on failure)
|
|
194
|
+
*/
|
|
195
|
+
async function scanInstanceSkills(
|
|
196
|
+
ctx: PluginInput,
|
|
197
|
+
): Promise<DiscoveredSkill[]> {
|
|
198
|
+
const skillFn = (
|
|
199
|
+
ctx.client.instance as unknown as {
|
|
200
|
+
skill?: (opts?: Record<string, unknown>) => Promise<{
|
|
201
|
+
data?: Array<{
|
|
202
|
+
name: string;
|
|
203
|
+
description?: string;
|
|
204
|
+
location: string;
|
|
205
|
+
}>;
|
|
206
|
+
}>;
|
|
207
|
+
}
|
|
208
|
+
).skill;
|
|
209
|
+
|
|
210
|
+
if (typeof skillFn !== 'function') {
|
|
211
|
+
log(
|
|
212
|
+
'[discovery] ctx.client.instance.skill() is not available, returning empty skills',
|
|
213
|
+
);
|
|
214
|
+
return [];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const response = await withTimeout(
|
|
218
|
+
skillFn(),
|
|
219
|
+
SDK_DISCOVERY_TIMEOUT_MS,
|
|
220
|
+
'Instance skill scan',
|
|
221
|
+
);
|
|
222
|
+
const items = Array.isArray(response?.data) ? response.data : [];
|
|
223
|
+
|
|
224
|
+
return items.map((s) => ({
|
|
225
|
+
name: s.name,
|
|
226
|
+
description: s.description,
|
|
227
|
+
location: s.location,
|
|
228
|
+
tags: deriveTags(s.name),
|
|
229
|
+
recommendedAgents: deriveRecommendedAgents(s.name),
|
|
230
|
+
source: determineSource(s.location),
|
|
231
|
+
}));
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// ── Cache ───────────────────────────────────────────────────────────────────
|
|
235
|
+
|
|
236
|
+
/** Internal cache entry for a completed scan result. */
|
|
237
|
+
interface CacheEntry {
|
|
238
|
+
result: LocalDiscoveryResult;
|
|
239
|
+
timestamp: number;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** Cache TTL in milliseconds (5 minutes). */
|
|
243
|
+
const CACHE_TTL_MS = 5 * 60 * 1_000;
|
|
244
|
+
|
|
245
|
+
/** Module-level scan result cache. */
|
|
246
|
+
let cache: CacheEntry | null = null;
|
|
247
|
+
|
|
248
|
+
// ── Exported API ────────────────────────────────────────────────────────────
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Scan locally configured MCP servers and skills using the OpenCode SDK.
|
|
252
|
+
*
|
|
253
|
+
* Calls `ctx.client.mcp.status()` and `ctx.client.instance.skill()` for fast,
|
|
254
|
+
* authoritative local discovery. Each SDK call is independently wrapped in a
|
|
255
|
+
* try/catch so that a failure in one does not prevent the other from
|
|
256
|
+
* succeeding. Empty arrays are returned for any failing SDK call.
|
|
257
|
+
*
|
|
258
|
+
* Results are **not** cached by this function – use
|
|
259
|
+
* {@link getLocalDiscovery} for caching support.
|
|
260
|
+
*
|
|
261
|
+
* @param ctx - The OpenCode plugin input context
|
|
262
|
+
* @returns A {@link LocalDiscoveryResult} with discovered MCPs and skills
|
|
263
|
+
*/
|
|
264
|
+
export async function scanLocal(
|
|
265
|
+
ctx: PluginInput,
|
|
266
|
+
): Promise<LocalDiscoveryResult> {
|
|
267
|
+
const start = performance.now();
|
|
268
|
+
|
|
269
|
+
let mcps: DiscoveredMcp[] = [];
|
|
270
|
+
let skills: DiscoveredSkill[] = [];
|
|
271
|
+
|
|
272
|
+
// Scan MCPs – failure is non-fatal, results default to empty
|
|
273
|
+
try {
|
|
274
|
+
mcps = await scanMcpStatuses(ctx);
|
|
275
|
+
} catch (err) {
|
|
276
|
+
log('[discovery] MCP scan failed', String(err));
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Scan skills – failure is non-fatal, results default to empty
|
|
280
|
+
try {
|
|
281
|
+
skills = await scanInstanceSkills(ctx);
|
|
282
|
+
} catch (err) {
|
|
283
|
+
log('[discovery] skill scan failed', String(err));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const scanDurationMs = performance.now() - start;
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
skills,
|
|
290
|
+
mcps,
|
|
291
|
+
scannedAt: Date.now(),
|
|
292
|
+
scanDurationMs,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Get locally discovered resources, using a cached result when available.
|
|
298
|
+
*
|
|
299
|
+
* Results are cached for 5 minutes. Call with `forceRefresh = true` to
|
|
300
|
+
* bypass the cache and perform a fresh scan. The cache lives at module
|
|
301
|
+
* scope and is shared across all callers within the same plugin instance.
|
|
302
|
+
*
|
|
303
|
+
* @param ctx - The OpenCode plugin input context
|
|
304
|
+
* @param forceRefresh - If `true`, bypass the cache and force a fresh scan
|
|
305
|
+
* @returns A {@link LocalDiscoveryResult}
|
|
306
|
+
*/
|
|
307
|
+
export async function getLocalDiscovery(
|
|
308
|
+
ctx: PluginInput,
|
|
309
|
+
forceRefresh?: boolean,
|
|
310
|
+
): Promise<LocalDiscoveryResult> {
|
|
311
|
+
if (
|
|
312
|
+
!forceRefresh &&
|
|
313
|
+
cache !== null &&
|
|
314
|
+
Date.now() - cache.timestamp < CACHE_TTL_MS
|
|
315
|
+
) {
|
|
316
|
+
return cache.result;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const result = await scanLocal(ctx);
|
|
320
|
+
cache = { result, timestamp: Date.now() };
|
|
321
|
+
return result;
|
|
322
|
+
}
|