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:
@@ -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,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user