@pmelab/gtd 52.0.0 → 53.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 (108) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +96 -131
  3. package/claude/hooks/drive.ts +0 -3
  4. package/claude/hooks/register.tsx +3 -68
  5. package/claude/hooks/ship.ts +85 -1595
  6. package/dist/chunks/{reserved-D0MKVFFa.mjs → reserved-CQ7amcKG.mjs} +87 -133
  7. package/dist/chunks/{review-ZzUQH1KZ.mjs → review-CNgN_V8T.mjs} +2 -2
  8. package/dist/chunks/{tail-I1-vVq0P.mjs → tail-JZ9PAOwp.mjs} +2 -14
  9. package/dist/chunks/{wire-BJuZWR3C.mjs → wire-C12dahrH.mjs} +2 -130
  10. package/dist/flows.mjs +1 -16
  11. package/dist/gtd.bundle.mjs +476 -982
  12. package/dist/testkit.mjs +58 -417
  13. package/dist/wire.mjs +2 -2
  14. package/dist/workflows/cleanup.mjs +2 -2
  15. package/dist/workflows/feature.mjs +159 -363
  16. package/dist/workflows/fix.mjs +2 -2
  17. package/dist/workflows/review.mjs +3 -3
  18. package/dist/workflows/rollout.mjs +1 -1
  19. package/dist/workflows.mjs +400 -675
  20. package/package.json +5 -4
  21. package/src/cli/Cli.test.ts +1 -86
  22. package/src/cli/Cli.ts +13 -133
  23. package/src/cli/Metrics.test.ts +21 -31
  24. package/src/cli/Metrics.ts +25 -36
  25. package/src/cli/Program.test.ts +1 -35
  26. package/src/cli/Program.ts +5 -64
  27. package/src/cli/ToolCommands.ts +0 -3
  28. package/src/edge/Edge.test.ts +20 -322
  29. package/src/edge/Edge.ts +10 -181
  30. package/src/edge/index.ts +0 -1
  31. package/src/flows/runtime.test.ts +0 -27
  32. package/src/flows/runtime.ts +1 -49
  33. package/src/install/Install.ts +15 -24
  34. package/src/replay/Replay.test.ts +0 -169
  35. package/src/replay/Replay.ts +4 -93
  36. package/src/replay/index.ts +0 -1
  37. package/src/testkit/Layers.ts +0 -1
  38. package/src/testkit/steps.ts +13 -0
  39. package/src/wire/BeatDocument.ts +2 -12
  40. package/src/wire/BeatStatus.ts +0 -3
  41. package/src/wire/WireSchema.test.ts +0 -18
  42. package/src/wire/index.ts +0 -2
  43. package/src/wire/types.ts +0 -7
  44. package/src/workflow/Workflow.ts +1 -9
  45. package/src/workflows/feature/acceptance-criteria.feature +159 -3
  46. package/src/workflows/feature/criteria.test.ts +23 -15
  47. package/src/workflows/feature/criteria.ts +72 -39
  48. package/src/workflows/feature/fast-path.feature +4 -0
  49. package/src/workflows/feature/feature.test.ts +6 -5
  50. package/src/workflows/feature/feature.ts +34 -118
  51. package/src/workflows/feature/flag-mode.feature +4 -0
  52. package/src/workflows/feature/hands-on-skip.feature +37 -65
  53. package/src/workflows/feature/index.ts +0 -1
  54. package/src/workflows/feature/lens-models.feature +4 -0
  55. package/src/workflows/feature/lens-review.feature +4 -0
  56. package/src/workflows/feature/naive-acceptance.feature +4 -0
  57. package/src/workflows/feature/one-step-land.feature +4 -4
  58. package/src/workflows/feature/planning.ts +2 -1
  59. package/src/workflows/feature/prototype-rounds.feature +5 -1
  60. package/src/workflows/feature/prototype.feature +11 -3
  61. package/src/workflows/feature/prototype.ts +18 -29
  62. package/src/workflows/feature/refactor-absorbs.feature +7 -8
  63. package/src/workflows/feature/refactor-first.feature +4 -5
  64. package/src/workflows/feature/refactor-lens-models.feature +4 -0
  65. package/src/workflows/feature/refactor-rebuild.feature +4 -6
  66. package/src/workflows/feature/refactor-review.feature +31 -11
  67. package/src/workflows/feature/refactor.ts +30 -64
  68. package/src/workflows/feature/review-answers.feature +4 -0
  69. package/src/workflows/feature/review-gate.feature +13 -1
  70. package/src/workflows/feature/reviewer-walkthrough.feature +4 -0
  71. package/src/workflows/feature/risk-tier.feature +32 -0
  72. package/src/workflows/feature/seam-rejection.feature +8 -4
  73. package/src/workflows/feature/seam.feature +8 -0
  74. package/src/workflows/feature/seam.test.ts +11 -28
  75. package/src/workflows/feature/seam.ts +52 -165
  76. package/src/workflows/feature/severity-budget.feature +4 -0
  77. package/src/workflows/feature/severity-sorted-review.feature +4 -0
  78. package/src/workflows/feature/standards.feature +4 -0
  79. package/src/workflows/feature/tier-pin.feature +4 -0
  80. package/src/workflows/index.ts +0 -1
  81. package/src/workflows/shared/lenses.ts +0 -13
  82. package/src/workflows/shared/options.test.ts +2 -11
  83. package/src/workflows/shared/options.ts +4 -21
  84. package/src/workflows/shared/review.test.ts +3 -3
  85. package/src/workflows/shared/steps.ts +0 -2
  86. package/src/workflows/shared/text.test.ts +41 -71
  87. package/src/workflows/shared/text.ts +82 -212
  88. package/src/workflows/shared/vars.ts +2 -8
  89. package/src/workflows/shared/workflows.steps.ts +0 -13
  90. package/claude/hooks/context.ts +0 -66
  91. package/src/replay/Slices.test.ts +0 -73
  92. package/src/replay/Slices.ts +0 -45
  93. package/src/wire/ContextLimit.fixture.ts +0 -30
  94. package/src/wire/ContextLimit.test.ts +0 -96
  95. package/src/wire/ContextLimit.ts +0 -169
  96. package/src/wire/Slices.ts +0 -25
  97. package/src/wire/golden/1/slices.json +0 -11
  98. package/src/workflows/feature/context-limit.feature +0 -37
  99. package/src/workflows/feature/continuation-cap.feature +0 -65
  100. package/src/workflows/feature/continuation-rebuild.feature +0 -88
  101. package/src/workflows/feature/continuation-slices.feature +0 -64
  102. package/src/workflows/feature/continuation.feature +0 -205
  103. package/src/workflows/feature/slice-findings.feature +0 -252
  104. package/src/workflows/feature/slicing-cap.feature +0 -23
  105. package/src/workflows/feature/slicing.feature +0 -265
  106. package/src/workflows/feature/slicing.test.ts +0 -49
  107. package/src/workflows/feature/slicing.ts +0 -105
  108. package/src/workflows/shared/continuation.ts +0 -92
