gsd-pi 2.81.0-dev.72a81bdf3 → 2.82.0-dev.2841a1e44
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 +49 -30
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/GSD-WORKFLOW.md +3 -1
- package/dist/resources/extensions/browser-tools/tools/screenshot.js +1 -0
- package/dist/resources/extensions/browser-tools/tools/zoom.js +1 -0
- package/dist/resources/extensions/cmux/index.js +5 -0
- package/dist/resources/extensions/gsd/auto/orchestrator.js +113 -6
- package/dist/resources/extensions/gsd/auto/phases.js +9 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +169 -124
- package/dist/resources/extensions/gsd/auto-prompts.js +13 -5
- package/dist/resources/extensions/gsd/auto-verification.js +28 -22
- package/dist/resources/extensions/gsd/auto.js +128 -52
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +5 -0
- package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +16 -7
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +55 -12
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +3 -1
- package/dist/resources/extensions/gsd/clean-root-preflight.js +170 -8
- package/dist/resources/extensions/gsd/commands/catalog.js +4 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +22 -1
- package/dist/resources/extensions/gsd/commands-bootstrap.js +5 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +15 -2
- package/dist/resources/extensions/gsd/context-store.js +112 -0
- package/dist/resources/extensions/gsd/db-writer.js +150 -84
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/doctor-git-checks.js +41 -6
- package/dist/resources/extensions/gsd/knowledge-backfill.js +144 -0
- package/dist/resources/extensions/gsd/knowledge-capture.js +136 -0
- package/dist/resources/extensions/gsd/knowledge-parser.js +154 -0
- package/dist/resources/extensions/gsd/knowledge-projection.js +210 -0
- package/dist/resources/extensions/gsd/markdown-renderer.js +6 -1
- package/dist/resources/extensions/gsd/md-importer.js +1 -1
- package/dist/resources/extensions/gsd/memory-backfill.js +73 -17
- package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +222 -0
- package/dist/resources/extensions/gsd/migrate/command.js +5 -0
- package/dist/resources/extensions/gsd/migrate/preview.js +9 -0
- package/dist/resources/extensions/gsd/migrate/transformer.js +51 -4
- package/dist/resources/extensions/gsd/migrate/writer.js +11 -1
- package/dist/resources/extensions/gsd/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/provider-switch-observer.js +146 -0
- package/dist/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +119 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +25 -2
- package/dist/resources/extensions/gsd/verification-verdict.js +26 -0
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +21 -2
- package/dist/resources/extensions/subagent/index.js +448 -78
- package/dist/resources/extensions/subagent/launch.js +77 -0
- package/dist/resources/extensions/subagent/run-store.js +148 -0
- package/dist/resources/extensions/visual-brief/artifact-policy.js +29 -0
- package/dist/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/dist/resources/extensions/visual-brief/index.js +5 -0
- package/dist/resources/extensions/visual-brief/page-contract.js +122 -0
- package/dist/resources/extensions/visual-brief/prompts.js +111 -0
- 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 +15 -15
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- 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/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +2 -2
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +2 -2
- 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 +2 -2
- 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 +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-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/.next/static/chunks/2973.33f26573894b6153.js +2 -0
- package/dist/web/standalone/.next/static/chunks/{8359.e059d86b255fce1c.js → 8359.7eb3bb8f8ecf4c01.js} +2 -2
- package/dist/web/standalone/.next/static/chunks/{webpack-de742b64187e13fe.js → webpack-6a95bc41e0f7ec89.js} +1 -1
- package/dist/web/standalone/.next/static/css/0262768ec1b89d34.css +1 -0
- package/package.json +5 -4
- package/packages/contracts/dist/rpc.test.js +7 -0
- package/packages/contracts/dist/rpc.test.js.map +1 -1
- package/packages/contracts/dist/workflow.d.ts +21 -0
- package/packages/contracts/dist/workflow.d.ts.map +1 -1
- package/packages/contracts/dist/workflow.js +24 -0
- package/packages/contracts/dist/workflow.js.map +1 -1
- package/packages/contracts/src/rpc.test.ts +8 -0
- package/packages/contracts/src/workflow.ts +24 -0
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/README.md +14 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts +0 -3
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +80 -0
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/workflow-tools-parity.test.ts +244 -0
- package/packages/mcp-server/src/workflow-tools.test.ts +22 -0
- package/packages/mcp-server/src/workflow-tools.ts +168 -0
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/index.d.ts +2 -2
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -1
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.d.ts +11 -0
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +20 -0
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/src/index.ts +7 -2
- package/packages/pi-ai/src/providers/transform-messages.ts +24 -0
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +4 -4
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js +17 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-file-safety.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/system-prompt.ts +4 -4
- package/packages/pi-coding-agent/src/tests/system-prompt-file-safety.test.ts +22 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +5 -0
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/tui.ts +6 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/GSD-WORKFLOW.md +3 -1
- package/src/resources/extensions/browser-tools/tools/screenshot.ts +1 -0
- package/src/resources/extensions/browser-tools/tools/zoom.ts +1 -0
- package/src/resources/extensions/cmux/index.ts +6 -0
- package/src/resources/extensions/gsd/auto/contracts.ts +46 -11
- package/src/resources/extensions/gsd/auto/orchestrator.ts +118 -6
- package/src/resources/extensions/gsd/auto/phases.ts +14 -0
- package/src/resources/extensions/gsd/auto-post-unit.ts +194 -137
- package/src/resources/extensions/gsd/auto-prompts.ts +13 -5
- package/src/resources/extensions/gsd/auto-verification.ts +36 -34
- package/src/resources/extensions/gsd/auto.ts +136 -51
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +6 -0
- package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +16 -6
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +58 -15
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +3 -2
- package/src/resources/extensions/gsd/clean-root-preflight.ts +174 -8
- package/src/resources/extensions/gsd/commands/catalog.ts +4 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +25 -1
- package/src/resources/extensions/gsd/commands-bootstrap.ts +10 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +19 -2
- package/src/resources/extensions/gsd/context-store.ts +120 -1
- package/src/resources/extensions/gsd/db-writer.ts +167 -84
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/doctor-git-checks.ts +44 -6
- package/src/resources/extensions/gsd/doctor-types.ts +2 -0
- package/src/resources/extensions/gsd/knowledge-backfill.ts +164 -0
- package/src/resources/extensions/gsd/knowledge-capture.ts +160 -0
- package/src/resources/extensions/gsd/knowledge-parser.ts +174 -0
- package/src/resources/extensions/gsd/knowledge-projection.ts +241 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +6 -1
- package/src/resources/extensions/gsd/md-importer.ts +1 -1
- package/src/resources/extensions/gsd/memory-backfill.ts +89 -17
- package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +277 -0
- package/src/resources/extensions/gsd/migrate/command.ts +5 -0
- package/src/resources/extensions/gsd/migrate/preview.ts +10 -0
- package/src/resources/extensions/gsd/migrate/transformer.ts +58 -4
- package/src/resources/extensions/gsd/migrate/writer.ts +14 -1
- package/src/resources/extensions/gsd/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/provider-switch-observer.ts +185 -0
- package/src/resources/extensions/gsd/templates/knowledge.md +2 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +408 -4
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +6 -5
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/brief-command.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/browser-tools-compatibility-declarations.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +107 -2
- package/src/resources/extensions/gsd/tests/closeout-git-deferral.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/context-store-decisions-from-memories.test.ts +312 -0
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +13 -8
- package/src/resources/extensions/gsd/tests/decisions-projection-from-memories.test.ts +453 -0
- package/src/resources/extensions/gsd/tests/decisions-stop-table-writes.test.ts +348 -0
- package/src/resources/extensions/gsd/tests/evidence-cross-ref.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +8 -4
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/integration/doctor-git.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/integration/integration-lifecycle.test.ts +13 -5
- package/src/resources/extensions/gsd/tests/integration/migrate-command.test.ts +48 -3
- package/src/resources/extensions/gsd/tests/knowledge-backfill-projection.test.ts +323 -0
- package/src/resources/extensions/gsd/tests/knowledge-capture.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -2
- package/src/resources/extensions/gsd/tests/load-knowledge-block-rules-only.test.ts +209 -0
- package/src/resources/extensions/gsd/tests/memory-consolidation-scanner.test.ts +316 -0
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +5 -1
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/plan-milestone-sketch-render.test.ts +157 -0
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +79 -1
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/provider-switch-observer.test.ts +252 -0
- package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +16 -4
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +16 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +135 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +35 -2
- package/src/resources/extensions/gsd/verification-verdict.ts +47 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +4 -0
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +20 -2
- package/src/resources/extensions/subagent/index.ts +567 -103
- package/src/resources/extensions/subagent/launch.ts +131 -0
- package/src/resources/extensions/subagent/run-store.ts +218 -0
- package/src/resources/extensions/subagent/tests/launch.test.ts +115 -0
- package/src/resources/extensions/subagent/tests/run-store.test.ts +111 -0
- package/src/resources/extensions/visual-brief/artifact-policy.ts +41 -0
- package/src/resources/extensions/visual-brief/extension-manifest.json +8 -0
- package/src/resources/extensions/visual-brief/index.ts +8 -0
- package/src/resources/extensions/visual-brief/page-contract.ts +134 -0
- package/src/resources/extensions/visual-brief/prompts.ts +147 -0
- package/src/resources/extensions/visual-brief/tests/visual-brief.test.ts +172 -0
- package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +0 -1
- package/dist/web/standalone/.next/static/css/54ec2745c1da488b.css +0 -1
- /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → Qgr2B_MRhPxC0z8fwv4vT}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{rIkMv4YSNlfSeqmGqWVns → Qgr2B_MRhPxC0z8fwv4vT}/_ssgManifest.js +0 -0
|
@@ -2,27 +2,31 @@
|
|
|
2
2
|
// File Purpose: Auto Orchestration module interfaces and ADR-015 invariant adapter contracts.
|
|
3
3
|
|
|
4
4
|
import type { GSDState } from "../types.js";
|
|
5
|
+
import type { MinimalModelRegistry } from "../context-budget.js";
|
|
5
6
|
|
|
6
7
|
export interface AutoSessionContext {
|
|
7
8
|
basePath: string;
|
|
8
9
|
trigger: "guided-flow" | "resume" | "auto-loop" | "manual";
|
|
9
10
|
}
|
|
10
11
|
|
|
12
|
+
export interface UnitRef {
|
|
13
|
+
unitType: string;
|
|
14
|
+
unitId: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
11
17
|
export interface AutoStatus {
|
|
12
18
|
phase: "idle" | "running" | "paused" | "stopped" | "error";
|
|
13
|
-
activeUnit?:
|
|
14
|
-
unitType: string;
|
|
15
|
-
unitId: string;
|
|
16
|
-
};
|
|
19
|
+
activeUnit?: UnitRef;
|
|
17
20
|
lastTransitionAt?: number;
|
|
18
21
|
transitionCount: number;
|
|
19
22
|
}
|
|
20
23
|
|
|
21
|
-
export
|
|
22
|
-
kind: "advanced"
|
|
23
|
-
reason
|
|
24
|
-
stateSnapshot?: GSDState
|
|
25
|
-
}
|
|
24
|
+
export type AutoAdvanceResult =
|
|
25
|
+
| { kind: "advanced"; unit: UnitRef; stateSnapshot: GSDState }
|
|
26
|
+
| { kind: "blocked"; reason: string; action: "pause" | "stop"; stateSnapshot?: GSDState }
|
|
27
|
+
| { kind: "stopped"; reason: string; stateSnapshot?: GSDState }
|
|
28
|
+
| { kind: "paused"; reason: string }
|
|
29
|
+
| { kind: "error"; reason: string };
|
|
26
30
|
|
|
27
31
|
export interface AutoOrchestrationModule {
|
|
28
32
|
start(sessionContext: AutoSessionContext): Promise<AutoAdvanceResult>;
|
|
@@ -33,7 +37,17 @@ export interface AutoOrchestrationModule {
|
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
export interface DispatchAdapter {
|
|
36
|
-
decideNextUnit(input: {
|
|
40
|
+
decideNextUnit(input: {
|
|
41
|
+
stateSnapshot: GSDState;
|
|
42
|
+
/** Mirrors `DispatchContext.structuredQuestionsAvailable` — "true"/"false" string per the dispatch contract. */
|
|
43
|
+
structuredQuestionsAvailable?: "true" | "false";
|
|
44
|
+
/** Session model context window in tokens, forwarded to the budget engine. */
|
|
45
|
+
sessionContextWindow?: number;
|
|
46
|
+
/** Session model provider, used for provider-specific effective context windows. */
|
|
47
|
+
sessionProvider?: string;
|
|
48
|
+
/** Model registry for executor-model lookups inside the budget engine. */
|
|
49
|
+
modelRegistry?: MinimalModelRegistry;
|
|
50
|
+
}): Promise<{
|
|
37
51
|
unitType: string;
|
|
38
52
|
unitId: string;
|
|
39
53
|
reason: string;
|
|
@@ -70,11 +84,31 @@ export interface WorktreeAdapter {
|
|
|
70
84
|
cleanupOnStop(reason: string): Promise<void>;
|
|
71
85
|
}
|
|
72
86
|
|
|
87
|
+
export type HealthGateResult =
|
|
88
|
+
| { kind: "pass"; fixesApplied?: readonly string[] }
|
|
89
|
+
| { kind: "fail"; reason: string }
|
|
90
|
+
| { kind: "threw"; error: unknown };
|
|
91
|
+
|
|
73
92
|
export interface HealthAdapter {
|
|
74
|
-
|
|
93
|
+
checkResourcesStale(): string | null;
|
|
94
|
+
preAdvanceGate(): Promise<HealthGateResult>;
|
|
75
95
|
postAdvanceRecord(result: AutoAdvanceResult): Promise<void>;
|
|
76
96
|
}
|
|
77
97
|
|
|
98
|
+
export interface UokGateInput {
|
|
99
|
+
gateId: string;
|
|
100
|
+
gateType: "policy" | "execution";
|
|
101
|
+
outcome: "pass" | "fail" | "manual-attention";
|
|
102
|
+
failureClass: "none" | "policy" | "manual-attention";
|
|
103
|
+
rationale: string;
|
|
104
|
+
findings?: string;
|
|
105
|
+
milestoneId?: string;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface UokGateAdapter {
|
|
109
|
+
emit(input: UokGateInput): Promise<void>;
|
|
110
|
+
}
|
|
111
|
+
|
|
78
112
|
export interface RuntimePersistenceAdapter {
|
|
79
113
|
ensureLockOwnership(): Promise<void>;
|
|
80
114
|
journalTransition(event: {
|
|
@@ -101,4 +135,5 @@ export interface AutoOrchestratorDeps {
|
|
|
101
135
|
health: HealthAdapter;
|
|
102
136
|
runtime: RuntimePersistenceAdapter;
|
|
103
137
|
notifications: NotificationAdapter;
|
|
138
|
+
uokGate: UokGateAdapter;
|
|
104
139
|
}
|
|
@@ -7,6 +7,16 @@ function now(): number {
|
|
|
7
7
|
return Date.now();
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Size of the dispatch-decision ring buffer used by the Auto Orchestration
|
|
12
|
+
* module's stuck-loop detector. When the same `${unitType}:${unitId}` key
|
|
13
|
+
* fills the window, advance() blocks with `action: "stop"`.
|
|
14
|
+
*
|
|
15
|
+
* Mirrors the legacy `STUCK_WINDOW_SIZE` in auto/phases.ts so behaviour is
|
|
16
|
+
* preserved across the eventual cutover (issue #5791).
|
|
17
|
+
*/
|
|
18
|
+
export const STUCK_WINDOW_SIZE = 6;
|
|
19
|
+
|
|
10
20
|
export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
11
21
|
private status: AutoStatus = {
|
|
12
22
|
phase: "idle",
|
|
@@ -14,6 +24,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
14
24
|
};
|
|
15
25
|
private readonly deps: AutoOrchestratorDeps;
|
|
16
26
|
private lastAdvanceKey: string | null = null;
|
|
27
|
+
private dispatchKeyWindow: string[] = [];
|
|
17
28
|
|
|
18
29
|
public constructor(deps: AutoOrchestratorDeps) {
|
|
19
30
|
this.deps = deps;
|
|
@@ -21,6 +32,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
21
32
|
|
|
22
33
|
public async start(_sessionContext: AutoSessionContext): Promise<AutoAdvanceResult> {
|
|
23
34
|
this.lastAdvanceKey = null;
|
|
35
|
+
this.dispatchKeyWindow = [];
|
|
24
36
|
this.status.phase = "running";
|
|
25
37
|
this.bumpTransition();
|
|
26
38
|
await this.deps.runtime.journalTransition({ name: "start" });
|
|
@@ -31,19 +43,72 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
31
43
|
public async advance(): Promise<AutoAdvanceResult> {
|
|
32
44
|
try {
|
|
33
45
|
await this.deps.runtime.ensureLockOwnership();
|
|
46
|
+
|
|
47
|
+
const staleMsg = this.deps.health.checkResourcesStale();
|
|
48
|
+
if (staleMsg) {
|
|
49
|
+
await this.deps.uokGate.emit({
|
|
50
|
+
gateId: "resource-version-guard",
|
|
51
|
+
gateType: "policy",
|
|
52
|
+
outcome: "fail",
|
|
53
|
+
failureClass: "policy",
|
|
54
|
+
rationale: "resource version guard blocked dispatch",
|
|
55
|
+
findings: staleMsg,
|
|
56
|
+
});
|
|
57
|
+
const blocked: AutoAdvanceResult = { kind: "blocked", reason: staleMsg, action: "stop" };
|
|
58
|
+
await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
|
|
59
|
+
await this.deps.health.postAdvanceRecord(blocked);
|
|
60
|
+
return blocked;
|
|
61
|
+
}
|
|
62
|
+
await this.deps.uokGate.emit({
|
|
63
|
+
gateId: "resource-version-guard",
|
|
64
|
+
gateType: "policy",
|
|
65
|
+
outcome: "pass",
|
|
66
|
+
failureClass: "none",
|
|
67
|
+
rationale: "resource version guard passed",
|
|
68
|
+
});
|
|
69
|
+
|
|
34
70
|
const gate = await this.deps.health.preAdvanceGate();
|
|
35
|
-
if (
|
|
36
|
-
|
|
71
|
+
if (gate.kind === "fail") {
|
|
72
|
+
await this.deps.uokGate.emit({
|
|
73
|
+
gateId: "pre-dispatch-health-gate",
|
|
74
|
+
gateType: "execution",
|
|
75
|
+
outcome: "manual-attention",
|
|
76
|
+
failureClass: "manual-attention",
|
|
77
|
+
rationale: "pre-dispatch health gate blocked dispatch",
|
|
78
|
+
findings: gate.reason,
|
|
79
|
+
});
|
|
80
|
+
const blocked: AutoAdvanceResult = { kind: "blocked", reason: gate.reason, action: "pause" };
|
|
37
81
|
await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
|
|
38
82
|
await this.deps.health.postAdvanceRecord(blocked);
|
|
39
83
|
return blocked;
|
|
40
84
|
}
|
|
85
|
+
if (gate.kind === "threw") {
|
|
86
|
+
await this.deps.uokGate.emit({
|
|
87
|
+
gateId: "pre-dispatch-health-gate",
|
|
88
|
+
gateType: "execution",
|
|
89
|
+
outcome: "manual-attention",
|
|
90
|
+
failureClass: "manual-attention",
|
|
91
|
+
rationale: "pre-dispatch health gate threw unexpectedly",
|
|
92
|
+
findings: String(gate.error),
|
|
93
|
+
});
|
|
94
|
+
// intentional fall-through: matches runPreDispatch behaviour
|
|
95
|
+
} else {
|
|
96
|
+
await this.deps.uokGate.emit({
|
|
97
|
+
gateId: "pre-dispatch-health-gate",
|
|
98
|
+
gateType: "execution",
|
|
99
|
+
outcome: "pass",
|
|
100
|
+
failureClass: "none",
|
|
101
|
+
rationale: "pre-dispatch health gate passed",
|
|
102
|
+
findings: gate.fixesApplied?.join(", ") ?? "",
|
|
103
|
+
});
|
|
104
|
+
}
|
|
41
105
|
|
|
42
106
|
const reconciliation = await this.deps.stateReconciliation.reconcileBeforeDispatch();
|
|
43
107
|
if (!reconciliation.ok || !reconciliation.stateSnapshot) {
|
|
44
108
|
const blocked: AutoAdvanceResult = {
|
|
45
109
|
kind: "blocked",
|
|
46
|
-
reason: reconciliation.reason,
|
|
110
|
+
reason: reconciliation.reason ?? "state reconciliation produced no snapshot",
|
|
111
|
+
action: "pause",
|
|
47
112
|
stateSnapshot: reconciliation.stateSnapshot,
|
|
48
113
|
};
|
|
49
114
|
await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
|
|
@@ -57,6 +122,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
57
122
|
this.status.phase = "stopped";
|
|
58
123
|
this.status.activeUnit = undefined;
|
|
59
124
|
this.lastAdvanceKey = null;
|
|
125
|
+
this.dispatchKeyWindow = [];
|
|
60
126
|
this.bumpTransition();
|
|
61
127
|
await this.deps.runtime.journalTransition({ name: "advance-stopped", reason: stopped.reason });
|
|
62
128
|
await this.deps.health.postAdvanceRecord(stopped);
|
|
@@ -64,8 +130,45 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
64
130
|
}
|
|
65
131
|
|
|
66
132
|
const nextKey = `${decision.unitType}:${decision.unitId}`;
|
|
67
|
-
|
|
68
|
-
|
|
133
|
+
|
|
134
|
+
// Record every dispatch decision in the ring buffer before pre-flight
|
|
135
|
+
// checks so the stuck-loop detector observes the full decision history
|
|
136
|
+
// (including decisions that idempotency would otherwise short-circuit).
|
|
137
|
+
// The ring is capped at STUCK_WINDOW_SIZE and evicts oldest-first.
|
|
138
|
+
this.dispatchKeyWindow.push(nextKey);
|
|
139
|
+
if (this.dispatchKeyWindow.length > STUCK_WINDOW_SIZE) {
|
|
140
|
+
this.dispatchKeyWindow.shift();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Idempotency: same key as immediately previous successful advance.
|
|
144
|
+
// This is the soft, fast-path block kept from #5786. It only fires when
|
|
145
|
+
// the ring is NOT yet saturated for this key — once the ring is full of
|
|
146
|
+
// `nextKey`, the stuck-loop verdict takes precedence (see below). Both
|
|
147
|
+
// checks coexist: idempotency for the common immediate-repeat case,
|
|
148
|
+
// stuck-loop for the saturated-window case.
|
|
149
|
+
const matchingCount = this.dispatchKeyWindow.filter((k) => k === nextKey).length;
|
|
150
|
+
if (this.lastAdvanceKey === nextKey && matchingCount < STUCK_WINDOW_SIZE) {
|
|
151
|
+
const blocked: AutoAdvanceResult = { kind: "blocked", reason: "idempotent advance: unit already active", action: "stop" };
|
|
152
|
+
await this.deps.runtime.journalTransition({
|
|
153
|
+
name: "advance-blocked",
|
|
154
|
+
reason: blocked.reason,
|
|
155
|
+
unitType: decision.unitType,
|
|
156
|
+
unitId: decision.unitId,
|
|
157
|
+
});
|
|
158
|
+
await this.deps.health.postAdvanceRecord(blocked);
|
|
159
|
+
return blocked;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Stuck-loop detection: when the ring is saturated with copies of
|
|
163
|
+
// `nextKey` (count >= STUCK_WINDOW_SIZE), the orchestrator has been
|
|
164
|
+
// picking the same unit across the whole window and must hard-stop with
|
|
165
|
+
// a diagnosable reason.
|
|
166
|
+
if (matchingCount >= STUCK_WINDOW_SIZE) {
|
|
167
|
+
const blocked: AutoAdvanceResult = {
|
|
168
|
+
kind: "blocked",
|
|
169
|
+
reason: `stuck-loop: ${nextKey} picked ${matchingCount} times`,
|
|
170
|
+
action: "stop",
|
|
171
|
+
};
|
|
69
172
|
await this.deps.runtime.journalTransition({
|
|
70
173
|
name: "advance-blocked",
|
|
71
174
|
reason: blocked.reason,
|
|
@@ -81,6 +184,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
81
184
|
const blocked: AutoAdvanceResult = {
|
|
82
185
|
kind: "blocked",
|
|
83
186
|
reason: contract.reason,
|
|
187
|
+
action: "pause",
|
|
84
188
|
stateSnapshot: reconciliation.stateSnapshot,
|
|
85
189
|
};
|
|
86
190
|
await this.deps.runtime.journalTransition({
|
|
@@ -98,6 +202,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
98
202
|
const blocked: AutoAdvanceResult = {
|
|
99
203
|
kind: "blocked",
|
|
100
204
|
reason: worktree.reason,
|
|
205
|
+
action: "pause",
|
|
101
206
|
stateSnapshot: reconciliation.stateSnapshot,
|
|
102
207
|
};
|
|
103
208
|
await this.deps.runtime.journalTransition({
|
|
@@ -123,7 +228,11 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
123
228
|
});
|
|
124
229
|
await this.deps.worktree.syncAfterUnit(decision.unitType, decision.unitId);
|
|
125
230
|
|
|
126
|
-
const advanced: AutoAdvanceResult = {
|
|
231
|
+
const advanced: AutoAdvanceResult = {
|
|
232
|
+
kind: "advanced",
|
|
233
|
+
unit: { unitType: decision.unitType, unitId: decision.unitId },
|
|
234
|
+
stateSnapshot: reconciliation.stateSnapshot,
|
|
235
|
+
};
|
|
127
236
|
await this.deps.health.postAdvanceRecord(advanced);
|
|
128
237
|
return advanced;
|
|
129
238
|
} catch (error) {
|
|
@@ -148,6 +257,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
148
257
|
|
|
149
258
|
if (result.kind === "stopped") {
|
|
150
259
|
this.lastAdvanceKey = null;
|
|
260
|
+
this.dispatchKeyWindow = [];
|
|
151
261
|
this.status.activeUnit = undefined;
|
|
152
262
|
}
|
|
153
263
|
this.bumpTransition();
|
|
@@ -173,6 +283,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
173
283
|
|
|
174
284
|
public async resume(): Promise<AutoAdvanceResult> {
|
|
175
285
|
this.lastAdvanceKey = null;
|
|
286
|
+
this.dispatchKeyWindow = [];
|
|
176
287
|
this.status.phase = "running";
|
|
177
288
|
this.bumpTransition();
|
|
178
289
|
await this.deps.runtime.journalTransition({ name: "resume" });
|
|
@@ -188,6 +299,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
|
|
|
188
299
|
this.status.phase = "stopped";
|
|
189
300
|
this.status.activeUnit = undefined;
|
|
190
301
|
this.lastAdvanceKey = null;
|
|
302
|
+
this.dispatchKeyWindow = [];
|
|
191
303
|
this.bumpTransition();
|
|
192
304
|
await this.deps.runtime.journalTransition({ name: "stop", reason });
|
|
193
305
|
await this.deps.notifications.notifyLifecycle({ name: "stop", detail: reason });
|
|
@@ -2233,6 +2233,20 @@ export async function runUnitPhase(
|
|
|
2233
2233
|
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
2234
2234
|
return { action: "break", reason: "session-timeout" };
|
|
2235
2235
|
}
|
|
2236
|
+
if (
|
|
2237
|
+
unitResult.errorContext?.isTransient &&
|
|
2238
|
+
errorCategory === "aborted"
|
|
2239
|
+
) {
|
|
2240
|
+
ctx.ui.notify(
|
|
2241
|
+
`Unit ${unitType} ${unitId} was aborted by the user. Pausing auto-mode (recoverable).`,
|
|
2242
|
+
"warning",
|
|
2243
|
+
);
|
|
2244
|
+
debugLog("autoLoop", { phase: "unit-aborted-transient-pause", unitType, unitId, category: errorCategory });
|
|
2245
|
+
await deps.pauseAuto(ctx, pi);
|
|
2246
|
+
await deps.autoCommitUnit?.(s.basePath, unitType, unitId, ctx);
|
|
2247
|
+
await emitCancelledUnitEnd(ic, unitType, unitId, unitStartSeq, unitResult.errorContext);
|
|
2248
|
+
return { action: "break", reason: "unit-aborted-pause" };
|
|
2249
|
+
}
|
|
2236
2250
|
// All other cancelled states (structural errors, non-transient failures): hard stop
|
|
2237
2251
|
if (s.currentUnit) {
|
|
2238
2252
|
await deps.closeoutUnit(
|