@pmelab/gtd 36.0.0 → 37.0.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 (50) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +21 -9
  3. package/claude/hooks/context.ts +66 -0
  4. package/claude/hooks/drive.ts +3 -0
  5. package/claude/hooks/register.tsx +69 -6
  6. package/dist/chunks/{reserved-BAv71I4i.mjs → reserved-zAfoJtR7.mjs} +53 -16
  7. package/dist/chunks/{tail-kar1zhOb.mjs → tail-BRC4DGdV.mjs} +1 -1
  8. package/dist/chunks/{wire-D3Rc5r22.mjs → wire-CSsa3Wxd.mjs} +117 -2
  9. package/dist/gtd.bundle.mjs +498 -56
  10. package/dist/testkit.mjs +115 -3
  11. package/dist/wire.mjs +2 -2
  12. package/dist/workflows/cleanup.mjs +2 -2
  13. package/dist/workflows/feature.mjs +126 -33
  14. package/dist/workflows/fix.mjs +2 -2
  15. package/dist/workflows/review.mjs +2 -2
  16. package/dist/workflows/rollout.mjs +1 -1
  17. package/dist/workflows.mjs +174 -44
  18. package/package.json +1 -1
  19. package/src/cli/Cli.test.ts +10 -3
  20. package/src/cli/Cli.ts +76 -1
  21. package/src/cli/Program.test.ts +1 -0
  22. package/src/cli/Program.ts +28 -0
  23. package/src/cli/ToolCommands.ts +3 -0
  24. package/src/edge/Edge.ts +11 -0
  25. package/src/flows/runtime.ts +11 -0
  26. package/src/replay/Replay.ts +51 -2
  27. package/src/testkit/Layers.ts +1 -0
  28. package/src/wire/BeatDocument.ts +12 -2
  29. package/src/wire/BeatStatus.ts +3 -0
  30. package/src/wire/ContextLimit.fixture.ts +30 -0
  31. package/src/wire/ContextLimit.test.ts +96 -0
  32. package/src/wire/ContextLimit.ts +169 -0
  33. package/src/wire/index.ts +1 -0
  34. package/src/wire/types.ts +7 -0
  35. package/src/workflow/Workflow.ts +9 -1
  36. package/src/workflows/feature/context-limit.feature +37 -0
  37. package/src/workflows/feature/coverage.ts +8 -2
  38. package/src/workflows/feature/feature.ts +6 -2
  39. package/src/workflows/feature/refactor-absorbs.feature +12 -5
  40. package/src/workflows/feature/refactor-first.feature +11 -2
  41. package/src/workflows/feature/refactor-lens-models.feature +4 -0
  42. package/src/workflows/feature/refactor-rebuild.feature +269 -0
  43. package/src/workflows/feature/refactor-review.feature +45 -1
  44. package/src/workflows/feature/refactor.ts +9 -3
  45. package/src/workflows/feature/seam.test.ts +108 -3
  46. package/src/workflows/feature/seam.ts +120 -19
  47. package/src/workflows/shared/options.test.ts +11 -2
  48. package/src/workflows/shared/options.ts +18 -4
  49. package/src/workflows/shared/steps.ts +1 -0
  50. package/src/workflows/shared/text.ts +80 -14
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 { O as ACCESS_REFUSAL, a as selectPath, d as renderLandPlain, g as statusOf, h as renderBeatJson, i as resolveSession, j as renderFormat, l as noopText, m as beatDocument, n as slicesDocument, o as judgeJson, p as renderBeatPlain, r as globMatches, s as landFields, t as renderSlicesJson, u as renderLandJson, v as beatKindOf, y as demandOf } from "./chunks/wire-D3Rc5r22.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";
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";
@@ -7128,6 +7128,15 @@ const budgeted = (evidence, budgetBytes) => {
7128
7128
  truncated
7129
7129
  };
7130
7130
  };
7131
+ const scopeLabel = (chain) => {
7132
+ const path = chain.flatMap((o) => o.name === void 0 ? [] : [o.name]).join(".");
7133
+ if (chain.at(-1)?.name !== void 0) return `scope "${path}"`;
7134
+ return path === "" ? "an unnamed scope" : `an unnamed scope inside "${path}"`;
7135
+ };
7136
+ const inheritedContext = (layers) => layers.reduce((merged, layer) => layer === void 0 ? merged : {
7137
+ ...merged,
7138
+ ...Object.fromEntries(Object.entries(layer).filter(([, value]) => value !== void 0))
7139
+ }, void 0);
7131
7140
  const sameSkills = (a, b) => (a?.length ?? 0) === (b?.length ?? 0) && (a ?? []).every((skill, i) => skill === b?.[i]);
7132
7141
  const samePersona = (a, b) => a.model === b.model && a.system === b.system && sameSkills(a.skills, b.skills) && sameAccess(a.access, b.access);