@@ -116,7 +116,6 @@ const statusOf = (input) => {
116
116
  initial,
117
117
  model: rendered.model,
118
118
  system: rendered.system !== void 0 && rendered.system !== "" ? rendered.system : void 0,
119
- context: rendered.context,
120
119
  log,
121
120
  state: rendered.state,
122
121
  actor: rendered.actor,
@@ -170,7 +169,7 @@ const dispatchFieldsOf = (demand) => {
170
169
  }
171
170
  };
172
171
  /**
173
- * Flatten a `Demand` plus its `BeatStatus` into the single 26-key document
172
+ * Flatten a `Demand` plus its `BeatStatus` into the single 25-key document
174
173
  * `gtd next --json` emits — the ONLY place the two are joined. `cost`/
175
174
  * `costByModel` are omitted together, exactly when no cost was recorded
176
175
  * (`cost <= 0`).
@@ -187,7 +186,6 @@ const beatDocument = (demand, status) => {
187
186
  session,
188
187
  model: status.model,
189
188
  system: status.system,
190
- context: status.context,
191
189
  validate,
192
190
  log: status.log,
193
191
  state: status.state,
@@ -477,130 +475,4 @@ const compile = (glob) => {
477
475
  };
478
476
  const globMatches = (path, glob) => compile(glob).test(path);
479
477
  //#endregion
480
- //#region src/wire/Slices.ts
481
- /** The ONLY place `gtd slices --json`'s shape is built; copies exactly the four fields, in order. */
482
- const slicesDocument = (slices) => ({
483
- schema: 1,
484
- slices: slices.map(({ name, base, tip, closed }) => ({
485
- name,
486
- base,
487
- tip,
488
- closed
489
- }))
490
- });
491
- const renderSlicesJson = (document) => JSON.stringify(document) + "\n";
492
- //#endregion
493
- //#region src/wire/ContextLimit.ts
494
- const DEFAULT_CONTEXT_LIMIT = {
495
- soft: .6,
496
- hard: .7
497
- };
498
- const DEFAULT_WINDOW = 2e5;
499
- const LONG_WINDOW = 1e6;
500
- /** Claude Code's `[1m]` suffix selects the long window; a transcript never names it, so the driver decides from the model it passed. */
501
- const contextWindowFor = (model) => model !== void 0 && /\[1m\]/i.test(model) ? LONG_WINDOW : DEFAULT_WINDOW;
502
- /** A positive whole number of tokens, or `undefined` for anything else. */
503
- const parseContextWindow = (raw) => {
504
- const n = Number(raw);
505
- return raw !== void 0 && raw.trim() !== "" && Number.isInteger(n) && n > 0 ? n : void 0;
506
- };
507
- /**
508
- * Where a driver asks `gtd context-hook` to record a hard stop's `stopReason`:
509
- * Claude Code prints it nowhere a driver reads, and `hook_stopped` alone would
510
- * also name any other hook that stopped the turn.
511
- */
512
- const CONTEXT_STOP_FILE_ENV = "GTD_LOOP_CONTEXT_STOP_FILE";
513
- /**
514
- * Why one layer of a limit (a scope's, a step's) is malformed, ignoring how its
515
- * two shares relate: layers merge key by key, so only the merged limit has to
516
- * keep `soft` below `hard`. Config is evaluated untyped, so anything may arrive.
517
- */
518
- const contextShapeFault = (limit) => {
519
- if (typeof limit !== "object" || limit === null || Array.isArray(limit)) return `context must be an object { soft, hard }, got ${JSON.stringify(limit)}`;
520
- const unknown = Object.keys(limit).filter((key) => key !== "soft" && key !== "hard");
521
- if (unknown.length > 0) return `unknown key(s) ${unknown.join(", ")} in context`;
522
- const shares = limit;
523
- for (const key of ["soft", "hard"]) {
524
- const value = shares[key];
525
- if (value === void 0) continue;
526
- if (typeof value !== "number" || !(value > 0 && value <= 1)) return `context.${key} must be a share of the context window in (0, 1], got ${JSON.stringify(value)}`;
527
- }
528
- };
529
- /** Why a whole limit is unusable, or `undefined` when it is fine. */
530
- const contextLimitFault = (limit) => {
531
- const shape = contextShapeFault(limit);
532
- if (shape !== void 0) return shape;
533
- const shares = limit;
534
- const soft = shares.soft ?? DEFAULT_CONTEXT_LIMIT.soft;
535
- const hard = shares.hard ?? DEFAULT_CONTEXT_LIMIT.hard;
536
- return soft < hard ? void 0 : `context.soft (${soft}) must be below context.hard (${hard})`;
537
- };
538
- const record = (value) => typeof value === "object" && value !== null ? value : void 0;
539
- const count = (value) => typeof value === "number" && value > 0 ? value : 0;
540
- /** What a message's usage puts in the context window: its whole input, cached or not. */
541
- const usageTokens = (usage) => {
542
- const u = record(usage);
543
- if (u === void 0) return void 0;
544
- return count(u["input_tokens"]) + count(u["cache_read_input_tokens"]) + count(u["cache_creation_input_tokens"]);
545
- };
546
- /**
547
- * The context size of the latest assistant message in a Claude Code transcript
548
- * (one JSON entry per line). Usage is per message, not a running sum, so the
549
- * last entry alone is the window's fill.
550
- */
551
- const transcriptTokens = (transcript) => {
552
- const lines = transcript.split("\n");
553
- for (let i = lines.length - 1; i >= 0; i--) {
554
- const line = lines[i].trim();
555
- if (line === "") continue;
556
- let entry;
557
- try {
558
- entry = JSON.parse(line);
559
- } catch {
560
- continue;
561
- }
562
- if (record(entry)?.["type"] !== "assistant") continue;
563
- const tokens = usageTokens(record(record(entry)?.["message"])?.["usage"]);
564
- if (tokens !== void 0) return tokens;
565
- }
566
- };
567
- /**
568
- * A worker subagent's own transcript. A hook its tool call fires is handed the
569
- * MAIN session's `transcript_path`; the worker's sits beside it.
570
- */
571
- const subagentTranscriptPath = (transcriptPath, agentId) => `${transcriptPath.replace(/\.jsonl$/, "")}/subagents/agent-${agentId}.jsonl`;
572
- /** Every hard stop's `stopReason` starts with this: the driver's context-limit marker. */
573
- const CONTEXT_LIMIT_MARKER = "gtd: context limit";
574
- const percent = (share) => `${Math.round(share * 100)}%`;
575
- /**
576
- * What a hook answers, or `undefined` to let the run go on. Compaction about
577
- * to happen means the limit was missed, so `PreCompact` is a hard stop whatever
578
- * the count says.
579
- */
580
- const contextHook = (input) => {
581
- const { event, tokens, window, limit } = input;
582
- if (event === "PreCompact") return {
583
- kind: "hard",
584
- stopReason: `${CONTEXT_LIMIT_MARKER}: the context is about to be compacted — the run is too big for one turn`
585
- };
586
- if (tokens === void 0) return void 0;
587
- const used = `${tokens} of ${window} tokens`;
588
- if (tokens >= limit.hard * window) return {
589
- kind: "hard",
590
- stopReason: `${CONTEXT_LIMIT_MARKER}: ${used}, past the ${percent(limit.hard)} hard limit`
591
- };
592
- if (tokens >= limit.soft * window) return {
593
- kind: "soft",
594
- reason: `Context limit: ${used} used, past the ${percent(limit.soft)} soft limit. Stop working now. Do not start anything new; end your turn with a short handoff note as your answer: what you touched, and what was next. Where your instructions name a file for that note, write it there too.`
595
- };
596
- };
597
- /** A decision as Claude Code's settings-hook JSON output. */
598
- const hookOutput = (decision) => decision.kind === "soft" ? {
599
- decision: "block",
600
- reason: decision.reason
601
- } : {
602
- continue: false,
603
- stopReason: decision.stopReason
604
- };
605
- //#endregion
606
- export { beatKindOf as A, ACCESS_REFUSAL as B, renderLandPlain as C, renderBeatJson as D, beatDocument as E, EXIT_RUNTIME_ERROR as F, WIRE_SCHEMA as H, EXIT_SIGINT as I, EXIT_SIGTERM as L, stallDiagnosis as M, EXIT_CODES as N, statusOf as O, EXIT_OK as P, EXIT_STRAYS_FOUND as R, renderLandJson as S, renderBeatPlain as T, renderFormat as U, UNATTRIBUTED_MODEL as V, selectPath as _, contextLimitFault as a, landProseText as b, hookOutput as c, transcriptTokens as d, usageTokens as f, resolveSession as g, globMatches as h, contextHook as i, demandOf as j, BEAT_KINDS as k, parseContextWindow as l, slicesDocument as m, CONTEXT_STOP_FILE_ENV as n, contextShapeFault as o, renderSlicesJson as p, DEFAULT_CONTEXT_LIMIT as r, contextWindowFor as s, CONTEXT_LIMIT_MARKER as t, subagentTranscriptPath as u, judgeJson as v, DEMAND_BRIEFING as w, noopText as x, landFields as y, EXIT_USAGE_ERROR as z };
478
+ export { EXIT_SIGTERM as C, UNATTRIBUTED_MODEL as D, ACCESS_REFUSAL as E, WIRE_SCHEMA as O, EXIT_SIGINT as S, EXIT_USAGE_ERROR as T, demandOf as _, landFields as a, EXIT_OK as b, renderLandJson as c, renderBeatPlain as d, beatDocument as f, beatKindOf as g, BEAT_KINDS as h, judgeJson as i, renderFormat as k, renderLandPlain as l, statusOf as m, resolveSession as n, landProseText as o, renderBeatJson as p, selectPath as r, noopText as s, globMatches as t, DEMAND_BRIEFING as u, stallDiagnosis as v, EXIT_STRAYS_FOUND as w, EXIT_RUNTIME_ERROR as x, EXIT_CODES as y };
package/dist/flows.mjs CHANGED
@@ -86,20 +86,6 @@ const scope = async (scope, fn) => {
86
86
  context.popScope();
87
87
  }
