@pmelab/gtd 27.4.0 → 27.5.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 (44) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +8 -0
  3. package/dist/chunks/{Schema-CyImoHTj.mjs → Schema-DO5ttJaI.mjs} +1 -1
  4. package/dist/chunks/{reserved-BPdVZkgv.mjs → reserved-DM5W_LAt.mjs} +64 -3
  5. package/dist/chunks/{tail-iLAMoigl.mjs → tail-6gvLXXcg.mjs} +1 -1
  6. package/dist/flows.mjs +4 -2
  7. package/dist/gtd.bundle.mjs +44 -9
  8. package/dist/testkit.mjs +43 -10
  9. package/dist/workflows/cleanup.mjs +2 -2
  10. package/dist/workflows/feature.mjs +140 -64
  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 +346 -107
  15. package/package.json +1 -1
  16. package/src/cli/Cli.test.ts +49 -1
  17. package/src/cli/Cli.ts +20 -3
  18. package/src/edge/Edge.test.ts +45 -1
  19. package/src/edge/Edge.ts +15 -4
  20. package/src/flags/index.test.ts +14 -1
  21. package/src/flags/index.ts +14 -3
  22. package/src/flows/helpers.ts +7 -3
  23. package/src/replay/judgeDiffShape.test.ts +43 -0
  24. package/src/step/planStart.ts +3 -2
  25. package/src/testkit/TestRepo.ts +3 -0
  26. package/src/testkit/steps.ts +18 -0
  27. package/src/workflow/index.ts +8 -1
  28. package/src/workflow/vars.test.ts +23 -1
  29. package/src/workflow/vars.ts +24 -0
  30. package/src/workflows/feature/feature.ts +9 -2
  31. package/src/workflows/feature/index.ts +1 -0
  32. package/src/workflows/feature/seam-pin.feature +52 -0
  33. package/src/workflows/feature/seam.feature +387 -0
  34. package/src/workflows/feature/seam.test.ts +88 -0
  35. package/src/workflows/feature/seam.ts +110 -0
  36. package/src/workflows/index.ts +1 -0
  37. package/src/workflows/shared/options.test.ts +12 -1
  38. package/src/workflows/shared/options.ts +1 -0
  39. package/src/workflows/shared/skills.test.ts +20 -2
  40. package/src/workflows/shared/skills.ts +6 -0
  41. package/src/workflows/shared/text.test.ts +59 -0
  42. package/src/workflows/shared/text.ts +86 -0
  43. package/src/workflows/shared/vars.ts +4 -0
  44. package/src/workflows/shared/workflows.steps.ts +39 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtd",
3
- "version": "27.4.0",
3
+ "version": "27.5.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
@@ -552,6 +552,14 @@ unknown key. `gtd.config.ts` is the only repository config: gtd 23 removed the
552
552
  home directory — fails every command until you delete it. See