7133
7142
  /**
@@ -7147,6 +7156,7 @@ const KNOWN_OPTIONS = {
7147
7156
  ...STEERING_OPTIONS,
7148
7157
  "model",
7149
7158
  "system",
7159
+ "context",
7150
7160
  "allowEmpty",
7151
7161
  "keep"
7152
7162
  ]),
@@ -7261,11 +7271,13 @@ const replay = async (input) => {
7261
7271
  if (s.model !== void 0) persona.model = s.model;
7262
7272
  if (s.system !== void 0) persona.system = s.system;
7263
7273
  }
7274
+ const context = inheritedContext([...scopes.map((s) => s.context), request.options.context]);
7264
7275
  return {
7265
7276
  ...request,
7266
7277
  options: {
7267
7278
  ...persona,
7268
- ...request.options
7279
+ ...request.options,
7280
+ ...context === void 0 ? {} : { context }
7269
7281
  }
7270
7282
  };
7271
7283
  }
@@ -7403,10 +7415,26 @@ const replay = async (input) => {
7403
7415
  });
7404
7416
  return landPending(step, input.pending);
7405
7417
  };
7418
+ const scopeContextFault = () => {
7419
+ for (const [i, s] of scopes.entries()) {
7420
+ const fault = s.context === void 0 ? void 0 : contextShapeFault(s.context);
7421
+ if (fault !== void 0) return `the context of ${scopeLabel(scopes.slice(0, i + 1))}: ${fault}`;
7422
+ }
7423
+ };
7424
+ const resolvedContextFault = (request) => {
7425
+ const own = request.options.context;
7426
+ const layered = scopeContextFault() ?? (own === void 0 ? void 0 : contextShapeFault(own));
7427
+ if (layered !== void 0) return layered;
7428
+ const resolved = resolve(request);
7429
+ const context = resolved.kind === "agent" ? resolved.options.context : void 0;
7430
+ return context === void 0 ? void 0 : contextLimitFault(context);
7431
+ };
7406
7432
  const requestFault = (request) => {
7407
7433
  if (request.kind === "run" && typeof request.body !== "string") return `gtd: step "${scoped(request.name)}": a run() body is a shell script string — decide in flow code, then render the script (see checkScript and friends)`;
7408
7434
  if (request.kind !== "agent") return void 0;
7409
7435
  const name = scoped(request.name);
7436
+ const contextFault = resolvedContextFault(request);
7437
+ if (contextFault !== void 0) return `gtd: step "${name}": ${contextFault}`;
7410
7438
  if (request.options.keep === true) {
7411
7439
  if (request.options.allowEmpty === true) return `gtd: step "${name}": keep: true cannot be combined with allowEmpty — a turn that changes nothing has nothing to keep`;
7412
7440
  const refFault = name.includes("/") ? "it contains \"/\"" : refNameFault(name);
@@ -9016,6 +9044,10 @@ const commonOf = (step) => {
9016
9044
  ...optional("mode", options.mode)
9017
9045
  };
9018
9046
  };
9047
+ const stepContext = (context) => context === void 0 ? void 0 : {
9048
+ ...optional("soft", context.soft),
9049
+ ...optional("hard", context.hard)
9050
+ };
9019
9051
  const promptDef = (common, request, skills, access) => ({
9020
9052
  ...common,
9021
9053
  kind: "prompt",
@@ -9024,6 +9056,7 @@ const promptDef = (common, request, skills, access) => ({
9024
9056
  ...optional("system", request.options.system),
9025
9057
  ...optional("allowEmpty", request.options.allowEmpty),
9026
9058
  ...optional("keep", request.options.keep),
9059
+ ...optional("context", stepContext(request.options.context)),
9027
9060
  ...optional("skills", skills),
9028
9061
  ...optional("access", access)
9029
9062
  });
@@ -9109,7 +9142,8 @@ const hintsOf = (def) => ({
9109
9142
  ...optional("system", def.system),
9110
9143
  ...optional("mode", def.mode),
9111
9144
  ...optional("skills", def.skills),
9112
- ...optional("access", def.access)
9145
+ ...optional("access", def.access),
9146
+ ...optional("context", def.context)
9113
9147
  });
9114
9148
  const normalizeStatus = (raw) => raw === "A" ? "A" : raw === "D" ? "D" : "M";
9115
9149
  /** Per-model token totals, highest-cost first (ties broken by model name). */
@@ -10390,6 +10424,17 @@ const readStdin = () => tryPromise({
10390
10424
  },
10391
10425
  catch: (e) => e instanceof Error ? e : new Error(String(e))
10392
10426
  });
10427
+ /** Stdout is written once: a hook reads one JSON document, or none. */
10428
+ const runContextHookCommand = (command, out) => gen(function* () {
10429
+ const tools = yield* ToolCommands;
10430
+ const input = yield* readStdin();
10431
+ out.write(yield* tools.contextHook({
10432
+ input,
10433
+ ...command.soft !== void 0 ? { soft: command.soft } : {},
10434
+ ...command.hard !== void 0 ? { hard: command.hard } : {},
10435
+ ...command.window !== void 0 ? { window: command.window } : {}
10436
+ }));
10437
+ });
10393
10438
  /** Stdout is written once, after the answerer resolves — a rejection leaves it empty. */