88
88
  };
89
- /**
90
- * Mark the span `fn` covers as one named slice of the process. Lands no
91
- * commit, prefixes no step name, opens no memory scope.
92
- */
93
- const slice = async (name, fn) => {
94
- const context = ctx();
95
- if (typeof context.enterSlice !== "function") return fn();
96
- context.enterSlice(name);
97
- try {
98
- return await fn();
99
- } finally {
100
- context.leaveSlice?.();
101
- }
102
- };
103
89
  const read = (path) => ctx().read(path);
104
90
  /** Every path in the tree matching `pattern` (`*` stays within a segment, `**` crosses them). */
105
91
  const glob = (pattern) => ctx().glob(pattern);
@@ -680,7 +666,6 @@ var flows_exports = /* @__PURE__ */ __exportAll({
680
666
  sections: () => sections,
681
667
  showScript: () => showScript,
682
668
  skillsFor: () => skillsFor,
683
- slice: () => slice,
684
669
  start: () => start,
685
670
  threads: () => threads,
686
671
  vars: () => vars,
@@ -688,4 +673,4 @@ var flows_exports = /* @__PURE__ */ __exportAll({
688
673
  wrote: () => wrote
689
674
  });
690
675
  //#endregion
691
- export { FLOWS_PROTOCOL, FlowsProtocolError, accessFor, agent, answered, applyScript, changes, changesSince, check, checkScript, codeChanges, codeThreads, configProblems, configure, defineConfig, defineWorkflow, displayPath, env, glob, hasThreadFor, head, human, installContext, isFactoryWorkflow, judge, judgeDiffShape, kept, mark, matches, moveScript, numeric, openQuestions, protocolMismatch, quote, read, refuse, removeScript, requireAnswers, requireProgress, requireReplies, requireRevert, requireThreadsClosed, restart, restoreScript, revertScript, run, scope, seamGate, sectionBodies, sections, showScript, skillsFor, slice, start, flows_exports as t, threads, vars, writeScript, wrote };
676
+ export { FLOWS_PROTOCOL, FlowsProtocolError, accessFor, agent, answered, applyScript, changes, changesSince, check, checkScript, codeChanges, codeThreads, configProblems, configure, defineConfig, defineWorkflow, displayPath, env, glob, hasThreadFor, head, human, installContext, isFactoryWorkflow, judge, judgeDiffShape, kept, mark, 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, writeScript, wrote };