gsd-pi 2.16.0 → 2.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/onboarding.js +2 -2
- package/dist/remote-questions-config.d.ts +10 -0
- package/dist/remote-questions-config.js +36 -0
- package/dist/resources/extensions/gsd/activity-log.ts +37 -7
- package/dist/resources/extensions/gsd/auto-dashboard.ts +4 -0
- package/dist/resources/extensions/gsd/auto-dispatch.ts +9 -3
- package/dist/resources/extensions/gsd/auto-prompts.ts +91 -42
- package/dist/resources/extensions/gsd/auto-recovery.ts +7 -2
- package/dist/resources/extensions/gsd/auto-worktree.ts +33 -4
- package/dist/resources/extensions/gsd/auto.ts +177 -25
- package/dist/resources/extensions/gsd/commands.ts +264 -23
- package/dist/resources/extensions/gsd/complexity.ts +236 -0
- package/dist/resources/extensions/gsd/dispatch-guard.ts +7 -19
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +202 -2
- package/dist/resources/extensions/gsd/files.ts +129 -3
- package/dist/resources/extensions/gsd/git-service.ts +19 -8
- package/dist/resources/extensions/gsd/gitignore.ts +41 -2
- package/dist/resources/extensions/gsd/guided-flow.ts +247 -10
- package/dist/resources/extensions/gsd/index.ts +47 -3
- package/dist/resources/extensions/gsd/metrics.ts +44 -0
- package/dist/resources/extensions/gsd/native-git-bridge.ts +5 -0
- package/dist/resources/extensions/gsd/native-parser-bridge.ts +5 -0
- package/dist/resources/extensions/gsd/paths.ts +9 -0
- package/dist/resources/extensions/gsd/preferences.ts +181 -2
- package/dist/resources/extensions/gsd/prompts/execute-task.md +6 -5
- package/dist/resources/extensions/gsd/prompts/system.md +2 -0
- package/dist/resources/extensions/gsd/queue-order.ts +231 -0
- package/dist/resources/extensions/gsd/queue-reorder-ui.ts +263 -0
- package/dist/resources/extensions/gsd/routing-history.ts +290 -0
- package/dist/resources/extensions/gsd/state.ts +15 -3
- package/dist/resources/extensions/gsd/templates/knowledge.md +19 -0
- package/dist/resources/extensions/gsd/templates/preferences.md +14 -0
- package/dist/resources/extensions/gsd/tests/auto-recovery.test.ts +50 -0
- package/dist/resources/extensions/gsd/tests/auto-worktree.test.ts +20 -0
- package/dist/resources/extensions/gsd/tests/budget-prediction.test.ts +220 -0
- package/dist/resources/extensions/gsd/tests/complexity-routing.test.ts +294 -0
- package/dist/resources/extensions/gsd/tests/context-compression.test.ts +180 -0
- package/dist/resources/extensions/gsd/tests/derive-state-deps.test.ts +99 -0
- package/dist/resources/extensions/gsd/tests/git-service.test.ts +132 -0
- package/dist/resources/extensions/gsd/tests/in-flight-tool-tracking.test.ts +79 -0
- package/dist/resources/extensions/gsd/tests/knowledge.test.ts +161 -0
- package/dist/resources/extensions/gsd/tests/memory-leak-guards.test.ts +87 -0
- package/dist/resources/extensions/gsd/tests/preferences-git.test.ts +28 -0
- package/dist/resources/extensions/gsd/tests/preferences-wizard-fields.test.ts +168 -0
- package/dist/resources/extensions/gsd/tests/queue-order.test.ts +204 -0
- package/dist/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +281 -0
- package/dist/resources/extensions/gsd/tests/routing-history.test.ts +87 -0
- package/dist/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +139 -0
- package/dist/resources/extensions/gsd/tests/stop-auto-remote.test.ts +130 -0
- package/dist/resources/extensions/gsd/tests/token-profile.test.ts +263 -0
- package/dist/resources/extensions/gsd/types.ts +28 -0
- package/dist/resources/extensions/gsd/worktree-manager.ts +8 -5
- package/dist/resources/extensions/gsd/worktree.ts +24 -2
- package/dist/resources/extensions/shared/next-action-ui.ts +16 -1
- package/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +493 -13
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +422 -62
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.d.ts +12 -0
- package/packages/pi-ai/dist/providers/google-shared.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.js +9 -22
- package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
- package/packages/pi-ai/dist/providers/google-shared.test.d.ts +2 -0
- package/packages/pi-ai/dist/providers/google-shared.test.d.ts.map +1 -0
- package/packages/pi-ai/dist/providers/google-shared.test.js +125 -0
- package/packages/pi-ai/dist/providers/google-shared.test.js.map +1 -0
- package/packages/pi-ai/src/models.generated.ts +422 -62
- package/packages/pi-ai/src/providers/google-shared.test.ts +137 -0
- package/packages/pi-ai/src/providers/google-shared.ts +10 -19
- package/packages/pi-coding-agent/dist/cli/args.d.ts +5 -0
- package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/cli/args.js +21 -0
- package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
- package/packages/pi-coding-agent/dist/cli/list-models.d.ts +14 -3
- package/packages/pi-coding-agent/dist/cli/list-models.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/cli/list-models.js +52 -17
- package/packages/pi-coding-agent/dist/cli/list-models.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/discovery-cache.d.ts +27 -0
- package/packages/pi-coding-agent/dist/core/discovery-cache.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/discovery-cache.js +79 -0
- package/packages/pi-coding-agent/dist/core/discovery-cache.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/discovery-cache.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/discovery-cache.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +140 -0
- package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-discovery.d.ts +35 -0
- package/packages/pi-coding-agent/dist/core/model-discovery.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-discovery.js +162 -0
- package/packages/pi-coding-agent/dist/core/model-discovery.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-discovery.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-discovery.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-discovery.test.js +100 -0
- package/packages/pi-coding-agent/dist/core/model-discovery.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js +113 -0
- package/packages/pi-coding-agent/dist/core/model-registry-discovery.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +26 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +98 -0
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/models-json-writer.d.ts +62 -0
- package/packages/pi-coding-agent/dist/core/models-json-writer.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/models-json-writer.js +145 -0
- package/packages/pi-coding-agent/dist/core/models-json-writer.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/models-json-writer.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/models-json-writer.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/models-json-writer.test.js +118 -0
- package/packages/pi-coding-agent/dist/core/models-json-writer.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
- package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.d.ts +7 -7
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.js +209 -13
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +67 -0
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts +5 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +4 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +17 -2
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/index.js +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +25 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +121 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +32 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +10 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/src/cli/args.ts +21 -0
- package/packages/pi-coding-agent/src/cli/list-models.ts +70 -17
- package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +170 -0
- package/packages/pi-coding-agent/src/core/discovery-cache.ts +97 -0
- package/packages/pi-coding-agent/src/core/model-discovery.test.ts +125 -0
- package/packages/pi-coding-agent/src/core/model-discovery.ts +231 -0
- package/packages/pi-coding-agent/src/core/model-registry-discovery.test.ts +135 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +107 -0
- package/packages/pi-coding-agent/src/core/models-json-writer.test.ts +145 -0
- package/packages/pi-coding-agent/src/core/models-json-writer.ts +188 -0
- package/packages/pi-coding-agent/src/core/settings-manager.ts +21 -0
- package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +85 -0
- package/packages/pi-coding-agent/src/core/tools/edit-diff.ts +245 -17
- package/packages/pi-coding-agent/src/index.ts +5 -0
- package/packages/pi-coding-agent/src/main.ts +19 -2
- package/packages/pi-coding-agent/src/modes/interactive/components/index.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +163 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +37 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +13 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +10 -0
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/src/resources/extensions/gsd/activity-log.ts +37 -7
- package/src/resources/extensions/gsd/auto-dashboard.ts +4 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +9 -3
- package/src/resources/extensions/gsd/auto-prompts.ts +91 -42
- package/src/resources/extensions/gsd/auto-recovery.ts +7 -2
- package/src/resources/extensions/gsd/auto-worktree.ts +33 -4
- package/src/resources/extensions/gsd/auto.ts +177 -25
- package/src/resources/extensions/gsd/commands.ts +264 -23
- package/src/resources/extensions/gsd/complexity.ts +236 -0
- package/src/resources/extensions/gsd/dispatch-guard.ts +7 -19
- package/src/resources/extensions/gsd/docs/preferences-reference.md +202 -2
- package/src/resources/extensions/gsd/files.ts +129 -3
- package/src/resources/extensions/gsd/git-service.ts +19 -8
- package/src/resources/extensions/gsd/gitignore.ts +41 -2
- package/src/resources/extensions/gsd/guided-flow.ts +247 -10
- package/src/resources/extensions/gsd/index.ts +47 -3
- package/src/resources/extensions/gsd/metrics.ts +44 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +5 -0
- package/src/resources/extensions/gsd/native-parser-bridge.ts +5 -0
- package/src/resources/extensions/gsd/paths.ts +9 -0
- package/src/resources/extensions/gsd/preferences.ts +181 -2
- package/src/resources/extensions/gsd/prompts/execute-task.md +6 -5
- package/src/resources/extensions/gsd/prompts/system.md +2 -0
- package/src/resources/extensions/gsd/queue-order.ts +231 -0
- package/src/resources/extensions/gsd/queue-reorder-ui.ts +263 -0
- package/src/resources/extensions/gsd/routing-history.ts +290 -0
- package/src/resources/extensions/gsd/state.ts +15 -3
- package/src/resources/extensions/gsd/templates/knowledge.md +19 -0
- package/src/resources/extensions/gsd/templates/preferences.md +14 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/budget-prediction.test.ts +220 -0
- package/src/resources/extensions/gsd/tests/complexity-routing.test.ts +294 -0
- package/src/resources/extensions/gsd/tests/context-compression.test.ts +180 -0
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/in-flight-tool-tracking.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +161 -0
- package/src/resources/extensions/gsd/tests/memory-leak-guards.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/preferences-git.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/preferences-wizard-fields.test.ts +168 -0
- package/src/resources/extensions/gsd/tests/queue-order.test.ts +204 -0
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +281 -0
- package/src/resources/extensions/gsd/tests/routing-history.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +139 -0
- package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +130 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +263 -0
- package/src/resources/extensions/gsd/types.ts +28 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +8 -5
- package/src/resources/extensions/gsd/worktree.ts +24 -2
- package/src/resources/extensions/shared/next-action-ui.ts +16 -1
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
buildMilestoneFileName, buildSliceFileName, buildTaskFileName,
|
|
30
30
|
} from "./paths.js";
|
|
31
31
|
import { invalidateAllCaches } from "./cache.js";
|
|
32
|
-
import { saveActivityLog } from "./activity-log.js";
|
|
32
|
+
import { saveActivityLog, clearActivityLogState } from "./activity-log.js";
|
|
33
33
|
import { synthesizeCrashRecovery, getDeepDiagnostic } from "./session-forensics.js";
|
|
34
34
|
import { writeLock, clearLock, readCrashLock, formatCrashInfo, isLockProcessAlive } from "./crash-recovery.js";
|
|
35
35
|
import {
|
|
@@ -92,7 +92,9 @@ import {
|
|
|
92
92
|
getAutoWorktreePath,
|
|
93
93
|
getAutoWorktreeOriginalBase,
|
|
94
94
|
mergeMilestoneToMain,
|
|
95
|
+
autoWorktreeBranch,
|
|
95
96
|
} from "./auto-worktree.js";
|
|
97
|
+
import { pruneQueueOrder } from "./queue-order.js";
|
|
96
98
|
import { showNextAction } from "../shared/next-action-ui.js";
|
|
97
99
|
import {
|
|
98
100
|
resolveExpectedArtifactPath,
|
|
@@ -196,6 +198,33 @@ function shouldUseWorktreeIsolation(): boolean {
|
|
|
196
198
|
return true; // default: worktree
|
|
197
199
|
}
|
|
198
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Detect and escape a stale worktree cwd (#608).
|
|
203
|
+
*
|
|
204
|
+
* After milestone completion + merge, the worktree directory is removed but
|
|
205
|
+
* the process cwd may still point inside `.gsd/worktrees/<MID>/`.
|
|
206
|
+
* When a new session starts, `process.cwd()` is passed as `base` to startAuto
|
|
207
|
+
* and all subsequent writes land in the wrong directory. This function detects
|
|
208
|
+
* that scenario and chdir back to the project root.
|
|
209
|
+
*
|
|
210
|
+
* Returns the corrected base path.
|
|
211
|
+
*/
|
|
212
|
+
function escapeStaleWorktree(base: string): string {
|
|
213
|
+
const marker = `${pathSep}.gsd${pathSep}worktrees${pathSep}`;
|
|
214
|
+
const idx = base.indexOf(marker);
|
|
215
|
+
if (idx === -1) return base;
|
|
216
|
+
|
|
217
|
+
// base is inside .gsd/worktrees/<something> — extract the project root
|
|
218
|
+
const projectRoot = base.slice(0, idx);
|
|
219
|
+
try {
|
|
220
|
+
process.chdir(projectRoot);
|
|
221
|
+
} catch {
|
|
222
|
+
// If chdir fails, return the original — caller will handle errors downstream
|
|
223
|
+
return base;
|
|
224
|
+
}
|
|
225
|
+
return projectRoot;
|
|
226
|
+
}
|
|
227
|
+
|
|
199
228
|
/** Crash recovery prompt — set by startAuto, consumed by first dispatchNextUnit */
|
|
200
229
|
let pendingCrashRecovery: string | null = null;
|
|
201
230
|
|
|
@@ -228,6 +257,9 @@ const DISPATCH_GAP_TIMEOUT_MS = 5_000; // 5 seconds
|
|
|
228
257
|
/** SIGTERM handler registered while auto-mode is active — cleared on stop/pause. */
|
|
229
258
|
let _sigtermHandler: (() => void) | null = null;
|
|
230
259
|
|
|
260
|
+
/** Tool calls currently being executed — prevents false idle detection during long-running tools. */
|
|
261
|
+
const inFlightTools = new Set<string>();
|
|
262
|
+
|
|
231
263
|
type BudgetAlertLevel = 0 | 75 | 90 | 100;
|
|
232
264
|
|
|
233
265
|
export function getBudgetAlertLevel(budgetPct: number): BudgetAlertLevel {
|
|
@@ -293,6 +325,57 @@ export function isAutoPaused(): boolean {
|
|
|
293
325
|
return paused;
|
|
294
326
|
}
|
|
295
327
|
|
|
328
|
+
/**
|
|
329
|
+
* Mark a tool execution as in-flight. Called from index.ts on tool_execution_start.
|
|
330
|
+
* Prevents the idle watchdog from declaring the agent idle while tools are executing.
|
|
331
|
+
*/
|
|
332
|
+
export function markToolStart(toolCallId: string): void {
|
|
333
|
+
if (!active) return;
|
|
334
|
+
inFlightTools.add(toolCallId);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Mark a tool execution as completed. Called from index.ts on tool_execution_end.
|
|
339
|
+
*/
|
|
340
|
+
export function markToolEnd(toolCallId: string): void {
|
|
341
|
+
inFlightTools.delete(toolCallId);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Return the base path to use for the auto.lock file.
|
|
346
|
+
* Always uses the original project root (not the worktree) so that
|
|
347
|
+
* a second terminal can discover and stop a running auto-mode session.
|
|
348
|
+
*/
|
|
349
|
+
function lockBase(): string {
|
|
350
|
+
return originalBasePath || basePath;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Attempt to stop a running auto-mode session from a different process.
|
|
355
|
+
* Reads the lock file at the project root, checks if the PID is alive,
|
|
356
|
+
* and sends SIGTERM to gracefully stop it.
|
|
357
|
+
*
|
|
358
|
+
* Returns true if a remote session was found and signaled, false otherwise.
|
|
359
|
+
*/
|
|
360
|
+
export function stopAutoRemote(projectRoot: string): { found: boolean; pid?: number; error?: string } {
|
|
361
|
+
const lock = readCrashLock(projectRoot);
|
|
362
|
+
if (!lock) return { found: false };
|
|
363
|
+
|
|
364
|
+
if (!isLockProcessAlive(lock)) {
|
|
365
|
+
// Stale lock — clean it up
|
|
366
|
+
clearLock(projectRoot);
|
|
367
|
+
return { found: false };
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Send SIGTERM — the auto-mode process has a handler that clears the lock and exits
|
|
371
|
+
try {
|
|
372
|
+
process.kill(lock.pid, "SIGTERM");
|
|
373
|
+
return { found: true, pid: lock.pid };
|
|
374
|
+
} catch (err) {
|
|
375
|
+
return { found: false, error: (err as Error).message };
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
296
379
|
export function isStepMode(): boolean {
|
|
297
380
|
return stepMode;
|
|
298
381
|
}
|
|
@@ -310,6 +393,7 @@ function clearUnitTimeout(): void {
|
|
|
310
393
|
clearInterval(idleWatchdogHandle);
|
|
311
394
|
idleWatchdogHandle = null;
|
|
312
395
|
}
|
|
396
|
+
inFlightTools.clear();
|
|
313
397
|
clearDispatchGapWatchdog();
|
|
314
398
|
}
|
|
315
399
|
|
|
@@ -371,7 +455,7 @@ function startDispatchGapWatchdog(ctx: ExtensionContext, pi: ExtensionAPI): void
|
|
|
371
455
|
export async function stopAuto(ctx?: ExtensionContext, pi?: ExtensionAPI): Promise<void> {
|
|
372
456
|
if (!active && !paused) return;
|
|
373
457
|
clearUnitTimeout();
|
|
374
|
-
if (
|
|
458
|
+
if (lockBase()) clearLock(lockBase());
|
|
375
459
|
clearSkillSnapshot();
|
|
376
460
|
_dispatching = false;
|
|
377
461
|
_skipDepth = 0;
|
|
@@ -391,14 +475,18 @@ export async function stopAuto(ctx?: ExtensionContext, pi?: ExtensionAPI): Promi
|
|
|
391
475
|
`Auto-worktree teardown failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
392
476
|
"warning",
|
|
393
477
|
);
|
|
394
|
-
// Force basePath back to original even if teardown failed
|
|
395
|
-
if (originalBasePath) {
|
|
396
|
-
basePath = originalBasePath;
|
|
397
|
-
try { process.chdir(basePath); } catch { /* best-effort */ }
|
|
398
|
-
}
|
|
399
478
|
}
|
|
400
479
|
}
|
|
401
480
|
|
|
481
|
+
// Always restore cwd to project root on stop (#608).
|
|
482
|
+
// Even if isInAutoWorktree returned false (e.g., module state was already
|
|
483
|
+
// cleared by mergeMilestoneToMain), the process cwd may still be inside
|
|
484
|
+
// the worktree directory. Force it back to originalBasePath.
|
|
485
|
+
if (originalBasePath) {
|
|
486
|
+
basePath = originalBasePath;
|
|
487
|
+
try { process.chdir(basePath); } catch { /* best-effort */ }
|
|
488
|
+
}
|
|
489
|
+
|
|
402
490
|
const ledger = getLedger();
|
|
403
491
|
if (ledger && ledger.units.length > 0) {
|
|
404
492
|
const totals = getProjectTotals(ledger.units);
|
|
@@ -423,12 +511,15 @@ export async function stopAuto(ctx?: ExtensionContext, pi?: ExtensionAPI): Promi
|
|
|
423
511
|
stepMode = false;
|
|
424
512
|
unitDispatchCount.clear();
|
|
425
513
|
unitRecoveryCount.clear();
|
|
514
|
+
inFlightTools.clear();
|
|
426
515
|
lastBudgetAlertLevel = 0;
|
|
427
516
|
unitLifetimeDispatches.clear();
|
|
428
517
|
currentUnit = null;
|
|
429
518
|
currentMilestoneId = null;
|
|
430
519
|
originalBasePath = "";
|
|
520
|
+
completedUnits = [];
|
|
431
521
|
clearSliceProgressCache();
|
|
522
|
+
clearActivityLogState();
|
|
432
523
|
pendingCrashRecovery = null;
|
|
433
524
|
_handlingAgentEnd = false;
|
|
434
525
|
ctx?.ui.setStatus("gsd-auto", undefined);
|
|
@@ -454,7 +545,7 @@ export async function stopAuto(ctx?: ExtensionContext, pi?: ExtensionAPI): Promi
|
|
|
454
545
|
export async function pauseAuto(ctx?: ExtensionContext, _pi?: ExtensionAPI): Promise<void> {
|
|
455
546
|
if (!active) return;
|
|
456
547
|
clearUnitTimeout();
|
|
457
|
-
if (
|
|
548
|
+
if (lockBase()) clearLock(lockBase());
|
|
458
549
|
|
|
459
550
|
// Remove SIGTERM handler registered at auto-mode start
|
|
460
551
|
deregisterSigtermHandler();
|
|
@@ -484,6 +575,11 @@ export async function startAuto(
|
|
|
484
575
|
): Promise<void> {
|
|
485
576
|
const requestedStepMode = options?.step ?? false;
|
|
486
577
|
|
|
578
|
+
// Escape stale worktree cwd from a previous milestone (#608).
|
|
579
|
+
// After milestone merge + worktree removal, the process cwd may still point
|
|
580
|
+
// inside .gsd/worktrees/<MID>/ — detect and chdir back to project root.
|
|
581
|
+
base = escapeStaleWorktree(base);
|
|
582
|
+
|
|
487
583
|
// If resuming from paused state, just re-activate and dispatch next unit.
|
|
488
584
|
// The conversation is still intact — no need to reinitialize everything.
|
|
489
585
|
if (paused) {
|
|
@@ -527,24 +623,24 @@ export async function startAuto(
|
|
|
527
623
|
}
|
|
528
624
|
}
|
|
529
625
|
|
|
530
|
-
// Re-register SIGTERM handler for the resumed session
|
|
531
|
-
registerSigtermHandler(
|
|
626
|
+
// Re-register SIGTERM handler for the resumed session (use original base for lock)
|
|
627
|
+
registerSigtermHandler(lockBase());
|
|
532
628
|
|
|
533
629
|
ctx.ui.setStatus("gsd-auto", stepMode ? "next" : "auto");
|
|
534
630
|
ctx.ui.setFooter(hideFooter);
|
|
535
631
|
ctx.ui.notify(stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "info");
|
|
536
632
|
// Restore hook state from disk in case session was interrupted
|
|
537
|
-
restoreHookState(
|
|
633
|
+
restoreHookState(basePath);
|
|
538
634
|
// Rebuild disk state before resuming — user interaction during pause may have changed files
|
|
539
|
-
try { await rebuildState(
|
|
635
|
+
try { await rebuildState(basePath); } catch { /* non-fatal */ }
|
|
540
636
|
try {
|
|
541
|
-
const report = await runGSDDoctor(
|
|
637
|
+
const report = await runGSDDoctor(basePath, { fix: true });
|
|
542
638
|
if (report.fixesApplied.length > 0) {
|
|
543
639
|
ctx.ui.notify(`Resume: applied ${report.fixesApplied.length} fix(es) to state.`, "info");
|
|
544
640
|
}
|
|
545
641
|
} catch { /* non-fatal */ }
|
|
546
642
|
// Self-heal: clear stale runtime records where artifacts already exist
|
|
547
|
-
await selfHealRuntimeRecords(
|
|
643
|
+
await selfHealRuntimeRecords(basePath, ctx, completedKeySet);
|
|
548
644
|
invalidateAllCaches();
|
|
549
645
|
await dispatchNextUnit(ctx, pi);
|
|
550
646
|
return;
|
|
@@ -557,17 +653,21 @@ export async function startAuto(
|
|
|
557
653
|
}
|
|
558
654
|
|
|
559
655
|
// Ensure .gitignore has baseline patterns
|
|
560
|
-
|
|
656
|
+
const commitDocs = loadEffectiveGSDPreferences()?.preferences?.git?.commit_docs;
|
|
657
|
+
ensureGitignore(base, { commitDocs });
|
|
561
658
|
untrackRuntimeFiles(base);
|
|
562
659
|
|
|
563
660
|
// Bootstrap .gsd/ if it doesn't exist
|
|
564
661
|
const gsdDir = join(base, ".gsd");
|
|
565
662
|
if (!existsSync(gsdDir)) {
|
|
566
663
|
mkdirSync(join(gsdDir, "milestones"), { recursive: true });
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
664
|
+
// Only commit .gsd/ init when commit_docs is not explicitly false
|
|
665
|
+
if (commitDocs !== false) {
|
|
666
|
+
try {
|
|
667
|
+
nativeAddPaths(base, [".gsd", ".gitignore"]);
|
|
668
|
+
nativeCommit(base, "chore: init gsd");
|
|
669
|
+
} catch { /* nothing to commit */ }
|
|
670
|
+
}
|
|
571
671
|
}
|
|
572
672
|
|
|
573
673
|
// Initialize GitServiceImpl — basePath is set and git repo confirmed
|
|
@@ -658,7 +758,7 @@ export async function startAuto(
|
|
|
658
758
|
// of the repo's default (main/master). Idempotent when the branch is the
|
|
659
759
|
// same; updates the record when started from a different branch (#300).
|
|
660
760
|
if (currentMilestoneId) {
|
|
661
|
-
captureIntegrationBranch(base, currentMilestoneId);
|
|
761
|
+
captureIntegrationBranch(base, currentMilestoneId, { commitDocs });
|
|
662
762
|
setActiveMilestoneId(base, currentMilestoneId);
|
|
663
763
|
}
|
|
664
764
|
|
|
@@ -695,8 +795,8 @@ export async function startAuto(
|
|
|
695
795
|
gitService = new GitServiceImpl(basePath, loadEffectiveGSDPreferences()?.preferences?.git ?? {});
|
|
696
796
|
ctx.ui.notify(`Created auto-worktree at ${wtPath}`, "info");
|
|
697
797
|
}
|
|
698
|
-
// Re-register SIGTERM handler with the
|
|
699
|
-
registerSigtermHandler(
|
|
798
|
+
// Re-register SIGTERM handler with the original basePath (lock lives there)
|
|
799
|
+
registerSigtermHandler(originalBasePath);
|
|
700
800
|
} catch (err) {
|
|
701
801
|
// Worktree creation is non-fatal — continue in the project root.
|
|
702
802
|
ctx.ui.notify(
|
|
@@ -952,7 +1052,7 @@ export async function handleAgentEnd(
|
|
|
952
1052
|
return;
|
|
953
1053
|
}
|
|
954
1054
|
const sessionFile = ctx.sessionManager.getSessionFile();
|
|
955
|
-
writeLock(
|
|
1055
|
+
writeLock(lockBase(), hookUnit.unitType, hookUnit.unitId, completedUnits.length, sessionFile);
|
|
956
1056
|
// Persist hook state so cycle counts survive crashes
|
|
957
1057
|
persistHookState(basePath);
|
|
958
1058
|
|
|
@@ -1211,7 +1311,12 @@ async function dispatchNextUnit(
|
|
|
1211
1311
|
unitRecoveryCount.clear();
|
|
1212
1312
|
unitLifetimeDispatches.clear();
|
|
1213
1313
|
// Capture integration branch for the new milestone and update git service
|
|
1214
|
-
captureIntegrationBranch(originalBasePath || basePath, mid);
|
|
1314
|
+
captureIntegrationBranch(originalBasePath || basePath, mid, { commitDocs: loadEffectiveGSDPreferences()?.preferences?.git?.commit_docs });
|
|
1315
|
+
// Prune completed milestone from queue order file
|
|
1316
|
+
const pendingIds = state.registry
|
|
1317
|
+
.filter(m => m.status !== "complete")
|
|
1318
|
+
.map(m => m.id);
|
|
1319
|
+
pruneQueueOrder(basePath, pendingIds);
|
|
1215
1320
|
}
|
|
1216
1321
|
if (mid) {
|
|
1217
1322
|
currentMilestoneId = mid;
|
|
@@ -1292,6 +1397,39 @@ async function dispatchNextUnit(
|
|
|
1292
1397
|
`Milestone merge failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1293
1398
|
"warning",
|
|
1294
1399
|
);
|
|
1400
|
+
// Ensure cwd is restored even if merge failed partway through (#608).
|
|
1401
|
+
// mergeMilestoneToMain may have chdir'd but then thrown, leaving us
|
|
1402
|
+
// in an indeterminate location.
|
|
1403
|
+
if (originalBasePath) {
|
|
1404
|
+
basePath = originalBasePath;
|
|
1405
|
+
try { process.chdir(basePath); } catch { /* best-effort */ }
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
} else if (currentMilestoneId && !isInAutoWorktree(basePath)) {
|
|
1409
|
+
// Branch isolation mode (#603): no worktree, but we may be on a milestone/* branch.
|
|
1410
|
+
// Squash-merge back to the integration branch (or main) before stopping.
|
|
1411
|
+
try {
|
|
1412
|
+
const currentBranch = getCurrentBranch(basePath);
|
|
1413
|
+
const milestoneBranch = autoWorktreeBranch(currentMilestoneId);
|
|
1414
|
+
if (currentBranch === milestoneBranch) {
|
|
1415
|
+
const roadmapPath = resolveMilestoneFile(basePath, currentMilestoneId, "ROADMAP");
|
|
1416
|
+
if (roadmapPath) {
|
|
1417
|
+
const roadmapContent = readFileSync(roadmapPath, "utf-8");
|
|
1418
|
+
// mergeMilestoneToMain handles: auto-commit, checkout integration branch,
|
|
1419
|
+
// squash merge, commit, optional push, branch deletion.
|
|
1420
|
+
const mergeResult = mergeMilestoneToMain(basePath, currentMilestoneId, roadmapContent);
|
|
1421
|
+
gitService = new GitServiceImpl(basePath, loadEffectiveGSDPreferences()?.preferences?.git ?? {});
|
|
1422
|
+
ctx.ui.notify(
|
|
1423
|
+
`Milestone ${currentMilestoneId} merged (branch mode).${mergeResult.pushed ? " Pushed to remote." : ""}`,
|
|
1424
|
+
"info",
|
|
1425
|
+
);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
} catch (err) {
|
|
1429
|
+
ctx.ui.notify(
|
|
1430
|
+
`Milestone merge failed (branch mode): ${err instanceof Error ? err.message : String(err)}`,
|
|
1431
|
+
"warning",
|
|
1432
|
+
);
|
|
1295
1433
|
}
|
|
1296
1434
|
}
|
|
1297
1435
|
sendDesktopNotification("GSD", `Milestone ${mid} complete!`, "success", "milestone");
|
|
@@ -1718,6 +1856,10 @@ async function dispatchNextUnit(
|
|
|
1718
1856
|
startedAt: currentUnit.startedAt,
|
|
1719
1857
|
finishedAt: Date.now(),
|
|
1720
1858
|
});
|
|
1859
|
+
// Cap to last 200 entries to prevent unbounded growth (#611)
|
|
1860
|
+
if (completedUnits.length > 200) {
|
|
1861
|
+
completedUnits = completedUnits.slice(-200);
|
|
1862
|
+
}
|
|
1721
1863
|
clearUnitRuntimeRecord(basePath, currentUnit.type, currentUnit.id);
|
|
1722
1864
|
unitDispatchCount.delete(`${currentUnit.type}/${currentUnit.id}`);
|
|
1723
1865
|
unitRecoveryCount.delete(`${currentUnit.type}/${currentUnit.id}`);
|
|
@@ -1758,7 +1900,7 @@ async function dispatchNextUnit(
|
|
|
1758
1900
|
// Pi appends entries incrementally via appendFileSync, so on crash the
|
|
1759
1901
|
// session file survives with every tool call up to the crash point.
|
|
1760
1902
|
const sessionFile = ctx.sessionManager.getSessionFile();
|
|
1761
|
-
writeLock(
|
|
1903
|
+
writeLock(lockBase(), unitType, unitId, completedUnits.length, sessionFile);
|
|
1762
1904
|
|
|
1763
1905
|
// On crash recovery, prepend the full recovery briefing
|
|
1764
1906
|
// On retry (stuck detection), prepend deep diagnostic from last attempt
|
|
@@ -1918,6 +2060,16 @@ async function dispatchNextUnit(
|
|
|
1918
2060
|
if (!runtime) return;
|
|
1919
2061
|
if (Date.now() - runtime.lastProgressAt < idleTimeoutMs) return;
|
|
1920
2062
|
|
|
2063
|
+
// Agent has tool calls currently executing (await_job, long bash, etc.) —
|
|
2064
|
+
// not idle, just waiting for tool completion.
|
|
2065
|
+
if (inFlightTools.size > 0) {
|
|
2066
|
+
writeUnitRuntimeRecord(basePath, unitType, unitId, currentUnit.startedAt, {
|
|
2067
|
+
lastProgressAt: Date.now(),
|
|
2068
|
+
lastProgressKind: "tool-in-flight",
|
|
2069
|
+
});
|
|
2070
|
+
return;
|
|
2071
|
+
}
|
|
2072
|
+
|
|
1921
2073
|
// Before triggering recovery, check if the agent is actually producing
|
|
1922
2074
|
// work on disk. `git status --porcelain` is cheap and catches any
|
|
1923
2075
|
// staged/unstaged/untracked changes the agent made since lastProgressAt.
|