@pmelab/gtd 37.0.0 → 38.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +15 -0
  3. package/dist/chunks/{reserved-zAfoJtR7.mjs → reserved-CfQ8eurM.mjs} +85 -17
  4. package/dist/chunks/{tail-BRC4DGdV.mjs → tail-C7yaWvaS.mjs} +1 -1
  5. package/dist/chunks/{wire-CSsa3Wxd.mjs → wire-BJuZWR3C.mjs} +1 -1
  6. package/dist/gtd.bundle.mjs +1 -1
  7. package/dist/testkit.mjs +1 -1
  8. package/dist/wire.mjs +1 -1
  9. package/dist/workflows/cleanup.mjs +2 -2
  10. package/dist/workflows/feature.mjs +318 -76
  11. package/dist/workflows/fix.mjs +2 -2
  12. package/dist/workflows/review.mjs +2 -2
  13. package/dist/workflows/rollout.mjs +1 -1
  14. package/dist/workflows.mjs +419 -109
  15. package/package.json +1 -1
  16. package/src/testkit/steps.ts +39 -0
  17. package/src/wire/ContextLimit.ts +1 -1
  18. package/src/workflows/feature/continuation-cap.feature +65 -0
  19. package/src/workflows/feature/continuation-rebuild.feature +88 -0
  20. package/src/workflows/feature/continuation-slices.feature +64 -0
  21. package/src/workflows/feature/continuation.feature +205 -0
  22. package/src/workflows/feature/coverage.ts +14 -6
  23. package/src/workflows/feature/criteria.test.ts +17 -1
  24. package/src/workflows/feature/criteria.ts +37 -3
  25. package/src/workflows/feature/feature.ts +64 -15
  26. package/src/workflows/feature/index.ts +1 -0
  27. package/src/workflows/feature/refactor.ts +64 -30
  28. package/src/workflows/feature/seam.ts +157 -48
  29. package/src/workflows/feature/slicing-cap.feature +14 -0
  30. package/src/workflows/feature/slicing.feature +225 -0
  31. package/src/workflows/feature/slicing.test.ts +49 -0
  32. package/src/workflows/feature/slicing.ts +105 -0
  33. package/src/workflows/index.ts +1 -0
  34. package/src/workflows/shared/continuation.ts +92 -0
  35. package/src/workflows/shared/fences.ts +5 -0
  36. package/src/workflows/shared/options.ts +3 -0
  37. package/src/workflows/shared/steps.ts +2 -0
  38. package/src/workflows/shared/text.test.ts +6 -2
  39. package/src/workflows/shared/text.ts +153 -22
  40. package/src/workflows/shared/vars.ts +6 -0
  41. package/src/workflows/shared/workflows.steps.ts +13 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtd",
3
- "version": "37.0.0",
3
+ "version": "38.1.0",
4
4
  "description": "Drive the gtd loop inside Claude Code: agent turns run as subagents, gtd decides every beat",
