@opengsd/gsd-pi 1.1.1-dev.616a1a1 → 1.1.1-dev.74e8dd1
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/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +167 -16
- package/dist/resources/extensions/gsd/auto/phases.js +4 -3
- package/dist/resources/extensions/gsd/auto-dashboard.js +15 -4
- package/dist/resources/extensions/gsd/auto-dispatch.js +39 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +113 -7
- package/dist/resources/extensions/gsd/auto-prompts.js +9 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +4 -4
- package/dist/resources/extensions/gsd/auto-start.js +94 -15
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +2 -1
- package/dist/resources/extensions/gsd/auto.js +22 -4
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +79 -0
- package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +43 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +30 -9
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +16 -10
- package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +6 -2
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +7 -3
- package/dist/resources/extensions/gsd/commands-maintenance.js +172 -2
- package/dist/resources/extensions/gsd/commands-mcp-status.js +107 -59
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +3 -1
- package/dist/resources/extensions/gsd/commands-verdict.js +1 -1
- package/dist/resources/extensions/gsd/config-overlay.js +2 -1
- package/dist/resources/extensions/gsd/error-classifier.js +2 -1
- package/dist/resources/extensions/gsd/exec-sandbox.js +2 -0
- package/dist/resources/extensions/gsd/gsd-db.js +37 -4
- package/dist/resources/extensions/gsd/guided-flow.js +1 -1
- package/dist/resources/extensions/gsd/mcp-filter.js +3 -0
- package/dist/resources/extensions/gsd/mcp-project-config.js +67 -8
- package/dist/resources/extensions/gsd/migration-auto-check.js +2 -2
- package/dist/resources/extensions/gsd/prompts/run-uat.md +10 -4
- package/dist/resources/extensions/gsd/prompts/system.md +3 -1
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +3 -0
- package/dist/resources/extensions/gsd/skill-activation.js +20 -3
- package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +4 -2
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +1 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +18 -1
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +6 -0
- package/dist/resources/extensions/gsd/state.js +15 -12
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +120 -0
- package/dist/resources/extensions/gsd/tools/exec-tool.js +109 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -9
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +366 -3
- package/dist/resources/extensions/gsd/unit-context-manifest.js +8 -3
- package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
- package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +3 -1
- package/dist/resources/extensions/gsd/workflow-mcp.js +5 -1
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -0
- package/dist/resources/extensions/mcp-client/manager.js +31 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +4 -4
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +4 -4
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +2 -2
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/dist/workflow.d.ts +14 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +16 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +72 -31
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js +2 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-class-constants.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +82 -0
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +15 -0
- package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.js +15 -0
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +338 -17
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +412 -112
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/terminal.d.ts +1 -0
- package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal.js +8 -4
- package/packages/pi-tui/dist/terminal.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +196 -16
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +239 -63
- package/src/resources/extensions/gsd/auto/phases.ts +5 -3
- package/src/resources/extensions/gsd/auto-dashboard.ts +16 -4
- package/src/resources/extensions/gsd/auto-dispatch.ts +48 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +138 -7
- package/src/resources/extensions/gsd/auto-prompts.ts +9 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +4 -4
- package/src/resources/extensions/gsd/auto-start.ts +112 -17
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +2 -1
- package/src/resources/extensions/gsd/auto.ts +35 -3
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +86 -0
- package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +51 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +51 -14
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +21 -10
- package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +6 -2
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +7 -3
- package/src/resources/extensions/gsd/commands-maintenance.ts +197 -2
- package/src/resources/extensions/gsd/commands-mcp-status.ts +134 -57
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -1
- package/src/resources/extensions/gsd/commands-verdict.ts +1 -1
- package/src/resources/extensions/gsd/config-overlay.ts +3 -1
- package/src/resources/extensions/gsd/error-classifier.ts +2 -1
- package/src/resources/extensions/gsd/exec-sandbox.ts +4 -0
- package/src/resources/extensions/gsd/gsd-db.ts +41 -6
- package/src/resources/extensions/gsd/guided-flow.ts +1 -1
- package/src/resources/extensions/gsd/mcp-filter.ts +3 -0
- package/src/resources/extensions/gsd/mcp-project-config.ts +92 -10
- package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +10 -4
- package/src/resources/extensions/gsd/prompts/system.md +3 -1
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +3 -0
- package/src/resources/extensions/gsd/skill-activation.ts +20 -2
- package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +4 -2
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +1 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +20 -0
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +6 -0
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +1 -0
- package/src/resources/extensions/gsd/state.ts +16 -12
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +86 -0
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +143 -2
- package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +24 -2
- package/src/resources/extensions/gsd/tests/commands-dispatcher-validation-block.test.ts +38 -3
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +50 -13
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/exec-tool.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/gsd-rebuild.test.ts +199 -0
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +13 -6
- package/src/resources/extensions/gsd/tests/mcp-filter.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +177 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +54 -7
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +39 -1
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +18 -1
- package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +6 -2
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +84 -10
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +29 -6
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +29 -6
- package/src/resources/extensions/gsd/tests/validation-block-guard.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +17 -2
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +25 -0
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +167 -0
- package/src/resources/extensions/gsd/tools/exec-tool.ts +130 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +14 -9
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +440 -2
- package/src/resources/extensions/gsd/unit-context-manifest.ts +14 -5
- package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
- package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -1
- package/src/resources/extensions/gsd/workflow-mcp.ts +5 -1
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +26 -0
- package/src/resources/extensions/mcp-client/manager.ts +33 -1
- package/src/resources/extensions/mcp-client/tests/manager.test.ts +35 -0
- /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → eRWf-RI9bzbrwEurm_3uI}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{L9N5SPFi7f-Ne4u2uXzCe → eRWf-RI9bzbrwEurm_3uI}/_ssgManifest.js +0 -0
|
@@ -4,8 +4,11 @@
|
|
|
4
4
|
import assert from "node:assert/strict";
|
|
5
5
|
import test from "node:test";
|
|
6
6
|
|
|
7
|
+
import { registerToolCompatibility } from "@gsd/pi-coding-agent";
|
|
8
|
+
|
|
7
9
|
import { DISCUSS_TOOLS_ALLOWLIST } from "../constants.ts";
|
|
8
10
|
import { buildMinimalAutoGsdToolSet, buildMinimalGsdToolSet, buildMinimalGsdWorkflowToolSet, buildRequestScopedGsdToolSet, MINIMAL_AUTO_BASE_TOOL_NAMES, MINIMAL_GSD_TOOL_NAMES, requestHasGsdCustomType, restoreGsdWorkflowTools, scopeGsdWorkflowToolsForDispatch } from "../bootstrap/register-hooks.ts";
|
|
11
|
+
import { filterToolsForProvider } from "../model-router.ts";
|
|
9
12
|
import { applyUnitSkillVisibility } from "../skill-scope.ts";
|
|
10
13
|
|
|
11
14
|
test("buildMinimalGsdToolSet preserves non-GSD tools and replaces broad GSD surface", () => {
|
|
@@ -31,7 +34,7 @@ test("buildMinimalGsdToolSet preserves non-GSD tools and replaces broad GSD surf
|
|
|
31
34
|
for (const toolName of MINIMAL_GSD_TOOL_NAMES) {
|
|
32
35
|
assert.ok(result.includes(toolName), `expected ${toolName}`);
|
|
33
36
|
}
|
|
34
|
-
assert.ok(
|
|
37
|
+
assert.ok(result.includes("gsd_plan_milestone"));
|
|
35
38
|
assert.ok(!result.includes("gsd_task_complete"));
|
|
36
39
|
assert.ok(!result.includes("gsd_graph"));
|
|
37
40
|
});
|
|
@@ -98,22 +101,39 @@ test("buildMinimalAutoGsdToolSet keeps unit-specific completion tools without al
|
|
|
98
101
|
assert.ok(!result.includes("gsd_complete_slice"));
|
|
99
102
|
});
|
|
100
103
|
|
|
101
|
-
test("buildMinimalAutoGsdToolSet
|
|
102
|
-
|
|
103
|
-
// tools stay registered. run-uat must still get them: resolution reads the
|
|
104
|
-
// full registry, not just the (browser-stripped) active set.
|
|
105
|
-
const active = ["ask_user_questions", "bash", "read", "gsd_summary_save"];
|
|
104
|
+
test("buildMinimalAutoGsdToolSet scopes run-uat to UAT-specific tools", () => {
|
|
105
|
+
const active = ["ask_user_questions", "bash", "read", "edit", "write", "gsd_summary_save"];
|
|
106
106
|
const registered = [
|
|
107
107
|
...active,
|
|
108
|
+
"gsd_uat_exec",
|
|
109
|
+
"gsd_uat_result_save",
|
|
110
|
+
"gsd_resume",
|
|
111
|
+
"gsd_milestone_status",
|
|
112
|
+
"gsd_journal_query",
|
|
113
|
+
"gsd_exec",
|
|
114
|
+
"gsd_save_gate_result",
|
|
115
|
+
"search-the-web",
|
|
108
116
|
"browser_navigate",
|
|
109
117
|
"browser_click",
|
|
110
118
|
"browser_snapshot_refs",
|
|
111
|
-
"gsd_exec",
|
|
112
119
|
];
|
|
113
120
|
const result = buildMinimalAutoGsdToolSet(active, "run-uat", registered);
|
|
121
|
+
assert.ok(result.includes("gsd_uat_exec"));
|
|
122
|
+
assert.ok(result.includes("gsd_uat_result_save"));
|
|
123
|
+
assert.ok(result.includes("gsd_resume"));
|
|
124
|
+
assert.ok(result.includes("gsd_milestone_status"));
|
|
125
|
+
assert.ok(result.includes("gsd_journal_query"));
|
|
114
126
|
assert.ok(result.includes("browser_navigate"), "run-uat needs browser_navigate");
|
|
115
127
|
assert.ok(result.includes("browser_click"), "run-uat needs browser_click");
|
|
116
|
-
assert.ok(result.includes("
|
|
128
|
+
assert.ok(!result.includes("ToolSearch"));
|
|
129
|
+
assert.ok(!result.includes("bash"));
|
|
130
|
+
assert.ok(!result.includes("read"));
|
|
131
|
+
assert.ok(!result.includes("edit"));
|
|
132
|
+
assert.ok(!result.includes("write"));
|
|
133
|
+
assert.ok(!result.includes("gsd_exec"));
|
|
134
|
+
assert.ok(!result.includes("gsd_summary_save"));
|
|
135
|
+
assert.ok(!result.includes("gsd_save_gate_result"));
|
|
136
|
+
assert.ok(!result.includes("search-the-web"));
|
|
117
137
|
});
|
|
118
138
|
|
|
119
139
|
test("buildMinimalAutoGsdToolSet keeps only the auto base non-GSD tools", () => {
|
|
@@ -175,17 +195,27 @@ test("buildMinimalAutoGsdToolSet re-injects registered base tools filtered from
|
|
|
175
195
|
assert.ok(result.includes("search-the-web"));
|
|
176
196
|
});
|
|
177
197
|
|
|
178
|
-
test("buildMinimalAutoGsdToolSet preserves browser
|
|
198
|
+
test("buildMinimalAutoGsdToolSet preserves compatible browser add-ons for run-uat", () => {
|
|
179
199
|
const result = buildMinimalAutoGsdToolSet([
|
|
180
200
|
"bash",
|
|
181
201
|
"read",
|
|
202
|
+
"edit",
|
|
203
|
+
"write",
|
|
182
204
|
"browser_navigate",
|
|
183
205
|
"browser_click",
|
|
184
206
|
"browser_type",
|
|
185
207
|
"browser_assert",
|
|
186
208
|
"browser_screenshot",
|
|
187
209
|
"browser_wait_for",
|
|
210
|
+
"gsd_uat_exec",
|
|
211
|
+
"gsd_uat_result_save",
|
|
212
|
+
"gsd_resume",
|
|
213
|
+
"gsd_milestone_status",
|
|
214
|
+
"gsd_journal_query",
|
|
215
|
+
"subagent",
|
|
188
216
|
"gsd_summary_save",
|
|
217
|
+
"gsd_exec",
|
|
218
|
+
"gsd_save_gate_result",
|
|
189
219
|
"gsd_task_complete",
|
|
190
220
|
"memory_query",
|
|
191
221
|
"capture_thought",
|
|
@@ -197,7 +227,17 @@ test("buildMinimalAutoGsdToolSet preserves browser tools for run-uat", () => {
|
|
|
197
227
|
assert.ok(result.includes("browser_assert"));
|
|
198
228
|
assert.ok(result.includes("browser_screenshot"));
|
|
199
229
|
assert.ok(result.includes("browser_wait_for"));
|
|
200
|
-
assert.ok(result.includes("
|
|
230
|
+
assert.ok(result.includes("gsd_uat_exec"));
|
|
231
|
+
assert.ok(result.includes("gsd_uat_result_save"));
|
|
232
|
+
assert.ok(result.includes("subagent"));
|
|
233
|
+
assert.ok(!result.includes("ToolSearch"));
|
|
234
|
+
assert.ok(!result.includes("bash"));
|
|
235
|
+
assert.ok(!result.includes("read"));
|
|
236
|
+
assert.ok(!result.includes("edit"));
|
|
237
|
+
assert.ok(!result.includes("write"));
|
|
238
|
+
assert.ok(!result.includes("gsd_exec"));
|
|
239
|
+
assert.ok(!result.includes("gsd_summary_save"));
|
|
240
|
+
assert.ok(!result.includes("gsd_save_gate_result"));
|
|
201
241
|
assert.ok(!result.includes("gsd_task_complete"));
|
|
202
242
|
});
|
|
203
243
|
|
|
@@ -218,6 +258,40 @@ test("buildMinimalAutoGsdToolSet prefers MCP browser tools for run-uat when avai
|
|
|
218
258
|
assert.ok(!result.includes("browser_click"));
|
|
219
259
|
});
|
|
220
260
|
|
|
261
|
+
test("buildMinimalAutoGsdToolSet honors provider-compatible registered tools for run-uat", () => {
|
|
262
|
+
registerToolCompatibility("browser_screenshot", { producesImages: true });
|
|
263
|
+
const registered = [
|
|
264
|
+
"bash",
|
|
265
|
+
"read",
|
|
266
|
+
"ToolSearch",
|
|
267
|
+
"browser_navigate",
|
|
268
|
+
"browser_click",
|
|
269
|
+
"browser_screenshot",
|
|
270
|
+
"gsd_uat_exec",
|
|
271
|
+
"gsd_uat_result_save",
|
|
272
|
+
"gsd_resume",
|
|
273
|
+
"gsd_milestone_status",
|
|
274
|
+
"gsd_journal_query",
|
|
275
|
+
"gsd_exec",
|
|
276
|
+
"gsd_summary_save",
|
|
277
|
+
"gsd_save_gate_result",
|
|
278
|
+
];
|
|
279
|
+
const providerCompatible = filterToolsForProvider(registered, "openai-responses").compatible;
|
|
280
|
+
const result = buildMinimalAutoGsdToolSet(["gsd_uat_exec"], "run-uat", providerCompatible);
|
|
281
|
+
|
|
282
|
+
assert.ok(result.includes("gsd_uat_exec"));
|
|
283
|
+
assert.ok(result.includes("gsd_uat_result_save"));
|
|
284
|
+
assert.ok(result.includes("browser_navigate"));
|
|
285
|
+
assert.ok(result.includes("browser_click"));
|
|
286
|
+
assert.ok(!result.includes("browser_screenshot"), "provider-filtered screenshot tool must stay filtered");
|
|
287
|
+
assert.ok(!result.includes("ToolSearch"));
|
|
288
|
+
assert.ok(!result.includes("bash"));
|
|
289
|
+
assert.ok(!result.includes("read"));
|
|
290
|
+
assert.ok(!result.includes("gsd_exec"));
|
|
291
|
+
assert.ok(!result.includes("gsd_summary_save"));
|
|
292
|
+
assert.ok(!result.includes("gsd_save_gate_result"));
|
|
293
|
+
});
|
|
294
|
+
|
|
221
295
|
test("buildMinimalAutoGsdToolSet includes discuss-slice persistence tools", () => {
|
|
222
296
|
const result = buildMinimalAutoGsdToolSet([
|
|
223
297
|
"bash",
|
|
@@ -39,6 +39,12 @@ const RENAME_MAP: Array<{ canonical: string; alias: string }> = [
|
|
|
39
39
|
{ canonical: "gsd_milestone_reopen", alias: "gsd_reopen_milestone" },
|
|
40
40
|
];
|
|
41
41
|
|
|
42
|
+
const STANDALONE_TOOLS = [
|
|
43
|
+
"gsd_save_gate_result",
|
|
44
|
+
"gsd_skip_slice",
|
|
45
|
+
"gsd_uat_result_save",
|
|
46
|
+
];
|
|
47
|
+
|
|
42
48
|
// ─── Registration count ──────────────────────────────────────────────────────
|
|
43
49
|
|
|
44
50
|
console.log('\n── Tool naming: registration count ──');
|
|
@@ -48,10 +54,14 @@ registerDbTools(pi);
|
|
|
48
54
|
|
|
49
55
|
assert.deepStrictEqual(
|
|
50
56
|
pi.tools.length,
|
|
51
|
-
RENAME_MAP.length * 2 +
|
|
52
|
-
'Should register canonical/alias tool pairs plus
|
|
57
|
+
RENAME_MAP.length * 2 + STANDALONE_TOOLS.length,
|
|
58
|
+
'Should register canonical/alias tool pairs plus standalone DB tools',
|
|
53
59
|
);
|
|
54
60
|
|
|
61
|
+
for (const name of STANDALONE_TOOLS) {
|
|
62
|
+
assert.ok(pi.tools.some((t: any) => t.name === name), `Standalone tool "${name}" should be registered`);
|
|
63
|
+
}
|
|
64
|
+
|
|
55
65
|
// ─── Both names exist for each pair ──────────────────────────────────────────
|
|
56
66
|
|
|
57
67
|
console.log('\n── Tool naming: canonical and alias names exist ──');
|
|
@@ -7,12 +7,17 @@
|
|
|
7
7
|
|
|
8
8
|
import test from "node:test";
|
|
9
9
|
import assert from "node:assert/strict";
|
|
10
|
-
import { mkdirSync, rmSync } from "node:fs";
|
|
10
|
+
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import { tmpdir } from "node:os";
|
|
13
13
|
import { visibleWidth } from "@gsd/pi-tui";
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
_resetWidgetModeForTests,
|
|
17
|
+
setCompletionProgressWidget,
|
|
18
|
+
setWidgetMode,
|
|
19
|
+
updateProgressWidget,
|
|
20
|
+
} from "../auto-dashboard.ts";
|
|
16
21
|
import type { GSDState } from "../types.ts";
|
|
17
22
|
|
|
18
23
|
interface CapturedSetHeader {
|
|
@@ -143,10 +148,18 @@ test("updateProgressWidget gracefully no-ops when ctx.ui lacks setHeader/setStat
|
|
|
143
148
|
|
|
144
149
|
// ── NEXT-mode footer guidance ───────────────────────────────────────────
|
|
145
150
|
|
|
146
|
-
test("auto-dashboard widget render output includes /gsd next guidance when isStepMode is true", (t) => {
|
|
151
|
+
test("auto-dashboard full widget render output includes /gsd next guidance when isStepMode is true", (t) => {
|
|
147
152
|
const dir = makeTempDir("step-hint");
|
|
148
153
|
mkdirSync(join(dir, ".gsd"), { recursive: true });
|
|
149
|
-
|
|
154
|
+
const projectPrefsPath = join(dir, ".gsd", "preferences.md");
|
|
155
|
+
const globalPrefsPath = join(dir, ".gsd", "global-preferences.md");
|
|
156
|
+
writeFileSync(projectPrefsPath, "---\nversion: 1\n---\n", "utf-8");
|
|
157
|
+
_resetWidgetModeForTests();
|
|
158
|
+
setWidgetMode("full", projectPrefsPath, globalPrefsPath);
|
|
159
|
+
t.after(() => {
|
|
160
|
+
_resetWidgetModeForTests();
|
|
161
|
+
cleanup(dir);
|
|
162
|
+
});
|
|
150
163
|
|
|
151
164
|
let widgetFactory: ((tui: unknown, theme: unknown) => any) | undefined;
|
|
152
165
|
|
|
@@ -173,6 +186,7 @@ test("auto-dashboard widget render output includes /gsd next guidance when isSte
|
|
|
173
186
|
bold: (text: string) => text,
|
|
174
187
|
};
|
|
175
188
|
const component = widgetFactory!(fakeTui, fakeTheme);
|
|
189
|
+
t.after(() => component.dispose?.());
|
|
176
190
|
const lines = component.render(120);
|
|
177
191
|
|
|
178
192
|
const hasStepHint = lines.some((line: string) => line.includes("/gsd next to advance one step"));
|
|
@@ -181,10 +195,18 @@ test("auto-dashboard widget render output includes /gsd next guidance when isSte
|
|
|
181
195
|
if (component.dispose) component.dispose();
|
|
182
196
|
});
|
|
183
197
|
|
|
184
|
-
test("auto-dashboard widget render output omits /gsd next guidance when isStepMode is false", (t) => {
|
|
198
|
+
test("auto-dashboard full widget render output omits /gsd next guidance when isStepMode is false", (t) => {
|
|
185
199
|
const dir = makeTempDir("no-step-hint");
|
|
186
200
|
mkdirSync(join(dir, ".gsd"), { recursive: true });
|
|
187
|
-
|
|
201
|
+
const projectPrefsPath = join(dir, ".gsd", "preferences.md");
|
|
202
|
+
const globalPrefsPath = join(dir, ".gsd", "global-preferences.md");
|
|
203
|
+
writeFileSync(projectPrefsPath, "---\nversion: 1\n---\n", "utf-8");
|
|
204
|
+
_resetWidgetModeForTests();
|
|
205
|
+
setWidgetMode("full", projectPrefsPath, globalPrefsPath);
|
|
206
|
+
t.after(() => {
|
|
207
|
+
_resetWidgetModeForTests();
|
|
208
|
+
cleanup(dir);
|
|
209
|
+
});
|
|
188
210
|
|
|
189
211
|
let widgetFactory: ((tui: unknown, theme: unknown) => any) | undefined;
|
|
190
212
|
|
|
@@ -211,6 +233,7 @@ test("auto-dashboard widget render output omits /gsd next guidance when isStepMo
|
|
|
211
233
|
bold: (text: string) => text,
|
|
212
234
|
};
|
|
213
235
|
const component = widgetFactory!(fakeTui, fakeTheme);
|
|
236
|
+
t.after(() => component.dispose?.());
|
|
214
237
|
const lines = component.render(120);
|
|
215
238
|
|
|
216
239
|
const hasStepHint = lines.some((line: string) => line.includes("/gsd next to advance one step"));
|
|
@@ -344,6 +344,7 @@ test("#5843: run-uat uses verification tools policy so build/test commands can r
|
|
|
344
344
|
const manifest = UNIT_MANIFESTS["run-uat"];
|
|
345
345
|
|
|
346
346
|
assert.strictEqual(manifest.tools.mode, "verification");
|
|
347
|
+
assert.deepEqual(manifest.tools.allowedSubagents, ["mnemo", "scout", "reviewer", "tester"]);
|
|
347
348
|
|
|
348
349
|
const buildResult = shouldBlockPlanningUnit(
|
|
349
350
|
"bash",
|
|
@@ -367,6 +368,20 @@ test("#5843: run-uat uses verification tools policy so build/test commands can r
|
|
|
367
368
|
);
|
|
368
369
|
assert.strictEqual(sourceWriteResult.block, true);
|
|
369
370
|
assert.match(sourceWriteResult.reason!, /tools-policy "verification"/);
|
|
371
|
+
|
|
372
|
+
const subagentResult = shouldBlockPlanningUnit(
|
|
373
|
+
"subagent",
|
|
374
|
+
"",
|
|
375
|
+
process.cwd(),
|
|
376
|
+
"run-uat",
|
|
377
|
+
manifest.tools,
|
|
378
|
+
["mnemo"],
|
|
379
|
+
);
|
|
380
|
+
assert.strictEqual(
|
|
381
|
+
subagentResult.block,
|
|
382
|
+
false,
|
|
383
|
+
`run-uat must allow listed verification subagents: ${subagentResult.reason}`,
|
|
384
|
+
);
|
|
370
385
|
});
|
|
371
386
|
|
|
372
387
|
test("planning-dispatch hard block message omits internal tracker references", () => {
|
|
@@ -420,6 +435,11 @@ test('Unit Tool Contract exposes subagent dispatch permissions', () => {
|
|
|
420
435
|
allowedSubagents: ["reviewer", "security", "tester"],
|
|
421
436
|
toolsMode: "planning-dispatch",
|
|
422
437
|
});
|
|
438
|
+
assert.deepEqual(resolveSubagentPermissionContract("run-uat"), {
|
|
439
|
+
allowed: true,
|
|
440
|
+
allowedSubagents: ["mnemo", "scout", "reviewer", "tester"],
|
|
441
|
+
toolsMode: "verification",
|
|
442
|
+
});
|
|
423
443
|
assert.deepEqual(resolveSubagentPermissionContract("discuss-milestone"), {
|
|
424
444
|
allowed: false,
|
|
425
445
|
allowedSubagents: [],
|
|
@@ -427,21 +447,24 @@ test('Unit Tool Contract exposes subagent dispatch permissions', () => {
|
|
|
427
447
|
});
|
|
428
448
|
});
|
|
429
449
|
|
|
430
|
-
test('
|
|
450
|
+
test('dispatch-capable manifests declare globally allowed subagents', () => {
|
|
431
451
|
for (const [unitType, manifest] of Object.entries(UNIT_MANIFESTS)) {
|
|
432
|
-
|
|
452
|
+
const allowedSubagents = "allowedSubagents" in manifest.tools
|
|
453
|
+
? manifest.tools.allowedSubagents
|
|
454
|
+
: undefined;
|
|
455
|
+
if (!allowedSubagents) continue;
|
|
433
456
|
assert.ok(
|
|
434
|
-
Array.isArray(
|
|
435
|
-
`manifest "${unitType}"
|
|
457
|
+
Array.isArray(allowedSubagents) && allowedSubagents.length > 0,
|
|
458
|
+
`manifest "${unitType}" enables subagent dispatch but has no allowedSubagents — explicit allowlist is required for runtime dispatch gating`,
|
|
436
459
|
);
|
|
437
|
-
for (const agent of
|
|
460
|
+
for (const agent of allowedSubagents) {
|
|
438
461
|
assert.ok(
|
|
439
462
|
typeof agent === "string" && agent.length > 0,
|
|
440
463
|
`manifest "${unitType}" has empty/invalid allowedSubagents entry: ${JSON.stringify(agent)}`,
|
|
441
464
|
);
|
|
442
465
|
assert.ok(
|
|
443
466
|
ALLOWED_PLANNING_DISPATCH_AGENTS.has(agent),
|
|
444
|
-
`manifest "${unitType}" allows "${agent}", but the runtime
|
|
467
|
+
`manifest "${unitType}" allows "${agent}", but the runtime controlled-dispatch registry will hard-block it`,
|
|
445
468
|
);
|
|
446
469
|
}
|
|
447
470
|
}
|
|
@@ -54,6 +54,8 @@ test("validation block allows recovery, diagnostics, and unrelated commands", ()
|
|
|
54
54
|
"status",
|
|
55
55
|
"verdict pass --rationale ok",
|
|
56
56
|
"validate-milestone",
|
|
57
|
+
"dispatch reassess",
|
|
58
|
+
"dispatch reassess-roadmap",
|
|
57
59
|
"dispatch validate",
|
|
58
60
|
"dispatch validate-milestone",
|
|
59
61
|
"park M006",
|
|
@@ -122,3 +124,22 @@ test("validation block message includes attempted command and recovery options",
|
|
|
122
124
|
assert.match(message, /\/gsd verdict pass --rationale/);
|
|
123
125
|
assert.match(message, /\/gsd park M006/);
|
|
124
126
|
});
|
|
127
|
+
|
|
128
|
+
test("validation block message can guide remediation through dispatch reassess", () => {
|
|
129
|
+
const message = formatValidationBlockedMessage({
|
|
130
|
+
...blockedState(),
|
|
131
|
+
blockers: [
|
|
132
|
+
[
|
|
133
|
+
"Milestone M006 is blocked because milestone validation returned needs-remediation, but all slices are complete.",
|
|
134
|
+
"Fix options:",
|
|
135
|
+
"1. Run `/gsd dispatch reassess` to add remediation slices, then run `/gsd auto`",
|
|
136
|
+
"2. If the finding is acceptable, override it: `/gsd verdict pass --rationale \"why this is okay\"`",
|
|
137
|
+
"3. If this should wait, defer it explicitly: `/gsd park M006`",
|
|
138
|
+
].join("\n"),
|
|
139
|
+
],
|
|
140
|
+
}, "auto");
|
|
141
|
+
|
|
142
|
+
assert.ok(message);
|
|
143
|
+
assert.match(message, /\/gsd dispatch reassess/);
|
|
144
|
+
assert.doesNotMatch(message, /gsd_reassess_roadmap/);
|
|
145
|
+
});
|
|
@@ -19,6 +19,14 @@ test("shouldAutoPrepareWorkflowMcp enables prep for externalCli local transport"
|
|
|
19
19
|
assert.equal(result, true);
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
+
test("shouldAutoPrepareWorkflowMcp enables prep when Claude Code provider is known before auth mode settles", () => {
|
|
23
|
+
const result = shouldAutoPrepareWorkflowMcp({
|
|
24
|
+
model: { provider: "claude-code", baseUrl: "local://claude-code" },
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
assert.equal(result, true);
|
|
28
|
+
});
|
|
29
|
+
|
|
22
30
|
test("prepareWorkflowMcpForProject uses the selected unit model when session provider differs", (t) => {
|
|
23
31
|
const projectRoot = mkdtempSync(join(tmpdir(), "gsd-mcp-unit-model-"));
|
|
24
32
|
const notifications: Array<{ message: string; level: "info" | "warning" | "error" | "success" }> = [];
|
|
@@ -46,7 +54,7 @@ test("prepareWorkflowMcpForProject uses the selected unit model when session pro
|
|
|
46
54
|
|
|
47
55
|
assert.equal(result?.status, "created");
|
|
48
56
|
assert.equal(existsSync(join(projectRoot, ".mcp.json")), true);
|
|
49
|
-
assert.match(notifications.map((entry) => entry.message).join("\n"), /
|
|
57
|
+
assert.match(notifications.map((entry) => entry.message).join("\n"), /GSD MCP Server Prepared/);
|
|
50
58
|
});
|
|
51
59
|
|
|
52
60
|
test("shouldAutoPrepareWorkflowMcp stays disabled for non-Claude active provider even when claude-code is ready", () => {
|
|
@@ -163,7 +171,14 @@ test("before_agent_start auto-prepares project workflow MCP for Claude Code CLI"
|
|
|
163
171
|
};
|
|
164
172
|
assert.ok(parsed.mcpServers?.[GSD_WORKFLOW_MCP_SERVER_NAME]);
|
|
165
173
|
assert.ok(parsed.mcpServers?.[GSD_BROWSER_MCP_SERVER_NAME]);
|
|
166
|
-
|
|
174
|
+
const settings = JSON.parse(readFileSync(join(projectRoot, ".claude", "settings.local.json"), "utf-8")) as {
|
|
175
|
+
enabledMcpjsonServers?: string[];
|
|
176
|
+
};
|
|
177
|
+
assert.deepEqual(settings.enabledMcpjsonServers, [
|
|
178
|
+
GSD_WORKFLOW_MCP_SERVER_NAME,
|
|
179
|
+
GSD_BROWSER_MCP_SERVER_NAME,
|
|
180
|
+
]);
|
|
181
|
+
assert.match(notifications.join("\n"), /GSD MCP Server Prepared/);
|
|
167
182
|
});
|
|
168
183
|
|
|
169
184
|
test("before_agent_start returns discovered skill fallback without project .gsd", async (t) => {
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
executeSliceComplete,
|
|
31
31
|
executeSliceReopen,
|
|
32
32
|
executeValidateMilestone,
|
|
33
|
+
executeUatResultSave,
|
|
33
34
|
} from "../tools/workflow-tool-executors.ts";
|
|
34
35
|
|
|
35
36
|
function makeTmpBase(): string {
|
|
@@ -504,6 +505,88 @@ test("executePlanSlice marks validation failures with isError", async () => {
|
|
|
504
505
|
}
|
|
505
506
|
});
|
|
506
507
|
|
|
508
|
+
test("executeUatResultSave accepts gsd_uat_exec evidence written in a milestone worktree", async () => {
|
|
509
|
+
const base = makeTmpBase();
|
|
510
|
+
const worktree = join(base, ".gsd", "worktrees", "M001");
|
|
511
|
+
const worktreeExecDir = join(worktree, ".gsd", "exec");
|
|
512
|
+
const browserTimelineDir = join(base, ".artifacts", "browser", "session");
|
|
513
|
+
const evidenceId = "worktree-uat-evidence";
|
|
514
|
+
const browserTimelinePath = join(browserTimelineDir, "s02-uat-browser-timeline.json");
|
|
515
|
+
try {
|
|
516
|
+
openTestDb(base);
|
|
517
|
+
seedMilestone("M001", "Milestone One");
|
|
518
|
+
seedSlice("M001", "S02", "complete");
|
|
519
|
+
mkdirSync(worktreeExecDir, { recursive: true });
|
|
520
|
+
mkdirSync(browserTimelineDir, { recursive: true });
|
|
521
|
+
writeFileSync(browserTimelinePath, JSON.stringify({ summary: "browser timeline evidence" }), "utf-8");
|
|
522
|
+
writeFileSync(
|
|
523
|
+
join(worktreeExecDir, `${evidenceId}.meta.json`),
|
|
524
|
+
JSON.stringify({
|
|
525
|
+
id: evidenceId,
|
|
526
|
+
metadata: {
|
|
527
|
+
kind: "uat_exec",
|
|
528
|
+
milestoneId: "M001",
|
|
529
|
+
sliceId: "S02",
|
|
530
|
+
checkId: "UAT-01",
|
|
531
|
+
intent: "uat-runtime-check",
|
|
532
|
+
},
|
|
533
|
+
}),
|
|
534
|
+
"utf-8",
|
|
535
|
+
);
|
|
536
|
+
|
|
537
|
+
const result = await inProjectDir(worktree, () => executeUatResultSave({
|
|
538
|
+
milestoneId: "M001",
|
|
539
|
+
sliceId: "S02",
|
|
540
|
+
uatType: "runtime-executable",
|
|
541
|
+
verdict: "PASS",
|
|
542
|
+
checks: [{
|
|
543
|
+
id: "UAT-01",
|
|
544
|
+
description: "Runtime path C:\\tmp|uat evidence was captured in the active worktree",
|
|
545
|
+
mode: "runtime",
|
|
546
|
+
result: "PASS",
|
|
547
|
+
evidence: [
|
|
548
|
+
{ kind: "gsd_uat_exec", ref: evidenceId },
|
|
549
|
+
{ kind: "browser", ref: browserTimelinePath },
|
|
550
|
+
],
|
|
551
|
+
notes: "Worktree-local gsd_uat_exec metadata should resolve with backslash \\ and pipe |.",
|
|
552
|
+
}],
|
|
553
|
+
presentation: {
|
|
554
|
+
surface: "mcp",
|
|
555
|
+
presentedTools: [
|
|
556
|
+
"gsd_uat_exec",
|
|
557
|
+
"gsd_uat_result_save",
|
|
558
|
+
"gsd_resume",
|
|
559
|
+
"gsd_milestone_status",
|
|
560
|
+
"gsd_journal_query",
|
|
561
|
+
],
|
|
562
|
+
blockedTools: [
|
|
563
|
+
{ name: "gsd_exec", reason: "forbidden during run-uat" },
|
|
564
|
+
{ name: "gsd_summary_save", reason: "forbidden during run-uat" },
|
|
565
|
+
{ name: "gsd_save_gate_result", reason: "forbidden during run-uat" },
|
|
566
|
+
],
|
|
567
|
+
},
|
|
568
|
+
notes: "UAT passed with worktree-local evidence.",
|
|
569
|
+
}, worktree));
|
|
570
|
+
|
|
571
|
+
assert.equal(result.isError, undefined);
|
|
572
|
+
assert.equal(result.details.operation, "save_uat_result");
|
|
573
|
+
assert.equal(result.details.verdict, "PASS");
|
|
574
|
+
assert.ok(
|
|
575
|
+
existsSync(join(base, ".gsd", "uat", "M001", "S02", "attempt-1.json")),
|
|
576
|
+
"attempt JSON should be persisted under the authoritative project .gsd",
|
|
577
|
+
);
|
|
578
|
+
const assessment = readFileSync(
|
|
579
|
+
join(base, ".gsd", "milestones", "M001", "slices", "S02", "S02-ASSESSMENT.md"),
|
|
580
|
+
"utf-8",
|
|
581
|
+
);
|
|
582
|
+
assert.match(assessment, /Runtime path C:\\\\tmp\\\|uat evidence/);
|
|
583
|
+
assert.match(assessment, /backslash \\\\ and pipe \\\|/);
|
|
584
|
+
} finally {
|
|
585
|
+
closeDatabase();
|
|
586
|
+
cleanup(base);
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
|
|
507
590
|
test("executeSliceComplete coerces string enrichment entries and writes summary/UAT artifacts", async () => {
|
|
508
591
|
const base = makeTmpBase();
|
|
509
592
|
try {
|
|
@@ -27,6 +27,10 @@ const PLANNING_DISPATCH_REVIEW: ToolsPolicy = {
|
|
|
27
27
|
const READ_ONLY: ToolsPolicy = { mode: 'read-only' };
|
|
28
28
|
const ALL: ToolsPolicy = { mode: 'all' };
|
|
29
29
|
const VERIFICATION: ToolsPolicy = { mode: 'verification' };
|
|
30
|
+
const VERIFICATION_UAT: ToolsPolicy = {
|
|
31
|
+
mode: 'verification',
|
|
32
|
+
allowedSubagents: ['mnemo', 'scout', 'reviewer', 'tester'],
|
|
33
|
+
};
|
|
30
34
|
const DOCS: ToolsPolicy = {
|
|
31
35
|
mode: 'docs',
|
|
32
36
|
allowedPathGlobs: ['docs/**', 'README.md', 'README.*.md', 'CHANGELOG.md', '*.md'],
|
|
@@ -469,6 +473,27 @@ test('verification-mode: run-uat still blocks subagent dispatch', () => {
|
|
|
469
473
|
assert.match(r.reason!, /subagent dispatch is not permitted/);
|
|
470
474
|
});
|
|
471
475
|
|
|
476
|
+
test('verification-mode: run-uat allows explicit UAT specialist subagents', () => {
|
|
477
|
+
for (const agent of ['mnemo', 'scout', 'reviewer', 'tester']) {
|
|
478
|
+
const r = shouldBlockPlanningUnit('subagent', '', BASE, 'run-uat', VERIFICATION_UAT, [agent]);
|
|
479
|
+
assert.strictEqual(r.block, false, `expected ${agent} to be allowed: ${r.reason}`);
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
test('verification-mode: run-uat blocks implementation-tier subagents', () => {
|
|
484
|
+
const r = shouldBlockPlanningUnit('subagent', '', BASE, 'run-uat', VERIFICATION_UAT, ['worker']);
|
|
485
|
+
assert.strictEqual(r.block, true);
|
|
486
|
+
assert.match(r.reason!, /"worker"/);
|
|
487
|
+
assert.match(r.reason!, /read-only specialists/);
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
test('verification-mode: run-uat blocks read-only specialists not listed by policy', () => {
|
|
491
|
+
const r = shouldBlockPlanningUnit('subagent', '', BASE, 'run-uat', VERIFICATION_UAT, ['security']);
|
|
492
|
+
assert.strictEqual(r.block, true);
|
|
493
|
+
assert.match(r.reason!, /"security"/);
|
|
494
|
+
assert.match(r.reason!, /ToolsPolicy\.allowedSubagents|permitted agents for this unit/);
|
|
495
|
+
});
|
|
496
|
+
|
|
472
497
|
// ─── read-only mode ───────────────────────────────────────────────────────
|
|
473
498
|
|
|
474
499
|
test('read-only: blocks any edit even to .gsd/', () => {
|