@opengsd/gsd-core 1.7.0-rc.4 → 1.7.0-rc.6
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.opencode/plugins/gsd-core.js +20 -0
- package/agents/gsd-doc-classifier.md +105 -0
- package/agents/gsd-doc-synthesizer.md +61 -0
- package/agents/gsd-ui-checker.md +30 -0
- package/agents/gsd-ui-researcher.md +1 -0
- package/bin/install.js +1568 -622
- package/gsd-core/bin/gsd-tools.cjs +40 -1
- package/gsd-core/bin/lib/api-coverage.cjs +466 -0
- package/gsd-core/bin/lib/audit.cjs +6 -3
- package/gsd-core/bin/lib/capability-loader.cjs +11 -9
- package/gsd-core/bin/lib/capability-registry.cjs +761 -84
- package/gsd-core/bin/lib/capability-validator.cjs +56 -18
- package/gsd-core/bin/lib/capability-writer.cjs +10 -1
- package/gsd-core/bin/lib/check-command-router.cjs +242 -3
- package/gsd-core/bin/lib/commands.cjs +7 -5
- package/gsd-core/bin/lib/config-loader.cjs +1 -0
- package/gsd-core/bin/lib/config.cjs +96 -0
- package/gsd-core/bin/lib/core-utils.cjs +4 -1
- package/gsd-core/bin/lib/host-integration-adapters/cline-sdk-binding.cjs +234 -0
- package/gsd-core/bin/lib/host-integration-adapters/imperative-hook-bus.cjs +145 -0
- package/gsd-core/bin/lib/host-integration.cjs +45 -4
- package/gsd-core/bin/lib/init.cjs +76 -39
- package/gsd-core/bin/lib/install-effort-resolver.cjs +213 -0
- package/gsd-core/bin/lib/install-engine.cjs +228 -18
- package/gsd-core/bin/lib/installer-migration-report.cjs +7 -0
- package/gsd-core/bin/lib/loop-resolver.cjs +68 -17
- package/gsd-core/bin/lib/markdown-sectionizer.cjs +50 -11
- package/gsd-core/bin/lib/mcp-server.cjs +18 -7
- package/gsd-core/bin/lib/milestone.cjs +3 -3
- package/gsd-core/bin/lib/normalize-test-command.cjs +187 -0
- package/gsd-core/bin/lib/phase-id.cjs +132 -3
- package/gsd-core/bin/lib/phase.cjs +78 -16
- package/gsd-core/bin/lib/planning-workspace.cjs +17 -0
- package/gsd-core/bin/lib/review-reviewer-selection.cjs +24 -7
- package/gsd-core/bin/lib/roadmap-command-router.cjs +5 -4
- package/gsd-core/bin/lib/roadmap-parser.cjs +21 -30
- package/gsd-core/bin/lib/roadmap-upgrade.cjs +9 -9
- package/gsd-core/bin/lib/roadmap.cjs +42 -56
- package/gsd-core/bin/lib/runtime-artifact-conversion.cjs +248 -44
- package/gsd-core/bin/lib/runtime-artifact-install-plan.cjs +2 -2
- package/gsd-core/bin/lib/runtime-artifact-layout.cjs +39 -23
- package/gsd-core/bin/lib/runtime-config-adapter-registry.cjs +19 -5
- package/gsd-core/bin/lib/runtime-homes.cjs +30 -0
- package/gsd-core/bin/lib/runtime-hooks-surface.cjs +534 -37
- package/gsd-core/bin/lib/runtime-name-policy.cjs +63 -5
- package/gsd-core/bin/lib/security.cjs +6 -36
- package/gsd-core/bin/lib/shell-command-projection.cjs +115 -2
- package/gsd-core/bin/lib/spec-section.cjs +111 -0
- package/gsd-core/bin/lib/stale-bake-guard.cjs +30 -10
- package/gsd-core/bin/lib/state-transition.cjs +1 -1
- package/gsd-core/bin/lib/state.cjs +24 -24
- package/gsd-core/bin/lib/surface.cjs +40 -6
- package/gsd-core/bin/lib/uat.cjs +4 -1
- package/gsd-core/bin/lib/ui-consideration-probe.cjs +249 -0
- package/gsd-core/bin/lib/validate.cjs +15 -6
- package/gsd-core/bin/lib/verify.cjs +33 -37
- package/gsd-core/bin/shared/config-schema.manifest.json +2 -0
- package/gsd-core/bin/shared/model-catalog.json +14 -9
- package/gsd-core/references/api-coverage.md +104 -0
- package/gsd-core/references/model-profiles.md +2 -2
- package/gsd-core/references/planning-config.md +2 -0
- package/gsd-core/references/specless-probe-fallback.md +172 -0
- package/gsd-core/references/ui-consideration-probe.md +73 -0
- package/gsd-core/templates/UI-SPEC.md +25 -0
- package/gsd-core/templates/VALIDATION.md +2 -0
- package/gsd-core/templates/config.json +2 -1
- package/gsd-core/workflows/audit-fix.md +9 -1
- package/gsd-core/workflows/audit-milestone.md +7 -4
- package/gsd-core/workflows/code-review-fix.md +7 -3
- package/gsd-core/workflows/code-review.md +4 -1
- package/gsd-core/workflows/discuss-phase-assumptions.md +4 -1
- package/gsd-core/workflows/execute-phase/steps/post-merge-gate.md +8 -4
- package/gsd-core/workflows/execute-phase/steps/regression-gate.md +42 -0
- package/gsd-core/workflows/execute-phase.md +1 -25
- package/gsd-core/workflows/plan-phase.md +37 -2
- package/gsd-core/workflows/quick.md +2 -2
- package/gsd-core/workflows/review.md +59 -13
- package/gsd-core/workflows/settings-advanced.md +12 -9
- package/gsd-core/workflows/settings.md +2 -2
- package/gsd-core/workflows/ui-phase.md +146 -1
- package/gsd-core/workflows/validate-phase.md +2 -2
- package/gsd-core/workflows/verify-phase.md +3 -2
- package/gsd-core/workflows/verify-work.md +38 -0
- package/hooks/dist/gsd-cursor-pre-tool.js +76 -0
- package/hooks/dist/gsd-cursor-stop.js +48 -0
- package/hooks/dist/gsd-cursor-subagent-start.js +50 -0
- package/hooks/dist/gsd-cursor-subagent-stop.js +40 -0
- package/hooks/dist/gsd-windsurf-pre-command.js +275 -0
- package/hooks/dist/gsd-windsurf-pre-write.js +132 -0
- package/hooks/dist/managed-hooks-registry.cjs +6 -0
- package/hooks/gsd-cursor-pre-tool.js +76 -0
- package/hooks/gsd-cursor-stop.js +48 -0
- package/hooks/gsd-cursor-subagent-start.js +50 -0
- package/hooks/gsd-cursor-subagent-stop.js +40 -0
- package/hooks/gsd-windsurf-pre-command.js +275 -0
- package/hooks/gsd-windsurf-pre-write.js +132 -0
- package/hooks/managed-hooks-registry.cjs +6 -0
- package/package.json +9 -4
- package/pi/gsd.cjs +354 -0
- package/scripts/build-hooks.js +8 -1
- package/scripts/gen-golden-install-parity-zcode.cjs +11 -1
- package/scripts/gen-registry.cjs +128 -0
- package/scripts/lint-phase-id-drift.cjs +150 -0
- package/scripts/lint-test-file-count.allowlist.json +2 -1
- package/scripts/registry-schema.cjs +565 -0
- package/scripts/run-tests.cjs +21 -1
- package/scripts/validate-registry.cjs +117 -0
- package/vscode/browser.js +197 -0
- package/vscode/extension.js +383 -0
- package/vscode/host-binding.js +113 -0
- package/vscode/package.json +96 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* scripts/validate-registry.cjs — CLI validator for the third-party
|
|
6
|
+
* discoverability catalogs (issue #2182):
|
|
7
|
+
*
|
|
8
|
+
* - docs/registries/capabilities.json ("GSD Community Capability Registry")
|
|
9
|
+
* - docs/registries/eos.json ("GSD EoS Registry", PR2 — optional
|
|
10
|
+
* until that JSON file ships)
|
|
11
|
+
*
|
|
12
|
+
* Validates each source's JSON array against the closed schema in
|
|
13
|
+
* scripts/registry-schema.cjs (validateEntries). Human-readable errors go to
|
|
14
|
+
* stderr; `--json` additionally prints a structured verdict to stdout.
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* node scripts/validate-registry.cjs # human-readable report
|
|
18
|
+
* node scripts/validate-registry.cjs --json # structured JSON verdict
|
|
19
|
+
*
|
|
20
|
+
* Exit codes:
|
|
21
|
+
* 0 every present source's entries are all valid
|
|
22
|
+
* 1 one or more entries failed validation (or a source's JSON is malformed)
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const fs = require('node:fs');
|
|
26
|
+
const path = require('node:path');
|
|
27
|
+
|
|
28
|
+
const { ExitError, runMain } = require('./lib/cli-exit.cjs');
|
|
29
|
+
const { validateEntries } = require('./registry-schema.cjs');
|
|
30
|
+
|
|
31
|
+
// Resolved relative to process.cwd() (not __dirname) so the CLI validates
|
|
32
|
+
// whichever project it is invoked from — this is what lets tests drive it as
|
|
33
|
+
// a subprocess against isolated temp-fixture directories via `cwd`.
|
|
34
|
+
const SOURCES = [
|
|
35
|
+
{ file: 'capabilities.json', type: 'capability' },
|
|
36
|
+
{ file: 'eos.json', type: 'eos' },
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Load + validate a single registry JSON file.
|
|
41
|
+
*
|
|
42
|
+
* @param {string} jsonPath absolute path to the registry JSON file
|
|
43
|
+
* @param {'capability'|'eos'} type
|
|
44
|
+
* @returns {{ok: boolean, errors: Array<{index: number, id?: string, field: string, reason: string}>}}
|
|
45
|
+
*/
|
|
46
|
+
function validateFile(jsonPath, type) {
|
|
47
|
+
let raw;
|
|
48
|
+
try {
|
|
49
|
+
raw = fs.readFileSync(jsonPath, 'utf8');
|
|
50
|
+
} catch (err) {
|
|
51
|
+
return {
|
|
52
|
+
ok: false,
|
|
53
|
+
errors: [{ index: -1, field: '<file>', reason: `could not read ${jsonPath}: ${err.message}` }],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let entries;
|
|
58
|
+
try {
|
|
59
|
+
entries = JSON.parse(raw);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
return {
|
|
62
|
+
ok: false,
|
|
63
|
+
errors: [{ index: -1, field: '<file>', reason: `JSON parse error in ${jsonPath}: ${err.message}` }],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!Array.isArray(entries)) {
|
|
68
|
+
return {
|
|
69
|
+
ok: false,
|
|
70
|
+
errors: [{ index: -1, field: '<file>', reason: `${jsonPath} must be a JSON array of entries` }],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return validateEntries(entries, { type });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function main() {
|
|
78
|
+
const jsonMode = process.argv.includes('--json');
|
|
79
|
+
const registriesDir = path.join(process.cwd(), 'docs', 'registries');
|
|
80
|
+
|
|
81
|
+
const results = [];
|
|
82
|
+
let anyFailed = false;
|
|
83
|
+
|
|
84
|
+
for (const { file, type } of SOURCES) {
|
|
85
|
+
const jsonPath = path.join(registriesDir, file);
|
|
86
|
+
// eos.json is optional until PR2 ships it — skip silently when absent.
|
|
87
|
+
if (type === 'eos' && !fs.existsSync(jsonPath)) continue;
|
|
88
|
+
|
|
89
|
+
const verdict = validateFile(jsonPath, type);
|
|
90
|
+
results.push({ file, type, ok: verdict.ok, errors: verdict.errors });
|
|
91
|
+
if (!verdict.ok) anyFailed = true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (jsonMode) {
|
|
95
|
+
process.stdout.write(JSON.stringify({ ok: !anyFailed, results }, null, 2) + '\n');
|
|
96
|
+
} else if (anyFailed) {
|
|
97
|
+
process.stderr.write('\nERROR validate-registry: one or more entries failed validation\n');
|
|
98
|
+
for (const result of results) {
|
|
99
|
+
if (result.ok) continue;
|
|
100
|
+
process.stderr.write(`\n${result.file}:\n`);
|
|
101
|
+
for (const e of result.errors) {
|
|
102
|
+
const idPart = e.id ? ` (id: ${e.id})` : '';
|
|
103
|
+
process.stderr.write(` entry[${e.index}]${idPart} field "${e.field}": ${e.reason}\n`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
process.stderr.write('\n');
|
|
107
|
+
} else {
|
|
108
|
+
process.stdout.write('ok validate-registry: all entries valid\n');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (anyFailed) throw new ExitError(1, 'registry validation failed');
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (require.main === module) runMain(main);
|
|
116
|
+
|
|
117
|
+
module.exports = { main, validateFile, SOURCES };
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GSD extension for VS Code — WEB (browser) entry, #2103.
|
|
5
|
+
*
|
|
6
|
+
* This is the `browser` entry point (vscode/package.json `"browser": "./browser.js"`),
|
|
7
|
+
* loaded by VS Code Web / vscode.dev in a webworker context. It has ZERO Node
|
|
8
|
+
* APIs: no `require('fs')`, `require('path')`, or `require('child_process')`,
|
|
9
|
+
* and no Node globals (`process`, `Buffer`, `__dirname`, `__filename`). This is
|
|
10
|
+
* a HARD constraint, not a style preference — a Web Extension host does not
|
|
11
|
+
* have Node's core modules available at all; requiring one throws immediately
|
|
12
|
+
* at load time and breaks activation.
|
|
13
|
+
*
|
|
14
|
+
* WHY THIS FILE DOES NOT REQUIRE `./host-binding.js` OR `./extension.js`
|
|
15
|
+
* (a deliberate deviation from "compose the seams via bindGsdToVscode" — see
|
|
16
|
+
* the #2103 dispatch-crux note below):
|
|
17
|
+
*
|
|
18
|
+
* `host-binding.js`'s `bindGsdToVscode` is NOT actually web-safe once its
|
|
19
|
+
* transitive dependencies are checked — three of its four required engine-lib
|
|
20
|
+
* modules pull in Node's `fs`/`os`/`path` at module-load time (eagerly, on
|
|
21
|
+
* every `require()`, regardless of which code path runs):
|
|
22
|
+
* - gsd-core/bin/lib/state-io.cjs → requires 'node:fs' directly.
|
|
23
|
+
* - gsd-core/bin/lib/adapter-imperative.cjs → requires install-engine.cjs +
|
|
24
|
+
* capability-loader.cjs (fs/os/path).
|
|
25
|
+
* - gsd-core/bin/lib/model-adapter.cjs → requires model-resolver.cjs →
|
|
26
|
+
* config-loader.cjs (fs/os/path) +
|
|
27
|
+
* configuration.cjs (fs/path).
|
|
28
|
+
* (gsd-core/bin/lib/hook-bus.cjs alone has no requires and is genuinely
|
|
29
|
+
* web-safe.) Requiring `host-binding.js` here would transitively pull in
|
|
30
|
+
* `node:fs` and throw at web-worker load time — the opposite of "zero Node
|
|
31
|
+
* APIs". See host-binding.js's own header comment for the full chain. Fixing
|
|
32
|
+
* those engine-lib modules to be fs-free is a separate, much larger
|
|
33
|
+
* engine-wide refactor (config/capability loading genuinely reads files from
|
|
34
|
+
* disk for every OTHER host) — out of scope here; flagged rather than routed
|
|
35
|
+
* around silently.
|
|
36
|
+
*
|
|
37
|
+
* So this file implements its OWN minimal, independently-verified-zero-Node-API
|
|
38
|
+
* composition directly against `vscode.lm` — no engine-lib requires at all.
|
|
39
|
+
*
|
|
40
|
+
* DISPATCH STORY ON WEB (per the #2103 dispatch-crux design): full GSD engine
|
|
41
|
+
* dispatch (the gsd-tools.cjs subprocess-shim `dispatchGsdCommand` used by the
|
|
42
|
+
* desktop `extension.js`) is fundamentally a Node `child_process.spawnSync`
|
|
43
|
+
* call — there is no web-worker equivalent. On web, GSD command dispatch is
|
|
44
|
+
* available through VS Code's NATIVE MCP client connecting to the GSD
|
|
45
|
+
* companion MCP server (gsd-core/bin/lib/mcp-server.cjs, `gsd-mcp-server`
|
|
46
|
+
* bin entry — a separate, already-existing surface; this file does NOT
|
|
47
|
+
* implement an MCP client itself, it only points the user at that story).
|
|
48
|
+
* The chat participant and Language Model Tools registered below are
|
|
49
|
+
* therefore intentionally limited on web: they register (so the surface is
|
|
50
|
+
* discoverable and `#runSubagent`-eligible per VS Code's chat engine) but
|
|
51
|
+
* their handlers return an honest "configure the GSD MCP server for full
|
|
52
|
+
* dispatch on web" message rather than silently failing or faking success.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Tokenizes a raw chat/free-form prompt string. Kept local (not shared with
|
|
57
|
+
* extension.js) so this file has zero requires of any kind beyond `vscode`.
|
|
58
|
+
* @param {string} rawPrompt
|
|
59
|
+
* @returns {{family: string, subcommand: string|undefined, args: string[]}}
|
|
60
|
+
*/
|
|
61
|
+
function parseChatPrompt(rawPrompt) {
|
|
62
|
+
const tokens = String(rawPrompt || '').trim().split(/\s+/).filter(Boolean);
|
|
63
|
+
return {
|
|
64
|
+
family: tokens[0] || '--help',
|
|
65
|
+
subcommand: tokens[1],
|
|
66
|
+
args: tokens.slice(2),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The honest "web mode" message every web-surface handler returns instead of
|
|
72
|
+
* attempting Node-only engine dispatch.
|
|
73
|
+
* @param {string} family
|
|
74
|
+
*/
|
|
75
|
+
function webDispatchUnavailableMessage(family) {
|
|
76
|
+
return (
|
|
77
|
+
`GSD web mode: full engine dispatch for "${family}" is not available in the browser ` +
|
|
78
|
+
'(the VS Code Web/webworker host has no Node runtime, so the gsd-tools.cjs ' +
|
|
79
|
+
'subprocess dispatch used on desktop cannot run here). Configure the GSD MCP ' +
|
|
80
|
+
'server (gsd-mcp-server) as a VS Code MCP server for full command dispatch on web, ' +
|
|
81
|
+
'or use the desktop GSD Core extension.'
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Registers the `@gsd` chat participant in web mode (#2103). Its handler is
|
|
87
|
+
* honest about the web dispatch limitation — see webDispatchUnavailableMessage.
|
|
88
|
+
* Exported separately so it is testable with a mock `vscode.chat`.
|
|
89
|
+
* @param {object} vscode
|
|
90
|
+
* @param {import('vscode').ExtensionContext} context
|
|
91
|
+
* @returns {object|null} the created participant, or null if vscode.chat is absent.
|
|
92
|
+
*/
|
|
93
|
+
function registerChatParticipant(vscode, context) {
|
|
94
|
+
if (!vscode || !vscode.chat || typeof vscode.chat.createChatParticipant !== 'function') {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const participant = vscode.chat.createChatParticipant('gsd', async (request, _chatContext, stream, _token) => {
|
|
98
|
+
const { family } = parseChatPrompt(request && request.prompt);
|
|
99
|
+
if (stream && typeof stream.markdown === 'function') {
|
|
100
|
+
stream.markdown(webDispatchUnavailableMessage(family));
|
|
101
|
+
}
|
|
102
|
+
return { metadata: { command: family, mode: 'web' } };
|
|
103
|
+
});
|
|
104
|
+
if (context && Array.isArray(context.subscriptions)) context.subscriptions.push(participant);
|
|
105
|
+
return participant;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The same representative LM tool NAMES as the desktop extension (must match
|
|
110
|
+
* package.json's contributes.languageModelTools[].name — underscored, the
|
|
111
|
+
* vscode.lm.registerTool registration name — so the manifest is identical
|
|
112
|
+
* across both entry points), but with web-mode invoke() handlers.
|
|
113
|
+
*/
|
|
114
|
+
const LM_TOOL_NAMES = ['gsd_progress', 'gsd_workstreams', 'gsd_plan_phase'];
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Registers web-mode LM tools via vscode.lm.registerTool (#2103). Each
|
|
118
|
+
* invoke() returns the honest web-dispatch-unavailable message — no engine-lib
|
|
119
|
+
* requires, no Node APIs.
|
|
120
|
+
* @param {object} vscode
|
|
121
|
+
* @param {import('vscode').ExtensionContext} context
|
|
122
|
+
* @returns {number} count of tools registered (0 if vscode.lm is absent — fail-soft).
|
|
123
|
+
*/
|
|
124
|
+
function registerLanguageModelTools(vscode, context) {
|
|
125
|
+
if (!vscode || !vscode.lm || typeof vscode.lm.registerTool !== 'function') return 0;
|
|
126
|
+
let count = 0;
|
|
127
|
+
for (const name of LM_TOOL_NAMES) {
|
|
128
|
+
const impl = {
|
|
129
|
+
async invoke(_options, _token) {
|
|
130
|
+
return new vscode.LanguageModelToolResult([
|
|
131
|
+
new vscode.LanguageModelTextPart(webDispatchUnavailableMessage(name)),
|
|
132
|
+
]);
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
const disposable = vscode.lm.registerTool(name, impl);
|
|
136
|
+
if (context && Array.isArray(context.subscriptions)) context.subscriptions.push(disposable);
|
|
137
|
+
count++;
|
|
138
|
+
}
|
|
139
|
+
return count;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Detects `#runSubagent` feature availability (`chat.subagents.allowInvocationsFromSubagents`,
|
|
144
|
+
* VS Code 1.105+). Fail-soft: never throws. Identical detection logic to the
|
|
145
|
+
* desktop extension.js (duplicated, not shared, to keep this file at zero
|
|
146
|
+
* requires) — see extension.js's registerSubagentDispatch for the rationale
|
|
147
|
+
* that VS Code's chat engine itself surfaces registered participants/tools to
|
|
148
|
+
* `#runSubagent`, with no separate registration API.
|
|
149
|
+
* @param {object} vscode
|
|
150
|
+
* @returns {{available: boolean}}
|
|
151
|
+
*/
|
|
152
|
+
function detectSubagentSupport(vscode) {
|
|
153
|
+
let available = false;
|
|
154
|
+
try {
|
|
155
|
+
const cfg = vscode && vscode.workspace && typeof vscode.workspace.getConfiguration === 'function'
|
|
156
|
+
? vscode.workspace.getConfiguration('chat.subagents')
|
|
157
|
+
: null;
|
|
158
|
+
available = !!(cfg && typeof cfg.get === 'function' && cfg.get('allowInvocationsFromSubagents') !== undefined);
|
|
159
|
+
} catch {
|
|
160
|
+
available = false;
|
|
161
|
+
}
|
|
162
|
+
return { available };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* VS Code Web extension activation. Registers the chat participant + Language
|
|
167
|
+
* Model Tools in web mode. Does NOT register the `gsd.invoke` command with a
|
|
168
|
+
* real-dispatch handler (there is no Node dispatch on web) — the command is
|
|
169
|
+
* still contributed (contributes.commands in package.json is shared across
|
|
170
|
+
* desktop/web), so it is registered here too, but its handler returns the
|
|
171
|
+
* same honest web-mode message.
|
|
172
|
+
* @param {import('vscode').ExtensionContext} context
|
|
173
|
+
*/
|
|
174
|
+
function activate(context) {
|
|
175
|
+
const vscode = require('vscode');
|
|
176
|
+
|
|
177
|
+
const gsdCommand = vscode.commands.registerCommand('gsd.invoke', async (args) => {
|
|
178
|
+
const a = (args && typeof args === 'object') ? args : {};
|
|
179
|
+
const family = (typeof a.family === 'string' && a.family) ? a.family : '--help';
|
|
180
|
+
return JSON.stringify({ ok: false, stdout: '', stderr: webDispatchUnavailableMessage(family), code: null, timedOut: false });
|
|
181
|
+
});
|
|
182
|
+
context.subscriptions.push(gsdCommand);
|
|
183
|
+
|
|
184
|
+
registerChatParticipant(vscode, context);
|
|
185
|
+
registerLanguageModelTools(vscode, context);
|
|
186
|
+
detectSubagentSupport(vscode);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
module.exports = {
|
|
190
|
+
activate,
|
|
191
|
+
parseChatPrompt,
|
|
192
|
+
webDispatchUnavailableMessage,
|
|
193
|
+
registerChatParticipant,
|
|
194
|
+
registerLanguageModelTools,
|
|
195
|
+
detectSubagentSupport,
|
|
196
|
+
LM_TOOL_NAMES,
|
|
197
|
+
};
|