@pmelab/gtd 59.0.0 → 60.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 (90) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +42 -38
  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-CMBAAyRK.mjs → testkit-BvecVjQ0.mjs} +937 -772
  7. package/dist/chunks/{wire-C12dahrH.mjs → wire-DZ8R1RU9.mjs} +9 -2
  8. package/dist/flows.mjs +2 -676
  9. package/dist/gtd.bundle.mjs +1101 -1025
  10. package/dist/steering.mjs +2 -2
  11. package/dist/testkit/gherkin.mjs +371 -82
  12. package/dist/testkit.mjs +3 -2
  13. package/dist/web/main.js +234 -232
  14. package/dist/wire.mjs +2 -2
  15. package/dist/workflow-kit.mjs +3 -3
  16. package/package.json +1 -1
  17. package/skills/authoring/SKILL.md +68 -61
  18. package/src/cli/Cli.test.ts +311 -229
  19. package/src/cli/Cli.ts +486 -585
  20. package/src/cli/Help.test.ts +47 -0
  21. package/src/cli/Help.ts +70 -0
  22. package/src/cli/History.ts +9 -4
  23. package/src/cli/Judges.ts +1 -1
  24. package/src/cli/Output.test.ts +35 -0
  25. package/src/cli/Output.ts +31 -1
  26. package/src/cli/Program.test.ts +131 -82
  27. package/src/cli/Program.ts +197 -111
  28. package/src/edge/Edge.test.ts +64 -56
  29. package/src/edge/Edge.ts +4 -4
  30. package/src/emit/Emit.test.ts +1 -1
  31. package/src/emit/Emit.ts +1 -1
  32. package/src/flows/factory.test.ts +14 -0
  33. package/src/flows/factory.ts +25 -6
  34. package/src/flows/helpers.test.ts +35 -0
  35. package/src/flows/helpers.ts +19 -10
  36. package/src/flows/index.test.ts +66 -0
  37. package/src/flows/index.ts +109 -5
  38. package/src/flows/internal.ts +7 -0
  39. package/src/flows/runtime.test.ts +192 -1
  40. package/src/flows/runtime.ts +188 -54
  41. package/src/gherkin/git-control.feature +6 -6
  42. package/src/gherkin/index.test.ts +127 -0
  43. package/src/gherkin/index.ts +481 -98
  44. package/src/gherkin/messages.test.ts +124 -0
  45. package/src/gherkin/messages.ts +101 -0
  46. package/src/gherkin/more-steps.feature +170 -0
  47. package/src/gherkin/scenario-end.feature +101 -0
  48. package/src/gherkin/testkit.feature +83 -7
  49. package/src/install/Install.test.ts +7 -7
  50. package/src/install/Install.ts +8 -8
  51. package/src/replay/Replay.test.ts +13 -2
  52. package/src/replay/Replay.ts +19 -30
  53. package/src/replay/judgeDiffShape.test.ts +1 -1
  54. package/src/steering/Footnotes.test.ts +1 -1
  55. package/src/steering/SteeringFormats.test.ts +1 -1
  56. package/src/steering/freeform.test.ts +1 -1
  57. package/src/steering/index.test.ts +27 -1
  58. package/src/steering/index.ts +6 -104
  59. package/src/steering/internal.ts +11 -0
  60. package/src/steering/qa.test.ts +7 -2
  61. package/src/steering/reads.test.ts +42 -0
  62. package/src/steering/reads.ts +43 -0
  63. package/src/steering/registry.ts +93 -0
  64. package/src/steering/review.test.ts +2 -2
  65. package/src/step/planStart.test.ts +18 -16
  66. package/src/step/planStart.ts +9 -9
  67. package/src/testkit/TestRepo.test.ts +289 -6
  68. package/src/testkit/TestRepo.ts +317 -41
  69. package/src/testkit/imports.test.ts +58 -0
  70. package/src/testkit/imports.ts +102 -0
  71. package/src/testkit/index.test.ts +28 -0
  72. package/src/testkit/index.ts +14 -2
  73. package/src/twins/EmittedScriptRecognizer.ts +7 -14
  74. package/src/twins/EmittedScripts.test.ts +4 -2
  75. package/src/twins/InMemRepo.ts +1 -0
  76. package/src/wire/Land.ts +1 -1
  77. package/src/wire/Script.ts +11 -0
  78. package/src/wire/WireSchema.test.ts +3 -0
  79. package/src/wire/golden/1/script.json +4 -0
  80. package/src/wire/index.ts +1 -0
  81. package/src/workflow/SteeringFormats.test.ts +1 -1
  82. package/src/workflow/compile.ts +2 -2
  83. package/src/workflow/discovery.test.ts +3 -3
  84. package/src/workflow/load.test.ts +256 -116
  85. package/src/workflow/load.ts +175 -152
  86. package/src/workflow/skills.test.ts +5 -5
  87. package/src/workflow/skills.ts +1 -1
  88. package/src/workflow-kit/index.test.ts +25 -0
  89. package/src/workflow-kit/index.ts +37 -4
  90. package/src/workflow-kit/review.ts +2 -2
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtd",
3
- "version": "59.0.0",
3
+ "version": "60.0.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
@@ -57,9 +57,9 @@ driver enforces it at the OS level. See
57
57
 
