@opengsd/gsd-pi 1.1.1-dev.9f86580 → 1.1.1-dev.b2556262
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/headless-recover.js +56 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/index.js +39 -22
- package/dist/resources/extensions/browser-tools/state.js +12 -0
- package/dist/resources/extensions/browser-tools/tools/session.js +3 -2
- package/dist/resources/extensions/browser-tools/utils.js +3 -3
- package/dist/resources/extensions/gsd/auto/loop.js +4 -2
- package/dist/resources/extensions/gsd/auto/phases.js +43 -10
- package/dist/resources/extensions/gsd/auto/session.js +20 -1
- package/dist/resources/extensions/gsd/auto/workflow-kernel.js +1 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +72 -12
- package/dist/resources/extensions/gsd/auto-model-selection.js +128 -9
- package/dist/resources/extensions/gsd/auto-post-unit.js +19 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -19
- package/dist/resources/extensions/gsd/auto-recovery.js +4 -2
- package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
- package/dist/resources/extensions/gsd/auto-start.js +1 -1
- package/dist/resources/extensions/gsd/auto.js +14 -11
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +172 -65
- package/dist/resources/extensions/gsd/closeout-wizard.js +32 -9
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -9
- package/dist/resources/extensions/gsd/commands-maintenance.js +93 -15
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +2 -2
- package/dist/resources/extensions/gsd/db-writer.js +35 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +50 -1
- package/dist/resources/extensions/gsd/gsd-db.js +480 -172
- package/dist/resources/extensions/gsd/markdown-renderer.js +37 -53
- package/dist/resources/extensions/gsd/md-importer.js +38 -3
- package/dist/resources/extensions/gsd/migration-auto-check.js +126 -31
- package/dist/resources/extensions/gsd/parsers-legacy.js +23 -0
- package/dist/resources/extensions/gsd/planning-path-scope.js +22 -4
- package/dist/resources/extensions/gsd/pre-execution-checks.js +10 -2
- package/dist/resources/extensions/gsd/preferences-models.js +110 -43
- package/dist/resources/extensions/gsd/preferences-types.js +13 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +68 -3
- package/dist/resources/extensions/gsd/preferences.js +4 -1
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +5 -1
- package/dist/resources/extensions/gsd/safety/content-validator.js +6 -4
- package/dist/resources/extensions/gsd/source-observations.js +306 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +15 -8
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +33 -5
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +34 -13
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +39 -14
- package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +4 -4
- package/dist/resources/extensions/gsd/state.js +7 -3
- package/dist/resources/extensions/gsd/tool-contract.js +14 -0
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +1 -9
- package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -6
- package/dist/resources/extensions/gsd/tools/plan-slice.js +42 -11
- package/dist/resources/extensions/gsd/tools/plan-task.js +7 -1
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +57 -429
- package/dist/resources/extensions/gsd/uat-policy.js +130 -0
- package/dist/resources/extensions/gsd/uat-run.js +414 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +3 -4
- package/dist/resources/extensions/gsd/verdict-parser.js +3 -8
- package/dist/resources/extensions/gsd/workflow-manifest.js +132 -5
- package/dist/resources/extensions/gsd/workflow-projections.js +8 -0
- package/dist/resources/extensions/gsd/worktree-state-projection.js +18 -17
- package/dist/resources/extensions/subagent/agents.js +1 -0
- package/dist/resources/extensions/subagent/index.js +27 -12
- package/dist/resources/extensions/subagent/launch.js +7 -2
- 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/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 +8 -8
- 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/dist/web/standalone/node_modules/@gsd/native/dist/native.js +22 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +4 -4
- 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/assistant-message.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js +21 -23
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +3 -0
- 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 +25 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +66 -12
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +18 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +16 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/workflow-tools.js +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/dist/native.js +22 -0
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +30 -0
- package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.js +30 -0
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +23 -17
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +25 -24
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/themes.js +1 -1
- package/packages/pi-coding-agent/dist/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/utils.d.ts +11 -0
- package/packages/pi-tui/dist/utils.d.ts.map +1 -1
- package/packages/pi-tui/dist/utils.js +119 -6
- package/packages/pi-tui/dist/utils.js.map +1 -1
- package/packages/pi-tui/package.json +2 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/themes.js +1 -1
- package/pkg/dist/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/index.ts +39 -22
- package/src/resources/extensions/browser-tools/state.ts +13 -0
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +57 -0
- package/src/resources/extensions/browser-tools/tools/session.ts +4 -2
- package/src/resources/extensions/browser-tools/utils.ts +3 -3
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/loop.ts +4 -2
- package/src/resources/extensions/gsd/auto/phases.ts +42 -10
- package/src/resources/extensions/gsd/auto/session.ts +22 -1
- package/src/resources/extensions/gsd/auto/workflow-kernel.ts +1 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +85 -12
- package/src/resources/extensions/gsd/auto-model-selection.ts +164 -12
- package/src/resources/extensions/gsd/auto-post-unit.ts +20 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +23 -20
- package/src/resources/extensions/gsd/auto-recovery.ts +22 -3
- package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
- package/src/resources/extensions/gsd/auto-start.ts +1 -1
- package/src/resources/extensions/gsd/auto.ts +13 -10
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +225 -72
- package/src/resources/extensions/gsd/closeout-wizard.ts +47 -13
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -17
- package/src/resources/extensions/gsd/commands-maintenance.ts +124 -13
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +2 -2
- package/src/resources/extensions/gsd/db-writer.ts +38 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +50 -1
- package/src/resources/extensions/gsd/gsd-db.ts +564 -186
- package/src/resources/extensions/gsd/markdown-renderer.ts +44 -66
- package/src/resources/extensions/gsd/md-importer.ts +49 -2
- package/src/resources/extensions/gsd/migration-auto-check.ts +154 -34
- package/src/resources/extensions/gsd/parsers-legacy.ts +20 -0
- package/src/resources/extensions/gsd/planning-path-scope.ts +22 -4
- package/src/resources/extensions/gsd/pre-execution-checks.ts +9 -2
- package/src/resources/extensions/gsd/preferences-models.ts +112 -43
- package/src/resources/extensions/gsd/preferences-types.ts +39 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +76 -2
- package/src/resources/extensions/gsd/preferences.ts +5 -0
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +6 -1
- package/src/resources/extensions/gsd/safety/content-validator.ts +8 -5
- package/src/resources/extensions/gsd/source-observations.ts +402 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +20 -8
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +44 -5
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +39 -11
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +45 -15
- package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +4 -4
- package/src/resources/extensions/gsd/state.ts +7 -4
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +299 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +75 -3
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +22 -1
- package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/closeout-wizard.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/content-validator.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +16 -2
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +1 -11
- package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +62 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +99 -2
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +101 -1
- package/src/resources/extensions/gsd/tests/repository-registry.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +162 -18
- package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/source-observations.test.ts +275 -0
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +76 -21
- package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +203 -0
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +170 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +306 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +73 -6
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +511 -1
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +44 -0
- package/src/resources/extensions/gsd/tool-contract.ts +28 -0
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +1 -11
- package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -6
- package/src/resources/extensions/gsd/tools/plan-slice.ts +54 -12
- package/src/resources/extensions/gsd/tools/plan-task.ts +8 -1
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +66 -526
- package/src/resources/extensions/gsd/types.ts +1 -0
- package/src/resources/extensions/gsd/uat-policy.ts +191 -0
- package/src/resources/extensions/gsd/uat-run.ts +550 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +3 -4
- package/src/resources/extensions/gsd/verdict-parser.ts +3 -10
- package/src/resources/extensions/gsd/workflow-manifest.ts +193 -7
- package/src/resources/extensions/gsd/workflow-projections.ts +9 -0
- package/src/resources/extensions/gsd/worktree-state-projection.ts +22 -22
- package/src/resources/extensions/shared/tests/format-utils.test.ts +8 -3
- package/src/resources/extensions/subagent/agents.ts +4 -0
- package/src/resources/extensions/subagent/index.ts +28 -3
- package/src/resources/extensions/subagent/launch.ts +8 -0
- package/src/resources/extensions/subagent/tests/model-override.test.ts +31 -0
- /package/dist/web/standalone/.next/static/{zzYMrKpPGfRQRxSFO32Jr → tJOKQbQRO-9MiFDO8DIDS}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{zzYMrKpPGfRQRxSFO32Jr → tJOKQbQRO-9MiFDO8DIDS}/_ssgManifest.js +0 -0
|
@@ -6,24 +6,70 @@ import {
|
|
|
6
6
|
readTransaction,
|
|
7
7
|
restoreManifest,
|
|
8
8
|
} from "./gsd-db.js";
|
|
9
|
-
import type { MilestoneRow } from "./db-milestone-artifact-rows.js";
|
|
9
|
+
import type { ArtifactRow, MilestoneRow } from "./db-milestone-artifact-rows.js";
|
|
10
10
|
import type { SliceRow, TaskRow } from "./db-task-slice-rows.js";
|
|
11
11
|
import type { VerificationEvidenceRow } from "./db-verification-evidence-rows.js";
|
|
12
|
-
import type { Decision } from "./types.js";
|
|
12
|
+
import type { Decision, GateRow, Requirement } from "./types.js";
|
|
13
13
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
14
|
+
import { getAllDecisionsFromMemories } from "./context-store.js";
|
|
15
|
+
import { backfillDecisionsToMemories } from "./memory-backfill.js";
|
|
16
|
+
import { invalidateAllCaches } from "./cache.js";
|
|
14
17
|
import { readFileSync, existsSync, mkdirSync } from "node:fs";
|
|
15
|
-
import { join } from "node:path";
|
|
18
|
+
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
16
19
|
|
|
17
20
|
// ─── Manifest Types ──────────────────────────────────────────────────────
|
|
18
21
|
|
|
22
|
+
export interface ManifestArtifactRow extends ArtifactRow {
|
|
23
|
+
content_hash: string | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface ReplanHistoryManifestRow {
|
|
27
|
+
id: number;
|
|
28
|
+
milestone_id: string;
|
|
29
|
+
slice_id: string | null;
|
|
30
|
+
task_id: string | null;
|
|
31
|
+
summary: string;
|
|
32
|
+
previous_artifact_path: string | null;
|
|
33
|
+
replacement_artifact_path: string | null;
|
|
34
|
+
created_at: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface AssessmentManifestRow {
|
|
38
|
+
path: string;
|
|
39
|
+
milestone_id: string;
|
|
40
|
+
slice_id: string | null;
|
|
41
|
+
task_id: string | null;
|
|
42
|
+
status: string;
|
|
43
|
+
scope: string;
|
|
44
|
+
full_content: string;
|
|
45
|
+
created_at: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface MilestoneCommitAttributionManifestRow {
|
|
49
|
+
commit_sha: string;
|
|
50
|
+
milestone_id: string;
|
|
51
|
+
slice_id: string | null;
|
|
52
|
+
task_id: string | null;
|
|
53
|
+
source: string;
|
|
54
|
+
confidence: number;
|
|
55
|
+
files_json: string;
|
|
56
|
+
created_at: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
19
59
|
export interface StateManifest {
|
|
20
60
|
version: 1;
|
|
21
61
|
exported_at: string; // ISO 8601
|
|
62
|
+
requirements?: Requirement[];
|
|
63
|
+
artifacts?: ManifestArtifactRow[];
|
|
22
64
|
milestones: MilestoneRow[];
|
|
23
65
|
slices: SliceRow[];
|
|
24
66
|
tasks: TaskRow[];
|
|
25
67
|
decisions: Decision[];
|
|
68
|
+
replan_history?: ReplanHistoryManifestRow[];
|
|
69
|
+
assessments?: AssessmentManifestRow[];
|
|
70
|
+
quality_gates?: GateRow[];
|
|
26
71
|
verification_evidence: VerificationEvidenceRow[];
|
|
72
|
+
milestone_commit_attributions?: MilestoneCommitAttributionManifestRow[];
|
|
27
73
|
}
|
|
28
74
|
|
|
29
75
|
// ─── helpers ─────────────────────────────────────────────────────────────
|
|
@@ -51,11 +97,26 @@ export function toNumeric(value: unknown, fallback: number | null = null): numbe
|
|
|
51
97
|
return fallback;
|
|
52
98
|
}
|
|
53
99
|
|
|
100
|
+
function mergeDecisionSurfaces(legacyDecisions: Decision[], memoryDecisions: Decision[]): Decision[] {
|
|
101
|
+
const byId = new Map<string, Decision>();
|
|
102
|
+
for (const decision of legacyDecisions) {
|
|
103
|
+
byId.set(decision.id, decision);
|
|
104
|
+
}
|
|
105
|
+
for (const decision of memoryDecisions) {
|
|
106
|
+
byId.set(decision.id, decision);
|
|
107
|
+
}
|
|
108
|
+
return Array.from(byId.values()).sort((a, b) => {
|
|
109
|
+
const seqDelta = (a.seq ?? 0) - (b.seq ?? 0);
|
|
110
|
+
return seqDelta === 0 ? a.id.localeCompare(b.id) : seqDelta;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
54
114
|
// ─── snapshotState ───────────────────────────────────────────────────────
|
|
55
115
|
|
|
56
116
|
/**
|
|
57
|
-
* Capture
|
|
58
|
-
*
|
|
117
|
+
* Capture DB-backed workflow state as a StateManifest.
|
|
118
|
+
* Runtime soft state and append-only audit streams stay outside this recovery
|
|
119
|
+
* substrate; correctness records and persisted evidence are included.
|
|
59
120
|
*
|
|
60
121
|
* Note: rows returned from raw queries are plain objects with TEXT columns for
|
|
61
122
|
* JSON arrays. We parse them into typed Row objects using the same logic as
|
|
@@ -67,6 +128,34 @@ export function snapshotState(): StateManifest {
|
|
|
67
128
|
// Wrap all reads in a deferred transaction so the snapshot is consistent
|
|
68
129
|
// (all SELECTs see the same DB state even if a concurrent write lands between them).
|
|
69
130
|
return readTransaction(() => {
|
|
131
|
+
const rawRequirements = db.prepare("SELECT * FROM requirements ORDER BY id").all() as Record<string, unknown>[];
|
|
132
|
+
const requirements: Requirement[] = rawRequirements.map((r) => ({
|
|
133
|
+
id: r["id"] as string,
|
|
134
|
+
class: (r["class"] as string) ?? "",
|
|
135
|
+
status: (r["status"] as string) ?? "",
|
|
136
|
+
description: (r["description"] as string) ?? "",
|
|
137
|
+
why: (r["why"] as string) ?? "",
|
|
138
|
+
source: (r["source"] as string) ?? "",
|
|
139
|
+
primary_owner: (r["primary_owner"] as string) ?? "",
|
|
140
|
+
supporting_slices: (r["supporting_slices"] as string) ?? "",
|
|
141
|
+
validation: (r["validation"] as string) ?? "",
|
|
142
|
+
notes: (r["notes"] as string) ?? "",
|
|
143
|
+
full_content: (r["full_content"] as string) ?? "",
|
|
144
|
+
superseded_by: (r["superseded_by"] as string) ?? null,
|
|
145
|
+
}));
|
|
146
|
+
|
|
147
|
+
const rawArtifacts = db.prepare("SELECT * FROM artifacts ORDER BY path").all() as Record<string, unknown>[];
|
|
148
|
+
const artifacts: ManifestArtifactRow[] = rawArtifacts.map((r) => ({
|
|
149
|
+
path: r["path"] as string,
|
|
150
|
+
artifact_type: (r["artifact_type"] as string) ?? "",
|
|
151
|
+
milestone_id: (r["milestone_id"] as string) ?? null,
|
|
152
|
+
slice_id: (r["slice_id"] as string) ?? null,
|
|
153
|
+
task_id: (r["task_id"] as string) ?? null,
|
|
154
|
+
full_content: (r["full_content"] as string) ?? "",
|
|
155
|
+
imported_at: (r["imported_at"] as string) ?? "",
|
|
156
|
+
content_hash: (r["content_hash"] as string) ?? null,
|
|
157
|
+
}));
|
|
158
|
+
|
|
70
159
|
const rawMilestones = db.prepare(
|
|
71
160
|
"SELECT * FROM milestones ORDER BY CASE WHEN sequence > 0 THEN 0 ELSE 1 END, sequence, id",
|
|
72
161
|
).all() as Record<string, unknown>[];
|
|
@@ -152,7 +241,7 @@ export function snapshotState(): StateManifest {
|
|
|
152
241
|
}));
|
|
153
242
|
|
|
154
243
|
const rawDecisions = db.prepare("SELECT * FROM decisions ORDER BY seq").all() as Record<string, unknown>[];
|
|
155
|
-
const
|
|
244
|
+
const legacyDecisions: Decision[] = rawDecisions.map((r) => ({
|
|
156
245
|
seq: toNumeric(r["seq"], 0) as number,
|
|
157
246
|
id: r["id"] as string,
|
|
158
247
|
when_context: (r["when_context"] as string) ?? "",
|
|
@@ -165,6 +254,45 @@ export function snapshotState(): StateManifest {
|
|
|
165
254
|
source: (r["source"] as string) ?? "discussion",
|
|
166
255
|
superseded_by: (r["superseded_by"] as string) ?? null,
|
|
167
256
|
}));
|
|
257
|
+
const decisions = mergeDecisionSurfaces(legacyDecisions, getAllDecisionsFromMemories());
|
|
258
|
+
|
|
259
|
+
const rawReplanHistory = db.prepare("SELECT * FROM replan_history ORDER BY id").all() as Record<string, unknown>[];
|
|
260
|
+
const replan_history: ReplanHistoryManifestRow[] = rawReplanHistory.map((r) => ({
|
|
261
|
+
id: toNumeric(r["id"], 0) as number,
|
|
262
|
+
milestone_id: (r["milestone_id"] as string) ?? "",
|
|
263
|
+
slice_id: (r["slice_id"] as string) ?? null,
|
|
264
|
+
task_id: (r["task_id"] as string) ?? null,
|
|
265
|
+
summary: (r["summary"] as string) ?? "",
|
|
266
|
+
previous_artifact_path: (r["previous_artifact_path"] as string) ?? null,
|
|
267
|
+
replacement_artifact_path: (r["replacement_artifact_path"] as string) ?? null,
|
|
268
|
+
created_at: (r["created_at"] as string) ?? "",
|
|
269
|
+
}));
|
|
270
|
+
|
|
271
|
+
const rawAssessments = db.prepare("SELECT * FROM assessments ORDER BY path").all() as Record<string, unknown>[];
|
|
272
|
+
const assessments: AssessmentManifestRow[] = rawAssessments.map((r) => ({
|
|
273
|
+
path: r["path"] as string,
|
|
274
|
+
milestone_id: (r["milestone_id"] as string) ?? "",
|
|
275
|
+
slice_id: (r["slice_id"] as string) ?? null,
|
|
276
|
+
task_id: (r["task_id"] as string) ?? null,
|
|
277
|
+
status: (r["status"] as string) ?? "",
|
|
278
|
+
scope: (r["scope"] as string) ?? "",
|
|
279
|
+
full_content: (r["full_content"] as string) ?? "",
|
|
280
|
+
created_at: (r["created_at"] as string) ?? "",
|
|
281
|
+
}));
|
|
282
|
+
|
|
283
|
+
const rawQualityGates = db.prepare("SELECT * FROM quality_gates ORDER BY milestone_id, slice_id, gate_id, task_id").all() as Record<string, unknown>[];
|
|
284
|
+
const quality_gates: GateRow[] = rawQualityGates.map((r) => ({
|
|
285
|
+
milestone_id: r["milestone_id"] as string,
|
|
286
|
+
slice_id: r["slice_id"] as string,
|
|
287
|
+
gate_id: r["gate_id"] as GateRow["gate_id"],
|
|
288
|
+
scope: r["scope"] as GateRow["scope"],
|
|
289
|
+
task_id: (r["task_id"] as string) ?? "",
|
|
290
|
+
status: r["status"] as GateRow["status"],
|
|
291
|
+
verdict: r["status"] === "pending" ? null : (r["verdict"] as GateRow["verdict"]),
|
|
292
|
+
rationale: (r["rationale"] as string) ?? "",
|
|
293
|
+
findings: (r["findings"] as string) ?? "",
|
|
294
|
+
evaluated_at: (r["evaluated_at"] as string) ?? null,
|
|
295
|
+
}));
|
|
168
296
|
|
|
169
297
|
const rawEvidence = db.prepare("SELECT * FROM verification_evidence ORDER BY id").all() as Record<string, unknown>[];
|
|
170
298
|
const verification_evidence: VerificationEvidenceRow[] = rawEvidence.map((r) => ({
|
|
@@ -179,14 +307,34 @@ export function snapshotState(): StateManifest {
|
|
|
179
307
|
created_at: r["created_at"] as string,
|
|
180
308
|
}));
|
|
181
309
|
|
|
310
|
+
const rawCommitAttributions = db.prepare(
|
|
311
|
+
"SELECT * FROM milestone_commit_attributions ORDER BY milestone_id, commit_sha",
|
|
312
|
+
).all() as Record<string, unknown>[];
|
|
313
|
+
const milestone_commit_attributions: MilestoneCommitAttributionManifestRow[] = rawCommitAttributions.map((r) => ({
|
|
314
|
+
commit_sha: r["commit_sha"] as string,
|
|
315
|
+
milestone_id: r["milestone_id"] as string,
|
|
316
|
+
slice_id: (r["slice_id"] as string) ?? null,
|
|
317
|
+
task_id: (r["task_id"] as string) ?? null,
|
|
318
|
+
source: (r["source"] as string) ?? "recorded",
|
|
319
|
+
confidence: toNumeric(r["confidence"], 1) as number,
|
|
320
|
+
files_json: (r["files_json"] as string) ?? "[]",
|
|
321
|
+
created_at: (r["created_at"] as string) ?? "",
|
|
322
|
+
}));
|
|
323
|
+
|
|
182
324
|
const result: StateManifest = {
|
|
183
325
|
version: 1,
|
|
184
326
|
exported_at: new Date().toISOString(),
|
|
327
|
+
requirements,
|
|
328
|
+
artifacts,
|
|
185
329
|
milestones,
|
|
186
330
|
slices,
|
|
187
331
|
tasks,
|
|
188
332
|
decisions,
|
|
333
|
+
replan_history,
|
|
334
|
+
assessments,
|
|
335
|
+
quality_gates,
|
|
189
336
|
verification_evidence,
|
|
337
|
+
milestone_commit_attributions,
|
|
190
338
|
};
|
|
191
339
|
|
|
192
340
|
return result;
|
|
@@ -232,20 +380,55 @@ export function readManifest(basePath: string): StateManifest | null {
|
|
|
232
380
|
throw new Error(`Unsupported manifest version: ${parsed.version}`);
|
|
233
381
|
}
|
|
234
382
|
|
|
235
|
-
// Validate required fields to avoid cryptic errors during restore
|
|
383
|
+
// Validate required fields to avoid cryptic errors during restore.
|
|
236
384
|
if (!Array.isArray(parsed.milestones) || !Array.isArray(parsed.slices) ||
|
|
237
385
|
!Array.isArray(parsed.tasks) || !Array.isArray(parsed.decisions) ||
|
|
238
386
|
!Array.isArray(parsed.verification_evidence)) {
|
|
239
387
|
throw new Error("Malformed manifest: missing or invalid required arrays");
|
|
240
388
|
}
|
|
241
389
|
|
|
390
|
+
for (const key of ["requirements", "artifacts", "replan_history", "assessments", "quality_gates", "milestone_commit_attributions"] as const) {
|
|
391
|
+
if (parsed[key] !== undefined && !Array.isArray(parsed[key])) {
|
|
392
|
+
throw new Error(`Malformed manifest: ${key} must be an array when present`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
242
396
|
return parsed;
|
|
243
397
|
}
|
|
244
398
|
|
|
399
|
+
function stripGsdPrefix(path: string): string {
|
|
400
|
+
return path.startsWith(".gsd/") ? path.slice(".gsd/".length) : path;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function artifactProjectionPath(basePath: string, artifactPath: string): string {
|
|
404
|
+
const gsdDir = resolve(basePath, ".gsd");
|
|
405
|
+
const fullPath = resolve(gsdDir, stripGsdPrefix(artifactPath));
|
|
406
|
+
const rel = relative(gsdDir, fullPath);
|
|
407
|
+
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
408
|
+
throw new Error(`Malformed manifest: artifact path escapes .gsd: ${artifactPath}`);
|
|
409
|
+
}
|
|
410
|
+
return fullPath;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function restoreArtifactProjections(basePath: string, manifest: StateManifest): void {
|
|
414
|
+
if (manifest.artifacts === undefined) return;
|
|
415
|
+
|
|
416
|
+
for (const artifact of manifest.artifacts) {
|
|
417
|
+
atomicWriteSync(
|
|
418
|
+
artifactProjectionPath(basePath, artifact.path),
|
|
419
|
+
artifact.full_content ?? "",
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
245
424
|
// ─── bootstrapFromManifest ──────────────────────────────────────────────
|
|
246
425
|
|
|
247
426
|
/**
|
|
248
427
|
* Read state-manifest.json and restore DB state from it.
|
|
428
|
+
* Rehydrates artifact projection files for restored artifacts so file-based
|
|
429
|
+
* fallback paths see the same evidence as the DB.
|
|
430
|
+
* Re-mirrors restored legacy decisions into memories so the ADR-013
|
|
431
|
+
* memory-backed decision readers see bootstrapped decisions immediately.
|
|
249
432
|
* Returns true if bootstrap succeeded, false if manifest file doesn't exist.
|
|
250
433
|
*/
|
|
251
434
|
export function bootstrapFromManifest(basePath: string): boolean {
|
|
@@ -256,5 +439,8 @@ export function bootstrapFromManifest(basePath: string): boolean {
|
|
|
256
439
|
}
|
|
257
440
|
|
|
258
441
|
restoreManifest(manifest);
|
|
442
|
+
restoreArtifactProjections(basePath, manifest);
|
|
443
|
+
backfillDecisionsToMemories();
|
|
444
|
+
invalidateAllCaches();
|
|
259
445
|
return true;
|
|
260
446
|
}
|
|
@@ -546,6 +546,15 @@ export async function regenerateIfMissing(
|
|
|
546
546
|
return false;
|
|
547
547
|
}
|
|
548
548
|
|
|
549
|
+
// A sketch slice (or any slice not yet planned into tasks) legitimately has
|
|
550
|
+
// no PLAN.md to project. renderPlanFromDb throws on a zero-task slice, so
|
|
551
|
+
// skip cleanly here rather than logging a spurious failure. The PLAN.md will
|
|
552
|
+
// be created once the slice is refined and its first task is written through
|
|
553
|
+
// the single writer.
|
|
554
|
+
if (fileType === "PLAN" && getSliceTasks(milestoneId, sliceId).length === 0) {
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
|
|
549
558
|
// Regenerate the missing file. Each renderer may swallow its own errors
|
|
550
559
|
// (e.g. renderStateProjection), so confirm the file actually exists on
|
|
551
560
|
// disk before reporting success — true must mean "file is there now".
|
|
@@ -123,36 +123,29 @@ function forceOverwriteAssessmentsWithVerdict(
|
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
function
|
|
126
|
+
function syncOtherMilestoneArtifacts(
|
|
127
127
|
srcMilestonesDir: string,
|
|
128
128
|
dstMilestonesDir: string,
|
|
129
|
+
currentMilestoneId: string,
|
|
129
130
|
): void {
|
|
130
131
|
if (!existsSync(srcMilestonesDir)) return;
|
|
131
132
|
|
|
132
133
|
try {
|
|
133
134
|
for (const milestoneEntry of readdirSync(srcMilestonesDir, { withFileTypes: true })) {
|
|
134
135
|
if (!milestoneEntry.isDirectory()) continue;
|
|
136
|
+
// The current milestone is already fully projected by the caller's
|
|
137
|
+
// additive safeCopyRecursive; skip it here to avoid redundant work.
|
|
138
|
+
if (milestoneEntry.name === currentMilestoneId) continue;
|
|
135
139
|
const srcMilestoneDir = join(srcMilestonesDir, milestoneEntry.name);
|
|
136
140
|
const dstMilestoneDir = join(dstMilestonesDir, milestoneEntry.name);
|
|
137
141
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
join(srcMilestoneDir, fileEntry.name),
|
|
146
|
-
join(dstMilestoneDir, fileEntry.name),
|
|
147
|
-
{ force: false },
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
} catch (err) {
|
|
151
|
-
logWarning(
|
|
152
|
-
"worktree",
|
|
153
|
-
`milestone top-level artifact sync failed (${milestoneEntry.name}): ${err instanceof Error ? err.message : String(err)}`,
|
|
154
|
-
);
|
|
155
|
-
}
|
|
142
|
+
// Additively project the entire milestone subtree (force:false), not just
|
|
143
|
+
// top-level files. Prior completed milestones keep their per-slice and
|
|
144
|
+
// per-task SUMMARY.md / UAT.md on disk so the worktree's stale-render
|
|
145
|
+
// detector doesn't flag them as missing (DB has summary, disk doesn't).
|
|
146
|
+
// force:false preserves any worktree-local files (#1886 invariant) and
|
|
147
|
+
// only fills in files absent from the worktree projection.
|
|
148
|
+
safeCopyRecursive(srcMilestoneDir, dstMilestoneDir, { force: false });
|
|
156
149
|
}
|
|
157
150
|
} catch (err) {
|
|
158
151
|
logWarning(
|
|
@@ -248,9 +241,16 @@ export function _projectRootToWorktreeImpl(
|
|
|
248
241
|
{ force: false },
|
|
249
242
|
);
|
|
250
243
|
|
|
251
|
-
// Additively project
|
|
252
|
-
//
|
|
253
|
-
|
|
244
|
+
// Additively project the full subtree of every OTHER milestone so
|
|
245
|
+
// worktree-bound units can read prior-milestone context artifacts and so
|
|
246
|
+
// completed milestones retain their per-slice/per-task SUMMARY.md and
|
|
247
|
+
// UAT.md on the worktree filesystem (otherwise the stale-render detector
|
|
248
|
+
// flags them as "complete in DB but missing on disk").
|
|
249
|
+
syncOtherMilestoneArtifacts(
|
|
250
|
+
join(prGsd, "milestones"),
|
|
251
|
+
join(wtGsd, "milestones"),
|
|
252
|
+
milestoneId,
|
|
253
|
+
);
|
|
254
254
|
|
|
255
255
|
// Force-sync ASSESSMENT files that have a verdict from project root (#2821).
|
|
256
256
|
// The additive-only copy above preserves worktree-local files, but
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
centerLine,
|
|
12
12
|
fitColumns,
|
|
13
13
|
} from "../layout-utils.js";
|
|
14
|
+
import { visibleWidth } from "@gsd/pi-tui";
|
|
14
15
|
|
|
15
16
|
describe("formatDuration", () => {
|
|
16
17
|
it("formats seconds", () => {
|
|
@@ -59,8 +60,10 @@ describe("joinColumns", () => {
|
|
|
59
60
|
|
|
60
61
|
it("truncates when content overflows", () => {
|
|
61
62
|
const result = joinColumns("a".repeat(20), "b".repeat(20), 30);
|
|
62
|
-
//
|
|
63
|
-
|
|
63
|
+
// truncateToWidth is ANSI-aware and brackets the ellipsis with zero-width
|
|
64
|
+
// SGR resets, so the visible width — not the raw string length — is the
|
|
65
|
+
// invariant that must hold within the column budget.
|
|
66
|
+
assert.ok(visibleWidth(result) <= 30);
|
|
64
67
|
});
|
|
65
68
|
});
|
|
66
69
|
|
|
@@ -72,7 +75,9 @@ describe("centerLine", () => {
|
|
|
72
75
|
|
|
73
76
|
it("truncates when content exceeds width", () => {
|
|
74
77
|
const result = centerLine("abcdefgh", 4);
|
|
75
|
-
|
|
78
|
+
// Visible width is the meaningful budget; the result may carry zero-width
|
|
79
|
+
// SGR reset codes around the ellipsis (see truncateToWidth).
|
|
80
|
+
assert.ok(visibleWidth(result) <= 4);
|
|
76
81
|
});
|
|
77
82
|
});
|
|
78
83
|
|
|
@@ -15,6 +15,8 @@ export interface AgentConfig {
|
|
|
15
15
|
description: string;
|
|
16
16
|
tools?: string[];
|
|
17
17
|
model?: string;
|
|
18
|
+
/** Default reasoning effort for this agent, forwarded as `--thinking` (#508). */
|
|
19
|
+
thinking?: string;
|
|
18
20
|
conflictsWith?: string[];
|
|
19
21
|
systemPrompt: string;
|
|
20
22
|
source: "user" | "project";
|
|
@@ -31,6 +33,7 @@ interface AgentFrontmatter extends Record<string, unknown> {
|
|
|
31
33
|
description?: string;
|
|
32
34
|
tools?: string | string[];
|
|
33
35
|
model?: string;
|
|
36
|
+
thinking?: string;
|
|
34
37
|
conflicts_with?: string;
|
|
35
38
|
}
|
|
36
39
|
|
|
@@ -100,6 +103,7 @@ function loadAgentsFromDir(dir: string, source: "user" | "project"): AgentConfig
|
|
|
100
103
|
description: frontmatter.description,
|
|
101
104
|
tools: tools && tools.length > 0 ? tools : undefined,
|
|
102
105
|
model: frontmatter.model,
|
|
106
|
+
thinking: typeof frontmatter.thinking === "string" ? frontmatter.thinking : undefined,
|
|
103
107
|
conflictsWith,
|
|
104
108
|
systemPrompt: body,
|
|
105
109
|
source,
|
|
@@ -341,6 +341,7 @@ interface TaskParam {
|
|
|
341
341
|
task: string;
|
|
342
342
|
cwd?: string;
|
|
343
343
|
model?: string;
|
|
344
|
+
thinking?: string;
|
|
344
345
|
context?: SubagentContextMode;
|
|
345
346
|
}
|
|
346
347
|
|
|
@@ -416,6 +417,9 @@ async function runSingleAgent(
|
|
|
416
417
|
parentSessionManager?: Parameters<typeof createSubagentLaunchPlan>[0]["parentSessionManager"],
|
|
417
418
|
sessionOverride?: SubagentSessionArgs,
|
|
418
419
|
trackingName?: string,
|
|
420
|
+
// Trailing param (kept after trackingName so existing positional call sites
|
|
421
|
+
// don't shift). Reasoning effort forwarded to the child (#508).
|
|
422
|
+
thinkingOverride?: string,
|
|
419
423
|
): Promise<SingleResult> {
|
|
420
424
|
const agent = agents.find((a) => a.name === agentName);
|
|
421
425
|
|
|
@@ -489,6 +493,7 @@ async function runSingleAgent(
|
|
|
489
493
|
task,
|
|
490
494
|
tmpPromptPath,
|
|
491
495
|
modelOverride,
|
|
496
|
+
thinkingOverride,
|
|
492
497
|
contextMode,
|
|
493
498
|
parentSessionManager,
|
|
494
499
|
session: sessionOverride,
|
|
@@ -581,10 +586,12 @@ async function runSingleAgentInCmuxSplit(
|
|
|
581
586
|
parentSessionManager?: Parameters<typeof createSubagentLaunchPlan>[0]["parentSessionManager"],
|
|
582
587
|
sessionOverride?: SubagentSessionArgs,
|
|
583
588
|
trackingName?: string,
|
|
589
|
+
// Trailing param (see runSingleAgent). Reasoning effort forwarded to the child (#508).
|
|
590
|
+
thinkingOverride?: string,
|
|
584
591
|
): Promise<SingleResult> {
|
|
585
592
|
const agent = agents.find((a) => a.name === agentName);
|
|
586
593
|
if (!agent) {
|
|
587
|
-
return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode, parentSessionManager, sessionOverride, trackingName);
|
|
594
|
+
return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode, parentSessionManager, sessionOverride, trackingName, thinkingOverride);
|
|
588
595
|
}
|
|
589
596
|
|
|
590
597
|
let tmpPromptDir: string | null = null;
|
|
@@ -631,7 +638,7 @@ async function runSingleAgentInCmuxSplit(
|
|
|
631
638
|
? await cmuxClient.createSplit(directionOrSurfaceId as "right" | "down" | "left" | "up")
|
|
632
639
|
: directionOrSurfaceId;
|
|
633
640
|
if (!cmuxSurfaceId) {
|
|
634
|
-
return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode, parentSessionManager, sessionOverride, trackingName);
|
|
641
|
+
return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode, parentSessionManager, sessionOverride, trackingName, thinkingOverride);
|
|
635
642
|
}
|
|
636
643
|
|
|
637
644
|
const bundledPaths = (process.env.GSD_BUNDLED_EXTENSION_PATHS ?? "").split(path.delimiter).map((s) => s.trim()).filter(Boolean);
|
|
@@ -641,6 +648,7 @@ async function runSingleAgentInCmuxSplit(
|
|
|
641
648
|
task,
|
|
642
649
|
tmpPromptPath,
|
|
643
650
|
modelOverride,
|
|
651
|
+
thinkingOverride,
|
|
644
652
|
contextMode,
|
|
645
653
|
parentSessionManager,
|
|
646
654
|
session: sessionOverride,
|
|
@@ -665,7 +673,7 @@ async function runSingleAgentInCmuxSplit(
|
|
|
665
673
|
|
|
666
674
|
const sent = await cmuxClient.sendSurface(cmuxSurfaceId, `bash -lc ${shellEscape(innerScript)}`);
|
|
667
675
|
if (!sent) {
|
|
668
|
-
return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode, parentSessionManager, sessionOverride, trackingName);
|
|
676
|
+
return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails, modelOverride, contextMode, parentSessionManager, sessionOverride, trackingName, thinkingOverride);
|
|
669
677
|
}
|
|
670
678
|
|
|
671
679
|
const finished = await waitForFile(exitPath, signal);
|
|
@@ -726,11 +734,18 @@ async function runSingleAgentInCmuxSplit(
|
|
|
726
734
|
}
|
|
727
735
|
}
|
|
728
736
|
|
|
737
|
+
const ThinkingLevelSchema = StringEnum(["off", "minimal", "low", "medium", "high", "xhigh"] as const, {
|
|
738
|
+
description:
|
|
739
|
+
"Reasoning effort override for the subagent (forwarded as --thinking). " +
|
|
740
|
+
"Independent of model choice; unsupported levels are clamped to the model at dispatch.",
|
|
741
|
+
});
|
|
742
|
+
|
|
729
743
|
const TaskItem = Type.Object({
|
|
730
744
|
agent: Type.String({ description: "Name of the agent to invoke" }),
|
|
731
745
|
task: Type.String({ description: "Task to delegate to the agent" }),
|
|
732
746
|
cwd: Type.Optional(Type.String({ description: "Working directory for the agent process" })),
|
|
733
747
|
model: Type.Optional(Type.String({ description: "Model override for this task (e.g. 'claude-sonnet-4-6')" })),
|
|
748
|
+
thinking: Type.Optional(ThinkingLevelSchema),
|
|
734
749
|
context: Type.Optional(StringEnum(["fresh", "fork"] as const, {
|
|
735
750
|
description: 'Context mode for this task (see context field on the top-level params).',
|
|
736
751
|
default: "fresh",
|
|
@@ -742,6 +757,7 @@ const ChainItem = Type.Object({
|
|
|
742
757
|
task: Type.String({ description: "Task with optional {previous} placeholder for prior step output" }),
|
|
743
758
|
cwd: Type.Optional(Type.String({ description: "Working directory for the agent process" })),
|
|
744
759
|
model: Type.Optional(Type.String({ description: "Model override for this step (e.g. 'claude-sonnet-4-6')" })),
|
|
760
|
+
thinking: Type.Optional(ThinkingLevelSchema),
|
|
745
761
|
context: Type.Optional(StringEnum(["fresh", "fork"] as const, {
|
|
746
762
|
description: 'Context mode for this step (see context field on the top-level params).',
|
|
747
763
|
default: "fresh",
|
|
@@ -779,6 +795,7 @@ const SubagentParams = Type.Object({
|
|
|
779
795
|
),
|
|
780
796
|
cwd: Type.Optional(Type.String({ description: "Working directory for the agent process (single mode)" })),
|
|
781
797
|
model: Type.Optional(Type.String({ description: "Model override for the subagent (e.g. 'claude-sonnet-4-6'). Takes precedence over the agent's frontmatter model." })),
|
|
798
|
+
thinking: Type.Optional(ThinkingLevelSchema),
|
|
782
799
|
isolated: Type.Optional(
|
|
783
800
|
Type.Boolean({
|
|
784
801
|
description:
|
|
@@ -930,6 +947,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
930
947
|
ctx.sessionManager,
|
|
931
948
|
{ mode: "fork", sessionFile: selected.sessionFile, sessionDir: path.dirname(selected.sessionFile) },
|
|
932
949
|
selected.trackingName,
|
|
950
|
+
params.thinking,
|
|
933
951
|
);
|
|
934
952
|
return {
|
|
935
953
|
content: [{ type: "text", text: getFinalOutput(result.messages) || result.errorMessage || result.stderr || "(no output)" }],
|
|
@@ -1244,6 +1262,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1244
1262
|
ctx.sessionManager,
|
|
1245
1263
|
undefined,
|
|
1246
1264
|
dispatchTrackingNames[0],
|
|
1265
|
+
params.thinking,
|
|
1247
1266
|
);
|
|
1248
1267
|
if (isolation && result.exitCode === 0) {
|
|
1249
1268
|
const patches = await isolation.captureDelta();
|
|
@@ -1317,6 +1336,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1317
1336
|
ctx.sessionManager,
|
|
1318
1337
|
undefined,
|
|
1319
1338
|
dispatchTrackingNames[i],
|
|
1339
|
+
step.thinking || params.thinking,
|
|
1320
1340
|
);
|
|
1321
1341
|
results.push(result);
|
|
1322
1342
|
persistRunResults(results);
|
|
@@ -1397,6 +1417,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1397
1417
|
const results = await mapWithConcurrencyLimit(taskParams, MAX_CONCURRENCY, async (t, index) => {
|
|
1398
1418
|
const workerId = registerWorker(t.agent, t.task, index, batchSize, batchId);
|
|
1399
1419
|
const taskModel = t.model || params.model;
|
|
1420
|
+
const taskThinking = t.thinking || params.thinking;
|
|
1400
1421
|
const updateParallelResult = (partial: AgentToolResult<SubagentDetails>) => {
|
|
1401
1422
|
if (partial.details?.results[0]) {
|
|
1402
1423
|
allResults[index] = partial.details.results[0];
|
|
@@ -1422,6 +1443,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1422
1443
|
ctx.sessionManager,
|
|
1423
1444
|
undefined,
|
|
1424
1445
|
dispatchTrackingNames[index],
|
|
1446
|
+
taskThinking,
|
|
1425
1447
|
)
|
|
1426
1448
|
: runSingleAgent(
|
|
1427
1449
|
ctx.cwd,
|
|
@@ -1438,6 +1460,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1438
1460
|
ctx.sessionManager,
|
|
1439
1461
|
undefined,
|
|
1440
1462
|
dispatchTrackingNames[index],
|
|
1463
|
+
taskThinking,
|
|
1441
1464
|
);
|
|
1442
1465
|
const runTask = async () => {
|
|
1443
1466
|
let isolation: IsolationEnvironment | null = null;
|
|
@@ -1536,6 +1559,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1536
1559
|
ctx.sessionManager,
|
|
1537
1560
|
undefined,
|
|
1538
1561
|
dispatchTrackingNames[0],
|
|
1562
|
+
params.thinking,
|
|
1539
1563
|
)
|
|
1540
1564
|
: await runSingleAgent(
|
|
1541
1565
|
ctx.cwd,
|
|
@@ -1552,6 +1576,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1552
1576
|
ctx.sessionManager,
|
|
1553
1577
|
undefined,
|
|
1554
1578
|
dispatchTrackingNames[0],
|
|
1579
|
+
params.thinking,
|
|
1555
1580
|
);
|
|
1556
1581
|
finalResults = [result];
|
|
1557
1582
|
|
|
@@ -25,6 +25,8 @@ export interface SubagentLaunchInput {
|
|
|
25
25
|
task: string;
|
|
26
26
|
tmpPromptPath: string | null;
|
|
27
27
|
modelOverride?: string;
|
|
28
|
+
/** Reasoning effort override forwarded as `--thinking` (ADR-026 / #508). */
|
|
29
|
+
thinkingOverride?: string;
|
|
28
30
|
contextMode?: SubagentContextMode;
|
|
29
31
|
parentSessionManager?: SubagentParentSessionManager;
|
|
30
32
|
session?: SubagentSessionArgs;
|
|
@@ -60,6 +62,7 @@ export function buildSubagentProcessArgs(
|
|
|
60
62
|
task: string,
|
|
61
63
|
tmpPromptPath: string | null,
|
|
62
64
|
modelOverride?: string,
|
|
65
|
+
thinkingOverride?: string,
|
|
63
66
|
session: SubagentSessionArgs = { mode: "fresh" },
|
|
64
67
|
): string[] {
|
|
65
68
|
const args: string[] = ["--mode", "json", "-p"];
|
|
@@ -71,6 +74,10 @@ export function buildSubagentProcessArgs(
|
|
|
71
74
|
}
|
|
72
75
|
const effectiveModel = modelOverride ?? agent.model;
|
|
73
76
|
if (effectiveModel) args.push("--model", effectiveModel);
|
|
77
|
+
// Reasoning effort travels with the model (ADR-026 / #508). The child CLI
|
|
78
|
+
// validates `--thinking` and clamps to the resolved model at dispatch.
|
|
79
|
+
const effectiveThinking = thinkingOverride ?? agent.thinking;
|
|
80
|
+
if (effectiveThinking) args.push("--thinking", effectiveThinking);
|
|
74
81
|
if (agent.tools && agent.tools.length > 0) args.push("--tools", agent.tools.join(","));
|
|
75
82
|
if (tmpPromptPath) args.push("--append-system-prompt", tmpPromptPath);
|
|
76
83
|
args.push(`Task: ${task}`);
|
|
@@ -122,6 +129,7 @@ export function createSubagentLaunchPlan(input: SubagentLaunchInput): SubagentLa
|
|
|
122
129
|
input.task,
|
|
123
130
|
input.tmpPromptPath,
|
|
124
131
|
input.modelOverride,
|
|
132
|
+
input.thinkingOverride,
|
|
125
133
|
session,
|
|
126
134
|
),
|
|
127
135
|
env: buildSubagentProcessEnv(),
|
|
@@ -53,3 +53,34 @@ describe("buildSubagentProcessArgs model override", () => {
|
|
|
53
53
|
assert.equal(args[modelIndex + 1], "model-override");
|
|
54
54
|
});
|
|
55
55
|
});
|
|
56
|
+
|
|
57
|
+
describe("buildSubagentProcessArgs thinking override (#508)", () => {
|
|
58
|
+
it("forwards thinkingOverride as --thinking", () => {
|
|
59
|
+
const args = buildSubagentProcessArgs(makeAgent(), "task", null, undefined, "low");
|
|
60
|
+
const idx = args.indexOf("--thinking");
|
|
61
|
+
assert.notEqual(idx, -1, "should include --thinking flag");
|
|
62
|
+
assert.equal(args[idx + 1], "low");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("falls back to agent.thinking when no override provided", () => {
|
|
66
|
+
const args = buildSubagentProcessArgs(makeAgent({ thinking: "high" }), "task", null);
|
|
67
|
+
const idx = args.indexOf("--thinking");
|
|
68
|
+
assert.equal(args[idx + 1], "high");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("override takes precedence over agent.thinking", () => {
|
|
72
|
+
const args = buildSubagentProcessArgs(makeAgent({ thinking: "high" }), "task", null, undefined, "minimal");
|
|
73
|
+
assert.equal(args[args.indexOf("--thinking") + 1], "minimal");
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("omits --thinking when neither override nor agent.thinking is set", () => {
|
|
77
|
+
const args = buildSubagentProcessArgs(makeAgent(), "task", null);
|
|
78
|
+
assert.equal(args.indexOf("--thinking"), -1, "should not include --thinking flag");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("forwards both model and thinking together", () => {
|
|
82
|
+
const args = buildSubagentProcessArgs(makeAgent(), "task", null, "model-x", "xhigh");
|
|
83
|
+
assert.equal(args[args.indexOf("--model") + 1], "model-x");
|
|
84
|
+
assert.equal(args[args.indexOf("--thinking") + 1], "xhigh");
|
|
85
|
+
});
|
|
86
|
+
});
|
|
File without changes
|
|
File without changes
|