@pmelab/gtd 24.2.0 → 24.4.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 (81) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +41 -6
  3. package/dist/chunks/{Schema-Dh-mkwkq.mjs → Schema-B5yK7QrT.mjs} +47 -1
  4. package/dist/chunks/{reserved-ejn-LVYO.mjs → reserved-B9pG93Fc.mjs} +53 -13
  5. package/dist/chunks/{steering-D-PvRC5W.mjs → steering-DVILanVf.mjs} +16 -5
  6. package/dist/flows.mjs +9 -1
  7. package/dist/gtd.bundle.mjs +1114 -865
  8. package/dist/steering.mjs +2 -2
  9. package/dist/testkit.mjs +1135 -218
  10. package/dist/workflow-kit.mjs +9 -7
  11. package/dist/workflows/feature.mjs +152 -35
  12. package/dist/workflows/fix.mjs +2 -2
  13. package/dist/workflows/review.mjs +1 -1
  14. package/dist/workflows.mjs +223 -54
  15. package/package.json +1 -1
  16. package/src/cli/Cli.test.ts +57 -0
  17. package/src/cli/Cli.ts +89 -9
  18. package/src/cli/History.test.ts +225 -0
  19. package/src/cli/History.ts +143 -0
  20. package/src/cli/Output.ts +68 -0
  21. package/src/cli/Program.test.ts +10 -9
  22. package/src/cli/Program.ts +24 -72
  23. package/src/edge/Edge.test.ts +261 -3
  24. package/src/edge/Edge.ts +218 -41
  25. package/src/edge/index.ts +1 -0
  26. package/src/emit/GitScript.test.ts +27 -0
  27. package/src/emit/GitScript.ts +18 -2
  28. package/src/emit/index.ts +2 -0
  29. package/src/flows/scripts.ts +6 -0
  30. package/src/platform/Git.test.ts +6 -9
  31. package/src/platform/Git.ts +48 -10
  32. package/src/platform/RetainedHistory.test.ts +14 -0
  33. package/src/platform/RetainedHistory.ts +5 -0
  34. package/src/platform/index.ts +7 -1
  35. package/src/replay/Trailers.test.ts +32 -0
  36. package/src/replay/Trailers.ts +17 -0
  37. package/src/steering/FORMATS.md +1 -1
  38. package/src/steering/SteeringFormat.test.ts +9 -1
  39. package/src/steering/SteeringFormat.ts +7 -0
  40. package/src/steering/contract.test.ts +3 -0
  41. package/src/steering/index.ts +1 -0
  42. package/src/steering/review.test.ts +30 -0
  43. package/src/steering/review.ts +8 -2
  44. package/src/step/LandStep.ts +3 -1
  45. package/src/step/RepoSnapshot.ts +7 -1
  46. package/src/step/planStart.test.ts +6 -3
  47. package/src/step/planStep.test.ts +29 -1
  48. package/src/step/planStep.ts +8 -0
  49. package/src/testkit/EmittedScriptRecognizer.test.ts +29 -30
  50. package/src/testkit/EmittedScriptRecognizer.ts +149 -52
  51. package/src/testkit/EmittedScripts.test.ts +166 -0
  52. package/src/testkit/FakeGitOperations.ts +6 -2
  53. package/src/testkit/FlowScripts.test.ts +242 -0
  54. package/src/testkit/FlowScripts.ts +326 -0
  55. package/src/testkit/GitTiers.ts +269 -47
  56. package/src/testkit/InMemRepo.ts +61 -8
  57. package/src/testkit/Layers.ts +10 -2
  58. package/src/testkit/TestRepo.ts +4 -1
  59. package/src/testkit/index.ts +1 -1
  60. package/src/workflow/discovery.test.ts +147 -0
  61. package/src/workflow/discovery.ts +5 -0
  62. package/src/workflow/fingerprint.test.ts +20 -4
  63. package/src/workflow/fingerprint.ts +8 -9
  64. package/src/workflow/index.ts +1 -6
  65. package/src/workflow/load.test.ts +5 -19
  66. package/src/workflow/load.ts +94 -10
  67. package/src/workflow-kit/review.test.ts +84 -0
  68. package/src/workflow-kit/review.ts +9 -6
  69. package/src/workflows/feature/review.test.ts +238 -12
  70. package/src/workflows/feature/review.ts +172 -31
  71. package/src/workflows/feature/steps.test.ts +12 -0
  72. package/src/workflows/feature/steps.ts +8 -1
  73. package/src/workflows/shared/access.test.ts +4 -2
  74. package/src/workflows/shared/access.ts +1 -0
  75. package/src/workflows/shared/options.test.ts +8 -0
  76. package/src/workflows/shared/options.ts +1 -0
  77. package/src/workflows/shared/steps.ts +2 -0
  78. package/src/workflows/shared/tail.ts +3 -11
  79. package/src/workflows/shared/text.test.ts +106 -0
  80. package/src/workflows/shared/text.ts +57 -1
  81. package/src/workflows/shared/vars.ts +1 -0