553
553
  [Migrating from `.gtdrc`](https://github.com/pmelab/gtd/blob/main/docs/configuration.md#migrating-from-gtdrc).
554
554
 
555
+ **Naive pass (flag `GTD_FLAG_NAIVE_PASS=1`, off by default).** Instead of an
556
+ architecture and package files, the agent first implements the requirements
557
+ directly. A judge checks whether it changed anything outside the expected set
558
+ (tests, steering files; see `seamAllow`). Incidental changes land; a needed seam
559
+ change goes to you for approval and is refactored first; a wrong approach is
560
+ retried twice, then rests for you to steer or overrule it. Details in
561
+ [the naive-pass path](docs/configuration.md#the-naive-pass-path).
562
+
555
563
  ### Rolling out and cleaning up release flags
556
564
 
557
565
  Two more bundled workflows retire a release flag:
@@ -25449,4 +25449,4 @@ Struct({
25449
25449
  description: "Represents an issue returned by the ArrayFormatter formatter"
25450
25450
  });
25451
25451
  //#endregion
25452
- export { logWarning as $, format$4 as $i, map$4 as $n, make$20 as $r, provide$1 as $t, catchIf as A, get$7 as Ai, scopeMake as An, flatMap$3 as Ar, suspend$1 as At, flatMap$1 as B, isNone as Bi, get as Bn, sync$1 as Br, unsafeMakeLatch as Bt, all as C, toArray$1 as Ci, isInterrupted as Cn, exitFail as Cr, sandbox as Ct, async as D, GenericTag as Di, squash as Dn, exitZipRight as Dr, scopedWith as Dt, asVoid as E, unsafeHead as Ei, reduceWithContext as En, exitVoid$1 as Er, scoped as Et, ensuring as F, splitAt as Fi, join as Fn, map$5 as Fr, tryMap as Ft, forkIn as G, some as Gi, TypeId$4 as Gn, whenEffect as Gr, zipLeft as Gt, fnUntraced as H, map$11 as Hi, modify as Hn, uninterruptible$1 as Hr, when as Ht, exit as I, filter$3 as Ii, sequential$1 as In, onInterrupt as Ir, tryPromise as It, ignore as J, match$7 as Ji, all$2 as Jn, DeferredTypeId as Jr, spaced as Jt, forkScoped as K, isLeft as Ki, Class as Kn, withFiberRuntime$1 as Kr, zipRight as Kt, fail$1 as L, flatMap$6 as Li, bind as Ln, scopeClose as Lr, try_ as Lt, die as M, omit$1 as Mi, _await as Mn, interruptAsFiber as Mr, tap as Mt, dieMessage as N, empty$22 as Ni, inheritAll as Nn, interruptFiber as Nr, tapErrorCause as Nt, catchAll as O, Tag as Oi, ensuring$1 as On, fiberId as Or, serviceOption as Ot, either as P, fromIterable$6 as Pi, interruptAllAs as Pn, interruptible$2 as Pr, timeout as Pt, isEffect as Q, NodeInspectSymbol as Qi, isFailure as Qn, ids as Qr, mergeAll as Qt, failCause as R, fromNullable as Ri, bindTo as Rn, succeed$5 as Rr, uninterruptible as Rt, addFinalizer as S, takeRight as Si, isDieType as Sn, exitAs as Sr, runtime as St, as as T, unsafeGet as Ti, map$3 as Tn, exitSucceed$1 as Tr, scopeWith as Tt, forEach as U, match$6 as Ui, set as Un, uninterruptibleMask$2 as Ur, withFiberRuntime as Ut, flatten as V, isSome as Vi, make$12 as Vn, tap$1 as Vr, unsafeMakeSemaphore as Vt, forkDaemon as W, none$4 as Wi, update$1 as Wn, void_$2 as Wr, zip as Wt, interruptible as X, pipeArguments as Xi, fail$4 as Xn, combine$5 as Xr, tagged as Xt, interrupt as Y, right as Yi, die$2 as Yn, empty$15 as Yr, TaggedError$1 as Yt, intoDeferred as Z, BaseProto as Zi, failCause$2 as Zn, combineAll as Zr, fromEffect as Zt, decodeSync as _, of$1 as _i, fail$2 as _n, deferredIsDone as _r, raceWith as _t, Literal as a, constUndefined as aa, size$2 as ai, updateContext as an, zipRight$1 as ar, matchCause as at, acquireRelease as b, reverse$1 as bi, interrupt$1 as bn, deferredUnsafeDone as br, runPromise as bt, String$ as c, identity as ca, append as ci, Scope as cn, asyncInterrupt as cr, negate as ct, Union as d, empty$19 as di, close as dn, deferredAwait as dr, orElse$1 as dt, toJSON as ea, none$2 as ei, provideMerge as en, mapBoth$2 as er, makeSemaphore as et, between as f, filter$1 as fi, extend$1 as fn, deferredComplete as fr, orElseSucceed as ft, standardSchemaV1 as g, map$9 as gi, die$1 as gn, deferredInterruptWith as gr, race as gt, optionalWith as h, isEmpty$5 as hi, NoSuchElementException as hn, deferredInterrupt as hr, provideService as ht, Defect as i, constTrue as ia, has$1 as ii, unsafeRunPromiseExit as in, zip$1 as ir, match as it, catchTag as j, getOption as ji, scopeTag as jn, interrupt$2 as jr, sync as jt, catchAllCause as k, add$2 as ki, forEachConcurrentDiscard as kn, fiberRefLocally as kr, succeed$1 as kt, Struct as l, pipe as la, appendAll$1 as li, addFinalizer$1 as ln, catchAll$1 as lr, onError as lt, optional as m, isChunk as mi, make$2 as mn, deferredFailCause as mr, provide as mt, Boolean$ as n, hasProperty as na, make$22 as ni, succeed$2 as nn, succeed$4 as nr, mapBoth$1 as nt, Never as o, constVoid as oa, decode as oi, forkIn$1 as on, as$1 as or, matchCauseEffect as ot, decodeUnknown as p, fromIterable$5 as pi, fork as pn, deferredFail as pr, promise as pt, gen as q, left as qi, spanTag as qn, zipRight$2 as qr, zipWith as qt, Cause as r, constFalse as ra, set$3 as ri, unsafeFork as rn, void_$1 as rr, mapError$1 as rt, Number$ as s, dual as sa, isFinite as si, unsafeMakeSemaphore$1 as sn, asVoid$1 as sr, matchEffect as st, Array$ as t, equals$2 as ta, get$4 as ti, scoped$1 as tn, match$3 as tr, map$1 as tt, TaggedError as u, drop as ui, addFinalizerExit as un, currentContext as ur, orDie as ut, encodeSync as v, prepend$1 as vi, failureOrCause as vn, deferredMake as vr, repeat as vt, annotateLogs as w, unsafeFromArray as wi, isInterruptedOnly as wn, exitFailCause$1 as wr, scope as wt, acquireUseRelease as x, take as xi, interruptors as xn, deferredUnsafeMake as xr, runPromiseExit as xt, _void as y, reduce$6 as yi, flipCauseOption as yn, deferredSucceed as yr, retry as yt, fiberIdWith as z, getOrElse as zi, sleep as zn, suspend$3 as zr, uninterruptibleMask as zt };
25452
+ export { logWarning as $, NodeInspectSymbol as $i, map$4 as $n, make$20 as $r, provide$1 as $t, catchIf as A, add$2 as Ai, scopeMake as An, flatMap$3 as Ar, suspend$1 as At, flatMap$1 as B, getOrElse as Bi, get as Bn, sync$1 as Br, unsafeMakeLatch as Bt, all as C, toArray$1 as Ci, isInterrupted as Cn, exitFail as Cr, sandbox as Ct, async as D, GenericTag as Di, squash as Dn, exitZipRight as Dr, scopedWith as Dt, asVoid as E, unsafeHead as Ei, reduceWithContext as En, exitVoid$1 as Er, scoped as Et, ensuring as F, fromIterable$6 as Fi, join as Fn, map$5 as Fr, tryMap as Ft, forkIn as G, none$4 as Gi, TypeId$4 as Gn, whenEffect as Gr, zipLeft as Gt, fnUntraced as H, isSome as Hi, modify as Hn, uninterruptible$1 as Hr, when as Ht, exit as I, splitAt as Ii, sequential$1 as In, onInterrupt as Ir, tryPromise as It, ignore as J, left as Ji, all$2 as Jn, DeferredTypeId as Jr, spaced as Jt, forkScoped as K, some as Ki, Class as Kn, withFiberRuntime$1 as Kr, zipRight as Kt, fail$1 as L, filter$3 as Li, bind as Ln, scopeClose as Lr, try_ as Lt, die as M, getOption as Mi, _await as Mn, interruptAsFiber as Mr, tap as Mt, dieMessage as N, omit$1 as Ni, inheritAll as Nn, interruptFiber as Nr, tapErrorCause as Nt, catchAll as O, Reference as Oi, ensuring$1 as On, fiberId as Or, serviceOption as Ot, either as P, empty$22 as Pi, interruptAllAs as Pn, interruptible$2 as Pr, timeout as Pt, isEffect as Q, BaseProto as Qi, isFailure as Qn, ids as Qr, mergeAll as Qt, failCause as R, flatMap$6 as Ri, bindTo as Rn, succeed$5 as Rr, uninterruptible as Rt, addFinalizer as S, takeRight as Si, isDieType as Sn, exitAs as Sr, runtime as St, as as T, unsafeGet as Ti, map$3 as Tn, exitSucceed$1 as Tr, scopeWith as Tt, forEach as U, map$11 as Ui, set as Un, uninterruptibleMask$2 as Ur, withFiberRuntime as Ut, flatten as V, isNone as Vi, make$12 as Vn, tap$1 as Vr, unsafeMakeSemaphore as Vt, forkDaemon as W, match$6 as Wi, update$1 as Wn, void_$2 as Wr, zip as Wt, interruptible as X, right as Xi, fail$4 as Xn, combine$5 as Xr, tagged as Xt, interrupt as Y, match$7 as Yi, die$2 as Yn, empty$15 as Yr, TaggedError$1 as Yt, intoDeferred as Z, pipeArguments as Zi, failCause$2 as Zn, combineAll as Zr, fromEffect as Zt, decodeSync as _, of$1 as _i, fail$2 as _n, deferredIsDone as _r, raceWith as _t, Literal as a, constTrue as aa, size$2 as ai, updateContext as an, zipRight$1 as ar, matchCause as at, acquireRelease as b, reverse$1 as bi, interrupt$1 as bn, deferredUnsafeDone as br, runPromise as bt, String$ as c, dual as ca, append as ci, Scope as cn, asyncInterrupt as cr, negate as ct, Union as d, empty$19 as di, close as dn, deferredAwait as dr, orElse$1 as dt, format$4 as ea, none$2 as ei, provideMerge as en, mapBoth$2 as er, makeSemaphore as et, between as f, filter$1 as fi, extend$1 as fn, deferredComplete as fr, orElseSucceed as ft, standardSchemaV1 as g, map$9 as gi, die$1 as gn, deferredInterruptWith as gr, race as gt, optionalWith as h, isEmpty$5 as hi, NoSuchElementException as hn, deferredInterrupt as hr, provideService as ht, Defect as i, constFalse as ia, has$1 as ii, unsafeRunPromiseExit as in, zip$1 as ir, match as it, catchTag as j, get$7 as ji, scopeTag as jn, interrupt$2 as jr, sync as jt, catchAllCause as k, Tag as ki, forEachConcurrentDiscard as kn, fiberRefLocally as kr, succeed$1 as kt, Struct as l, identity as la, appendAll$1 as li, addFinalizer$1 as ln, catchAll$1 as lr, onError as lt, optional as m, isChunk as mi, make$2 as mn, deferredFailCause as mr, provide as mt, Boolean$ as n, equals$2 as na, make$22 as ni, succeed$2 as nn, succeed$4 as nr, mapBoth$1 as nt, Never as o, constUndefined as oa, decode as oi, forkIn$1 as on, as$1 as or, matchCauseEffect as ot, decodeUnknown as p, fromIterable$5 as pi, fork as pn, deferredFail as pr, promise as pt, gen as q, isLeft as qi, spanTag as qn, zipRight$2 as qr, zipWith as qt, Cause as r, hasProperty as ra, set$3 as ri, unsafeFork as rn, void_$1 as rr, mapError$1 as rt, Number$ as s, constVoid as sa, isFinite as si, unsafeMakeSemaphore$1 as sn, asVoid$1 as sr, matchEffect as st, Array$ as t, toJSON as ta, get$4 as ti, scoped$1 as tn, match$3 as tr, map$1 as tt, TaggedError as u, pipe as ua, drop as ui, addFinalizerExit as un, currentContext as ur, orDie as ut, encodeSync as v, prepend$1 as vi, failureOrCause as vn, deferredMake as vr, repeat as vt, annotateLogs as w, unsafeFromArray as wi, isInterruptedOnly as wn, exitFailCause$1 as wr, scope as wt, acquireUseRelease as x, take as xi, interruptors as xn, deferredUnsafeMake as xr, runPromiseExit as xt, _void as y, reduce$6 as yi, flipCauseOption as yn, deferredSucceed as yr, retry as yt, fiberIdWith as z, fromNullable as zi, sleep as zn, suspend$3 as zr, uninterruptibleMask as zt };
@@ -1,6 +1,6 @@
1
- import { accessFor, agent, answered, changesSince, check, codeThreads, defineWorkflow, env, head, human, judge, numeric, quote, skillsFor, start, vars } from "../flows.mjs";
1
+ import { accessFor, agent, answered, changesSince, check, codeThreads, defineWorkflow, displayPath, env, head, human, judge, numeric, quote, skillsFor, start, vars } from "../flows.mjs";
2
2
  import { escalation as escalation$1, gate as gate$1, healthy as healthy$1, lensScopes, lensesOf, removedAssertions } from "../workflow-kit.mjs";
3
- import { c as String$, g as standardSchemaV1, h as optionalWith, l as Struct } from "./Schema-CyImoHTj.mjs";
3
+ import { c as String$, g as standardSchemaV1, h as optionalWith, l as Struct } from "./Schema-DO5ttJaI.mjs";
4
4
  //#region src/workflows/shared/prose.ts
5
5
  const skillsPreamble = `- Load whatever's listed here that your harness actually has installed,
6
6
  skip anything it doesn't — silently, never stopping or asking about a
@@ -1071,6 +1071,60 @@ ${it.processCostByModel.map((m) => `- ${m.model}: ${m.cost}\n`).join("")}
1071
1071
  Print the closing message and stop — this writes nothing itself.
1072
1072
  `;
1073
1073
  };
1074
+ const listed = (paths, unreadable = []) => paths.map((path) => ` - \`${displayPath(path)}\`${unreadable.includes(path) ? " (unreadable)" : ""}`).join("\n");
1075
+ const naivePassPrompt = (rejection) => `${stateFileRules}
1076
+ - Read \`.gtd/REQUIREMENTS.md\`: the settled requirements for this change
1077
+ - Implement them the quickest way that works — the naive version. Do not
1078
+ restructure, abstract or refactor around the change; a later step judges
1079
+ the shape of your diff and a reviewer makes it fit
1080
+ - Add tests as you go, and leave \`.gtd/\` untouched
1081
+ - Leave everything uncommitted and finish your turn — do not commit
1082
+ ${rejection === void 0 ? "" : `
1083
+ Your previous attempt was rejected: the judge answered \`reject\` (p=${rejection.p}),
1084
+ meaning the naive pass solved the task the wrong way — discard it and
1085
+ re-implement. It changed these files outside the expected set:
1086
+ ${listed(rejection.strays)}
1087
+ Start over and choose a different approach; do not rebuild the same diff.
1088
+ `}`;
1089
+ const implementBuildingPrompt = (reference) => `${stateFileRules}
1090
+ - Read \`.gtd/REQUIREMENTS.md\`: the settled requirements for this change
1091
+ - Implement them properly, fitting the codebase's seams and conventions
1092
+ - Reference only: \`git show ${reference}\` shows an earlier naive attempt.
1093
+ Read it for ideas; never apply, cherry-pick or check it out — write
1094
+ the change fresh
1095
+ - Put the new behaviour behind a new release flag, following the
1096
+ repository's flag conventions
1097
+ - Write the tests first, then the code that makes them pass
1098
+ - Leave \`.gtd/REQUIREMENTS.md\` in place and everything uncommitted, then
1099
+ finish your turn
1100
+ `;
1101
+ const implementFixPrompt = () => `${stateFileRules}
1102
+ ${fixFeedbackPrompt}
1103
+ - Leave everything uncommitted and finish your turn — do not commit
1104
+ `;
1105
+ const seamSteerMessage = (rejection) => `The naive pass was rejected three times and the retries are spent.
1106
+ The last attempt changed these files outside the expected set:
1107
+ ${listed(rejection.strays)}
1108
+
1109
+ Two ways forward (then run \`gtd land\`):
1110
+ - **Steer** — edit \`.gtd/REQUIREMENTS.md\` to redirect the change; the naive
1111
+ pass runs again with a fresh retry budget
1112
+ - **Overrule** — land a clean tree to accept the last attempt's approach:
1113
+ the implementation is built against it as reference, with no seam gate
1114
+ and no refactor. Risk: this ships the seam the judge objected to,
1115
+ unaddressed — the choice is recorded in history.
1116
+
1117
+ An edit together with an approval counts as steer. Only
1118
+ \`.gtd/REQUIREMENTS.md\` is meant to change here: any other edit lands on the
1119
+ branch unjudged.
1120
+ `;
1121
+ const seamByHandMessage = (strays, unreadable, reference) => `The judge could not read some of these files, so the diff was never
1122
+ fully judged and no refactor runs. Unreadable ones are marked:
1123
+ ${listed(strays, unreadable)}
1124
+
1125
+ See them with \`git show ${reference} -- <path>\` and review by hand. Land a
1126
+ clean tree to go on to the implementation, which runs next.
1127
+ `;
1074
1128
  //#endregion
