@pmelab/gtd 59.0.1 → 60.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +48 -32
  3. package/claude/hooks/doors.ts +8 -4
  4. package/dist/chunks/flows-DENt0uWV.mjs +707 -0
  5. package/dist/chunks/{steering-CCNvngSH.mjs → steering-DF_BMadH.mjs} +292 -289
  6. package/dist/chunks/testkit-BhTey1Do.mjs +30517 -0
  7. package/dist/chunks/{wire-BTUhRGXj.mjs → wire-DZ8R1RU9.mjs} +8 -1
  8. package/dist/flows.mjs +2 -676
  9. package/dist/gtd.bundle.mjs +11285 -19864
  10. package/dist/gtd.core.mjs +593 -0
  11. package/dist/steering.mjs +2 -2
  12. package/dist/testkit/gherkin.mjs +246 -37
  13. package/dist/testkit.mjs +3 -2
  14. package/dist/web/main.js +234 -232
  15. package/dist/wire.mjs +2 -2
  16. package/dist/workflow-kit.mjs +3 -3
  17. package/package.json +7 -7
  18. package/skills/authoring/SKILL.md +66 -60
  19. package/src/cli/Cli.test.ts +185 -184
  20. package/src/cli/Cli.ts +219 -224
  21. package/src/cli/History.ts +9 -4
  22. package/src/cli/Judges.ts +1 -1
  23. package/src/cli/Output.test.ts +35 -0
  24. package/src/cli/Output.ts +34 -3
  25. package/src/cli/Program.test.ts +78 -84
  26. package/src/cli/Program.ts +192 -128
  27. package/src/cli/ToolCommands.ts +2 -2
  28. package/src/edge/Edge.test.ts +72 -62
  29. package/src/edge/Edge.ts +6 -6
  30. package/src/flows/factory.test.ts +14 -0
  31. package/src/flows/factory.ts +22 -5
  32. package/src/flows/helpers.test.ts +35 -0
  33. package/src/flows/helpers.ts +19 -10
  34. package/src/flows/index.test.ts +66 -0
  35. package/src/flows/index.ts +109 -5
  36. package/src/flows/internal.ts +7 -0
  37. package/src/flows/runtime.test.ts +192 -1
  38. package/src/flows/runtime.ts +189 -55
  39. package/src/gherkin/git-control.feature +6 -6
  40. package/src/gherkin/index.test.ts +127 -0
  41. package/src/gherkin/index.ts +370 -51
  42. package/src/gherkin/messages.test.ts +38 -4
  43. package/src/gherkin/messages.ts +21 -4
  44. package/src/gherkin/more-steps.feature +170 -0
  45. package/src/gherkin/scenario-end.feature +101 -0
  46. package/src/gherkin/testkit.feature +83 -7
  47. package/src/install/Install.test.ts +7 -7
  48. package/src/install/Install.ts +8 -8
  49. package/src/install/Version.ts +9 -3
  50. package/src/install/index.ts +1 -1
  51. package/src/platform/CommandRunner.ts +13 -11
  52. package/src/platform/Commentary.ts +2 -2
  53. package/src/platform/Git.test.ts +4 -5
  54. package/src/platform/Git.ts +42 -38
  55. package/src/platform/Host.ts +1 -1
  56. package/src/platform/NodeServices.ts +11 -0
  57. package/src/platform/Workspace.test.ts +4 -5
  58. package/src/platform/Workspace.ts +3 -3
  59. package/src/platform/WorktreeState.test.ts +2 -3
  60. package/src/platform/WorktreeState.ts +1 -1
  61. package/src/platform/index.ts +2 -1
  62. package/src/replay/Replay.test.ts +13 -2
  63. package/src/replay/Replay.ts +19 -30
  64. package/src/replay/judgeDiffShape.test.ts +1 -1
  65. package/src/steering/Footnotes.test.ts +1 -1
  66. package/src/steering/SteeringFormats.test.ts +1 -1
  67. package/src/steering/freeform.test.ts +1 -1
  68. package/src/steering/index.test.ts +27 -1
  69. package/src/steering/index.ts +6 -104
  70. package/src/steering/internal.ts +11 -0
  71. package/src/steering/qa.test.ts +7 -2
  72. package/src/steering/reads.test.ts +42 -0
  73. package/src/steering/reads.ts +43 -0
  74. package/src/steering/registry.ts +93 -0
  75. package/src/steering/review.test.ts +2 -2
  76. package/src/step/planStart.test.ts +18 -16
  77. package/src/step/planStart.ts +12 -12
  78. package/src/testkit/TestRepo.test.ts +245 -7
  79. package/src/testkit/TestRepo.ts +271 -40
  80. package/src/testkit/imports.test.ts +58 -0
  81. package/src/testkit/imports.ts +102 -0
  82. package/src/testkit/index.test.ts +28 -0
  83. package/src/testkit/index.ts +14 -2
  84. package/src/twins/EmittedScriptRecognizer.ts +2 -6
  85. package/src/twins/EmittedScripts.test.ts +5 -3
  86. package/src/twins/GitTiers.ts +6 -7
  87. package/src/twins/InMemRepo.ts +1 -0
  88. package/src/twins/Layers.test.ts +1 -1
  89. package/src/twins/Layers.ts +10 -3
  90. package/src/twins/cliIo.ts +9 -4
  91. package/src/wire/Script.ts +11 -0
  92. package/src/wire/WireSchema.test.ts +3 -0
  93. package/src/wire/golden/1/script.json +4 -0
  94. package/src/wire/index.ts +1 -0
  95. package/src/workflow/SteeringFormats.test.ts +1 -1
  96. package/src/workflow/compile.ts +2 -2
  97. package/src/workflow/discovery.test.ts +27 -10
  98. package/src/workflow/discovery.ts +5 -6
  99. package/src/workflow/index.ts +1 -0
  100. package/src/workflow/load.test.ts +316 -119
  101. package/src/workflow/load.ts +478 -305
  102. package/src/workflow/pin.test.ts +159 -0
  103. package/src/workflow/pin.ts +72 -0
  104. package/src/workflow/vars.ts +3 -3
  105. package/src/workflow-kit/index.test.ts +25 -0
  106. package/src/workflow-kit/index.ts +37 -4
  107. package/src/workflow-kit/review.ts +2 -2
  108. package/dist/chunks/testkit-07Z_ENch.mjs +0 -32175
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtd",
3
- "version": "59.0.1",
3
+ "version": "60.1.0",
4
4
  "description": "Drive the gtd loop inside Claude Code: agent turns run as subagents, gtd decides every beat",