@@ -1,5 +1,5 @@
1
1
  import { changes, changesSince, hasThreadFor, head, read, refuse, requireReplies, requireThreadsClosed, scope } from "./flows.mjs";
2
- import { c as stripCodeThreads, d as reviewNotes, f as reviewRisks } from "./chunks/steering-D-PvRC5W.mjs";
2
+ import { c as stripCodeThreads, d as reviewNotes, f as reviewRisks } from "./chunks/steering-DVILanVf.mjs";
3
3
  //#region src/workflow-kit/health.ts
4
4
  /** Hand a red suite that repeated attempts could not fix to a person, until `limit` rounds are spent. */
5
5
  const escalation = async (count, steps) => {
@@ -196,16 +196,17 @@ const converse = async (p, base, collectedBefore) => {
196
196
  if (!hasThreadFor("human", p.file)) return collectedAt;
197
197
  }
198
198
  };
199
- /** Judge every note, then run each verdict's route: answers, then nit fixes, then the edits' lap. */
199
+ /** Judge every note, then run each verdict's route: answers, then nit fixes, then deferrals, then the edits' lap. */
200
200
  const routeNotes = async (p, notes, r) => {
201
201
  const verdicts = await p.triage(notes);
202
202
  const of = (v) => notes.filter((n) => (verdicts.get(n.id) ?? "edit") === v);
203
- const [edits, questions, nits] = [
203
+ const [edits, questions, nits, deferred] = [
204
204
  of("edit"),
205
205
  of("question"),
206
- of("nit")
206
+ of("nit"),
207
+ of("defer")
207
208
  ];
208
- if (edits.length + questions.length + nits.length === 0) return r.unfolded();
209
+ if (edits.length + questions.length + nits.length + deferred.length === 0) return r.unfolded();
209
210
  let answeredAt;
210
211
  if (questions.length > 0) {
211
212
  await p.answerQuestions(questions);
@@ -215,6 +216,7 @@ const routeNotes = async (p, notes, r) => {
215
216
  await p.fixNits(nits);
216
217
  await p.keepGreen();
217
218
  }
219
+ if (deferred.length > 0) await p.defer(deferred);
218
220
  if (edits.length > 0) {
219
221
  await r.close();
220
222
  return r.outcome(await collect(p, p.captures.editNotes(r.round, edits, answeredAt)));
@@ -228,7 +230,7 @@ const routeNotes = async (p, notes, r) => {
228
230
  }
229
231
  return {
230
232
  next: "await",
231
- reviewed: answeredAt
233
+ reviewed: answeredAt ?? r.round
232
234
  };
233
235
  };
234
236
  /** A code edit, not a thread-only change: lines that only add, answer or remove code threads don't count. */
@@ -349,4 +351,4 @@ const reviewToHandOff = async (base, p) => {
349
351
  }
350
352
  };
351
353
  //#endregion
352
- export { driftedScenarios, escalation, fixFindings, freezeScenarios, gate, healthy, holdWording, lensScopes, lensesOf, qualityLap, review, reviewToHandOff, scenarioText, untilSettled, wordingDrift };
354
+ export { driftedScenarios, escalation, fixFindings, freezeScenarios, gate, healthy, holdWording, lensScopes, lensesOf, qualityLap, review, reviewToHandOff, routeNotes, scenarioText, untilSettled, wordingDrift };
@@ -1,6 +1,6 @@
1
1
  import { answered, changes, changesSince, glob, hasThreadFor, head, human, judge, numeric, read, refuse, removeScript, requireAnswers, requireProgress, requireReplies, requireRevert, requireThreadsClosed, restoreScript, revertScript, run, scope, start, vars } from "../flows.mjs";
2
2
  import { freezeScenarios, review as review$1 } from "../workflow-kit.mjs";
3
- import { $ as unwindFailure, A as architectureAuthorPrompt, B as designTriagePrompt, C as fixCheck, D as reviewing, E as reviewMissing, F as buildReviewFixNitsPrompt, G as packagesItemFixSuitePrompt, I as buildReviewTriageMessage, K as reviewEditNotesCapture, L as builderSystem, M as architectureGateAnswerMessage, N as buildReviewAnswerQuestionsPrompt, O as agentWithSkills, P as buildReviewCollectingPrompt, Q as unwindFailedMessage, R as designGateAnswerMessage, S as coder, T as planner, U as idleMessage, W as packagesItemBuildingPrompt, X as reviewerSystem, Y as reviewNotesCapture, Z as startGateBlockedMessage, _ as ARCHITECTURE, b as REVIEW, c as refusePendingHandOff, d as shipped, f as defaults, g as healthy, h as gate, i as skills, j as architectureDecomposePrompt, k as architectSystem, l as tail, n as summary, o as closeReview, p as envDefaults, q as reviewEditsCapture, r as access, t as steering, u as guarded, v as FEEDBACK, w as fixRisks, x as awaitReview, y as REQUIREMENTS, z as designSystem } from "../chunks/reserved-ejn-LVYO.mjs";
3
+ import { $ as startGateBlockedMessage, A as architectureAuthorPrompt, B as designGateAnswerMessage, C as fixCheck, D as reviewing, E as reviewMissing, F as buildReviewCollectingPrompt, G as idleMessage, H as designTriagePrompt, I as buildReviewFixNitsPrompt, J as reviewEditNotesCapture, K as packagesItemBuildingPrompt, L as buildReviewTriageMessage, M as architectureGateAnswerMessage, N as buildReviewAnswerQuestionsPrompt, O as agentWithSkills, P as buildReviewAwaitAfterDeferMessage, Q as reviewerSystem, R as builderSystem, S as coder, T as planner, V as designSystem, Y as reviewEditsCapture, Z as reviewNotesCapture, _ as ARCHITECTURE, b as REVIEW, c as refusePendingHandOff, d as shipped, et as unwindFailedMessage, f as defaults, g as healthy, h as gate, i as skills, j as architectureDecomposePrompt, k as architectSystem, l as tail, n as summary, o as closeReview, p as envDefaults, q as packagesItemFixSuitePrompt, r as access, t as steering, tt as unwindFailure, u as guarded, v as FEEDBACK, w as fixRisks, x as awaitReview, y as REQUIREMENTS, z as deferNotesScript } from "../chunks/reserved-B9pG93Fc.mjs";
4
4
  //#region src/workflows/feature/steps.ts
5
5
  /** Turn the sketch since `base` into `.gtd/REQUIREMENTS.md`. */
6
6
  const triage = (base) => agentWithSkills("triage", designTriagePrompt(base), {
@@ -71,6 +71,11 @@ const collecting = (capture) => agentWithSkills("review.collecting", buildReview
71
71
  system: reviewerSystem(),
72
72
  allowEmpty: true
73
73
  });
74
+ /** `build.review.defer`: append `notes` to `.gtd/TODO.md` as one section; the step's landing is the commit. */
75
+ const deferNotes = (notes, round) => run("review.defer", deferNotesScript(notes, round), {
76
+ label: "Deferring could-notes to TODO.md",
77
+ file: ".gtd/TODO.md"
78
+ });
74
79
  //#endregion
75
80
  //#region src/workflows/feature/packages.ts
76
81
  /** Package 0: the e2e scenarios, written red. */
@@ -194,23 +199,106 @@ const verdictQuestion = (note) => ({
194
199
  instructions: `Classify the human's note on review item "${note.anchor}" (in .gtd/REVIEW.md). Its evidence holds the anchor, the reviewer's text and the human's text.`,
195
200
  criteria: "edit: a request to change behaviour, design or scope — anything needing a plan, or any note you are unsure about. question: asks something and wants an answer, with no change requested. nit: a small, local, unambiguous fix (naming, typo, formatting, comment wording) needing no re-plan. praise: an approving remark with nothing to do."
196
201
  });
202
+ const SEVERITY_ANSWERS = {
203
+ security: ["yes", "no"],
204
+ reversibility: ["one-way", "two-way"],
205
+ blastRadius: [
206
+ "local",
207
+ "module",
208
+ "contract"
209
+ ],
210
+ newConcept: ["yes", "no"]
211
+ };
212
+ /**
213
+ * Deferring is the risky direction: anything unanswered, unrecognised, cut or
214
+ * below `minP` is `critical`, never `could`.
215
+ */
216
+ const severityOf = (note, judgment, minP) => {
217
+ const ans = (q) => judgment.answers[`${note.id}.${q}`];
218
+ const a = (q) => ans(q)?.answer;
219
+ const rank = () => a("reversibility") === "one-way" ? 0 : a("newConcept") === "yes" ? 1 : 2;
220
+ if (note.forced) return {
221
+ tier: "critical",
222
+ reason: "critical: forced by `!`",
223
+ rank: 2
224
+ };
225
+ if (judgment.truncated.includes(note.id) || Object.entries(SEVERITY_ANSWERS).some(([q, allowed]) => !allowed.includes(a(q) ?? "") || !((ans(q)?.p ?? NaN) >= minP))) return {
226
+ tier: "critical",
227
+ reason: "critical: judge unsure",
228
+ rank: 2
229
+ };
230
+ const critical = [...a("security") === "yes" ? ["security"] : [], ...a("reversibility") === "one-way" ? ["one-way door"] : []];
231
+ if (critical.length > 0) return {
232
+ tier: "critical",
233
+ reason: `critical: ${critical.join(", ")}`,
234
+ rank: rank()
235
+ };
236
+ const should = [...a("blastRadius") === "contract" ? ["contract"] : [], ...a("newConcept") === "yes" ? ["new concept"] : []];
237
+ if (should.length > 0) return {
238
+ tier: "should",
239
+ reason: `should: ${should.join(", ")}`,
240
+ rank: rank()
241
+ };
242
+ return {
243
+ tier: "could",
244
+ reason: "could",
245
+ rank: 2
246
+ };
247
+ };
248
+ const severityQuestions = (note) => [
249
+ {
250
+ id: `${note.id}.security`,
251
+ primitive: "noul",
252
+ instructions: `Does the change the human asks for in note "${note.id}" (on "${note.anchor}") touch security — authentication, authorisation, secrets, untrusted input or data exposure?`,
253
+ criteria: "yes: it changes or could weaken a security property. no: it does not."
254
+ },
255
+ {
256
+ id: `${note.id}.reversibility`,
257
+ primitive: "choice",
258
+ instructions: `Once the change in note "${note.id}" ships, can it be undone without breaking anyone who already depends on it?`,
259
+ criteria: "one-way: a published API, file format, persisted data, protocol or other contract that cannot be taken back. two-way: can be reverted freely."
260
+ },
261
+ {
262
+ id: `${note.id}.blastRadius`,
263
+ primitive: "choice",
264
+ instructions: `How far does the change in note "${note.id}" reach?`,
265
+ criteria: "local: one function or file. module: a whole module or several files. contract: a public interface other code or users depend on."
266
+ },
267
+ {
268
+ id: `${note.id}.newConcept`,
269
+ primitive: "noul",
270
+ instructions: `Does the change in note "${note.id}" introduce a concept new to this codebase — a new abstraction, entity or term? Judge from the evidence, never a glossary; reusing or extending an existing concept is not new.`,
271
+ criteria: "yes: a genuinely new concept. no: reuses or extends an existing one."
272
+ }
273
+ ];
197
274
  /**
198
- * One judge rest, one verdict per note. Dismissing a note is the risky
275
+ * One judge rest: a verdict per unforced note (a forced note is asked
276
+ * nothing) plus four severity answers. Dismissing a note is the risky
199
277
  * direction, so only a confident non-`edit` verdict on uncut evidence counts;
200
- * a cut, unanswered or below-floor note is an `edit`, and a blank floor makes
201
- * every note one.
278
+ * a cut, unanswered or below-floor note is an `edit`. Severity answers on a
279
+ * non-`edit` note are ignored. A confident `could` edit becomes `defer`.
202
280
  */
203
- const triage$1 = async (notes) => {
204
- const { answers, truncated } = await judge("review.triage", {
205
- questions: notes.map(verdictQuestion),
206
- evidence: Object.fromEntries(notes.map((n) => [n.id, `Anchor: ${n.anchor}\nReviewer's text: ${n.before}\nHuman's text: ${n.text}`])),
281
+ const triage$1 = (severities) => async (notes) => {
282
+ const asked = notes.filter((n) => !n.forced);
283
+ const judgment = asked.length === 0 ? {
284
+ answers: {},
285
+ truncated: []
286
+ } : await judge("review.triage", {
287
+ questions: asked.flatMap((n) => [verdictQuestion(n), ...severityQuestions(n)]),
288
+ evidence: Object.fromEntries(asked.map((n) => [n.id, `Anchor: ${n.anchor}\nReviewer's text: ${n.before}\nHuman's text: ${n.text}`])),
207
289
  message: buildReviewTriageMessage(),
208
290
  label: "Judging each note"
209
291
  });
292
+ const { answers, truncated } = judgment;
210
293
  const minP = numeric(vars.reviewNoteActionable, Infinity);
294
+ const severityMinP = numeric(vars.reviewSeverityMinP, Infinity);
295
+ severities.clear();
211
296
  return new Map(notes.map((n) => {
212
- const verdict = VERDICTS.find((v) => v !== "edit" && answered(answers[n.id], v, minP));
213
- return [n.id, truncated.includes(n.id) || verdict === void 0 ? "edit" : verdict];
297
+ const verdict = n.forced ? void 0 : VERDICTS.find((v) => v !== "edit" && answered(answers[n.id], v, minP));
298
+ if (verdict !== void 0 && !truncated.includes(n.id)) return [n.id, verdict];
299
+ const severity = severityOf(n, judgment, severityMinP);
300
+ severities.set(n.id, severity);
301
+ return [n.id, severity.tier === "could" ? "defer" : "edit"];
214
302
  }));
215
303
  };
216
304
  const isCode = (path) => path !== ".gtd" && !path.startsWith(".gtd/");
@@ -220,30 +308,59 @@ const isCode = (path) => path !== ".gtd" && !path.startsWith(".gtd/");
220
308
  * another planning lap, questions are answered in place, nits fixed in one
221
309
  * batch, praise dropped.
222
310
  */
223
- const review = (base, escalations = { rounds: 0 }, frozen) => review$1(base, {
224
- file: REVIEW,
225
- feedback: REQUIREMENTS,
226
- isCode,
227
- reviewing,
228
- fixRisks: (risks) => guarded(frozen, () => fixRisks(risks), "review")(),
229
- keepGreen: () => healthy(guarded(frozen, fixCheck, "review"), { escalations }),
230
- awaitReview,
231
- reviewMissing,
232
- collecting,
233
- triage: triage$1,
234
- answerQuestions: answerReviewQuestions,
235
- fixNits: (notes) => guarded(frozen, () => fixNits(notes), "review")(),
236
- close: closeReview,
237
- captures: {
238
- edits: reviewEditsCapture,
239
- notes: reviewNotesCapture,
240
- editNotes: reviewEditNotesCapture
241
- },
242
- refusals: {
243
- deleted: "gtd land: review-doc: .gtd/REVIEW.md was deleted — restore it, or leave a note (or edit code) to request changes.",
244
- unmatched: "gtd land: no declared pattern matches the pending changes — write .gtd/REQUIREMENTS.md from the feedback, or change nothing when it asks for nothing"
245
- }
246
- });
311
+ const review = (base, escalations = { rounds: 0 }, frozen) => {
312
+ const severities = /* @__PURE__ */ new Map();
313
+ let deferred = [];
314
+ return review$1(base, {
315
+ file: REVIEW,
316
+ feedback: REQUIREMENTS,
317
+ isCode,
318
+ reviewing: (b, carry) => {
319
+ deferred = [];
320
+ return reviewing(b, carry);
321
+ },
322
+ fixRisks: (risks) => guarded(frozen, () => fixRisks(risks), "review")(),
323
+ keepGreen: () => healthy(guarded(frozen, fixCheck, "review"), { escalations }),
324
+ awaitReview: (b) => {
325
+ const notes = deferred;
326
+ deferred = [];
327
+ return notes.length > 0 ? awaitReview(b, buildReviewAwaitAfterDeferMessage(b, notes), true) : awaitReview(b);
328
+ },
329
+ reviewMissing,
330
+ collecting,
331
+ triage: triage$1(severities),
332
+ defer: (notes) => {
333
+ deferred = notes.map((n) => ({
334
+ id: n.id,
335
+ anchor: n.anchor,
336
+ text: n.text,
337
+ label: severities.get(n.id).reason
338
+ }));
339
+ return deferNotes(deferred, head());
340
+ },
341
+ answerQuestions: answerReviewQuestions,
342
+ fixNits: (notes) => guarded(frozen, () => fixNits(notes), "review")(),
343
+ close: closeReview,
344
+ captures: {
345
+ edits: reviewEditsCapture,
346
+ notes: reviewNotesCapture,
347
+ editNotes: (round, edits, answeredAt) => reviewEditNotesCapture(round, edits.map((n, i) => ({
348
+ n,
349
+ i,
350
+ s: severities.get(n.id)
351
+ })).sort((x, y) => Number(x.s?.tier === "should") - Number(y.s?.tier === "should") || (x.s?.rank ?? 2) - (y.s?.rank ?? 2) || x.i - y.i).map(({ n, s }) => ({
352
+ id: n.id,
353
+ anchor: n.anchor,
354
+ text: n.forced ? n.text.replace(/^!\s*/, "") : n.text,
355
+ ...s === void 0 ? {} : { label: s.reason }
356
+ })), answeredAt)
357
+ },
358
+ refusals: {
359
+ deleted: "gtd land: review-doc: .gtd/REVIEW.md was deleted — restore it, or leave a note (or edit code) to request changes.",
360
+ unmatched: "gtd land: no declared pattern matches the pending changes — write .gtd/REQUIREMENTS.md from the feedback, or change nothing when it asks for nothing"
361
+ }
362
+ });
363
+ };
247
364
  /** The build tail: fix (when entered red), keep green, the quality lap, then human review since `base`. */
248
365
  const buildTail = (fixFirst, base, built) => tail(fixFirst, (escalations, frozen) => review(base, escalations, frozen), built);
249
366
  //#endregion
@@ -312,4 +429,4 @@ const feature = shipped(ordinaryStart);
312
429
  //#region src/workflows/feature/index.ts
313
430
  var feature_default = feature;
314
431
  //#endregion
315
- export { SCENARIO_PACKAGE, access, afterTail, answerProductQuestions, answerReviewQuestions, answerTechnicalQuestions, architecture, author, build, buildTail, collecting, declaredTests, decompose, feature_default as default, defaults, design, envDefaults, feature, fixNits, fixSuite, nextPackage, ordinaryStart, packageItem, packages, planAndBuild, reUnwind, requireDeclaredTests, skills, steering, summary, triage, unwind };
432
+ export { SCENARIO_PACKAGE, access, afterTail, answerProductQuestions, answerReviewQuestions, answerTechnicalQuestions, architecture, author, build, buildTail, collecting, declaredTests, decompose, feature_default as default, defaults, deferNotes, design, envDefaults, feature, fixNits, fixSuite, nextPackage, ordinaryStart, packageItem, packages, planAndBuild, reUnwind, requireDeclaredTests, skills, steering, summary, triage, unwind };
@@ -1,6 +1,6 @@
1
1
  import { read, refuse, removeScript, run, scope, start } from "../flows.mjs";
2
- import { d as reviewNotes, f as reviewRisks } from "../chunks/steering-D-PvRC5W.mjs";
3
- import { H as fixReviewNotesPrompt, O as agentWithSkills, S as coder, V as finisherSystem, a as REVIEW_ORIG, b as REVIEW, d as shipped, f as defaults, i as skills, m as baseline, n as summary, p as envDefaults, r as access, s as handOffTail, t as steering } from "../chunks/reserved-ejn-LVYO.mjs";
2
+ import { d as reviewNotes, f as reviewRisks } from "../chunks/steering-DVILanVf.mjs";
3
+ import { O as agentWithSkills, S as coder, U as finisherSystem, W as fixReviewNotesPrompt, a as REVIEW_ORIG, b as REVIEW, d as shipped, f as defaults, i as skills, m as baseline, n as summary, p as envDefaults, r as access, s as handOffTail, t as steering } from "../chunks/reserved-B9pG93Fc.mjs";
4
4
  //#region src/workflows/fix/fix.ts
5
5
  /**
6
6
  * Fix every note a human left in a handed-off `.gtd/REVIEW.md` and every
@@ -1,5 +1,5 @@
1
1
  import { start } from "../flows.mjs";
2
- import { J as reviewGateBlockedMessage, c as refusePendingHandOff, d as shipped, f as defaults, h as gate, i as skills, n as summary, p as envDefaults, r as access, s as handOffTail, t as steering } from "../chunks/reserved-ejn-LVYO.mjs";
2
+ import { X as reviewGateBlockedMessage, c as refusePendingHandOff, d as shipped, f as defaults, h as gate, i as skills, n as summary, p as envDefaults, r as access, s as handOffTail, t as steering } from "../chunks/reserved-B9pG93Fc.mjs";
3
3
  //#region src/workflows/review/review.ts
4
4
  /**
5
5
  * Pure review of everything since `reviewBase`: a green gate, the quality