58
58
  > **A repository's `gtd.config.ts` is code, and gtd runs it.** A custom workflow
59
59
  > 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.
60
+ > `gtd next`, `gtd lsp` and `gtd start` included, not just `gtd land` —
61
+ > evaluates it. Treat it like a Makefile or a `package.json` script: don't run
62
+ > gtd in a checkout you don't trust.
63
63
 
64
64
  ## Quick start
65
65
 
@@ -67,7 +67,7 @@ Put a `gtd.config.ts` at your repository's root (see [Install](#install)) and
67
67
  commit it; gtd refuses to run without one. The repository need not be a
68
68
  JavaScript project: gtd resolves the config's `@pmelab/gtd/*` imports itself, so
69
69
  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
70
+ run `gtd guide`: it writes nothing and prints a briefing (and where to get a
71
71
  workflow, if you have none yet). Pipe that briefing into your coding agent and
72
72
  answer its questions. It should build you a script that will autonomously run
73
73
  the process for you. Ask your agent if you have any questions.
@@ -155,14 +155,14 @@ gtd land
155
155
 
156
156
  ```
157
157
  commit everything with this message: gtd(human): idle → unwind
158
- (run `gtd land --json=script | sh` to get the landing script)
158
+ (to land it: s=$(gtd land --json=script) && sh -c "$s")
159
159
  ```
160
160
 
161
161
  You could run that commit by hand. Take the script instead — it spells out the
162
162
  exact message and reports what landed:
163
163
 
164
164
  ```bash
165
- gtd land --json=script | sh
165
+ s=$(gtd land --json=script) && sh -c "$s"
166
166
  ```
167
167
 
168
168
  ```
@@ -205,7 +205,7 @@ before:
205
205
 
206
206
  ```bash
207
207
  sh -c "$(gtd next --json=content)"
208
- gtd land --json=script | sh
208
+ s=$(gtd land --json=script) && sh -c "$s"
209
209
  ```
210
210
 
211
211
  `--json=<field>` is how a script reads one value out of a beat. Bare `--json`
@@ -263,7 +263,7 @@ gtd next | claude -p --dangerously-skip-permissions
263
263
  **The turn ends when `claude -p` returns** — a command the agent backgrounds
264
264
  dies unread, and the process stalls on an empty turn. Claude Code lets the agent
265
265
  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):
266
+ driver exports these first (`gtd guide`'s reference driver does):
267
267
 
268
268
  ```bash
269
269
  export CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1
