refactor: hard-fork GSD -> MSD (Make Software Done)

Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD
across contents and paths, upstream package/repo coordinates -> @golem15/msd-core
and golem15com/msd-core. Deep links into upstream history, sibling upstream
packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is.

Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line,
package/plugin identity, regenerated lockfile, install-tree fixtures, derived
registries and benchmark baseline; migration checksum baseline re-locked
(MSD keeps its own install state, so no install had applied the old sums);
sort-order and regex-escaped expectations in tests adjusted.
This commit is contained in:
Jakub Zych
2026-10-06 01:47:40 +02:00
parent fe069b2a56
commit a9a7a328e6
2763 changed files with 78465 additions and 78434 deletions

View File

@@ -1,7 +1,7 @@
'use strict';
/**
* GSD extension for VS Code — WEB (browser) entry, #2103.
* MSD extension for VS Code — WEB (browser) entry, #2103.
*
* This is the `browser` entry point (vscode/package.json `"browser": "./browser.js"`),
* loaded by VS Code Web / vscode.dev in a webworker context. It has ZERO Node
@@ -12,20 +12,20 @@
* at load time and breaks activation.
*
* WHY THIS FILE DOES NOT REQUIRE `./host-binding.js` OR `./extension.js`
* (a deliberate deviation from "compose the seams via bindGsdToVscode" — see
* (a deliberate deviation from "compose the seams via bindMsdToVscode" — see
* the #2103 dispatch-crux note below):
*
* `host-binding.js`'s `bindGsdToVscode` is NOT actually web-safe once its
* `host-binding.js`'s `bindMsdToVscode` is NOT actually web-safe once its
* transitive dependencies are checked — three of its four required engine-lib
* modules pull in Node's `fs`/`os`/`path` at module-load time (eagerly, on
* every `require()`, regardless of which code path runs):
* - gsd-core/bin/lib/state-io.cjs → requires 'node:fs' directly.
* - gsd-core/bin/lib/adapter-imperative.cjs → requires install-engine.cjs +
* - msd-core/bin/lib/state-io.cjs → requires 'node:fs' directly.
* - msd-core/bin/lib/adapter-imperative.cjs → requires install-engine.cjs +
* capability-loader.cjs (fs/os/path).
* - gsd-core/bin/lib/model-adapter.cjs → requires model-resolver.cjs →
* - msd-core/bin/lib/model-adapter.cjs → requires model-resolver.cjs →
* config-loader.cjs (fs/os/path) +
* configuration.cjs (fs/path).
* (gsd-core/bin/lib/hook-bus.cjs alone has no requires and is genuinely
* (msd-core/bin/lib/hook-bus.cjs alone has no requires and is genuinely
* web-safe.) Requiring `host-binding.js` here would transitively pull in
* `node:fs` and throw at web-worker load time — the opposite of "zero Node
* APIs". See host-binding.js's own header comment for the full chain. Fixing
@@ -37,18 +37,18 @@
* So this file implements its OWN minimal, independently-verified-zero-Node-API
* composition directly against `vscode.lm` — no engine-lib requires at all.
*
* DISPATCH STORY ON WEB (per the #2103 dispatch-crux design): full GSD engine
* dispatch (the gsd-tools.cjs subprocess-shim `dispatchGsdCommand` used by the
* DISPATCH STORY ON WEB (per the #2103 dispatch-crux design): full MSD engine
* dispatch (the msd-tools.cjs subprocess-shim `dispatchMsdCommand` used by the
* desktop `extension.js`) is fundamentally a Node `child_process.spawnSync`
* call — there is no web-worker equivalent. On web, GSD command dispatch is
* available through VS Code's NATIVE MCP client connecting to the GSD
* companion MCP server (gsd-core/bin/lib/mcp-server.cjs, `gsd-mcp-server`
* call — there is no web-worker equivalent. On web, MSD command dispatch is
* available through VS Code's NATIVE MCP client connecting to the MSD
* companion MCP server (msd-core/bin/lib/mcp-server.cjs, `msd-mcp-server`
* bin entry — a separate, already-existing surface; this file does NOT
* implement an MCP client itself, it only points the user at that story).
* The chat participant and Language Model Tools registered below are
* therefore intentionally limited on web: they register (so the surface is
* discoverable and `#runSubagent`-eligible per VS Code's chat engine) but
* their handlers return an honest "configure the GSD MCP server for full
* their handlers return an honest "configure the MSD MCP server for full
* dispatch on web" message rather than silently failing or faking success.
*/
@@ -74,16 +74,16 @@ function parseChatPrompt(rawPrompt) {
*/
function webDispatchUnavailableMessage(family) {
return (
`GSD web mode: full engine dispatch for "${family}" is not available in the browser ` +
'(the VS Code Web/webworker host has no Node runtime, so the gsd-tools.cjs ' +
'subprocess dispatch used on desktop cannot run here). Configure the GSD MCP ' +
'server (gsd-mcp-server) as a VS Code MCP server for full command dispatch on web, ' +
'or use the desktop GSD Core extension.'
`MSD web mode: full engine dispatch for "${family}" is not available in the browser ` +
'(the VS Code Web/webworker host has no Node runtime, so the msd-tools.cjs ' +
'subprocess dispatch used on desktop cannot run here). Configure the MSD MCP ' +
'server (msd-mcp-server) as a VS Code MCP server for full command dispatch on web, ' +
'or use the desktop MSD Core extension.'
);
}
/**
* Registers the `@gsd` chat participant in web mode (#2103). Its handler is
* Registers the `@msd` chat participant in web mode (#2103). Its handler is
* honest about the web dispatch limitation — see webDispatchUnavailableMessage.
* Exported separately so it is testable with a mock `vscode.chat`.
* @param {object} vscode
@@ -94,7 +94,7 @@ function registerChatParticipant(vscode, context) {
if (!vscode || !vscode.chat || typeof vscode.chat.createChatParticipant !== 'function') {
return null;
}
const participant = vscode.chat.createChatParticipant('gsd', async (request, _chatContext, stream, _token) => {
const participant = vscode.chat.createChatParticipant('msd', async (request, _chatContext, stream, _token) => {
const { family } = parseChatPrompt(request && request.prompt);
if (stream && typeof stream.markdown === 'function') {
stream.markdown(webDispatchUnavailableMessage(family));
@@ -111,7 +111,7 @@ function registerChatParticipant(vscode, context) {
* vscode.lm.registerTool registration name — so the manifest is identical
* across both entry points), but with web-mode invoke() handlers.
*/
const LM_TOOL_NAMES = ['gsd_progress', 'gsd_workstreams', 'gsd_plan_phase'];
const LM_TOOL_NAMES = ['msd_progress', 'msd_workstreams', 'msd_plan_phase'];
/**
* Registers web-mode LM tools via vscode.lm.registerTool (#2103). Each
@@ -164,7 +164,7 @@ function detectSubagentSupport(vscode) {
/**
* VS Code Web extension activation. Registers the chat participant + Language
* Model Tools in web mode. Does NOT register the `gsd.invoke` command with a
* Model Tools in web mode. Does NOT register the `msd.invoke` command with a
* real-dispatch handler (there is no Node dispatch on web) — the command is
* still contributed (contributes.commands in package.json is shared across
* desktop/web), so it is registered here too, but its handler returns the
@@ -174,12 +174,12 @@ function detectSubagentSupport(vscode) {
function activate(context) {
const vscode = require('vscode');
const gsdCommand = vscode.commands.registerCommand('gsd.invoke', async (args) => {
const msdCommand = vscode.commands.registerCommand('msd.invoke', async (args) => {
const a = (args && typeof args === 'object') ? args : {};
const family = (typeof a.family === 'string' && a.family) ? a.family : '--help';
return JSON.stringify({ ok: false, stdout: '', stderr: webDispatchUnavailableMessage(family), code: null, timedOut: false });
});
context.subscriptions.push(gsdCommand);
context.subscriptions.push(msdCommand);
registerChatParticipant(vscode, context);
registerLanguageModelTools(vscode, context);

View File

@@ -1,7 +1,7 @@
'use strict';
/**
* GSD extension for VS Code — ADR-1239 Phase D / #1942, dispatch fixed +
* MSD extension for VS Code — ADR-1239 Phase D / #1942, dispatch fixed +
* extension surface (chat participant, Language Model Tools, #runSubagent
* wiring) added #2103.
*
@@ -9,7 +9,7 @@
* Extension `browser` entry, which is intentionally a SEPARATE, much more
* minimal file (zero Node APIs; does not require this file or host-binding.js).
*
* VS Code is the IDE-profile reference host. This extension binds GSD's command
* VS Code is the IDE-profile reference host. This extension binds MSD's command
* surface to VS Code's Command Palette + Chat participant via the imperative
* adapter path. Engine entry: in-process CJS require (the extension host runs
* Node). The engine seams (active model via vscode.lm, engine-owned hook bus,
@@ -19,22 +19,22 @@
* Installation: Marketplace/VSIX extension (see capabilities/vscode/capability.json
* — installSurface:'none', it is never CLI-installed by bin/install.js).
*
* Engine entry: dispatch is SUBPROCESS-REUSE to gsd-tools.cjs (bounded,
* no-throw — the shared `dispatchGsdCommand` in
* gsd-core/bin/lib/shell-command-projection.cjs), NOT an in-process
* Engine entry: dispatch is SUBPROCESS-REUSE to msd-tools.cjs (bounded,
* no-throw — the shared `dispatchMsdCommand` in
* msd-core/bin/lib/shell-command-projection.cjs), NOT an in-process
* command-routing hub. No fully-populated hub factory exists anywhere in
* gsd-core — every createHub() caller builds a single-family hub for its own
* msd-core — every createHub() caller builds a single-family hub for its own
* narrow purpose — so calling createHub() with no args (the original #1942
* cut) always answered UnknownCommand. This mirrors the fix already applied
* to the pi extension (pi/gsd.cjs) and the companion MCP server
* (gsd-core/bin/lib/mcp-server.cjs), which dispatch through the SAME shared
* to the pi extension (pi/msd.cjs) and the companion MCP server
* (msd-core/bin/lib/mcp-server.cjs), which dispatch through the SAME shared
* helper (#2102 Stage 2 / #2103).
*
* Extension surface (#2103):
* - Chat participant `@gsd` (contributes.chatParticipants) — dispatches free-form
* prompts through the same dispatchGsdCommand.
* - Chat participant `@msd` (contributes.chatParticipants) — dispatches free-form
* prompts through the same dispatchMsdCommand.
* - Language Model Tools (contributes.languageModelTools) — a representative
* set of GSD skills exposed as vscode.lm tools, each dispatching through the
* set of MSD skills exposed as vscode.lm tools, each dispatching through the
* same shared helper (UPGRADE 1).
* - #runSubagent wiring — VS Code 1.105+ lets the primary chat agent invoke
* registered chat participants / languageModelTools as a nested agent turn
@@ -42,7 +42,7 @@
* setting. There is no separate "subagent contribution" registration API
* beyond the participant + tools already registered above — VS Code's own
* chat engine surfaces them. This extension's own contribution is a
* belt-and-suspenders depth cap (dispatchAsSubagent, GSD_MAX_SUBAGENT_DEPTH)
* belt-and-suspenders depth cap (dispatchAsSubagent, MSD_MAX_SUBAGENT_DEPTH)
* mirroring capabilities/vscode/capability.json's
* hostIntegration.dispatch.maxDepth:5, independent of whatever VS Code
* itself enforces natively (UPGRADE 2).
@@ -51,11 +51,11 @@
const path = require('path');
const fs = require('fs');
// Resolve the GSD engine tree (walk up to find gsd-core/).
// Resolve the MSD engine tree (walk up to find msd-core/).
function resolveEngineRoot(startDir) {
let dir = startDir;
for (let i = 0; i < 6; i++) {
if (fs.existsSync(path.join(dir, 'gsd-core'))) return dir;
if (fs.existsSync(path.join(dir, 'msd-core'))) return dir;
const parent = path.dirname(dir);
if (parent === dir) break;
dir = parent;
@@ -64,13 +64,13 @@ function resolveEngineRoot(startDir) {
}
const ENGINE_ROOT = resolveEngineRoot(__dirname);
const GSD_CORE = path.join(ENGINE_ROOT, 'gsd-core');
const MSD_CORE = path.join(ENGINE_ROOT, 'msd-core');
/**
* Pure command handler — dispatches through the SHARED subprocess-shim
* `dispatchGsdCommand` (gsd-core/bin/lib/shell-command-projection.cjs), the
* same helper the pi extension (pi/gsd.cjs) and the companion MCP server
* (gsd-core/bin/lib/mcp-server.cjs) dispatch through.
* `dispatchMsdCommand` (msd-core/bin/lib/shell-command-projection.cjs), the
* same helper the pi extension (pi/msd.cjs) and the companion MCP server
* (msd-core/bin/lib/mcp-server.cjs) dispatch through.
*
* Exported separately from activate() so it is testable WITHOUT a VS Code
* host. Preserves the original return CONTRACT — a JSON-stringified result
@@ -78,18 +78,18 @@ const GSD_CORE = path.join(ENGINE_ROOT, 'gsd-core');
* `createHub()` that always answered UnknownCommand (#2103 fix).
*
* Empty/omitted args default to `--help` (a real, working, ok:true
* gsd-tools.cjs command) — NOT the `'query'`/`'help'` pairing the original
* cut used, which is not a valid gsd-tools.cjs command and always produced
* msd-tools.cjs command) — NOT the `'query'`/`'help'` pairing the original
* cut used, which is not a valid msd-tools.cjs command and always produced
* UnknownCommand (mirrors the same fix already applied to
* pi/gsd.cjs's parseGsdCommandArgs).
* pi/msd.cjs's parseMsdCommandArgs).
*
* @returns {Promise<string>} JSON-stringified dispatch result:
* `{ok, stdout, stderr, code, timedOut}` on a normal dispatch, or
* `{ok:false, stdout:'', stderr:'GSD engine unavailable: ...', code:null,
* `{ok:false, stdout:'', stderr:'MSD engine unavailable: ...', code:null,
* timedOut:false}` if the shared helper itself cannot be loaded (e.g.
* gsd-core/ missing from the tree).
* msd-core/ missing from the tree).
*/
async function dispatchGsdCommand(args) {
async function dispatchMsdCommand(args) {
const a = (args && typeof args === 'object') ? args : {};
const family = (typeof a.family === 'string' && a.family) ? a.family : '--help';
const subcommand = (typeof a.subcommand === 'string' && a.subcommand) ? a.subcommand : undefined;
@@ -98,12 +98,12 @@ async function dispatchGsdCommand(args) {
let dispatchViaShim;
try {
({ dispatchGsdCommand: dispatchViaShim } = require(path.join(GSD_CORE, 'bin', 'lib', 'shell-command-projection.cjs')));
({ dispatchMsdCommand: dispatchViaShim } = require(path.join(MSD_CORE, 'bin', 'lib', 'shell-command-projection.cjs')));
} catch (e) {
return JSON.stringify({
ok: false,
stdout: '',
stderr: `GSD engine unavailable: ${e && e.message ? e.message : String(e)}`,
stderr: `MSD engine unavailable: ${e && e.message ? e.message : String(e)}`,
code: null,
timedOut: false,
});
@@ -114,10 +114,10 @@ async function dispatchGsdCommand(args) {
/**
* Resolves the current workspace's root directory, per-invocation (never
* cached at activate() time), so GSD commands dispatch against the user's
* cached at activate() time), so MSD commands dispatch against the user's
* actual project instead of the extension host's own `process.cwd()` (#2103
* FIX — adversarial review: all three desktop dispatch surfaces previously
* omitted `cwd` entirely when calling dispatchGsdCommand, silently defaulting
* omitted `cwd` entirely when calling dispatchMsdCommand, silently defaulting
* to the wrong directory). Falls back to `process.cwd()` only when no
* workspace folder is open (e.g. an empty window) — mirrors VS Code's own
* single-root convention of reading `workspaceFolders[0]`.
@@ -133,9 +133,9 @@ function resolveWorkspaceCwd(vscode) {
/**
* Tokenizes a raw chat/free-form prompt string into {family, subcommand, args}.
* Mirrors pi/gsd.cjs's parseGsdCommandArgs (simple whitespace split — no shell
* Mirrors pi/msd.cjs's parseMsdCommandArgs (simple whitespace split — no shell
* quoting support needed for a chat prompt). Empty input defaults to `--help`
* (a real, working gsd-tools.cjs command), matching dispatchGsdCommand's own
* (a real, working msd-tools.cjs command), matching dispatchMsdCommand's own
* default so the two surfaces (palette vs. chat) never diverge on "no input".
* @param {string} rawPrompt
* @returns {{family: string, subcommand: string|undefined, args: string[]}}
@@ -150,8 +150,8 @@ function parseChatPrompt(rawPrompt) {
}
/**
* Registers the `@gsd` chat participant (#2103). Its handler dispatches the
* user's free-form prompt through the SAME dispatchGsdCommand as gsd.invoke —
* Registers the `@msd` chat participant (#2103). Its handler dispatches the
* user's free-form prompt through the SAME dispatchMsdCommand as msd.invoke —
* one dispatch path for every command surface (palette / chat / LM tools).
* Exported separately so it is testable with a mock `vscode.chat`.
* @param {object} vscode
@@ -163,16 +163,16 @@ function registerChatParticipant(vscode, context) {
if (!vscode || !vscode.chat || typeof vscode.chat.createChatParticipant !== 'function') {
return null;
}
const participant = vscode.chat.createChatParticipant('gsd', async (request, _chatContext, stream, _token) => {
const participant = vscode.chat.createChatParticipant('msd', async (request, _chatContext, stream, _token) => {
// #2103 FIX: resolve the user's actual workspace, not the extension host's
// process.cwd() — computed per-invocation so it always reflects the
// CURRENT workspace (a chat request has no cwd field of its own; VS Code's
// ChatContext does not carry one).
const cwd = resolveWorkspaceCwd(vscode);
const { family, subcommand, args } = parseChatPrompt(request && request.prompt);
const result = JSON.parse(await dispatchGsdCommand({ family, subcommand, args, cwd }));
const result = JSON.parse(await dispatchMsdCommand({ family, subcommand, args, cwd }));
if (stream && typeof stream.markdown === 'function') {
stream.markdown(result.ok ? result.stdout : `GSD error: ${result.stderr || result.stdout || 'dispatch failed'}`);
stream.markdown(result.ok ? result.stdout : `MSD error: ${result.stderr || result.stdout || 'dispatch failed'}`);
}
return { metadata: { command: family } };
});
@@ -183,37 +183,37 @@ function registerChatParticipant(vscode, context) {
/**
* #2103 UPGRADE 1 — Language Model Tools.
*
* A representative set of GSD skills (see skills/gsd-progress, skills/gsd-workstreams,
* skills/gsd-plan-phase) exposed as vscode.lm tools, matching the
* A representative set of MSD skills (see skills/msd-progress, skills/msd-workstreams,
* skills/msd-plan-phase) exposed as vscode.lm tools, matching the
* contributes.languageModelTools manifest entries in package.json. Each tool's
* invoke() dispatches through the SAME shared dispatchGsdCommand as gsd.invoke —
* invoke() dispatches through the SAME shared dispatchMsdCommand as msd.invoke —
* the tool name maps to a real, verified family/subcommand pair (verified by
* direct `gsd-tools.cjs <family> [subcommand] --raw --json-errors` invocation;
* direct `msd-tools.cjs <family> [subcommand] --raw --json-errors` invocation;
* see the #2103 CORE-stage precedent for `progress json`).
*
* Kept to a small, curated set rather than all 71 shipped skills: these three
* both name a real skill AND map cleanly onto a single, safe, read-only
* gsd-tools.cjs command (the rest are multi-step agent workflows that do not
* msd-tools.cjs command (the rest are multi-step agent workflows that do not
* reduce to one non-interactive CLI call, and stay slash-command-native).
*/
// `name` uses underscores (vscode.lm.registerTool's registration name — MUST
// match contributes.languageModelTools[].name in package.json exactly); the
// hyphenated `#gsd-progress`-style mention alias is package.json's separate
// hyphenated `#msd-progress`-style mention alias is package.json's separate
// `toolReferenceName` field (VS Code owns that mapping internally).
const LM_TOOLS = [
{
name: 'gsd_progress',
// skills/gsd-progress — real, verified: `gsd-tools.cjs progress json`.
name: 'msd_progress',
// skills/msd-progress — real, verified: `msd-tools.cjs progress json`.
resolveCommand: () => ({ family: 'progress', subcommand: 'json', args: [] }),
},
{
name: 'gsd_workstreams',
// skills/gsd-workstreams — real, verified: `gsd-tools.cjs workstream list`.
name: 'msd_workstreams',
// skills/msd-workstreams — real, verified: `msd-tools.cjs workstream list`.
resolveCommand: () => ({ family: 'workstream', subcommand: 'list', args: [] }),
},
{
name: 'gsd_plan_phase',
// skills/gsd-plan-phase — real, verified: `gsd-tools.cjs phase-plan-index <phase>`.
name: 'msd_plan_phase',
// skills/msd-plan-phase — real, verified: `msd-tools.cjs phase-plan-index <phase>`.
// (The full multi-step planning workflow stays slash-command-native; this
// tool exposes the read-only plan-index lookup the workflow itself queries first.)
resolveCommand: (input) => ({
@@ -238,8 +238,8 @@ function createLanguageModelTool(toolDef, vscode) {
// has no cwd field of its own.
const cwd = resolveWorkspaceCwd(vscode);
const { family, subcommand, args } = toolDef.resolveCommand(input);
const result = JSON.parse(await dispatchGsdCommand({ family, subcommand, args, cwd }));
const text = result.ok ? result.stdout : `GSD error: ${result.stderr || result.stdout || 'dispatch failed'}`;
const result = JSON.parse(await dispatchMsdCommand({ family, subcommand, args, cwd }));
const text = result.ok ? result.stdout : `MSD error: ${result.stderr || result.stdout || 'dispatch failed'}`;
return new vscode.LanguageModelToolResult([new vscode.LanguageModelTextPart(text)]);
},
};
@@ -264,32 +264,32 @@ function registerLanguageModelTools(vscode, context) {
}
/** Mirrors capabilities/vscode/capability.json's hostIntegration.dispatch.maxDepth. */
const GSD_MAX_SUBAGENT_DEPTH = 5;
const MSD_MAX_SUBAGENT_DEPTH = 5;
/**
* #2103 UPGRADE 2 — native subagent dispatch (#runSubagent).
*
* Dispatches a command as a (possibly nested) subagent turn, enforcing GSD's
* Dispatches a command as a (possibly nested) subagent turn, enforcing MSD's
* own maxDepth:5 ceiling (capabilities/vscode/capability.json) independent of
* whatever VS Code's chat engine enforces natively for `#runSubagent` /
* `chat.subagents.allowInvocationsFromSubagents` — belt-and-suspenders, never
* silently trusts the host's own depth accounting.
* @param {{family?:string, subcommand?:string, args?:string[], cwd?:string, depth?:number}} args
* @returns {Promise<string>} same JSON-stringified contract as dispatchGsdCommand.
* @returns {Promise<string>} same JSON-stringified contract as dispatchMsdCommand.
*/
async function dispatchAsSubagent(args) {
const a = (args && typeof args === 'object') ? args : {};
const depth = Number.isInteger(a.depth) ? a.depth : 0;
if (depth > GSD_MAX_SUBAGENT_DEPTH) {
if (depth > MSD_MAX_SUBAGENT_DEPTH) {
return JSON.stringify({
ok: false,
stdout: '',
stderr: `GSD subagent dispatch refused: depth ${depth} exceeds maxDepth ${GSD_MAX_SUBAGENT_DEPTH}`,
stderr: `MSD subagent dispatch refused: depth ${depth} exceeds maxDepth ${MSD_MAX_SUBAGENT_DEPTH}`,
code: null,
timedOut: false,
});
}
return dispatchGsdCommand(a);
return dispatchMsdCommand(a);
}
/**
@@ -313,13 +313,13 @@ function registerSubagentDispatch(vscode) {
} catch {
available = false;
}
return { available, dispatchAsSubagent, maxDepth: GSD_MAX_SUBAGENT_DEPTH };
return { available, dispatchAsSubagent, maxDepth: MSD_MAX_SUBAGENT_DEPTH };
}
/**
* VS Code extension activation. Composes the IDE-profile seams (per the #1933
* reference binding) + registers the full command surface: palette
* (gsd.invoke), chat participant (@gsd), Language Model Tools, and the
* (msd.invoke), chat participant (@msd), Language Model Tools, and the
* #runSubagent depth-cap wiring.
* @param {import('vscode').ExtensionContext} context
*/
@@ -327,18 +327,18 @@ function activate(context) {
const vscode = require('vscode');
// ── Command surface: palette ──────────────────────────────────────────────
// #2103 FIX: wrap dispatchGsdCommand (rather than registering it directly as
// #2103 FIX: wrap dispatchMsdCommand (rather than registering it directly as
// the handler) so a palette invocation that omits `cwd` resolves the user's
// actual workspace instead of silently defaulting to the extension host's
// own process.cwd(). An explicit `args.cwd` (e.g. from a programmatic
// vscode.commands.executeCommand('gsd.invoke', {..., cwd}) caller) still
// vscode.commands.executeCommand('msd.invoke', {..., cwd}) caller) still
// takes precedence.
const gsdCommand = vscode.commands.registerCommand('gsd.invoke', (args) => {
const msdCommand = vscode.commands.registerCommand('msd.invoke', (args) => {
const a = (args && typeof args === 'object') ? args : {};
const cwd = a.cwd || resolveWorkspaceCwd(vscode);
return dispatchGsdCommand({ ...a, cwd });
return dispatchMsdCommand({ ...a, cwd });
});
context.subscriptions.push(gsdCommand);
context.subscriptions.push(msdCommand);
// ── IDE-profile host binding (#1933 reference binding; desktop/Node only —
// see host-binding.js's header for why browser.js does NOT use this path).
@@ -348,17 +348,17 @@ function activate(context) {
// wrapped fail-open so a genuinely older VS Code build (no vscode.lm at all)
// degrades to the palette command only, rather than blocking activation.
try {
const bindGsdToVscode = require('./host-binding.js');
const bindMsdToVscode = require('./host-binding.js');
const hostStorage = {
read: (key) => context.globalState.get(key),
write: (key, value) => context.globalState.update(key, value),
};
bindGsdToVscode(vscode, hostStorage);
bindMsdToVscode(vscode, hostStorage);
} catch {
// fail-open — see doc comment above.
}
// ── Chat participant (@gsd) ───────────────────────────────────────────────
// ── Chat participant (@msd) ───────────────────────────────────────────────
registerChatParticipant(vscode, context);
// ── Language Model Tools (#2103 UPGRADE 1) ────────────────────────────────
@@ -370,7 +370,7 @@ function activate(context) {
module.exports = {
activate,
dispatchGsdCommand,
dispatchMsdCommand,
resolveEngineRoot,
resolveWorkspaceCwd,
parseChatPrompt,
@@ -379,5 +379,5 @@ module.exports = {
registerSubagentDispatch,
dispatchAsSubagent,
LM_TOOLS,
GSD_MAX_SUBAGENT_DEPTH,
MSD_MAX_SUBAGENT_DEPTH,
};

View File

@@ -1,7 +1,7 @@
'use strict';
/**
* VS Code IDE host binding for GSD (ADR-1239 Phase D / #1933, shipped #2103).
* VS Code IDE host binding for MSD (ADR-1239 Phase D / #1933, shipped #2103).
*
* VS Code is the IDE-profile reference host. This module composes the Phase-3
* engine seams for the negotiated `ide` profile (host-integration.cts
@@ -17,7 +17,7 @@
* rejects system-role messages, so the request mapper uses User
* role only.
* - hookBus: 'engine' → createHookBus({bus:'engine'}) — VS Code has NO host event bus,
* so GSD owns the bus in-process (full subscribe + emit).
* so MSD owns the bus in-process (full subscribe + emit).
* - stateIO: 'sandboxed-storage' → createStateIO({io:'sandboxed-storage'}, {backend}) bound to a
* host-supplied storage (no arbitrary FS — web/no-child_process safe
* AT THE STATE-IO SEAM ITSELF; see the DESKTOP-ONLY note below for
@@ -33,12 +33,12 @@
* despite the per-seam design above being conceptually host-agnostic, the CONCRETE engine-lib
* modules this file requires are NOT web-safe today — each pulls in Node's `fs`/`os`/`path`
* at module-load time (eagerly, regardless of which code path actually runs):
* - gsd-core/bin/lib/state-io.cjs → requires 'node:fs' directly.
* - gsd-core/bin/lib/adapter-imperative.cjs → requires install-engine.cjs (fs/os/path) and
* - msd-core/bin/lib/state-io.cjs → requires 'node:fs' directly.
* - msd-core/bin/lib/adapter-imperative.cjs → requires install-engine.cjs (fs/os/path) and
* capability-loader.cjs (fs/os/path).
* - gsd-core/bin/lib/model-adapter.cjs → requires model-resolver.cjs → config-loader.cjs
* - msd-core/bin/lib/model-adapter.cjs → requires model-resolver.cjs → config-loader.cjs
* (fs/os/path) and configuration.cjs (fs/path).
* - gsd-core/bin/lib/hook-bus.cjs → no requires; this one alone is web-safe.
* - msd-core/bin/lib/hook-bus.cjs → no requires; this one alone is web-safe.
* In a real VS Code Web Extension host (webworker context) `require('node:fs')` does not
* resolve — activation would throw immediately. This is why `vscode/browser.js` does NOT
* require this module (or any of the engine-lib adapters) and instead implements its own
@@ -57,25 +57,25 @@
* sandboxed-storage backend (e.g. globalState/workspaceState/secrets).
* @returns {object} the composed IDE host surface: { runtime, model, hookBus, stateIO, adapter, commands }
*/
module.exports = function bindGsdToVscode(vscode, hostStorage) {
module.exports = function bindMsdToVscode(vscode, hostStorage) {
if (!vscode || !vscode.lm || typeof vscode.lm.selectChatModels !== 'function') {
throw new TypeError('bindGsdToVscode: vscode.lm.selectChatModels is required (active model provider — VS Code exposes no vscode.lm.sendRequest; a model is selected via selectChatModels() and ITS sendRequest is called)');
throw new TypeError('bindMsdToVscode: vscode.lm.selectChatModels is required (active model provider — VS Code exposes no vscode.lm.sendRequest; a model is selected via selectChatModels() and ITS sendRequest is called)');
}
if (!hostStorage || typeof hostStorage.read !== 'function' || typeof hostStorage.write !== 'function') {
throw new TypeError('bindGsdToVscode: hostStorage {read,write} is required (sandboxed-storage backend)');
throw new TypeError('bindMsdToVscode: hostStorage {read,write} is required (sandboxed-storage backend)');
}
const { createImperativeAdapter } = require('../gsd-core/bin/lib/adapter-imperative.cjs');
const { createModelAdapter } = require('../gsd-core/bin/lib/model-adapter.cjs');
const { createHookBus } = require('../gsd-core/bin/lib/hook-bus.cjs');
const { createStateIO } = require('../gsd-core/bin/lib/state-io.cjs');
const { createImperativeAdapter } = require('../msd-core/bin/lib/adapter-imperative.cjs');
const { createModelAdapter } = require('../msd-core/bin/lib/model-adapter.cjs');
const { createHookBus } = require('../msd-core/bin/lib/hook-bus.cjs');
const { createStateIO } = require('../msd-core/bin/lib/state-io.cjs');
// Active model: GSD model calls route through vscode.lm. There is no
// Active model: MSD model calls route through vscode.lm. There is no
// `vscode.lm.sendRequest` — a model must be selected first
// (`vscode.lm.selectChatModels()`, async → LanguageModelChat[]), then THAT
// model's own `.sendRequest(messages, options?, token?)` is called. Selects
// fresh on every call (no cross-call caching) so a model becoming available/
// unavailable between calls is always reflected; gsd-core/bin/lib/model-adapter.cjs's
// unavailable between calls is always reflected; msd-core/bin/lib/model-adapter.cjs's
// ActiveModelAdapter.sendRequest is a plain (non-async) pass-through that
// returns whatever the injected function returns, so an async injected
// function composes transparently — no adapter-side change needed (verified
@@ -87,13 +87,13 @@ module.exports = function bindGsdToVscode(vscode, hostStorage) {
const models = await vscode.lm.selectChatModels();
const [chatModel] = models || [];
if (!chatModel || typeof chatModel.sendRequest !== 'function') {
throw new Error('bindGsdToVscode: vscode.lm.selectChatModels() returned no usable model (no active model available)');
throw new Error('bindMsdToVscode: vscode.lm.selectChatModels() returned no usable model (no active model available)');
}
return chatModel.sendRequest(req);
},
});
// Engine-owned hook bus: VS Code has no host bus, so GSD owns it in-process.
// Engine-owned hook bus: VS Code has no host bus, so MSD owns it in-process.
const hookBus = createHookBus({ bus: 'engine' });
// Sandboxed-storage stateIO bound to the host storage backend (no fs / no child_process).
@@ -103,10 +103,10 @@ module.exports = function bindGsdToVscode(vscode, hostStorage) {
const adapter = createImperativeAdapter({ runtime: 'vscode' });
// Command surface: Command Palette + Chat participant entries bound to the
// GSD command-routing hub via the imperative adapter (interface point 1).
// MSD command-routing hub via the imperative adapter (interface point 1).
const commands = Object.freeze({
'gsd.invoke': Object.freeze({ description: 'Invoke a GSD command via the embedded engine (palette/chat).' }),
'gsd.help': Object.freeze({ description: 'List GSD commands available in the IDE host.' }),
'msd.invoke': Object.freeze({ description: 'Invoke a MSD command via the embedded engine (palette/chat).' }),
'msd.help': Object.freeze({ description: 'List MSD commands available in the IDE host.' }),
});
return Object.freeze({ runtime: 'vscode', model, hookBus, stateIO, adapter, commands });

View File

@@ -1,7 +1,7 @@
{
"name": "gsd-core-vscode",
"displayName": "GSD Core",
"description": "GSD orchestration engine embedded in VS Code (ADR-1239 IDE profile).",
"name": "msd-core-vscode",
"displayName": "MSD Core",
"description": "MSD orchestration engine embedded in VS Code (ADR-1239 IDE profile).",
"version": "1.14.0",
"publisher": "opengsd",
"engines": {
@@ -11,37 +11,37 @@
"Other"
],
"activationEvents": [
"onCommand:gsd.invoke"
"onCommand:msd.invoke"
],
"main": "./extension.js",
"browser": "./browser.js",
"contributes": {
"commands": [
{
"command": "gsd.invoke",
"title": "GSD: Invoke Command"
"command": "msd.invoke",
"title": "MSD: Invoke Command"
}
],
"chatParticipants": [
{
"id": "gsd",
"name": "gsd",
"fullName": "GSD Core",
"description": "Invoke GSD orchestration commands from chat.",
"id": "msd",
"name": "msd",
"fullName": "MSD Core",
"description": "Invoke MSD orchestration commands from chat.",
"isSticky": true
}
],
"languageModelTools": [
{
"name": "gsd_progress",
"name": "msd_progress",
"tags": [
"gsd",
"msd",
"status"
],
"toolReferenceName": "gsd-progress",
"displayName": "GSD Progress",
"modelDescription": "Reports GSD milestone/phase progress (percent complete, plan and summary counts) for the current project.",
"userDescription": "Check GSD project progress.",
"toolReferenceName": "msd-progress",
"displayName": "MSD Progress",
"modelDescription": "Reports MSD milestone/phase progress (percent complete, plan and summary counts) for the current project.",
"userDescription": "Check MSD project progress.",
"canBeReferencedInPrompt": true,
"inputSchema": {
"type": "object",
@@ -50,15 +50,15 @@
}
},
{
"name": "gsd_workstreams",
"name": "msd_workstreams",
"tags": [
"gsd",
"msd",
"status"
],
"toolReferenceName": "gsd-workstreams",
"displayName": "GSD Workstreams",
"modelDescription": "Lists the GSD parallel workstreams for the current project (or reports flat/single-workstream mode).",
"userDescription": "List GSD workstreams.",
"toolReferenceName": "msd-workstreams",
"displayName": "MSD Workstreams",
"modelDescription": "Lists the MSD parallel workstreams for the current project (or reports flat/single-workstream mode).",
"userDescription": "List MSD workstreams.",
"canBeReferencedInPrompt": true,
"inputSchema": {
"type": "object",
@@ -67,22 +67,22 @@
}
},
{
"name": "gsd_plan_phase",
"name": "msd_plan_phase",
"tags": [
"gsd",
"msd",
"plan"
],
"toolReferenceName": "gsd-plan-phase",
"displayName": "GSD Plan Phase",
"modelDescription": "Looks up the plan index (plans, waves, checkpoints) for a named GSD phase. Read-only — does not create or modify a phase plan; use the /gsd-plan-phase chat workflow for full phase planning.",
"userDescription": "Look up a GSD phase's plan index.",
"toolReferenceName": "msd-plan-phase",
"displayName": "MSD Plan Phase",
"modelDescription": "Looks up the plan index (plans, waves, checkpoints) for a named MSD phase. Read-only — does not create or modify a phase plan; use the /msd-plan-phase chat workflow for full phase planning.",
"userDescription": "Look up a MSD phase's plan index.",
"canBeReferencedInPrompt": true,
"inputSchema": {
"type": "object",
"properties": {
"phase": {
"type": "string",
"description": "The GSD phase name to look up (e.g. \"01-core\")."
"description": "The MSD phase name to look up (e.g. \"01-core\")."
}
},
"required": [