gsd-pi 2.35.0-dev.39eee32 → 2.35.0-dev.4bbf377
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 +3 -1
- package/dist/resources/extensions/gsd/auto-loop.js +7 -2
- package/dist/resources/extensions/gsd/auto-model-selection.js +15 -3
- package/dist/resources/extensions/gsd/commands-rate.js +31 -0
- package/dist/resources/extensions/gsd/commands.js +43 -1
- package/dist/resources/extensions/gsd/guided-flow.js +7 -1
- package/dist/resources/extensions/gsd/index.js +16 -32
- package/dist/resources/extensions/gsd/preferences.js +12 -0
- package/dist/resources/extensions/gsd/session-lock.js +27 -0
- package/dist/resources/skills/core-web-vitals/SKILL.md +1 -1
- package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +1 -1
- package/dist/resources/skills/github-workflows/SKILL.md +0 -2
- package/dist/resources/skills/web-quality-audit/SKILL.md +0 -2
- package/package.json +1 -1
- package/packages/pi-agent-core/dist/agent.d.ts +10 -2
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +19 -8
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/src/agent.ts +31 -10
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +20 -4
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +36 -12
- package/src/resources/extensions/gsd/auto-loop.ts +11 -1
- package/src/resources/extensions/gsd/auto-model-selection.ts +23 -2
- package/src/resources/extensions/gsd/commands-rate.ts +55 -0
- package/src/resources/extensions/gsd/commands.ts +43 -1
- package/src/resources/extensions/gsd/guided-flow.ts +7 -1
- package/src/resources/extensions/gsd/index.ts +20 -32
- package/src/resources/extensions/gsd/preferences.ts +14 -1
- package/src/resources/extensions/gsd/session-lock.ts +30 -0
- package/src/resources/skills/core-web-vitals/SKILL.md +1 -1
- package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +1 -1
- package/src/resources/skills/github-workflows/SKILL.md +0 -2
- package/src/resources/skills/web-quality-audit/SKILL.md +0 -2
- package/dist/resources/skills/swiftui/SKILL.md +0 -208
- package/dist/resources/skills/swiftui/references/animations.md +0 -921
- package/dist/resources/skills/swiftui/references/architecture.md +0 -1561
- package/dist/resources/skills/swiftui/references/layout-system.md +0 -1186
- package/dist/resources/skills/swiftui/references/navigation.md +0 -1492
- package/dist/resources/skills/swiftui/references/networking-async.md +0 -214
- package/dist/resources/skills/swiftui/references/performance.md +0 -1706
- package/dist/resources/skills/swiftui/references/platform-integration.md +0 -204
- package/dist/resources/skills/swiftui/references/state-management.md +0 -1443
- package/dist/resources/skills/swiftui/references/swiftdata.md +0 -297
- package/dist/resources/skills/swiftui/references/testing-debugging.md +0 -247
- package/dist/resources/skills/swiftui/references/uikit-appkit-interop.md +0 -218
- package/dist/resources/skills/swiftui/workflows/add-feature.md +0 -191
- package/dist/resources/skills/swiftui/workflows/build-new-app.md +0 -311
- package/dist/resources/skills/swiftui/workflows/debug-swiftui.md +0 -192
- package/dist/resources/skills/swiftui/workflows/optimize-performance.md +0 -197
- package/dist/resources/skills/swiftui/workflows/ship-app.md +0 -203
- package/dist/resources/skills/swiftui/workflows/write-tests.md +0 -235
- package/src/resources/skills/swiftui/SKILL.md +0 -208
- package/src/resources/skills/swiftui/references/animations.md +0 -921
- package/src/resources/skills/swiftui/references/architecture.md +0 -1561
- package/src/resources/skills/swiftui/references/layout-system.md +0 -1186
- package/src/resources/skills/swiftui/references/navigation.md +0 -1492
- package/src/resources/skills/swiftui/references/networking-async.md +0 -214
- package/src/resources/skills/swiftui/references/performance.md +0 -1706
- package/src/resources/skills/swiftui/references/platform-integration.md +0 -204
- package/src/resources/skills/swiftui/references/state-management.md +0 -1443
- package/src/resources/skills/swiftui/references/swiftdata.md +0 -297
- package/src/resources/skills/swiftui/references/testing-debugging.md +0 -247
- package/src/resources/skills/swiftui/references/uikit-appkit-interop.md +0 -218
- package/src/resources/skills/swiftui/workflows/add-feature.md +0 -191
- package/src/resources/skills/swiftui/workflows/build-new-app.md +0 -311
- package/src/resources/skills/swiftui/workflows/debug-swiftui.md +0 -192
- package/src/resources/skills/swiftui/workflows/optimize-performance.md +0 -197
- package/src/resources/skills/swiftui/workflows/ship-app.md +0 -203
- package/src/resources/skills/swiftui/workflows/write-tests.md +0 -235
package/README.md
CHANGED
|
@@ -455,7 +455,9 @@ auto_report: true
|
|
|
455
455
|
|
|
456
456
|
### Agent Instructions
|
|
457
457
|
|
|
458
|
-
|
|
458
|
+
Place an `AGENTS.md` file in any directory to provide persistent behavioral guidance for that scope. Pi core loads `AGENTS.md` automatically (with `CLAUDE.md` as a fallback) at both user and project levels. Use these files for coding standards, architectural decisions, domain terminology, or workflow preferences.
|
|
459
|
+
|
|
460
|
+
> **Note:** The legacy `agent-instructions.md` format (`~/.gsd/agent-instructions.md` and `.gsd/agent-instructions.md`) is deprecated and no longer loaded. Migrate any existing instructions to `AGENTS.md` or `CLAUDE.md`.
|
|
459
461
|
|
|
460
462
|
### Debug Mode
|
|
461
463
|
|
|
@@ -632,6 +632,11 @@ export async function autoLoop(ctx, pi, s, deps) {
|
|
|
632
632
|
unitType,
|
|
633
633
|
unitId,
|
|
634
634
|
});
|
|
635
|
+
// Detect retry and capture previous tier for escalation
|
|
636
|
+
const isRetry = !!(s.currentUnit &&
|
|
637
|
+
s.currentUnit.type === unitType &&
|
|
638
|
+
s.currentUnit.id === unitId);
|
|
639
|
+
const previousTier = s.currentUnitRouting?.tier;
|
|
635
640
|
// Closeout previous unit
|
|
636
641
|
if (s.currentUnit) {
|
|
637
642
|
await deps.closeoutUnit(ctx, s.basePath, s.currentUnit.type, s.currentUnit.id, s.currentUnit.startedAt, deps.buildSnapshotOpts(s.currentUnit.type, s.currentUnit.id));
|
|
@@ -737,8 +742,8 @@ export async function autoLoop(ctx, pi, s, deps) {
|
|
|
737
742
|
const msg = reorderErr instanceof Error ? reorderErr.message : String(reorderErr);
|
|
738
743
|
process.stderr.write(`[gsd] prompt reorder failed (non-fatal): ${msg}\n`);
|
|
739
744
|
}
|
|
740
|
-
// Select and apply model
|
|
741
|
-
const modelResult = await deps.selectAndApplyModel(ctx, pi, unitType, unitId, s.basePath, prefs, s.verbose, s.autoModeStartModel);
|
|
745
|
+
// Select and apply model (with tier escalation on retry)
|
|
746
|
+
const modelResult = await deps.selectAndApplyModel(ctx, pi, unitType, unitId, s.basePath, prefs, s.verbose, s.autoModeStartModel, { isRetry, previousTier });
|
|
742
747
|
s.currentUnitRouting =
|
|
743
748
|
modelResult.routing;
|
|
744
749
|
// Start unit supervision
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { resolveModelWithFallbacksForUnit, resolveDynamicRoutingConfig } from "./preferences.js";
|
|
7
7
|
import { classifyUnitComplexity, tierLabel } from "./complexity-classifier.js";
|
|
8
|
-
import { resolveModelForComplexity } from "./model-router.js";
|
|
8
|
+
import { resolveModelForComplexity, escalateTier } from "./model-router.js";
|
|
9
9
|
import { getLedger, getProjectTotals } from "./metrics.js";
|
|
10
10
|
import { unitPhaseLabel } from "./auto-dashboard.js";
|
|
11
11
|
/**
|
|
@@ -15,7 +15,7 @@ import { unitPhaseLabel } from "./auto-dashboard.js";
|
|
|
15
15
|
*
|
|
16
16
|
* Returns routing metadata for metrics tracking.
|
|
17
17
|
*/
|
|
18
|
-
export async function selectAndApplyModel(ctx, pi, unitType, unitId, basePath, prefs, verbose, autoModeStartModel) {
|
|
18
|
+
export async function selectAndApplyModel(ctx, pi, unitType, unitId, basePath, prefs, verbose, autoModeStartModel, retryContext) {
|
|
19
19
|
const modelConfig = resolveModelWithFallbacksForUnit(unitType);
|
|
20
20
|
let routing = null;
|
|
21
21
|
if (modelConfig) {
|
|
@@ -37,8 +37,20 @@ export async function selectAndApplyModel(ctx, pi, unitType, unitId, basePath, p
|
|
|
37
37
|
const isHook = unitType.startsWith("hook/");
|
|
38
38
|
const shouldClassify = !isHook || routingConfig.hooks !== false;
|
|
39
39
|
if (shouldClassify) {
|
|
40
|
-
|
|
40
|
+
let classification = classifyUnitComplexity(unitType, unitId, basePath, budgetPct);
|
|
41
41
|
const availableModelIds = availableModels.map(m => m.id);
|
|
42
|
+
// Escalate tier on retry when escalate_on_failure is enabled (default: true)
|
|
43
|
+
if (retryContext?.isRetry &&
|
|
44
|
+
retryContext.previousTier &&
|
|
45
|
+
routingConfig.escalate_on_failure !== false) {
|
|
46
|
+
const escalated = escalateTier(retryContext.previousTier);
|
|
47
|
+
if (escalated) {
|
|
48
|
+
classification = { ...classification, tier: escalated, reason: "escalated after failure" };
|
|
49
|
+
if (verbose) {
|
|
50
|
+
ctx.ui.notify(`Tier escalation: ${retryContext.previousTier} → ${escalated} (retry after failure)`, "info");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
42
54
|
const routingResult = resolveModelForComplexity(classification, modelConfig, routingConfig, availableModelIds);
|
|
43
55
|
if (routingResult.wasDowngraded) {
|
|
44
56
|
effectiveModelConfig = {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /gsd rate — Submit feedback on the last unit's model tier assignment.
|
|
3
|
+
* Feeds into the adaptive routing history so future dispatches improve.
|
|
4
|
+
*/
|
|
5
|
+
import { loadLedgerFromDisk } from "./metrics.js";
|
|
6
|
+
import { recordFeedback, initRoutingHistory } from "./routing-history.js";
|
|
7
|
+
const VALID_RATINGS = new Set(["over", "under", "ok"]);
|
|
8
|
+
export async function handleRate(args, ctx, basePath) {
|
|
9
|
+
const rating = args.trim().toLowerCase();
|
|
10
|
+
if (!rating || !VALID_RATINGS.has(rating)) {
|
|
11
|
+
ctx.ui.notify("Usage: /gsd rate <over|ok|under>\n" +
|
|
12
|
+
" over — model was overpowered for that task (encourage cheaper)\n" +
|
|
13
|
+
" ok — model was appropriate\n" +
|
|
14
|
+
" under — model was too weak (encourage stronger)", "info");
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const ledger = loadLedgerFromDisk(basePath);
|
|
18
|
+
if (!ledger || ledger.units.length === 0) {
|
|
19
|
+
ctx.ui.notify("No completed units found — nothing to rate.", "warning");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const lastUnit = ledger.units[ledger.units.length - 1];
|
|
23
|
+
const tier = lastUnit.tier;
|
|
24
|
+
if (!tier) {
|
|
25
|
+
ctx.ui.notify("Last unit has no tier data (dynamic routing was not active). Rating skipped.", "warning");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
initRoutingHistory(basePath);
|
|
29
|
+
recordFeedback(lastUnit.type, lastUnit.id, tier, rating);
|
|
30
|
+
ctx.ui.notify(`Recorded "${rating}" for ${lastUnit.type}/${lastUnit.id} at tier ${tier}.`, "info");
|
|
31
|
+
}
|
|
@@ -36,6 +36,7 @@ import { computeProgressScore, formatProgressLine } from "./progress-score.js";
|
|
|
36
36
|
import { runEnvironmentChecks } from "./doctor-environment.js";
|
|
37
37
|
import { handleLogs } from "./commands-logs.js";
|
|
38
38
|
import { handleStart, handleTemplates, getTemplateCompletions } from "./commands-workflow-templates.js";
|
|
39
|
+
import { readSessionLockData, isSessionLockProcessAlive } from "./session-lock.js";
|
|
39
40
|
/** Resolve the effective project root, accounting for worktree paths. */
|
|
40
41
|
export function projectRoot() {
|
|
41
42
|
const cwd = process.cwd();
|
|
@@ -54,6 +55,38 @@ export function projectRoot() {
|
|
|
54
55
|
}
|
|
55
56
|
return root;
|
|
56
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Check if another process holds the auto-mode session lock.
|
|
60
|
+
* Returns the lock data if a remote session is alive, null otherwise.
|
|
61
|
+
*/
|
|
62
|
+
function getRemoteAutoSession(basePath) {
|
|
63
|
+
const lockData = readSessionLockData(basePath);
|
|
64
|
+
if (!lockData)
|
|
65
|
+
return null;
|
|
66
|
+
if (lockData.pid === process.pid)
|
|
67
|
+
return null;
|
|
68
|
+
if (!isSessionLockProcessAlive(lockData))
|
|
69
|
+
return null;
|
|
70
|
+
return { pid: lockData.pid };
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Show a steering menu when auto-mode is running in another process.
|
|
74
|
+
* Returns true if a remote session was detected (caller should return early).
|
|
75
|
+
*/
|
|
76
|
+
function notifyRemoteAutoActive(ctx, basePath) {
|
|
77
|
+
const remote = getRemoteAutoSession(basePath);
|
|
78
|
+
if (!remote)
|
|
79
|
+
return false;
|
|
80
|
+
ctx.ui.notify(`Auto-mode is running in another process (PID ${remote.pid}).\n` +
|
|
81
|
+
`Use these commands to interact with it:\n` +
|
|
82
|
+
` /gsd status — check progress\n` +
|
|
83
|
+
` /gsd discuss — discuss architecture decisions\n` +
|
|
84
|
+
` /gsd queue — queue the next milestone\n` +
|
|
85
|
+
` /gsd steer — apply an override to active work\n` +
|
|
86
|
+
` /gsd capture — fire-and-forget thought\n` +
|
|
87
|
+
` /gsd stop — stop auto-mode`, "warning");
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
57
90
|
export function registerGSDCommand(pi) {
|
|
58
91
|
pi.registerCommand("gsd", {
|
|
59
92
|
description: "GSD — Get Shit Done: /gsd help|start|templates|next|auto|stop|pause|status|visualize|queue|quick|capture|triage|dispatch|history|undo|skip|export|cleanup|mode|prefs|config|keys|hooks|run-hook|skill-health|doctor|forensics|changelog|migrate|remote|steer|knowledge|new-milestone|parallel|update",
|
|
@@ -74,6 +107,7 @@ export function registerGSDCommand(pi) {
|
|
|
74
107
|
{ cmd: "triage", desc: "Manually trigger triage of pending captures" },
|
|
75
108
|
{ cmd: "dispatch", desc: "Dispatch a specific phase directly" },
|
|
76
109
|
{ cmd: "history", desc: "View execution history" },
|
|
110
|
+
{ cmd: "rate", desc: "Rate last unit's model tier (over/ok/under) — improves adaptive routing" },
|
|
77
111
|
{ cmd: "undo", desc: "Revert last completed unit" },
|
|
78
112
|
{ cmd: "skip", desc: "Prevent a unit from auto-mode dispatch" },
|
|
79
113
|
{ cmd: "export", desc: "Export milestone/slice results" },
|
|
@@ -459,6 +493,8 @@ export async function handleGSDCommand(args, ctx, pi) {
|
|
|
459
493
|
await handleDryRun(ctx, projectRoot());
|
|
460
494
|
return;
|
|
461
495
|
}
|
|
496
|
+
if (notifyRemoteAutoActive(ctx, projectRoot()))
|
|
497
|
+
return;
|
|
462
498
|
const verboseMode = trimmed.includes("--verbose");
|
|
463
499
|
const debugMode = trimmed.includes("--debug");
|
|
464
500
|
if (debugMode)
|
|
@@ -513,6 +549,11 @@ export async function handleGSDCommand(args, ctx, pi) {
|
|
|
513
549
|
await handleUndo(trimmed.replace(/^undo\s*/, "").trim(), ctx, pi, projectRoot());
|
|
514
550
|
return;
|
|
515
551
|
}
|
|
552
|
+
if (trimmed === "rate" || trimmed.startsWith("rate ")) {
|
|
553
|
+
const { handleRate } = await import("./commands-rate.js");
|
|
554
|
+
await handleRate(trimmed.replace(/^rate\s*/, "").trim(), ctx, projectRoot());
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
516
557
|
if (trimmed.startsWith("skip ")) {
|
|
517
558
|
await handleSkip(trimmed.replace(/^skip\s*/, "").trim(), ctx, projectRoot());
|
|
518
559
|
return;
|
|
@@ -809,7 +850,8 @@ Examples:
|
|
|
809
850
|
return;
|
|
810
851
|
}
|
|
811
852
|
if (trimmed === "") {
|
|
812
|
-
|
|
853
|
+
if (notifyRemoteAutoActive(ctx, projectRoot()))
|
|
854
|
+
return;
|
|
813
855
|
await startAuto(ctx, pi, projectRoot(), false, { step: true });
|
|
814
856
|
return;
|
|
815
857
|
}
|
|
@@ -17,6 +17,7 @@ import { resolveExpectedArtifactPath } from "./auto.js";
|
|
|
17
17
|
import { gsdRoot, milestonesDir, resolveMilestoneFile, resolveSliceFile, resolveSlicePath, resolveGsdRootFile, relGsdRootFile, relMilestoneFile, relSliceFile, } from "./paths.js";
|
|
18
18
|
import { join } from "node:path";
|
|
19
19
|
import { readFileSync, existsSync, mkdirSync, readdirSync, unlinkSync } from "node:fs";
|
|
20
|
+
import { readSessionLockData, isSessionLockProcessAlive } from "./session-lock.js";
|
|
20
21
|
import { nativeIsRepo, nativeInit } from "./native-git-bridge.js";
|
|
21
22
|
import { ensureGitignore, ensurePreferences, untrackRuntimeFiles } from "./gitignore.js";
|
|
22
23
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
@@ -426,7 +427,12 @@ export async function showDiscuss(ctx, pi, basePath) {
|
|
|
426
427
|
// If all pending slices are discussed, notify and exit instead of looping
|
|
427
428
|
const allDiscussed = pendingSlices.every(s => discussedMap.get(s.id));
|
|
428
429
|
if (allDiscussed) {
|
|
429
|
-
|
|
430
|
+
const lockData = readSessionLockData(basePath);
|
|
431
|
+
const remoteAutoRunning = lockData && lockData.pid !== process.pid && isSessionLockProcessAlive(lockData);
|
|
432
|
+
const nextStep = remoteAutoRunning
|
|
433
|
+
? "Auto-mode is already running — use /gsd status to check progress."
|
|
434
|
+
: "Run /gsd to start planning.";
|
|
435
|
+
ctx.ui.notify(`All ${pendingSlices.length} slices discussed. ${nextStep}`, "info");
|
|
430
436
|
return;
|
|
431
437
|
}
|
|
432
438
|
// Find the first undiscussed slice to recommend
|
|
@@ -46,33 +46,21 @@ import { pauseAutoForProviderError, classifyProviderError } from "./provider-err
|
|
|
46
46
|
import { toPosixPath } from "../shared/mod.js";
|
|
47
47
|
import { isParallelActive, shutdownParallel } from "./parallel-orchestrator.js";
|
|
48
48
|
import { DEFAULT_BASH_TIMEOUT_SECS } from "./constants.js";
|
|
49
|
-
// ── Agent Instructions
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
catch { /* non-fatal — skip unreadable file */ }
|
|
63
|
-
}
|
|
64
|
-
const projectPath = join(process.cwd(), ".gsd", "agent-instructions.md");
|
|
65
|
-
if (existsSync(projectPath)) {
|
|
66
|
-
try {
|
|
67
|
-
const content = readFileSync(projectPath, "utf-8").trim();
|
|
68
|
-
if (content)
|
|
69
|
-
parts.push(content);
|
|
49
|
+
// ── Agent Instructions (DEPRECATED) ──────────────────────────────────────
|
|
50
|
+
// agent-instructions.md is deprecated. Use AGENTS.md or CLAUDE.md instead.
|
|
51
|
+
// Pi core natively supports AGENTS.md (with CLAUDE.md fallback) per directory.
|
|
52
|
+
function warnDeprecatedAgentInstructions() {
|
|
53
|
+
const paths = [
|
|
54
|
+
join(homedir(), ".gsd", "agent-instructions.md"),
|
|
55
|
+
join(process.cwd(), ".gsd", "agent-instructions.md"),
|
|
56
|
+
];
|
|
57
|
+
for (const p of paths) {
|
|
58
|
+
if (existsSync(p)) {
|
|
59
|
+
console.warn(`[GSD] DEPRECATED: ${p} is no longer loaded. ` +
|
|
60
|
+
`Migrate your instructions to AGENTS.md (or CLAUDE.md) in the same directory. ` +
|
|
61
|
+
`See https://github.com/gsd-build/GSD-2/issues/1492`);
|
|
70
62
|
}
|
|
71
|
-
catch { /* non-fatal — skip unreadable file */ }
|
|
72
63
|
}
|
|
73
|
-
if (parts.length === 0)
|
|
74
|
-
return null;
|
|
75
|
-
return parts.join("\n\n");
|
|
76
64
|
}
|
|
77
65
|
// ── Depth verification state ──────────────────────────────────────────────
|
|
78
66
|
let depthVerificationDone = false;
|
|
@@ -589,12 +577,8 @@ export default function (pi) {
|
|
|
589
577
|
newSkillsBlock = formatSkillsXml(newSkills);
|
|
590
578
|
}
|
|
591
579
|
}
|
|
592
|
-
//
|
|
593
|
-
|
|
594
|
-
const agentInstructions = loadAgentInstructions();
|
|
595
|
-
if (agentInstructions) {
|
|
596
|
-
agentInstructionsBlock = `\n\n## Agent Instructions\n\nThe following instructions were provided by the user and must be followed in every session:\n\n${agentInstructions}`;
|
|
597
|
-
}
|
|
580
|
+
// Warn if deprecated agent-instructions.md files are still present
|
|
581
|
+
warnDeprecatedAgentInstructions();
|
|
598
582
|
const injection = await buildGuidedExecuteContextInjection(event.prompt, process.cwd());
|
|
599
583
|
// Worktree context — override the static CWD in the system prompt
|
|
600
584
|
let worktreeBlock = "";
|
|
@@ -637,7 +621,7 @@ export default function (pi) {
|
|
|
637
621
|
"Write every .gsd artifact in the worktree path above, never in the main project tree.",
|
|
638
622
|
].join("\n");
|
|
639
623
|
}
|
|
640
|
-
const fullSystem = `${event.systemPrompt}\n\n[SYSTEM CONTEXT — GSD]\n\n${systemContent}${preferenceBlock}${
|
|
624
|
+
const fullSystem = `${event.systemPrompt}\n\n[SYSTEM CONTEXT — GSD]\n\n${systemContent}${preferenceBlock}${knowledgeBlock}${memoryBlock}${newSkillsBlock}${worktreeBlock}`;
|
|
641
625
|
stopContextTimer({
|
|
642
626
|
systemPromptSize: fullSystem.length,
|
|
643
627
|
injectionSize: injection?.length ?? 0,
|
|
@@ -15,6 +15,7 @@ import { join } from "node:path";
|
|
|
15
15
|
import { gsdRoot } from "./paths.js";
|
|
16
16
|
import { parse as parseYaml } from "yaml";
|
|
17
17
|
import { normalizeStringArray } from "../shared/mod.js";
|
|
18
|
+
import { resolveProfileDefaults as _resolveProfileDefaults } from "./preferences-models.js";
|
|
18
19
|
import { MODE_DEFAULTS, } from "./preferences-types.js";
|
|
19
20
|
import { validatePreferences } from "./preferences-validation.js";
|
|
20
21
|
import { formatSkillRef } from "./preferences-skills.js";
|
|
@@ -79,6 +80,17 @@ export function loadEffectiveGSDPreferences() {
|
|
|
79
80
|
...(mergedWarnings.length > 0 ? { warnings: mergedWarnings } : {}),
|
|
80
81
|
};
|
|
81
82
|
}
|
|
83
|
+
// Apply token-profile defaults as the lowest-priority layer so that
|
|
84
|
+
// `token_profile: budget` sets models and phase-skips automatically.
|
|
85
|
+
// Explicit user preferences always override profile defaults.
|
|
86
|
+
const profile = result.preferences.token_profile;
|
|
87
|
+
if (profile) {
|
|
88
|
+
const profileDefaults = _resolveProfileDefaults(profile);
|
|
89
|
+
result = {
|
|
90
|
+
...result,
|
|
91
|
+
preferences: mergePreferences(profileDefaults, result.preferences),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
82
94
|
// Apply mode defaults as the lowest-priority layer
|
|
83
95
|
if (result.preferences.mode) {
|
|
84
96
|
result = {
|
|
@@ -231,6 +231,14 @@ export function acquireSessionLock(basePath) {
|
|
|
231
231
|
stale: 1_800_000, // 30 minutes — match primary lock settings
|
|
232
232
|
update: 10_000,
|
|
233
233
|
onCompromised: () => {
|
|
234
|
+
// Same false-positive suppression as the primary lock (#1512).
|
|
235
|
+
// Without this, the retry path fires _lockCompromised unconditionally
|
|
236
|
+
// on benign mtime drift (laptop sleep, heavy LLM event loop stalls).
|
|
237
|
+
const elapsed = Date.now() - _lockAcquiredAt;
|
|
238
|
+
if (elapsed < 1_800_000) {
|
|
239
|
+
process.stderr.write(`[gsd] Lock heartbeat mismatch after ${Math.round(elapsed / 1000)}s — event loop stall, continuing.\n`);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
234
242
|
_lockCompromised = true;
|
|
235
243
|
_releaseFunction = null;
|
|
236
244
|
},
|
|
@@ -315,6 +323,25 @@ export function updateSessionLock(basePath, unitType, unitId, completedUnits, se
|
|
|
315
323
|
export function validateSessionLock(basePath) {
|
|
316
324
|
// Lock was compromised by proper-lockfile (mtime drift from sleep, stall, etc.)
|
|
317
325
|
if (_lockCompromised) {
|
|
326
|
+
// Recovery gate (#1512): Before declaring the lock lost, check if the lock
|
|
327
|
+
// file still contains our PID. If it does, no other process took over — the
|
|
328
|
+
// onCompromised fired from benign mtime drift (laptop sleep, event loop stall
|
|
329
|
+
// beyond the stale window). Attempt re-acquisition instead of giving up.
|
|
330
|
+
const lp = lockPath(basePath);
|
|
331
|
+
const existing = readExistingLockData(lp);
|
|
332
|
+
if (existing && existing.pid === process.pid) {
|
|
333
|
+
// Lock file still ours — try to re-acquire the OS lock
|
|
334
|
+
try {
|
|
335
|
+
const result = acquireSessionLock(basePath);
|
|
336
|
+
if (result.acquired) {
|
|
337
|
+
process.stderr.write(`[gsd] Lock recovered after onCompromised — lock file PID matched, re-acquired.\n`);
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
catch {
|
|
342
|
+
// Re-acquisition failed — fall through to return false
|
|
343
|
+
}
|
|
344
|
+
}
|
|
318
345
|
return false;
|
|
319
346
|
}
|
|
320
347
|
// If we have an OS-level lock, we're still the owner
|
|
@@ -438,4 +438,4 @@ startTransition(() => setExpensiveState(newValue));
|
|
|
438
438
|
- [web.dev LCP](https://web.dev/articles/lcp)
|
|
439
439
|
- [web.dev INP](https://web.dev/articles/inp)
|
|
440
440
|
- [web.dev CLS](https://web.dev/articles/cls)
|
|
441
|
-
- [
|
|
441
|
+
- [Code Optimizer skill](../code-optimizer/SKILL.md)
|
|
@@ -42,7 +42,7 @@ The file must `export default function(pi: ExtensionAPI) { ... }`.
|
|
|
42
42
|
|
|
43
43
|
## Step 4: Check for Common Mistakes
|
|
44
44
|
|
|
45
|
-
Read
|
|
45
|
+
Read `../references/key-rules-gotchas.md` and verify each rule against the extension code.
|
|
46
46
|
|
|
47
47
|
## Step 5: Add Debugging
|
|
48
48
|
|
|
@@ -163,8 +163,6 @@ When performing an audit, structure findings as:
|
|
|
163
163
|
## References
|
|
164
164
|
|
|
165
165
|
For detailed guidelines on specific areas:
|
|
166
|
-
- [Performance Optimization](../performance/SKILL.md)
|
|
167
166
|
- [Core Web Vitals](../core-web-vitals/SKILL.md)
|
|
168
167
|
- [Accessibility](../accessibility/SKILL.md)
|
|
169
|
-
- [SEO](../seo/SKILL.md)
|
|
170
168
|
- [Best Practices](../best-practices/SKILL.md)
|
package/package.json
CHANGED
|
@@ -140,15 +140,23 @@ export declare class Agent {
|
|
|
140
140
|
* Queue a steering message to interrupt the agent mid-run.
|
|
141
141
|
* Delivered after current tool execution, skips remaining tools.
|
|
142
142
|
*/
|
|
143
|
-
steer(m: AgentMessage): void;
|
|
143
|
+
steer(m: AgentMessage, origin?: "user" | "system"): void;
|
|
144
144
|
/**
|
|
145
145
|
* Queue a follow-up message to be processed after the agent finishes.
|
|
146
146
|
* Delivered only when agent has no more tool calls or steering messages.
|
|
147
147
|
*/
|
|
148
|
-
followUp(m: AgentMessage): void;
|
|
148
|
+
followUp(m: AgentMessage, origin?: "user" | "system"): void;
|
|
149
149
|
clearSteeringQueue(): void;
|
|
150
150
|
clearFollowUpQueue(): void;
|
|
151
151
|
clearAllQueues(): void;
|
|
152
|
+
/**
|
|
153
|
+
* Drain user-origin messages from queues, leaving system messages in place.
|
|
154
|
+
* Used during abort to preserve messages the user explicitly typed.
|
|
155
|
+
*/
|
|
156
|
+
drainUserMessages(): {
|
|
157
|
+
steering: AgentMessage[];
|
|
158
|
+
followUp: AgentMessage[];
|
|
159
|
+
};
|
|
152
160
|
hasQueuedMessages(): boolean;
|
|
153
161
|
private dequeueSteeringMessages;
|
|
154
162
|
private dequeueFollowUpMessages;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEN,KAAK,YAAY,EACjB,KAAK,OAAO,EACZ,KAAK,KAAK,EACV,KAAK,mBAAmB,EAGxB,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAEX,UAAU,EACV,eAAe,EACf,YAAY,EACZ,UAAU,EACV,SAAS,EAKT,QAAQ,EACR,aAAa,EACb,MAAM,YAAY,CAAC;AASpB,MAAM,WAAW,YAAY;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAEnC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAE5E;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAE/F;;OAEG;IACH,YAAY,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC;IAEvC;;OAEG;IACH,YAAY,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC;IAEvC;;OAEG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAEpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,SAAS,CAAC;IAEnF;;OAEG;IACH,SAAS,CAAC,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;IAE7C;;OAEG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC;;OAEG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEN,KAAK,YAAY,EACjB,KAAK,OAAO,EACZ,KAAK,KAAK,EACV,KAAK,mBAAmB,EAGxB,KAAK,eAAe,EACpB,KAAK,SAAS,EACd,MAAM,YAAY,CAAC;AAEpB,OAAO,KAAK,EAEX,UAAU,EACV,eAAe,EACf,YAAY,EACZ,UAAU,EACV,SAAS,EAKT,QAAQ,EACR,aAAa,EACb,MAAM,YAAY,CAAC;AASpB,MAAM,WAAW,YAAY;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAEnC;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IAE5E;;;OAGG;IACH,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAE/F;;OAEG;IACH,YAAY,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC;IAEvC;;OAEG;IACH,YAAY,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC;IAEvC;;OAEG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAEpB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,SAAS,CAAC;IAEnF;;OAEG;IACH,SAAS,CAAC,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;IAE7C;;OAEG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC;;OAEG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAWD,qBAAa,KAAK;IACjB,OAAO,CAAC,MAAM,CAUZ;IAEF,OAAO,CAAC,SAAS,CAAsC;IACvD,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,YAAY,CAA+D;IACnF,OAAO,CAAC,gBAAgB,CAAC,CAA8E;IACvG,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,aAAa,CAAoB;IACzC,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,YAAY,CAA0B;IACvC,QAAQ,EAAE,QAAQ,CAAC;IAC1B,OAAO,CAAC,UAAU,CAAC,CAAS;IACrB,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,GAAG,SAAS,CAAC;IAC1F,OAAO,CAAC,UAAU,CAAC,CAAmC;IACtD,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,oBAAoB,CAAC,CAAa;IAC1C,OAAO,CAAC,gBAAgB,CAAC,CAAkB;IAC3C,OAAO,CAAC,UAAU,CAAY;IAC9B,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAClC,OAAO,CAAC,eAAe,CAAC,CAAoC;IAC5D,OAAO,CAAC,cAAc,CAAC,CAAmC;gBAE9C,IAAI,GAAE,YAAiB;IAenC;;OAEG;IACH,IAAI,SAAS,IAAI,MAAM,GAAG,SAAS,CAElC;IAED;;;OAGG;IACH,IAAI,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAEtC;IAED;;OAEG;IACH,IAAI,eAAe,IAAI,eAAe,GAAG,SAAS,CAEjD;IAED;;OAEG;IACH,IAAI,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,SAAS,EAErD;IAED;;OAEG;IACH,IAAI,SAAS,IAAI,SAAS,CAEzB;IAED;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,SAAS;IAI7B;;OAEG;IACH,IAAI,eAAe,IAAI,MAAM,GAAG,SAAS,CAExC;IAED;;;OAGG;IACH,IAAI,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAE5C;IAED;;;OAGG;IACH,iBAAiB,CAAC,EAAE,EAAE,eAAe,CAAC,gBAAgB,CAAC,GAAG,IAAI;IAI9D;;;OAGG;IACH,gBAAgB,CAAC,EAAE,EAAE,eAAe,CAAC,eAAe,CAAC,GAAG,IAAI;IAI5D,IAAI,KAAK,IAAI,UAAU,CAEtB;IAED,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,IAAI,GAAG,MAAM,IAAI;IAMlD,eAAe,CAAC,CAAC,EAAE,MAAM;IAIzB,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC;IAItB,gBAAgB,CAAC,CAAC,EAAE,aAAa;IAIjC,eAAe,CAAC,IAAI,EAAE,KAAK,GAAG,eAAe;IAI7C,eAAe,IAAI,KAAK,GAAG,eAAe;IAI1C,eAAe,CAAC,IAAI,EAAE,KAAK,GAAG,eAAe;IAI7C,eAAe,IAAI,KAAK,GAAG,eAAe;IAI1C,QAAQ,CAAC,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE;IAI5B,eAAe,CAAC,EAAE,EAAE,YAAY,EAAE;IAIlC,aAAa,CAAC,CAAC,EAAE,YAAY;IAI7B;;;OAGG;IACH,KAAK,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,GAAE,MAAM,GAAG,QAAmB;IAI3D;;;OAGG;IACH,QAAQ,CAAC,CAAC,EAAE,YAAY,EAAE,MAAM,GAAE,MAAM,GAAG,QAAmB;IAI9D,kBAAkB;IAIlB,kBAAkB;IAIlB,cAAc;IAKd;;;OAGG;IACH,iBAAiB,IAAI;QAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;QAAC,QAAQ,EAAE,YAAY,EAAE,CAAA;KAAE;IAQ3E,iBAAiB,IAAI,OAAO;IAI5B,OAAO,CAAC,uBAAuB;IAe/B,OAAO,CAAC,uBAAuB;IAe/B,aAAa;IAIb,KAAK;IAIL,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,KAAK;IAUL,yCAAyC;IACnC,MAAM,CAAC,OAAO,EAAE,YAAY,GAAG,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAC7D,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkCnE;;OAEG;IACG,QAAQ;IA4Bd;;;;OAIG;YACW,QAAQ;IAuItB,OAAO,CAAC,uBAAuB;IAM/B,OAAO,CAAC,IAAI;CAKZ"}
|
|
@@ -145,15 +145,15 @@ export class Agent {
|
|
|
145
145
|
* Queue a steering message to interrupt the agent mid-run.
|
|
146
146
|
* Delivered after current tool execution, skips remaining tools.
|
|
147
147
|
*/
|
|
148
|
-
steer(m) {
|
|
149
|
-
this.steeringQueue.push(m);
|
|
148
|
+
steer(m, origin = "system") {
|
|
149
|
+
this.steeringQueue.push({ message: m, origin });
|
|
150
150
|
}
|
|
151
151
|
/**
|
|
152
152
|
* Queue a follow-up message to be processed after the agent finishes.
|
|
153
153
|
* Delivered only when agent has no more tool calls or steering messages.
|
|
154
154
|
*/
|
|
155
|
-
followUp(m) {
|
|
156
|
-
this.followUpQueue.push(m);
|
|
155
|
+
followUp(m, origin = "system") {
|
|
156
|
+
this.followUpQueue.push({ message: m, origin });
|
|
157
157
|
}
|
|
158
158
|
clearSteeringQueue() {
|
|
159
159
|
this.steeringQueue = [];
|
|
@@ -165,6 +165,17 @@ export class Agent {
|
|
|
165
165
|
this.steeringQueue = [];
|
|
166
166
|
this.followUpQueue = [];
|
|
167
167
|
}
|
|
168
|
+
/**
|
|
169
|
+
* Drain user-origin messages from queues, leaving system messages in place.
|
|
170
|
+
* Used during abort to preserve messages the user explicitly typed.
|
|
171
|
+
*/
|
|
172
|
+
drainUserMessages() {
|
|
173
|
+
const userSteering = this.steeringQueue.filter((e) => e.origin === "user").map((e) => e.message);
|
|
174
|
+
const userFollowUp = this.followUpQueue.filter((e) => e.origin === "user").map((e) => e.message);
|
|
175
|
+
this.steeringQueue = this.steeringQueue.filter((e) => e.origin !== "user");
|
|
176
|
+
this.followUpQueue = this.followUpQueue.filter((e) => e.origin !== "user");
|
|
177
|
+
return { steering: userSteering, followUp: userFollowUp };
|
|
178
|
+
}
|
|
168
179
|
hasQueuedMessages() {
|
|
169
180
|
return this.steeringQueue.length > 0 || this.followUpQueue.length > 0;
|
|
170
181
|
}
|
|
@@ -173,11 +184,11 @@ export class Agent {
|
|
|
173
184
|
if (this.steeringQueue.length > 0) {
|
|
174
185
|
const first = this.steeringQueue[0];
|
|
175
186
|
this.steeringQueue = this.steeringQueue.slice(1);
|
|
176
|
-
return [first];
|
|
187
|
+
return [first.message];
|
|
177
188
|
}
|
|
178
189
|
return [];
|
|
179
190
|
}
|
|
180
|
-
const steering = this.steeringQueue.
|
|
191
|
+
const steering = this.steeringQueue.map((e) => e.message);
|
|
181
192
|
this.steeringQueue = [];
|
|
182
193
|
return steering;
|
|
183
194
|
}
|
|
@@ -186,11 +197,11 @@ export class Agent {
|
|
|
186
197
|
if (this.followUpQueue.length > 0) {
|
|
187
198
|
const first = this.followUpQueue[0];
|
|
188
199
|
this.followUpQueue = this.followUpQueue.slice(1);
|
|
189
|
-
return [first];
|
|
200
|
+
return [first.message];
|
|
190
201
|
}
|
|
191
202
|
return [];
|
|
192
203
|
}
|
|
193
|
-
const followUp = this.followUpQueue.
|
|
204
|
+
const followUp = this.followUpQueue.map((e) => e.message);
|
|
194
205
|
this.followUpQueue = [];
|
|
195
206
|
return followUp;
|
|
196
207
|
}
|