@@ -278,7 +278,7 @@ The prompt tells the agent to asses your request and write
278
278
  `.gtd/REQUIREMENTS.md`, and that file is the turn. Land it like any other beat:
279
279
 
280
280
  ```bash
281
- gtd land --json=script | sh
281
+ s=$(gtd land --json=script) && sh -c "$s"
282
282
  ```
283
283
 
284
284
  `gtd next --json=validate` is there if you want to check the agent's work first:
@@ -303,7 +303,7 @@ while :; do
303
303
  # Nothing left to do, abort.
304
304
  stalled) gtd next >&2; exit 1 ;;
305
305
  esac
306
- gtd land --json=script | sh
306
+ s=$(gtd land --json=script) && sh -c "$s"
307
307
  done
308
308
  ```
309
309
 
@@ -346,9 +346,9 @@ The requirements go to the top of `.gtd/TODO.md`, above whatever it already
346
346
  holds. A long, multi-line requirements paste still starts a process; if Claude
347
347
  Code never expanded the paste, gtd says it could not read it, and you add the
348
348
  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
349
+ takes one of the doors a bare `gtd start` lists (gtd-workflows' `default` brings
350
+ `fix`, `review [base]`, and `rollout <flag>` and `cleanup <flag>` where the
351
+ config exports them); text whose word count does not fit a door's args (bare
352
352
  `/gtd rollout` included) starts a process from that text as requirements. At
353
353
  every human rest Claude itself takes over: it walks you through the open
354
354
  questions one at a time, answers your own questions about the plan or the diff,
@@ -381,7 +381,7 @@ But lets be honest, who reads documentation these days. Paste this into your
381
381
  coding agent:
382
382
 
383
383
  ```
384
- !gtd install
384
+ !gtd guide
385
385
  ```
386
386
 
387
387
  It prints a self-contained briefing that teaches the agent to set the project
@@ -390,8 +390,8 @@ you what you want before it starts driving. You get one prompt to paste, not a
390
390
  state name to choose. The four commands: **`gtd-build`** drives beats until the
391
391
  process rests; **`gtd-edit`** opens the steering file the process is waiting on
392
392
  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'
393
+ **`gtd-door <name> [args...]`** starts a process through one of the doors a bare
394
+ `gtd start` lists (`gtd-door fix`, `gtd-door review [base]` with gtd-workflows'
395
395
  `default`) and drives it. The `.gtd/TODO.md` fallback is also how you begin: on
396
396
  a clean repository the edit command opens the empty `.gtd/TODO.md`, and whatever
397
397
  you write there is the first sketch the whole process gets planned from. As a
@@ -447,9 +447,9 @@ The workflow itself is a plain async TypeScript function, and the
447
447
  `gtd.config.ts` at the repository root names it. A workflow may be a factory —
448
448
  `feature({ testCommand: "npm run ci" })` — whose options gtd validates when it
449
449
  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
450
+ workflow, the key and what was expected. `gtd start` lists the workflows your
451
+ config exports and the doors they bring, and `gtd start <name> [args...]` starts
452
+ one by name; a door named like a workflow wins. See
453
453
  [Configuration](https://github.com/pmelab/gtd/blob/main/docs/configuration.md) —
454
454
  and remember gtd evaluates that file on every command. A shared workflow package
455
455
  bundling its own `@pmelab/gtd` is checked against the running gtd and refused,
@@ -484,14 +484,16 @@ doesn't lose it. `/gtd ship` pushes this process's own ref to origin alongside
484
484
  the branch (never the others) and writes a `Gtd-History: <ref>` trailer on the
485
485
  squashed commit. The push is forced, so it replaces origin's copy of that one
486
486
  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>`.
487
+ full trail with `s=$(gtd history fetch --json=script) && sh -c "$s"`, then
488
+ `gtd history show <ref>`.
488
489
 