1075
1129
  //#region src/workflows/shared/steps.ts
1076
1130
  const FEEDBACK = ".gtd/FEEDBACK.md";
@@ -1257,6 +1311,8 @@ const defaults = {
1257
1311
  reviewNoteActionable: "0.7",
1258
1312
  reviewSeverityMinP: "0.7",
1259
1313
  refactorFlagPattern: "\\bGTD_FLAG_\\w+",
1314
+ seamAllow: "**/*.test.*, **/*.spec.*, **/*.feature, **/tests/**, **/test/**, **/__tests__/**, .gtd/**",
1315
+ flag_naive_pass: "0",
1260
1316
  qualityReviews: "correctness, owasp-security, ponytail-review, test-audit, conventions, spec-challenge"
1261
1317
  };
1262
1318
  /** Environment settings. */
@@ -1275,6 +1331,7 @@ const ShippedOptions = Struct({
1275
1331
  reviewNoteActionable: setting,
1276
1332
  reviewSeverityMinP: setting,
1277
1333
  refactorFlagPattern: setting,
1334
+ seamAllow: setting,
1278
1335
  qualityReviews: setting,
1279
1336
  testCommand: setting,
1280
1337
  plannerModel: setting,
@@ -1339,6 +1396,10 @@ const skills = (vars) => ({
1339
1396
  refactor: ["ponytail"],
1340
1397
  "refactor.fix.suite": ["ponytail", "debugging-and-error-recovery"],
1341
1398
  "refactor.health": ["ponytail", "debugging-and-error-recovery"],
1399
+ seam: ["incremental-implementation"],
1400
+ implement: ["test-driven-development", "incremental-implementation"],
1401
+ "implement.fix.suite": ["debugging-and-error-recovery"],
1402
+ "implement.health": ["debugging-and-error-recovery"],
1342
1403
  ...lensScopes("build.quality", lensesOf(vars.qualityReviews ?? ""), (lens) => builtInLenses[lens]?.skills ?? [lens])
1343
1404
  });
1344
1405
  //#endregion
@@ -1362,4 +1423,4 @@ const steering = {
1362
1423
  [REVIEW]: "review"
1363
1424
  };
1364
1425
  //#endregion
1365
- export { reviewGateBlockedMessage as $, architectureAuthorPrompt as A, designGateAnswerMessage as B, fixRisks as C, reviewing as D, reviewQuality as E, buildReviewCollectingPrompt as F, handOffAwaitReviewMessage as G, designTriagePrompt as H, buildReviewFixNitsPrompt as I, packagesItemFixSuitePrompt as J, idleMessage as K, buildReviewTriageMessage as L, architectureGateAnswerMessage as M, buildReviewAnswerQuestionsPrompt as N, agentWithSkills as O, buildReviewAwaitAfterDeferMessage as P, reviewEditsCapture as Q, builderSystem as R, fixQuality as S, reviewMissing as T, finisherSystem as U, designSystem as V, fixReviewNotesPrompt as W, refactorFixPrompt as X, refactorBuildingPrompt as Y, reviewEditNotesCapture as Z, REQUIREMENTS as _, flagShipped as a, coder as b, envDefaults as c, gate as d, reviewNotesCapture as et, guarded as f, QUALITY as g, FEEDBACK as h, skills as i, unwindFailure as it, architectureDecomposePrompt as j, architectSystem as k, baseline as l, ARCHITECTURE as m, summary as n, startGateBlockedMessage as nt, shipped as o, healthy as p, packagesItemBuildingPrompt as q, access as r, unwindFailedMessage as rt, defaults as s, steering as t, reviewerSystem as tt, escalation as u, REVIEW as v, planner as w, fixCheck as x, awaitReview as y, deferNotesScript as z };
1426
+ export { refactorFixPrompt as $, architectureAuthorPrompt as A, designGateAnswerMessage as B, fixRisks as C, reviewing as D, reviewQuality as E, buildReviewCollectingPrompt as F, handOffAwaitReviewMessage as G, designTriagePrompt as H, buildReviewFixNitsPrompt as I, implementFixPrompt as J, idleMessage as K, buildReviewTriageMessage as L, architectureGateAnswerMessage as M, buildReviewAnswerQuestionsPrompt as N, agentWithSkills as O, buildReviewAwaitAfterDeferMessage as P, refactorBuildingPrompt as Q, builderSystem as R, fixQuality as S, reviewMissing as T, finisherSystem as U, designSystem as V, fixReviewNotesPrompt as W, packagesItemBuildingPrompt as X, naivePassPrompt as Y, packagesItemFixSuitePrompt as Z, REQUIREMENTS as _, flagShipped as a, seamByHandMessage as at, coder as b, envDefaults as c, unwindFailedMessage as ct, gate as d, reviewEditNotesCapture as et, guarded as f, QUALITY as g, FEEDBACK as h, skills as i, reviewerSystem as it, architectureDecomposePrompt as j, architectSystem as k, baseline as l, unwindFailure as lt, ARCHITECTURE as m, summary as n, reviewGateBlockedMessage as nt, shipped as o, seamSteerMessage as ot, healthy as p, implementBuildingPrompt as q, access as r, reviewNotesCapture as rt, defaults as s, startGateBlockedMessage as st, steering as t, reviewEditsCapture as tt, escalation as u, REVIEW as v, planner as w, fixCheck as x, awaitReview as y, deferNotesScript as z };
@@ -1,6 +1,6 @@
1
1
  import { read, refuse, removeScript, run, scope, showScript, vars } from "../flows.mjs";
2
2
  import { fixFindings, lensesOf, qualityLap as qualityLap$1, reviewToHandOff } from "../workflow-kit.mjs";
3
- import { C as fixRisks, D as reviewing, E as reviewQuality, G as handOffAwaitReviewMessage, S as fixQuality, T as reviewMissing, f as guarded, g as QUALITY, p as healthy, u as escalation, v as REVIEW, x as fixCheck, y as awaitReview } from "./reserved-BPdVZkgv.mjs";
3
+ import { C as fixRisks, D as reviewing, E as reviewQuality, G as handOffAwaitReviewMessage, S as fixQuality, T as reviewMissing, f as guarded, g as QUALITY, p as healthy, u as escalation, v as REVIEW, x as fixCheck, y as awaitReview } from "./reserved-DM5W_LAt.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";
package/dist/flows.mjs CHANGED
@@ -354,7 +354,8 @@ const strayContent = (strays) => strays.map((c) => [
354
354
  */
355
355
  const judgeDiffShape = async (name, options) => {
356
356
  const { changes: all, allow } = options;
357
- const isStray = (c) => !allow.some((pattern) => matches(c.path, pattern));
357
+ const exempt = options.exempt ?? [];
358
+ const isStray = (c) => !exempt.includes(c.path) && !allow.some((pattern) => matches(c.path, pattern));
358
359
  const strayChanges = all.filter(isStray).sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0).map(({ path, status, before, after }) => ({
359
360
  path,
360
361
  status,
@@ -600,6 +601,7 @@ var flows_exports = /* @__PURE__ */ __exportAll({
600
601
  configure: () => configure,
601
602
  defineConfig: () => defineConfig,
602
603
  defineWorkflow: () => defineWorkflow,
604
+ displayPath: () => displayPath,
603
605
  env: () => env,
604
606
  glob: () => glob,
605
607
  hasThreadFor: () => hasThreadFor,
@@ -640,4 +642,4 @@ var flows_exports = /* @__PURE__ */ __exportAll({
640
642
  wrote: () => wrote
641
643
  });
642
644
  //#endregion
643
- export { FLOWS_PROTOCOL, FlowsProtocolError, accessFor, agent, answered, changes, changesSince, check, checkScript, codeChanges, codeThreads, configProblems, configure, defineConfig, defineWorkflow, env, glob, hasThreadFor, head, human, installContext, isFactoryWorkflow, judge, judgeDiffShape, kept, matches, moveScript, numeric, openQuestions, protocolMismatch, quote, read, refuse, removeScript, requireAnswers, requireProgress, requireReplies, requireRevert, requireThreadsClosed, restart, restoreScript, revertScript, run, scope, seamGate, sectionBodies, sections, showScript, skillsFor, start, flows_exports as t, threads, vars, wrote };
645
+ export { FLOWS_PROTOCOL, FlowsProtocolError, accessFor, agent, answered, changes, changesSince, check, checkScript, codeChanges, codeThreads, configProblems, configure, defineConfig, defineWorkflow, displayPath, env, glob, hasThreadFor, head, human, installContext, isFactoryWorkflow, judge, judgeDiffShape, kept, matches, moveScript, numeric, openQuestions, protocolMismatch, quote, read, refuse, removeScript, requireAnswers, requireProgress, requireReplies, requireRevert, requireThreadsClosed, restart, restoreScript, revertScript, run, scope, seamGate, sectionBodies, sections, showScript, skillsFor, start, flows_exports as t, threads, vars, wrote };
@@ -20970,13 +20970,23 @@ const restorability = (git, headHash, tipHash) => gen(function* () {
20970
20970
  });
20971
20971
  //#endregion
20972
20972
  //#region src/flags/index.ts
20973
- const FLAGS$1 = [];
20973
+ const FLAGS$1 = [{
20974
+ name: "naive_pass",
20975
+ owner: "pmelab",
20976
+ expiry: "2027-01-15",
20977
+ kind: "release"
20978
+ }];
20974
20979
  const BOOL = {
20975
20980
  "0": false,
20976
20981
  false: false,
20977
20982
  "1": true,
20978
20983
  true: true
20979
20984
  };
20985
+ /** A `flag_<name>` setting's value as the pinned `"1"`/`"0"`, or undefined when garbled. */
20986
+ const flagSettingValue = (raw) => {
20987
+ const key = raw.toLowerCase();
20988
+ return Object.hasOwn(BOOL, key) ? BOOL[key] ? "1" : "0" : void 0;
20989
+ };
20980
20990
  const resolveFlags = (env, registry = FLAGS$1) => {
20981
20991
  const out = {};
20982
20992
  for (const { name, defaultOn } of registry) {
@@ -20991,6 +21001,7 @@ const resolveFlags = (env, registry = FLAGS$1) => {
20991
21001
  }
20992
21002
  return out;
20993
21003
  };
21004
+ const flagSettings = (flags) => Object.fromEntries(Object.entries(flags).map(([name, on]) => [`flag_${name}`, on ? "1" : "0"]));
20994
21005
  //#endregion
20995
21006
  //#region src/install/Version.ts
20996
21007
  const _require = createRequire(import.meta.url);
@@ -21976,7 +21987,8 @@ const strayContent = (strays) => strays.map((c) => [
21976
21987
  */
21977
21988
  const judgeDiffShape = async (name, options) => {
21978
21989
  const { changes: all, allow } = options;
21979
- const isStray = (c) => !allow.some((pattern) => matches(c.path, pattern));
21990
+ const exempt = options.exempt ?? [];
21991
+ const isStray = (c) => !exempt.includes(c.path) && !allow.some((pattern) => matches(c.path, pattern));
21980
21992
  const strayChanges = all.filter(isStray).sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0).map(({ path, status, before, after }) => ({
21981
21993
  path,
21982
21994
  status,
@@ -22222,6 +22234,7 @@ var flows_exports = /* @__PURE__ */ __exportAll({
22222
22234
  configure: () => configure$1,
22223
22235
  defineConfig: () => defineConfig,
22224
22236
  defineWorkflow: () => defineWorkflow,
22237
+ displayPath: () => displayPath,
22225
22238
  env: () => env,
22226
22239
  glob: () => glob,
22227
22240
  hasThreadFor: () => hasThreadFor,
@@ -38368,7 +38381,10 @@ const compileConfig = (value, origin) => {
38368
38381
  };
38369
38382
  //#endregion
38370
38383
  //#region src/workflow/vars.ts
38384
+ init_esm();
38371
38385
  const PREFIX = "GTD_";
38386
+ /** The live release flags as `flag_<name>` settings, provided by the CLI; absent means no flags. */
38387
+ var StartFlags = class extends Reference()("StartFlags", { defaultValue: () => ({}) }) {};
38372
38388
  /**
38373
38389
  * One kind of setting, later wins: the workflow's own defaults, `--var`
38374
38390
  * overrides (process settings only; environment settings pass `{}`), then
@@ -38388,6 +38404,18 @@ const resolveVars = (workflowVars, entryVars, env) => {
38388
38404
  }
38389
38405
  return merged;
38390
38406
  };
38407
+ /**
38408
+ * `resolveVars` for a process being STARTED: `flags` land between the workflow
38409
+ * defaults and `--var`, for already-declared names only. A running process never
38410
+ * calls this — it replays its pinned record.
38411
+ */
38412
+ const resolveStartVars = (workflowVars, flags, entryVars, env) => {
38413
+ const declared = Object.fromEntries(Object.entries(flags).filter(([name]) => Object.hasOwn(workflowVars, name)));
38414
+ return resolveVars({
38415
+ ...workflowVars,
38416
+ ...declared
38417
+ }, entryVars, env);
38418
+ };
38391
38419
  /** The first process setting whose value spans lines — a `Gtd-Var:` trailer cannot carry it. */
38392
38420
  const multilineSetting = (vars) => Object.keys(vars).sort().find((name) => /[\r\n]/.test(vars[name]));
38393
38421
  const SETTING_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
@@ -39321,7 +39349,7 @@ const planStart = (current, actor, start) => gen(function* () {
39321
39349
  const overrideRefusal = yield* checkOverrides(commandLabel, varOverrides, Object.keys(workflow.vars), Object.keys(workflow.env));
39322
39350
  if (overrideRefusal !== void 0) return overrideRefusal;
39323
39351
  const baseOf = workflow.def.base;
39324
- const vars = resolveVars(workflow.vars, varOverrides, (yield* Host).env);
39352
+ const vars = resolveStartVars(workflow.vars, yield* StartFlags, varOverrides, (yield* Host).env);
39325
39353
  const multiline = multilineSetting(vars);
39326
39354
  if (multiline !== void 0) return refusal(`${commandLabel}: process setting "${multiline}" spans several lines — a process setting is pinned in a commit trailer and must be a single line`);
39327
39355
  const template = yield* try_({
@@ -39673,9 +39701,9 @@ const pendingTree = (workspace, entries, rewrite) => {
39673
39701
  * are always live. `startOverrides` are `--var` values, passed only while a
39674
39702
  * process is being started.
39675
39703
  */
39676
- const settingsFor = (workflow, pinnedVars, hostEnv, startOverrides = {}) => ({
39704
+ const settingsFor = (workflow, pinnedVars, hostEnv, startOverrides = {}, startFlags) => ({
39677
39705
  vars: {
39678
- ...resolveVars(workflow.vars, startOverrides, hostEnv),
39706
+ ...resolveStartVars(workflow.vars, startFlags, startOverrides, hostEnv),
39679
39707
  ...pinnedVars
39680
39708
  },
39681
39709
  env: resolveVars(workflow.env, {}, hostEnv)
@@ -39849,7 +39877,8 @@ const costByModel = (entries) => {
39849
39877
  const setupFor = (config, run, workspace, host, startOverrides = {}) => gen(function* () {
39850
39878
  const resolved = yield* workflowOf(config, run);
39851
39879
  const def = resolved.def;
39852
- const { vars, env } = settingsFor(resolved, run.pinnedVars, host.env, startOverrides);
39880
+ const startFlags = run.trace.length === 0 ? yield* StartFlags : {};
39881
+ const { vars, env } = settingsFor(resolved, run.pinnedVars, host.env, startOverrides, startFlags);
39853
39882
  const skills = yield* resolveScopeSkills(def, vars);
39854
39883
  const access = yield* resolveScopeAccess(def, skills, vars);
39855
39884
  const budget = yield* try_({
@@ -39959,7 +39988,7 @@ const currentRest = restAt(void 0);
39959
39988
  */
39960
39989
  const startRefusal = (rest, resolved, startVars) => gen(function* () {
39961
39990
  const host = yield* Host;
39962
- const { vars, env } = settingsFor(resolved, {}, host.env, startVars);
39991
+ const { vars, env } = settingsFor(resolved, {}, host.env, startVars, yield* StartFlags);
39963
39992
  const skills = yield* resolveScopeSkills(resolved.def, vars);
39964
39993
  const access = yield* resolveScopeAccess(resolved.def, skills, vars);
39965
39994
  const workspace = rest.setup.workspace;
@@ -40173,7 +40202,7 @@ const summaryFor = (run) => gen(function* () {
40173
40202
  })),
40174
40203
  processCost: run.costEntries.reduce((sum, entry) => sum + entry.cost, 0),
40175
40204
  processCostByModel: costByModel(run.costEntries),
40176
- ...settingsFor(resolved, run.pinnedVars, host.env)
40205
+ ...settingsFor(resolved, run.pinnedVars, host.env, {}, {})
40177
40206
  });
40178
40207
  });
40179
40208
  /** Repository-relative paths of the config files today's config and the process's own record name; one outside the repository cannot be read at a ref, so it is left out. */
@@ -41651,6 +41680,12 @@ const FLAGS = [
41651
41680
  if (/[\r\n]/.test(value)) return left(`gtd: --var ${name} must be a single-line value`);
41652
41681
  if (seen.has(name)) return left(`gtd: --var ${name} specified more than once`);
41653
41682
  seen.add(name);
41683
+ if (name.startsWith("flag_")) {
41684
+ const pinned = flagSettingValue(value);
41685
+ if (pinned === void 0) return left(`gtd: --var ${name} must be 1, 0, true or false`);
41686
+ vars[name] = pinned;
41687
+ continue;
41688
+ }
41654
41689
  vars[name] = value;
41655
41690
  }
41656
41691
  return right(vars);
@@ -42488,7 +42523,7 @@ const runCli = (argv, io) => {
42488
42523
  return flatMap$4(Host, ({ env }) => try_({
42489
42524
  try: () => resolveFlags(env, io.flags),
42490
42525
  catch: (e) => new GtdError(e.message)
42491
- })).pipe(flatMap$4(() => runCommand(plan.command, plan.json, out)), map$4((code) => {
42526
+ })).pipe(flatMap$4((flags) => runCommand(plan.command, plan.json, out).pipe(provideService(StartFlags, flagSettings(flags)))), map$4((code) => {
42492
42527
  out.flush();
42493
42528
  io.exit(code);
42494
42529
  }), provide$1(io.layers(plan.verbose)), sandbox, catchAll((cause) => isInterruptedOnly(cause) ? failCause$2(cause) : report(io, plan.json.kind !== "off")(cause)));
package/dist/testkit.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { checkScript, configProblems, configure, installContext, isFactoryWorkflow, moveScript, protocolMismatch, removeScript, restoreScript, revertScript, showScript, t as flows_exports } from "./flows.mjs";
2
2
  import { E as ACCESS_REFUSAL, _ as demandOf, a as landFields, c as renderLandJson, d as renderBeatPlain, f as beatDocument, g as beatKindOf, i as judgeJson, k as renderFormat, l as renderLandPlain, m as statusOf, n as resolveSession, p as renderBeatJson, r as selectPath, s as noopText, t as globMatches } from "./chunks/wire-C12dahrH.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
- import { $ as logWarning, $i as format, $n as map$5, $r as make$19, $t as provide$1, A as catchIf, Ai as get$5, An as scopeMake, Ar as flatMap$3, At as suspend$5, B as flatMap$4, Bi as isNone, 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 splitAt, Fn as join$3, Fr as map$3, Ft as tryMap, G as forkIn, Gi as some, Gn as TypeId$10, Gr as whenEffect, Gt as zipLeft, H as fnUntraced, Hi as map$8, Hn as modify$1, Hr as uninterruptible, Ht as when, I as exit, Ii as filter$1, In as sequential, Ir as onInterrupt, It as tryPromise, J as ignore, Ji as match$2, Jn as all, Jr as DeferredTypeId$1, Jt as spaced$1, K as forkScoped, Ki as isLeft, Kn as Class, Kr as withFiberRuntime, Kt as zipRight$3, L as fail$5, Li as flatMap$5, Ln as bind, Lr as scopeClose, Lt as try_, M as die$2, Mi as omit, Mn as _await$2, Mr as interruptAsFiber, Mt as tap, N as dieMessage, Ni as empty$5, Nn as inheritAll$1, Nr as interruptFiber, Nt as tapErrorCause, O as catchAll$1, Oi as Tag, On as ensuring$3, Or as fiberId, Ot as serviceOption, P as either, Pi as fromIterable, Pn as interruptAllAs$1, Pr as interruptible$1, Pt as timeout, Q as isEffect, Qi as NodeInspectSymbol, Qn as isFailure, Qr as ids, Qt as mergeAll$2, R as failCause$4, Ri as fromNullable, 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 match$4, Un as set$1, Ur as uninterruptibleMask$1, Ut as withFiberRuntime$1, V as flatten$4, Vi as isSome, Vn as make$16, Vr as tap$1, Vt as unsafeMakeSemaphore$1, W as forkDaemon, Wi as none, Wn as update$1, Wr as void_$2, Wt as zip$1, X as interruptible, Xi as pipeArguments, Xn as fail$4, Xr as combine, Xt as tagged, Y as interrupt$4, Yi as right, Yn as die, Yr as empty$6, Yt as TaggedError$1, Z as intoDeferred, Zi as BaseProto, 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 constUndefined, 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 identity, 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 toJSON, 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 constTrue, ii as has, in as unsafeRunPromiseExit, ir as zip$2, it as match$5, j as catchTag, ji as getOption, jn as scopeTag, jr as interrupt$2, jt as sync$2, k as catchAllCause, ki as add, kn as forEachConcurrentDiscard, kr as fiberRefLocally, kt as succeed$6, l as Struct, la as pipe, 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 hasProperty, ni as make$17, nn as succeed$3, nr as succeed$5, nt as mapBoth$1, o as Never, oa as constVoid, 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 left, qn as spanTag, qr as zipRight$1, qt as zipWith, r as Cause, ra as constFalse, ri as set$2, rn as unsafeFork, rr as void_$3, rt as mapError, s as Number$, sa as dual, si as isFinite, sn as unsafeMakeSemaphore, sr as asVoid, st as matchEffect, t as Array$, ta as equals, ti as get$4, tn as scoped$3, tr as match$3, tt as map$4, u as TaggedError, 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 getOrElse, zn as sleep, zr as suspend$4, zt as uninterruptibleMask } from "./chunks/Schema-CyImoHTj.mjs";
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";
6
6
  import * as Crypto from "node:crypto";
7
7
  import { createHash } from "node:crypto";
@@ -6097,13 +6097,23 @@ const restorability = (git, headHash, tipHash) => gen(function* () {
6097
6097
  });
6098
6098
  //#endregion
6099
6099
  //#region src/flags/index.ts
6100
- const FLAGS$1 = [];
6100
+ const FLAGS$1 = [{
6101
+ name: "naive_pass",
6102
+ owner: "pmelab",
6103
+ expiry: "2027-01-15",
6104
+ kind: "release"
6105
+ }];
6101
6106
  const BOOL = {
6102
6107
  "0": false,
6103
6108
  false: false,
6104
6109
  "1": true,
6105
6110
  true: true
6106
6111
  };
6112
+ /** A `flag_<name>` setting's value as the pinned `"1"`/`"0"`, or undefined when garbled. */
6113
+ const flagSettingValue = (raw) => {
6114
+ const key = raw.toLowerCase();
6115
+ return Object.hasOwn(BOOL, key) ? BOOL[key] ? "1" : "0" : void 0;
6116
+ };
6107
6117
  const resolveFlags = (env, registry = FLAGS$1) => {
6108
6118
  const out = {};
6109
6119
  for (const { name, defaultOn } of registry) {
@@ -6118,6 +6128,7 @@ const resolveFlags = (env, registry = FLAGS$1) => {
6118
6128
  }
6119
6129
  return out;
6120
6130
  };
6131
+ const flagSettings = (flags) => Object.fromEntries(Object.entries(flags).map(([name, on]) => [`flag_${name}`, on ? "1" : "0"]));
6121
6132
  //#endregion
6122
6133
  //#region src/install/Version.ts
6123
6134
  const _require = createRequire(import.meta.url);
@@ -7533,6 +7544,8 @@ const compileConfig = (value, origin) => {
7533
7544
  //#endregion
7534
7545
  //#region src/workflow/vars.ts
7535
7546
  const PREFIX = "GTD_";
7547
+ /** The live release flags as `flag_<name>` settings, provided by the CLI; absent means no flags. */
7548
+ var StartFlags = class extends Reference()("StartFlags", { defaultValue: () => ({}) }) {};
7536
7549
  /**
7537
7550
  * One kind of setting, later wins: the workflow's own defaults, `--var`
7538
7551
  * overrides (process settings only; environment settings pass `{}`), then
@@ -7552,6 +7565,18 @@ const resolveVars = (workflowVars, entryVars, env) => {
7552
7565
  }
7553
7566
  return merged;
7554
7567
  };
7568
+ /**
7569
+ * `resolveVars` for a process being STARTED: `flags` land between the workflow
7570
+ * defaults and `--var`, for already-declared names only. A running process never
7571
+ * calls this — it replays its pinned record.
7572
+ */
7573
+ const resolveStartVars = (workflowVars, flags, entryVars, env) => {
7574
+ const declared = Object.fromEntries(Object.entries(flags).filter(([name]) => Object.hasOwn(workflowVars, name)));
7575
+ return resolveVars({
7576
+ ...workflowVars,
7577
+ ...declared
7578
+ }, entryVars, env);
7579
+ };
7555
7580
  /** The first process setting whose value spans lines — a `Gtd-Var:` trailer cannot carry it. */
7556
7581
  const multilineSetting = (vars) => Object.keys(vars).sort().find((name) => /[\r\n]/.test(vars[name]));
7557
7582
  const SETTING_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
@@ -8480,7 +8505,7 @@ const planStart = (current, actor, start) => gen(function* () {
8480
8505
  const overrideRefusal = yield* checkOverrides(commandLabel, varOverrides, Object.keys(workflow.vars), Object.keys(workflow.env));
8481
8506
  if (overrideRefusal !== void 0) return overrideRefusal;
8482
8507
  const baseOf = workflow.def.base;
8483
- const vars = resolveVars(workflow.vars, varOverrides, (yield* Host).env);
8508
+ const vars = resolveStartVars(workflow.vars, yield* StartFlags, varOverrides, (yield* Host).env);
8484
8509
  const multiline = multilineSetting(vars);
8485
8510
  if (multiline !== void 0) return refusal(`${commandLabel}: process setting "${multiline}" spans several lines — a process setting is pinned in a commit trailer and must be a single line`);
8486
8511
  const template = yield* try_({
@@ -8828,9 +8853,9 @@ const pendingTree = (workspace, entries, rewrite) => {
8828
8853
  * are always live. `startOverrides` are `--var` values, passed only while a
8829
8854
  * process is being started.
8830
8855
  */
8831
- const settingsFor = (workflow, pinnedVars, hostEnv, startOverrides = {}) => ({
8856
+ const settingsFor = (workflow, pinnedVars, hostEnv, startOverrides = {}, startFlags) => ({
8832
8857
  vars: {
8833
- ...resolveVars(workflow.vars, startOverrides, hostEnv),
8858
+ ...resolveStartVars(workflow.vars, startFlags, startOverrides, hostEnv),
8834
8859
  ...pinnedVars
8835
8860
  },
8836
8861
  env: resolveVars(workflow.env, {}, hostEnv)
@@ -9004,7 +9029,8 @@ const costByModel = (entries) => {
9004
9029
  const setupFor = (config, run, workspace, host, startOverrides = {}) => gen(function* () {
9005
9030
  const resolved = yield* workflowOf(config, run);
9006
9031
  const def = resolved.def;
9007
- const { vars, env } = settingsFor(resolved, run.pinnedVars, host.env, startOverrides);
9032
+ const startFlags = run.trace.length === 0 ? yield* StartFlags : {};
9033
+ const { vars, env } = settingsFor(resolved, run.pinnedVars, host.env, startOverrides, startFlags);
9008
9034
  const skills = yield* resolveScopeSkills(def, vars);
9009
9035
  const access = yield* resolveScopeAccess(def, skills, vars);
9010
9036
  const budget = yield* try_({
@@ -9114,7 +9140,7 @@ const currentRest = restAt(void 0);
9114
9140
  */
9115
9141
  const startRefusal = (rest, resolved, startVars) => gen(function* () {
9116
9142
  const host = yield* Host;
9117
- const { vars, env } = settingsFor(resolved, {}, host.env, startVars);
9143
+ const { vars, env } = settingsFor(resolved, {}, host.env, startVars, yield* StartFlags);
9118
9144
  const skills = yield* resolveScopeSkills(resolved.def, vars);
9119
9145
  const access = yield* resolveScopeAccess(resolved.def, skills, vars);
9120
9146
  const workspace = rest.setup.workspace;
@@ -9328,7 +9354,7 @@ const summaryFor = (run) => gen(function* () {
9328
9354
  })),
9329
9355
  processCost: run.costEntries.reduce((sum, entry) => sum + entry.cost, 0),
9330
9356
  processCostByModel: costByModel(run.costEntries),
9331
- ...settingsFor(resolved, run.pinnedVars, host.env)
9357
+ ...settingsFor(resolved, run.pinnedVars, host.env, {}, {})
9332
9358
  });
9333
9359
  });
9334
9360
  /** Repository-relative paths of the config files today's config and the process's own record name; one outside the repository cannot be read at a ref, so it is left out. */
@@ -10800,6 +10826,12 @@ const FLAGS = [
10800
10826
  if (/[\r\n]/.test(value)) return left(`gtd: --var ${name} must be a single-line value`);
10801
10827
  if (seen.has(name)) return left(`gtd: --var ${name} specified more than once`);
10802
10828
  seen.add(name);
10829
+ if (name.startsWith("flag_")) {
10830
+ const pinned = flagSettingValue(value);
10831
+ if (pinned === void 0) return left(`gtd: --var ${name} must be 1, 0, true or false`);
10832
+ vars[name] = pinned;
10833
+ continue;
10834
+ }
10803
10835
  vars[name] = value;
10804
10836
  }
10805
10837
  return right(vars);
@@ -11624,7 +11656,7 @@ const runCli = (argv, io) => {
11624
11656
  return flatMap$4(Host, ({ env }) => try_({
11625
11657
  try: () => resolveFlags(env, io.flags),
11626
11658
  catch: (e) => new GtdError(e.message)
11627
- })).pipe(flatMap$4(() => runCommand$1(plan.command, plan.json, out)), map$4((code) => {
11659
+ })).pipe(flatMap$4((flags) => runCommand$1(plan.command, plan.json, out).pipe(provideService(StartFlags, flagSettings(flags)))), map$4((code) => {
11628
11660
  out.flush();
11629
11661
  io.exit(code);
11630
11662
  }), provide$2(io.layers(plan.verbose)), sandbox, catchAll$1((cause) => isInterruptedOnly(cause) ? failCause$4(cause) : report(io, plan.json.kind !== "off")(cause)));
@@ -13376,7 +13408,8 @@ const testRepo = (options) => {
13376
13408
  }
13377
13409
  throw new Error(`the process did not rest within ${maxBeats} beats`);
13378
13410
  },
13379
- subjects: () => repo.commitHistory().map(({ message }) => message.split("\n")[0] ?? "")
13411
+ subjects: () => repo.commitHistory().map(({ message }) => message.split("\n")[0] ?? ""),
13412
+ messages: () => repo.commitHistory().map(({ message }) => message)
13380
13413
  };
13381
13414
  return self;
13382
13415
  };
@@ -1,6 +1,6 @@
1
1
  import { agent, changes, glob, read, refuse, scope, start, vars } from "../flows.mjs";
2
- import { a as flagShipped, b as coder, c as envDefaults, i as skills, n as summary, r as access, s as defaults, t as steering } from "../chunks/reserved-BPdVZkgv.mjs";
3
- import { i as refusePendingHandOff, r as handOffTail } from "../chunks/tail-iLAMoigl.mjs";
2
+ import { a as flagShipped, b as coder, c as envDefaults, i as skills, n as summary, r as access, s as defaults, t as steering } from "../chunks/reserved-DM5W_LAt.mjs";
3
+ import { i as refusePendingHandOff, r as handOffTail } from "../chunks/tail-6gvLXXcg.mjs";
4
4
  import { i as requireFlag, r as registryEntry, t as flagReferences } from "../chunks/registry-CP3YuV9j.mjs";
5
5
  //#region src/workflows/cleanup/cleanup.ts
6
6
  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.`;