10394
10439
  const runJudgeRunCommand = (command, out) => gen(function* () {
10395
10440
  const host = yield* Host;
@@ -10846,6 +10891,7 @@ const needsOf = (kind) => {
10846
10891
  case "lsp":
10847
10892
  case "install":
10848
10893
  case "loop":
10894
+ case "contextHook":
10849
10895
  case "judgeRun":
10850
10896
  case "strays": return "none";
10851
10897
  case "check":
@@ -10885,6 +10931,7 @@ const dispatchVoidCommand = (command, json, out) => {
10885
10931
  case "uncheck": return runUncheckCommand(command.file);
10886
10932
  case "install": return runInstallCommand(out);
10887
10933
  case "loop": return runLoopCommand();
10934
+ case "contextHook": return runContextHookCommand(command, out);
10888
10935
  case "summary": return runSummaryCommand(out, command.slice);
10889
10936
  case "base": return runBaseCommand(out);
10890
10937
  case "judge": return runJudgeCommand(json, out);
@@ -10926,6 +10973,10 @@ const nonNegativeNumber = (raw, flag) => {
10926
10973
  if (raw.trim() === "" || !Number.isFinite(n) || n < 0) return left(`gtd: ${flag} must be a non-negative number — got "${raw}"`);
10927
10974
  return right(n);
10928
10975
  };
10976
+ const share = (raw, flag) => {
10977
+ const n = Number(raw);
10978
+ return raw.trim() !== "" && n > 0 && n <= 1 ? right(n) : left(`gtd: ${flag} must be a share of the context window in (0, 1] — got "${raw}"`);
10979
+ };
10929
10980
  const FLAGS = [
10930
10981
  {
10931
10982
  name: "--json",
@@ -11053,6 +11104,39 @@ const FLAGS = [
11053
11104
  "GTD_JUDGE_MODEL, then judge.json, then sonnet"
11054
11105
  ]
11055
11106
  },
11107
+ {
11108
+ name: "--soft",
11109
+ arity: 1,
11110
+ repeatable: false,
11111
+ scope: (kind) => kind === "contextHook",
11112
+ decode: ([raw]) => share(raw ?? "", "--soft"),
11113
+ scopeError: "gtd: --soft is only valid for `gtd context-hook`",
11114
+ valueHint: "<share>",
11115
+ help: ["(gtd context-hook only) the soft limit; default 0.6"]
11116
+ },
11117
+ {
11118
+ name: "--hard",
11119
+ arity: 1,
11120
+ repeatable: false,
11121
+ scope: (kind) => kind === "contextHook",
11122
+ decode: ([raw]) => share(raw ?? "", "--hard"),
11123
+ scopeError: "gtd: --hard is only valid for `gtd context-hook`",
11124
+ valueHint: "<share>",
11125
+ help: ["(gtd context-hook only) the hard limit; default 0.7"]
11126
+ },
11127
+ {
11128
+ name: "--window",
11129
+ arity: 1,
11130
+ repeatable: false,
11131
+ scope: (kind) => kind === "contextHook",
11132
+ decode: ([raw]) => {
11133
+ const window = parseContextWindow(raw);
11134
+ return window !== void 0 ? right(window) : left(`gtd: --window must be a positive integer — got "${raw ?? ""}"`);
11135
+ },
11136
+ scopeError: "gtd: --window is only valid for `gtd context-hook`",
11137
+ valueHint: "<tokens>",
11138
+ help: ["(gtd context-hook only) the model's context window in", "tokens; default 200000"]
11139
+ },
11056
11140
  {
11057
11141
  name: "--slice",
11058
11142
  arity: 1,
@@ -11359,6 +11443,22 @@ const COMMAND_ROWS = [
11359
11443
  "~/.config/gtd/loop.json); see docs/driver.md"
11360
11444
  ]
11361
11445
  },
11446
+ {
11447
+ token: "context-hook",
11448
+ kind: "contextHook",
11449
+ arity: "none",
11450
+ details: [
11451
+ "A Claude Code PostToolUse and PreCompact hook that stops an",
11452
+ "agent turn at a share of its context window. Reads the",
11453
+ "hook's input on stdin and the context the transcript's",
11454
+ "latest assistant message used. Past --soft it blocks with a",
11455
+ "request to end the turn with a handoff note; past --hard,",
11456
+ "or at PreCompact, it stops the turn with a stopReason",
11457
+ "starting \"gtd: context limit\". Prints nothing otherwise,",
11458
+ "and for a subagent's tool call. Always exits 0 on valid",
11459
+ "input; see docs/driver.md"
11460
+ ]
11461
+ },
11362
11462
  {
11363
11463
  token: "summary",
11364
11464
  kind: "summary",
@@ -11837,6 +11937,17 @@ const parseArgv = (argv) => {
11837
11937
  verbose
11838
11938
  };
11839
11939
  }
11940
+ if (kind === "contextHook") return {
11941
+ kind: "command",
11942
+ command: {
11943
+ kind: "contextHook",
11944
+ ...bag["--soft"] !== void 0 ? { soft: bag["--soft"] } : {},
11945
+ ...bag["--hard"] !== void 0 ? { hard: bag["--hard"] } : {},
11946
+ ...bag["--window"] !== void 0 ? { window: bag["--window"] } : {}
11947
+ },
11948
+ json,
11949
+ verbose
11950
+ };
11840
11951
  if (kind === "summary") return {
11841
11952
  kind: "command",
11842
11953
  command: {
@@ -12615,6 +12726,7 @@ const missingToolCommands = {
12615
12726
  ui: missingTool("ui"),
12616
12727
  lsp: missingTool("lsp"),
12617
12728
  loop: missingTool("loop"),
12729
+ contextHook: missingTool("context-hook"),
12618
12730
  judge: () => Promise.reject(/* @__PURE__ */ new Error("gtd judge run: ToolCommands has no test double wired into testLayers()"))
12619
12731
  };
12620
12732
  /** The fine-grained `GitService` layer alone — for unit tests that need only git. */
package/dist/wire.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { A as WIRE_SCHEMA, C as EXIT_RUNTIME_ERROR, D as EXIT_USAGE_ERROR, E as EXIT_STRAYS_FOUND, O as ACCESS_REFUSAL, S as EXIT_OK, T as EXIT_SIGTERM, _ as BEAT_KINDS, a as selectPath, b as stallDiagnosis, c as landProseText, d as renderLandPlain, f as DEMAND_BRIEFING, g as statusOf, h as renderBeatJson, i as resolveSession, j as renderFormat, k as UNATTRIBUTED_MODEL, l as noopText, m as beatDocument, n as slicesDocument, o as judgeJson, p as renderBeatPlain, r as globMatches, s as landFields, t as renderSlicesJson, u as renderLandJson, v as beatKindOf, w as EXIT_SIGINT, x as EXIT_CODES, y as demandOf } from "./chunks/wire-D3Rc5r22.mjs";
2
- export { ACCESS_REFUSAL, BEAT_KINDS, 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, demandOf, globMatches, judgeJson, landFields, landProseText, noopText, renderBeatJson, renderBeatPlain, renderFormat, renderLandJson, renderLandPlain, renderSlicesJson, resolveSession, selectPath, slicesDocument, stallDiagnosis, statusOf };
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";
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 { St as requireFlag, gt as envDefaults, ht as defaults, i as skills, n as summary, o as flagShipped, r as access, t as steering, xt as registryEntry, y as coder, yt as flagReferences } from "../chunks/reserved-BAv71I4i.mjs";
3
- import { a as refusePendingHandOff, r as handOffTail } from "../chunks/tail-kar1zhOb.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";
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 () => {
@@ -1,7 +1,7 @@
1
- import { answered, applyScript, changes, changesSince, check, codeChanges, env, hasThreadFor, head, human, judge, judgeDiffShape, kept, mark, matches, numeric, quote, read, refuse, removeScript, requireAnswers, requireProgress, requireReplies, requireRevert, requireThreadsClosed, restoreScript, revertScript, run, scope, slice, start, vars, wrote } from "../flows.mjs";
1
+ import { agent, answered, applyScript, changes, changesSince, check, codeChanges, env, hasThreadFor, head, human, judge, judgeDiffShape, kept, mark, matches, numeric, quote, read, refuse, removeScript, requireAnswers, requireProgress, requireReplies, requireRevert, requireThreadsClosed, restoreScript, revertScript, run, scope, slice, start, vars, wrote } from "../flows.mjs";
2
2
  import { lensEntriesOf, review as review$1 } from "../workflow-kit.mjs";
3
- import { $ as qualityUnresolvedMessage, A as buildReviewCollectingPrompt, B as deferNotesScript, C as planner, D as agentWithSkills, E as reviewing, F as clearCriteriaQuestion, H as designSystem, I as coverageMessage, J as implementBuildingPrompt, L as coverageQuestion, M as buildReviewTriageMessage, N as builderSystem, O as buildReviewAnswerQuestionsPrompt, P as clearCriteriaMessage, Q as normaliseCriteriaScript, R as coveringPrompt, S as fixRisks, U as designTriagePrompt, V as designGateAnswerMessage, X as naiveApplyFailure, Y as implementFixPrompt, Z as naivePassPrompt, _ as REVIEW, _t as testFileGlobs, a as flagModeOn, at as reviewEditsCapture, b as fixCheck, ct as reviewerSystem, d as guarded, dt as startGateBlockedMessage, et as refactorBuildingPrompt, f as healthy, ft as uncoveredMessage, g as REQUIREMENTS, gt as envDefaults, h as REFACTOR, ht as defaults, i as skills, it as reviewEditNotesCapture, j as buildReviewFixNitsPrompt, k as buildReviewAwaitAfterDeferMessage, lt as seamByHandMessage, m as QUALITY, mt as unwindFailure, n as summary, nt as refactorFixPrompt, p as FEEDBACK, pt as unwindFailedMessage, q as idleMessage, r as access, rt as refactorRules, s as shipped, st as reviewNotesCapture, t as steering, tt as refactorDroppedRefusal, u as gate, ut as seamSteerMessage, v as awaitReview, w as reviewMissing, y as coder, z as criterionLine } from "../chunks/reserved-BAv71I4i.mjs";
4
- import { a as refusePendingHandOff, i as isOptionalObject, n as closeReview, o as tail } from "../chunks/tail-kar1zhOb.mjs";
3
+ import { $ as normaliseCriteriaScript, A as buildReviewAwaitAfterDeferMessage, B as criterionLine, C as fixRisks, D as reviewing, F as clearCriteriaMessage, H as designGateAnswerMessage, I as clearCriteriaQuestion, J as idleMessage, L as coverageMessage, M as buildReviewFixNitsPrompt, N as buildReviewTriageMessage, O as agentWithSkills, P as builderSystem, Q as naivePassPrompt, R as coverageQuestion, T as reviewMissing, U as designSystem, V as deferNotesScript, W as designTriagePrompt, X as implementFixPrompt, Y as implementBuildingPrompt, Z as naiveApplyFailure, _ as REQUIREMENTS, _t as defaults, a as flagModeOn, at as refactorRules, b as coder, d as guarded, dt as seamByHandMessage, et as qualityUnresolvedMessage, f as healthy, ft as seamSteerMessage, g as REFACTOR_NOTE, gt as unwindFailure, h as REFACTOR, ht as unwindFailedMessage, i as skills, it as refactorNotePrompt, j as buildReviewCollectingPrompt, k as buildReviewAnswerQuestionsPrompt, lt as reviewNotesCapture, m as QUALITY, mt as uncoveredMessage, n as summary, nt as refactorDroppedRefusal, ot as reviewEditNotesCapture, p as FEEDBACK, pt as startGateBlockedMessage, r as access, rt as refactorFixPrompt, s as shipped, st as reviewEditsCapture, t as steering, tt as refactorBuildingPrompt, u as gate, ut as reviewerSystem, v as REVIEW, vt as envDefaults, w as planner, x as fixCheck, y as awaitReview, yt as testFileGlobs, z as coveringPrompt } from "../chunks/reserved-zAfoJtR7.mjs";
4
+ import { a as refusePendingHandOff, i as isOptionalObject, n as closeReview, o as tail } from "../chunks/tail-BRC4DGdV.mjs";
5
5
  import { posix } from "node:path";
6
6
  //#region src/workflows/shared/fences.ts
7
7
  const markFenced = (text) => {
@@ -623,7 +623,8 @@ const plan = (shape, options) => {
623
623
  return {
624
624
  pattern,
625
625
  strays,
626
- reference: options.reference?.trim() ? options.reference : void 0
626
+ reference: options.reference?.trim() ? options.reference : void 0,
627
+ note: options.note?.trim() ? options.note : void 0
627
628
  };
628
629
  };
629
630
  const guardOf = ({ pattern, strays }, entry) => () => {
@@ -632,13 +633,22 @@ const guardOf = ({ pattern, strays }, entry) => () => {
632
633
  };
633
634
  /** Derive, build, check and close one refactor lap; `feedback` is the collected review text of the lap before. */
634
635
  const refactorLap = async (p, guard, feedback) => {
635
- const { pattern, strays, reference } = p;
636
- await run("deriving", deriveScript([...packageLines(strays, pattern, reference), ...feedback === void 0 ? [] : [
637
- "## Review feedback",
638
- "",
639
- ...demoteHeadings(feedback),
640
- ""
641
- ]]), {
636
+ const { pattern, strays, reference, note } = p;
637
+ await run("deriving", deriveScript([
638
+ ...packageLines(strays, pattern, reference),
639
+ ...note === void 0 ? [] : [
640
+ "## Refactor note",
641
+ "",
642
+ ...demoteHeadings(note),
643
+ ""
644
+ ],
645
+ ...feedback === void 0 ? [] : [
646
+ "## Review feedback",
647
+ "",
648
+ ...demoteHeadings(feedback),
649
+ ""
650
+ ]
651
+ ]), {
642
652
  label: "Deriving the refactor package",
643
653
  file: REFACTOR_PACKAGE
644
654
  });
@@ -647,7 +657,8 @@ const refactorLap = async (p, guard, feedback) => {
647
657
  strays,
648
658
  pattern,
649
659
  reference,
650
- feedback: feedback !== void 0
660
+ feedback: feedback !== void 0,
661
+ note: note !== void 0
651
662
  }), {
652
663
  label: "Refactoring",
653
664
  model: coder(),
@@ -733,13 +744,16 @@ const COVERED_MIN_P = .7;
733
744
  /** Covering turns before the process rests at `uncovered`; a human edit there refills them. */
734
745
  const COVERING_RETRIES = 2;
735
746
  const frozen = () => requireCriteriaFrozen(REQUIREMENTS);
736
- const green = () => healthy(() => agentWithSkills("fix.suite.fixing", implementFixPrompt(), {
747
+ const green = (guard) => healthy(() => agentWithSkills("fix.suite.fixing", implementFixPrompt(), {
737
748
  label: "Fixing the check",
738
749
  file: FEEDBACK,
739
750
  model: coder(),
740
751
  system: builderSystem()
741
752
  }), {
742
- guard: frozen,
753
+ guard: () => {
754
+ frozen();
755
+ guard?.();
756
+ },
743
757
  guardRests: false
744
758
  });
745
759
  const testsSince = (base) => changesSince(base).filter((c) => c.after !== void 0 && isCode$1(c.path) && isTestFile(c.path)).sort((a, b) => Number(/\bAC-\d/.test(a.after)) - Number(/\bAC-\d/.test(b.after))).map((c) => `=== ${c.path} (${c.status})\n${c.after}`).join("\n");
@@ -853,16 +867,20 @@ const addedLines = (change) => {
853
867
  const before = new Set((change.before ?? "").split("\n"));
854
868
  return change.after.split("\n").filter((line) => !before.has(line)).join("\n");
855
869
  };
870
+ const acceptanceTests = (changes) => changes.filter((c) => c.after !== void 0 && isCode$1(c.path) && isTestFile(c.path));
871
+ const idsOf = (file) => (criteriaOf(read(file) ?? "") ?? []).map((c) => c.id).filter((id) => id !== "");
872
+ const unnamed = (ids, tests) => {
873
+ const lines = tests.map(addedLines);
874
+ return ids.filter((id) => !lines.some((text) => named(id, text)));
875
+ };
856
876
  /**
857
877
  * Why `tip`'s tests fall short, or `undefined`: a criterion ID of `file` no
858
878
  * test line of the pass names, or a test importing a file the pass added —
859
879
  * naive structure a reset and refactor replaces, which the tests must survive.
860
880
  */
861
881
  const acceptanceFault = (file, tip) => {
862
- const ids = (criteriaOf(read(file) ?? "") ?? []).map((c) => c.id).filter((id) => id !== "");
863
- const tests = tip.changes.filter((c) => c.after !== void 0 && isCode$1(c.path) && isTestFile(c.path));
864
- const lines = tests.map(addedLines);
865
- const untested = ids.filter((id) => !lines.some((text) => named(id, text)));
882
+ const tests = acceptanceTests(tip.changes);
883
+ const untested = unnamed(idsOf(file), tests);
866
884
  if (untested.length > 0) return `acceptance-tests: no test of the naive pass names ${untested.join(", ")} — write a behaviour-level test for each criterion with its ID in the test or scenario name, e.g. "[${untested[0]}] …"`;
867
885
  const added = tip.changes.filter((c) => c.status === "added" && isCode$1(c.path) && !isTestFile(c.path)).map((c) => c.path);
868
886
  const reaching = tests.filter((test) => holdsCallSites(test.path)).flatMap((test) => {
@@ -871,6 +889,41 @@ const acceptanceFault = (file, tip) => {
871
889
  });
872
890
  if (reaching.length > 0) return `acceptance-internals: these tests import files the naive pass added — test through code that existed before it (a public entry point, an existing module's exports):\n${reaching.join("\n")}`;
873
891
  };
892
+ /** What a rebuild carries over from the naive pass `tip`: the IDs its tests name, and those test files. */
893
+ const naiveAcceptance = (tip) => {
894
+ const ids = idsOf(REQUIREMENTS);
895
+ const perTest = acceptanceTests(tip.changes).map((c) => {
896
+ const lines = addedLines(c);
897
+ return {
898
+ path: c.path,
899
+ ids: ids.filter((id) => named(id, lines))
900
+ };
901
+ });
902
+ return {
903
+ hash: tip.hash,
904
+ tests: perTest.filter((c) => c.ids.length > 0).map((c) => c.path),
905
+ ids: ids.filter((id) => perTest.some((c) => c.ids.includes(id)))
906
+ };
907
+ };
908
+ /**
909
+ * Refuse a rebuild whose test changes since `since` leave out an ID the naive
910
+ * pass's tests named. A skipped test still counts: the gate reads text, never runs it.
911
+ */
912
+ const requireAcceptance = (acceptance, since) => {
913
+ const missing = unnamed(acceptance.ids, acceptanceTests(changesSince(since)));
914
+ if (missing.length === 0) return;
915
+ refuse(`gtd land: rebuild-acceptance: the rebuild's tests leave out ${missing.join(", ")} — carry over the naive pass's acceptance tests (\`git show ${acceptance.hash} -- ${acceptance.tests.map(quote).join(" ")}\`), each with its ID in the test or scenario name`);
916
+ };
917
+ /**
918
+ * Refuse a fix turn that, on its own, drops an ID the naive pass's tests named
919
+ * from a test file. Turn-local, so a person's edit at an escalation rest never
920
+ * wedges later fix turns.
921
+ */
922
+ const requireAcceptanceKept = (acceptance) => {
923
+ const dropped = acceptance.ids.filter((id) => changes().filter((c) => isCode$1(c.path) && isTestFile(c.path)).some((c) => named(id, c.before ?? "") && !named(id, c.after ?? "")));
924
+ if (dropped.length === 0) return;
925
+ refuse(`gtd land: rebuild-acceptance: this turn drops ${dropped.join(", ")} from the tests — the naive pass's acceptance tests stay; fix the code, not them`);
926
+ };
874
927
  const restore = (path) => `if git cat-file -e ${quote(`HEAD:${path}`)} 2>/dev/null; then git checkout -q HEAD -- ${quote(path)}; else rm -f -- ${quote(path)}; fi`;
875
928
  /**
876
929
  * Run the suite with `tip`'s diff applied, then take it out again; resolves
@@ -914,16 +967,20 @@ function implement(first, tier, amend) {
914
967
  amend
915
968
  };
916
969
  return scope("implement", async () => {
917
- if (options.naive === void 0 || !await applied(options.naive)) await agentWithSkills("building", implementBuildingPrompt(options.reference, options.tier, options.amend, options.afterRefactor, flagModeOn()), {
970
+ const since = head();
971
+ const acceptance = options.rebuild?.acceptance;
972
+ const built = options.naive === void 0 || !await applied(options.naive);
973
+ if (built) await agentWithSkills("building", implementBuildingPrompt(options.reference, options.tier, options.amend, options.afterRefactor, flagModeOn(), options.rebuild), {
918
974
  label: "Implementing",
919
975
  model: coder(),
920
976
  system: builderSystem(),
921
977
  ...options.afterRefactor === true ? { allowEmpty: true } : {}
922
978
  });
923
979
  requireCriteriaFrozen(REQUIREMENTS);
924
- await green();
980
+ if (built && acceptance !== void 0) requireAcceptance(acceptance, since);
981
+ await green(built && acceptance !== void 0 ? () => requireAcceptanceKept(acceptance) : void 0);
925
982
  await requireCoverage();
926
- await run("closing", removeScript([REQUIREMENTS]), { label: "Closing out the implementation" });
983
+ await run("closing", removeScript([REQUIREMENTS, REFACTOR_NOTE]), { label: "Closing out the implementation" });
927
984
  });
928
985
  }
929
986
  /** Resolves `true` when the human steered (edited), `false` on a clean overrule. */
@@ -973,16 +1030,23 @@ const vetted = async (tip, vetting) => {
973
1030
  /** The judge's ruling on a vetted pass: the decision, or the next attempt's verdict. */
974
1031
  const ruled = async (tip, again) => {
975
1032
  const shape = await judgeSeam(tip);
976
- if (shape.choice === "land") return { reference: tip.hash };
1033
+ if (shape.choice === "land") return {
1034
+ reference: tip.hash,
1035
+ tip
1036
+ };
977
1037
  if (shape.choice === "refactor-first") return {
978
1038
  reference: tip.hash,
1039
+ tip,
979
1040
  shape
980
1041
  };
981
1042
  const next = await again({
982
1043
  strays: shape.strays,
983
1044
  p: shape.judgment?.answers.shape?.p ?? 0
984
1045
  });
985
- return next.kind === "overruled" ? { reference: tip.hash } : next;
1046
+ return next.kind === "overruled" ? {
1047
+ reference: tip.hash,
1048
+ tip
1049
+ } : next;
986
1050
  };
987
1051
  const decide = () => scope("seam", async () => {
988
1052
  const vetting = {
@@ -993,13 +1057,29 @@ const decide = () => scope("seam", async () => {
993
1057
  for (;;) {
994
1058
  await naivePass(retry);
995
1059
  const tip = kept("naive");
996
- const outcome = await vetted(tip, vetting) ?? (flagModeOn() ? await ruled(tip, vetting.again) : { reference: tip.hash });
1060
+ const outcome = await vetted(tip, vetting) ?? (flagModeOn() ? await ruled(tip, vetting.again) : {
1061
+ reference: tip.hash,
1062
+ tip
1063
+ });
997
1064
  if (!("kind" in outcome)) return outcome;
998
1065
  retry = outcome.kind === "retry" ? outcome.retry : void 0;
999
1066
  }
1000
1067
  });
1068
+ /** Write the refactor note from the whole naive pass; a turn that changes anything else is refused. */
1069
+ const refactorNote = async (reference, strays) => {
1070
+ await agent("note", refactorNotePrompt(reference, strays), {
1071
+ label: "Writing the refactor note",
1072
+ file: REFACTOR_NOTE,
1073
+ model: coder(),
1074
+ system: builderSystem()
1075
+ });
1076
+ const others = changes().map((c) => c.path).filter((path) => path !== REFACTOR_NOTE);
1077
+ const note = read(".gtd/REFACTOR-NOTE.md") ?? "";
1078
+ if (others.length > 0 || note.trim() === "") refuse(`gtd land: refactor-note: write ${REFACTOR_NOTE} and change nothing else${others.length > 0 ? ` — revert these:\n${others.map((path) => ` - ${path}`).join("\n")}` : ""}`);
1079
+ return note;
1080
+ };
1001
1081
  const seamBuild = async (base) => {
1002
- const { reference, shape } = await decide();
1082
+ const { reference, tip, shape } = await decide();
1003
1083
  if (shape === void 0) return {
1004
1084
  reference,
1005
1085
  base,
@@ -1013,18 +1093,29 @@ const seamBuild = async (base) => {
1013
1093
  }));
1014
1094
  return {
1015
1095
  reference,
1016
- base
1096
+ base,
1097
+ rebuild: { acceptance: naiveAcceptance(tip) }
1017
1098
  };
1018
1099
  }
1019
- if (refactorStrays(shape).length === 0) return {
1100
+ const strays = refactorStrays(shape);
1101
+ if (strays.length === 0) return {
1020
1102
  reference,
1021
- base
1103
+ base,
1104
+ rebuild: { acceptance: naiveAcceptance(tip) }
1022
1105
  };
1023
- const refactored = await slice("refactor", () => reviewedRefactor(shape, { reference }));
1106
+ const note = await scope("seam", () => refactorNote(reference, strays));
1107
+ const refactored = await slice("refactor", () => reviewedRefactor(shape, {
1108
+ reference,
1109
+ note
1110
+ }));
1024
1111
  return {
1025
1112
  reference,
1026
1113
  base: head(),
1027
- refactored
1114
+ refactored,
1115
+ rebuild: {
1116
+ note,
1117
+ acceptance: naiveAcceptance(tip)
1118
+ }
1028
1119
  };
1029
1120
  };
1030
1121
  //#endregion
@@ -1043,9 +1134,11 @@ const buildFeature = async (firstBase) => {
1043
1134
  reference: seam.reference,
1044
1135
  tier,
1045
1136
  afterRefactor: seam.refactored,
1046
- naive: seam.land === true ? seam.reference : void 0
1137
+ naive: seam.land === true ? seam.reference : void 0,
1138
+ rebuild: seam.rebuild
1047
1139
  });
1048
- const base = seam.refactored === true && !changesSince(seam.base).some((c) => isCode$1(c.path)) ? firstBase : seam.base;
1140
+ const carried = seam.rebuild?.acceptance?.tests ?? [];
1141
+ const base = seam.refactored === true && !changesSince(seam.base).some((c) => isCode$1(c.path) && !carried.includes(c.path)) ? firstBase : seam.base;
1049
1142
  await tail(settleQuality, {
1050
1143
  green: true,
1051
1144
  lensBase: base
@@ -1109,4 +1202,4 @@ const feature = shipped(ordinaryStart);
1109
1202
  //#region src/workflows/feature/index.ts
1110
1203
  var feature_default = feature;
1111
1204
  //#endregion
1112
- export { COMMENT, REFACTOR_PACKAGE, acceptanceFault, access, afterTail, answerProductQuestions, answerReviewQuestions, buildFeature, buildTail, collecting, criteriaOf, feature_default as default, defaults, deferNotes, design, envDefaults, feature, fixNits, holdsCallSites, implement, isTestFile, judgeSeam, naivePass, ordinaryStart, planAndBuild, reUnwind, refactorCollecting, refactorFirst, refactorStrays, requireCriteria, requireCriteriaFrozen, requireNoNewFlags, requireNoTestFiles, requireTestCallSitesOnly, requireWithin, reviewedRefactor, seamBuild, skills, skipDesign, statedCriteria, steering, summary, triage, unwind };
1205
+ export { COMMENT, REFACTOR_PACKAGE, acceptanceFault, access, afterTail, answerProductQuestions, answerReviewQuestions, buildFeature, buildTail, collecting, criteriaOf, feature_default as default, defaults, deferNotes, design, envDefaults, feature, fixNits, holdsCallSites, implement, isTestFile, judgeSeam, naiveAcceptance, naivePass, ordinaryStart, planAndBuild, reUnwind, refactorCollecting, refactorFirst, refactorNote, refactorStrays, requireAcceptance, requireAcceptanceKept, requireCriteria, requireCriteriaFrozen, requireNoNewFlags, requireNoTestFiles, requireTestCallSitesOnly, requireWithin, reviewedRefactor, seamBuild, skills, skipDesign, statedCriteria, steering, summary, triage, unwind };
@@ -1,7 +1,7 @@
1
1
  import { read, refuse, removeScript, run, scope, start } from "../flows.mjs";
2
2
  import { d as reviewNotes, f as reviewRisks } from "../chunks/steering-DVILanVf.mjs";
3
- import { D as agentWithSkills, G as fixReviewNotesPrompt, W as finisherSystem, _ as REVIEW, c as baseline, gt as envDefaults, ht as defaults, i as skills, n as summary, r as access, s as shipped, t as steering, y as coder } from "../chunks/reserved-BAv71I4i.mjs";
4
- import { r as handOffTail, t as REVIEW_ORIG } from "../chunks/tail-kar1zhOb.mjs";
3
+ import { G as finisherSystem, K as fixReviewNotesPrompt, O as agentWithSkills, _t as defaults, b as coder, c as baseline, i as skills, n as summary, r as access, s as shipped, t as steering, v as REVIEW, vt as envDefaults } from "../chunks/reserved-zAfoJtR7.mjs";
4
+ import { r as handOffTail, t as REVIEW_ORIG } from "../chunks/tail-BRC4DGdV.mjs";
5
5
  //#region src/workflows/fix/fix.ts
6
6
  /**
7
7
  * Fix every note a human left in a handed-off `.gtd/REVIEW.md` and every
@@ -1,6 +1,6 @@
1
1
  import { start } from "../flows.mjs";
2
- import { gt as envDefaults, ht as defaults, i as skills, n as summary, ot as reviewGateBlockedMessage, r as access, s as shipped, t as steering, u as gate } from "../chunks/reserved-BAv71I4i.mjs";
3
- import { a as refusePendingHandOff, r as handOffTail } from "../chunks/tail-kar1zhOb.mjs";
2
+ import { _t as defaults, ct as reviewGateBlockedMessage, i as skills, n as summary, r as access, s as shipped, t as steering, u as gate, vt as envDefaults } from "../chunks/reserved-zAfoJtR7.mjs";
3
+ import { a as refusePendingHandOff, r as handOffTail } from "../chunks/tail-BRC4DGdV.mjs";
4
4
  //#region src/workflows/review/review.ts
5
5
  /**
6
6
  * Pure review of everything since `reviewBase`: a green gate, the quality
@@ -1,5 +1,5 @@
1
1
  import { agent, changesSince, glob, head, mark, read, refuse, removeScript, run, scope, vars } from "../flows.mjs";
2
- import { St as requireFlag, bt as flipProblems, gt as envDefaults, ht as defaults, i as skills, n as summary, o as flagShipped, p as FEEDBACK, r as access, t as steering, u as gate, vt as flagMentions, y as coder } from "../chunks/reserved-BAv71I4i.mjs";
2
+ import { St as flipProblems, _t as defaults, b as coder, bt as flagMentions, i as skills, n as summary, o as flagShipped, p as FEEDBACK, r as access, t as steering, u as gate, vt as envDefaults, wt as requireFlag } from "../chunks/reserved-zAfoJtR7.mjs";
3
3
  //#region src/workflows/rollout/rollout.ts
4
4
  const flippingPrompt = (name, registry) => `Roll out the release flag "${name}": in ${registry}, set \`defaultOn: true\` on its entry. Change nothing else — no other entry, no other field, no other file, no comments.`;
5
5
  const suiteBlockedMessage = () => "The suite is red after the rollout. Fix it by hand — a rollout may only touch the flag's registry entry — then land.";