@opengsd/gsd-pi 1.9.0 → 1.10.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/README.md +10 -10
- package/dist/headless.js +2 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +2 -2
- package/dist/resources/extensions/gsd/artifact-verification.js +3 -4
- package/dist/resources/extensions/gsd/auto/loop.js +24 -4
- package/dist/resources/extensions/gsd/auto/run-unit.js +19 -1
- package/dist/resources/extensions/gsd/auto/unit-phase.js +37 -5
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +14 -8
- package/dist/resources/extensions/gsd/auto-dispatch.js +2 -0
- package/dist/resources/extensions/gsd/auto-prompts.js +102 -21
- package/dist/resources/extensions/gsd/auto-recovery.js +10 -5
- package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -5
- package/dist/resources/extensions/gsd/auto-start.js +29 -9
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +40 -0
- package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +7 -3
- package/dist/resources/extensions/gsd/auto-worktree-teardown.js +1 -1
- package/dist/resources/extensions/gsd/auto.js +15 -5
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +2 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +33 -7
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +10 -3
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +4 -24
- package/dist/resources/extensions/gsd/commands-verdict.js +10 -9
- package/dist/resources/extensions/gsd/compat/compat-marker.js +80 -5
- package/dist/resources/extensions/gsd/constants.js +12 -13
- package/dist/resources/extensions/gsd/context-masker.js +97 -21
- package/dist/resources/extensions/gsd/db/engine.js +5 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +22 -0
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +24 -8
- package/dist/resources/extensions/gsd/error-classifier.js +12 -2
- package/dist/resources/extensions/gsd/exec-sandbox.js +1 -0
- package/dist/resources/extensions/gsd/flat-phase-migration.js +12 -0
- package/dist/resources/extensions/gsd/git-service.js +19 -7
- package/dist/resources/extensions/gsd/gsd-db.js +75 -31
- package/dist/resources/extensions/gsd/guided-flow.js +11 -5
- package/dist/resources/extensions/gsd/markdown-renderer.js +5 -21
- package/dist/resources/extensions/gsd/md-importer.js +5 -6
- package/dist/resources/extensions/gsd/model-cost-table.js +2 -0
- package/dist/resources/extensions/gsd/model-router.js +11 -0
- package/dist/resources/extensions/gsd/paths.js +66 -15
- package/dist/resources/extensions/gsd/planning-subagent-policy.js +37 -0
- package/dist/resources/extensions/gsd/planning-subagent-registry.js +25 -0
- package/dist/resources/extensions/gsd/preferences-types.js +5 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +48 -1
- package/dist/resources/extensions/gsd/preferences.js +17 -0
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
- package/dist/resources/extensions/gsd/provider-payload-policy.js +16 -5
- package/dist/resources/extensions/gsd/safety/destructive-guard.js +1 -1
- package/dist/resources/extensions/gsd/skill-activation.js +17 -3
- package/dist/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.js +98 -2
- package/dist/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.js +4 -1
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +5 -2
- package/dist/resources/extensions/gsd/stop-notice.js +9 -0
- package/dist/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
- package/dist/resources/extensions/gsd/tools/complete-task.js +12 -5
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +14 -5
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +15 -5
- package/dist/resources/extensions/gsd/tools/reopen-task.js +16 -10
- package/dist/resources/extensions/gsd/unit-context-composer.js +28 -5
- package/dist/resources/extensions/gsd/workflow-projections.js +2 -3
- package/dist/resources/extensions/gsd/workspace.js +2 -1
- package/dist/resources/extensions/gsd/worktree-state-projection.js +20 -18
- package/dist/resources/extensions/shared/interview-ui.js +43 -6
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- 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 +8 -8
- package/dist/web/standalone/.next/server/chunks/1991.js +2 -2
- package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
- 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/node_modules/@gsd/native/package.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +1 -1
- package/integrations/hermes/pyproject.toml +1 -1
- package/package.json +7 -6
- 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/dist/compaction/compaction.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/compaction/compaction.js +36 -4
- package/packages/gsd-agent-core/dist/compaction/compaction.js.map +1 -1
- package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
- package/packages/gsd-agent-core/dist/sdk.js +1 -0
- package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/gsd-cloud/README.md +9 -3
- package/packages/gsd-cloud/dist/background-cli.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/background-cli.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/background-cli.test.js +248 -0
- package/packages/gsd-cloud/dist/background-cli.test.js.map +1 -0
- package/packages/gsd-cloud/dist/cli.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cli.js +121 -15
- package/packages/gsd-cloud/dist/cli.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-config.d.ts +1 -1
- package/packages/gsd-cloud/dist/cloud-config.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cloud-config.js +7 -1
- package/packages/gsd-cloud/dist/cloud-config.js.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts +1 -3
- package/packages/gsd-cloud/dist/cloud-runtime.d.ts.map +1 -1
- package/packages/gsd-cloud/dist/cloud-runtime.js +9 -7
- package/packages/gsd-cloud/dist/cloud-runtime.js.map +1 -1
- package/packages/gsd-cloud/dist/runtime-process.d.ts +27 -0
- package/packages/gsd-cloud/dist/runtime-process.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.js +272 -0
- package/packages/gsd-cloud/dist/runtime-process.js.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.test.d.ts +2 -0
- package/packages/gsd-cloud/dist/runtime-process.test.d.ts.map +1 -0
- package/packages/gsd-cloud/dist/runtime-process.test.js +97 -0
- package/packages/gsd-cloud/dist/runtime-process.test.js.map +1 -0
- package/packages/gsd-cloud/package.json +2 -2
- package/packages/mcp-server/README.md +7 -2
- package/packages/mcp-server/dist/cli-runner.d.ts +3 -0
- package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -1
- package/packages/mcp-server/dist/cli-runner.js +119 -33
- package/packages/mcp-server/dist/cli-runner.js.map +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +5 -5
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts +4 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +5 -1
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +2 -0
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +76 -0
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +70 -0
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +6 -1
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-completions.js +103 -0
- package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js +1 -1
- package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -1
- package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +11 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +54 -0
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +2 -2
- package/src/resources/extensions/gsd/artifact-verification.ts +3 -8
- package/src/resources/extensions/gsd/auto/loop.ts +48 -4
- package/src/resources/extensions/gsd/auto/run-unit.ts +20 -1
- package/src/resources/extensions/gsd/auto/unit-phase.ts +41 -5
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +14 -7
- package/src/resources/extensions/gsd/auto-dispatch.ts +1 -0
- package/src/resources/extensions/gsd/auto-prompts.ts +118 -19
- package/src/resources/extensions/gsd/auto-recovery.ts +10 -8
- package/src/resources/extensions/gsd/auto-runtime-state.ts +12 -7
- package/src/resources/extensions/gsd/auto-start.ts +31 -8
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +56 -0
- package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +4 -0
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +10 -3
- package/src/resources/extensions/gsd/auto-worktree-teardown.ts +1 -1
- package/src/resources/extensions/gsd/auto.ts +20 -7
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +1 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +41 -12
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +11 -3
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +7 -29
- package/src/resources/extensions/gsd/commands-verdict.ts +16 -9
- package/src/resources/extensions/gsd/compat/compat-marker.ts +99 -5
- package/src/resources/extensions/gsd/constants.ts +14 -13
- package/src/resources/extensions/gsd/context-masker.ts +98 -2
- package/src/resources/extensions/gsd/db/engine.ts +5 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +22 -0
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +30 -7
- package/src/resources/extensions/gsd/error-classifier.ts +13 -2
- package/src/resources/extensions/gsd/exec-sandbox.ts +1 -0
- package/src/resources/extensions/gsd/flat-phase-migration.ts +14 -0
- package/src/resources/extensions/gsd/git-service.ts +19 -6
- package/src/resources/extensions/gsd/gsd-db.ts +85 -33
- package/src/resources/extensions/gsd/guided-flow.ts +11 -4
- package/src/resources/extensions/gsd/markdown-renderer.ts +5 -23
- package/src/resources/extensions/gsd/md-importer.ts +5 -5
- package/src/resources/extensions/gsd/model-cost-table.ts +2 -0
- package/src/resources/extensions/gsd/model-router.ts +12 -0
- package/src/resources/extensions/gsd/paths.ts +73 -15
- package/src/resources/extensions/gsd/planning-subagent-policy.ts +58 -0
- package/src/resources/extensions/gsd/planning-subagent-registry.ts +31 -0
- package/src/resources/extensions/gsd/preferences-types.ts +16 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +62 -0
- package/src/resources/extensions/gsd/preferences.ts +25 -0
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +5 -5
- package/src/resources/extensions/gsd/provider-payload-policy.ts +18 -4
- package/src/resources/extensions/gsd/safety/destructive-guard.ts +1 -1
- package/src/resources/extensions/gsd/skill-activation.ts +17 -3
- package/src/resources/extensions/gsd/state-reconciliation/drift/external-markdown-edit.ts +132 -2
- package/src/resources/extensions/gsd/state-reconciliation/drift/external-planning-edit.ts +4 -1
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +4 -2
- package/src/resources/extensions/gsd/stop-notice.ts +11 -0
- package/src/resources/extensions/gsd/templates/PREFERENCES.md +5 -0
- package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +264 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +74 -1
- package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/compat-marker.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +76 -1
- package/src/resources/extensions/gsd/tests/context-masker.test.ts +204 -8
- package/src/resources/extensions/gsd/tests/db-engine-cjs-compat.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/db-tools-alias-suppression.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/destructive-guard.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +33 -1
- package/src/resources/extensions/gsd/tests/external-markdown-edit.test.ts +38 -1
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +8 -9
- package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +20 -1
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/integration/paths.test.ts +22 -4
- package/src/resources/extensions/gsd/tests/integration-branch-meta-location.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/preferences.test.ts +84 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/reactive-executor.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/register-hooks-loop-guard-auto.test.ts +105 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +33 -7
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -16
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/stop-notice.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +13 -7
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +34 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +20 -5
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +24 -5
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +25 -5
- package/src/resources/extensions/gsd/tools/reopen-task.ts +23 -9
- package/src/resources/extensions/gsd/unit-context-composer.ts +34 -8
- package/src/resources/extensions/gsd/workflow-projections.ts +2 -3
- package/src/resources/extensions/gsd/workspace.ts +2 -1
- package/src/resources/extensions/gsd/worktree-state-projection.ts +21 -24
- package/src/resources/extensions/shared/interview-ui.ts +47 -8
- package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +29 -0
- /package/dist/web/standalone/.next/static/{BE5XoklToI6lZjRzpXih8 → EAhnhYMt5UVOiG9-iPDjc}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{BE5XoklToI6lZjRzpXih8 → EAhnhYMt5UVOiG9-iPDjc}/_ssgManifest.js +0 -0
|
@@ -46,9 +46,10 @@ import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.
|
|
|
46
46
|
import { extractVerdict } from "./verdict-parser.js";
|
|
47
47
|
import { auditOrphanedPreflightStashes } from "./orphan-stash-audit.js";
|
|
48
48
|
import { parseProject } from "./schemas/parsers.js";
|
|
49
|
+
import { LAYOUT_SEGMENTS } from "./layout-policy.js";
|
|
49
50
|
import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath, } from "./debug-logger.js";
|
|
50
51
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
51
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, } from "node:fs";
|
|
52
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, } from "node:fs";
|
|
52
53
|
import { join } from "node:path";
|
|
53
54
|
import { validateDirectory } from "./validate-directory.js";
|
|
54
55
|
import { isCustomProvider, resolveDefaultSessionModel, resolveDynamicRoutingConfig, } from "./preferences-models.js";
|
|
@@ -73,6 +74,30 @@ const MAX_CONSECUTIVE_COMPLETE_BOOTSTRAPS = 2;
|
|
|
73
74
|
export function hasGitIndexLockForTest(basePath) {
|
|
74
75
|
return existsSync(join(basePath, ".git", "index.lock"));
|
|
75
76
|
}
|
|
77
|
+
function isEmptyDirectory(dirPath) {
|
|
78
|
+
try {
|
|
79
|
+
return existsSync(dirPath) && readdirSync(dirPath).length === 0;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export function reconcileFlatPhaseBootstrapLayout(basePath) {
|
|
86
|
+
const gsdDir = join(basePath, ".gsd");
|
|
87
|
+
const phasesPath = join(gsdDir, LAYOUT_SEGMENTS.level1);
|
|
88
|
+
const milestonesPath = join(gsdDir, "milestones");
|
|
89
|
+
if (isEmptyDirectory(milestonesPath)) {
|
|
90
|
+
if (!existsSync(phasesPath))
|
|
91
|
+
mkdirSync(phasesPath, { recursive: true });
|
|
92
|
+
rmSync(milestonesPath, { recursive: true, force: true });
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
if (!existsSync(phasesPath) && !existsSync(milestonesPath)) {
|
|
96
|
+
mkdirSync(phasesPath, { recursive: true });
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
76
101
|
export function _shouldAbortBootstrapForUnavailableDbForTest(gsdDbPath, dbAvailable, pathExists = existsSync) {
|
|
77
102
|
return pathExists(gsdDbPath) && !dbAvailable;
|
|
78
103
|
}
|
|
@@ -868,20 +893,15 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
|
|
|
868
893
|
ensureGitignore(base, { manageGitignore });
|
|
869
894
|
if (manageGitignore !== false)
|
|
870
895
|
untrackRuntimeFiles(base);
|
|
871
|
-
// Bootstrap
|
|
872
|
-
|
|
873
|
-
// so checking .gsd/ existence would be dead code (#2942).
|
|
874
|
-
const gsdDir = join(base, ".gsd");
|
|
875
|
-
const milestonesPath = join(gsdDir, "milestones");
|
|
876
|
-
if (!existsSync(milestonesPath)) {
|
|
877
|
-
mkdirSync(milestonesPath, { recursive: true });
|
|
896
|
+
// Bootstrap the flat-phase projection root and clean empty legacy scaffolds.
|
|
897
|
+
if (reconcileFlatPhaseBootstrapLayout(base)) {
|
|
878
898
|
try {
|
|
879
899
|
nativeAddAll(base);
|
|
880
900
|
nativeCommit(base, "chore: init gsd");
|
|
881
901
|
}
|
|
882
902
|
catch (err) {
|
|
883
903
|
/* nothing to commit */
|
|
884
|
-
logWarning("engine", `
|
|
904
|
+
logWarning("engine", `layout bootstrap commit failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
885
905
|
}
|
|
886
906
|
}
|
|
887
907
|
{
|
|
@@ -118,6 +118,8 @@ export function clearInFlightTools() {
|
|
|
118
118
|
*/
|
|
119
119
|
const TOOL_INVOCATION_ERROR_RE = /Validation failed for tool|Input validation error|Invalid arguments for tool|MCP error -32602|No such tool available|Expected ',' or '\}'(?: after property value)?(?: in JSON)?|Unexpected end of JSON|Unexpected token.*in JSON|does not provide an export named|Named export .* not found|Cannot find module|ERR_MODULE_NOT_FOUND|ERR_MODULE_NOT_EXPORTED|ERR_PACKAGE_PATH_NOT_EXPORTED/i;
|
|
120
120
|
const DETERMINISTIC_POLICY_ERROR_RE = /(?:^|\b)(?:HARD BLOCK:|Blocked: \/gsd queue is a planning tool|Direct writes to \.gsd\/STATE\.md and \.gsd\/gsd\.db are blocked|This is a mechanical gate)/i;
|
|
121
|
+
const SCHEDULE_WAKEUP_TOOL_NAME = "ScheduleWakeup";
|
|
122
|
+
const SCHEDULE_WAKEUP_CONTINUATION_ERROR = "`prompt` is required when `stop` is not true";
|
|
121
123
|
/**
|
|
122
124
|
* Matches the runtime's "tool not registered" error. Unlike the deterministic
|
|
123
125
|
* invocation failures above, this one is usually transient: the workflow MCP
|
|
@@ -135,6 +137,44 @@ export function isToolInvocationError(errorMsg) {
|
|
|
135
137
|
return false;
|
|
136
138
|
return TOOL_INVOCATION_ERROR_RE.test(errorMsg) || isDeterministicPolicyError(errorMsg);
|
|
137
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* Claude Code validates its native ScheduleWakeup tool outside GSD's schema.
|
|
142
|
+
* Keep this exact and tool-scoped so similarly worded business validation from
|
|
143
|
+
* unrelated tools does not pause auto-mode.
|
|
144
|
+
*/
|
|
145
|
+
export function isScheduleWakeupContinuationError(toolName, errorMsg) {
|
|
146
|
+
return stripMcpToolPrefix(toolName) === SCHEDULE_WAKEUP_TOOL_NAME
|
|
147
|
+
&& errorMsg.trim() === SCHEDULE_WAKEUP_CONTINUATION_ERROR;
|
|
148
|
+
}
|
|
149
|
+
function shouldRecordToolInvocationError(toolName, errorMsg) {
|
|
150
|
+
return isScheduleWakeupContinuationError(toolName, errorMsg)
|
|
151
|
+
|| isToolInvocationError(errorMsg)
|
|
152
|
+
|| isQueuedUserMessageSkip(errorMsg);
|
|
153
|
+
}
|
|
154
|
+
function isRecordedScheduleWakeupContinuationError(recordedError) {
|
|
155
|
+
if (!recordedError)
|
|
156
|
+
return false;
|
|
157
|
+
const separator = recordedError.indexOf(": ");
|
|
158
|
+
return separator >= 0 && isScheduleWakeupContinuationError(recordedError.slice(0, separator), recordedError.slice(separator + 2));
|
|
159
|
+
}
|
|
160
|
+
export function updateToolInvocationError(recordedError, toolName, errorMsg) {
|
|
161
|
+
if (!shouldRecordToolInvocationError(toolName, errorMsg))
|
|
162
|
+
return recordedError;
|
|
163
|
+
if (isRecordedScheduleWakeupContinuationError(recordedError)
|
|
164
|
+
&& !isScheduleWakeupContinuationError(toolName, errorMsg))
|
|
165
|
+
return recordedError;
|
|
166
|
+
return `${toolName}: ${errorMsg}`;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* A failed continuation must survive successful diagnostic/read calls in the
|
|
170
|
+
* same turn. Only a later successful ScheduleWakeup proves the continuation
|
|
171
|
+
* was armed; all other invocation errors retain their existing clear-on-success
|
|
172
|
+
* behavior.
|
|
173
|
+
*/
|
|
174
|
+
export function shouldClearToolInvocationErrorAfterSuccess(recordedError, successfulToolName) {
|
|
175
|
+
return !isRecordedScheduleWakeupContinuationError(recordedError)
|
|
176
|
+
|| stripMcpToolPrefix(successfulToolName ?? "") === SCHEDULE_WAKEUP_TOOL_NAME;
|
|
177
|
+
}
|
|
138
178
|
/**
|
|
139
179
|
* Returns true if the error message indicates the called tool was not on the
|
|
140
180
|
* session's tool surface (MCP startup race — see TOOL_UNAVAILABLE_ERROR_RE).
|
|
@@ -8,6 +8,7 @@ import { execFileSync } from "node:child_process";
|
|
|
8
8
|
import { existsSync, realpathSync, unlinkSync } from "node:fs";
|
|
9
9
|
import { isAbsolute, join, relative } from "node:path";
|
|
10
10
|
import { gsdRoot } from "./paths.js";
|
|
11
|
+
import { milestoneMetaPath } from "./git-service.js";
|
|
11
12
|
import { logWarning } from "./workflow-logger.js";
|
|
12
13
|
function isSamePath(a, b) {
|
|
13
14
|
try {
|
|
@@ -73,6 +74,9 @@ export function clearProjectRootStateFiles(basePath, milestoneId) {
|
|
|
73
74
|
// worth removing on teardown.
|
|
74
75
|
const transientFiles = [
|
|
75
76
|
join(gsdDir, "STATE.md"),
|
|
77
|
+
// Integration-branch META now lives flat at .gsd/<MID>-META.json (ADR-045).
|
|
78
|
+
milestoneMetaPath(basePath, milestoneId),
|
|
79
|
+
// Legacy location — still cleaned for pre-migration trees.
|
|
76
80
|
join(gsdDir, "milestones", milestoneId, `${milestoneId}-META.json`),
|
|
77
81
|
];
|
|
78
82
|
for (const file of transientFiles) {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { cpSync, existsSync, lstatSync as lstatSyncFn, mkdirSync, readdirSync, } from "node:fs";
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import { _isSamePath as isSamePath, } from "./auto-worktree-cleanup.js";
|
|
8
|
-
import { resolveGsdPathContract } from "./paths.js";
|
|
8
|
+
import { dirIsContentBearingLegacyMilestone, resolveGsdPathContract } from "./paths.js";
|
|
9
9
|
import { WorktreeStateProjection } from "./worktree-state-projection.js";
|
|
10
10
|
import { logWarning } from "./workflow-logger.js";
|
|
11
11
|
const PROJECT_PREFERENCES_FILE = "PREFERENCES.md";
|
|
@@ -143,10 +143,14 @@ function syncMilestoneLayout(mainGsd, wtGsd, layoutSegment, synced) {
|
|
|
143
143
|
if (!existsSync(mainMilestonesDir))
|
|
144
144
|
return;
|
|
145
145
|
try {
|
|
146
|
-
mkdirSync(wtMilestonesDir, { recursive: true });
|
|
147
146
|
const mainMilestones = readdirSync(mainMilestonesDir, { withFileTypes: true })
|
|
148
147
|
.filter((entry) => entry.isDirectory())
|
|
149
|
-
.map((entry) => entry.name)
|
|
148
|
+
.map((entry) => entry.name)
|
|
149
|
+
.filter((name) => layoutSegment !== "milestones" ||
|
|
150
|
+
dirIsContentBearingLegacyMilestone(join(mainMilestonesDir, name)));
|
|
151
|
+
if (mainMilestones.length === 0)
|
|
152
|
+
return;
|
|
153
|
+
mkdirSync(wtMilestonesDir, { recursive: true });
|
|
150
154
|
for (const milestoneId of mainMilestones) {
|
|
151
155
|
syncMilestoneDirectory(mainMilestonesDir, wtMilestonesDir, milestoneId, synced);
|
|
152
156
|
}
|
|
@@ -45,7 +45,7 @@ export function teardownAutoWorktree(originalBasePath, milestoneId, opts = {}) {
|
|
|
45
45
|
throw new GSDError(GSD_IO_ERROR, `Failed to chdir back to ${originalBasePath} during teardown: ${err instanceof Error ? err.message : String(err)}`);
|
|
46
46
|
}
|
|
47
47
|
// Mirror cleanup steps from mergeMilestoneToMain abort path:
|
|
48
|
-
// 1. Remove transient state files (STATE.md, auto.lock, {MID}-META.json).
|
|
48
|
+
// 1. Remove transient state files (STATE.md, auto.lock, .gsd/{MID}-META.json).
|
|
49
49
|
// Non-fatal — must not block teardown.
|
|
50
50
|
try {
|
|
51
51
|
clearProjectRootStateFiles(originalBasePath, milestoneId);
|
|
@@ -28,7 +28,7 @@ import { acquireSessionLock, getSessionLockStatus, releaseSessionLock, updateSes
|
|
|
28
28
|
import { resolveAutoSupervisorConfig, loadEffectiveGSDPreferences, loadEffectiveGSDPreferencesWithRegistry, resolveProfileAnchorProvider, getIsolationMode, resolveEffectiveUnitIsolationMode, } from "./preferences.js";
|
|
29
29
|
import { playNotificationBell, sendDesktopNotification } from "./notifications.js";
|
|
30
30
|
import { getBudgetAlertLevel, getNewBudgetAlertLevel, getBudgetEnforcementAction, HARD_CONTEXT_REROOT_THRESHOLD_PERCENT, resolveCompactionThresholdPercent, shouldRerootStepSessionForContext, shouldWarnStepSessionForContext, } from "./auto-budget.js";
|
|
31
|
-
import { markToolStart as _markToolStart, markToolEnd as _markToolEnd, getOldestInFlightToolAgeMs as _getOldestInFlightToolAgeMs, clearInFlightTools,
|
|
31
|
+
import { markToolStart as _markToolStart, markToolEnd as _markToolEnd, getOldestInFlightToolAgeMs as _getOldestInFlightToolAgeMs, clearInFlightTools, updateToolInvocationError, } from "./auto-tool-tracking.js";
|
|
32
32
|
import { closeoutUnit } from "./auto-unit-closeout.js";
|
|
33
33
|
import { selectAndApplyModel, resolveModelId, clearToolBaseline, isModelUnavailable, applyThinkingLevelForModel } from "./auto-model-selection.js";
|
|
34
34
|
import { resolveModelWithFallbacksForUnit } from "./preferences-models.js";
|
|
@@ -617,15 +617,14 @@ export function markToolEnd(toolCallId) {
|
|
|
617
617
|
* Called from tool_execution_end when a GSD tool fails with isError.
|
|
618
618
|
* Stores the error if it matches:
|
|
619
619
|
* - tool-invocation-error pattern (malformed/truncated JSON)
|
|
620
|
+
* - failed ScheduleWakeup continuation validation (#1379)
|
|
620
621
|
* - queued-user-message skip pattern
|
|
621
622
|
* - deterministic policy rejection (#4973, e.g. context_write_blocked)
|
|
622
623
|
*/
|
|
623
624
|
export function recordToolInvocationError(toolName, errorMsg) {
|
|
624
625
|
if (!s.active)
|
|
625
626
|
return;
|
|
626
|
-
|
|
627
|
-
s.lastToolInvocationError = `${toolName}: ${errorMsg}`;
|
|
628
|
-
}
|
|
627
|
+
s.lastToolInvocationError = updateToolInvocationError(s.lastToolInvocationError, toolName, errorMsg);
|
|
629
628
|
}
|
|
630
629
|
export function getOldestInFlightToolAgeMs() {
|
|
631
630
|
return _getOldestInFlightToolAgeMs();
|
|
@@ -2441,7 +2440,18 @@ export async function dispatchHookUnit(ctx, pi, hookName, triggerUnitType, trigg
|
|
|
2441
2440
|
startedAt: hookStartedAt,
|
|
2442
2441
|
workspaceRoot: s.basePath,
|
|
2443
2442
|
});
|
|
2444
|
-
const
|
|
2443
|
+
const cmdCtx = s.cmdCtx;
|
|
2444
|
+
if (typeof cmdCtx?.newSession !== "function") {
|
|
2445
|
+
const message = "Auto-mode has no command context for dispatch.";
|
|
2446
|
+
ctx.ui.notify(message, "error");
|
|
2447
|
+
const unitToCommit = previousCurrentUnit ?? s.currentUnit;
|
|
2448
|
+
if (unitToCommit) {
|
|
2449
|
+
await autoCommitUnit(s.basePath, unitToCommit.type, unitToCommit.id, ctx);
|
|
2450
|
+
}
|
|
2451
|
+
await stopAuto(ctx, pi, message, { preserveWorktree: true });
|
|
2452
|
+
return false;
|
|
2453
|
+
}
|
|
2454
|
+
const result = await cmdCtx.newSession({ workspaceRoot: s.basePath });
|
|
2445
2455
|
if (result.cancelled) {
|
|
2446
2456
|
await stopAuto(ctx, pi);
|
|
2447
2457
|
return false;
|
|
@@ -46,6 +46,8 @@ function registerAlias(pi, toolDef, aliasName, canonicalName) {
|
|
|
46
46
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- toolDef shape matches ToolDefinition but varies by schema
|
|
47
47
|
function registerWorkflowTool(pi, toolDef) {
|
|
48
48
|
pi.registerTool(toolDef);
|
|
49
|
+
if (process.env.GSD_ADVERTISE_TOOL_ALIASES !== "1")
|
|
50
|
+
return; // canonical-only model surface (see plan 035)
|
|
49
51
|
for (const alias of aliasesForWorkflowTool(toolDef.name)) {
|
|
50
52
|
registerAlias(pi, toolDef, alias, toolDef.name);
|
|
51
53
|
}
|
|
@@ -22,13 +22,14 @@ import { saveActivityLog } from "../activity-log.js";
|
|
|
22
22
|
import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult, saveEvidenceToDisk } from "../safety/evidence-collector.js";
|
|
23
23
|
import { parseUnitId } from "../unit-id.js";
|
|
24
24
|
import { classifyCommand } from "../safety/destructive-guard.js";
|
|
25
|
-
import { confirmDestructiveCommand, consumeDestructiveConfirmation, isDestructiveConfirmGateId, requestDestructiveConfirmation, } from "../safety/destructive-confirmation.js";
|
|
25
|
+
import { confirmDestructiveCommand, consumeDestructiveConfirmation, isDestructiveConfirmGateId, peekPendingDestructiveCommand, requestDestructiveConfirmation, resetDestructiveConfirmation, } from "../safety/destructive-confirmation.js";
|
|
26
26
|
import { logWarning as safetyLogWarning, setStderrLoggingEnabled } from "../workflow-logger.js";
|
|
27
27
|
import { isUnitCloseoutTool, runInteractiveUnitCloseout } from "../unit-closeout.js";
|
|
28
28
|
import { installNotifyInterceptor } from "./notify-interceptor.js";
|
|
29
29
|
import { initNotificationStore } from "../notification-store.js";
|
|
30
30
|
import { initNotificationWidget } from "../notification-widget.js";
|
|
31
31
|
import { notifyPreferenceDiagnostics } from "../preferences-diagnostics.js";
|
|
32
|
+
import { resolveEffectivePlanningToolsPolicy } from "../planning-subagent-policy.js";
|
|
32
33
|
import { resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
33
34
|
import { extractSubagentAgentClasses } from "./subagent-input.js";
|
|
34
35
|
import { approvalGateIdForUnit, evaluateAskUserQuestionsRound, formatUnansweredConsentQuestionMessage, isExplicitApprovalResponse, messageHasPendingAskUserQuestionsTool, shouldPauseForQuestion, } from "../consent-question.js";
|
|
@@ -136,6 +137,7 @@ function suppressWelcomeHeader(ctx) {
|
|
|
136
137
|
* are bounded — cleared on activation, session boundaries, and verification.
|
|
137
138
|
*/
|
|
138
139
|
const deferredApprovalGates = new Map();
|
|
140
|
+
const deferredDestructiveConfirmationPauses = new Set();
|
|
139
141
|
export const MINIMAL_GSD_TOOL_NAMES = [
|
|
140
142
|
"gsd_exec",
|
|
141
143
|
"gsd_exec_search",
|
|
@@ -456,6 +458,21 @@ function clearDeferredApprovalGate(basePath) {
|
|
|
456
458
|
deferredApprovalGates.delete(basePath);
|
|
457
459
|
}
|
|
458
460
|
}
|
|
461
|
+
function deferDestructiveConfirmationPause(basePath) {
|
|
462
|
+
deferredDestructiveConfirmationPauses.add(basePath);
|
|
463
|
+
}
|
|
464
|
+
function clearDeferredDestructiveConfirmationPause(basePath) {
|
|
465
|
+
if (!basePath) {
|
|
466
|
+
deferredDestructiveConfirmationPauses.clear();
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
deferredDestructiveConfirmationPauses.delete(basePath);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
function isDestructiveConfirmationBlocking(basePath) {
|
|
473
|
+
return deferredDestructiveConfirmationPauses.has(basePath)
|
|
474
|
+
&& Boolean(peekPendingDestructiveCommand(basePath));
|
|
475
|
+
}
|
|
459
476
|
function deferApprovalGate(gateId, basePath) {
|
|
460
477
|
// Verified-on-disk wins (same adapter policy as activation/re-arm): if the
|
|
461
478
|
// workflow MCP child already verified this gate, deferring would block
|
|
@@ -798,6 +815,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
798
815
|
await applyToolCallLoopGuardConfig(basePath);
|
|
799
816
|
approvalQuestionAbortInFlight = false;
|
|
800
817
|
clearDeferredApprovalGate();
|
|
818
|
+
clearDeferredDestructiveConfirmationPause();
|
|
801
819
|
await resetAskUserQuestionsTurnCache();
|
|
802
820
|
await syncServiceTierStatus(ctx);
|
|
803
821
|
await applyDisabledModelProviderPolicy(ctx);
|
|
@@ -883,6 +901,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
883
901
|
resetToolCallLoopGuard();
|
|
884
902
|
await applyToolCallLoopGuardConfig(basePath);
|
|
885
903
|
clearDeferredApprovalGate();
|
|
904
|
+
clearDeferredDestructiveConfirmationPause();
|
|
886
905
|
await resetAskUserQuestionsTurnCache();
|
|
887
906
|
clearDiscussionFlowState(basePath);
|
|
888
907
|
// /clear or /new destroys the conversation holding a discuss interview, so
|
|
@@ -933,6 +952,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
933
952
|
}
|
|
934
953
|
}
|
|
935
954
|
clearDeferredApprovalGate(beforeAgentBasePath);
|
|
955
|
+
clearDeferredDestructiveConfirmationPause(beforeAgentBasePath);
|
|
936
956
|
// session_start can fire before the active provider has settled. By
|
|
937
957
|
// before_agent_start, Claude Code CLI sessions should get the same
|
|
938
958
|
// project MCP config that /gsd mcp init would write.
|
|
@@ -1010,7 +1030,10 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1010
1030
|
}
|
|
1011
1031
|
finally {
|
|
1012
1032
|
activateDeferredApprovalGate(agentEndBasePath);
|
|
1033
|
+
const destructiveConfirmationBlocking = isDestructiveConfirmationBlocking(agentEndBasePath);
|
|
1034
|
+
clearDeferredDestructiveConfirmationPause(agentEndBasePath);
|
|
1013
1035
|
await maybePauseAutoForApprovalGate(ctx, pi, isApprovalGateBlocking(agentEndBasePath), "Depth confirmation is waiting for your answer — pausing auto-mode.");
|
|
1036
|
+
await maybePauseAutoForApprovalGate(ctx, pi, destructiveConfirmationBlocking, "Destructive-command confirmation is waiting for your answer — pausing auto-mode.");
|
|
1014
1037
|
}
|
|
1015
1038
|
});
|
|
1016
1039
|
pi.on("message_end", async (event) => {
|
|
@@ -1276,6 +1299,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1276
1299
|
const activeUnitType = dash.currentUnit?.type ?? guidedUnit?.unitType;
|
|
1277
1300
|
if (activeUnitType) {
|
|
1278
1301
|
const manifest = resolveManifest(activeUnitType);
|
|
1302
|
+
const planningBasePath = dash.basePath || guidedUnit?.basePath || discussionBasePath;
|
|
1279
1303
|
let planningInput = "";
|
|
1280
1304
|
let agentClasses;
|
|
1281
1305
|
if (isToolCallEventType("write", event)) {
|
|
@@ -1291,7 +1315,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1291
1315
|
// Subagent inputs use { agent }, { tasks: [{ agent }] }, or { chain: [{ agent }] }.
|
|
1292
1316
|
agentClasses = extractSubagentAgentClasses(event.input);
|
|
1293
1317
|
}
|
|
1294
|
-
const planningGuard = shouldBlockPlanningUnit(event.toolName, planningInput,
|
|
1318
|
+
const planningGuard = shouldBlockPlanningUnit(event.toolName, planningInput, planningBasePath, activeUnitType, resolveEffectivePlanningToolsPolicy(activeUnitType, manifest?.tools, planningBasePath), agentClasses, event.input, dash.currentUnit?.id);
|
|
1295
1319
|
if (planningGuard.block)
|
|
1296
1320
|
return planningGuard;
|
|
1297
1321
|
}
|
|
@@ -1373,6 +1397,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1373
1397
|
// Record the command as pending so an affirmative answer to a
|
|
1374
1398
|
// destructive_confirm gate (handled in tool_result) can confirm it.
|
|
1375
1399
|
requestDestructiveConfirmation(command, guardBasePath);
|
|
1400
|
+
deferDestructiveConfirmationPause(guardBasePath);
|
|
1376
1401
|
const reason = [
|
|
1377
1402
|
"HARD BLOCK: destructive Bash command requires explicit human confirmation.",
|
|
1378
1403
|
`Detected: ${classification.labels.join(", ")}`,
|
|
@@ -1383,9 +1408,6 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1383
1408
|
safetyLogWarning("safety", `destructive command: ${classification.labels.join(", ")}`, {
|
|
1384
1409
|
command: String(command).slice(0, 200),
|
|
1385
1410
|
});
|
|
1386
|
-
if (ctx) {
|
|
1387
|
-
await maybePauseAutoForApprovalGate(ctx, pi, isAutoActive(), "Destructive-command confirmation is waiting for your answer — pausing auto-mode.");
|
|
1388
|
-
}
|
|
1389
1411
|
return { block: true, reason };
|
|
1390
1412
|
}
|
|
1391
1413
|
}
|
|
@@ -1426,7 +1448,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1426
1448
|
recordRetryableHarnessToolError(toolName, resultPayload, errorText);
|
|
1427
1449
|
}
|
|
1428
1450
|
else if (isAutoActive()) {
|
|
1429
|
-
clearToolInvocationError();
|
|
1451
|
+
clearToolInvocationError(event.toolName);
|
|
1430
1452
|
}
|
|
1431
1453
|
// Interactive Closeout adapter (ADR-032): auto-mode owns closeout for its
|
|
1432
1454
|
// own units; interactive completions get the durable git subset (commit +
|
|
@@ -1541,6 +1563,10 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1541
1563
|
if (isDepthConfirmationAnswer(answer?.selected, question.options)) {
|
|
1542
1564
|
confirmDestructiveCommand(basePath);
|
|
1543
1565
|
}
|
|
1566
|
+
else {
|
|
1567
|
+
resetDestructiveConfirmation(basePath);
|
|
1568
|
+
}
|
|
1569
|
+
clearDeferredDestructiveConfirmationPause(basePath);
|
|
1544
1570
|
break;
|
|
1545
1571
|
}
|
|
1546
1572
|
}
|
|
@@ -1605,7 +1631,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
1605
1631
|
recordRetryableHarnessToolError(toolName, event.result, errorText);
|
|
1606
1632
|
}
|
|
1607
1633
|
else if (isAutoActive()) {
|
|
1608
|
-
clearToolInvocationError();
|
|
1634
|
+
clearToolInvocationError(event.toolName);
|
|
1609
1635
|
}
|
|
1610
1636
|
// Safety harness: record tool execution results for evidence cross-referencing
|
|
1611
1637
|
if (isAutoActive()) {
|
|
@@ -18,6 +18,13 @@ import { formatOverridesSection, formatShortcut, loadActiveOverrides, loadFile,
|
|
|
18
18
|
import { toPosixPath } from "../../shared/mod.js";
|
|
19
19
|
import { autoEnableCmuxPreferences } from "../commands-cmux.js";
|
|
20
20
|
import { gsdHome } from "../gsd-home.js";
|
|
21
|
+
import { GSD_CONTEXT_MESSAGE_SENTINEL } from "../constants.js";
|
|
22
|
+
// Single source of truth lives in ../constants.js; re-exported here because
|
|
23
|
+
// buildContextMessage() stamps this marker on every context injection and the
|
|
24
|
+
// provider payload policy (filterSupersededContextInjections in
|
|
25
|
+
// context-masker.ts) matches it to dedupe. Adding a new context customType?
|
|
26
|
+
// Ensure buildContextMessage still prepends this sentinel.
|
|
27
|
+
export { GSD_CONTEXT_MESSAGE_SENTINEL };
|
|
21
28
|
const DEFAULT_CONTEXT_MESSAGE_MAX_CHARS = 4_000;
|
|
22
29
|
const DEFAULT_KNOWLEDGE_MAX_CHARS = 12_000;
|
|
23
30
|
const DEFAULT_CODEBASE_MAX_CHARS = 8_000;
|
|
@@ -385,17 +392,17 @@ export function buildContextMessage(opts) {
|
|
|
385
392
|
const contextCharLimit = getContextMessageCharLimit();
|
|
386
393
|
const memoryContent = markMemoryContextSupplied(opts.memoryBlock.trim());
|
|
387
394
|
if (opts.injection) {
|
|
388
|
-
const content = limitContextMessageContent(memoryContent ? `${memoryContent}\n\n${opts.injection}` : opts.injection
|
|
395
|
+
const content = limitContextMessageContent(`${GSD_CONTEXT_MESSAGE_SENTINEL}\n${memoryContent ? `${memoryContent}\n\n${opts.injection}` : opts.injection}`, contextCharLimit);
|
|
389
396
|
return { customType: "gsd-guided-context", content, display: false };
|
|
390
397
|
}
|
|
391
398
|
if (opts.forensicsInjection) {
|
|
392
|
-
const content = limitContextMessageContent(memoryContent ? `${memoryContent}\n\n${opts.forensicsInjection}` : opts.forensicsInjection
|
|
399
|
+
const content = limitContextMessageContent(`${GSD_CONTEXT_MESSAGE_SENTINEL}\n${memoryContent ? `${memoryContent}\n\n${opts.forensicsInjection}` : opts.forensicsInjection}`, contextCharLimit);
|
|
393
400
|
return { customType: "gsd-forensics", content, display: false };
|
|
394
401
|
}
|
|
395
402
|
if (memoryContent) {
|
|
396
403
|
return {
|
|
397
404
|
customType: "gsd-memory",
|
|
398
|
-
content: limitContextMessageContent(memoryContent
|
|
405
|
+
content: limitContextMessageContent(`${GSD_CONTEXT_MESSAGE_SENTINEL}\n${memoryContent}`, contextCharLimit),
|
|
399
406
|
display: false,
|
|
400
407
|
};
|
|
401
408
|
}
|
|
@@ -7,6 +7,7 @@ import { canonicalToolName } from "../engine-hook-contract.js";
|
|
|
7
7
|
import { loadJsonFileOrNull } from "../json-persistence.js";
|
|
8
8
|
import { getIsolationMode } from "../preferences.js";
|
|
9
9
|
import { compileSubagentPermissionContract } from "../unit-context-manifest.js";
|
|
10
|
+
import { allowedPlanningDispatchAgentsList, isReadOnlyPlanningDispatchAgent, } from "../planning-subagent-registry.js";
|
|
10
11
|
import { logWarning } from "../workflow-logger.js";
|
|
11
12
|
import { acquireSyncLock, releaseSyncLock } from "../sync-lock.js";
|
|
12
13
|
import { isGsdWorktreePath, resolveWorktreeProjectRoot } from "../worktree-root.js";
|
|
@@ -981,29 +982,8 @@ export function shouldBlockQueueExecutionInSnapshot(snapshot, toolName, input, q
|
|
|
981
982
|
// guards.
|
|
982
983
|
const PLANNING_WRITE_TOOLS = new Set(["write", "edit", "multi_edit", "notebook_edit"]);
|
|
983
984
|
const PLANNING_SUBAGENT_TOOLS = new Set(["subagent", "task"]);
|
|
984
|
-
|
|
985
|
-
* Canonical registry for agents that planning-dispatch may consider. Unit
|
|
986
|
-
* manifests still declare per-unit subsets via ToolsPolicy.allowedSubagents.
|
|
987
|
-
*/
|
|
988
|
-
const PLANNING_DISPATCH_AGENT_REGISTRY = {
|
|
989
|
-
mnemo: { readOnlySpecialist: true },
|
|
990
|
-
scout: { readOnlySpecialist: true },
|
|
991
|
-
planner: { readOnlySpecialist: true },
|
|
992
|
-
reviewer: { readOnlySpecialist: true },
|
|
993
|
-
security: { readOnlySpecialist: true },
|
|
994
|
-
tester: { readOnlySpecialist: true },
|
|
995
|
-
};
|
|
996
|
-
export const ALLOWED_PLANNING_DISPATCH_AGENTS = new Set(Object.entries(PLANNING_DISPATCH_AGENT_REGISTRY)
|
|
997
|
-
.filter(([, metadata]) => metadata.readOnlySpecialist)
|
|
998
|
-
.map(([agentId]) => agentId));
|
|
985
|
+
export { ALLOWED_PLANNING_DISPATCH_AGENTS } from "../planning-subagent-registry.js";
|
|
999
986
|
let warnedMissingControlledDispatchAgentClasses = false;
|
|
1000
|
-
function isReadOnlySpecialist(agentId) {
|
|
1001
|
-
const metadata = PLANNING_DISPATCH_AGENT_REGISTRY[agentId];
|
|
1002
|
-
return metadata?.readOnlySpecialist === true;
|
|
1003
|
-
}
|
|
1004
|
-
function allowedPlanningDispatchAgentsList() {
|
|
1005
|
-
return [...ALLOWED_PLANNING_DISPATCH_AGENTS].join(", ");
|
|
1006
|
-
}
|
|
1007
987
|
function allowsControlledSubagentDispatch(policy) {
|
|
1008
988
|
return ((policy.mode === "planning-dispatch" || policy.mode === "verification" || policy.mode === "workflow-only") &&
|
|
1009
989
|
Array.isArray(policy.allowedSubagents));
|
|
@@ -1151,13 +1131,13 @@ export function shouldBlockPlanningUnit(toolName, pathOrCommand, basePath, unitT
|
|
|
1151
1131
|
if (requested.length === 0) {
|
|
1152
1132
|
return { block: false };
|
|
1153
1133
|
}
|
|
1154
|
-
const globallyDisallowed = requested.find(a => !
|
|
1134
|
+
const globallyDisallowed = requested.find(a => !isReadOnlyPlanningDispatchAgent(a));
|
|
1155
1135
|
if (globallyDisallowed) {
|
|
1156
1136
|
return planningBlock(unitType, policy.mode, `subagent dispatch of "${globallyDisallowed}" not permitted; only read-only specialists (${allowedPlanningDispatchAgentsList()}) may be dispatched from ${policy.mode} units`);
|
|
1157
1137
|
}
|
|
1158
1138
|
const disallowedByPolicy = requested.find(a => !allowed.has(a));
|
|
1159
1139
|
if (disallowedByPolicy) {
|
|
1160
|
-
return planningBlock(unitType, policy.mode, `subagent dispatch of "${disallowedByPolicy}" not permitted by ToolsPolicy.allowedSubagents; permitted agents for this unit: ${allowedSubagents.join(", ")}`);
|
|
1140
|
+
return planningBlock(unitType, policy.mode, `subagent dispatch of "${disallowedByPolicy}" not permitted by unit allowlist (ToolsPolicy.allowedSubagents/planning_subagents); permitted agents for this unit: ${allowedSubagents.join(", ")}`);
|
|
1161
1141
|
}
|
|
1162
1142
|
return { block: false };
|
|
1163
1143
|
}
|
|
@@ -8,6 +8,7 @@ import { executeValidateMilestone } from "./tools/workflow-tool-executors.js";
|
|
|
8
8
|
import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
|
|
9
9
|
import { getLatestAssessmentByScope } from "./gsd-db.js";
|
|
10
10
|
import { checkpointWorkflowDatabase } from "./db-workspace.js";
|
|
11
|
+
import { formatVerdictRecordedNotice, formatVerdictRejectedNotice } from "./stop-notice.js";
|
|
11
12
|
import { VALIDATION_VERDICTS, extractVerdict, isValidMilestoneVerdict, } from "./verdict-parser.js";
|
|
12
13
|
const USAGE = 'Usage: /gsd verdict <pass|needs-attention|needs-remediation> [--milestone Mxxx] [--rationale "..."]';
|
|
13
14
|
function tokenize(raw) {
|
|
@@ -123,35 +124,35 @@ async function loadExistingValidation(basePath, milestoneId) {
|
|
|
123
124
|
}
|
|
124
125
|
export async function handleVerdict(rawArgs, ctx, basePath) {
|
|
125
126
|
if (!rawArgs.trim()) {
|
|
126
|
-
ctx.ui.notify(USAGE, "warning");
|
|
127
|
+
ctx.ui.notify(formatVerdictRejectedNotice(USAGE), "warning");
|
|
127
128
|
return;
|
|
128
129
|
}
|
|
129
130
|
const parsed = parseArgs(rawArgs);
|
|
130
131
|
if ("error" in parsed) {
|
|
131
|
-
ctx.ui.notify(`${parsed.error}\n${USAGE}
|
|
132
|
+
ctx.ui.notify(formatVerdictRejectedNotice(`${parsed.error}\n${USAGE}`), "warning");
|
|
132
133
|
return;
|
|
133
134
|
}
|
|
134
135
|
if (!parsed.verdict) {
|
|
135
|
-
ctx.ui.notify(USAGE, "warning");
|
|
136
|
+
ctx.ui.notify(formatVerdictRejectedNotice(USAGE), "warning");
|
|
136
137
|
return;
|
|
137
138
|
}
|
|
138
139
|
let milestoneId = parsed.milestoneId;
|
|
139
140
|
if (!milestoneId) {
|
|
140
141
|
const state = await deriveState(basePath);
|
|
141
142
|
if (!state.activeMilestone) {
|
|
142
|
-
ctx.ui.notify("No active milestone — pass --milestone Mxxx to target a specific milestone.", "warning");
|
|
143
|
+
ctx.ui.notify(formatVerdictRejectedNotice("No active milestone — pass --milestone Mxxx to target a specific milestone."), "warning");
|
|
143
144
|
return;
|
|
144
145
|
}
|
|
145
146
|
milestoneId = state.activeMilestone.id;
|
|
146
147
|
}
|
|
147
148
|
const existingValidation = await loadExistingValidation(basePath, milestoneId);
|
|
148
149
|
if (!existingValidation) {
|
|
149
|
-
ctx.ui.notify(`No milestone validation found for ${milestoneId}. Run /gsd auto to validate first, then retry /gsd verdict
|
|
150
|
+
ctx.ui.notify(formatVerdictRejectedNotice(`No milestone validation found for ${milestoneId}. Run /gsd auto to validate first, then retry /gsd verdict.`), "warning");
|
|
150
151
|
return;
|
|
151
152
|
}
|
|
152
153
|
const current = parseValidationFile(existingValidation.content);
|
|
153
154
|
if (parsed.verdict !== "pass" && !parsed.rationale) {
|
|
154
|
-
ctx.ui.notify(`--rationale is required when overriding to ${parsed.verdict}
|
|
155
|
+
ctx.ui.notify(formatVerdictRejectedNotice(`--rationale is required when overriding to ${parsed.verdict}.`), "warning");
|
|
155
156
|
return;
|
|
156
157
|
}
|
|
157
158
|
const verdictRationale = parsed.rationale ?? "Manually overridden via /gsd verdict";
|
|
@@ -169,17 +170,17 @@ export async function handleVerdict(rawArgs, ctx, basePath) {
|
|
|
169
170
|
}, basePath, parsed.verdict === "pass" ? { skipBrowserEvidenceGate: true } : undefined);
|
|
170
171
|
if (result.isError) {
|
|
171
172
|
const msg = result.content[0]?.type === "text" ? result.content[0].text : "Unknown error";
|
|
172
|
-
ctx.ui.notify(msg, "error");
|
|
173
|
+
ctx.ui.notify(formatVerdictRejectedNotice(msg), "error");
|
|
173
174
|
return;
|
|
174
175
|
}
|
|
175
176
|
checkpointWorkflowDatabase();
|
|
176
177
|
const prevVerdict = current.verdict ?? "unknown";
|
|
177
178
|
const effectiveVerdict = extractEffectiveVerdict(result.details, parsed.verdict);
|
|
178
179
|
if (effectiveVerdict !== parsed.verdict) {
|
|
179
|
-
ctx.ui.notify(`Milestone ${milestoneId} verdict requested: ${parsed.verdict}, effective: ${effectiveVerdict} (${existingValidation.source})
|
|
180
|
+
ctx.ui.notify(formatVerdictRecordedNotice(`Milestone ${milestoneId} verdict requested: ${parsed.verdict}, effective: ${effectiveVerdict} (${existingValidation.source})`), "warning");
|
|
180
181
|
}
|
|
181
182
|
else {
|
|
182
|
-
ctx.ui.notify(`Milestone ${milestoneId} verdict: ${prevVerdict} -> ${effectiveVerdict} (${existingValidation.source})
|
|
183
|
+
ctx.ui.notify(formatVerdictRecordedNotice(`Milestone ${milestoneId} verdict: ${prevVerdict} -> ${effectiveVerdict} (${existingValidation.source})`), "success");
|
|
183
184
|
}
|
|
184
185
|
if (effectiveVerdict === "needs-remediation") {
|
|
185
186
|
ctx.ui.notify("Follow up with /gsd dispatch reassess to add remediation slices, then re-run /gsd auto.", "info");
|