5
5
  "author": {
6
6
  "name": "Philipp Melab"
package/README.md CHANGED
@@ -313,6 +313,12 @@ note, past 70% (or when the context is about to be compacted) the turn stops and
313
313
  nothing lands. A step's `context` option, or the bundled workflows'
314
314
  `contextLimit` option, moves the two limits — see
315
315
  [Context limits](https://github.com/pmelab/gtd/blob/main/docs/driver.md#context-limits).
316
+ In `feature`, a naive pass, refactor or build turn that wrapped up that way is a
317
+ snapshot: a fresh turn picks up from it with the handoff note and the criteria
318
+ still open, up to 3 times per phase, across its retries (`continuations`), and a
319
+ phase whose continuations keep stopping, or close nothing twice in a row
320
+ (`continuationStall`), rests for a person — see
321
+ [Continuations](https://github.com/pmelab/gtd/blob/main/docs/configuration.md#continuations).
316
322
 
317
323
  ### Or drive it from inside Claude Code
318
324
 
@@ -638,6 +644,15 @@ out is `gtd abandon`. A process from 27.5.0 or later whose judge ruled
638
644
  that slice. Details in
639
645
  [the naive-pass path](docs/configuration.md#the-naive-pass-path).
640
646
 
647
+ **Coarse slices (`sliceMaxCriteria`, default 8).** A change with more acceptance
648
+ criteria than the cap is built in slices: after design an agent groups related
649
+ criteria (same flow or subsystem) into `.gtd/SLICES.md`, as few slices as the
650
+ cap allows, and each slice — naive pass, refactor and rebuild when judged so,
651
+ health loop, quality lap — runs in order from where the previous one landed.
652
+ `gtd slices` lists them as `feature-1`, `feature-2`, … (`refactor-<n>` ahead of
653
+ a refactored one). A change within the cap is one `feature` slice, as before.
654
+ See [Coarse slices](docs/configuration.md#coarse-slices).
655
+
641
656
  **Flag mode (`flagMode`, on by default).** On, the naive pass's judge runs as
642
657
  above and a rebuilt implementation is asked for a new release flag (none at a
643
658
  `low` risk tier); a pass the judge lets land is not asked for one. A project
@@ -133,9 +133,12 @@ const defaults = {
133
133
  refactorFlagPattern: "\\bGTD_FLAG_\\w+",
134
134
  seamAllow: [...testFileGlobs, ".gtd/**"].join(", "),
135
135
  flagMode: "true",
136
+ sliceMaxCriteria: "8",
136
137
  flag_risk_tier: "0",
137
138
  qualityReviews: "correctness, owasp-security, ponytail-review, test-audit, conventions, spec-challenge",
138
- refactorQualityReviews: "correctness, ponytail-review, conventions"
139
+ refactorQualityReviews: "correctness, ponytail-review, conventions",
140
+ continuations: "3",
141
+ continuationStall: "2"
139
142
  };
140
143
  /** Environment settings. */
141
144
  const envDefaults = {
@@ -592,6 +595,24 @@ printf '%s\\n' ${[
592
595
  ].map(quote).join(" ")} > ${quote(".gtd/REQUIREMENTS.md")}
593
596
  `;
594
597
  };
598
+ const slicingPrompt = (cap) => `${stateFileRules}
599
+ - Read \`.gtd/REQUIREMENTS.md\`: its \`## Acceptance Criteria\` are settled
600
+ and more than ${cap}, too many to build in one slice
601
+ - Group them into slices in \`.gtd/SLICES.md\`, one \`## <title>\` heading per
602
+ slice over a \`- AC-<n>\` list item per criterion it builds. Put criteria of
603
+ the same flow or subsystem together; every criterion in exactly one slice,
604
+ at most ${cap} per slice
605
+ - Keep it coarse: as few slices as the cap allows, never one per criterion
606
+ - Order the slices so each builds on the ones before: they run in that order,
607
+ each from where the previous one landed
608
+ - Change nothing but \`.gtd/SLICES.md\` — leave the criteria as they are
609
+ - Leave everything uncommitted and finish your turn — do not commit
610
+ `;
611
+ /** The line telling a slice's turn which criteria are its own; empty for a single slice. */
612
+ const sliceLine = (ids) => ids === void 0 ? "" : `- This slice builds ${ids.join(", ")} only: every rule here about the criteria
613
+ means these. The others are for other slices, before or after it — leave
614
+ them unbuilt and untested
615
+ `;
595
616
  const designSystem = () => `${designPersona}
596
617
 
597
618
  ${agentConduct}`;
@@ -635,7 +656,7 @@ ${strays.map((path) => ` - \`${displayPath(path)}\``).join("\n")}
635
656
  - Introduce no new flag read and add no second read of an existing one:
636
657
  every match of \`${pattern}\` may move, never increase in number`;
637
658
  const withRules = (rules) => rules === void 0 ? "" : `${rules}\n`;
638
- const refactorBuildingPrompt = ({ pkg, strays, pattern, reference, feedback = false, note = false }) => `${stateFileRules}
659
+ const refactorBuildingPrompt = ({ pkg, strays, pattern, reference, feedback = false, note = false, from }) => `${stateFileRules}
639
660
  - The package to implement is \`${pkg}\`; never delete it
640
661
  ${note ? `- The package's \`## Refactor note\` section names the seams to open and the
641
662
  shape each takes, written from the whole naive pass: build exactly those
@@ -650,8 +671,9 @@ ${reference === void 0 ? "" : `- Reference only: \`git show ${reference} -- ${st
650
671
  restructuring afresh here, minus the feature's own behaviour. A
651
672
  refactor that touches none of it is wrong, however clean — never
652
673
  swap in an unrelated tidy-up
653
- `}- Leave everything uncommitted and finish your turn — do not commit
654
- `;
674
+ `}${handoffRule()}
675
+ - Leave everything uncommitted and finish your turn — do not commit
676
+ ${from === void 0 ? "" : continuationLines(from)}`;
655
677
  const refactorFixPrompt = (strays, pattern) => `${stateFileRules}
656
678
  ${fixFeedbackPrompt}
657
679
  ${refactorRules(strays, pattern)}
@@ -1219,7 +1241,7 @@ Print the closing message and stop — this writes nothing itself.
1219
1241
  const listed = (paths, unreadable = []) => paths.map((path) => ` - \`${displayPath(path)}\`${unreadable.includes(path) ? " (unreadable)" : ""}`).join("\n");
1220
1242
  const isRed = (retry) => "red" in retry;
1221
1243
  const isFault = (retry) => "fault" in retry;
1222
- const pickUp = (hash) => `Pick it up — \`git diff --binary ${hash}^ ${hash} | git apply\``;
1244
+ const pickUp = (hash, exclude) => `Pick it up — \`git diff --binary --no-color --no-ext-diff --no-textconv ${hash}^ ${hash}${exclude === void 0 ? "" : ` -- ${quote(":(top)")} ${quote(`:(top,exclude)${exclude}`)}`} | git apply\``;
1223
1245
  const criteriaBinding = (refused) => `- Its \`## Acceptance Criteria\` (\`AC-<n>\`) bind this turn: re-read them from
1224
1246
  the file, never from memory, and stop only when each one holds. They are
1225
1247
  settled — ${refused ? "a turn that changes them is refused" : "leave them as they are"}`;
@@ -1238,9 +1260,35 @@ re-implement. It changed these files outside the expected set:
1238
1260
  ${listed(retry.strays)}
1239
1261
  Start over and choose a different approach; do not rebuild the same diff.
1240
1262
  `;
1241
- const naivePassPrompt = (retry) => `${stateFileRules}
1263
+ const quoted = (text) => text.trimEnd().split("\n").map((line) => line === "" ? "" : ` > ${line}`).join("\n");
1264
+ /** Every turn a continuation may pick up tells its agent where the note goes. */
1265
+ const handoffRule = () => `- Should you be told to stop at a context limit, write the handoff note to
1266
+ \`.gtd/HANDOFF.md\` — what you touched, what was next — and finish your turn:
1267
+ a fresh turn picks up from what you leave, broken or not. That file is the one
1268
+ exception to any path rule here; write it at no other time`;
1269
+ /** `pickUp`: how the snapshot gets into the tree — absent when it already is. */
1270
+ const continuationLines = (from, pickUp) => `
1271
+ Your previous turn stopped at its context limit; this fresh turn picks up from
1272
+ its snapshot (\`${from.snapshot}\`). ${pickUp === void 0 ? "Its work is already in the tree." : `${pickUp}.`} Its handoff note:
1273
+
1274
+ ${quoted(from.note === "" ? "(empty)" : from.note)}
1275
+
1276
+ Still open: ${from.open.length === 0 ? "nothing the workflow can count — finish what the note says is next" : from.open.join(", ")}.
1277
+ ${pickUp === void 0 ? "Delete `.gtd/HANDOFF.md` once you are done; rewrite it should you be stopped again.\n" : ""}`;
1278
+ const oversizedMessage = (phase, from, why, narrowable = true) => `The ${phase} keeps outgrowing its context: ${"cap" in why ? why.cap === 0 ? "continuations are off (`continuations` is 0) and the turn stopped at its context limit" : `${why.cap} continuation${why.cap === 1 ? "" : "s"} ran and the last still stopped at its context limit` : `the last ${why.stall} continuation${why.stall === 1 ? "" : "s"} closed nothing still open`}. The last snapshot is \`${from.snapshot}\`; still open: ${from.open.length === 0 ? "nothing countable" : from.open.join(", ")}.
1279
+
1280
+ Its handoff note:
1281
+
1282
+ ${quoted(from.note === "" ? "(empty)" : from.note)}
1283
+
1284
+ Land to go on: a fresh round of continuations picks up from that snapshot${narrowable ? ` — narrow
1285
+ \`.gtd/REQUIREMENTS.md\` first if the change is too big, or raise the context limit` : ` — raise
1286
+ the context limit first if the refactor is too big`}. \`gtd abandon\` gives the change up.
1287
+ `;
1288
+ /** `from`: a continuation of a pass that stopped at its context limit, in place of `retry`'s pick-up. */
1289
+ const naivePassPrompt = (retry, slice, from) => `${stateFileRules}
1242
1290
  - Read \`.gtd/REQUIREMENTS.md\`: the settled requirements for this change
1243
- ${criteriaBinding(false)}
1291
+ ${sliceLine(slice)}${criteriaBinding(false)}
1244
1292
  - Implement them the quickest way that works — the naive version. Do not
1245
1293
  restructure, abstract or refactor around the change; it may land exactly as
1246
1294
  you leave it, and a reviewer makes it fit
@@ -1255,9 +1303,20 @@ ${criteriaBinding(false)}
1255
1303
  - Run \`${env.testCommand}\` and finish only once it is green with every
1256
1304
  criterion's test passing: the next step runs it on your diff and sends a red
1257
1305
  pass back
1258
- - Leave \`.gtd/\` untouched
1306
+ - Leave \`.gtd/\` untouched, a handoff note excepted
1307
+ ${handoffRule()}
1259
1308
  - Leave everything uncommitted and finish your turn — do not commit
1260
- ${retry === void 0 ? "" : naiveRetry(retry)}`;
1309
+ ${from !== void 0 ? `${continuationLines(from, pickUp(from.snapshot, ".gtd/HANDOFF.md"))}${retry === void 0 ? "" : isFault(retry) ? `
1310
+ The pass this continues was a retry: its tests fell short, and still must not:
1311
+ ${retry.fault}
1312
+ ` : isRed(retry) ? `
1313
+ The pass this continues was a retry after a red suite (\`.gtd/FEEDBACK.md\`
1314
+ holds the output): finish only once the suite is green.
1315
+ ` : `
1316
+ The pass this continues was a retry after a \`reject\`: keep away from the
1317
+ approach that changed these files outside the expected set:
1318
+ ${listed(retry.strays)}
1319
+ `}` : retry === void 0 ? "" : naiveRetry(retry)}`;
1261
1320
  const carries = (rebuild) => (rebuild.acceptance?.ids.length ?? 0) > 0;
1262
1321
  const rebuildLines = ({ note, acceptance }) => `${note === void 0 ? "" : `- The refactor note (\`.gtd/REFACTOR-NOTE.md\`) named the seams the refactor
1263
1322
  opened; plug the change into them:
@@ -1290,9 +1349,13 @@ const afterRefactorLine = (rebuild) => `- A reviewed refactor has just landed an
1290
1349
  though never a release flag. Build only what is still missing, held to every
1291
1350
  rule below; if nothing is, ${carries(rebuild) ? "carry over the acceptance tests below and change nothing else" : "change nothing and finish your turn"}
1292
1351
  `;
1293
- const implementBuildingPrompt = (reference, tier, amend, afterRefactor, flagMode = true, rebuild = {}) => `${stateFileRules}
1352
+ const flagLine = (flagMode, tier, amend, sliced) => !flagMode ? "- Add no release flag — this project ships without release flags" : tier === "low" ? "- Add no release flag — this change is low risk tier" : amend === true ? "- Keep the release flag the earlier lap added, if it added one; otherwise put\n the behaviour behind a new release flag" : sliced ? `- Put the new behaviour behind the release flag an earlier slice of this
1353
+ change added; only when none did, behind a new one, following the
1354
+ repository's flag conventions` : `- Put the new behaviour behind a new release flag, following the
1355
+ repository's flag conventions`;
1356
+ const implementBuildingPrompt = (reference, tier, amend, afterRefactor, flagMode = true, rebuild = {}, slice, from) => `${stateFileRules}
1294
1357
  - Read \`.gtd/REQUIREMENTS.md\`: the settled requirements for this change
1295
- ${criteriaBinding(true)}
1358
+ ${sliceLine(slice)}${criteriaBinding(true)}
1296
1359
  ${afterRefactor === true ? afterRefactorLine(rebuild) : ""}${amend === true ? `- The change already exists in the tree from an earlier lap; amend it to meet
1297
1360
  the re-derived requirements instead of rewriting it
1298
1361
  ` : flagMode ? `- Implement them properly, fitting the codebase's seams and conventions
@@ -1301,14 +1364,14 @@ ${afterRefactor === true ? afterRefactorLine(rebuild) : ""}${amend === true ? `-
1301
1364
  `}${reference === void 0 || amend === true ? "" : `- Reference only: \`git show ${reference}\` shows an earlier naive attempt.
1302
1365
  Read it for ideas; never apply, cherry-pick or check it out — write
1303
1366
  the change fresh${carries(rebuild) ? ", its acceptance tests excepted (below)" : ""}
1304
- `}${rebuildLines(rebuild)}${!flagMode ? "- Add no release flag — this project ships without release flags" : tier === "low" ? "- Add no release flag — this change is low risk tier" : amend === true ? "- Keep the release flag the earlier lap added, if it added one; otherwise put\n the behaviour behind a new release flag" : `- Put the new behaviour behind a new release flag, following the
1305
- repository's flag conventions`}
1367
+ `}${rebuildLines(rebuild)}${flagLine(flagMode, tier, amend, slice !== void 0)}
1306
1368
  - Write the tests first, then the code that makes them pass. Name each
1307
1369
  criterion's ID in the test that covers it (\`[AC-3] …\`): once the suite is
1308
1370
  green a judge checks every ID has a passing test, and sends uncovered ones back
1371
+ ${handoffRule()}
1309
1372
  - Leave \`.gtd/REQUIREMENTS.md\` in place and everything uncommitted, then
1310
1373
  finish your turn
1311
- `;
1374
+ ${from === void 0 ? "" : continuationLines(from)}`;
1312
1375
  const implementFixPrompt = () => `${stateFileRules}
1313
1376
  ${fixFeedbackPrompt}
1314
1377
  - Leave everything uncommitted and finish your turn — do not commit
@@ -1383,9 +1446,9 @@ const coverageMessage = () => `Judging acceptance-criteria coverage. Run \`gtd j
1383
1446
  \`yes\`/\`no\` verdict per criterion ID — or land without a verdict, which
1384
1447
  counts every criterion as uncovered.
1385
1448
  `;
1386
- const coveringPrompt = (uncovered) => `${stateFileRules}
1449
+ const coveringPrompt = (uncovered, slice) => `${stateFileRules}
1387
1450
  - Read \`.gtd/REQUIREMENTS.md\`: the settled requirements for this change
1388
- ${criteriaBinding(true)}
1451
+ ${sliceLine(slice)}${criteriaBinding(true)}
1389
1452
  - A judge found no passing test in this change that covers ${uncovered.join(", ")}.
1390
1453
  Write a behaviour-level test for each, naming its ID in the test or scenario
1391
1454
  name (\`[${uncovered[0]}] …\`), and fix the code if the test shows it falls short
@@ -1412,6 +1475,8 @@ const REVIEW = ".gtd/REVIEW.md";
1412
1475
  const REFACTOR = ".gtd/REFACTOR.md";
1413
1476
  const REFACTOR_NOTE = ".gtd/REFACTOR-NOTE.md";
1414
1477
  const QUALITY = ".gtd/QUALITY.md";
1478
+ const SLICES = ".gtd/SLICES.md";
1479
+ const HANDOFF = ".gtd/HANDOFF.md";
1415
1480
  const planner = () => env.plannerModel ?? "";
1416
1481
  const coder = () => env.coderModel ?? "";
1417
1482
  const fixCheck = (rules) => agentWithSkills("fix", buildFixPrompt(rules), {
@@ -1605,8 +1670,11 @@ const ShippedOptions = Struct({
1605
1670
  reviewSeverityMinP: setting,
1606
1671
  refactorFlagPattern: setting,
1607
1672
  seamAllow: setting,
1673
+ sliceMaxCriteria: setting,
1608
1674
  qualityReviews: setting,
1609
1675
  refactorQualityReviews: setting,
1676
+ continuations: setting,
1677
+ continuationStall: setting,
1610
1678
  testCommand: setting,
1611
1679
  plannerModel: setting,
1612
1680
  coderModel: setting,
@@ -1710,4 +1778,4 @@ const steering = {
1710
1778
  [REVIEW]: "review"
1711
1779
  };
1712
1780
  //#endregion
1713
- export { normaliseCriteriaScript as $, buildReviewAwaitAfterDeferMessage as A, criterionLine as B, fixRisks as C, registryEntry as Ct, reviewing as D, reviewQuality as E, clearCriteriaMessage as F, finisherSystem as G, designGateAnswerMessage as H, clearCriteriaQuestion as I, idleMessage as J, fixReviewNotesPrompt as K, coverageMessage as L, buildReviewFixNitsPrompt as M, buildReviewTriageMessage as N, agentWithSkills as O, builderSystem as P, naivePassPrompt as Q, coverageQuestion as R, fixQuality as S, flipProblems as St, reviewMissing as T, designSystem as U, deferNotesScript as V, designTriagePrompt as W, implementFixPrompt as X, implementBuildingPrompt as Y, naiveApplyFailure as Z, REQUIREMENTS as _, defaults as _t, flagModeOn as a, refactorRules as at, coder as b, flagMentions as bt, baseline as c, reviewGateBlockedMessage as ct, guarded as d, seamByHandMessage as dt, qualityUnresolvedMessage as et, healthy as f, seamSteerMessage as ft, REFACTOR_NOTE as g, unwindFailure as gt, REFACTOR as h, unwindFailedMessage as ht, skills as i, refactorNotePrompt as it, buildReviewCollectingPrompt as j, buildReviewAnswerQuestionsPrompt as k, escalation as l, reviewNotesCapture as lt, QUALITY as m, uncoveredMessage as mt, summary as n, refactorDroppedRefusal as nt, flagShipped as o, reviewEditNotesCapture as ot, FEEDBACK as p, startGateBlockedMessage as pt, handOffAwaitReviewMessage as q, access as r, refactorFixPrompt as rt, shipped as s, reviewEditsCapture as st, steering as t, refactorBuildingPrompt as tt, gate as u, reviewerSystem as ut, REVIEW as v, envDefaults as vt, planner as w, requireFlag as wt, fixCheck as x, flagReferences as xt, awaitReview as y, testFileGlobs as yt, coveringPrompt as z };
1781
+ export { naiveApplyFailure as $, agentWithSkills as A, coverageQuestion as B, fixCheck as C, testFileGlobs as Ct, reviewMissing as D, registryEntry as Dt, planner as E, flipProblems as Et, buildReviewTriageMessage as F, designSystem as G, criterionLine as H, builderSystem as I, fixReviewNotesPrompt as J, designTriagePrompt as K, clearCriteriaMessage as L, buildReviewAwaitAfterDeferMessage as M, buildReviewCollectingPrompt as N, reviewQuality as O, requireFlag as Ot, buildReviewFixNitsPrompt as P, implementFixPrompt as Q, clearCriteriaQuestion as R, coder as S, envDefaults as St, fixRisks as T, flagReferences as Tt, deferNotesScript as U, coveringPrompt as V, designGateAnswerMessage as W, idleMessage as X, handOffAwaitReviewMessage as Y, implementBuildingPrompt as Z, REFACTOR_NOTE as _, startGateBlockedMessage as _t, flagModeOn as a, refactorDroppedRefusal as at, SLICES as b, unwindFailure as bt, baseline as c, refactorRules as ct, guarded as d, reviewGateBlockedMessage as dt, naivePassPrompt as et, healthy as f, reviewNotesCapture as ft, REFACTOR as g, slicingPrompt as gt, QUALITY as h, seamSteerMessage as ht, skills as i, refactorBuildingPrompt as it, buildReviewAnswerQuestionsPrompt as j, reviewing as k, escalation as l, reviewEditNotesCapture as lt, HANDOFF as m, seamByHandMessage as mt, summary as n, oversizedMessage as nt, flagShipped as o, refactorFixPrompt as ot, FEEDBACK as p, reviewerSystem as pt, finisherSystem as q, access as r, qualityUnresolvedMessage as rt, shipped as s, refactorNotePrompt as st, steering as t, normaliseCriteriaScript as tt, gate as u, reviewEditsCapture as ut, REQUIREMENTS as v, uncoveredMessage as vt, fixQuality as w, flagMentions as wt, awaitReview as x, defaults as xt, REVIEW as y, unwindFailedMessage as yt, coverageMessage as z };
@@ -1,6 +1,6 @@
1
1
  import { read, refuse, removeScript, run, scope, showScript, vars } from "../flows.mjs";
2
2
  import { fixFindings, lensEntriesOf, lensOf, qualityLap as qualityLap$1, reviewToHandOff } from "../workflow-kit.mjs";
3
- import { C as fixRisks, D as reviewing, E as reviewQuality, S as fixQuality, T as reviewMissing, d as guarded, f as healthy, l as escalation, m as QUALITY, q as handOffAwaitReviewMessage, v as REVIEW, x as fixCheck, y as awaitReview } from "./reserved-zAfoJtR7.mjs";
3
+ import { C as fixCheck, D as reviewMissing, O as reviewQuality, T as fixRisks, Y as handOffAwaitReviewMessage, d as guarded, f as healthy, h as QUALITY, k as reviewing, l as escalation, w as fixQuality, x as awaitReview, y as REVIEW } from "./reserved-CfQ8eurM.mjs";
4
4
  //#region src/workflows/shared/tail.ts
5
5
  /** The reviewer's own `.gtd/REVIEW.md`, kept beside the human's notes so `fix` can tell them apart. */
6
6
  const REVIEW_ORIG = ".gtd/REVIEW.orig.md";
@@ -591,7 +591,7 @@ const contextHook = (input) => {
591
591
  };
592
592
  if (tokens >= limit.soft * window) return {
593
593
  kind: "soft",
594
- reason: `Context limit: ${used} used, past the ${percent(limit.soft)} soft limit. Stop working now. Do not start anything new; end your turn with a short handoff note as your answer: what you touched, and what was next.`
594
+ reason: `Context limit: ${used} used, past the ${percent(limit.soft)} soft limit. Stop working now. Do not start anything new; end your turn with a short handoff note as your answer: what you touched, and what was next. Where your instructions name a file for that note, write it there too.`
595
595
  };
596
596
  };
597
597
  /** A decision as Claude Code's settings-hook JSON output. */
@@ -37839,7 +37839,7 @@ var init_ContextLimit = __esmMin((() => {
37839
37839
  };
37840
37840
  if (tokens >= limit.soft * window) return {
37841
37841
  kind: "soft",
37842
- reason: `Context limit: ${used} used, past the ${percent(limit.soft)} soft limit. Stop working now. Do not start anything new; end your turn with a short handoff note as your answer: what you touched, and what was next.`
37842
+ reason: `Context limit: ${used} used, past the ${percent(limit.soft)} soft limit. Stop working now. Do not start anything new; end your turn with a short handoff note as your answer: what you touched, and what was next. Where your instructions name a file for that note, write it there too.`
37843
37843
  };
37844
37844
  };
37845
37845
  hookOutput = (decision) => decision.kind === "soft" ? {
package/dist/testkit.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { applyScript, checkScript, configProblems, configure, installContext, isFactoryWorkflow, moveScript, protocolMismatch, removeScript, restoreScript, revertScript, showScript, t as flows_exports } from "./flows.mjs";
2
- import { A as beatKindOf, B as ACCESS_REFUSAL, C as renderLandPlain, D as renderBeatJson, E as beatDocument, O as statusOf, S as renderLandJson, T as renderBeatPlain, U as renderFormat, _ as selectPath, a as contextLimitFault, g as resolveSession, h as globMatches, j as demandOf, l as parseContextWindow, m as slicesDocument, o as contextShapeFault, p as renderSlicesJson, v as judgeJson, x as noopText, y as landFields } from "./chunks/wire-CSsa3Wxd.mjs";
2
+ import { A as beatKindOf, B as ACCESS_REFUSAL, C as renderLandPlain, D as renderBeatJson, E as beatDocument, O as statusOf, S as renderLandJson, T as renderBeatPlain, U as renderFormat, _ as selectPath, a as contextLimitFault, g as resolveSession, h as globMatches, j as demandOf, l as parseContextWindow, m as slicesDocument, o as contextShapeFault, p as renderSlicesJson, v as judgeJson, x as noopText, y as landFields } from "./chunks/wire-BJuZWR3C.mjs";
3
3
  import { C as headingSections, S as headingSectionBodies, a as unansweredQuestions, b as parseThreadsWithFindings, n as openThreads, r as steeringFormatFor, s as parseCodeThreads, t as BUILT_IN_MODE_NAMES, w as formatFinding } from "./chunks/steering-DVILanVf.mjs";
4
4
  import { $ as logWarning, $i as NodeInspectSymbol, $n as map$5, $r as make$19, $t as provide$1, A as catchIf, Ai as add, An as scopeMake, Ar as flatMap$3, At as suspend$5, B as flatMap$4, Bi as getOrElse, Bn as get$3, Br as sync$1, Bt as unsafeMakeLatch, C as all$1, Ci as toArray, Cn as isInterrupted, Cr as exitFail, Ct as sandbox, D as async, Di as GenericTag, Dn as squash, Dr as exitZipRight, Dt as scopedWith$1, E as asVoid$1, Ei as unsafeHead, En as reduceWithContext, Er as exitVoid, Et as scoped$4, F as ensuring$2, Fi as fromIterable, Fn as join$3, Fr as map$3, Ft as tryMap, G as forkIn, Gi as none, Gn as TypeId$10, Gr as whenEffect, Gt as zipLeft, H as fnUntraced, Hi as isSome, Hn as modify$1, Hr as uninterruptible, Ht as when, I as exit, Ii as splitAt, In as sequential, Ir as onInterrupt, It as tryPromise, J as ignore, Ji as left, Jn as all, Jr as DeferredTypeId$1, Jt as spaced$1, K as forkScoped, Ki as some, Kn as Class, Kr as withFiberRuntime, Kt as zipRight$3, L as fail$5, Li as filter$1, Ln as bind, Lr as scopeClose, Lt as try_, M as die$2, Mi as getOption, Mn as _await$2, Mr as interruptAsFiber, Mt as tap, N as dieMessage, Ni as omit, Nn as inheritAll$1, Nr as interruptFiber, Nt as tapErrorCause, O as catchAll$1, Oi as Reference, On as ensuring$3, Or as fiberId, Ot as serviceOption, P as either, Pi as empty$5, Pn as interruptAllAs$1, Pr as interruptible$1, Pt as timeout, Q as isEffect, Qi as BaseProto, Qn as isFailure, Qr as ids, Qt as mergeAll$2, R as failCause$4, Ri as flatMap$5, Rn as bindTo, Rr as succeed$4, Rt as uninterruptible$1, S as addFinalizer$1, Si as takeRight, Sn as isDieType, Sr as exitAs, St as runtime, T as as, Ti as unsafeGet, Tn as map$6, Tr as exitSucceed, Tt as scopeWith, U as forEach$2, Ui as map$8, Un as set$1, Ur as uninterruptibleMask$1, Ut as withFiberRuntime$1, V as flatten$4, Vi as isNone, Vn as make$16, Vr as tap$1, Vt as unsafeMakeSemaphore$1, W as forkDaemon, Wi as match$4, Wn as update$1, Wr as void_$2, Wt as zip$1, X as interruptible, Xi as right, Xn as fail$4, Xr as combine, Xt as tagged, Y as interrupt$4, Yi as match$2, Yn as die, Yr as empty$6, Yt as TaggedError$1, Z as intoDeferred, Zi as pipeArguments, Zn as failCause$3, Zr as combineAll, Zt as fromEffect$5, _ as decodeSync, _i as of, _n as fail$3, _r as deferredIsDone, _t as raceWith, a as Literal, aa as constTrue, ai as size$2, an as updateContext$1, ar as zipRight$2, at as matchCause, b as acquireRelease, bi as reverse, bn as interrupt$3, br as deferredUnsafeDone, bt as runPromise, c as String$, ca as dual, ci as append$1, cn as Scope, cr as asyncInterrupt, ct as negate, d as Union, di as empty$4, dn as close, dr as deferredAwait, dt as orElse, ea as format, ei as none$1, en as provideMerge$1, er as mapBoth, et as makeSemaphore, f as between, fi as filter, fn as extend, fr as deferredComplete, ft as orElseSucceed, gi as map$7, gn as die$1, gr as deferredInterruptWith, gt as race, hi as isEmpty$2, hn as NoSuchElementException, hr as deferredInterrupt, ht as provideService, i as Defect, ia as constFalse, ii as has, in as unsafeRunPromiseExit, ir as zip$2, it as match$5, j as catchTag, ji as get$5, jn as scopeTag, jr as interrupt$2, jt as sync$2, k as catchAllCause, ki as Tag, kn as forEachConcurrentDiscard, kr as fiberRefLocally, kt as succeed$6, l as Struct, la as identity, li as appendAll, ln as addFinalizer, lr as catchAll, lt as onError, m as optional$1, mi as isChunk, mn as make$18, mr as deferredFailCause, mt as provide$2, n as Boolean$, na as equals, ni as make$17, nn as succeed$3, nr as succeed$5, nt as mapBoth$1, o as Never, oa as constUndefined, oi as decode, on as forkIn$1, or as as$1, ot as matchCauseEffect, p as decodeUnknown, pi as fromIterable$1, pn as fork, pr as deferredFail, pt as promise, q as gen, qi as isLeft, qn as spanTag, qr as zipRight$1, qt as zipWith, r as Cause, ra as hasProperty, ri as set$2, rn as unsafeFork, rr as void_$3, rt as mapError, s as Number$, sa as constVoid, si as isFinite, sn as unsafeMakeSemaphore, sr as asVoid, st as matchEffect, t as Array$, ta as toJSON, ti as get$4, tn as scoped$3, tr as match$3, tt as map$4, u as TaggedError, ua as pipe, ui as drop, un as addFinalizerExit, ur as currentContext$1, ut as orDie, v as encodeSync, vi as prepend, vn as failureOrCause, vr as deferredMake, vt as repeat, w as annotateLogs, wi as unsafeFromArray, wn as isInterruptedOnly, wr as exitFailCause, wt as scope, x as acquireUseRelease$2, xi as take$2, xn as interruptors, xr as deferredUnsafeMake, xt as runPromiseExit$1, y as _void, yi as reduce, yn as flipCauseOption, yr as deferredSucceed, yt as retry, z as fiberIdWith, zi as fromNullable, zn as sleep, zr as suspend$4, zt as uninterruptibleMask } from "./chunks/Schema-DO5ttJaI.mjs";
5
5
  import { createRequire } from "node:module";
package/dist/wire.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { A as beatKindOf, B as ACCESS_REFUSAL, C as renderLandPlain, D as renderBeatJson, E as beatDocument, F as EXIT_RUNTIME_ERROR, H as WIRE_SCHEMA, I as EXIT_SIGINT, L as EXIT_SIGTERM, M as stallDiagnosis, N as EXIT_CODES, O as statusOf, P as EXIT_OK, R as EXIT_STRAYS_FOUND, S as renderLandJson, T as renderBeatPlain, U as renderFormat, V as UNATTRIBUTED_MODEL, _ as selectPath, a as contextLimitFault, b as landProseText, c as hookOutput, d as transcriptTokens, f as usageTokens, g as resolveSession, h as globMatches, i as contextHook, j as demandOf, k as BEAT_KINDS, l as parseContextWindow, m as slicesDocument, n as CONTEXT_STOP_FILE_ENV, o as contextShapeFault, p as renderSlicesJson, r as DEFAULT_CONTEXT_LIMIT, s as contextWindowFor, t as CONTEXT_LIMIT_MARKER, u as subagentTranscriptPath, v as judgeJson, w as DEMAND_BRIEFING, x as noopText, y as landFields, z as EXIT_USAGE_ERROR } from "./chunks/wire-CSsa3Wxd.mjs";
1
+ import { A as beatKindOf, B as ACCESS_REFUSAL, C as renderLandPlain, D as renderBeatJson, E as beatDocument, F as EXIT_RUNTIME_ERROR, H as WIRE_SCHEMA, I as EXIT_SIGINT, L as EXIT_SIGTERM, M as stallDiagnosis, N as EXIT_CODES, O as statusOf, P as EXIT_OK, R as EXIT_STRAYS_FOUND, S as renderLandJson, T as renderBeatPlain, U as renderFormat, V as UNATTRIBUTED_MODEL, _ as selectPath, a as contextLimitFault, b as landProseText, c as hookOutput, d as transcriptTokens, f as usageTokens, g as resolveSession, h as globMatches, i as contextHook, j as demandOf, k as BEAT_KINDS, l as parseContextWindow, m as slicesDocument, n as CONTEXT_STOP_FILE_ENV, o as contextShapeFault, p as renderSlicesJson, r as DEFAULT_CONTEXT_LIMIT, s as contextWindowFor, t as CONTEXT_LIMIT_MARKER, u as subagentTranscriptPath, v as judgeJson, w as DEMAND_BRIEFING, x as noopText, y as landFields, z as EXIT_USAGE_ERROR } from "./chunks/wire-BJuZWR3C.mjs";
2
2
  export { ACCESS_REFUSAL, BEAT_KINDS, CONTEXT_LIMIT_MARKER, CONTEXT_STOP_FILE_ENV, DEFAULT_CONTEXT_LIMIT, DEMAND_BRIEFING, EXIT_CODES, EXIT_OK, EXIT_RUNTIME_ERROR, EXIT_SIGINT, EXIT_SIGTERM, EXIT_STRAYS_FOUND, EXIT_USAGE_ERROR, UNATTRIBUTED_MODEL, WIRE_SCHEMA, beatDocument, beatKindOf, contextHook, contextLimitFault, contextShapeFault, contextWindowFor, demandOf, globMatches, hookOutput, judgeJson, landFields, landProseText, noopText, parseContextWindow, renderBeatJson, renderBeatPlain, renderFormat, renderLandJson, renderLandPlain, renderSlicesJson, resolveSession, selectPath, slicesDocument, stallDiagnosis, statusOf, subagentTranscriptPath, transcriptTokens, usageTokens };
@@ -1,6 +1,6 @@
1
1
  import { agent, changes, glob, read, refuse, scope, start, vars } from "../flows.mjs";
2
- import { Ct as registryEntry, _t as defaults, b as coder, i as skills, n as summary, o as flagShipped, r as access, t as steering, vt as envDefaults, wt as requireFlag, xt as flagReferences } from "../chunks/reserved-zAfoJtR7.mjs";
3
- import { a as refusePendingHandOff, r as handOffTail } from "../chunks/tail-BRC4DGdV.mjs";
2
+ import { Dt as registryEntry, Ot as requireFlag, S as coder, St as envDefaults, Tt as flagReferences, i as skills, n as summary, o as flagShipped, r as access, t as steering, xt as defaults } from "../chunks/reserved-CfQ8eurM.mjs";
3
+ import { a as refusePendingHandOff, r as handOffTail } from "../chunks/tail-C7yaWvaS.mjs";
4
4
  //#region src/workflows/cleanup/cleanup.ts
5
5
  const removingPrompt = (name, registry) => `Clean up the release flag "${name}", which is default-on: delete its entry in ${registry}, and remove every \`GTD_FLAG_${name.toUpperCase()}\` check from the shipped sources. Keep the flag-on path; delete code only the off path reached, including tests that pin the off path.`;
6
6
  const cleanupFlow = async () => {