gsd-pi 2.82.0-dev.3a3c6509d → 2.82.0-dev.57fd453e4
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 +1 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto/loop.js +14 -1
- package/dist/resources/extensions/gsd/auto/session.js +4 -0
- package/dist/resources/extensions/gsd/auto/workflow-kernel.js +3 -0
- package/dist/resources/extensions/gsd/auto-post-unit.js +12 -5
- package/dist/resources/extensions/gsd/auto.js +14 -7
- package/dist/resources/extensions/gsd/markdown-renderer.js +10 -8
- package/dist/resources/extensions/gsd/paths.js +4 -0
- package/dist/resources/extensions/gsd/templates/plan.md +1 -0
- package/dist/resources/extensions/gsd/templates/task-plan.md +6 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +3 -5
- package/dist/resources/extensions/ttsr/ttsr-manager.js +3 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/8359.65b24fac92188a6b.js +10 -0
- package/dist/web/standalone/.next/static/chunks/9441.ff70bb53f6835771.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-9a4db269f9ed63ad.js → webpack-855d616060cb6e59.js} +1 -1
- package/package.json +1 -1
- package/src/resources/extensions/gsd/auto/loop.ts +14 -1
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto/workflow-kernel.ts +5 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +13 -5
- package/src/resources/extensions/gsd/auto.ts +13 -7
- package/src/resources/extensions/gsd/markdown-renderer.ts +10 -8
- package/src/resources/extensions/gsd/paths.ts +5 -0
- package/src/resources/extensions/gsd/templates/plan.md +1 -0
- package/src/resources/extensions/gsd/templates/task-plan.md +6 -0
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/auto-post-unit-step-message.test.ts +6 -5
- package/src/resources/extensions/gsd/tests/gsdroot-worktree-detection.test.ts +5 -2
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +84 -0
- package/src/resources/extensions/gsd/tests/quality-gates.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +3 -4
- package/src/resources/extensions/ttsr/ttsr-manager.ts +5 -1
- package/dist/web/standalone/.next/static/chunks/8359.7eb3bb8f8ecf4c01.js +0 -10
- package/dist/web/standalone/.next/static/chunks/9441.1081da1125d1764f.js +0 -1
- /package/dist/web/standalone/.next/static/{O6femb9LLl3nlgsDaYwS- → ky6ieNHfZXB_oHPklwTJb}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{O6femb9LLl3nlgsDaYwS- → ky6ieNHfZXB_oHPklwTJb}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -350,7 +350,7 @@ This is what makes GSD different. Run it, walk away, come back to built software
|
|
|
350
350
|
|
|
351
351
|
Auto mode is a state machine driven by the GSD database at the project root. It derives the next unit of work from authoritative SQLite state, creates a fresh agent session, injects a focused prompt with all relevant context pre-inlined, and lets the LLM execute. When the LLM finishes, auto mode persists the result to the database, refreshes markdown projections such as `STATE.md`, and dispatches the next unit.
|
|
352
352
|
|
|
353
|
-
The database is authoritative for milestones, slices, tasks, requirements, summaries, and completion status. Durable decisions and project knowledge are stored in the `memories` table: decisions are `architecture` memories, and KNOWLEDGE patterns/lessons are `pattern`/`gotcha` memories. Markdown under `.gsd/` is a rendered projection for review, prompts, and git-friendly history; it is not a runtime fallback unless you explicitly run a recovery/import command. In worktree mode,
|
|
353
|
+
The database is authoritative for milestones, slices, tasks, requirements, summaries, and completion status. Durable decisions and project knowledge are stored in the `memories` table: decisions are `architecture` memories, and KNOWLEDGE patterns/lessons are `pattern`/`gotcha` memories. Markdown under `.gsd/` is a rendered projection for review, prompts, and git-friendly history; it is not a runtime fallback unless you explicitly run a recovery/import command. In worktree mode, artifact/projection writes are rendered under the active worktree-local `.gsd/`, while the project-root DB remains authoritative runtime state.
|
|
354
354
|
|
|
355
355
|
`KNOWLEDGE.md` is hybrid: rules remain file-canonical, while patterns and lessons are stored in the `memories` table and rendered back into `KNOWLEDGE.md` on the next session-start projection. Existing pattern and lesson rows are backfilled into memories before projection, so newly captured patterns and lessons may appear in memory-backed prompt context before the file view refreshes.
|
|
356
356
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
8862dc8dc822437d
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Main auto-mode execution loop.
|
|
1
3
|
/**
|
|
2
4
|
* auto/loop.ts — Main auto-mode execution loop.
|
|
3
5
|
*
|
|
@@ -789,11 +791,18 @@ export async function autoLoop(ctx, pi, s, deps, options) {
|
|
|
789
791
|
unitId: iterData.unitId,
|
|
790
792
|
});
|
|
791
793
|
const finalizeReason = finalizeResult.action === "break" ? finalizeResult.reason : undefined;
|
|
794
|
+
const finalizeStatus = finalizeReason === "step-wizard"
|
|
795
|
+
? "completed"
|
|
796
|
+
: finalizeResult.action === "next"
|
|
797
|
+
? "completed"
|
|
798
|
+
: finalizeResult.action === "continue"
|
|
799
|
+
? "retry"
|
|
800
|
+
: "stopped";
|
|
792
801
|
journalReporter.emit("post-unit-finalize-end", {
|
|
793
802
|
iteration,
|
|
794
803
|
unitType: iterData.unitType,
|
|
795
804
|
unitId: iterData.unitId,
|
|
796
|
-
status:
|
|
805
|
+
status: finalizeStatus,
|
|
797
806
|
action: finalizeResult.action,
|
|
798
807
|
...(finalizeReason ? { reason: finalizeReason } : {}),
|
|
799
808
|
});
|
|
@@ -837,6 +846,10 @@ export async function autoLoop(ctx, pi, s, deps, options) {
|
|
|
837
846
|
}) || dispatchSettled;
|
|
838
847
|
completeIteration();
|
|
839
848
|
finishTurn("completed");
|
|
849
|
+
if (finalizeDecision.action === "complete-and-break") {
|
|
850
|
+
s.preserveStepSurfaceAfterLoopExit = true;
|
|
851
|
+
break;
|
|
852
|
+
}
|
|
840
853
|
}
|
|
841
854
|
catch (loopErr) {
|
|
842
855
|
// ── Blanket catch: absorb unexpected exceptions, apply graduated recovery ──
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Mutable auto-mode session state container.
|
|
1
3
|
/**
|
|
2
4
|
* AutoSession — encapsulates all mutable auto-mode state into a single instance.
|
|
3
5
|
*
|
|
@@ -26,6 +28,7 @@ export class AutoSession {
|
|
|
26
28
|
active = false;
|
|
27
29
|
paused = false;
|
|
28
30
|
completionStopInProgress = false;
|
|
31
|
+
preserveStepSurfaceAfterLoopExit = false;
|
|
29
32
|
stepMode = false;
|
|
30
33
|
verbose = false;
|
|
31
34
|
activeEngineId = null;
|
|
@@ -210,6 +213,7 @@ export class AutoSession {
|
|
|
210
213
|
this.active = false;
|
|
211
214
|
this.paused = false;
|
|
212
215
|
this.completionStopInProgress = false;
|
|
216
|
+
this.preserveStepSurfaceAfterLoopExit = false;
|
|
213
217
|
this.stepMode = false;
|
|
214
218
|
this.verbose = false;
|
|
215
219
|
this.activeEngineId = null;
|
|
@@ -66,6 +66,9 @@ export function decideEngineDispatch(input) {
|
|
|
66
66
|
export function decideFinalizeResult(input) {
|
|
67
67
|
if (input.action === "break") {
|
|
68
68
|
const reason = input.reason ?? "unknown";
|
|
69
|
+
if (reason === "step-wizard") {
|
|
70
|
+
return { action: "complete-and-break" };
|
|
71
|
+
}
|
|
69
72
|
return {
|
|
70
73
|
action: "stop",
|
|
71
74
|
failureClass: reason === "git-closeout-failure" ? "git" : "closeout",
|
|
@@ -28,7 +28,7 @@ import { regenerateIfMissing } from "./workflow-projections.js";
|
|
|
28
28
|
import { WorktreeStateProjection } from "./worktree-state-projection.js";
|
|
29
29
|
import { createWorkspace, scopeMilestone } from "./workspace.js";
|
|
30
30
|
import { normalizeWorktreePathForCompare } from "./worktree-root.js";
|
|
31
|
-
import { isDbAvailable, getTask, getSlice, getMilestone, updateTaskStatus, _getAdapter, getVerificationEvidence } from "./gsd-db.js";
|
|
31
|
+
import { isDbAvailable, getDbPath, refreshOpenDatabaseFromDisk, getTask, getSlice, getMilestone, updateTaskStatus, _getAdapter, getVerificationEvidence } from "./gsd-db.js";
|
|
32
32
|
import { renderPlanCheckboxes } from "./markdown-renderer.js";
|
|
33
33
|
import { consumeSignal } from "./session-status-io.js";
|
|
34
34
|
import { checkPostUnitHooks, isRetryPending, consumeRetryTrigger, persistHookState, resolveHookArtifactPath, } from "./post-unit-hooks.js";
|
|
@@ -294,14 +294,14 @@ export function detectRogueFileWrites(unitType, unitId, basePath) {
|
|
|
294
294
|
* looping indefinitely (#2007).
|
|
295
295
|
*/
|
|
296
296
|
export const MAX_ARTIFACT_VERIFICATION_RETRIES = 3;
|
|
297
|
-
export const STEP_COMPLETE_FALLBACK_MESSAGE = "Step complete. Run /clear, then /gsd to continue (or /gsd auto to run continuously).";
|
|
297
|
+
export const STEP_COMPLETE_FALLBACK_MESSAGE = "Step complete. Run /clear if you want a clean view, then /gsd next to continue one step (or /gsd auto to run continuously).";
|
|
298
298
|
export function buildStepCompleteMessage(nextState) {
|
|
299
299
|
if (nextState.phase === "complete") {
|
|
300
300
|
return "Step complete — milestone finished. Run /gsd status to review, or start the next milestone.";
|
|
301
301
|
}
|
|
302
302
|
const next = describeNextUnit(nextState);
|
|
303
303
|
return `Step complete. Next: ${next.label}\n`
|
|
304
|
-
+ `Run /clear, then /gsd to continue (or /gsd auto to run continuously).`;
|
|
304
|
+
+ `Run /clear if you want a clean view, then /gsd next to continue one step (or /gsd auto to run continuously).`;
|
|
305
305
|
}
|
|
306
306
|
/**
|
|
307
307
|
* Decide whether step mode should stop at the step wizard after a unit finishes.
|
|
@@ -553,6 +553,13 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
553
553
|
if (!opts?.skipSettleDelay) {
|
|
554
554
|
await new Promise(r => setTimeout(r, 100));
|
|
555
555
|
}
|
|
556
|
+
const dbPath = getDbPath();
|
|
557
|
+
if (isDbAvailable() && dbPath && dbPath !== ":memory:") {
|
|
558
|
+
const refreshed = refreshOpenDatabaseFromDisk();
|
|
559
|
+
if (!refreshed) {
|
|
560
|
+
logWarning("db", "post-unit database refresh failed; derived state may be stale");
|
|
561
|
+
}
|
|
562
|
+
}
|
|
556
563
|
// Turn-level git action (commit | snapshot | status-only)
|
|
557
564
|
if (s.currentUnit) {
|
|
558
565
|
const unit = s.currentUnit;
|
|
@@ -1458,8 +1465,8 @@ export async function postUnitPostVerification(pctx) {
|
|
|
1458
1465
|
}
|
|
1459
1466
|
}
|
|
1460
1467
|
// Step mode → show wizard instead of dispatch.
|
|
1461
|
-
// Without this notify(), /gsd
|
|
1462
|
-
//
|
|
1468
|
+
// Without this notify(), /gsd next finishes a unit and silently exits the
|
|
1469
|
+
// loop, leaving the user with no next-step command.
|
|
1463
1470
|
if (s.stepMode) {
|
|
1464
1471
|
let phaseAfterUnit = null;
|
|
1465
1472
|
try {
|
|
@@ -689,6 +689,8 @@ export async function rerootCommandSession(cmdCtx, workspaceRoot) {
|
|
|
689
689
|
}
|
|
690
690
|
}
|
|
691
691
|
export async function cleanupAfterLoopExit(ctx) {
|
|
692
|
+
const preserveStepSurface = s.preserveStepSurfaceAfterLoopExit;
|
|
693
|
+
const preservePausedSurface = s.paused;
|
|
692
694
|
s.currentUnit = null;
|
|
693
695
|
s.active = false;
|
|
694
696
|
deactivateGSD();
|
|
@@ -712,19 +714,24 @@ export async function cleanupAfterLoopExit(ctx) {
|
|
|
712
714
|
// A transient provider-error pause intentionally leaves the paused badge
|
|
713
715
|
// visible so the user still has a resumable auto-mode signal on screen.
|
|
714
716
|
if (!s.paused) {
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
717
|
+
if (preserveStepSurface) {
|
|
718
|
+
s.preserveStepSurfaceAfterLoopExit = false;
|
|
719
|
+
}
|
|
720
|
+
else {
|
|
721
|
+
ctx.ui.setStatus("gsd-auto", undefined);
|
|
722
|
+
ctx.ui.setWidget("gsd-progress", undefined);
|
|
723
|
+
if (s.completionStopInProgress) {
|
|
724
|
+
s.completionStopInProgress = false;
|
|
725
|
+
}
|
|
726
|
+
initHealthWidget(ctx);
|
|
719
727
|
}
|
|
720
|
-
initHealthWidget(ctx);
|
|
721
728
|
}
|
|
722
729
|
// ADR-016 phase 3 (#5693): the stop-path basePath restore + chdir routes
|
|
723
730
|
// through `Lifecycle.restoreToProjectRoot()`, the sole owner of both
|
|
724
731
|
// `s.basePath` mutation and the paired `process.chdir` for auto-loop
|
|
725
732
|
// transitions. The verb assigns `s.basePath` before any throwable work, so
|
|
726
733
|
// a thrown error still leaves basePath restored.
|
|
727
|
-
if (s.originalBasePath) {
|
|
734
|
+
if (s.originalBasePath && !preserveStepSurface && !preservePausedSurface) {
|
|
728
735
|
try {
|
|
729
736
|
buildLifecycle().restoreToProjectRoot();
|
|
730
737
|
}
|
|
@@ -732,7 +739,7 @@ export async function cleanupAfterLoopExit(ctx) {
|
|
|
732
739
|
logWarning("engine", `restore project root failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
733
740
|
}
|
|
734
741
|
}
|
|
735
|
-
if (s.originalBasePath && s.cmdCtx) {
|
|
742
|
+
if (s.originalBasePath && s.cmdCtx && !preserveStepSurface && !preservePausedSurface) {
|
|
736
743
|
const result = await rerootCommandSession(s.cmdCtx, s.originalBasePath);
|
|
737
744
|
if (result.status === "cancelled") {
|
|
738
745
|
logWarning("engine", "post-loop session re-root was cancelled", { file: "auto.ts", basePath: s.originalBasePath });
|
|
@@ -14,7 +14,7 @@ import { isClosedStatus } from "./status-guards.js";
|
|
|
14
14
|
import { join, relative } from "node:path";
|
|
15
15
|
import { createRequire } from "node:module";
|
|
16
16
|
import { getAllMilestones, getMilestone, getMilestoneSlices, getSliceTasks, getTask, getSlice, getArtifact, insertArtifact, getGateResults, } from "./gsd-db.js";
|
|
17
|
-
import { resolveMilestoneFile, resolveSliceFile, resolveSlicePath,
|
|
17
|
+
import { resolveMilestoneFile, resolveSliceFile, resolveSlicePath, gsdProjectionRoot, gsdRoot, buildTaskFileName, buildSliceFileName, } from "./paths.js";
|
|
18
18
|
import { saveFile, clearParseCache } from "./files.js";
|
|
19
19
|
import { invalidateStateCache } from "./state.js";
|
|
20
20
|
import { clearPathCache } from "./paths.js";
|
|
@@ -24,7 +24,11 @@ import { clearPathCache } from "./paths.js";
|
|
|
24
24
|
* E.g. "/project/.gsd/milestones/M001/M001-ROADMAP.md" → "milestones/M001/M001-ROADMAP.md"
|
|
25
25
|
*/
|
|
26
26
|
function toArtifactPath(absPath, basePath) {
|
|
27
|
-
const
|
|
27
|
+
const projectionRoot = gsdProjectionRoot(basePath);
|
|
28
|
+
const projectionRel = relative(projectionRoot, absPath);
|
|
29
|
+
const root = projectionRel && !projectionRel.startsWith("..") && !projectionRel.startsWith("/")
|
|
30
|
+
? projectionRoot
|
|
31
|
+
: gsdRoot(basePath);
|
|
28
32
|
const rel = relative(root, absPath);
|
|
29
33
|
// Normalize to forward slashes for consistent DB keys
|
|
30
34
|
return rel.replace(/\\/g, "/");
|
|
@@ -305,10 +309,9 @@ export async function renderPlanFromDb(basePath, milestoneId, sliceId) {
|
|
|
305
309
|
if (tasks.length === 0) {
|
|
306
310
|
throw new Error(`no tasks found for ${milestoneId}/${sliceId}`);
|
|
307
311
|
}
|
|
308
|
-
const slicePath =
|
|
309
|
-
|
|
310
|
-
const absPath =
|
|
311
|
-
?? join(slicePath, `${sliceId}-PLAN.md`);
|
|
312
|
+
const slicePath = join(gsdProjectionRoot(basePath), "milestones", milestoneId, "slices", sliceId);
|
|
313
|
+
mkdirSync(slicePath, { recursive: true });
|
|
314
|
+
const absPath = join(slicePath, `${sliceId}-PLAN.md`);
|
|
312
315
|
const artifactPath = toArtifactPath(absPath, basePath);
|
|
313
316
|
const sliceGates = getGateResults(milestoneId, sliceId, "slice");
|
|
314
317
|
const content = renderSlicePlanMarkdown(slice, tasks, sliceGates);
|
|
@@ -329,8 +332,7 @@ export async function renderTaskPlanFromDb(basePath, milestoneId, sliceId, taskI
|
|
|
329
332
|
if (!task) {
|
|
330
333
|
throw new Error(`task ${milestoneId}/${sliceId}/${taskId} not found`);
|
|
331
334
|
}
|
|
332
|
-
const tasksDir =
|
|
333
|
-
?? join(gsdRoot(basePath), "milestones", milestoneId, "slices", sliceId, "tasks");
|
|
335
|
+
const tasksDir = join(gsdProjectionRoot(basePath), "milestones", milestoneId, "slices", sliceId, "tasks");
|
|
334
336
|
mkdirSync(tasksDir, { recursive: true });
|
|
335
337
|
const absPath = join(tasksDir, buildTaskFileName(taskId, "PLAN"));
|
|
336
338
|
const artifactPath = toArtifactPath(absPath, basePath);
|
|
@@ -320,6 +320,10 @@ export function resolveGsdPathContract(workRoot, originalProjectRoot) {
|
|
|
320
320
|
isWorktree,
|
|
321
321
|
};
|
|
322
322
|
}
|
|
323
|
+
export function gsdProjectionRoot(basePath) {
|
|
324
|
+
const contract = resolveGsdPathContract(basePath);
|
|
325
|
+
return normalizeRealPath(contract.worktreeGsd ?? contract.projectGsd);
|
|
326
|
+
}
|
|
323
327
|
/**
|
|
324
328
|
* Invalidate the gsdRoot cache.
|
|
325
329
|
* Use ONLY at session-reset boundaries: workspace switch, process exit, or
|
|
@@ -132,6 +132,7 @@
|
|
|
132
132
|
Verify field rules:
|
|
133
133
|
- MUST be a mechanically executable command: `npm test`, `grep -q "pattern" file`, `test -f path`
|
|
134
134
|
- MUST NOT use shell pipes, redirects, semicolons, backticks, command substitution, or output trimming
|
|
135
|
+
- MUST NOT use inline `node -e` assertions for verification; put assertions in a real test file and run it with `node --test` or a package test script
|
|
135
136
|
- For content/document tasks: verify file existence, section count, YAML validity, or word count
|
|
136
137
|
NOT exact phrasing, specific formulas, or "zero TBD" aspirational criteria
|
|
137
138
|
- If no command can verify the output, write: "Manual review — file exists and is non-empty"
|
|
@@ -57,6 +57,12 @@ skills_used:
|
|
|
57
57
|
- {{howToVerifyThisTaskIsActuallyDone}}
|
|
58
58
|
- {{commandToRun_OR_behaviorToCheck}}
|
|
59
59
|
|
|
60
|
+
## Verify Rules
|
|
61
|
+
|
|
62
|
+
- Use a real executable check, not prose.
|
|
63
|
+
- If the check needs file-content assertions, write a `node:test` file and run it with `node --test` or a package test script.
|
|
64
|
+
- Do not use inline `node -e` assertions for verification.
|
|
65
|
+
|
|
60
66
|
## Observability Impact
|
|
61
67
|
|
|
62
68
|
<!-- OMIT THIS SECTION ENTIRELY for simple tasks that don't touch runtime boundaries,
|
|
@@ -12,7 +12,7 @@ import { appendEvent } from "../workflow-events.js";
|
|
|
12
12
|
import { logWarning } from "../workflow-logger.js";
|
|
13
13
|
import { validatePlanningPathScope } from "../planning-path-scope.js";
|
|
14
14
|
import { checkFilePathConsistency, checkTaskOrdering } from "../pre-execution-checks.js";
|
|
15
|
-
import { buildTaskFileName,
|
|
15
|
+
import { buildTaskFileName, gsdProjectionRoot } from "../paths.js";
|
|
16
16
|
function validateTasks(value) {
|
|
17
17
|
if (!Array.isArray(value) || value.length === 0) {
|
|
18
18
|
throw new Error("tasks must be a non-empty array");
|
|
@@ -241,14 +241,12 @@ export async function handlePlanSlice(rawParams, basePath) {
|
|
|
241
241
|
return { error: guardError };
|
|
242
242
|
}
|
|
243
243
|
try {
|
|
244
|
-
const tasksDir =
|
|
244
|
+
const tasksDir = join(gsdProjectionRoot(basePath), "milestones", params.milestoneId, "slices", params.sliceId, "tasks");
|
|
245
245
|
for (const taskId of omittedTaskIds) {
|
|
246
|
-
if (!tasksDir)
|
|
247
|
-
continue;
|
|
248
246
|
const taskPlanPath = join(tasksDir, buildTaskFileName(taskId, "PLAN"));
|
|
249
247
|
if (existsSync(taskPlanPath))
|
|
250
248
|
rmSync(taskPlanPath, { force: true });
|
|
251
|
-
const artifactPath = relative(
|
|
249
|
+
const artifactPath = relative(gsdProjectionRoot(basePath), taskPlanPath).replace(/\\/g, "/");
|
|
252
250
|
deleteArtifactByPath(artifactPath);
|
|
253
251
|
}
|
|
254
252
|
const renderResult = await renderPlanFromDb(basePath, params.milestoneId, params.sliceId);
|
|
@@ -43,6 +43,7 @@ const MAX_BUFFER_BYTES = 512 * 1024;
|
|
|
43
43
|
* Prevents CPU spinning when deltas arrive faster than regex evaluation (#468).
|
|
44
44
|
*/
|
|
45
45
|
const JS_FALLBACK_CHECK_INTERVAL_MS = 50;
|
|
46
|
+
const JS_FALLBACK_THROTTLE_MIN_BUFFER_BYTES = 4 * 1024;
|
|
46
47
|
const DEFAULT_SCOPE = {
|
|
47
48
|
allowText: true,
|
|
48
49
|
allowThinking: false,
|
|
@@ -308,7 +309,8 @@ export class TtsrManager {
|
|
|
308
309
|
// streams — regex on a growing buffer is O(rules × buffer_size) (#468).
|
|
309
310
|
const now = Date.now();
|
|
310
311
|
const lastCheck = this.#lastJsCheckAt.get(bufferKey) ?? 0;
|
|
311
|
-
if (
|
|
312
|
+
if (nextBuffer.length >= JS_FALLBACK_THROTTLE_MIN_BUFFER_BYTES &&
|
|
313
|
+
now - lastCheck < JS_FALLBACK_CHECK_INTERVAL_MS) {
|
|
312
314
|
stopTimer({ bufferSize: nextBuffer.length, throttled: true });
|
|
313
315
|
return [];
|
|
314
316
|
}
|