gsd-pi 2.32.0-dev.d792ba5 → 2.32.0-dev.f3d5d53
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/resource-loader.js +13 -3
- package/dist/resources/extensions/gsd/auto-prompts.ts +46 -44
- package/dist/resources/extensions/gsd/auto-start.ts +6 -5
- package/dist/resources/extensions/gsd/auto-timers.ts +3 -2
- package/dist/resources/extensions/gsd/auto-verification.ts +2 -1
- package/dist/resources/extensions/gsd/auto-worktree.ts +5 -4
- package/dist/resources/extensions/gsd/auto.ts +24 -23
- package/dist/resources/extensions/gsd/commands-inspect.ts +2 -1
- package/dist/resources/extensions/gsd/commands-workflow-templates.ts +2 -1
- package/dist/resources/extensions/gsd/error-utils.ts +6 -0
- package/dist/resources/extensions/gsd/export.ts +2 -1
- package/dist/resources/extensions/gsd/git-service.ts +3 -2
- package/dist/resources/extensions/gsd/guided-flow.ts +3 -2
- package/dist/resources/extensions/gsd/index.ts +6 -5
- package/dist/resources/extensions/gsd/key-manager.ts +2 -1
- package/dist/resources/extensions/gsd/marketplace-discovery.ts +4 -3
- package/dist/resources/extensions/gsd/migrate-external.ts +3 -2
- package/dist/resources/extensions/gsd/milestone-ids.ts +2 -1
- package/dist/resources/extensions/gsd/native-git-bridge.ts +2 -1
- package/dist/resources/extensions/gsd/parallel-merge.ts +2 -1
- package/dist/resources/extensions/gsd/parallel-orchestrator.ts +2 -1
- package/dist/resources/extensions/gsd/quick.ts +2 -1
- package/dist/resources/extensions/gsd/session-lock.ts +12 -1
- package/dist/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
- package/dist/resources/extensions/gsd/worktree-command.ts +8 -7
- package/package.json +1 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +46 -44
- package/src/resources/extensions/gsd/auto-start.ts +6 -5
- package/src/resources/extensions/gsd/auto-timers.ts +3 -2
- package/src/resources/extensions/gsd/auto-verification.ts +2 -1
- package/src/resources/extensions/gsd/auto-worktree.ts +5 -4
- package/src/resources/extensions/gsd/auto.ts +24 -23
- package/src/resources/extensions/gsd/commands-inspect.ts +2 -1
- package/src/resources/extensions/gsd/commands-workflow-templates.ts +2 -1
- package/src/resources/extensions/gsd/error-utils.ts +6 -0
- package/src/resources/extensions/gsd/export.ts +2 -1
- package/src/resources/extensions/gsd/git-service.ts +3 -2
- package/src/resources/extensions/gsd/guided-flow.ts +3 -2
- package/src/resources/extensions/gsd/index.ts +6 -5
- package/src/resources/extensions/gsd/key-manager.ts +2 -1
- package/src/resources/extensions/gsd/marketplace-discovery.ts +4 -3
- package/src/resources/extensions/gsd/migrate-external.ts +3 -2
- package/src/resources/extensions/gsd/milestone-ids.ts +2 -1
- package/src/resources/extensions/gsd/native-git-bridge.ts +2 -1
- package/src/resources/extensions/gsd/parallel-merge.ts +2 -1
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +2 -1
- package/src/resources/extensions/gsd/quick.ts +2 -1
- package/src/resources/extensions/gsd/session-lock.ts +12 -1
- package/src/resources/extensions/gsd/tests/context-compression.test.ts +1 -1
- package/src/resources/extensions/gsd/worktree-command.ts +8 -7
package/dist/resource-loader.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DefaultResourceLoader } from '@gsd/pi-coding-agent';
|
|
2
2
|
import { createHash } from 'node:crypto';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
|
-
import { chmodSync, copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { chmodSync, copyFileSync, cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
5
5
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import { compareSemver } from './update-check.js';
|
|
@@ -118,7 +118,12 @@ export function getNewerManagedResourceVersion(agentDir, currentVersion) {
|
|
|
118
118
|
function makeTreeWritable(dirPath) {
|
|
119
119
|
if (!existsSync(dirPath))
|
|
120
120
|
return;
|
|
121
|
-
|
|
121
|
+
// Use lstatSync to avoid following symlinks into immutable filesystems
|
|
122
|
+
// (e.g., Nix store on NixOS/nix-darwin). Symlinks don't carry their own
|
|
123
|
+
// permissions and their targets may be read-only by design (#1298).
|
|
124
|
+
const stats = lstatSync(dirPath);
|
|
125
|
+
if (stats.isSymbolicLink())
|
|
126
|
+
return;
|
|
122
127
|
const isDir = stats.isDirectory();
|
|
123
128
|
const currentMode = stats.mode & 0o777;
|
|
124
129
|
// Ensure owner-write; for directories also ensure owner-exec so they remain traversable.
|
|
@@ -127,7 +132,12 @@ function makeTreeWritable(dirPath) {
|
|
|
127
132
|
newMode |= 0o100;
|
|
128
133
|
}
|
|
129
134
|
if (newMode !== currentMode) {
|
|
130
|
-
|
|
135
|
+
try {
|
|
136
|
+
chmodSync(dirPath, newMode);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// Non-fatal — may fail on read-only filesystems or insufficient permissions
|
|
140
|
+
}
|
|
131
141
|
}
|
|
132
142
|
if (isDir) {
|
|
133
143
|
for (const entry of readdirSync(dirPath, { withFileTypes: true })) {
|
|
@@ -189,30 +189,52 @@ export async function inlineGsdRootFile(
|
|
|
189
189
|
// ─── DB-Aware Inline Helpers ──────────────────────────────────────────────
|
|
190
190
|
|
|
191
191
|
/**
|
|
192
|
-
*
|
|
193
|
-
*
|
|
192
|
+
* Shared DB-fallback pattern: attempt a DB query via the context-store, format
|
|
193
|
+
* the result, and fall back to the filesystem file when the DB is unavailable
|
|
194
|
+
* or the query yields no results.
|
|
195
|
+
*
|
|
196
|
+
* @param base Project root for filesystem fallback
|
|
197
|
+
* @param label Section heading (e.g. "Decisions")
|
|
198
|
+
* @param filename Filesystem fallback file (e.g. "decisions.md")
|
|
199
|
+
* @param queryDb Async callback receiving the dynamically-imported
|
|
200
|
+
* context-store module. Returns formatted markdown or null.
|
|
194
201
|
*/
|
|
195
|
-
|
|
196
|
-
base: string,
|
|
202
|
+
async function inlineFromDbOrFile(
|
|
203
|
+
base: string,
|
|
204
|
+
label: string,
|
|
205
|
+
filename: string,
|
|
206
|
+
queryDb: (cs: typeof import("./context-store.js")) => string | null,
|
|
197
207
|
): Promise<string | null> {
|
|
198
|
-
const inlineLevel = level ?? resolveInlineLevel();
|
|
199
208
|
try {
|
|
200
209
|
const { isDbAvailable } = await import("./gsd-db.js");
|
|
201
210
|
if (isDbAvailable()) {
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
if (
|
|
205
|
-
|
|
206
|
-
const formatted = inlineLevel !== "full"
|
|
207
|
-
? formatDecisionsCompact(decisions)
|
|
208
|
-
: formatDecisionsForPrompt(decisions);
|
|
209
|
-
return `### Decisions\nSource: \`.gsd/DECISIONS.md\`\n\n${formatted}`;
|
|
211
|
+
const contextStore = await import("./context-store.js");
|
|
212
|
+
const content = queryDb(contextStore);
|
|
213
|
+
if (content) {
|
|
214
|
+
return `### ${label}\nSource: \`.gsd/${filename.toUpperCase().replace(/\.MD$/i, "")}.md\`\n\n${content}`;
|
|
210
215
|
}
|
|
211
216
|
}
|
|
212
217
|
} catch {
|
|
213
218
|
// DB not available — fall through to filesystem
|
|
214
219
|
}
|
|
215
|
-
return inlineGsdRootFile(base,
|
|
220
|
+
return inlineGsdRootFile(base, filename, label);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Inline decisions with optional milestone scoping from the DB.
|
|
225
|
+
* Falls back to filesystem via inlineGsdRootFile when DB unavailable or empty.
|
|
226
|
+
*/
|
|
227
|
+
export async function inlineDecisionsFromDb(
|
|
228
|
+
base: string, milestoneId?: string, scope?: string, level?: InlineLevel,
|
|
229
|
+
): Promise<string | null> {
|
|
230
|
+
const inlineLevel = level ?? resolveInlineLevel();
|
|
231
|
+
return inlineFromDbOrFile(base, "Decisions", "decisions.md", (cs) => {
|
|
232
|
+
const decisions = cs.queryDecisions({ milestoneId, scope });
|
|
233
|
+
if (decisions.length === 0) return null;
|
|
234
|
+
return inlineLevel !== "full"
|
|
235
|
+
? formatDecisionsCompact(decisions)
|
|
236
|
+
: cs.formatDecisionsForPrompt(decisions);
|
|
237
|
+
});
|
|
216
238
|
}
|
|
217
239
|
|
|
218
240
|
/**
|
|
@@ -223,23 +245,13 @@ export async function inlineRequirementsFromDb(
|
|
|
223
245
|
base: string, sliceId?: string, level?: InlineLevel,
|
|
224
246
|
): Promise<string | null> {
|
|
225
247
|
const inlineLevel = level ?? resolveInlineLevel();
|
|
226
|
-
|
|
227
|
-
const {
|
|
228
|
-
if (
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const formatted = inlineLevel !== "full"
|
|
234
|
-
? formatRequirementsCompact(requirements)
|
|
235
|
-
: formatRequirementsForPrompt(requirements);
|
|
236
|
-
return `### Requirements\nSource: \`.gsd/REQUIREMENTS.md\`\n\n${formatted}`;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
} catch {
|
|
240
|
-
// DB not available — fall through to filesystem
|
|
241
|
-
}
|
|
242
|
-
return inlineGsdRootFile(base, "requirements.md", "Requirements");
|
|
248
|
+
return inlineFromDbOrFile(base, "Requirements", "requirements.md", (cs) => {
|
|
249
|
+
const requirements = cs.queryRequirements({ sliceId });
|
|
250
|
+
if (requirements.length === 0) return null;
|
|
251
|
+
return inlineLevel !== "full"
|
|
252
|
+
? formatRequirementsCompact(requirements)
|
|
253
|
+
: cs.formatRequirementsForPrompt(requirements);
|
|
254
|
+
});
|
|
243
255
|
}
|
|
244
256
|
|
|
245
257
|
/**
|
|
@@ -249,19 +261,9 @@ export async function inlineRequirementsFromDb(
|
|
|
249
261
|
export async function inlineProjectFromDb(
|
|
250
262
|
base: string,
|
|
251
263
|
): Promise<string | null> {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
const { queryProject } = await import("./context-store.js");
|
|
256
|
-
const content = queryProject();
|
|
257
|
-
if (content) {
|
|
258
|
-
return `### Project\nSource: \`.gsd/PROJECT.md\`\n\n${content}`;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
} catch {
|
|
262
|
-
// DB not available — fall through to filesystem
|
|
263
|
-
}
|
|
264
|
-
return inlineGsdRootFile(base, "project.md", "Project");
|
|
264
|
+
return inlineFromDbOrFile(base, "Project", "project.md", (cs) => {
|
|
265
|
+
return cs.queryProject();
|
|
266
|
+
});
|
|
265
267
|
}
|
|
266
268
|
|
|
267
269
|
// ─── Skill Discovery ──────────────────────────────────────────────────────
|
|
@@ -63,6 +63,7 @@ import { debugLog, enableDebug, isDebugEnabled, getDebugLogPath } from "./debug-
|
|
|
63
63
|
import type { AutoSession } from "./auto/session.js";
|
|
64
64
|
import { existsSync, mkdirSync, readdirSync, statSync, unlinkSync } from "node:fs";
|
|
65
65
|
import { join } from "node:path";
|
|
66
|
+
import { getErrorMessage } from "./error-utils.js";
|
|
66
67
|
|
|
67
68
|
export interface BootstrapDeps {
|
|
68
69
|
shouldUseWorktreeIsolation: () => boolean;
|
|
@@ -201,11 +202,11 @@ export async function bootstrapAutoSession(
|
|
|
201
202
|
if (!midMatch) continue;
|
|
202
203
|
const mid = midMatch[1];
|
|
203
204
|
if (resolveMilestoneFile(base, mid, "SUMMARY")) {
|
|
204
|
-
try { unlinkSync(join(runtimeUnitsDir, file)); } catch (e) { debugLog("stale-unit-cleanup-failed", { file, error:
|
|
205
|
+
try { unlinkSync(join(runtimeUnitsDir, file)); } catch (e) { debugLog("stale-unit-cleanup-failed", { file, error: getErrorMessage(e) }); }
|
|
205
206
|
}
|
|
206
207
|
}
|
|
207
208
|
}
|
|
208
|
-
} catch (e) { debugLog("stale-unit-dir-cleanup-failed", { error:
|
|
209
|
+
} catch (e) { debugLog("stale-unit-dir-cleanup-failed", { error: getErrorMessage(e) }); }
|
|
209
210
|
|
|
210
211
|
let state = await deriveState(base);
|
|
211
212
|
|
|
@@ -343,7 +344,7 @@ export async function bootstrapAutoSession(
|
|
|
343
344
|
registerSigtermHandler(s.originalBasePath);
|
|
344
345
|
} catch (err) {
|
|
345
346
|
ctx.ui.notify(
|
|
346
|
-
`Auto-worktree setup failed: ${
|
|
347
|
+
`Auto-worktree setup failed: ${getErrorMessage(err)}. Continuing in project root.`,
|
|
347
348
|
"warning",
|
|
348
349
|
);
|
|
349
350
|
}
|
|
@@ -435,7 +436,7 @@ export async function bootstrapAutoSession(
|
|
|
435
436
|
}
|
|
436
437
|
} catch (err) {
|
|
437
438
|
ctx.ui.notify(
|
|
438
|
-
`Secrets check error: ${
|
|
439
|
+
`Secrets check error: ${getErrorMessage(err)}. Continuing without secrets.`,
|
|
439
440
|
"warning",
|
|
440
441
|
);
|
|
441
442
|
}
|
|
@@ -453,7 +454,7 @@ export async function bootstrapAutoSession(
|
|
|
453
454
|
ctx.ui.notify("Removed stale .git/index.lock from prior crash.", "info");
|
|
454
455
|
}
|
|
455
456
|
}
|
|
456
|
-
} catch (e) { debugLog("git-lock-cleanup-failed", { error:
|
|
457
|
+
} catch (e) { debugLog("git-lock-cleanup-failed", { error: getErrorMessage(e) }); }
|
|
457
458
|
|
|
458
459
|
// Pre-flight: validate milestone queue
|
|
459
460
|
try {
|
|
@@ -20,6 +20,7 @@ import { closeoutUnit, type CloseoutOptions } from "./auto-unit-closeout.js";
|
|
|
20
20
|
import { saveActivityLog } from "./activity-log.js";
|
|
21
21
|
import { recoverTimedOutUnit, type RecoveryContext } from "./auto-timeout-recovery.js";
|
|
22
22
|
import type { AutoSession } from "./auto/session.js";
|
|
23
|
+
import { getErrorMessage } from "./error-utils.js";
|
|
23
24
|
|
|
24
25
|
export interface SupervisionContext {
|
|
25
26
|
s: AutoSession;
|
|
@@ -127,7 +128,7 @@ export function startUnitSupervision(sctx: SupervisionContext): void {
|
|
|
127
128
|
);
|
|
128
129
|
await pauseAuto(ctx, pi);
|
|
129
130
|
} catch (err) {
|
|
130
|
-
const message =
|
|
131
|
+
const message = getErrorMessage(err);
|
|
131
132
|
console.error(`[idle-watchdog] Unhandled error: ${message}`);
|
|
132
133
|
try {
|
|
133
134
|
ctx.ui.notify(`Idle watchdog error: ${message}`, "warning");
|
|
@@ -159,7 +160,7 @@ export function startUnitSupervision(sctx: SupervisionContext): void {
|
|
|
159
160
|
);
|
|
160
161
|
await pauseAuto(ctx, pi);
|
|
161
162
|
} catch (err) {
|
|
162
|
-
const message =
|
|
163
|
+
const message = getErrorMessage(err);
|
|
163
164
|
console.error(`[hard-timeout] Unhandled error: ${message}`);
|
|
164
165
|
try {
|
|
165
166
|
ctx.ui.notify(`Hard timeout error: ${message}`, "warning");
|
|
@@ -24,6 +24,7 @@ import { writeVerificationJSON } from "./verification-evidence.js";
|
|
|
24
24
|
import { removePersistedKey } from "./auto-recovery.js";
|
|
25
25
|
import type { AutoSession, PendingVerificationRetry } from "./auto/session.js";
|
|
26
26
|
import { join } from "node:path";
|
|
27
|
+
import { getErrorMessage } from "./error-utils.js";
|
|
27
28
|
|
|
28
29
|
export interface VerificationContext {
|
|
29
30
|
s: AutoSession;
|
|
@@ -204,7 +205,7 @@ export async function runPostUnitVerification(
|
|
|
204
205
|
try {
|
|
205
206
|
await dispatchNextUnit(ctx, pi);
|
|
206
207
|
} catch (retryDispatchErr) {
|
|
207
|
-
const msg =
|
|
208
|
+
const msg = getErrorMessage(retryDispatchErr);
|
|
208
209
|
ctx.ui.notify(`Verification retry dispatch error: ${msg}`, "error");
|
|
209
210
|
startDispatchGapWatchdog(ctx, pi);
|
|
210
211
|
}
|
|
@@ -38,6 +38,7 @@ import {
|
|
|
38
38
|
nativeBranchDelete,
|
|
39
39
|
nativeBranchExists,
|
|
40
40
|
} from "./native-git-bridge.js";
|
|
41
|
+
import { getErrorMessage } from "./error-utils.js";
|
|
41
42
|
|
|
42
43
|
// ─── Module State ──────────────────────────────────────────────────────────
|
|
43
44
|
|
|
@@ -81,7 +82,7 @@ export function runWorktreePostCreateHook(sourceDir: string, worktreeDir: string
|
|
|
81
82
|
});
|
|
82
83
|
return null;
|
|
83
84
|
} catch (err) {
|
|
84
|
-
const msg =
|
|
85
|
+
const msg = getErrorMessage(err);
|
|
85
86
|
return `Worktree post-create hook failed: ${msg}`;
|
|
86
87
|
}
|
|
87
88
|
}
|
|
@@ -141,7 +142,7 @@ export function createAutoWorktree(basePath: string, milestoneId: string): strin
|
|
|
141
142
|
// Don't store originalBase -- caller can retry or clean up.
|
|
142
143
|
throw new GSDError(
|
|
143
144
|
GSD_IO_ERROR,
|
|
144
|
-
`Auto-worktree created at ${info.path} but chdir failed: ${
|
|
145
|
+
`Auto-worktree created at ${info.path} but chdir failed: ${getErrorMessage(err)}`,
|
|
145
146
|
);
|
|
146
147
|
}
|
|
147
148
|
|
|
@@ -168,7 +169,7 @@ export function teardownAutoWorktree(
|
|
|
168
169
|
} catch (err) {
|
|
169
170
|
throw new GSDError(
|
|
170
171
|
GSD_IO_ERROR,
|
|
171
|
-
`Failed to chdir back to ${originalBasePath} during teardown: ${
|
|
172
|
+
`Failed to chdir back to ${originalBasePath} during teardown: ${getErrorMessage(err)}`,
|
|
172
173
|
);
|
|
173
174
|
}
|
|
174
175
|
|
|
@@ -274,7 +275,7 @@ export function enterAutoWorktree(basePath: string, milestoneId: string): string
|
|
|
274
275
|
} catch (err) {
|
|
275
276
|
throw new GSDError(
|
|
276
277
|
GSD_IO_ERROR,
|
|
277
|
-
`Failed to enter auto-worktree at ${p}: ${
|
|
278
|
+
`Failed to enter auto-worktree at ${p}: ${getErrorMessage(err)}`,
|
|
278
279
|
);
|
|
279
280
|
}
|
|
280
281
|
|
|
@@ -189,6 +189,7 @@ import {
|
|
|
189
189
|
NEW_SESSION_TIMEOUT_MS, DISPATCH_HANG_TIMEOUT_MS,
|
|
190
190
|
} from "./auto/session.js";
|
|
191
191
|
import type { CompletedUnit, CurrentUnit, UnitRouting, StartModel, PendingVerificationRetry } from "./auto/session.js";
|
|
192
|
+
import { getErrorMessage } from "./error-utils.js";
|
|
192
193
|
|
|
193
194
|
// ── ENCAPSULATION INVARIANT ─────────────────────────────────────────────────
|
|
194
195
|
// ALL mutable auto-mode state lives in the AutoSession class (auto/session.ts).
|
|
@@ -428,7 +429,7 @@ function startDispatchGapWatchdog(ctx: ExtensionContext, pi: ExtensionAPI): void
|
|
|
428
429
|
try {
|
|
429
430
|
await dispatchNextUnit(ctx, pi);
|
|
430
431
|
} catch (retryErr) {
|
|
431
|
-
const message =
|
|
432
|
+
const message = getErrorMessage(retryErr);
|
|
432
433
|
await stopAuto(ctx, pi, `Dispatch gap recovery failed: ${message}`);
|
|
433
434
|
return;
|
|
434
435
|
}
|
|
@@ -458,14 +459,14 @@ export async function stopAuto(ctx?: ExtensionContext, pi?: ExtensionAPI, reason
|
|
|
458
459
|
// ── Auto-worktree: exit worktree and reset s.basePath on stop ──
|
|
459
460
|
if (s.currentMilestoneId && isInAutoWorktree(s.basePath)) {
|
|
460
461
|
try {
|
|
461
|
-
try { autoCommitCurrentBranch(s.basePath, "stop", s.currentMilestoneId); } catch (e) { debugLog("stop-auto-commit-failed", { error:
|
|
462
|
+
try { autoCommitCurrentBranch(s.basePath, "stop", s.currentMilestoneId); } catch (e) { debugLog("stop-auto-commit-failed", { error: getErrorMessage(e) }); }
|
|
462
463
|
teardownAutoWorktree(s.originalBasePath, s.currentMilestoneId, { preserveBranch: true });
|
|
463
464
|
s.basePath = s.originalBasePath;
|
|
464
465
|
s.gitService = createGitService(s.basePath);
|
|
465
466
|
ctx?.ui.notify("Exited auto-worktree (branch preserved for resume).", "info");
|
|
466
467
|
} catch (err) {
|
|
467
468
|
ctx?.ui.notify(
|
|
468
|
-
`Auto-worktree teardown failed: ${
|
|
469
|
+
`Auto-worktree teardown failed: ${getErrorMessage(err)}`,
|
|
469
470
|
"warning",
|
|
470
471
|
);
|
|
471
472
|
}
|
|
@@ -476,7 +477,7 @@ export async function stopAuto(ctx?: ExtensionContext, pi?: ExtensionAPI, reason
|
|
|
476
477
|
try {
|
|
477
478
|
const { closeDatabase } = await import("./gsd-db.js");
|
|
478
479
|
closeDatabase();
|
|
479
|
-
} catch (e) { debugLog("db-close-failed", { error:
|
|
480
|
+
} catch (e) { debugLog("db-close-failed", { error: getErrorMessage(e) }); }
|
|
480
481
|
}
|
|
481
482
|
|
|
482
483
|
if (s.originalBasePath) {
|
|
@@ -496,7 +497,7 @@ export async function stopAuto(ctx?: ExtensionContext, pi?: ExtensionAPI, reason
|
|
|
496
497
|
}
|
|
497
498
|
|
|
498
499
|
if (s.basePath) {
|
|
499
|
-
try { await rebuildState(s.basePath); } catch (e) { debugLog("stop-rebuild-state-failed", { error:
|
|
500
|
+
try { await rebuildState(s.basePath); } catch (e) { debugLog("stop-rebuild-state-failed", { error: getErrorMessage(e) }); }
|
|
500
501
|
}
|
|
501
502
|
|
|
502
503
|
if (isDebugEnabled()) {
|
|
@@ -635,7 +636,7 @@ export async function startAuto(
|
|
|
635
636
|
}
|
|
636
637
|
} catch (err) {
|
|
637
638
|
ctx.ui.notify(
|
|
638
|
-
`Auto-worktree re-entry failed: ${
|
|
639
|
+
`Auto-worktree re-entry failed: ${getErrorMessage(err)}. Continuing at current path.`,
|
|
639
640
|
"warning",
|
|
640
641
|
);
|
|
641
642
|
}
|
|
@@ -647,13 +648,13 @@ export async function startAuto(
|
|
|
647
648
|
ctx.ui.setFooter(hideFooter);
|
|
648
649
|
ctx.ui.notify(s.stepMode ? "Step-mode resumed." : "Auto-mode resumed.", "info");
|
|
649
650
|
restoreHookState(s.basePath);
|
|
650
|
-
try { await rebuildState(s.basePath); } catch (e) { debugLog("resume-rebuild-state-failed", { error:
|
|
651
|
+
try { await rebuildState(s.basePath); } catch (e) { debugLog("resume-rebuild-state-failed", { error: getErrorMessage(e) }); }
|
|
651
652
|
try {
|
|
652
653
|
const report = await runGSDDoctor(s.basePath, { fix: true });
|
|
653
654
|
if (report.fixesApplied.length > 0) {
|
|
654
655
|
ctx.ui.notify(`Resume: applied ${report.fixesApplied.length} fix(es) to state.`, "info");
|
|
655
656
|
}
|
|
656
|
-
} catch (e) { debugLog("resume-doctor-failed", { error:
|
|
657
|
+
} catch (e) { debugLog("resume-doctor-failed", { error: getErrorMessage(e) }); }
|
|
657
658
|
await selfHealRuntimeRecords(s.basePath, ctx, s.completedKeySet);
|
|
658
659
|
invalidateAllCaches();
|
|
659
660
|
|
|
@@ -700,7 +701,7 @@ export async function startAuto(
|
|
|
700
701
|
}
|
|
701
702
|
} catch (err) {
|
|
702
703
|
ctx.ui.notify(
|
|
703
|
-
`Secrets check error: ${
|
|
704
|
+
`Secrets check error: ${getErrorMessage(err)}. Continuing without secrets.`,
|
|
704
705
|
"warning",
|
|
705
706
|
);
|
|
706
707
|
}
|
|
@@ -807,7 +808,7 @@ export async function handleAgentEnd(
|
|
|
807
808
|
try {
|
|
808
809
|
await dispatchNextUnit(ctx, pi);
|
|
809
810
|
} catch (dispatchErr) {
|
|
810
|
-
const message =
|
|
811
|
+
const message = getErrorMessage(dispatchErr);
|
|
811
812
|
ctx.ui.notify(
|
|
812
813
|
`Dispatch error after unit completion: ${message}. Retrying in ${DISPATCH_GAP_TIMEOUT_MS / 1000}s.`,
|
|
813
814
|
"error",
|
|
@@ -838,7 +839,7 @@ export async function handleAgentEnd(
|
|
|
838
839
|
clearDispatchGapWatchdog();
|
|
839
840
|
setImmediate(() => {
|
|
840
841
|
handleAgentEnd(ctx, pi).catch((err) => {
|
|
841
|
-
const msg =
|
|
842
|
+
const msg = getErrorMessage(err);
|
|
842
843
|
ctx.ui.notify(`Deferred agent_end retry failed: ${msg}`, "error");
|
|
843
844
|
pauseAuto(ctx, pi).catch(() => {});
|
|
844
845
|
});
|
|
@@ -1086,7 +1087,7 @@ async function dispatchNextUnit(
|
|
|
1086
1087
|
);
|
|
1087
1088
|
} catch (err) {
|
|
1088
1089
|
ctx.ui.notify(
|
|
1089
|
-
`Report generation failed: ${
|
|
1090
|
+
`Report generation failed: ${getErrorMessage(err)}`,
|
|
1090
1091
|
"warning",
|
|
1091
1092
|
);
|
|
1092
1093
|
}
|
|
@@ -1102,7 +1103,7 @@ async function dispatchNextUnit(
|
|
|
1102
1103
|
atomicWriteSync(file, JSON.stringify([]));
|
|
1103
1104
|
}
|
|
1104
1105
|
s.completedKeySet.clear();
|
|
1105
|
-
} catch (e) { debugLog("completed-keys-reset-failed", { error:
|
|
1106
|
+
} catch (e) { debugLog("completed-keys-reset-failed", { error: getErrorMessage(e) }); }
|
|
1106
1107
|
|
|
1107
1108
|
// ── Worktree lifecycle on milestone transition (#616) ──
|
|
1108
1109
|
if (isInAutoWorktree(s.basePath) && s.originalBasePath && shouldUseWorktreeIsolation()) {
|
|
@@ -1121,7 +1122,7 @@ async function dispatchNextUnit(
|
|
|
1121
1122
|
}
|
|
1122
1123
|
} catch (err) {
|
|
1123
1124
|
ctx.ui.notify(
|
|
1124
|
-
`Milestone merge failed during transition: ${
|
|
1125
|
+
`Milestone merge failed during transition: ${getErrorMessage(err)}`,
|
|
1125
1126
|
"warning",
|
|
1126
1127
|
);
|
|
1127
1128
|
if (s.originalBasePath) {
|
|
@@ -1146,7 +1147,7 @@ async function dispatchNextUnit(
|
|
|
1146
1147
|
ctx.ui.notify(`Created auto-worktree for ${mid} at ${wtPath}`, "info");
|
|
1147
1148
|
} catch (err) {
|
|
1148
1149
|
ctx.ui.notify(
|
|
1149
|
-
`Auto-worktree creation for ${mid} failed: ${
|
|
1150
|
+
`Auto-worktree creation for ${mid} failed: ${getErrorMessage(err)}. Continuing in project root.`,
|
|
1150
1151
|
"warning",
|
|
1151
1152
|
);
|
|
1152
1153
|
}
|
|
@@ -1190,7 +1191,7 @@ async function dispatchNextUnit(
|
|
|
1190
1191
|
}
|
|
1191
1192
|
} catch (err) {
|
|
1192
1193
|
ctx.ui.notify(
|
|
1193
|
-
`Milestone merge failed: ${
|
|
1194
|
+
`Milestone merge failed: ${getErrorMessage(err)}`,
|
|
1194
1195
|
"warning",
|
|
1195
1196
|
);
|
|
1196
1197
|
if (s.originalBasePath) {
|
|
@@ -1216,7 +1217,7 @@ async function dispatchNextUnit(
|
|
|
1216
1217
|
}
|
|
1217
1218
|
} catch (err) {
|
|
1218
1219
|
ctx.ui.notify(
|
|
1219
|
-
`Milestone merge failed (branch mode): ${
|
|
1220
|
+
`Milestone merge failed (branch mode): ${getErrorMessage(err)}`,
|
|
1220
1221
|
"warning",
|
|
1221
1222
|
);
|
|
1222
1223
|
}
|
|
@@ -1276,7 +1277,7 @@ async function dispatchNextUnit(
|
|
|
1276
1277
|
atomicWriteSync(file, JSON.stringify([]));
|
|
1277
1278
|
}
|
|
1278
1279
|
s.completedKeySet.clear();
|
|
1279
|
-
} catch (e) { debugLog("completed-keys-reset-failed", { error:
|
|
1280
|
+
} catch (e) { debugLog("completed-keys-reset-failed", { error: getErrorMessage(e) }); }
|
|
1280
1281
|
// ── Milestone merge ──
|
|
1281
1282
|
if (s.currentMilestoneId && isInAutoWorktree(s.basePath) && s.originalBasePath) {
|
|
1282
1283
|
try {
|
|
@@ -1292,7 +1293,7 @@ async function dispatchNextUnit(
|
|
|
1292
1293
|
);
|
|
1293
1294
|
} catch (err) {
|
|
1294
1295
|
ctx.ui.notify(
|
|
1295
|
-
`Milestone merge failed: ${
|
|
1296
|
+
`Milestone merge failed: ${getErrorMessage(err)}`,
|
|
1296
1297
|
"warning",
|
|
1297
1298
|
);
|
|
1298
1299
|
if (s.originalBasePath) {
|
|
@@ -1318,7 +1319,7 @@ async function dispatchNextUnit(
|
|
|
1318
1319
|
}
|
|
1319
1320
|
} catch (err) {
|
|
1320
1321
|
ctx.ui.notify(
|
|
1321
|
-
`Milestone merge failed (branch mode): ${
|
|
1322
|
+
`Milestone merge failed (branch mode): ${getErrorMessage(err)}`,
|
|
1322
1323
|
"warning",
|
|
1323
1324
|
);
|
|
1324
1325
|
}
|
|
@@ -1417,7 +1418,7 @@ async function dispatchNextUnit(
|
|
|
1417
1418
|
}
|
|
1418
1419
|
} catch (err) {
|
|
1419
1420
|
ctx.ui.notify(
|
|
1420
|
-
`Secrets collection error: ${
|
|
1421
|
+
`Secrets collection error: ${getErrorMessage(err)}. Continuing with next task.`,
|
|
1421
1422
|
"warning",
|
|
1422
1423
|
);
|
|
1423
1424
|
}
|
|
@@ -1628,7 +1629,7 @@ async function dispatchNextUnit(
|
|
|
1628
1629
|
);
|
|
1629
1630
|
result = await Promise.race([sessionPromise, timeoutPromise]);
|
|
1630
1631
|
} catch (sessionErr) {
|
|
1631
|
-
const msg =
|
|
1632
|
+
const msg = getErrorMessage(sessionErr);
|
|
1632
1633
|
ctx.ui.notify(`Session creation failed: ${msg}. Retrying via watchdog.`, "error");
|
|
1633
1634
|
throw new Error(`newSession() failed: ${msg}`);
|
|
1634
1635
|
}
|
|
@@ -1704,7 +1705,7 @@ async function dispatchNextUnit(
|
|
|
1704
1705
|
const { reorderForCaching } = await import("./prompt-ordering.js");
|
|
1705
1706
|
finalPrompt = reorderForCaching(finalPrompt);
|
|
1706
1707
|
} catch (reorderErr) {
|
|
1707
|
-
const msg =
|
|
1708
|
+
const msg = getErrorMessage(reorderErr);
|
|
1708
1709
|
process.stderr.write(`[gsd] prompt reorder failed (non-fatal): ${msg}\n`);
|
|
1709
1710
|
}
|
|
1710
1711
|
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
|
|
8
|
+
import { getErrorMessage } from "./error-utils.js";
|
|
8
9
|
|
|
9
10
|
export interface InspectData {
|
|
10
11
|
schemaVersion: number | null;
|
|
@@ -84,7 +85,7 @@ export async function handleInspect(ctx: ExtensionCommandContext): Promise<void>
|
|
|
84
85
|
|
|
85
86
|
ctx.ui.notify(formatInspectOutput(data), "info");
|
|
86
87
|
} catch (err) {
|
|
87
|
-
process.stderr.write(`gsd-db: /gsd inspect failed: ${
|
|
88
|
+
process.stderr.write(`gsd-db: /gsd inspect failed: ${getErrorMessage(err)}\n`);
|
|
88
89
|
ctx.ui.notify("Failed to inspect GSD database. Check stderr for details.", "error");
|
|
89
90
|
}
|
|
90
91
|
}
|
|
@@ -21,6 +21,7 @@ import { loadPrompt } from "./prompt-loader.js";
|
|
|
21
21
|
import { gsdRoot } from "./paths.js";
|
|
22
22
|
import { createGitService, runGit } from "./git-service.js";
|
|
23
23
|
import { isAutoActive, isAutoPaused } from "./auto.js";
|
|
24
|
+
import { getErrorMessage } from "./error-utils.js";
|
|
24
25
|
|
|
25
26
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
26
27
|
|
|
@@ -439,7 +440,7 @@ export async function handleStart(
|
|
|
439
440
|
branchCreated = true;
|
|
440
441
|
}
|
|
441
442
|
} catch (err) {
|
|
442
|
-
const message =
|
|
443
|
+
const message = getErrorMessage(err);
|
|
443
444
|
ctx.ui.notify(
|
|
444
445
|
`Could not create branch ${branchName}: ${message}. Working on current branch.`,
|
|
445
446
|
"warning",
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import type { UnitMetrics } from "./metrics.js";
|
|
13
13
|
import { gsdRoot } from "./paths.js";
|
|
14
14
|
import { formatDuration, fileLink } from "../shared/mod.js";
|
|
15
|
+
import { getErrorMessage } from "./error-utils.js";
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Open a file in the user's default browser.
|
|
@@ -226,7 +227,7 @@ export async function handleExport(args: string, ctx: ExtensionCommandContext, b
|
|
|
226
227
|
}
|
|
227
228
|
} catch (err) {
|
|
228
229
|
ctx.ui.notify(
|
|
229
|
-
`HTML export failed: ${
|
|
230
|
+
`HTML export failed: ${getErrorMessage(err)}`,
|
|
230
231
|
"error",
|
|
231
232
|
);
|
|
232
233
|
}
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
nativeAddPaths,
|
|
34
34
|
} from "./native-git-bridge.js";
|
|
35
35
|
import { GSDError, GSD_MERGE_CONFLICT, GSD_GIT_ERROR } from "./errors.js";
|
|
36
|
+
import { getErrorMessage } from "./error-utils.js";
|
|
36
37
|
|
|
37
38
|
// ─── Types ─────────────────────────────────────────────────────────────────
|
|
38
39
|
|
|
@@ -281,7 +282,7 @@ export function runGit(basePath: string, args: string[], options: { allowFailure
|
|
|
281
282
|
}).trim();
|
|
282
283
|
} catch (error) {
|
|
283
284
|
if (options.allowFailure) return "";
|
|
284
|
-
const message =
|
|
285
|
+
const message = getErrorMessage(error);
|
|
285
286
|
throw new GSDError(GSD_GIT_ERROR, `git ${args.join(" ")} failed in ${basePath}: ${filterGitSvnNoise(message)}`);
|
|
286
287
|
}
|
|
287
288
|
}
|
|
@@ -533,7 +534,7 @@ export class GitServiceImpl {
|
|
|
533
534
|
execSync(command, { cwd: this.basePath, stdio: "pipe", encoding: "utf-8" });
|
|
534
535
|
return { passed: true, skipped: false, command };
|
|
535
536
|
} catch (err) {
|
|
536
|
-
const msg =
|
|
537
|
+
const msg = getErrorMessage(err);
|
|
537
538
|
return { passed: false, skipped: false, command, error: msg };
|
|
538
539
|
}
|
|
539
540
|
}
|
|
@@ -44,6 +44,7 @@ export {
|
|
|
44
44
|
showQueue, handleQueueReorder, showQueueAdd,
|
|
45
45
|
buildExistingMilestonesContext,
|
|
46
46
|
} from "./guided-flow-queue.js";
|
|
47
|
+
import { getErrorMessage } from "./error-utils.js";
|
|
47
48
|
|
|
48
49
|
// ─── Commit Instruction Helpers ──────────────────────────────────────────────
|
|
49
50
|
|
|
@@ -158,9 +159,9 @@ export function checkAutoStartAfterDiscuss(): boolean {
|
|
|
158
159
|
|
|
159
160
|
pendingAutoStart = null;
|
|
160
161
|
startAuto(ctx, pi, basePath, false, { step }).catch((err) => {
|
|
161
|
-
ctx.ui.notify(`Auto-start failed: ${
|
|
162
|
+
ctx.ui.notify(`Auto-start failed: ${getErrorMessage(err)}`, "error");
|
|
162
163
|
if (process.env.GSD_DEBUG) console.error('[gsd] auto start error:', err);
|
|
163
|
-
debugLog("auto-start-failed", { error:
|
|
164
|
+
debugLog("auto-start-failed", { error: getErrorMessage(err) });
|
|
164
165
|
});
|
|
165
166
|
return true;
|
|
166
167
|
}
|
|
@@ -64,6 +64,7 @@ import { pauseAutoForProviderError, classifyProviderError } from "./provider-err
|
|
|
64
64
|
import { toPosixPath } from "../shared/mod.js";
|
|
65
65
|
import { isParallelActive, shutdownParallel } from "./parallel-orchestrator.js";
|
|
66
66
|
import { DEFAULT_BASH_TIMEOUT_SECS } from "./constants.js";
|
|
67
|
+
import { getErrorMessage } from "./error-utils.js";
|
|
67
68
|
|
|
68
69
|
/**
|
|
69
70
|
* Ensure the GSD database is available, auto-initializing if needed.
|
|
@@ -374,7 +375,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
374
375
|
details: { operation: "save_decision", id },
|
|
375
376
|
};
|
|
376
377
|
} catch (err) {
|
|
377
|
-
const msg =
|
|
378
|
+
const msg = getErrorMessage(err);
|
|
378
379
|
process.stderr.write(`gsd-db: gsd_save_decision tool failed: ${msg}\n`);
|
|
379
380
|
return {
|
|
380
381
|
content: [{ type: "text" as const, text: `Error saving decision: ${msg}` }],
|
|
@@ -445,7 +446,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
445
446
|
details: { operation: "update_requirement", id: params.id },
|
|
446
447
|
};
|
|
447
448
|
} catch (err) {
|
|
448
|
-
const msg =
|
|
449
|
+
const msg = getErrorMessage(err);
|
|
449
450
|
process.stderr.write(`gsd-db: gsd_update_requirement tool failed: ${msg}\n`);
|
|
450
451
|
return {
|
|
451
452
|
content: [{ type: "text" as const, text: `Error updating requirement: ${msg}` }],
|
|
@@ -525,7 +526,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
525
526
|
details: { operation: "save_summary", path: relativePath, artifact_type: params.artifact_type },
|
|
526
527
|
};
|
|
527
528
|
} catch (err) {
|
|
528
|
-
const msg =
|
|
529
|
+
const msg = getErrorMessage(err);
|
|
529
530
|
process.stderr.write(`gsd-db: gsd_save_summary tool failed: ${msg}\n`);
|
|
530
531
|
return {
|
|
531
532
|
content: [{ type: "text" as const, text: `Error saving artifact: ${msg}` }],
|
|
@@ -574,7 +575,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
574
575
|
details: { operation: "generate_milestone_id", id: newId, existingCount: existingIds.length, reservedCount: reservedMilestoneIds.size, uniqueEnabled },
|
|
575
576
|
};
|
|
576
577
|
} catch (err) {
|
|
577
|
-
const msg =
|
|
578
|
+
const msg = getErrorMessage(err);
|
|
578
579
|
return {
|
|
579
580
|
content: [{ type: "text" as const, text: `Error generating milestone ID: ${msg}` }],
|
|
580
581
|
isError: true,
|
|
@@ -993,7 +994,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
993
994
|
} catch (err) {
|
|
994
995
|
// Safety net: if handleAgentEnd throws despite its internal try-catch,
|
|
995
996
|
// ensure auto-mode stops gracefully instead of silently stalling (#381).
|
|
996
|
-
const message =
|
|
997
|
+
const message = getErrorMessage(err);
|
|
997
998
|
ctx.ui.notify(
|
|
998
999
|
`Auto-mode error in agent_end handler: ${message}. Stopping auto-mode.`,
|
|
999
1000
|
"error",
|