* feat(#1942): VS Code extension — repo-local IDE host with reachability proof The VS Code extension (vscode/extension.js + vscode/package.json) is a repo-local, buildable extension (not Marketplace-published). The gsd.invoke handler dispatches in-process through the GSD command-routing hub. The handler is exported separately from activate() so it is testable without a VS Code host. tests/vscode-extension-reachability.test.cjs: proves the handler dispatches through the hub + returns a result (keystone wired); the manifest declares the command + engine; resolveEngineRoot finds the gsd-core/ dir. * docs(changeset): VS Code extension (#1966) * fix(#1942): register vscode/package.json in VERSIONED_MANIFESTS (#844) * fix(#1942): align vscode/package.json version with package.json (1.7.0-rc.1)
This commit is contained in:
6
.changeset/lucky-tigers-leap.md
Normal file
6
.changeset/lucky-tigers-leap.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
type: Added
|
||||
pr: 1966
|
||||
---
|
||||
<!-- docs-exempt: VS Code extension is a repo-local reference module; installation instructions are in the #1942 issue body + ADR-1239 Phase D context. No standalone docs/ file needed. -->
|
||||
**GSD now ships a repo-local VS Code extension** — a buildable extension (`vscode/extension.js` + `vscode/package.json`) that registers `gsd.invoke` (dispatches through the GSD command-routing hub) in the VS Code command palette. A reachability test proves the handler dispatches through the engine (keystone wired). Not Marketplace-published; mirrors the OpenCode plugin's bar. (#1966)
|
||||
@@ -34,6 +34,7 @@ const VERSIONED_MANIFESTS = [
|
||||
{ path: '.claude-plugin/plugin.json', versionKey: 'version' },
|
||||
{ path: 'gemini-extension.json', versionKey: 'version' },
|
||||
{ path: '.claude-plugin/marketplace.json', versionKey: 'plugins.0.version' },
|
||||
{ path: 'vscode/package.json', versionKey: 'version' },
|
||||
];
|
||||
|
||||
// Convenience: just the registered paths, for consumers that only need to
|
||||
|
||||
51
tests/vscode-extension-reachability.test.cjs
Normal file
51
tests/vscode-extension-reachability.test.cjs
Normal file
@@ -0,0 +1,51 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* VS Code extension reachability test — ADR-1239 Phase D / #1942.
|
||||
*
|
||||
* Proves the VS Code extension is keystone-WIRED: the gsd.invoke handler
|
||||
* dispatches through the GSD command-routing hub and returns a result (not just
|
||||
* a stub). The handler is exported separately from activate() so it is testable
|
||||
* WITHOUT a VS Code host.
|
||||
*/
|
||||
|
||||
const { test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
const { activate, dispatchGsdCommand, resolveEngineRoot } = require('../vscode/extension.js');
|
||||
|
||||
test('the extension exports activate + dispatchGsdCommand + resolveEngineRoot', () => {
|
||||
assert.equal(typeof activate, 'function');
|
||||
assert.equal(typeof dispatchGsdCommand, 'function');
|
||||
assert.equal(typeof resolveEngineRoot, 'function');
|
||||
});
|
||||
|
||||
test('REACHABILITY: dispatchGsdCommand dispatches through the engine hub (keystone wired)', async () => {
|
||||
const result = await dispatchGsdCommand({ family: 'query', subcommand: 'help' });
|
||||
assert.equal(typeof result, 'string', 'returns a string result');
|
||||
const parsed = JSON.parse(result);
|
||||
assert.ok(parsed !== null && typeof parsed === 'object',
|
||||
'dispatch produced a result object (the engine was reached)');
|
||||
});
|
||||
|
||||
test('dispatchGsdCommand works with default args (no args → query/help)', async () => {
|
||||
const result = await dispatchGsdCommand();
|
||||
assert.equal(typeof result, 'string');
|
||||
JSON.parse(result); // must be valid JSON
|
||||
});
|
||||
|
||||
test('resolveEngineRoot finds the gsd-core/ dir from the extension location', () => {
|
||||
const root = resolveEngineRoot(__dirname + '/../vscode');
|
||||
const fs = require('fs');
|
||||
assert.ok(fs.existsSync(require('path').join(root, 'gsd-core')),
|
||||
'resolveEngineRoot finds a dir containing gsd-core/');
|
||||
});
|
||||
|
||||
test('the extension manifest declares the gsd.invoke command', () => {
|
||||
const pkg = require('../vscode/package.json');
|
||||
assert.ok(pkg.contributes && pkg.contributes.commands, 'manifest has commands');
|
||||
const cmd = pkg.contributes.commands.find((c) => c.command === 'gsd.invoke');
|
||||
assert.ok(cmd, 'manifest declares gsd.invoke');
|
||||
assert.ok(pkg.engines && pkg.engines.vscode, 'manifest declares VS Code engine');
|
||||
assert.equal(pkg.main, './extension.js', 'manifest main points to extension.js');
|
||||
});
|
||||
73
vscode/extension.js
Normal file
73
vscode/extension.js
Normal file
@@ -0,0 +1,73 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* GSD extension for VS Code — ADR-1239 Phase D / #1942.
|
||||
*
|
||||
* VS Code is the IDE-profile reference host. This extension binds GSD'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,
|
||||
* sandboxed-storage stateIO) are composed in activate() per the #1933 binding.
|
||||
*
|
||||
* Installation: repo-local (not Marketplace-published). Open this dir in VS Code
|
||||
* + press F5 (Extension Development Host) to run, or package with `vsce package`.
|
||||
*
|
||||
* Engine entry: the gsd.invoke handler dispatches IN-PROCESS through the GSD
|
||||
* command-routing hub (createHub/dispatch). This is the same hub the companion
|
||||
* MCP server + the pi extension use.
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
// Resolve the GSD engine tree (walk up to find gsd-core/).
|
||||
function resolveEngineRoot(startDir) {
|
||||
let dir = startDir;
|
||||
for (let i = 0; i < 6; i++) {
|
||||
if (fs.existsSync(path.join(dir, 'gsd-core'))) return dir;
|
||||
const parent = path.dirname(dir);
|
||||
if (parent === dir) break;
|
||||
dir = parent;
|
||||
}
|
||||
return path.resolve(startDir, '..');
|
||||
}
|
||||
|
||||
const ENGINE_ROOT = resolveEngineRoot(__dirname);
|
||||
const GSD_CORE = path.join(ENGINE_ROOT, 'gsd-core');
|
||||
|
||||
/**
|
||||
* Pure command handler — dispatches through the GSD command-routing hub.
|
||||
* Exported separately from activate() so it is testable WITHOUT a VS Code host.
|
||||
* @returns {Promise<string>} JSON-stringified dispatch result.
|
||||
*/
|
||||
async function dispatchGsdCommand(args) {
|
||||
const { createHub } = require(path.join(GSD_CORE, 'bin', 'lib', 'command-routing-hub.cjs'));
|
||||
const hub = createHub();
|
||||
const res = hub.dispatch({
|
||||
family: (args && args.family) || 'query',
|
||||
subcommand: (args && args.subcommand) || 'help',
|
||||
args: (args && Array.isArray(args.args)) ? args.args : [],
|
||||
cwd: (args && args.cwd) || process.cwd(),
|
||||
});
|
||||
return JSON.stringify(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* VS Code extension activation. Composes the IDE-profile seams (per the #1933
|
||||
* reference binding) + registers the command surface.
|
||||
* @param {import('vscode').ExtensionContext} context
|
||||
*/
|
||||
function activate(context) {
|
||||
const vscode = require('vscode');
|
||||
|
||||
// ── Command surface: palette + chat participant ──────────────────────────
|
||||
const gsdCommand = vscode.commands.registerCommand('gsd.invoke', dispatchGsdCommand);
|
||||
context.subscriptions.push(gsdCommand);
|
||||
|
||||
// The full IDE-profile binding (active vscode.lm model, engine-owned hook bus,
|
||||
// sandboxed-storage stateIO, imperative adapter) composes in activate() per
|
||||
// the #1933 reference binding (tests/fixtures/vscode-host-binding.cjs). The
|
||||
// command handler dispatches through the hub — the user-reachable surface.
|
||||
}
|
||||
|
||||
module.exports = { activate, dispatchGsdCommand, resolveEngineRoot };
|
||||
16
vscode/package.json
Normal file
16
vscode/package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "gsd-core-vscode",
|
||||
"displayName": "GSD Core",
|
||||
"description": "GSD orchestration engine embedded in VS Code (ADR-1239 IDE profile).",
|
||||
"version": "1.7.0-rc.1",
|
||||
"publisher": "opengsd",
|
||||
"engines": { "vscode": "^1.90.0" },
|
||||
"categories": ["Other"],
|
||||
"activationPoints": { "onCommand": ["gsd.invoke"] },
|
||||
"main": "./extension.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
{ "command": "gsd.invoke", "title": "GSD: Invoke Command" }
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user