5
5
  "author": {
6
6
  "name": "Philipp Melab"
package/README.md CHANGED
@@ -15,6 +15,8 @@ to any machine that checks it out.
15
15
 
16
16
  ## Install
17
17
 
18
+ gtd needs Node 22.19 or newer.
19
+
18
20
  ```bash
19
21
  npm install -g @pmelab/gtd
20
22
  ```
@@ -23,6 +25,11 @@ That installs `latest`, which moves once a day to the newest release. Every
23
25
  merge to `main` publishes to `next` first: `npm install -g @pmelab/gtd@next`
24
26
  gets each one as it lands.
25
27
 
28
+ gtd bundles `gtd.config.ts` with [rolldown](https://rolldown.rs), whose native
29
+ binary npm installs for your platform. Where rolldown ships none, install its
30
+ WebAssembly build next to gtd:
31
+ `npm install -g --force @rolldown/binding-wasm32-wasi`.
32
+
26
33
  Or run without installing (prefix every `gtd` below with `npx`) — see
27
34
  [Configuration](https://github.com/pmelab/gtd/blob/main/docs/configuration.md)
28
35
  for the settings most projects tune. A process setting's value is committed to
@@ -57,9 +64,9 @@ driver enforces it at the OS level. See
57
64
 
58
65
  > **A repository's `gtd.config.ts` is code, and gtd runs it.** A custom workflow
59
66
  > is a TypeScript module, and every gtd command that looks at workflow state —
60
- > `gtd next`, `gtd lsp`, `gtd door` and `gtd doors` included, not just
61
- > `gtd land` — evaluates it. Treat it like a Makefile or a `package.json`
62
- > script: don't run gtd in a checkout you don't trust.
67
+ > `gtd next`, `gtd lsp` and `gtd start` included, not just `gtd land` —
68
+ > evaluates it. Treat it like a Makefile or a `package.json` script: don't run
69
+ > gtd in a checkout you don't trust.
63
70
 
64
71
  ## Quick start
65
72
 
@@ -67,7 +74,7 @@ Put a `gtd.config.ts` at your repository's root (see [Install](#install)) and
67
74
  commit it; gtd refuses to run without one. The repository need not be a
68
75
  JavaScript project: gtd resolves the config's `@pmelab/gtd/*` imports itself, so
69
76
  a Python, Rust or notes repository needs no `package.json` and no install. Then
70
- run `gtd install`: it writes nothing and prints a briefing (and where to get a
77
+ run `gtd guide`: it writes nothing and prints a briefing (and where to get a
71
78
  workflow, if you have none yet). Pipe that briefing into your coding agent and
72
79
  answer its questions. It should build you a script that will autonomously run
73
80
  the process for you. Ask your agent if you have any questions.
@@ -263,7 +270,7 @@ gtd next | claude -p --dangerously-skip-permissions
263
270
  **The turn ends when `claude -p` returns** — a command the agent backgrounds
264
271
  dies unread, and the process stalls on an empty turn. Claude Code lets the agent
265
272
  background commands and caps foreground ones at 10 minutes by default, so a real
266
- driver exports these first (`gtd install`'s reference driver does):
273
+ driver exports these first (`gtd guide`'s reference driver does):
267
274
 
268
275
  ```bash
269
276
  export CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1
@@ -346,9 +353,9 @@ The requirements go to the top of `.gtd/TODO.md`, above whatever it already
346
353
  holds. A long, multi-line requirements paste still starts a process; if Claude
347
354
  Code never expanded the paste, gtd says it could not read it, and you add the
348
355
  requirements to the top of `.gtd/TODO.md` and run `/gtd`. `/gtd <door> [args]`
349
- takes one of the doors `gtd doors` lists (gtd-workflows' `default` brings `fix`,
350
- `review [base]`, and `rollout <flag>` and `cleanup <flag>` where the config
351
- exports them); text whose word count does not fit a door's args (bare
356
+ takes one of the doors a bare `gtd start` lists (gtd-workflows' `default` brings
357
+ `fix`, `review [base]`, and `rollout <flag>` and `cleanup <flag>` where the
358
+ config exports them); text whose word count does not fit a door's args (bare
352
359
  `/gtd rollout` included) starts a process from that text as requirements. At
353
360
  every human rest Claude itself takes over: it walks you through the open
354
361
  questions one at a time, answers your own questions about the plan or the diff,
@@ -381,7 +388,7 @@ But lets be honest, who reads documentation these days. Paste this into your
381
388
  coding agent:
382
389
 
383
390
  ```
384
- !gtd install
391
+ !gtd guide
385
392
  ```
386
393
 
387
394
  It prints a self-contained briefing that teaches the agent to set the project
@@ -390,8 +397,8 @@ you what you want before it starts driving. You get one prompt to paste, not a
390
397
  state name to choose. The four commands: **`gtd-build`** drives beats until the
391
398
  process rests; **`gtd-edit`** opens the steering file the process is waiting on
392
399
  right now — falling back to `.gtd/TODO.md` when the resting state declares none;
393
- **`gtd-door <name> [args...]`** starts a process through one of the doors
394
- `gtd doors` lists (`gtd-door fix`, `gtd-door review [base]` with gtd-workflows'
400
+ **`gtd-door <name> [args...]`** starts a process through one of the doors a bare
401
+ `gtd start` lists (`gtd-door fix`, `gtd-door review [base]` with gtd-workflows'
395
402
  `default`) and drives it. The `.gtd/TODO.md` fallback is also how you begin: on
396
403
  a clean repository the edit command opens the empty `.gtd/TODO.md`, and whatever
397
404
  you write there is the first sketch the whole process gets planned from. As a
@@ -447,9 +454,9 @@ The workflow itself is a plain async TypeScript function, and the
447
454
  `gtd.config.ts` at the repository root names it. A workflow may be a factory —
448
455
  `feature({ testCommand: "npm run ci" })` — whose options gtd validates when it
449
456
  loads the config: a misspelled or mistyped one fails every command, naming the
450
- workflow, the key and what was expected. `gtd doors` lists the doors of the
451
- workflows your config exports, and `gtd --workflow <name>` starts any workflow
452
- by name. See
457
+ workflow, the key and what was expected. `gtd start` lists the workflows your
458
+ config exports and the doors they bring, and `gtd start <name> [args...]` starts
459
+ one by name; a door named like a workflow wins. See
453
460
  [Configuration](https://github.com/pmelab/gtd/blob/main/docs/configuration.md) —
454
461
  and remember gtd evaluates that file on every command. A shared workflow package
455
462
  bundling its own `@pmelab/gtd` is checked against the running gtd and refused,
@@ -484,14 +491,16 @@ doesn't lose it. `/gtd ship` pushes this process's own ref to origin alongside
484
491
  the branch (never the others) and writes a `Gtd-History: <ref>` trailer on the
485
492
  squashed commit. The push is forced, so it replaces origin's copy of that one
486
493
  ref. If that push fails, the ship fails and nothing is squashed. Recover the
487
- full trail with `gtd history fetch | sh`, then `gtd history show <ref>`.
494
+ full trail with `s=$(gtd history fetch --json=script) && sh -c "$s"`, then
495
+ `gtd history show <ref>`.
488
496
 
489
497
  ```sh
490
498
  gtd history list # one line per kept process
491
499
  gtd history show <ref> # replay its steps, judge verdicts and approvals
492
500
  gtd history metrics [ref...] # how the kept processes went, per process and in total
493
501
  gtd history judges [ref...] # how often each judge's verdicts were overturned
494
- gtd history fetch | sh # pull every kept ref from origin
502
+ # pull every kept ref from origin
503
+ s=$(gtd history fetch --json=script) && sh -c "$s"
495
504
  ```
496
505
 
497
506
  `gtd history metrics` measures gtd-workflows' `default` `feature` workflow from
@@ -537,12 +546,13 @@ contradicts it:
537
546
 
538
547
  Any other verdict has no outcome. The report counts verdicts, scored verdicts
539
548
  and overturns per judge and per `p` bucket (`0.8-0.9: 1/2` — one of two
540
- overturned). `--var <threshold>=<value>` re-decides every past verdict under
541
- another threshold and prints the decisions that would change, against the
542
- threshold each process recorded (a process that recorded none is left out):
549
+ overturned). `--threshold <name>=<value>` (formerly `--var`) re-decides every
550
+ past verdict under another threshold and prints the decisions that would change,
551
+ against the threshold each process recorded (a process that recorded none is
552
+ left out):
543
553
 
544
554
  ```sh
545
- gtd history judges --var qualityTriageMinP=0.9
555
+ gtd history judges --threshold qualityTriageMinP=0.9
546
556
  # what-if qualityTriageMinP=0.9: 7 noise drops become notes (2 overturned)
547
557
  ```
548
558
 
@@ -600,25 +610,31 @@ approvals as `approvals` (`[]` when none), and `gtd history show` prints each as
600
610
  gtd is one package, `@pmelab/gtd`, and every entrypoint shares its version and
601
611
  [SemVer promise](https://github.com/pmelab/gtd/blob/main/COMPATIBILITY.md).
602
612
 
603
- | Import | What it is |
604
- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
605
- | `@pmelab/gtd/flows` | The flow API a workflow is written in: the steps (`agent`, `human`, `run`, …), `scope`, workflow factories, `defineConfig` and `FLOWS_PROTOCOL`. |
606
- | `@pmelab/gtd/wire` | The driver protocol: `WIRE_SCHEMA`, the exit codes and the types of every `--json` document. |
607
- | `@pmelab/gtd/steering` | The steering-file formats (`qa`, `review`, `findings`) and the review-note readers. |
608
- | `@pmelab/gtd/workflow-kit` | Policy-free building blocks to compose a workflow from: health checks, quality laps, scenario freezing, review tails. |
609
- | `@pmelab/gtd/testkit` | Runs any workflow against the real engine in an in-memory repository, under any test runner. See [Testing a workflow](https://github.com/pmelab/gtd/blob/main/docs/testing.md). |
610
- | `@pmelab/gtd/testkit/gherkin` | The testkit as quickpickle steps for vitest. Needs `vitest` and `quickpickle`, optional peer dependencies. |
613
+ | Import | What it is |
614
+ | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
615
+ | `@pmelab/gtd/flows` | The flow API a workflow is written in: the steps (`agent`, `human`, `run`, …), `scope`, `workflow()`, workflow factories, `defineConfig` and `FLOWS_PROTOCOL`. |
616
+ | `@pmelab/gtd/wire` | The driver protocol: `WIRE_SCHEMA`, the exit codes and the types of every `--json` document. |
617
+ | `@pmelab/gtd/steering` | The steering-file formats (`qa`, `review`, `findings`), the review-note readers, and `sections`, `threads` and `openQuestions` as plain functions. |
618
+ | `@pmelab/gtd/workflow-kit` | Policy-free building blocks to compose a workflow from: health checks, quality laps, scenario freezing, review tails. See [Workflow kit](https://github.com/pmelab/gtd/blob/main/docs/workflow-kit.md). |
619
+ | `@pmelab/gtd/testkit` | Runs any workflow against the real engine in an in-memory repository, under any test runner, plus a flow-context harness for rendering prompts. See [Testing a workflow](https://github.com/pmelab/gtd/blob/main/docs/testing.md). |
620
+ | `@pmelab/gtd/testkit/gherkin` | The testkit as quickpickle steps for vitest. Needs `vitest` and `quickpickle`, optional peer dependencies. |
611
621
 
612
622
  Types come from the TypeScript sources the package ships. Configs never need an
613
623
  install for any of these but the testkit's: gtd resolves a `gtd.config.ts`'s
614
624
  `@pmelab/gtd/*` imports to its own copy.
615
625
 
616
- The `gtd` bin's commands — `next`, `land`, `abandon`, `restore`, `validate`,
617
- `check`, `uncheck`, `install`, `summary`, `base`, `door`, `doors`, `version`,
626
+ The `gtd` bin's commands — `next`, `land`, `start`, `abandon`, `restore`,
627
+ `validate`, `check`, `uncheck`, `guide`, `bundle`, `summary`, `base`, `version`,
618
628
  `help`, `history list`, `history show`, `history metrics`, `history judges`,
619
- `history fetch`, `strays`, and the tools `ui`, `lsp`, `judge` (`judge answer`,
629
+ `history fetch`, `strays`, the tools `ui`, `lsp`, `judge` (`judge answer`,
620
630
  `judge run`) — are listed in the
621
- [CLI reference](https://github.com/pmelab/gtd/blob/main/docs/cli.md).
631
+ [CLI reference](https://github.com/pmelab/gtd/blob/main/docs/cli.md). Every
632
+ command that prints a script takes `--json=script`, and `--` ends the options.
633
+
634
+ `gtd bundle` prints a pin: gtd's engine and the current workflow, npm packages
635
+ included, as one gzipped ES module after a plain-text
636
+ `gtdpin <format> gtd <version>` line. A workflow using a package with a native
637
+ addon cannot be pinned.
622
638
 
623
639
  ## License
624
640
 
@@ -1,4 +1,4 @@
1
- // Doors are the workflow's named shortcuts into a process (`gtd doors`). gtd
1
+ // Doors are the workflow's named shortcuts into a process (`gtd start` lists them). gtd
2
2
  // prints the script that starts one; running it is the driver's job, as with
3
3
  // every git write gtd plans. The mod hardcodes no door: it asks gtd.
4
4
 
@@ -12,19 +12,23 @@ export type Door = {
12
12
 
13
13
  const fail = (text: string): Shipped => ({ ok: false, text })
14
14
 
15
+ type Startable = { kind: "workflow"; name: string } | ({ kind: "door" } & Door)
16
+
15
17
  // Every door the repository offers; none when gtd cannot say.
16
18
  export async function doors(io: ShipIo): Promise<Door[]> {
17
- const listed = await io.run(["gtd", "doors", "--json"])
19
+ const listed = await io.run(["gtd", "start", "--json"])
18
20
  if (listed.code !== 0) return []
19
21
  try {
20
- return JSON.parse(listed.out) as Door[]
22
+ return (JSON.parse(listed.out) as Startable[]).flatMap((s) =>
23
+ s.kind === "door" ? [{ name: s.name, workflow: s.workflow, args: s.args }] : [],
24
+ )
21
25
  } catch {
22
26
  return []
23
27
  }
24
28
  }
25
29
 
26
30
  export async function enter(io: ShipIo, name: string, args: string[]): Promise<Shipped> {
27
- const argv = ["gtd", "door", name, ...args]
31
+ const argv = ["gtd", "start", name, ...args]
28
32
  const planned = await io.run(argv)
29
33
  if (planned.code !== 0)
30
34
  return fail(planned.err.trim() || `${argv.join(" ")} exited ${planned.code}`)