werkmeister 0.14.0 → 0.15.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/dist/main.js +96 -24
- package/dist/mcp.js +49 -34
- package/dist/sandbox-workspaces.vsix +0 -0
- package/infra/schemas/workspace.schema.json +1 -1
- package/infra/skills/sb-test/SKILL.md +1 -1
- package/package.json +2 -2
- package/werkmeister +3 -3
package/dist/main.js
CHANGED
|
@@ -44,7 +44,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
44
44
|
var define_SANDBOX_BUILD_default;
|
|
45
45
|
var init_define_SANDBOX_BUILD = __esm({
|
|
46
46
|
"<define:__SANDBOX_BUILD__>"() {
|
|
47
|
-
define_SANDBOX_BUILD_default = { sha: "
|
|
47
|
+
define_SANDBOX_BUILD_default = { sha: "8bf0338bcc3351a5e1154beba68c1b6f9beea71a", dirty: false };
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
|
|
@@ -13276,7 +13276,7 @@ function writeWorkspaceSettings(workspaceRoot) {
|
|
|
13276
13276
|
writeWorkspaceModel(workspaceRoot, readModel(workspaceRoot));
|
|
13277
13277
|
writeAutoStopHook(workspaceRoot, readAutoStop(workspaceRoot));
|
|
13278
13278
|
}
|
|
13279
|
-
var _HOOK_MARKER, _GATE_MARKER, _PR_GUARD_MARKER, _AUTO_STOP_MARKER, _SKILLS_SELF_HEAL, SESSION_START_COMMAND, PRE_TOOL_USE_GATE_COMMAND, PR_GUARD_COMMAND, SESSION_END_COMMAND, _SESSION_END_TIMEOUT_S, READ_ONLY_GIT_RULES, AUTONOMOUS_RULES, AUTONOMOUS_DENY, permissionsRecord, _strings;
|
|
13279
|
+
var _HOOK_MARKER, _GATE_MARKER, _PR_GUARD_MARKER, _AUTO_STOP_MARKER, _SKILLS_SELF_HEAL, SESSION_START_COMMAND, PRE_TOOL_USE_GATE_COMMAND, PR_GUARD_COMMAND, SESSION_END_COMMAND, _SESSION_END_TIMEOUT_S, READ_ONLY_GIT_RULES, PLUGIN_MCP_PREFIXES, pluginTool, AUTONOMOUS_RULES, AUTONOMOUS_DENY, permissionsRecord, _strings;
|
|
13280
13280
|
var init_hooks_gen = __esm({
|
|
13281
13281
|
"../../packages/sandbox-core/dist/hooks_gen.js"() {
|
|
13282
13282
|
"use strict";
|
|
@@ -13299,6 +13299,11 @@ var init_hooks_gen = __esm({
|
|
|
13299
13299
|
"Bash(git status:*)",
|
|
13300
13300
|
"Bash(git ls-files:*)"
|
|
13301
13301
|
];
|
|
13302
|
+
PLUGIN_MCP_PREFIXES = [
|
|
13303
|
+
"mcp__plugin_werkmeister_workspaces__",
|
|
13304
|
+
"mcp__plugin_sandbox-tools_sandbox-workspace__"
|
|
13305
|
+
];
|
|
13306
|
+
pluginTool = (tool) => PLUGIN_MCP_PREFIXES.map((prefix) => `${prefix}${tool}`);
|
|
13302
13307
|
AUTONOMOUS_RULES = [
|
|
13303
13308
|
"Bash(git:*)",
|
|
13304
13309
|
// `sandbox pr open` does the push and the PR; gh is read-only here.
|
|
@@ -13322,7 +13327,7 @@ var init_hooks_gen = __esm({
|
|
|
13322
13327
|
"workspace-prs",
|
|
13323
13328
|
"kube-context",
|
|
13324
13329
|
"k8s-forwards-status"
|
|
13325
|
-
].
|
|
13330
|
+
].flatMap(pluginTool)
|
|
13326
13331
|
];
|
|
13327
13332
|
AUTONOMOUS_DENY = [
|
|
13328
13333
|
...[
|
|
@@ -13365,7 +13370,7 @@ var init_hooks_gen = __esm({
|
|
|
13365
13370
|
"claude-send",
|
|
13366
13371
|
"claude-resume",
|
|
13367
13372
|
"sandbox-connect"
|
|
13368
|
-
].
|
|
13373
|
+
].flatMap(pluginTool)
|
|
13369
13374
|
];
|
|
13370
13375
|
permissionsRecord = (workspaceRoot) => path7.join(dotDir(workspaceRoot), "claude-permissions.json");
|
|
13371
13376
|
_strings = (v) => Array.isArray(v) ? v.filter((r) => typeof r === "string") : [];
|
|
@@ -32507,7 +32512,7 @@ models:
|
|
|
32507
32512
|
claude-sonnet-5: { input: 3, output: 15, cacheWrite: 3.75, cacheRead: 0.30 }
|
|
32508
32513
|
claude-haiku-4-5: { input: 1, output: 5, cacheWrite: 1.25, cacheRead: 0.10 }
|
|
32509
32514
|
`;
|
|
32510
|
-
SANDBOX_MCP_SERVER = "
|
|
32515
|
+
SANDBOX_MCP_SERVER = "werkmeister";
|
|
32511
32516
|
REGISTRY_DEFAULTS = {
|
|
32512
32517
|
archetypes: {
|
|
32513
32518
|
"node-web": {
|
|
@@ -54253,7 +54258,7 @@ function cacheSet(key, v) {
|
|
|
54253
54258
|
await fs45.writeFile(tmp, JSON.stringify(store), "utf-8");
|
|
54254
54259
|
await fs45.rename(tmp, file);
|
|
54255
54260
|
} catch (e) {
|
|
54256
|
-
console.error(`[
|
|
54261
|
+
console.error(`[werkmeister] cache write failed for ${key}:`, e.message);
|
|
54257
54262
|
}
|
|
54258
54263
|
});
|
|
54259
54264
|
writeChain = run34.catch(() => {
|
|
@@ -54266,7 +54271,7 @@ function runBatchOnce(keys, job) {
|
|
|
54266
54271
|
return;
|
|
54267
54272
|
for (const k of fresh)
|
|
54268
54273
|
inFlight.add(k);
|
|
54269
|
-
void Promise.resolve().then(() => job(fresh)).catch((e) => console.error("[
|
|
54274
|
+
void Promise.resolve().then(() => job(fresh)).catch((e) => console.error("[werkmeister] background cache refresh failed:", e.message)).finally(() => {
|
|
54270
54275
|
for (const k of fresh)
|
|
54271
54276
|
inFlight.delete(k);
|
|
54272
54277
|
});
|
|
@@ -57378,13 +57383,13 @@ function loadRegistry(claudePluginsDir) {
|
|
|
57378
57383
|
const plugins = typeof data === "object" && data !== null && !Array.isArray(data) ? data["plugins"] : void 0;
|
|
57379
57384
|
return typeof plugins === "object" && plugins !== null && !Array.isArray(plugins) ? plugins : null;
|
|
57380
57385
|
}
|
|
57381
|
-
function installedPlugin(claudePluginsDir) {
|
|
57386
|
+
function installedPlugin(claudePluginsDir, name = PLUGIN_NAME) {
|
|
57382
57387
|
const plugins = loadRegistry(claudePluginsDir);
|
|
57383
57388
|
if (plugins === null) {
|
|
57384
57389
|
return [null, null];
|
|
57385
57390
|
}
|
|
57386
57391
|
for (const [key, entries] of Object.entries(plugins)) {
|
|
57387
|
-
if (!key.startsWith(`${
|
|
57392
|
+
if (!key.startsWith(`${name}@`) || !Array.isArray(entries)) {
|
|
57388
57393
|
continue;
|
|
57389
57394
|
}
|
|
57390
57395
|
for (const entry of entries) {
|
|
@@ -57466,8 +57471,13 @@ function pluginDriftWarnings(repoPluginDir, claudePluginsDir) {
|
|
|
57466
57471
|
}
|
|
57467
57472
|
const [installedVersion2, installPath] = installedPlugin(claudePluginsDir);
|
|
57468
57473
|
if (installPath === null) {
|
|
57474
|
+
if (installedPlugin(claudePluginsDir, LEGACY_PLUGIN_NAME)[1] !== null) {
|
|
57475
|
+
return [
|
|
57476
|
+
`the ${LEGACY_PLUGIN_NAME} plugin was renamed ${PLUGIN_NAME}, and only the old one is installed \u2014 its skills are now ${PLUGIN_NAME}:diagnose, ${PLUGIN_NAME}:status, ${PLUGIN_NAME}:workspace, \u2026 Run \`w9r setup\` to switch over.`
|
|
57477
|
+
];
|
|
57478
|
+
}
|
|
57469
57479
|
return [
|
|
57470
|
-
`${PLUGIN_NAME} plugin is not installed \u2014 the
|
|
57480
|
+
`${PLUGIN_NAME} plugin is not installed \u2014 the ops skills (${PLUGIN_NAME}:diagnose, ${PLUGIN_NAME}:status, ${PLUGIN_NAME}:workspace, \u2026) will not surface in Claude Code sessions. Run \`w9r setup\` to install it (or use /plugin in Claude Code). The sb-* skills are unaffected \u2014 they are projected into each workspace by init-workspace.`
|
|
57471
57481
|
];
|
|
57472
57482
|
}
|
|
57473
57483
|
const drift = skillDrift(path58.join(repoPluginDir, "skills"), path58.join(installPath, "skills"));
|
|
@@ -57483,14 +57493,15 @@ function pluginDriftWarnings(repoPluginDir, claudePluginsDir) {
|
|
|
57483
57493
|
}
|
|
57484
57494
|
return [`${lag}: ${drift.join("; ")} \u2014 ${REFRESH_HINT}.`];
|
|
57485
57495
|
}
|
|
57486
|
-
var PLUGIN_NAME, REFRESH_HINT;
|
|
57496
|
+
var PLUGIN_NAME, LEGACY_PLUGIN_NAME, REFRESH_HINT;
|
|
57487
57497
|
var init_plugin_check = __esm({
|
|
57488
57498
|
"../../packages/sandbox-core/dist/plugin_check.js"() {
|
|
57489
57499
|
"use strict";
|
|
57490
57500
|
init_define_SANDBOX_BUILD();
|
|
57491
57501
|
init_config();
|
|
57492
|
-
PLUGIN_NAME = "
|
|
57493
|
-
|
|
57502
|
+
PLUGIN_NAME = "werkmeister";
|
|
57503
|
+
LEGACY_PLUGIN_NAME = "sandbox-tools";
|
|
57504
|
+
REFRESH_HINT = "run `w9r setup` to refresh it so sessions pick up the current werkmeister ops skills";
|
|
57494
57505
|
}
|
|
57495
57506
|
});
|
|
57496
57507
|
|
|
@@ -57629,6 +57640,53 @@ function briefOutput(out, maxLines = 4) {
|
|
|
57629
57640
|
return out.trim().slice(0, 200);
|
|
57630
57641
|
return lines.slice(0, maxLines).join("; ");
|
|
57631
57642
|
}
|
|
57643
|
+
function retireLegacyPlugin(claudePluginsDir, runner, checkOnly) {
|
|
57644
|
+
const label = `plugin ${LEGACY_PLUGIN.name} (renamed ${PLUGIN_NAME})`;
|
|
57645
|
+
const installed = installedVersion(claudePluginsDir, LEGACY_PLUGIN) !== null;
|
|
57646
|
+
const marketplaceKnown = LEGACY_PLUGIN.marketplace in knownMarketplaces(claudePluginsDir);
|
|
57647
|
+
if (!installed && !marketplaceKnown)
|
|
57648
|
+
return [];
|
|
57649
|
+
if (checkOnly) {
|
|
57650
|
+
return [
|
|
57651
|
+
{
|
|
57652
|
+
label,
|
|
57653
|
+
ok: false,
|
|
57654
|
+
detail: `old name still set up; run \`w9r setup\` to switch to ${PLUGIN_NAME}`
|
|
57655
|
+
}
|
|
57656
|
+
];
|
|
57657
|
+
}
|
|
57658
|
+
const steps = [];
|
|
57659
|
+
if (installed) {
|
|
57660
|
+
const [rc, out] = runner([
|
|
57661
|
+
"claude",
|
|
57662
|
+
"plugin",
|
|
57663
|
+
"uninstall",
|
|
57664
|
+
`${LEGACY_PLUGIN.name}@${LEGACY_PLUGIN.marketplace}`
|
|
57665
|
+
]);
|
|
57666
|
+
steps.push({
|
|
57667
|
+
label,
|
|
57668
|
+
ok: rc === 0,
|
|
57669
|
+
detail: rc === 0 ? "uninstalled" : `uninstall failed: ${out}`
|
|
57670
|
+
});
|
|
57671
|
+
if (rc !== 0)
|
|
57672
|
+
return steps;
|
|
57673
|
+
}
|
|
57674
|
+
if (marketplaceKnown) {
|
|
57675
|
+
const [rc, out] = runner([
|
|
57676
|
+
"claude",
|
|
57677
|
+
"plugin",
|
|
57678
|
+
"marketplace",
|
|
57679
|
+
"remove",
|
|
57680
|
+
LEGACY_PLUGIN.marketplace
|
|
57681
|
+
]);
|
|
57682
|
+
steps.push({
|
|
57683
|
+
label,
|
|
57684
|
+
ok: rc === 0,
|
|
57685
|
+
detail: rc === 0 ? `removed marketplace ${LEGACY_PLUGIN.marketplace}` : `marketplace remove failed: ${out}`
|
|
57686
|
+
});
|
|
57687
|
+
}
|
|
57688
|
+
return steps;
|
|
57689
|
+
}
|
|
57632
57690
|
function workspaceRepoUrl(slug) {
|
|
57633
57691
|
return `https://github.com/${slug}.git`;
|
|
57634
57692
|
}
|
|
@@ -58378,7 +58436,7 @@ async function runSetup(options = {}) {
|
|
|
58378
58436
|
const checkOnly = options.checkOnly ?? false;
|
|
58379
58437
|
const reposRoot = options.reposRoot ?? getReposRoot();
|
|
58380
58438
|
const claudePluginsDir = options.claudePluginsDir ?? path60.join(os18.homedir(), ".claude", "plugins");
|
|
58381
|
-
const repoPluginDir = options.repoPluginDir ?? path60.join(sandboxRoot(), "plugins",
|
|
58439
|
+
const repoPluginDir = options.repoPluginDir ?? path60.join(sandboxRoot(), "plugins", PLUGIN_NAME);
|
|
58382
58440
|
const runner = options.runner ?? defaultRunner;
|
|
58383
58441
|
const jira2 = options.jira ?? loadJira();
|
|
58384
58442
|
const steps = [];
|
|
@@ -58393,15 +58451,19 @@ async function runSetup(options = {}) {
|
|
|
58393
58451
|
steps.push({
|
|
58394
58452
|
label: "claude CLI",
|
|
58395
58453
|
ok: false,
|
|
58396
|
-
detail:
|
|
58454
|
+
detail: `not found on PATH \u2014 the ${PLUGIN_NAME} and ponytail plugins cannot be installed without it. Install Claude Code from https://claude.com/claude-code (the VS Code extension alone does not put \`claude\` on PATH), then re-run \`sandbox setup\`.`
|
|
58397
58455
|
});
|
|
58398
58456
|
} else {
|
|
58399
58457
|
for (const spec of REQUIRED_PLUGINS) {
|
|
58400
58458
|
let driftProbe = null;
|
|
58401
|
-
if (spec.name ===
|
|
58459
|
+
if (spec.name === PLUGIN_NAME) {
|
|
58402
58460
|
driftProbe = () => pluginDriftWarnings(repoPluginDir, claudePluginsDir);
|
|
58403
58461
|
}
|
|
58404
|
-
|
|
58462
|
+
const synced = syncPlugin(spec, claudePluginsDir, runner, checkOnly, driftProbe);
|
|
58463
|
+
steps.push(...synced);
|
|
58464
|
+
if (spec.name === PLUGIN_NAME && (checkOnly || synced.every((step) => step.ok))) {
|
|
58465
|
+
steps.push(...retireLegacyPlugin(claudePluginsDir, runner, checkOnly));
|
|
58466
|
+
}
|
|
58405
58467
|
}
|
|
58406
58468
|
for (const spec of OPTIONAL_PLUGINS) {
|
|
58407
58469
|
steps.push(...syncOptionalPlugin(spec, claudePluginsDir, runner, checkOnly, options.installOptionalPlugins ?? false));
|
|
@@ -58432,7 +58494,7 @@ async function runSetup(options = {}) {
|
|
|
58432
58494
|
steps.push(...syncVscodeExtension(checkOnly, options.installVscodeExtension ?? false, vscodeExtensionState(runner), runner));
|
|
58433
58495
|
return steps;
|
|
58434
58496
|
}
|
|
58435
|
-
var REQUIRED_PLUGINS, OPTIONAL_PLUGINS, WORKSPACE_ROOT_REPO, isLogin, DEMO_SERVICES_REPO, DEMO_SERVICES_REPO_URL, workspaceRootSpec, DEMO_SERVICES_SPEC, LEGACY_CONFIG_DIR, JIRA_TOKEN_URL, JIRA_REQUIRED_KEYS, JIRA_CONFIG_SNIPPET, EDITOR_SCHEMAS, VSCODE_EXTENSION_ID, BUNDLED_VSIX_REL;
|
|
58497
|
+
var REQUIRED_PLUGINS, LEGACY_PLUGIN, OPTIONAL_PLUGINS, WORKSPACE_ROOT_REPO, isLogin, DEMO_SERVICES_REPO, DEMO_SERVICES_REPO_URL, workspaceRootSpec, DEMO_SERVICES_SPEC, LEGACY_CONFIG_DIR, JIRA_TOKEN_URL, JIRA_REQUIRED_KEYS, JIRA_CONFIG_SNIPPET, EDITOR_SCHEMAS, VSCODE_EXTENSION_ID, BUNDLED_VSIX_REL;
|
|
58436
58498
|
var init_machine_setup = __esm({
|
|
58437
58499
|
"../../packages/sandbox-core/dist/machine_setup.js"() {
|
|
58438
58500
|
"use strict";
|
|
@@ -58449,11 +58511,11 @@ var init_machine_setup = __esm({
|
|
|
58449
58511
|
init_test_run();
|
|
58450
58512
|
REQUIRED_PLUGINS = [
|
|
58451
58513
|
// This repo doubles as the marketplace: `.claude-plugin/marketplace.json` at
|
|
58452
|
-
// the root serves `plugins/
|
|
58514
|
+
// the root serves `plugins/werkmeister`. `marketplace` must match the
|
|
58453
58515
|
// `name` field in that manifest, or install resolves nothing.
|
|
58454
58516
|
{
|
|
58455
|
-
name: "
|
|
58456
|
-
marketplace: "
|
|
58517
|
+
name: "werkmeister",
|
|
58518
|
+
marketplace: "werkmeister",
|
|
58457
58519
|
source: "jbbz-sandbox/werkmeister@main"
|
|
58458
58520
|
},
|
|
58459
58521
|
{
|
|
@@ -58462,6 +58524,11 @@ var init_machine_setup = __esm({
|
|
|
58462
58524
|
source: "DietrichGebert/ponytail"
|
|
58463
58525
|
}
|
|
58464
58526
|
];
|
|
58527
|
+
LEGACY_PLUGIN = {
|
|
58528
|
+
name: LEGACY_PLUGIN_NAME,
|
|
58529
|
+
marketplace: "sandbox",
|
|
58530
|
+
source: "jbbz-sandbox/werkmeister@main"
|
|
58531
|
+
};
|
|
58465
58532
|
OPTIONAL_PLUGINS = [
|
|
58466
58533
|
{
|
|
58467
58534
|
// Not obra/superpowers directly: that repo's manifest names itself
|
|
@@ -58495,7 +58562,7 @@ var init_machine_setup = __esm({
|
|
|
58495
58562
|
"services-fragment.schema.json": "**/.sandbox/services.yaml",
|
|
58496
58563
|
"workspace.schema.json": "**/.sandbox/workspace.yml"
|
|
58497
58564
|
};
|
|
58498
|
-
VSCODE_EXTENSION_ID = "jbbz.vscode
|
|
58565
|
+
VSCODE_EXTENSION_ID = "jbbz.werkmeister-vscode";
|
|
58499
58566
|
BUNDLED_VSIX_REL = path60.join("dist", "sandbox-workspaces.vsix");
|
|
58500
58567
|
}
|
|
58501
58568
|
});
|
|
@@ -58575,14 +58642,19 @@ function writeWorkspaceMcp(workspaceRoot, serverNames, definitions, vars2 = {})
|
|
|
58575
58642
|
delete servers[name];
|
|
58576
58643
|
}
|
|
58577
58644
|
}
|
|
58645
|
+
const legacy = servers[LEGACY_SERVER];
|
|
58646
|
+
if (legacy?.headers?.["X-Sandbox-Feature"] !== void 0)
|
|
58647
|
+
delete servers[LEGACY_SERVER];
|
|
58578
58648
|
Object.assign(servers, wanted);
|
|
58579
58649
|
fs53.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + "\n");
|
|
58580
58650
|
return mcpPath;
|
|
58581
58651
|
}
|
|
58652
|
+
var LEGACY_SERVER;
|
|
58582
58653
|
var init_mcp_gen = __esm({
|
|
58583
58654
|
"../../packages/sandbox-core/dist/mcp_gen.js"() {
|
|
58584
58655
|
"use strict";
|
|
58585
58656
|
init_define_SANDBOX_BUILD();
|
|
58657
|
+
LEGACY_SERVER = "sandbox";
|
|
58586
58658
|
}
|
|
58587
58659
|
});
|
|
58588
58660
|
|
|
@@ -63631,7 +63703,7 @@ import { execFileSync } from "node:child_process";
|
|
|
63631
63703
|
import * as fs21 from "node:fs";
|
|
63632
63704
|
import * as path22 from "node:path";
|
|
63633
63705
|
var BUILD_STAMP = typeof define_SANDBOX_BUILD_default === "undefined" ? void 0 : define_SANDBOX_BUILD_default;
|
|
63634
|
-
var REBUILD_COMMAND = "npm run build --workspace
|
|
63706
|
+
var REBUILD_COMMAND = "npm run build --workspace werkmeister-core && npm run build --workspace apps/cli";
|
|
63635
63707
|
function staleBuildWarning(build, repoRoot) {
|
|
63636
63708
|
if (!build?.sha || !fs21.existsSync(path22.join(repoRoot, ".git"))) return null;
|
|
63637
63709
|
let head;
|
|
@@ -64366,7 +64438,7 @@ ${_RED}Interrupted${_RESET}`));
|
|
|
64366
64438
|
for (const [name, description] of [
|
|
64367
64439
|
[
|
|
64368
64440
|
"dashboard",
|
|
64369
|
-
"Launch the workspace dashboard's MCP server over stdio (Claude Desktop, the
|
|
64441
|
+
"Launch the workspace dashboard's MCP server over stdio (Claude Desktop, the werkmeister plugin)"
|
|
64370
64442
|
],
|
|
64371
64443
|
[
|
|
64372
64444
|
"mcp",
|
package/dist/mcp.js
CHANGED
|
@@ -83141,6 +83141,11 @@ var READ_ONLY_GIT_RULES = [
|
|
|
83141
83141
|
"Bash(git status:*)",
|
|
83142
83142
|
"Bash(git ls-files:*)"
|
|
83143
83143
|
];
|
|
83144
|
+
var PLUGIN_MCP_PREFIXES = [
|
|
83145
|
+
"mcp__plugin_werkmeister_workspaces__",
|
|
83146
|
+
"mcp__plugin_sandbox-tools_sandbox-workspace__"
|
|
83147
|
+
];
|
|
83148
|
+
var pluginTool = (tool) => PLUGIN_MCP_PREFIXES.map((prefix) => `${prefix}${tool}`);
|
|
83144
83149
|
var AUTONOMOUS_RULES = [
|
|
83145
83150
|
"Bash(git:*)",
|
|
83146
83151
|
// `sandbox pr open` does the push and the PR; gh is read-only here.
|
|
@@ -83164,7 +83169,7 @@ var AUTONOMOUS_RULES = [
|
|
|
83164
83169
|
"workspace-prs",
|
|
83165
83170
|
"kube-context",
|
|
83166
83171
|
"k8s-forwards-status"
|
|
83167
|
-
].
|
|
83172
|
+
].flatMap(pluginTool)
|
|
83168
83173
|
];
|
|
83169
83174
|
function autonomousRules(feature2, services) {
|
|
83170
83175
|
if (!feature2)
|
|
@@ -83223,7 +83228,7 @@ var AUTONOMOUS_DENY = [
|
|
|
83223
83228
|
"claude-send",
|
|
83224
83229
|
"claude-resume",
|
|
83225
83230
|
"sandbox-connect"
|
|
83226
|
-
].
|
|
83231
|
+
].flatMap(pluginTool)
|
|
83227
83232
|
];
|
|
83228
83233
|
var permissionsRecord = (workspaceRoot) => path27.join(dotDir(workspaceRoot), "claude-permissions.json");
|
|
83229
83234
|
function buildAllowRules(feature2, services, servicesConfig, archetypes) {
|
|
@@ -85906,8 +85911,9 @@ init_config();
|
|
|
85906
85911
|
import * as fs39 from "node:fs";
|
|
85907
85912
|
import * as os11 from "node:os";
|
|
85908
85913
|
import * as path36 from "node:path";
|
|
85909
|
-
var PLUGIN_NAME = "
|
|
85910
|
-
var
|
|
85914
|
+
var PLUGIN_NAME = "werkmeister";
|
|
85915
|
+
var LEGACY_PLUGIN_NAME = "sandbox-tools";
|
|
85916
|
+
var REFRESH_HINT = "run `w9r setup` to refresh it so sessions pick up the current werkmeister ops skills";
|
|
85911
85917
|
function defaultRepoPluginDir() {
|
|
85912
85918
|
return path36.join(sandboxRoot(), "plugins", PLUGIN_NAME);
|
|
85913
85919
|
}
|
|
@@ -85936,13 +85942,13 @@ function loadRegistry(claudePluginsDir) {
|
|
|
85936
85942
|
const plugins = typeof data === "object" && data !== null && !Array.isArray(data) ? data["plugins"] : void 0;
|
|
85937
85943
|
return typeof plugins === "object" && plugins !== null && !Array.isArray(plugins) ? plugins : null;
|
|
85938
85944
|
}
|
|
85939
|
-
function installedPlugin(claudePluginsDir) {
|
|
85945
|
+
function installedPlugin(claudePluginsDir, name = PLUGIN_NAME) {
|
|
85940
85946
|
const plugins = loadRegistry(claudePluginsDir);
|
|
85941
85947
|
if (plugins === null) {
|
|
85942
85948
|
return [null, null];
|
|
85943
85949
|
}
|
|
85944
85950
|
for (const [key, entries] of Object.entries(plugins)) {
|
|
85945
|
-
if (!key.startsWith(`${
|
|
85951
|
+
if (!key.startsWith(`${name}@`) || !Array.isArray(entries)) {
|
|
85946
85952
|
continue;
|
|
85947
85953
|
}
|
|
85948
85954
|
for (const entry of entries) {
|
|
@@ -86024,8 +86030,13 @@ function pluginDriftWarnings(repoPluginDir, claudePluginsDir) {
|
|
|
86024
86030
|
}
|
|
86025
86031
|
const [installedVersion, installPath] = installedPlugin(claudePluginsDir);
|
|
86026
86032
|
if (installPath === null) {
|
|
86033
|
+
if (installedPlugin(claudePluginsDir, LEGACY_PLUGIN_NAME)[1] !== null) {
|
|
86034
|
+
return [
|
|
86035
|
+
`the ${LEGACY_PLUGIN_NAME} plugin was renamed ${PLUGIN_NAME}, and only the old one is installed \u2014 its skills are now ${PLUGIN_NAME}:diagnose, ${PLUGIN_NAME}:status, ${PLUGIN_NAME}:workspace, \u2026 Run \`w9r setup\` to switch over.`
|
|
86036
|
+
];
|
|
86037
|
+
}
|
|
86027
86038
|
return [
|
|
86028
|
-
`${PLUGIN_NAME} plugin is not installed \u2014 the
|
|
86039
|
+
`${PLUGIN_NAME} plugin is not installed \u2014 the ops skills (${PLUGIN_NAME}:diagnose, ${PLUGIN_NAME}:status, ${PLUGIN_NAME}:workspace, \u2026) will not surface in Claude Code sessions. Run \`w9r setup\` to install it (or use /plugin in Claude Code). The sb-* skills are unaffected \u2014 they are projected into each workspace by init-workspace.`
|
|
86029
86040
|
];
|
|
86030
86041
|
}
|
|
86031
86042
|
const drift = skillDrift(path36.join(repoPluginDir, "skills"), path36.join(installPath, "skills"));
|
|
@@ -86054,7 +86065,7 @@ import * as path37 from "node:path";
|
|
|
86054
86065
|
|
|
86055
86066
|
// ../../packages/sandbox-core/dist/scaffold.js
|
|
86056
86067
|
init_define_SANDBOX_BUILD();
|
|
86057
|
-
var SANDBOX_MCP_SERVER = "
|
|
86068
|
+
var SANDBOX_MCP_SERVER = "werkmeister";
|
|
86058
86069
|
var REGISTRY_DEFAULTS = {
|
|
86059
86070
|
archetypes: {
|
|
86060
86071
|
"node-web": {
|
|
@@ -86338,6 +86349,7 @@ var BUNDLED_VSIX_REL = path39.join("dist", "sandbox-workspaces.vsix");
|
|
|
86338
86349
|
init_define_SANDBOX_BUILD();
|
|
86339
86350
|
import * as fs42 from "node:fs";
|
|
86340
86351
|
import * as path40 from "node:path";
|
|
86352
|
+
var LEGACY_SERVER = "sandbox";
|
|
86341
86353
|
function resolveWorkspaceMcpServers(presentArchetypes2, archetypes) {
|
|
86342
86354
|
const names = /* @__PURE__ */ new Set();
|
|
86343
86355
|
for (const archName of Object.keys(presentArchetypes2)) {
|
|
@@ -86410,6 +86422,9 @@ function writeWorkspaceMcp(workspaceRoot, serverNames, definitions, vars2 = {})
|
|
|
86410
86422
|
delete servers[name];
|
|
86411
86423
|
}
|
|
86412
86424
|
}
|
|
86425
|
+
const legacy = servers[LEGACY_SERVER];
|
|
86426
|
+
if (legacy?.headers?.["X-Sandbox-Feature"] !== void 0)
|
|
86427
|
+
delete servers[LEGACY_SERVER];
|
|
86413
86428
|
Object.assign(servers, wanted);
|
|
86414
86429
|
fs42.writeFileSync(mcpPath, JSON.stringify(config2, null, 2) + "\n");
|
|
86415
86430
|
return mcpPath;
|
|
@@ -89075,7 +89090,7 @@ function registerTools(server) {
|
|
|
89075
89090
|
}
|
|
89076
89091
|
function registerLifecycleTools(server) {
|
|
89077
89092
|
server.registerTool(
|
|
89078
|
-
"
|
|
89093
|
+
"up",
|
|
89079
89094
|
{
|
|
89080
89095
|
title: "Bring a feature up",
|
|
89081
89096
|
description: "Allocate the feature's slot, start its containers, and point the reverse proxy at them. Returns the slot, port range, local services and their URLs.",
|
|
@@ -89087,10 +89102,10 @@ function registerLifecycleTools(server) {
|
|
|
89087
89102
|
})
|
|
89088
89103
|
);
|
|
89089
89104
|
server.registerTool(
|
|
89090
|
-
"
|
|
89105
|
+
"down",
|
|
89091
89106
|
{
|
|
89092
89107
|
title: "Tear a feature down",
|
|
89093
|
-
description: "Leave the feature's k8s intercepts, remove its containers, and release its slot. Does not reload the reverse proxy \u2014 call
|
|
89108
|
+
description: "Leave the feature's k8s intercepts, remove its containers, and release its slot. Does not reload the reverse proxy \u2014 call proxy-reload after tearing down.",
|
|
89094
89109
|
inputSchema: {
|
|
89095
89110
|
...FEATURE_ARG,
|
|
89096
89111
|
removeVolumes: external_exports.boolean().optional().describe("Also remove the feature's named volumes. Default false.")
|
|
@@ -89107,10 +89122,10 @@ function registerLifecycleTools(server) {
|
|
|
89107
89122
|
})
|
|
89108
89123
|
);
|
|
89109
89124
|
server.registerTool(
|
|
89110
|
-
"
|
|
89125
|
+
"stop",
|
|
89111
89126
|
{
|
|
89112
89127
|
title: "Stop a feature's containers",
|
|
89113
|
-
description: "Stop the containers, leaving them and the slot in place so
|
|
89128
|
+
description: "Stop the containers, leaving them and the slot in place so restart or up can resume the feature.",
|
|
89114
89129
|
inputSchema: { ...FEATURE_ARG }
|
|
89115
89130
|
},
|
|
89116
89131
|
async (args, extra) => adapt(async () => ({
|
|
@@ -89118,7 +89133,7 @@ function registerLifecycleTools(server) {
|
|
|
89118
89133
|
}))
|
|
89119
89134
|
);
|
|
89120
89135
|
server.registerTool(
|
|
89121
|
-
"
|
|
89136
|
+
"restart",
|
|
89122
89137
|
{
|
|
89123
89138
|
title: "Restart a feature's containers",
|
|
89124
89139
|
description: "Bounce the feature's containers, reusing its slot.",
|
|
@@ -89129,7 +89144,7 @@ function registerLifecycleTools(server) {
|
|
|
89129
89144
|
}))
|
|
89130
89145
|
);
|
|
89131
89146
|
server.registerTool(
|
|
89132
|
-
"
|
|
89147
|
+
"status",
|
|
89133
89148
|
{
|
|
89134
89149
|
title: "Sandbox status",
|
|
89135
89150
|
description: "Everything `sandbox status` knows: infrastructure containers, the host web servers, k8s forwards, every feature's slot and containers, and telepresence intercepts. Host-side, so the k8s forward health reported here is the real one.",
|
|
@@ -89141,7 +89156,7 @@ function registerLifecycleTools(server) {
|
|
|
89141
89156
|
}))
|
|
89142
89157
|
);
|
|
89143
89158
|
server.registerTool(
|
|
89144
|
-
"
|
|
89159
|
+
"detect",
|
|
89145
89160
|
{
|
|
89146
89161
|
title: "Generate a repo's service-registry fragment",
|
|
89147
89162
|
description: "Scan a repo (package manifests, Dockerfiles, compose, Helm, k8s, kustomize) and propose its .sandbox/services.yaml. Returns the report, the proposed YAML and the questions the scan could not settle. Writes only with write: true. Answer questions by passing `answers` ({ item: <question id>, value, reason, files_read }); answers can only fill those questions.",
|
|
@@ -89189,7 +89204,7 @@ function registerLifecycleTools(server) {
|
|
|
89189
89204
|
})
|
|
89190
89205
|
);
|
|
89191
89206
|
server.registerTool(
|
|
89192
|
-
"
|
|
89207
|
+
"services",
|
|
89193
89208
|
{
|
|
89194
89209
|
title: "Where a feature's services answer",
|
|
89195
89210
|
description: "Every registered service and its endpoint for this feature \u2014 local container, k8s forward, or not configured.",
|
|
@@ -89202,7 +89217,7 @@ function registerLifecycleTools(server) {
|
|
|
89202
89217
|
}))
|
|
89203
89218
|
);
|
|
89204
89219
|
server.registerTool(
|
|
89205
|
-
"
|
|
89220
|
+
"logs",
|
|
89206
89221
|
{
|
|
89207
89222
|
title: "Read a feature's container logs",
|
|
89208
89223
|
description: "A bounded read of `docker compose logs` for the feature, optionally one service. This is not a subscription: it never follows, and returns the last `tail` lines.",
|
|
@@ -89221,7 +89236,7 @@ function registerLifecycleTools(server) {
|
|
|
89221
89236
|
})
|
|
89222
89237
|
);
|
|
89223
89238
|
server.registerTool(
|
|
89224
|
-
"
|
|
89239
|
+
"remove",
|
|
89225
89240
|
{
|
|
89226
89241
|
title: "Drop a service from a feature",
|
|
89227
89242
|
description: "Remove one service from the feature's local services so it falls back to k8s: regenerate the workspace files, restart (or stop) the containers, re-point the proxy.",
|
|
@@ -89238,7 +89253,7 @@ function registerLifecycleTools(server) {
|
|
|
89238
89253
|
}))
|
|
89239
89254
|
);
|
|
89240
89255
|
server.registerTool(
|
|
89241
|
-
"
|
|
89256
|
+
"test",
|
|
89242
89257
|
{
|
|
89243
89258
|
title: "Run a feature's Playwright suite",
|
|
89244
89259
|
description: "Run the feature's Playwright tests with SANDBOX_FEATURE set, so the suite carries the X-Feature routing cookie. Runs only when the workspace has a Playwright config; otherwise nothing runs and `message` lists each service's test command and validation guidance. A failing suite is a result (non-zero `status`), not an error.",
|
|
@@ -89260,7 +89275,7 @@ function registerLifecycleTools(server) {
|
|
|
89260
89275
|
})
|
|
89261
89276
|
);
|
|
89262
89277
|
server.registerTool(
|
|
89263
|
-
"
|
|
89278
|
+
"proxy-reload",
|
|
89264
89279
|
{
|
|
89265
89280
|
title: "Regenerate and reload the reverse proxy",
|
|
89266
89281
|
description: "Rebuild the Caddyfile from the active features and hand it to Caddy, starting Caddy if it is down. Call this after tearing features down.",
|
|
@@ -89283,7 +89298,7 @@ var WORKSPACE_FIELDS = {
|
|
|
89283
89298
|
};
|
|
89284
89299
|
function registerAuthoringTools(server) {
|
|
89285
89300
|
server.registerTool(
|
|
89286
|
-
"
|
|
89301
|
+
"workspace",
|
|
89287
89302
|
{
|
|
89288
89303
|
title: "Create a sandbox workspace",
|
|
89289
89304
|
description: "Create a workspace: git worktrees on a <user>/<workspace> branch under the workspaces root, then init-workspace. Runs `createWorkspace` in this process; with an `issue_id` the issue is fetched and stored in `.sandbox/issue.md` (the create fails if it can't be read). Non-interactive \u2014 every wizard input is an argument here. Never opens VS Code.",
|
|
@@ -89302,7 +89317,7 @@ function registerAuthoringTools(server) {
|
|
|
89302
89317
|
})
|
|
89303
89318
|
);
|
|
89304
89319
|
server.registerTool(
|
|
89305
|
-
"
|
|
89320
|
+
"list-workspaces",
|
|
89306
89321
|
{
|
|
89307
89322
|
title: "List sandbox workspaces",
|
|
89308
89323
|
description: "Every workspace directory under the workspaces root, with its path, issue ID, labels and VS Code URI. Not scoped to a feature \u2014 this is the whole root, and it lists workspaces that were never brought up.",
|
|
@@ -89318,12 +89333,12 @@ function registerAuthoringTools(server) {
|
|
|
89318
89333
|
})
|
|
89319
89334
|
);
|
|
89320
89335
|
server.registerTool(
|
|
89321
|
-
"
|
|
89336
|
+
"close-out",
|
|
89322
89337
|
{
|
|
89323
89338
|
title: "End a workspace",
|
|
89324
89339
|
description: "The one way to end a workspace. After every PR shipped: close the issue, write closeout.md, commit and push every branch, tear the feature down, delete the workspace directory and the merged code branches. With `abandon` (a reason) when work is unshipped: record the reason, leave the issue, push and keep every branch, then remove. Destructive, and NOT scoped to your feature \u2014 it names a workspace. Nothing is deleted if any branch cannot be pushed.",
|
|
89325
89340
|
inputSchema: {
|
|
89326
|
-
name: external_exports.string().describe("Workspace directory name, as
|
|
89341
|
+
name: external_exports.string().describe("Workspace directory name, as list-workspaces reports it."),
|
|
89327
89342
|
abandon: external_exports.string().optional().describe(
|
|
89328
89343
|
"Close out without shipping: why the work is abandoned. Recorded in closeout.md and the PR files."
|
|
89329
89344
|
)
|
|
@@ -89342,7 +89357,7 @@ function registerAuthoringTools(server) {
|
|
|
89342
89357
|
})
|
|
89343
89358
|
);
|
|
89344
89359
|
server.registerTool(
|
|
89345
|
-
"
|
|
89360
|
+
"init-workspace",
|
|
89346
89361
|
{
|
|
89347
89362
|
title: "Reconcile a workspace",
|
|
89348
89363
|
description: `Re-run init-workspace against an existing workspace: reconcile worktrees, regenerate CLAUDE.md, .env, ${COMPOSE_FILE}, skills, agents, hooks and .mcp.json from .sandbox/workspace.yml plus any arguments given here.`,
|
|
@@ -89356,7 +89371,7 @@ function registerAuthoringTools(server) {
|
|
|
89356
89371
|
})
|
|
89357
89372
|
);
|
|
89358
89373
|
server.registerTool(
|
|
89359
|
-
"
|
|
89374
|
+
"skills",
|
|
89360
89375
|
{
|
|
89361
89376
|
title: "Check or sync a workspace's context layer",
|
|
89362
89377
|
description: "`check` reports drift between the workspace's context layer and a fresh rendering; `sync` rewrites what drifted. The layer is the workspace's `context_strategy` (jit: sb-* skills and gate manifest; icm: standards and stage contracts).",
|
|
@@ -89373,7 +89388,7 @@ function registerAuthoringTools(server) {
|
|
|
89373
89388
|
})
|
|
89374
89389
|
);
|
|
89375
89390
|
server.registerTool(
|
|
89376
|
-
"
|
|
89391
|
+
"standards",
|
|
89377
89392
|
{
|
|
89378
89393
|
title: "Validate the standards tree",
|
|
89379
89394
|
description: "Run every structural validator over the configured standards tree. Errors come back as data \u2014 an empty `errors` with a non-zero `moduleCount` is a clean tree.",
|
|
@@ -89382,7 +89397,7 @@ function registerAuthoringTools(server) {
|
|
|
89382
89397
|
async () => adapt(async () => ({ ...checkStandards() }))
|
|
89383
89398
|
);
|
|
89384
89399
|
server.registerTool(
|
|
89385
|
-
"
|
|
89400
|
+
"hooks",
|
|
89386
89401
|
{
|
|
89387
89402
|
title: "Refresh a workspace's context layer",
|
|
89388
89403
|
description: "Refresh the workspace's context layer the way `sandbox up` does: jit re-merges its SessionStart and PreToolUse hooks into .claude/settings.json; icm removes any sandbox-managed hooks. Never touches hooks it does not own.",
|
|
@@ -89397,7 +89412,7 @@ function registerAuthoringTools(server) {
|
|
|
89397
89412
|
})
|
|
89398
89413
|
);
|
|
89399
89414
|
server.registerTool(
|
|
89400
|
-
"
|
|
89415
|
+
"notes",
|
|
89401
89416
|
{
|
|
89402
89417
|
title: "Read or graduate a workspace's notes",
|
|
89403
89418
|
description: "`context` renders the session-start standards + notes block. `list` returns the workspace's notes. `graduate` scaffolds a decision note into a standards domain \u2014 domain and kind must be supplied, because the CLI's prompts are not available here.",
|
|
@@ -89444,7 +89459,7 @@ function registerAuthoringTools(server) {
|
|
|
89444
89459
|
}
|
|
89445
89460
|
function registerHostTools(server) {
|
|
89446
89461
|
server.registerTool(
|
|
89447
|
-
"
|
|
89462
|
+
"connect",
|
|
89448
89463
|
{
|
|
89449
89464
|
title: "Start shared infrastructure",
|
|
89450
89465
|
description: "Bring up the shared infra every feature depends on: generated proxy files, the corporate CA, the compose stack (caddy, k8s forwards, jaeger) and the host web servers. Host-wide, not scoped to your feature.",
|
|
@@ -89460,7 +89475,7 @@ function registerHostTools(server) {
|
|
|
89460
89475
|
})
|
|
89461
89476
|
);
|
|
89462
89477
|
server.registerTool(
|
|
89463
|
-
"
|
|
89478
|
+
"open",
|
|
89464
89479
|
{
|
|
89465
89480
|
title: "Open a feature-tagged browser window",
|
|
89466
89481
|
description: "Launch a browser window on the HOST, pre-configured with the feature's X-Feature routing cookie and tagged so it is unmistakably this feature's window. The window outlives this call; it closes when the user closes it.",
|
|
@@ -89500,7 +89515,7 @@ function registerHostTools(server) {
|
|
|
89500
89515
|
})
|
|
89501
89516
|
);
|
|
89502
89517
|
server.registerTool(
|
|
89503
|
-
"
|
|
89518
|
+
"intercept",
|
|
89504
89519
|
{
|
|
89505
89520
|
title: "Start or leave a k8s traffic intercept",
|
|
89506
89521
|
description: "Route the slice of live k8s dev traffic carrying `x-feature: <feature>` to this feature's local container, or stop doing so. Runs host-side, where the telepresence root daemon lives \u2014 with exactly the authority a host terminal has.",
|
|
@@ -89540,7 +89555,7 @@ function registerHostTools(server) {
|
|
|
89540
89555
|
|
|
89541
89556
|
// ../mcp/src/main.ts
|
|
89542
89557
|
function createServer2() {
|
|
89543
|
-
const server = new McpServer({ name: "
|
|
89558
|
+
const server = new McpServer({ name: "werkmeister", version: "0.1.0" });
|
|
89544
89559
|
registerTools(server);
|
|
89545
89560
|
return server;
|
|
89546
89561
|
}
|
|
Binary file
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"autonomous": {
|
|
27
27
|
"type": "boolean",
|
|
28
28
|
"default": false,
|
|
29
|
-
"description": "icm: run stage 01 to `sandbox pr open` with self-checks instead of human checks. Every strategy: add the Bash and
|
|
29
|
+
"description": "icm: run stage 01 to `sandbox pr open` with self-checks instead of human checks. Every strategy: add the Bash and werkmeister workspaces MCP allow rules a headless session needs to .claude/settings.json (recorded in .sandbox/claude-permissions.json, removed when this turns off)."
|
|
30
30
|
},
|
|
31
31
|
"model": {
|
|
32
32
|
"type": "string",
|
|
@@ -20,7 +20,7 @@ description: "Begin the test phase in a sandbox workspace. Use when running or w
|
|
|
20
20
|
assertions with suspected causes, and open questions.
|
|
21
21
|
- **Verifying the running feature.** The tester agents run a proxy smoke check (curl
|
|
22
22
|
through Caddy with the `X-Feature` cookie) when the containers are up. For a headed
|
|
23
|
-
browser session against the feature URL, use the `
|
|
23
|
+
browser session against the feature URL, use the `werkmeister:feature-test`
|
|
24
24
|
plugin skill; the URL and cookie are in `.sandbox/sandbox-context.md`. That applies to
|
|
25
25
|
URL-addressed services only; libraries, CLIs and extensions follow the "How to validate"
|
|
26
26
|
section of the same file.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "werkmeister",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "Multi-feature concurrent development orchestrator CLI tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"@types/node": "^22.13.0",
|
|
54
54
|
"commander": "^13.1.0",
|
|
55
55
|
"esbuild": "^0.24.0",
|
|
56
|
-
"
|
|
56
|
+
"werkmeister-core": "^0.15.0",
|
|
57
57
|
"tsx": "^4.19.0",
|
|
58
58
|
"typescript": "^5.7.0",
|
|
59
59
|
"vitest": "^3.0.0",
|
package/werkmeister
CHANGED
|
@@ -5,7 +5,7 @@ set -euo pipefail
|
|
|
5
5
|
|
|
6
6
|
# Load machine-global config exports (generated by `sandbox config` from
|
|
7
7
|
# ~/.sandbox/config.yaml) so the CLI inherits SANDBOX_* without a per-client env block.
|
|
8
|
-
# ~/.werkmeister wins when it exists, else ~/.sandbox (SW-7), same as
|
|
8
|
+
# ~/.werkmeister wins when it exists, else ~/.sandbox (SW-7), same as werkmeister-core's dotDir.
|
|
9
9
|
for d in .werkmeister .sandbox; do
|
|
10
10
|
if [ -d "$HOME/$d" ]; then
|
|
11
11
|
[ -f "$HOME/$d/env.sh" ] && . "$HOME/$d/env.sh"
|
|
@@ -74,7 +74,7 @@ fi
|
|
|
74
74
|
|
|
75
75
|
# `dashboard` and `mcp` are sibling apps, not CLI subcommands: each has its own
|
|
76
76
|
# dist/main.js. Both are launched here over stdio, which is what an MCP client
|
|
77
|
-
# (Claude Desktop, the
|
|
77
|
+
# (Claude Desktop, the werkmeister plugin) needs -- their HTTP modes are
|
|
78
78
|
# started by `sandbox connect` as managed WebApps, which execs those same
|
|
79
79
|
# entrypoints directly without --stdio. That is why neither verb takes a
|
|
80
80
|
# transport flag; extra args are still forwarded, so an explicit --stdio from an
|
|
@@ -85,7 +85,7 @@ fi
|
|
|
85
85
|
# package as dist/mcp.js (esbuild.mjs), so `mcp` always has a target. The
|
|
86
86
|
# dashboard (Jira, PRs, MCP Apps UI) is checkout-only; where it is missing its
|
|
87
87
|
# verb falls back to the headless server, which carries the same sandbox-*
|
|
88
|
-
# verbs, so the
|
|
88
|
+
# verbs, so the werkmeister plugin's `w9r dashboard` MCP entry keeps
|
|
89
89
|
# working on a package install instead of failing at every session start.
|
|
90
90
|
case "${1:-}" in
|
|
91
91
|
dashboard) app_dir="sandbox-dashboard" ;;
|