gsd-pi 2.37.1-dev.d3ace49 → 2.38.0-dev.361f5e3
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/app-paths.js +1 -1
- package/dist/cli.js +9 -0
- package/dist/extension-discovery.d.ts +5 -3
- package/dist/extension-discovery.js +14 -9
- package/dist/extension-registry.js +2 -2
- package/dist/remote-questions-config.js +2 -2
- package/dist/resources/extensions/browser-tools/package.json +3 -1
- package/dist/resources/extensions/cmux/index.js +55 -1
- package/dist/resources/extensions/context7/package.json +1 -1
- package/dist/resources/extensions/env-utils.js +29 -0
- package/dist/resources/extensions/get-secrets-from-user.js +5 -24
- package/dist/resources/extensions/github-sync/cli.js +284 -0
- package/dist/resources/extensions/github-sync/index.js +73 -0
- package/dist/resources/extensions/github-sync/mapping.js +67 -0
- package/dist/resources/extensions/github-sync/sync.js +424 -0
- package/dist/resources/extensions/github-sync/templates.js +118 -0
- package/dist/resources/extensions/github-sync/types.js +7 -0
- package/dist/resources/extensions/google-search/package.json +3 -1
- package/dist/resources/extensions/gsd/auto/session.js +6 -23
- package/dist/resources/extensions/gsd/auto-dispatch.js +7 -8
- package/dist/resources/extensions/gsd/auto-loop.js +149 -170
- package/dist/resources/extensions/gsd/auto-post-unit.js +92 -70
- package/dist/resources/extensions/gsd/auto-prompts.js +7 -31
- package/dist/resources/extensions/gsd/auto-start.js +13 -2
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +13 -5
- package/dist/resources/extensions/gsd/auto.js +143 -96
- package/dist/resources/extensions/gsd/captures.js +9 -1
- package/dist/resources/extensions/gsd/commands-extensions.js +3 -2
- package/dist/resources/extensions/gsd/commands-handlers.js +16 -3
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
- package/dist/resources/extensions/gsd/commands.js +22 -2
- package/dist/resources/extensions/gsd/context-budget.js +2 -10
- package/dist/resources/extensions/gsd/detection.js +1 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -2
- package/dist/resources/extensions/gsd/doctor-checks.js +82 -0
- package/dist/resources/extensions/gsd/doctor-environment.js +78 -0
- package/dist/resources/extensions/gsd/doctor-format.js +15 -0
- package/dist/resources/extensions/gsd/doctor-providers.js +27 -11
- package/dist/resources/extensions/gsd/doctor.js +184 -11
- package/dist/resources/extensions/gsd/export.js +1 -1
- package/dist/resources/extensions/gsd/files.js +2 -2
- package/dist/resources/extensions/gsd/forensics.js +1 -1
- package/dist/resources/extensions/gsd/git-service.js +8 -1
- package/dist/resources/extensions/gsd/index.js +2 -1
- package/dist/resources/extensions/gsd/migrate/parsers.js +1 -1
- package/dist/resources/extensions/gsd/package.json +1 -1
- package/dist/resources/extensions/gsd/preferences-models.js +0 -12
- package/dist/resources/extensions/gsd/preferences-types.js +1 -1
- package/dist/resources/extensions/gsd/preferences-validation.js +59 -11
- package/dist/resources/extensions/gsd/preferences.js +8 -5
- package/dist/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
- package/dist/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/queue.md +4 -8
- package/dist/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
- package/dist/resources/extensions/gsd/prompts/run-uat.md +25 -10
- package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/dist/resources/extensions/gsd/repo-identity.js +21 -4
- package/dist/resources/extensions/gsd/resource-version.js +2 -1
- package/dist/resources/extensions/gsd/state.js +1 -1
- package/dist/resources/extensions/gsd/visualizer-data.js +1 -1
- package/dist/resources/extensions/gsd/worktree.js +35 -16
- package/dist/resources/extensions/remote-questions/status.js +2 -1
- package/dist/resources/extensions/remote-questions/store.js +2 -1
- package/dist/resources/extensions/search-the-web/provider.js +2 -1
- package/dist/resources/extensions/subagent/index.js +12 -3
- package/dist/resources/extensions/subagent/isolation.js +2 -1
- package/dist/resources/extensions/ttsr/rule-loader.js +2 -1
- package/dist/resources/extensions/universal-config/package.json +1 -1
- package/dist/welcome-screen.d.ts +12 -0
- package/dist/welcome-screen.js +53 -0
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.js +8 -4
- package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/package-manager.ts +8 -4
- package/pkg/package.json +1 -1
- package/src/resources/extensions/cmux/index.ts +57 -1
- package/src/resources/extensions/env-utils.ts +31 -0
- package/src/resources/extensions/get-secrets-from-user.ts +5 -24
- package/src/resources/extensions/github-sync/cli.ts +364 -0
- package/src/resources/extensions/github-sync/index.ts +93 -0
- package/src/resources/extensions/github-sync/mapping.ts +81 -0
- package/src/resources/extensions/github-sync/sync.ts +556 -0
- package/src/resources/extensions/github-sync/templates.ts +183 -0
- package/src/resources/extensions/github-sync/tests/cli.test.ts +20 -0
- package/src/resources/extensions/github-sync/tests/commit-linking.test.ts +39 -0
- package/src/resources/extensions/github-sync/tests/mapping.test.ts +104 -0
- package/src/resources/extensions/github-sync/tests/templates.test.ts +110 -0
- package/src/resources/extensions/github-sync/types.ts +47 -0
- package/src/resources/extensions/gsd/auto/session.ts +7 -25
- package/src/resources/extensions/gsd/auto-dispatch.ts +6 -8
- package/src/resources/extensions/gsd/auto-loop.ts +207 -252
- package/src/resources/extensions/gsd/auto-post-unit.ts +69 -41
- package/src/resources/extensions/gsd/auto-prompts.ts +7 -33
- package/src/resources/extensions/gsd/auto-start.ts +18 -2
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +15 -4
- package/src/resources/extensions/gsd/auto.ts +139 -101
- package/src/resources/extensions/gsd/captures.ts +10 -1
- package/src/resources/extensions/gsd/commands-extensions.ts +4 -2
- package/src/resources/extensions/gsd/commands-handlers.ts +17 -2
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
- package/src/resources/extensions/gsd/commands.ts +24 -2
- package/src/resources/extensions/gsd/context-budget.ts +2 -12
- package/src/resources/extensions/gsd/detection.ts +2 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -2
- package/src/resources/extensions/gsd/doctor-checks.ts +75 -0
- package/src/resources/extensions/gsd/doctor-environment.ts +82 -1
- package/src/resources/extensions/gsd/doctor-format.ts +20 -0
- package/src/resources/extensions/gsd/doctor-providers.ts +26 -9
- package/src/resources/extensions/gsd/doctor-types.ts +16 -1
- package/src/resources/extensions/gsd/doctor.ts +177 -13
- package/src/resources/extensions/gsd/export.ts +1 -1
- package/src/resources/extensions/gsd/files.ts +2 -2
- package/src/resources/extensions/gsd/forensics.ts +1 -1
- package/src/resources/extensions/gsd/git-service.ts +13 -1
- package/src/resources/extensions/gsd/index.ts +3 -1
- package/src/resources/extensions/gsd/migrate/parsers.ts +1 -1
- package/src/resources/extensions/gsd/preferences-models.ts +0 -12
- package/src/resources/extensions/gsd/preferences-types.ts +4 -4
- package/src/resources/extensions/gsd/preferences-validation.ts +51 -11
- package/src/resources/extensions/gsd/preferences.ts +8 -5
- package/src/resources/extensions/gsd/prompts/discuss.md +11 -14
- package/src/resources/extensions/gsd/prompts/execute-task.md +2 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +11 -12
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +8 -10
- package/src/resources/extensions/gsd/prompts/guided-resume-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/queue.md +4 -8
- package/src/resources/extensions/gsd/prompts/reactive-execute.md +11 -8
- package/src/resources/extensions/gsd/prompts/run-uat.md +25 -10
- package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -2
- package/src/resources/extensions/gsd/repo-identity.ts +23 -4
- package/src/resources/extensions/gsd/resource-version.ts +3 -1
- package/src/resources/extensions/gsd/state.ts +1 -1
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +21 -18
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +16 -37
- package/src/resources/extensions/gsd/tests/cmux.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +266 -0
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +86 -3
- package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -7
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +21 -1
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +11 -3
- package/src/resources/extensions/gsd/tests/worktree.test.ts +47 -0
- package/src/resources/extensions/gsd/types.ts +0 -1
- package/src/resources/extensions/gsd/visualizer-data.ts +1 -1
- package/src/resources/extensions/gsd/worktree.ts +35 -15
- package/src/resources/extensions/remote-questions/status.ts +3 -1
- package/src/resources/extensions/remote-questions/store.ts +3 -1
- package/src/resources/extensions/search-the-web/provider.ts +2 -1
- package/src/resources/extensions/subagent/index.ts +12 -3
- package/src/resources/extensions/subagent/isolation.ts +3 -1
- package/src/resources/extensions/ttsr/rule-loader.ts +3 -1
- package/dist/resources/extensions/gsd/prompt-compressor.js +0 -393
- package/dist/resources/extensions/gsd/semantic-chunker.js +0 -254
- package/dist/resources/extensions/gsd/summary-distiller.js +0 -212
- package/src/resources/extensions/gsd/prompt-compressor.ts +0 -508
- package/src/resources/extensions/gsd/semantic-chunker.ts +0 -336
- package/src/resources/extensions/gsd/summary-distiller.ts +0 -258
- package/src/resources/extensions/gsd/tests/context-compression.test.ts +0 -193
- package/src/resources/extensions/gsd/tests/prompt-compressor.test.ts +0 -529
- package/src/resources/extensions/gsd/tests/semantic-chunker.test.ts +0 -426
- package/src/resources/extensions/gsd/tests/summary-distiller.test.ts +0 -323
- package/src/resources/extensions/gsd/tests/token-optimization-benchmark.test.ts +0 -1272
- package/src/resources/extensions/gsd/tests/token-optimization-prefs.test.ts +0 -164
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* pattern with a while loop. The agent_end event resolves a promise instead
|
|
6
6
|
* of recursing.
|
|
7
7
|
*
|
|
8
|
-
* MAINTENANCE RULE:
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* MAINTENANCE RULE: Module-level mutable state is limited to `_currentResolve`
|
|
9
|
+
* (per-unit one-shot resolver) and `_sessionSwitchInFlight` (guard for
|
|
10
|
+
* session rotation). No queue — stale agent_end events are dropped.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import type { ExtensionAPI, ExtensionContext } from "@gsd/pi-coding-agent";
|
|
@@ -18,7 +18,7 @@ import type { GSDPreferences } from "./preferences.js";
|
|
|
18
18
|
import type { SessionLockStatus } from "./session-lock.js";
|
|
19
19
|
import type { GSDState } from "./types.js";
|
|
20
20
|
import type { CloseoutOptions } from "./auto-unit-closeout.js";
|
|
21
|
-
import type { PostUnitContext } from "./auto-post-unit.js";
|
|
21
|
+
import type { PostUnitContext, PreVerificationOpts } from "./auto-post-unit.js";
|
|
22
22
|
import type {
|
|
23
23
|
VerificationContext,
|
|
24
24
|
VerificationResult,
|
|
@@ -36,6 +36,21 @@ import type { CmuxLogLevel } from "../cmux/index.js";
|
|
|
36
36
|
*/
|
|
37
37
|
const MAX_LOOP_ITERATIONS = 500;
|
|
38
38
|
|
|
39
|
+
/** Data-driven budget threshold notifications (descending). The 100% entry
|
|
40
|
+
* triggers special enforcement logic (halt/pause/warn); sub-100 entries fire
|
|
41
|
+
* a simple notification. */
|
|
42
|
+
const BUDGET_THRESHOLDS: Array<{
|
|
43
|
+
pct: number;
|
|
44
|
+
label: string;
|
|
45
|
+
notifyLevel: "info" | "warning" | "error";
|
|
46
|
+
cmuxLevel: "progress" | "warning" | "error";
|
|
47
|
+
}> = [
|
|
48
|
+
{ pct: 100, label: "Budget ceiling reached", notifyLevel: "error", cmuxLevel: "error" },
|
|
49
|
+
{ pct: 90, label: "Budget 90%", notifyLevel: "warning", cmuxLevel: "warning" },
|
|
50
|
+
{ pct: 80, label: "Approaching budget ceiling — 80%", notifyLevel: "warning", cmuxLevel: "warning" },
|
|
51
|
+
{ pct: 75, label: "Budget 75%", notifyLevel: "info", cmuxLevel: "progress" },
|
|
52
|
+
];
|
|
53
|
+
|
|
39
54
|
// ─── Types ───────────────────────────────────────────────────────────────────
|
|
40
55
|
|
|
41
56
|
/**
|
|
@@ -54,17 +69,15 @@ export interface UnitResult {
|
|
|
54
69
|
event?: AgentEndEvent;
|
|
55
70
|
}
|
|
56
71
|
|
|
57
|
-
// ───
|
|
72
|
+
// ─── Per-unit one-shot promise state ────────────────────────────────────────
|
|
58
73
|
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
74
|
+
// A single module-level resolve function scoped to the current unit execution.
|
|
75
|
+
// No queue — if an agent_end arrives with no pending resolver, it is dropped
|
|
76
|
+
// (logged as warning). This is simpler and safer than the previous session-
|
|
77
|
+
// scoped pendingResolve + pendingAgentEndQueue pattern.
|
|
61
78
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
* on entry so that the agent_end handler in index.ts can resolve the correct
|
|
65
|
-
* session's promise without needing a direct reference to `s`.
|
|
66
|
-
*/
|
|
67
|
-
let _activeSession: AutoSession | null = null;
|
|
79
|
+
let _currentResolve: ((result: UnitResult) => void) | null = null;
|
|
80
|
+
let _sessionSwitchInFlight = false;
|
|
68
81
|
|
|
69
82
|
// ─── resolveAgentEnd ─────────────────────────────────────────────────────────
|
|
70
83
|
|
|
@@ -73,60 +86,48 @@ let _activeSession: AutoSession | null = null;
|
|
|
73
86
|
* in-flight unit promise. One-shot: the resolver is nulled before calling
|
|
74
87
|
* to prevent double-resolution from model fallback retries.
|
|
75
88
|
*
|
|
76
|
-
* If no
|
|
77
|
-
* the event is
|
|
89
|
+
* If no resolver exists (event arrived between loop iterations or during
|
|
90
|
+
* session switch), the event is dropped with a debug warning.
|
|
78
91
|
*/
|
|
79
92
|
export function resolveAgentEnd(event: AgentEndEvent): void {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
debugLog("resolveAgentEnd", {
|
|
83
|
-
status: "no-active-session",
|
|
84
|
-
warning: "agent_end with no active loop session",
|
|
85
|
-
});
|
|
93
|
+
if (_sessionSwitchInFlight) {
|
|
94
|
+
debugLog("resolveAgentEnd", { status: "ignored-during-switch" });
|
|
86
95
|
return;
|
|
87
96
|
}
|
|
88
|
-
|
|
89
|
-
if (s.pendingResolve) {
|
|
97
|
+
if (_currentResolve) {
|
|
90
98
|
debugLog("resolveAgentEnd", { status: "resolving", hasEvent: true });
|
|
91
|
-
const r =
|
|
92
|
-
|
|
99
|
+
const r = _currentResolve;
|
|
100
|
+
_currentResolve = null;
|
|
93
101
|
r({ status: "completed", event });
|
|
94
102
|
} else {
|
|
95
|
-
// Queue the event so the next runUnit picks it up immediately
|
|
96
103
|
debugLog("resolveAgentEnd", {
|
|
97
|
-
status: "
|
|
98
|
-
|
|
99
|
-
warning:
|
|
100
|
-
"agent_end arrived between loop iterations — queued for next runUnit",
|
|
104
|
+
status: "no-pending-resolve",
|
|
105
|
+
warning: "agent_end with no pending unit",
|
|
101
106
|
});
|
|
102
|
-
s.pendingAgentEndQueue.push(event);
|
|
103
107
|
}
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
export function isSessionSwitchInFlight(): boolean {
|
|
107
|
-
return
|
|
111
|
+
return _sessionSwitchInFlight;
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
// ─── resetPendingResolve (test helper) ───────────────────────────────────────
|
|
111
115
|
|
|
112
116
|
/**
|
|
113
|
-
* Reset
|
|
114
|
-
* should never call this.
|
|
117
|
+
* Reset module-level promise state. Only exported for test cleanup —
|
|
118
|
+
* production code should never call this.
|
|
115
119
|
*/
|
|
116
120
|
export function _resetPendingResolve(): void {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
_activeSession.pendingAgentEndQueue = [];
|
|
120
|
-
}
|
|
121
|
-
_activeSession = null;
|
|
121
|
+
_currentResolve = null;
|
|
122
|
+
_sessionSwitchInFlight = false;
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
/**
|
|
125
|
-
*
|
|
126
|
-
*
|
|
126
|
+
* No-op for backward compatibility with tests that previously set the
|
|
127
|
+
* active session. The module no longer holds a session reference.
|
|
127
128
|
*/
|
|
128
|
-
export function _setActiveSession(
|
|
129
|
-
|
|
129
|
+
export function _setActiveSession(_session: AutoSession | null): void {
|
|
130
|
+
// No-op — kept for test backward compatibility
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
// ─── runUnit ─────────────────────────────────────────────────────────────────
|
|
@@ -146,45 +147,18 @@ export async function runUnit(
|
|
|
146
147
|
unitType: string,
|
|
147
148
|
unitId: string,
|
|
148
149
|
prompt: string,
|
|
149
|
-
_prefs: GSDPreferences | undefined,
|
|
150
150
|
): Promise<UnitResult> {
|
|
151
151
|
debugLog("runUnit", { phase: "start", unitType, unitId });
|
|
152
152
|
|
|
153
|
-
// ── Drain queued events from error-recovery retries ──
|
|
154
|
-
// If an agent_end arrived between iterations (e.g. from a model fallback
|
|
155
|
-
// sendMessage retry), consume it immediately instead of creating a new promise.
|
|
156
|
-
// Cap queue to 3 entries to prevent unbounded growth from stale events.
|
|
157
|
-
if (s.pendingAgentEndQueue.length > 3) {
|
|
158
|
-
debugLog("runUnit", {
|
|
159
|
-
phase: "queue-overflow",
|
|
160
|
-
dropped: s.pendingAgentEndQueue.length - 1,
|
|
161
|
-
unitType,
|
|
162
|
-
unitId,
|
|
163
|
-
});
|
|
164
|
-
s.pendingAgentEndQueue = [
|
|
165
|
-
s.pendingAgentEndQueue[s.pendingAgentEndQueue.length - 1]!,
|
|
166
|
-
];
|
|
167
|
-
}
|
|
168
|
-
if (s.pendingAgentEndQueue.length > 0) {
|
|
169
|
-
const queued = s.pendingAgentEndQueue.shift()!;
|
|
170
|
-
debugLog("runUnit", {
|
|
171
|
-
phase: "drained-queued-event",
|
|
172
|
-
unitType,
|
|
173
|
-
unitId,
|
|
174
|
-
queueRemaining: s.pendingAgentEndQueue.length,
|
|
175
|
-
});
|
|
176
|
-
return { status: "completed", event: queued };
|
|
177
|
-
}
|
|
178
|
-
|
|
179
153
|
// ── Session creation with timeout ──
|
|
180
154
|
debugLog("runUnit", { phase: "session-create", unitType, unitId });
|
|
181
155
|
|
|
182
156
|
let sessionResult: { cancelled: boolean };
|
|
183
157
|
let sessionTimeoutHandle: ReturnType<typeof setTimeout> | undefined;
|
|
184
|
-
|
|
158
|
+
_sessionSwitchInFlight = true;
|
|
185
159
|
try {
|
|
186
160
|
const sessionPromise = s.cmdCtx!.newSession().finally(() => {
|
|
187
|
-
|
|
161
|
+
_sessionSwitchInFlight = false;
|
|
188
162
|
});
|
|
189
163
|
const timeoutPromise = new Promise<{ cancelled: true }>((resolve) => {
|
|
190
164
|
sessionTimeoutHandle = setTimeout(
|
|
@@ -216,11 +190,12 @@ export async function runUnit(
|
|
|
216
190
|
return { status: "cancelled" };
|
|
217
191
|
}
|
|
218
192
|
|
|
219
|
-
// ── Create the agent_end promise (
|
|
193
|
+
// ── Create the agent_end promise (per-unit one-shot) ──
|
|
220
194
|
// This happens after newSession completes so session-switch agent_end events
|
|
221
195
|
// from the previous session cannot resolve the new unit.
|
|
196
|
+
_sessionSwitchInFlight = false;
|
|
222
197
|
const unitPromise = new Promise<UnitResult>((resolve) => {
|
|
223
|
-
|
|
198
|
+
_currentResolve = resolve;
|
|
224
199
|
});
|
|
225
200
|
|
|
226
201
|
// Ensure cwd matches basePath before dispatch (#1389).
|
|
@@ -383,6 +358,7 @@ export interface LoopDeps {
|
|
|
383
358
|
midTitle: string;
|
|
384
359
|
state: GSDState;
|
|
385
360
|
prefs: GSDPreferences | undefined;
|
|
361
|
+
session?: AutoSession;
|
|
386
362
|
}) => Promise<DispatchAction>;
|
|
387
363
|
runPreDispatchHooks: (
|
|
388
364
|
unitType: string,
|
|
@@ -500,6 +476,7 @@ export interface LoopDeps {
|
|
|
500
476
|
// Post-unit processing
|
|
501
477
|
postUnitPreVerification: (
|
|
502
478
|
pctx: PostUnitContext,
|
|
479
|
+
opts?: PreVerificationOpts,
|
|
503
480
|
) => Promise<"dispatched" | "continue">;
|
|
504
481
|
runPostUnitVerification: (
|
|
505
482
|
vctx: VerificationContext,
|
|
@@ -513,6 +490,96 @@ export interface LoopDeps {
|
|
|
513
490
|
getSessionFile: (ctx: ExtensionContext) => string;
|
|
514
491
|
}
|
|
515
492
|
|
|
493
|
+
// ─── generateMilestoneReport ──────────────────────────────────────────────────
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Generate and write an HTML milestone report snapshot.
|
|
497
|
+
* Extracted from the milestone-transition block in autoLoop.
|
|
498
|
+
*/
|
|
499
|
+
async function generateMilestoneReport(
|
|
500
|
+
s: AutoSession,
|
|
501
|
+
ctx: ExtensionContext,
|
|
502
|
+
milestoneId: string,
|
|
503
|
+
): Promise<void> {
|
|
504
|
+
const { loadVisualizerData } = await import("./visualizer-data.js");
|
|
505
|
+
const { generateHtmlReport } = await import("./export-html.js");
|
|
506
|
+
const { writeReportSnapshot } = await import("./reports.js");
|
|
507
|
+
const { basename } = await import("node:path");
|
|
508
|
+
|
|
509
|
+
const snapData = await loadVisualizerData(s.basePath);
|
|
510
|
+
const completedMs = snapData.milestones.find(
|
|
511
|
+
(m: { id: string }) => m.id === milestoneId,
|
|
512
|
+
);
|
|
513
|
+
const msTitle = completedMs?.title ?? milestoneId;
|
|
514
|
+
const gsdVersion = process.env.GSD_VERSION ?? "0.0.0";
|
|
515
|
+
const projName = basename(s.basePath);
|
|
516
|
+
const doneSlices = snapData.milestones.reduce(
|
|
517
|
+
(acc: number, m: { slices: { done: boolean }[] }) =>
|
|
518
|
+
acc + m.slices.filter((sl: { done: boolean }) => sl.done).length,
|
|
519
|
+
0,
|
|
520
|
+
);
|
|
521
|
+
const totalSlices = snapData.milestones.reduce(
|
|
522
|
+
(acc: number, m: { slices: unknown[] }) => acc + m.slices.length,
|
|
523
|
+
0,
|
|
524
|
+
);
|
|
525
|
+
const outPath = writeReportSnapshot({
|
|
526
|
+
basePath: s.basePath,
|
|
527
|
+
html: generateHtmlReport(snapData, {
|
|
528
|
+
projectName: projName,
|
|
529
|
+
projectPath: s.basePath,
|
|
530
|
+
gsdVersion,
|
|
531
|
+
milestoneId,
|
|
532
|
+
indexRelPath: "index.html",
|
|
533
|
+
}),
|
|
534
|
+
milestoneId,
|
|
535
|
+
milestoneTitle: msTitle,
|
|
536
|
+
kind: "milestone",
|
|
537
|
+
projectName: projName,
|
|
538
|
+
projectPath: s.basePath,
|
|
539
|
+
gsdVersion,
|
|
540
|
+
totalCost: snapData.totals?.cost ?? 0,
|
|
541
|
+
totalTokens: snapData.totals?.tokens.total ?? 0,
|
|
542
|
+
totalDuration: snapData.totals?.duration ?? 0,
|
|
543
|
+
doneSlices,
|
|
544
|
+
totalSlices,
|
|
545
|
+
doneMilestones: snapData.milestones.filter(
|
|
546
|
+
(m: { status: string }) => m.status === "complete",
|
|
547
|
+
).length,
|
|
548
|
+
totalMilestones: snapData.milestones.length,
|
|
549
|
+
phase: snapData.phase,
|
|
550
|
+
});
|
|
551
|
+
ctx.ui.notify(
|
|
552
|
+
`Report saved: .gsd/reports/${basename(outPath)} — open index.html to browse progression.`,
|
|
553
|
+
"info",
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// ─── closeoutAndStop ──────────────────────────────────────────────────────────
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* If a unit is in-flight, close it out, then stop auto-mode.
|
|
561
|
+
* Extracted from ~4 identical if-closeout-then-stop sequences in autoLoop.
|
|
562
|
+
*/
|
|
563
|
+
async function closeoutAndStop(
|
|
564
|
+
ctx: ExtensionContext,
|
|
565
|
+
pi: ExtensionAPI,
|
|
566
|
+
s: AutoSession,
|
|
567
|
+
deps: LoopDeps,
|
|
568
|
+
reason: string,
|
|
569
|
+
): Promise<void> {
|
|
570
|
+
if (s.currentUnit) {
|
|
571
|
+
await deps.closeoutUnit(
|
|
572
|
+
ctx,
|
|
573
|
+
s.basePath,
|
|
574
|
+
s.currentUnit.type,
|
|
575
|
+
s.currentUnit.id,
|
|
576
|
+
s.currentUnit.startedAt,
|
|
577
|
+
deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id),
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
await deps.stopAuto(ctx, pi, reason);
|
|
581
|
+
}
|
|
582
|
+
|
|
516
583
|
// ─── autoLoop ────────────────────────────────────────────────────────────────
|
|
517
584
|
|
|
518
585
|
/**
|
|
@@ -530,7 +597,6 @@ export async function autoLoop(
|
|
|
530
597
|
deps: LoopDeps,
|
|
531
598
|
): Promise<void> {
|
|
532
599
|
debugLog("autoLoop", { phase: "enter" });
|
|
533
|
-
_activeSession = s;
|
|
534
600
|
let iteration = 0;
|
|
535
601
|
let lastDerivedUnit = "";
|
|
536
602
|
let sameUnitCount = 0;
|
|
@@ -668,57 +734,7 @@ export async function autoLoop(
|
|
|
668
734
|
}
|
|
669
735
|
if (vizPrefs?.auto_report !== false) {
|
|
670
736
|
try {
|
|
671
|
-
|
|
672
|
-
const { generateHtmlReport } = await import("./export-html.js");
|
|
673
|
-
const { writeReportSnapshot } = await import("./reports.js");
|
|
674
|
-
const { basename } = await import("node:path");
|
|
675
|
-
const snapData = await loadVisualizerData(s.basePath);
|
|
676
|
-
const completedMs = snapData.milestones.find(
|
|
677
|
-
(m: { id: string }) => m.id === s.currentMilestoneId,
|
|
678
|
-
);
|
|
679
|
-
const msTitle = completedMs?.title ?? s.currentMilestoneId;
|
|
680
|
-
const gsdVersion = process.env.GSD_VERSION ?? "0.0.0";
|
|
681
|
-
const projName = basename(s.basePath);
|
|
682
|
-
const doneSlices = snapData.milestones.reduce(
|
|
683
|
-
(acc: number, m: { slices: { done: boolean }[] }) =>
|
|
684
|
-
acc +
|
|
685
|
-
m.slices.filter((sl: { done: boolean }) => sl.done).length,
|
|
686
|
-
0,
|
|
687
|
-
);
|
|
688
|
-
const totalSlices = snapData.milestones.reduce(
|
|
689
|
-
(acc: number, m: { slices: unknown[] }) => acc + m.slices.length,
|
|
690
|
-
0,
|
|
691
|
-
);
|
|
692
|
-
const outPath = writeReportSnapshot({
|
|
693
|
-
basePath: s.basePath,
|
|
694
|
-
html: generateHtmlReport(snapData, {
|
|
695
|
-
projectName: projName,
|
|
696
|
-
projectPath: s.basePath,
|
|
697
|
-
gsdVersion,
|
|
698
|
-
milestoneId: s.currentMilestoneId,
|
|
699
|
-
indexRelPath: "index.html",
|
|
700
|
-
}),
|
|
701
|
-
milestoneId: s.currentMilestoneId!,
|
|
702
|
-
milestoneTitle: msTitle,
|
|
703
|
-
kind: "milestone",
|
|
704
|
-
projectName: projName,
|
|
705
|
-
projectPath: s.basePath,
|
|
706
|
-
gsdVersion,
|
|
707
|
-
totalCost: snapData.totals?.cost ?? 0,
|
|
708
|
-
totalTokens: snapData.totals?.tokens.total ?? 0,
|
|
709
|
-
totalDuration: snapData.totals?.duration ?? 0,
|
|
710
|
-
doneSlices,
|
|
711
|
-
totalSlices,
|
|
712
|
-
doneMilestones: snapData.milestones.filter(
|
|
713
|
-
(m: { status: string }) => m.status === "complete",
|
|
714
|
-
).length,
|
|
715
|
-
totalMilestones: snapData.milestones.length,
|
|
716
|
-
phase: snapData.phase,
|
|
717
|
-
});
|
|
718
|
-
ctx.ui.notify(
|
|
719
|
-
`Report saved: .gsd/reports/${(await import("node:path")).basename(outPath)} — open index.html to browse progression.`,
|
|
720
|
-
"info",
|
|
721
|
-
);
|
|
737
|
+
await generateMilestoneReport(s, ctx, s.currentMilestoneId!);
|
|
722
738
|
} catch (err) {
|
|
723
739
|
ctx.ui.notify(
|
|
724
740
|
`Report generation failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
@@ -787,7 +803,7 @@ export async function autoLoop(
|
|
|
787
803
|
(m: { status: string }) =>
|
|
788
804
|
m.status !== "complete" && m.status !== "parked",
|
|
789
805
|
);
|
|
790
|
-
if (incomplete.length === 0) {
|
|
806
|
+
if (incomplete.length === 0 && state.registry.length > 0) {
|
|
791
807
|
// All milestones complete — merge milestone branch before stopping
|
|
792
808
|
if (s.currentMilestoneId) {
|
|
793
809
|
deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
|
|
@@ -804,6 +820,18 @@ export async function autoLoop(
|
|
|
804
820
|
"success",
|
|
805
821
|
);
|
|
806
822
|
await deps.stopAuto(ctx, pi, "All milestones complete");
|
|
823
|
+
} else if (incomplete.length === 0 && state.registry.length === 0) {
|
|
824
|
+
// Empty registry — no milestones visible, likely a path resolution bug
|
|
825
|
+
const diag = `basePath=${s.basePath}, phase=${state.phase}`;
|
|
826
|
+
ctx.ui.notify(
|
|
827
|
+
`No milestones visible in current scope. Possible path resolution issue.\n Diagnostic: ${diag}`,
|
|
828
|
+
"error",
|
|
829
|
+
);
|
|
830
|
+
await deps.stopAuto(
|
|
831
|
+
ctx,
|
|
832
|
+
pi,
|
|
833
|
+
`No milestones found — check basePath resolution`,
|
|
834
|
+
);
|
|
807
835
|
} else if (state.phase === "blocked") {
|
|
808
836
|
const blockerMsg = `Blocked: ${state.blockers.join(", ")}`;
|
|
809
837
|
await deps.stopAuto(ctx, pi, blockerMsg);
|
|
@@ -844,20 +872,10 @@ export async function autoLoop(
|
|
|
844
872
|
}
|
|
845
873
|
|
|
846
874
|
if (!mid || !midTitle) {
|
|
847
|
-
if (s.currentUnit) {
|
|
848
|
-
await deps.closeoutUnit(
|
|
849
|
-
ctx,
|
|
850
|
-
s.basePath,
|
|
851
|
-
s.currentUnit.type,
|
|
852
|
-
s.currentUnit.id,
|
|
853
|
-
s.currentUnit.startedAt,
|
|
854
|
-
deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id),
|
|
855
|
-
);
|
|
856
|
-
}
|
|
857
875
|
const noMilestoneReason = !mid
|
|
858
876
|
? "No active milestone after merge reconciliation"
|
|
859
877
|
: `Milestone ${mid} has no title after reconciliation`;
|
|
860
|
-
await
|
|
878
|
+
await closeoutAndStop(ctx, pi, s, deps, noMilestoneReason);
|
|
861
879
|
debugLog("autoLoop", {
|
|
862
880
|
phase: "exit",
|
|
863
881
|
reason: "no-milestone-after-reconciliation",
|
|
@@ -867,17 +885,7 @@ export async function autoLoop(
|
|
|
867
885
|
|
|
868
886
|
// Terminal: complete
|
|
869
887
|
if (state.phase === "complete") {
|
|
870
|
-
|
|
871
|
-
await deps.closeoutUnit(
|
|
872
|
-
ctx,
|
|
873
|
-
s.basePath,
|
|
874
|
-
s.currentUnit.type,
|
|
875
|
-
s.currentUnit.id,
|
|
876
|
-
s.currentUnit.startedAt,
|
|
877
|
-
deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id),
|
|
878
|
-
);
|
|
879
|
-
}
|
|
880
|
-
// Milestone merge on complete
|
|
888
|
+
// Milestone merge on complete (before closeout so branch state is clean)
|
|
881
889
|
if (s.currentMilestoneId) {
|
|
882
890
|
deps.resolver.mergeAndExit(s.currentMilestoneId, ctx.ui);
|
|
883
891
|
}
|
|
@@ -892,25 +900,15 @@ export async function autoLoop(
|
|
|
892
900
|
`Milestone ${mid} complete.`,
|
|
893
901
|
"success",
|
|
894
902
|
);
|
|
895
|
-
await
|
|
903
|
+
await closeoutAndStop(ctx, pi, s, deps, `Milestone ${mid} complete`);
|
|
896
904
|
debugLog("autoLoop", { phase: "exit", reason: "milestone-complete" });
|
|
897
905
|
break;
|
|
898
906
|
}
|
|
899
907
|
|
|
900
908
|
// Terminal: blocked
|
|
901
909
|
if (state.phase === "blocked") {
|
|
902
|
-
if (s.currentUnit) {
|
|
903
|
-
await deps.closeoutUnit(
|
|
904
|
-
ctx,
|
|
905
|
-
s.basePath,
|
|
906
|
-
s.currentUnit.type,
|
|
907
|
-
s.currentUnit.id,
|
|
908
|
-
s.currentUnit.startedAt,
|
|
909
|
-
deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id),
|
|
910
|
-
);
|
|
911
|
-
}
|
|
912
910
|
const blockerMsg = `Blocked: ${state.blockers.join(", ")}`;
|
|
913
|
-
await
|
|
911
|
+
await closeoutAndStop(ctx, pi, s, deps, blockerMsg);
|
|
914
912
|
ctx.ui.notify(`${blockerMsg}. Fix and run /gsd auto.`, "warning");
|
|
915
913
|
deps.sendDesktopNotification("GSD", blockerMsg, "error", "attention");
|
|
916
914
|
deps.logCmuxEvent(deps.loadEffectiveGSDPreferences()?.preferences, blockerMsg, "error");
|
|
@@ -941,84 +939,49 @@ export async function autoLoop(
|
|
|
941
939
|
budgetPct,
|
|
942
940
|
);
|
|
943
941
|
|
|
944
|
-
|
|
945
|
-
|
|
942
|
+
// Data-driven threshold check — loop descending, fire first match
|
|
943
|
+
const threshold = BUDGET_THRESHOLDS.find(
|
|
944
|
+
(t) => newBudgetAlertLevel >= t.pct,
|
|
945
|
+
);
|
|
946
|
+
if (threshold) {
|
|
946
947
|
s.lastBudgetAlertLevel =
|
|
947
948
|
newBudgetAlertLevel as AutoSession["lastBudgetAlertLevel"];
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
)
|
|
949
|
+
|
|
950
|
+
if (threshold.pct === 100 && budgetEnforcementAction !== "none") {
|
|
951
|
+
// 100% — special enforcement logic (halt/pause/warn)
|
|
952
|
+
const msg = `Budget ceiling ${deps.formatCost(budgetCeiling)} reached (spent ${deps.formatCost(totalCost)}).`;
|
|
953
|
+
if (budgetEnforcementAction === "halt") {
|
|
954
|
+
deps.sendDesktopNotification("GSD", msg, "error", "budget");
|
|
955
|
+
await deps.stopAuto(ctx, pi, "Budget ceiling reached");
|
|
956
|
+
debugLog("autoLoop", { phase: "exit", reason: "budget-halt" });
|
|
957
|
+
break;
|
|
958
|
+
}
|
|
959
|
+
if (budgetEnforcementAction === "pause") {
|
|
960
|
+
ctx.ui.notify(
|
|
961
|
+
`${msg} Pausing auto-mode — /gsd auto to override and continue.`,
|
|
962
|
+
"warning",
|
|
963
|
+
);
|
|
964
|
+
deps.sendDesktopNotification("GSD", msg, "warning", "budget");
|
|
965
|
+
deps.logCmuxEvent(prefs, msg, "warning");
|
|
966
|
+
await deps.pauseAuto(ctx, pi);
|
|
967
|
+
debugLog("autoLoop", { phase: "exit", reason: "budget-pause" });
|
|
968
|
+
break;
|
|
969
|
+
}
|
|
970
|
+
ctx.ui.notify(`${msg} Continuing (enforcement: warn).`, "warning");
|
|
959
971
|
deps.sendDesktopNotification("GSD", msg, "warning", "budget");
|
|
960
972
|
deps.logCmuxEvent(prefs, msg, "warning");
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
973
|
+
} else if (threshold.pct < 100) {
|
|
974
|
+
// Sub-100% — simple notification
|
|
975
|
+
const msg = `${threshold.label}: ${deps.formatCost(totalCost)} / ${deps.formatCost(budgetCeiling)}`;
|
|
976
|
+
ctx.ui.notify(msg, threshold.notifyLevel);
|
|
977
|
+
deps.sendDesktopNotification(
|
|
978
|
+
"GSD",
|
|
979
|
+
msg,
|
|
980
|
+
threshold.notifyLevel,
|
|
981
|
+
"budget",
|
|
982
|
+
);
|
|
983
|
+
deps.logCmuxEvent(prefs, msg, threshold.cmuxLevel);
|
|
964
984
|
}
|
|
965
|
-
ctx.ui.notify(`${msg} Continuing (enforcement: warn).`, "warning");
|
|
966
|
-
deps.sendDesktopNotification("GSD", msg, "warning", "budget");
|
|
967
|
-
deps.logCmuxEvent(prefs, msg, "warning");
|
|
968
|
-
} else if (newBudgetAlertLevel === 90) {
|
|
969
|
-
s.lastBudgetAlertLevel =
|
|
970
|
-
newBudgetAlertLevel as AutoSession["lastBudgetAlertLevel"];
|
|
971
|
-
ctx.ui.notify(
|
|
972
|
-
`Budget 90%: ${deps.formatCost(totalCost)} / ${deps.formatCost(budgetCeiling)}`,
|
|
973
|
-
"warning",
|
|
974
|
-
);
|
|
975
|
-
deps.sendDesktopNotification(
|
|
976
|
-
"GSD",
|
|
977
|
-
`Budget 90%: ${deps.formatCost(totalCost)} / ${deps.formatCost(budgetCeiling)}`,
|
|
978
|
-
"warning",
|
|
979
|
-
"budget",
|
|
980
|
-
);
|
|
981
|
-
deps.logCmuxEvent(
|
|
982
|
-
prefs,
|
|
983
|
-
`Budget 90%: ${deps.formatCost(totalCost)} / ${deps.formatCost(budgetCeiling)}`,
|
|
984
|
-
"warning",
|
|
985
|
-
);
|
|
986
|
-
} else if (newBudgetAlertLevel === 80) {
|
|
987
|
-
s.lastBudgetAlertLevel =
|
|
988
|
-
newBudgetAlertLevel as AutoSession["lastBudgetAlertLevel"];
|
|
989
|
-
ctx.ui.notify(
|
|
990
|
-
`Approaching budget ceiling — 80%: ${deps.formatCost(totalCost)} / ${deps.formatCost(budgetCeiling)}`,
|
|
991
|
-
"warning",
|
|
992
|
-
);
|
|
993
|
-
deps.sendDesktopNotification(
|
|
994
|
-
"GSD",
|
|
995
|
-
`Approaching budget ceiling — 80%: ${deps.formatCost(totalCost)} / ${deps.formatCost(budgetCeiling)}`,
|
|
996
|
-
"warning",
|
|
997
|
-
"budget",
|
|
998
|
-
);
|
|
999
|
-
deps.logCmuxEvent(
|
|
1000
|
-
prefs,
|
|
1001
|
-
`Budget 80%: ${deps.formatCost(totalCost)} / ${deps.formatCost(budgetCeiling)}`,
|
|
1002
|
-
"warning",
|
|
1003
|
-
);
|
|
1004
|
-
} else if (newBudgetAlertLevel === 75) {
|
|
1005
|
-
s.lastBudgetAlertLevel =
|
|
1006
|
-
newBudgetAlertLevel as AutoSession["lastBudgetAlertLevel"];
|
|
1007
|
-
ctx.ui.notify(
|
|
1008
|
-
`Budget 75%: ${deps.formatCost(totalCost)} / ${deps.formatCost(budgetCeiling)}`,
|
|
1009
|
-
"info",
|
|
1010
|
-
);
|
|
1011
|
-
deps.sendDesktopNotification(
|
|
1012
|
-
"GSD",
|
|
1013
|
-
`Budget 75%: ${deps.formatCost(totalCost)} / ${deps.formatCost(budgetCeiling)}`,
|
|
1014
|
-
"info",
|
|
1015
|
-
"budget",
|
|
1016
|
-
);
|
|
1017
|
-
deps.logCmuxEvent(
|
|
1018
|
-
prefs,
|
|
1019
|
-
`Budget 75%: ${deps.formatCost(totalCost)} / ${deps.formatCost(budgetCeiling)}`,
|
|
1020
|
-
"progress",
|
|
1021
|
-
);
|
|
1022
985
|
} else if (budgetAlertLevel === 0) {
|
|
1023
986
|
s.lastBudgetAlertLevel = 0;
|
|
1024
987
|
}
|
|
@@ -1091,20 +1054,11 @@ export async function autoLoop(
|
|
|
1091
1054
|
midTitle: midTitle!,
|
|
1092
1055
|
state,
|
|
1093
1056
|
prefs,
|
|
1057
|
+
session: s,
|
|
1094
1058
|
});
|
|
1095
1059
|
|
|
1096
1060
|
if (dispatchResult.action === "stop") {
|
|
1097
|
-
|
|
1098
|
-
await deps.closeoutUnit(
|
|
1099
|
-
ctx,
|
|
1100
|
-
s.basePath,
|
|
1101
|
-
s.currentUnit.type,
|
|
1102
|
-
s.currentUnit.id,
|
|
1103
|
-
s.currentUnit.startedAt,
|
|
1104
|
-
deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id),
|
|
1105
|
-
);
|
|
1106
|
-
}
|
|
1107
|
-
await deps.stopAuto(ctx, pi, dispatchResult.reason);
|
|
1061
|
+
await closeoutAndStop(ctx, pi, s, deps, dispatchResult.reason);
|
|
1108
1062
|
debugLog("autoLoop", { phase: "exit", reason: "dispatch-stop" });
|
|
1109
1063
|
break;
|
|
1110
1064
|
}
|
|
@@ -1263,12 +1217,12 @@ export async function autoLoop(
|
|
|
1263
1217
|
);
|
|
1264
1218
|
|
|
1265
1219
|
if (s.currentUnitRouting) {
|
|
1266
|
-
const
|
|
1220
|
+
const isRetryForOutcome =
|
|
1267
1221
|
s.currentUnit.type === unitType && s.currentUnit.id === unitId;
|
|
1268
1222
|
deps.recordOutcome(
|
|
1269
1223
|
s.currentUnit.type,
|
|
1270
1224
|
s.currentUnitRouting.tier as "light" | "standard" | "heavy",
|
|
1271
|
-
!
|
|
1225
|
+
!isRetryForOutcome,
|
|
1272
1226
|
);
|
|
1273
1227
|
}
|
|
1274
1228
|
|
|
@@ -1463,7 +1417,6 @@ export async function autoLoop(
|
|
|
1463
1417
|
unitType,
|
|
1464
1418
|
unitId,
|
|
1465
1419
|
finalPrompt,
|
|
1466
|
-
prefs,
|
|
1467
1420
|
);
|
|
1468
1421
|
debugLog("autoLoop", {
|
|
1469
1422
|
phase: "runUnit-end",
|
|
@@ -1635,7 +1588,6 @@ export async function autoLoop(
|
|
|
1635
1588
|
item.unitType,
|
|
1636
1589
|
item.unitId,
|
|
1637
1590
|
item.prompt,
|
|
1638
|
-
prefs,
|
|
1639
1591
|
);
|
|
1640
1592
|
deps.clearUnitTimeout();
|
|
1641
1593
|
|
|
@@ -1649,9 +1601,12 @@ export async function autoLoop(
|
|
|
1649
1601
|
break;
|
|
1650
1602
|
}
|
|
1651
1603
|
|
|
1652
|
-
// Run pre-verification for the sidecar unit
|
|
1604
|
+
// Run pre-verification for the sidecar unit (lightweight path)
|
|
1605
|
+
const sidecarPreOpts: PreVerificationOpts = item.kind === "hook"
|
|
1606
|
+
? { skipSettleDelay: true, skipDoctor: true, skipStateRebuild: true, skipWorktreeSync: true }
|
|
1607
|
+
: { skipSettleDelay: true, skipStateRebuild: true };
|
|
1653
1608
|
const sidecarPreResult =
|
|
1654
|
-
await deps.postUnitPreVerification(postUnitCtx);
|
|
1609
|
+
await deps.postUnitPreVerification(postUnitCtx, sidecarPreOpts);
|
|
1655
1610
|
if (sidecarPreResult === "dispatched") {
|
|
1656
1611
|
// Pre-verification caused stop/pause
|
|
1657
1612
|
debugLog("autoLoop", {
|
|
@@ -1740,6 +1695,6 @@ export async function autoLoop(
|
|
|
1740
1695
|
}
|
|
1741
1696
|
}
|
|
1742
1697
|
|
|
1743
|
-
|
|
1698
|
+
_currentResolve = null;
|
|
1744
1699
|
debugLog("autoLoop", { phase: "exit", totalIterations: iteration });
|
|
1745
1700
|
}
|