@opengsd/gsd-pi 1.1.1-dev.9bb7453 → 1.1.1-dev.9f86580
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/browser-tools/engine/managed-gsd-browser.js +18 -2
- package/dist/resources/extensions/browser-tools/engine/selection.js +1 -1
- package/dist/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/dist/resources/extensions/browser-tools/index.js +29 -2
- package/dist/resources/extensions/browser-tools/web-app-detect.js +52 -0
- package/dist/resources/extensions/gsd/auto/phases.js +45 -3
- package/dist/resources/extensions/gsd/auto/session.js +2 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +21 -2
- package/dist/resources/extensions/gsd/auto-model-selection.js +26 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +4 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +3 -4
- package/dist/resources/extensions/gsd/auto-timers.js +24 -10
- package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +18 -66
- package/dist/resources/extensions/gsd/auto-worktree.js +18 -5
- package/dist/resources/extensions/gsd/auto.js +26 -4
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +16 -10
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +48 -29
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +18 -29
- package/dist/resources/extensions/gsd/closeout-consistency-gate.js +61 -0
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +10 -0
- package/dist/resources/extensions/gsd/commands-mcp-status.js +1 -1
- package/dist/resources/extensions/gsd/config-overlay.js +1 -0
- package/dist/resources/extensions/gsd/context-masker.js +129 -5
- package/dist/resources/extensions/gsd/guided-flow.js +93 -108
- package/dist/resources/extensions/gsd/milestone-closeout.js +3 -1
- package/dist/resources/extensions/gsd/pending-auto-start.js +0 -1
- package/dist/resources/extensions/gsd/planner-handoff.js +98 -0
- package/dist/resources/extensions/gsd/preferences-models.js +1 -0
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/run-uat.md +5 -19
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/recovery-classification.js +20 -0
- package/dist/resources/extensions/gsd/skill-manifest.js +12 -0
- package/dist/resources/extensions/gsd/tool-contract.js +6 -1
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +47 -7
- package/dist/resources/extensions/gsd/tools/complete-slice.js +28 -1
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +113 -8
- package/dist/resources/extensions/gsd/unit-tool-contracts.js +193 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +5 -78
- package/dist/resources/extensions/gsd/worktree-manager.js +26 -0
- package/dist/resources/extensions/gsd/worktree-reentry.js +96 -0
- package/dist/resources/extensions/shared/gsd-browser-cli.js +6 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
- 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 +5 -5
- 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 +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- 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/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +5 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +4 -3
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/agent-harness.js +3 -1
- package/packages/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
- package/packages/pi-agent-core/dist/harness/types.d.ts +1 -0
- package/packages/pi-agent-core/dist/harness/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/harness/types.js.map +1 -1
- package/packages/pi-agent-core/dist/types.d.ts +3 -1
- package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/types.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +157 -18
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +159 -36
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +8 -1
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js +2 -2
- package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit.js +3 -2
- package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/render-utils.js +6 -0
- package/packages/pi-coding-agent/dist/core/tools/render-utils.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/write.js +3 -2
- package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/scripts/install/handoff.js +16 -3
- package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +21 -2
- package/src/resources/extensions/browser-tools/engine/selection.ts +1 -1
- package/src/resources/extensions/browser-tools/extension-manifest.json +1 -1
- package/src/resources/extensions/browser-tools/index.ts +36 -5
- package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +2 -2
- package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +37 -0
- package/src/resources/extensions/browser-tools/tests/web-app-detect.test.mjs +68 -0
- package/src/resources/extensions/browser-tools/web-app-detect.ts +63 -0
- package/src/resources/extensions/gsd/auto/phases.ts +48 -6
- package/src/resources/extensions/gsd/auto/session.ts +2 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +48 -2
- package/src/resources/extensions/gsd/auto-model-selection.ts +26 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +4 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +3 -3
- package/src/resources/extensions/gsd/auto-timers.ts +25 -9
- package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +43 -74
- package/src/resources/extensions/gsd/auto-worktree.ts +23 -5
- package/src/resources/extensions/gsd/auto.ts +28 -4
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +16 -10
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +63 -29
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +50 -54
- package/src/resources/extensions/gsd/closeout-consistency-gate.ts +137 -0
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -0
- package/src/resources/extensions/gsd/commands-mcp-status.ts +1 -1
- package/src/resources/extensions/gsd/config-overlay.ts +1 -0
- package/src/resources/extensions/gsd/context-masker.ts +152 -5
- package/src/resources/extensions/gsd/guided-flow.ts +128 -135
- package/src/resources/extensions/gsd/milestone-closeout.ts +3 -1
- package/src/resources/extensions/gsd/pending-auto-start.ts +0 -2
- package/src/resources/extensions/gsd/planner-handoff.ts +149 -0
- package/src/resources/extensions/gsd/preferences-models.ts +1 -0
- package/src/resources/extensions/gsd/preferences-types.ts +8 -0
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/run-uat.md +5 -19
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/recovery-classification.ts +20 -0
- package/src/resources/extensions/gsd/skill-manifest.ts +12 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +66 -4
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +10 -2
- package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +4 -0
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/check-auto-start-pending-gate.test.ts +9 -15
- package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +26 -16
- package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +118 -0
- package/src/resources/extensions/gsd/tests/context-masker.test.ts +56 -1
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +40 -1
- package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +31 -79
- package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +40 -4
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/interrupted-session-auto.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +10 -1
- package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/planner-handoff.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +147 -5
- package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +77 -10
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +409 -0
- package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -0
- package/src/resources/extensions/gsd/tool-contract.ts +7 -1
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +82 -7
- package/src/resources/extensions/gsd/tools/complete-slice.ts +29 -1
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +146 -9
- package/src/resources/extensions/gsd/unit-tool-contracts.ts +210 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +5 -78
- package/src/resources/extensions/gsd/worktree-manager.ts +32 -0
- package/src/resources/extensions/gsd/worktree-reentry.ts +103 -0
- package/src/resources/extensions/shared/gsd-browser-cli.ts +6 -0
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +0 -246
- package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +0 -218
- /package/dist/web/standalone/.next/static/{jBtwT9v1u2lUA3UEOy_ZH → zzYMrKpPGfRQRxSFO32Jr}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{jBtwT9v1u2lUA3UEOy_ZH → zzYMrKpPGfRQRxSFO32Jr}/_ssgManifest.js +0 -0
|
@@ -114,6 +114,18 @@ const UNIT_TYPE_SKILL_MANIFEST = {
|
|
|
114
114
|
"review",
|
|
115
115
|
"accessibility",
|
|
116
116
|
],
|
|
117
|
+
// Slice closeout — the "closer" role: verify assembled task work, write the
|
|
118
|
+
// downstream-ready summary + UAT, optionally drive reviewer/security/tester
|
|
119
|
+
// subagents. Predictable skill set, mirrors `complete-milestone`.
|
|
120
|
+
"complete-slice": [
|
|
121
|
+
"verify-before-complete",
|
|
122
|
+
"test",
|
|
123
|
+
"review",
|
|
124
|
+
"security-review",
|
|
125
|
+
"write-docs",
|
|
126
|
+
"observability",
|
|
127
|
+
"handoff",
|
|
128
|
+
],
|
|
117
129
|
// `execute-task` intentionally omitted — implementation hot path covers a
|
|
118
130
|
// wide surface of technologies; wildcard fallback preserves today's
|
|
119
131
|
// behavior until per-task skill hints can be derived from task-plan
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
// File Purpose: ADR-015 Tool Contract module for Unit prompt, policy, and tool parity.
|
|
3
3
|
import { resolveManifest, } from "./unit-context-manifest.js";
|
|
4
4
|
import { getRequiredWorkflowToolsForAutoUnit } from "./workflow-mcp.js";
|
|
5
|
+
import { getUnitToolSurfaceContract } from "./unit-tool-contracts.js";
|
|
5
6
|
export function compileUnitToolContract(unitType) {
|
|
6
7
|
const manifest = resolveManifest(unitType);
|
|
8
|
+
const surfaceContract = getUnitToolSurfaceContract(unitType);
|
|
7
9
|
if (!manifest) {
|
|
8
10
|
return {
|
|
9
11
|
ok: false,
|
|
@@ -12,7 +14,9 @@ export function compileUnitToolContract(unitType) {
|
|
|
12
14
|
};
|
|
13
15
|
}
|
|
14
16
|
const requiredWorkflowTools = getRequiredWorkflowToolsForAutoUnit(unitType);
|
|
15
|
-
const
|
|
17
|
+
const forbiddenWorkflowTools = Object.entries(surfaceContract?.forbiddenGsdTools ?? {})
|
|
18
|
+
.map(([name, reason]) => ({ name, reason }));
|
|
19
|
+
const closeoutTools = requiredWorkflowTools.filter((tool) => /^gsd_(?:task|slice|milestone|complete|validate|save|summary|uat)/.test(tool));
|
|
16
20
|
if (requiresCloseoutTool(unitType) && closeoutTools.length === 0) {
|
|
17
21
|
return {
|
|
18
22
|
ok: false,
|
|
@@ -27,6 +31,7 @@ export function compileUnitToolContract(unitType) {
|
|
|
27
31
|
contextMode: manifest.contextMode,
|
|
28
32
|
toolsPolicy: manifest.tools,
|
|
29
33
|
requiredWorkflowTools,
|
|
34
|
+
forbiddenWorkflowTools,
|
|
30
35
|
promptObligations: [
|
|
31
36
|
`context-mode:${manifest.contextMode}`,
|
|
32
37
|
`tools-policy:${manifest.tools.mode}`,
|
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
// Project/App: gsd-pi
|
|
2
2
|
// File Purpose: Resolve phase-aware tool surfaces for GSD model presentations.
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
"gsd_uat_result_save",
|
|
6
|
-
"gsd_resume",
|
|
7
|
-
"gsd_milestone_status",
|
|
8
|
-
"gsd_journal_query",
|
|
9
|
-
];
|
|
3
|
+
import { RUN_UAT_BROWSER_TOOL_NAMES, RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_TOOL_PRESENTATION_PLAN_ID, RUN_UAT_WORKFLOW_TOOL_NAMES, } from "./unit-tool-contracts.js";
|
|
4
|
+
export { RUN_UAT_BROWSER_TOOL_NAMES, RUN_UAT_READ_ONLY_TOOL_NAMES, RUN_UAT_TOOL_PRESENTATION_PLAN_ID, RUN_UAT_WORKFLOW_TOOL_NAMES, } from "./unit-tool-contracts.js";
|
|
10
5
|
export const RUN_UAT_FORBIDDEN_TOOL_NAMES = [
|
|
11
6
|
"edit",
|
|
12
7
|
"write",
|
|
@@ -74,9 +69,54 @@ function addBlockedTool(blocked, name, reason) {
|
|
|
74
69
|
export function buildRunUatCanonicalToolNames(options = {}) {
|
|
75
70
|
return dedupe([
|
|
76
71
|
...RUN_UAT_WORKFLOW_TOOL_NAMES,
|
|
72
|
+
...RUN_UAT_READ_ONLY_TOOL_NAMES,
|
|
77
73
|
...(options.includeBrowserTools ?? []),
|
|
78
74
|
]);
|
|
79
75
|
}
|
|
76
|
+
// UAT modes whose run-uat instructions direct the runner to exercise the live
|
|
77
|
+
// app in a browser. These modes receive the browser tool surface so the runner
|
|
78
|
+
// can actually drive the page instead of silently deferring browser checks to a
|
|
79
|
+
// human. See run-uat.md automation rules: `browser-executable`, `live-runtime`,
|
|
80
|
+
// and `mixed` are all told to drive a browser/runtime path, and
|
|
81
|
+
// `human-experience` is told to capture screenshots. Without this, a webpage
|
|
82
|
+
// UAT classified as anything but `browser-executable` had no browser tools and
|
|
83
|
+
// downgraded its live checks to NEEDS-HUMAN (M001/S03 regression).
|
|
84
|
+
export const BROWSER_INCLUSIVE_UAT_TYPES = [
|
|
85
|
+
"browser-executable",
|
|
86
|
+
"live-runtime",
|
|
87
|
+
"mixed",
|
|
88
|
+
"human-experience",
|
|
89
|
+
];
|
|
90
|
+
function uatTypeIncludesBrowser(uatType) {
|
|
91
|
+
return uatType !== undefined && BROWSER_INCLUSIVE_UAT_TYPES.includes(uatType);
|
|
92
|
+
}
|
|
93
|
+
export function runUatBrowserToolsForType(uatType) {
|
|
94
|
+
return uatTypeIncludesBrowser(uatType) ? RUN_UAT_BROWSER_TOOL_NAMES : [];
|
|
95
|
+
}
|
|
96
|
+
export function runUatPresentationSurfaceForType(uatType) {
|
|
97
|
+
return uatTypeIncludesBrowser(uatType) ? "hybrid" : "mcp";
|
|
98
|
+
}
|
|
99
|
+
export function buildRunUatPresentationForType(uatType, options = {}) {
|
|
100
|
+
return buildRunUatResultPresentation({
|
|
101
|
+
...options,
|
|
102
|
+
surface: options.surface ?? runUatPresentationSurfaceForType(uatType),
|
|
103
|
+
includeBrowserTools: runUatBrowserToolsForType(uatType),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
export function buildRunUatResultPresentation(options = {}) {
|
|
107
|
+
const presentedTools = options.presentedTools
|
|
108
|
+
? dedupe(options.presentedTools)
|
|
109
|
+
: buildRunUatCanonicalToolNames({ includeBrowserTools: options.includeBrowserTools });
|
|
110
|
+
const blockedTools = RUN_UAT_FORBIDDEN_TOOL_NAMES
|
|
111
|
+
.filter((toolName) => !toolName.includes("*"))
|
|
112
|
+
.map((name) => ({ name, reason: "forbidden during run-uat" }));
|
|
113
|
+
return {
|
|
114
|
+
surface: options.surface ?? "mcp",
|
|
115
|
+
presentedTools,
|
|
116
|
+
blockedTools,
|
|
117
|
+
toolPresentationPlanId: RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
80
120
|
export function resolveToolPresentationPlan(options) {
|
|
81
121
|
const requested = options.requestedToolNames ?? (options.phase === "run-uat"
|
|
82
122
|
? buildRunUatCanonicalToolNames({ includeBrowserTools: options.includeBrowserTools })
|
|
@@ -17,7 +17,8 @@ import { getGatesForTurn } from "../gate-registry.js";
|
|
|
17
17
|
import { gsdProjectionRoot, clearPathCache, resolveMilestoneFile } from "../paths.js";
|
|
18
18
|
import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
|
|
19
19
|
import { checkOwnership, sliceUnitKey } from "../unit-ownership.js";
|
|
20
|
-
import { saveFile, clearParseCache } from "../files.js";
|
|
20
|
+
import { saveFile, clearParseCache, extractUatType } from "../files.js";
|
|
21
|
+
import { hasBrowserRequiredText } from "../browser-evidence.js";
|
|
21
22
|
import { invalidateStateCache } from "../state.js";
|
|
22
23
|
import { renderRoadmapFromDb } from "../markdown-renderer.js";
|
|
23
24
|
import { parseRoadmap } from "../parsers-legacy.js";
|
|
@@ -267,6 +268,32 @@ export async function handleCompleteSlice(params, basePath) {
|
|
|
267
268
|
if (BLOCKED_SIGNALS.test(params.verification || "") || BLOCKED_SIGNALS.test(params.uatContent || "")) {
|
|
268
269
|
return { error: `slice verification indicates blocked/failed state — do not complete a slice that has not passed verification. Address the blockers and re-verify first.` };
|
|
269
270
|
}
|
|
271
|
+
// ── Browser/web UAT classification gate ────────────────────────────────
|
|
272
|
+
// A UAT that drives a running web UI (opening a page in a browser,
|
|
273
|
+
// navigating to a page/localhost) must declare a browser-capable mode so the
|
|
274
|
+
// run-uat runner surfaces browser tools and actually launches a browser.
|
|
275
|
+
// Otherwise the browser checks get silently deferred to a human and the slice
|
|
276
|
+
// passes on static checks alone (M001/S03 regression). `browser-executable`,
|
|
277
|
+
// `live-runtime`, and `mixed` all receive browser tools (see
|
|
278
|
+
// BROWSER_INCLUSIVE_UAT_TYPES); only the non-browser modes are rejected here.
|
|
279
|
+
//
|
|
280
|
+
// Reuse the canonical hasBrowserRequiredText detector (also used by dispatch
|
|
281
|
+
// and milestone validation): it skips Not-Proven/Out-of-Scope disclaimer
|
|
282
|
+
// sections and only treats verbs like navigate/open as web when they sit next
|
|
283
|
+
// to browser/page/localhost — avoiding false positives on CLI/file/API steps.
|
|
284
|
+
//
|
|
285
|
+
// Only `artifact-driven` is gated. It is the one mode that performs no
|
|
286
|
+
// execution at all (static/file checks), so a browser-requiring UAT under it
|
|
287
|
+
// genuinely defers verification to a human. Every other mode has a real
|
|
288
|
+
// verification path: `runtime-executable` runs browser test commands like
|
|
289
|
+
// `npx playwright test` via gsd_uat_exec, and live-runtime/mixed/
|
|
290
|
+
// browser-executable receive browser tools (BROWSER_INCLUSIVE_UAT_TYPES).
|
|
291
|
+
const declaredUatMode = extractUatType(params.uatContent || "") ?? "artifact-driven";
|
|
292
|
+
if (declaredUatMode === "artifact-driven" && hasBrowserRequiredText(params.uatContent || "")) {
|
|
293
|
+
return {
|
|
294
|
+
error: `UAT requires browser verification (opening a page in a browser, navigating to a page or localhost, screenshots) but declares "UAT mode: artifact-driven", which only runs static/file checks and would defer the browser work to a human. Use a mode that actually verifies the UI: "browser-executable" (interactive browser tools), "runtime-executable" (a browser test command such as playwright), or a browser-inclusive "mixed"/"live-runtime". Re-author the UAT Type section and complete the slice again.`,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
270
297
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
271
298
|
const completedAt = new Date().toISOString();
|
|
272
299
|
let guardError = null;
|
|
@@ -6,8 +6,9 @@ import { loadWriteGateSnapshot, shouldBlockContextArtifactSaveInSnapshot, should
|
|
|
6
6
|
import { getActiveRequirements, insertMilestone, getMilestone, getSliceStatusSummary, getSliceTaskCounts, insertGateRun, readTransaction, saveGateResult, upsertQualityGate, } from "../gsd-db.js";
|
|
7
7
|
import { GATE_REGISTRY } from "../gate-registry.js";
|
|
8
8
|
import { generateRequirementsMd, saveArtifactToDb } from "../db-writer.js";
|
|
9
|
-
import { clearPathCache, resolveGsdPathContract, resolveMilestoneFile, resolveSliceFile } from "../paths.js";
|
|
9
|
+
import { clearPathCache, relSliceFile, resolveGsdPathContract, resolveMilestoneFile, resolveSliceFile } from "../paths.js";
|
|
10
10
|
import { saveFile, clearParseCache } from "../files.js";
|
|
11
|
+
import { buildManualValidationGuidance, resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
|
|
11
12
|
import { existsSync, readdirSync, readFileSync, unlinkSync } from "node:fs";
|
|
12
13
|
import { isAbsolute, join, resolve } from "node:path";
|
|
13
14
|
import { handleCompleteMilestone } from "./complete-milestone.js";
|
|
@@ -26,7 +27,7 @@ import { invalidateStateCache } from "../state.js";
|
|
|
26
27
|
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
27
28
|
import { parseProject } from "../schemas/parsers.js";
|
|
28
29
|
import { getAutoRuntimeSnapshot } from "../auto-runtime-state.js";
|
|
29
|
-
import { canonicalWorkflowToolName, parseMcpToolName, RUN_UAT_FORBIDDEN_TOOL_NAMES, RUN_UAT_WORKFLOW_TOOL_NAMES, } from "../tool-presentation-plan.js";
|
|
30
|
+
import { buildRunUatPresentationForType, canonicalWorkflowToolName, parseMcpToolName, RUN_UAT_FORBIDDEN_TOOL_NAMES, RUN_UAT_TOOL_PRESENTATION_PLAN_ID, RUN_UAT_WORKFLOW_TOOL_NAMES, } from "../tool-presentation-plan.js";
|
|
30
31
|
export const SUPPORTED_SUMMARY_ARTIFACT_TYPES = [
|
|
31
32
|
"SUMMARY",
|
|
32
33
|
"RESEARCH",
|
|
@@ -53,7 +54,7 @@ function blockIfWrongAutoUnit(requiredUnitType, operation) {
|
|
|
53
54
|
return null;
|
|
54
55
|
if (snapshot.currentUnit.type === requiredUnitType)
|
|
55
56
|
return null;
|
|
56
|
-
const error = `HARD BLOCK: ${operation} may only run from ${requiredUnitType}; active unit is ${snapshot.currentUnit.type}. The orchestrator owns phase transitions.`;
|
|
57
|
+
const error = `HARD BLOCK: Tool Contract failure: ${operation} may only run from ${requiredUnitType}; active unit is ${snapshot.currentUnit.type}. Fix unit-tool-contracts.ts or the active Unit prompt. The orchestrator owns phase transitions.`;
|
|
57
58
|
return {
|
|
58
59
|
content: [{ type: "text", text: error }],
|
|
59
60
|
details: { operation, error },
|
|
@@ -121,7 +122,11 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
|
|
|
121
122
|
if (rootArtifactGuard.block) {
|
|
122
123
|
return {
|
|
123
124
|
content: [{ type: "text", text: `Error saving artifact: ${rootArtifactGuard.reason ?? "root artifact write blocked"}` }],
|
|
124
|
-
details: {
|
|
125
|
+
details: {
|
|
126
|
+
operation: "save_summary",
|
|
127
|
+
error: "root_artifact_write_blocked",
|
|
128
|
+
displayReason: "Approval confirmation required before saving final project setup artifacts.",
|
|
129
|
+
},
|
|
125
130
|
isError: true,
|
|
126
131
|
};
|
|
127
132
|
}
|
|
@@ -129,7 +134,11 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
|
|
|
129
134
|
if (contextGuard.block) {
|
|
130
135
|
return {
|
|
131
136
|
content: [{ type: "text", text: `Error saving artifact: ${contextGuard.reason ?? "context write blocked"}` }],
|
|
132
|
-
details: {
|
|
137
|
+
details: {
|
|
138
|
+
operation: "save_summary",
|
|
139
|
+
error: "context_write_blocked",
|
|
140
|
+
displayReason: "Depth check required before writing milestone context.",
|
|
141
|
+
},
|
|
133
142
|
isError: true,
|
|
134
143
|
};
|
|
135
144
|
}
|
|
@@ -808,6 +817,52 @@ function errorResult(operation, message, error) {
|
|
|
808
817
|
function isNonEmptyString(value) {
|
|
809
818
|
return typeof value === "string" && value.trim().length > 0;
|
|
810
819
|
}
|
|
820
|
+
function mergeBlockedTools(current, canonical) {
|
|
821
|
+
const merged = new Map();
|
|
822
|
+
for (const entry of [...(current ?? []), ...canonical]) {
|
|
823
|
+
merged.set(canonicalWorkflowToolName(parseMcpToolName(entry.name)?.tool ?? entry.name), entry);
|
|
824
|
+
}
|
|
825
|
+
return [...merged.values()];
|
|
826
|
+
}
|
|
827
|
+
function mergePresentedTools(current, canonical) {
|
|
828
|
+
return [...new Set([...(current ?? []), ...canonical])];
|
|
829
|
+
}
|
|
830
|
+
function normalizeUatVerdict(params) {
|
|
831
|
+
const raw = params;
|
|
832
|
+
if (typeof raw.verdict === "string") {
|
|
833
|
+
return { ...params, verdict: raw.verdict.toUpperCase() };
|
|
834
|
+
}
|
|
835
|
+
return params;
|
|
836
|
+
}
|
|
837
|
+
function supplyDefaultPresentation(params) {
|
|
838
|
+
const raw = params;
|
|
839
|
+
if (!raw.presentation) {
|
|
840
|
+
return { ...params, presentation: buildRunUatPresentationForType(params.uatType) };
|
|
841
|
+
}
|
|
842
|
+
return params;
|
|
843
|
+
}
|
|
844
|
+
function mergeCanonicalPresentation(params) {
|
|
845
|
+
const canonicalPresentation = buildRunUatPresentationForType(params.uatType);
|
|
846
|
+
const providedPresentation = params.presentation;
|
|
847
|
+
return {
|
|
848
|
+
...params,
|
|
849
|
+
presentation: {
|
|
850
|
+
...providedPresentation,
|
|
851
|
+
surface: providedPresentation.surface ?? canonicalPresentation.surface,
|
|
852
|
+
presentedTools: mergePresentedTools(providedPresentation.presentedTools, canonicalPresentation.presentedTools),
|
|
853
|
+
blockedTools: mergeBlockedTools(providedPresentation.blockedTools, canonicalPresentation.blockedTools),
|
|
854
|
+
toolPresentationPlanId: RUN_UAT_TOOL_PRESENTATION_PLAN_ID,
|
|
855
|
+
},
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
const VALID_UAT_TYPES = [
|
|
859
|
+
"artifact-driven",
|
|
860
|
+
"browser-executable",
|
|
861
|
+
"runtime-executable",
|
|
862
|
+
"live-runtime",
|
|
863
|
+
"mixed",
|
|
864
|
+
"human-experience",
|
|
865
|
+
];
|
|
811
866
|
function ensureUatRequiredFields(params) {
|
|
812
867
|
if (!isNonEmptyString(params.milestoneId))
|
|
813
868
|
return "milestoneId is required";
|
|
@@ -815,6 +870,9 @@ function ensureUatRequiredFields(params) {
|
|
|
815
870
|
return "sliceId is required";
|
|
816
871
|
if (!isNonEmptyString(params.uatType))
|
|
817
872
|
return "uatType is required";
|
|
873
|
+
if (!VALID_UAT_TYPES.includes(params.uatType)) {
|
|
874
|
+
return `uatType must be one of: ${VALID_UAT_TYPES.join(", ")}`;
|
|
875
|
+
}
|
|
818
876
|
if (!["PASS", "FAIL", "PARTIAL"].includes(params.verdict))
|
|
819
877
|
return "verdict must be PASS, FAIL, or PARTIAL";
|
|
820
878
|
if (!Array.isArray(params.checks) || params.checks.length === 0)
|
|
@@ -951,6 +1009,12 @@ function validateUatChecks(basePath, params) {
|
|
|
951
1009
|
}
|
|
952
1010
|
return null;
|
|
953
1011
|
}
|
|
1012
|
+
function validateFreshUatOwnedEvidence(params) {
|
|
1013
|
+
const hasFreshUatEvidence = params.checks.some((check) => (check.evidence ?? []).some((evidence) => evidence.kind === "gsd_uat_exec"));
|
|
1014
|
+
return hasFreshUatEvidence
|
|
1015
|
+
? null
|
|
1016
|
+
: "UAT Assessment requires at least one fresh gsd_uat_exec evidence reference from run-uat";
|
|
1017
|
+
}
|
|
954
1018
|
function validateUatMode(params) {
|
|
955
1019
|
const modes = new Set(params.checks.map((check) => check.mode));
|
|
956
1020
|
const hasHuman = params.checks.some((check) => check.result === "NEEDS-HUMAN");
|
|
@@ -1043,7 +1107,7 @@ function escapeMarkdownTableCell(value) {
|
|
|
1043
1107
|
.replace(/[\\|]/g, (char) => `\\${char}`)
|
|
1044
1108
|
.replace(/\r?\n/g, "<br>");
|
|
1045
1109
|
}
|
|
1046
|
-
function renderUatAssessment(params, attempt, gateVerdict) {
|
|
1110
|
+
function renderUatAssessment(params, attempt, gateVerdict, basePath) {
|
|
1047
1111
|
const lines = [
|
|
1048
1112
|
"---",
|
|
1049
1113
|
`sliceId: ${params.sliceId}`,
|
|
@@ -1078,6 +1142,18 @@ function renderUatAssessment(params, attempt, gateVerdict) {
|
|
|
1078
1142
|
"",
|
|
1079
1143
|
`Aggregate UAT gate saved as ${gateVerdict}.`,
|
|
1080
1144
|
];
|
|
1145
|
+
// When any check still needs a human, point them at the exact checkout to
|
|
1146
|
+
// validate — critical for worktree milestones whose code sits under a hidden
|
|
1147
|
+
// `.gsd/worktrees/` path the reviewer would otherwise have to hunt for.
|
|
1148
|
+
const hasHuman = params.checks.some((check) => check.result === "NEEDS-HUMAN");
|
|
1149
|
+
if (hasHuman) {
|
|
1150
|
+
const guidance = buildManualValidationGuidance(basePath, params.milestoneId, {
|
|
1151
|
+
uatPath: relSliceFile(basePath, params.milestoneId, params.sliceId, "UAT"),
|
|
1152
|
+
});
|
|
1153
|
+
if (guidance) {
|
|
1154
|
+
lines.push("", "## Manual Validation", "", "One or more checks are marked `NEEDS-HUMAN` and require a person to validate:", "", ...guidance.split("\n").map((line) => `- ${line}`));
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1081
1157
|
return `${lines.join("\n")}\n`;
|
|
1082
1158
|
}
|
|
1083
1159
|
async function saveUatAttemptArtifact(basePath, params, attempt) {
|
|
@@ -1087,18 +1163,32 @@ async function saveUatAttemptArtifact(basePath, params, attempt) {
|
|
|
1087
1163
|
return relativePath;
|
|
1088
1164
|
}
|
|
1089
1165
|
export async function executeUatResultSave(params, basePath = process.cwd()) {
|
|
1166
|
+
const unitGuard = blockIfWrongAutoUnit("run-uat", "save_uat_result");
|
|
1167
|
+
if (unitGuard)
|
|
1168
|
+
return unitGuard;
|
|
1169
|
+
// Phase 1: normalize verdict and supply the canonical presentation when none was provided.
|
|
1170
|
+
params = normalizeUatVerdict(params);
|
|
1171
|
+
params = supplyDefaultPresentation(params);
|
|
1090
1172
|
const dbAvailable = await ensureDbOpen(basePath);
|
|
1091
1173
|
if (!dbAvailable)
|
|
1092
1174
|
return errorResult("save_uat_result", "GSD database is not available.", "db_unavailable");
|
|
1175
|
+
// Phase 2: validate the submitted presentation before the canonical merge so that
|
|
1176
|
+
// presentations missing required workflow tools are rejected rather than silently patched.
|
|
1093
1177
|
const requiredError = ensureUatRequiredFields(params);
|
|
1094
1178
|
if (requiredError)
|
|
1095
1179
|
return errorResult("save_uat_result", requiredError, "invalid_params");
|
|
1096
1180
|
const presentationError = validateCanonicalPresentation(params);
|
|
1097
1181
|
if (presentationError)
|
|
1098
1182
|
return errorResult("save_uat_result", presentationError, "alias_tool_name");
|
|
1183
|
+
// Phase 3: merge in the canonical plan ID and read-only audit tools so the persisted
|
|
1184
|
+
// artifact always carries the full audit surface even when the provider omitted them.
|
|
1185
|
+
params = mergeCanonicalPresentation(params);
|
|
1099
1186
|
const checkError = validateUatChecks(basePath, params);
|
|
1100
1187
|
if (checkError)
|
|
1101
1188
|
return errorResult("save_uat_result", checkError, "invalid_evidence");
|
|
1189
|
+
const freshEvidenceError = validateFreshUatOwnedEvidence(params);
|
|
1190
|
+
if (freshEvidenceError)
|
|
1191
|
+
return errorResult("save_uat_result", freshEvidenceError, "missing_fresh_uat_evidence");
|
|
1102
1192
|
const modeError = validateUatMode(params);
|
|
1103
1193
|
if (modeError)
|
|
1104
1194
|
return errorResult("save_uat_result", modeError, "uat_mode_mismatch");
|
|
@@ -1113,7 +1203,7 @@ export async function executeUatResultSave(params, basePath = process.cwd()) {
|
|
|
1113
1203
|
}
|
|
1114
1204
|
const gateVerdict = params.verdict === "PASS" ? "pass" : "flag";
|
|
1115
1205
|
const rationale = params.notes ?? `UAT ${params.verdict} for ${params.sliceId}.`;
|
|
1116
|
-
const assessment = renderUatAssessment(params, attempt, gateVerdict);
|
|
1206
|
+
const assessment = renderUatAssessment(params, attempt, gateVerdict, basePath);
|
|
1117
1207
|
const summary = await executeSummarySave({
|
|
1118
1208
|
milestone_id: params.milestoneId,
|
|
1119
1209
|
slice_id: params.sliceId,
|
|
@@ -1155,8 +1245,20 @@ export async function executeUatResultSave(params, basePath = process.cwd()) {
|
|
|
1155
1245
|
evaluatedAt,
|
|
1156
1246
|
});
|
|
1157
1247
|
invalidateStateCache();
|
|
1248
|
+
// Surface where to validate when checks are left for a human, so the path
|
|
1249
|
+
// (often a buried worktree checkout) reaches the reviewer, not just the file.
|
|
1250
|
+
const hasHuman = params.checks.some((check) => check.result === "NEEDS-HUMAN");
|
|
1251
|
+
const manualGuidance = hasHuman
|
|
1252
|
+
? buildManualValidationGuidance(basePath, params.milestoneId, {
|
|
1253
|
+
uatPath: relSliceFile(basePath, params.milestoneId, params.sliceId, "UAT"),
|
|
1254
|
+
})
|
|
1255
|
+
: null;
|
|
1256
|
+
const savedText = `UAT result saved for ${params.milestoneId}/${params.sliceId}: ${params.verdict}`;
|
|
1158
1257
|
return {
|
|
1159
|
-
content: [{
|
|
1258
|
+
content: [{
|
|
1259
|
+
type: "text",
|
|
1260
|
+
text: manualGuidance ? `${savedText}\n\nManual validation needed:\n${manualGuidance}` : savedText,
|
|
1261
|
+
}],
|
|
1160
1262
|
details: {
|
|
1161
1263
|
operation: "save_uat_result",
|
|
1162
1264
|
milestoneId: params.milestoneId,
|
|
@@ -1166,6 +1268,9 @@ export async function executeUatResultSave(params, basePath = process.cwd()) {
|
|
|
1166
1268
|
attempt,
|
|
1167
1269
|
attemptPath,
|
|
1168
1270
|
recommendedNextUnit: params.verdict === "PASS" ? null : "reactive-execute",
|
|
1271
|
+
...(hasHuman
|
|
1272
|
+
? { manualValidationPath: resolveCanonicalMilestoneRoot(basePath, params.milestoneId) }
|
|
1273
|
+
: {}),
|
|
1169
1274
|
},
|
|
1170
1275
|
};
|
|
1171
1276
|
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// Project/App: gsd-pi
|
|
2
|
+
// File Purpose: Central Unit-to-tool contracts for phase-aware GSD tool surfaces.
|
|
3
|
+
export const RUN_UAT_WORKFLOW_TOOL_NAMES = [
|
|
4
|
+
"gsd_uat_exec",
|
|
5
|
+
"gsd_uat_result_save",
|
|
6
|
+
"gsd_resume",
|
|
7
|
+
"gsd_milestone_status",
|
|
8
|
+
"gsd_journal_query",
|
|
9
|
+
];
|
|
10
|
+
export const RUN_UAT_READ_ONLY_TOOL_NAMES = [
|
|
11
|
+
"find",
|
|
12
|
+
"glob",
|
|
13
|
+
"grep",
|
|
14
|
+
"ls",
|
|
15
|
+
"read",
|
|
16
|
+
];
|
|
17
|
+
export const RUN_UAT_BROWSER_TOOL_NAMES = [
|
|
18
|
+
"browser_navigate",
|
|
19
|
+
"browser_click",
|
|
20
|
+
"browser_type",
|
|
21
|
+
"browser_fill_form",
|
|
22
|
+
"browser_click_ref",
|
|
23
|
+
"browser_fill_ref",
|
|
24
|
+
"browser_wait_for",
|
|
25
|
+
"browser_assert",
|
|
26
|
+
"browser_verify",
|
|
27
|
+
"browser_screenshot",
|
|
28
|
+
"browser_snapshot_refs",
|
|
29
|
+
"browser_find",
|
|
30
|
+
"browser_get_console_logs",
|
|
31
|
+
"browser_get_network_logs",
|
|
32
|
+
"browser_evaluate",
|
|
33
|
+
"browser_reload",
|
|
34
|
+
"browser_batch",
|
|
35
|
+
"browser_act",
|
|
36
|
+
];
|
|
37
|
+
export const RUN_UAT_TOOL_PRESENTATION_PLAN_ID = "run-uat/default-v1";
|
|
38
|
+
export const UNIT_TOOL_CONTRACTS = {
|
|
39
|
+
"research-milestone": {
|
|
40
|
+
allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
|
|
41
|
+
requiredWorkflowTools: ["gsd_summary_save"],
|
|
42
|
+
},
|
|
43
|
+
"plan-milestone": {
|
|
44
|
+
allowedGsdTools: [
|
|
45
|
+
"gsd_milestone_status",
|
|
46
|
+
"gsd_plan_milestone",
|
|
47
|
+
"gsd_plan_slice",
|
|
48
|
+
"gsd_decision_save",
|
|
49
|
+
"gsd_requirement_update",
|
|
50
|
+
],
|
|
51
|
+
requiredWorkflowTools: ["gsd_milestone_status", "gsd_plan_milestone", "gsd_plan_slice"],
|
|
52
|
+
},
|
|
53
|
+
"discuss-milestone": {
|
|
54
|
+
allowedGsdTools: [
|
|
55
|
+
"gsd_summary_save",
|
|
56
|
+
"gsd_decision_save",
|
|
57
|
+
"gsd_requirement_save",
|
|
58
|
+
"gsd_requirement_update",
|
|
59
|
+
"gsd_plan_milestone",
|
|
60
|
+
"gsd_milestone_generate_id",
|
|
61
|
+
],
|
|
62
|
+
requiredWorkflowTools: [
|
|
63
|
+
"gsd_summary_save",
|
|
64
|
+
"gsd_requirement_save",
|
|
65
|
+
"gsd_requirement_update",
|
|
66
|
+
"gsd_plan_milestone",
|
|
67
|
+
"gsd_milestone_generate_id",
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
"discuss-slice": {
|
|
71
|
+
allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
|
|
72
|
+
requiredWorkflowTools: ["gsd_summary_save"],
|
|
73
|
+
},
|
|
74
|
+
"validate-milestone": {
|
|
75
|
+
allowedGsdTools: ["gsd_milestone_status", "gsd_validate_milestone", "gsd_reassess_roadmap", "subagent"],
|
|
76
|
+
requiredWorkflowTools: ["gsd_milestone_status", "gsd_validate_milestone", "gsd_reassess_roadmap"],
|
|
77
|
+
},
|
|
78
|
+
"complete-milestone": {
|
|
79
|
+
allowedGsdTools: [
|
|
80
|
+
"gsd_milestone_status",
|
|
81
|
+
"gsd_requirement_update",
|
|
82
|
+
"gsd_summary_save",
|
|
83
|
+
"gsd_complete_milestone",
|
|
84
|
+
"subagent",
|
|
85
|
+
],
|
|
86
|
+
requiredWorkflowTools: [
|
|
87
|
+
"gsd_milestone_status",
|
|
88
|
+
"gsd_requirement_update",
|
|
89
|
+
"gsd_summary_save",
|
|
90
|
+
"gsd_complete_milestone",
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
"research-slice": {
|
|
94
|
+
allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
|
|
95
|
+
requiredWorkflowTools: ["gsd_summary_save"],
|
|
96
|
+
},
|
|
97
|
+
"plan-slice": {
|
|
98
|
+
allowedGsdTools: ["gsd_plan_slice", "gsd_reassess_roadmap", "gsd_decision_save"],
|
|
99
|
+
requiredWorkflowTools: ["gsd_plan_slice", "gsd_reassess_roadmap"],
|
|
100
|
+
},
|
|
101
|
+
"refine-slice": {
|
|
102
|
+
allowedGsdTools: ["gsd_plan_slice", "gsd_decision_save"],
|
|
103
|
+
requiredWorkflowTools: ["gsd_plan_slice"],
|
|
104
|
+
},
|
|
105
|
+
"replan-slice": {
|
|
106
|
+
allowedGsdTools: ["gsd_replan_slice", "gsd_decision_save"],
|
|
107
|
+
requiredWorkflowTools: ["gsd_replan_slice"],
|
|
108
|
+
},
|
|
109
|
+
"complete-slice": {
|
|
110
|
+
allowedGsdTools: [
|
|
111
|
+
"gsd_slice_complete",
|
|
112
|
+
"gsd_task_reopen",
|
|
113
|
+
"gsd_replan_slice",
|
|
114
|
+
"gsd_decision_save",
|
|
115
|
+
"gsd_requirement_update",
|
|
116
|
+
"gsd_summary_save",
|
|
117
|
+
"subagent",
|
|
118
|
+
],
|
|
119
|
+
requiredWorkflowTools: [
|
|
120
|
+
"gsd_slice_complete",
|
|
121
|
+
"gsd_task_reopen",
|
|
122
|
+
"gsd_replan_slice",
|
|
123
|
+
"gsd_requirement_update",
|
|
124
|
+
"gsd_summary_save",
|
|
125
|
+
],
|
|
126
|
+
forbiddenGsdTools: {
|
|
127
|
+
gsd_uat_result_save: "Run UAT owns persisted UAT Assessment.",
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
"reassess-roadmap": {
|
|
131
|
+
allowedGsdTools: ["gsd_milestone_status", "gsd_reassess_roadmap"],
|
|
132
|
+
requiredWorkflowTools: ["gsd_milestone_status", "gsd_reassess_roadmap"],
|
|
133
|
+
},
|
|
134
|
+
"execute-task": {
|
|
135
|
+
allowedGsdTools: ["gsd_task_complete", "gsd_decision_save"],
|
|
136
|
+
requiredWorkflowTools: ["gsd_task_complete"],
|
|
137
|
+
},
|
|
138
|
+
"execute-task-simple": {
|
|
139
|
+
allowedGsdTools: ["gsd_task_complete", "gsd_decision_save"],
|
|
140
|
+
requiredWorkflowTools: ["gsd_task_complete"],
|
|
141
|
+
},
|
|
142
|
+
"reactive-execute": {
|
|
143
|
+
allowedGsdTools: ["gsd_task_complete", "gsd_summary_save", "gsd_decision_save"],
|
|
144
|
+
requiredWorkflowTools: ["gsd_task_complete", "gsd_summary_save"],
|
|
145
|
+
},
|
|
146
|
+
"run-uat": {
|
|
147
|
+
allowedGsdTools: [...RUN_UAT_WORKFLOW_TOOL_NAMES, "subagent"],
|
|
148
|
+
requiredWorkflowTools: [...RUN_UAT_WORKFLOW_TOOL_NAMES],
|
|
149
|
+
forbiddenGsdTools: {
|
|
150
|
+
gsd_exec: "Use gsd_uat_exec so acceptance evidence is typed as UAT-owned.",
|
|
151
|
+
gsd_save_gate_result: "gsd_uat_result_save owns the aggregate UAT gate.",
|
|
152
|
+
gsd_summary_save: "gsd_uat_result_save owns persisted UAT Assessment writes.",
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
"gate-evaluate": {
|
|
156
|
+
allowedGsdTools: ["gsd_save_gate_result"],
|
|
157
|
+
requiredWorkflowTools: ["gsd_save_gate_result"],
|
|
158
|
+
},
|
|
159
|
+
"rewrite-docs": {
|
|
160
|
+
allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
|
|
161
|
+
requiredWorkflowTools: [],
|
|
162
|
+
},
|
|
163
|
+
"workflow-preferences": {
|
|
164
|
+
allowedGsdTools: ["gsd_summary_save"],
|
|
165
|
+
requiredWorkflowTools: [],
|
|
166
|
+
},
|
|
167
|
+
"discuss-project": {
|
|
168
|
+
allowedGsdTools: ["gsd_summary_save", "gsd_decision_save", "gsd_requirement_save"],
|
|
169
|
+
requiredWorkflowTools: ["ask_user_questions", "gsd_summary_save"],
|
|
170
|
+
},
|
|
171
|
+
"discuss-requirements": {
|
|
172
|
+
allowedGsdTools: ["gsd_requirement_save", "gsd_summary_save"],
|
|
173
|
+
requiredWorkflowTools: ["ask_user_questions", "gsd_requirement_save", "gsd_summary_save"],
|
|
174
|
+
},
|
|
175
|
+
"research-decision": {
|
|
176
|
+
allowedGsdTools: ["gsd_summary_save"],
|
|
177
|
+
requiredWorkflowTools: ["ask_user_questions"],
|
|
178
|
+
},
|
|
179
|
+
"research-project": {
|
|
180
|
+
allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
|
|
181
|
+
requiredWorkflowTools: [],
|
|
182
|
+
},
|
|
183
|
+
};
|
|
184
|
+
export const AUTO_UNIT_SCOPED_TOOLS = Object.fromEntries(Object.entries(UNIT_TOOL_CONTRACTS).map(([unitType, contract]) => [unitType, contract.allowedGsdTools]));
|
|
185
|
+
export function getUnitToolSurfaceContract(unitType) {
|
|
186
|
+
return UNIT_TOOL_CONTRACTS[unitType];
|
|
187
|
+
}
|
|
188
|
+
export function getRequiredWorkflowToolsForUnit(unitType) {
|
|
189
|
+
return [...(UNIT_TOOL_CONTRACTS[unitType]?.requiredWorkflowTools ?? [])];
|
|
190
|
+
}
|
|
191
|
+
export function getForbiddenGsdToolReason(unitType, toolName) {
|
|
192
|
+
return UNIT_TOOL_CONTRACTS[unitType]?.forbiddenGsdTools?.[toolName];
|
|
193
|
+
}
|