489
490
  ```sh
490
491
  gtd history list # one line per kept process
491
492
  gtd history show <ref> # replay its steps, judge verdicts and approvals
492
493
  gtd history metrics [ref...] # how the kept processes went, per process and in total
493
494
  gtd history judges [ref...] # how often each judge's verdicts were overturned
494
- gtd history fetch | sh # pull every kept ref from origin
495
+ # pull every kept ref from origin
496
+ s=$(gtd history fetch --json=script) && sh -c "$s"
495
497
  ```
496
498
 
497
499
  `gtd history metrics` measures gtd-workflows' `default` `feature` workflow from
@@ -537,12 +539,13 @@ contradicts it:
537
539
 
538
540
  Any other verdict has no outcome. The report counts verdicts, scored verdicts
539
541
  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):
542
+ overturned). `--threshold <name>=<value>` (formerly `--var`) re-decides every
543
+ past verdict under another threshold and prints the decisions that would change,
544
+ against the threshold each process recorded (a process that recorded none is
545
+ left out):
543
546
 
544
547
  ```sh
545
- gtd history judges --var qualityTriageMinP=0.9
548
+ gtd history judges --threshold qualityTriageMinP=0.9
546
549
  # what-if qualityTriageMinP=0.9: 7 noise drops become notes (2 overturned)
547
550
  ```
548
551
 
@@ -600,25 +603,26 @@ approvals as `approvals` (`[]` when none), and `gtd history show` prints each as
600
603
  gtd is one package, `@pmelab/gtd`, and every entrypoint shares its version and
601
604
  [SemVer promise](https://github.com/pmelab/gtd/blob/main/COMPATIBILITY.md).
602
605
 
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. |
606
+ | Import | What it is |
607
+ | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
608
+ | `@pmelab/gtd/flows` | The flow API a workflow is written in: the steps (`agent`, `human`, `run`, …), `scope`, `workflow()`, workflow factories, `defineConfig` and `FLOWS_PROTOCOL`. |
609
+ | `@pmelab/gtd/wire` | The driver protocol: `WIRE_SCHEMA`, the exit codes and the types of every `--json` document. |
610
+ | `@pmelab/gtd/steering` | The steering-file formats (`qa`, `review`, `findings`), the review-note readers, and `sections`, `threads` and `openQuestions` as plain functions. |
611
+ | `@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). |
612
+ | `@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). |
613
+ | `@pmelab/gtd/testkit/gherkin` | The testkit as quickpickle steps for vitest. Needs `vitest` and `quickpickle`, optional peer dependencies. |
611
614
 
612
615
  Types come from the TypeScript sources the package ships. Configs never need an
613
616
  install for any of these but the testkit's: gtd resolves a `gtd.config.ts`'s
614
617
  `@pmelab/gtd/*` imports to its own copy.
615
618
 
616
- The `gtd` bin's commands — `next`, `land`, `abandon`, `restore`, `validate`,
617
- `check`, `uncheck`, `install`, `summary`, `base`, `door`, `doors`, `version`,
618
- `help`, `history list`, `history show`, `history metrics`, `history judges`,
619
- `history fetch`, `strays`, and the tools `ui`, `lsp`, `judge` (`judge answer`,
619
+ The `gtd` bin's commands — `next`, `land`, `start`, `abandon`, `restore`,
620
+ `validate`, `check`, `uncheck`, `guide`, `summary`, `base`, `version`, `help`,
621
+ `history list`, `history show`, `history metrics`, `history judges`,
622
+ `history fetch`, `strays`, the tools `ui`, `lsp`, `judge` (`judge answer`,
620
623
  `judge run`) — are listed in the
621
- [CLI reference](https://github.com/pmelab/gtd/blob/main/docs/cli.md).
624
+ [CLI reference](https://github.com/pmelab/gtd/blob/main/docs/cli.md). Every
625
+ command that prints a script takes `--json=script`, and `--` ends the options.
622
626
 
623
627
  ## License
624
628
 
@@ -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}`)