@pmelab/gtd 1.9.0 → 1.9.2

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 (3) hide show
  1. package/README.md +63 -31
  2. package/dist/gtd.bundle.mjs +915 -845
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -218,7 +218,10 @@ The last commit subject is bucketed two ways:
218
218
  Review; uncommitted → Await Review (commits REVIEW.md and auto-advances to
219
219
  Done). 5a. **HEAD `gtd: done` + `squash` enabled + squash base present + no
220
220
  unrelated code dirty** (a lone untracked `SQUASH_MSG.md` is allowed) →
221
- Squashing; unrelated code dirty → New Feature.
221
+ Squashing; unrelated code dirty → New Feature. 8a. **Green health check + ≥1
222
+ `gtd: health-fix` + `squash` enabled** → Squashing (same agent-authored
223
+ conventional-commits path as the feature-cycle squash — no hardcoded
224
+ placeholder).
222
225
  6. **Boundary HEAD + pending changes** (and no `.gtd`/REVIEW/FEEDBACK), or HEAD
223
226
  `gtd: new task` + clean tree (regenerate a lost seed) → New Feature.
224
227
  7. **TODO.md present** → Grilling / Grilled.
@@ -241,8 +244,8 @@ flowchart TD
241
244
  P2 -->|"empty = approval"| Close["Close package — rm pkg dir, gtd: package done"]:::edge
242
245
  P2 -->|"non-empty"| Fixing["Fixing — rm FEEDBACK, fixer agent"]:::agent
243
246
  P2 -->|absent| P2b{"HEALTH.md?"}
244
- P2b -->|"present"| HealthFix["Health Fixing — rm HEALTH.md, gtd: health-fix, fixer agent"]:::agent
245
- HealthFix -.->|"re-resolve"| HealthCheck
247
+ P2b -->|"present"| HealthFix["Health Fixing — rm HEALTH.md, gtd: health-check, fixer agent (leaves edits uncommitted)"]:::agent
248
+ HealthFix -.->|"next gtd run: dirty health HEAD → commit gtd: health-fix, re-resolve"| HealthCheck
246
249
  P2b -->|absent| P3{".gtd/?"}
247
250
  P3 -->|"modified"| Planning["Planning — gtd: planning"]:::agent
248
251
  P3 -->|"code dirty / resume / no-op fixer"| Testing["Testing — gtd: building, run tests"]:::edge
@@ -254,7 +257,7 @@ flowchart TD
254
257
  P4 -->|"uncommitted"| Await["Await Review — commit gtd: awaiting review"]:::edge
255
258
  Await -.->|"re-resolve"| Done
256
259
  P4 -->|absent| P5{"boundary HEAD + dirty,<br/>or gtd: new task + clean?"}
257
- Done -->|"squash enabled"| Squashing["Squashing — reset --soft base, squash commit"]:::agent
260
+ Done -->|"squash enabled"| Squashing["Squashing — agent authors conventional-commits message, reset --soft base, squash commit"]:::agent
258
261
  Done -->|"squash disabled"| Idle
259
262
  Squashing --> Idle["Idle — nothing to do (STOP)"]:::gate
260
263
  P5 -->|yes| NewFeature["New Feature — gtd: new task, revert, seed TODO"]:::edge
@@ -330,27 +333,27 @@ Each state has a **condition** (when it wins), a deterministic **action**, the
330
333
  human; **edge-only** states render no prompt at all — the driver performs their
331
334
  action and re-resolves silently.
332
335
 
333
- | State | Kind | Wins when | Action & commit | Advances to |
334
- | ------------------ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
335
- | **Transport** | edge-only, auto | HEAD `gtd: transport` (hand-made handoff commit) | mixed-reset HEAD (`git reset HEAD~1`), keep work in tree; **no commit** | re-derive from the restored tree |
336
- | **Escalate** | STOP | ERRORS.md present | none | held until the human deletes ERRORS.md |
337
- | **Fixing** | agent, auto | non-empty FEEDBACK.md present | inline FEEDBACK into the prompt, remove FEEDBACK.md; commit its removal `gtd: fixing` (FEEDBACK was committed by Testing) or `gtd: feedback` (uncommitted, written by Agentic Review) | fixer edits → Testing |
338
- | **Health Fixing** | agent, auto | HEALTH.md present (no `.gtd`, REVIEW.md, or FEEDBACK.md) | read HEALTH.md into the prompt, commit its removal `gtd: health-fix` | fixer edits → Health check |
339
- | **Close package** | edge-only, auto | empty FEEDBACK.md present (clean review); also reached from Agentic Review force-approve | rm FEEDBACK.md, rm the first (finished) package dir (+ the now-empty `.gtd/`); commit `gtd: package done` | more packages → Building; `.gtd` gone → Clean |
340
- | **Planning** | agent, auto | `.gtd` present **and modified**; HEAD `gtd: grilled` or `gtd: planning` | commit the `.gtd/` changes `gtd: planning` | continue decomposing, else → Building |
341
- | **Testing** | edge-only, auto | `.gtd` present, no FEEDBACK/ERRORS, and a reason to test: code changes, a pending ERRORS.md deletion (human resume), or a clean tree under HEAD `gtd: fixing` (no-op fixer) | commit pending tree `gtd: building`, run `testCommand`; green → proceed; red → write FEEDBACK (below cap) or ERRORS (at cap), commit `gtd: errors`; if captured output is empty/whitespace, a sentinel string is written so the file is never empty (empty FEEDBACK remains reserved for agentic-review approval) | green → Agentic Review; FEEDBACK → Fixing; ERRORS → Escalate |
342
- | **Building** | agent, auto | `.gtd` present and clean, clean tree; HEAD `gtd: planning` or `gtd: package done` | if HEAD `gtd: planning` and TODO.md present, delete TODO.md and commit (prefix unchanged, fires once); select the first package, inline its tasks; agent leaves work **uncommitted** | Testing |
343
- | **Agentic Review** | agent, auto | `.gtd` present and clean, clean tree; HEAD `gtd: building` | reviewer writes FEEDBACK.md (empty = approval), uncommitted — **unless** force-approved (kill-switch off or review-fix threshold hit), which routes straight to Close package | empty FEEDBACK → Close package; non-empty → Fixing |
344
- | **Done** | edge-only, auto | REVIEW.md committed + clean tree, **or** committed + checkbox-only edits (only `- [ ]`→`- [x]` flips in REVIEW.md = approval) | rm REVIEW.md, commit `gtd: done` | Squashing (if enabled) or Idle |
345
- | **Squashing** | agent, auto | no steering files, HEAD `gtd: done` or green Health check with ≥1 `gtd: health-fix`, `squash` enabled, squash base present, no unrelated code dirty (a lone untracked `SQUASH_MSG.md` is allowed) | agent authors a conventional-commits message from the full `<base>..HEAD` diff, then runs `git reset --soft <base>` + `git commit` — collapses all intermediate `gtd: *` commits (including any interleaved non-gtd commits) into one; **gtd then STOPs** — post-squash review fires only on the next manual `gtd` run | Idle (STOP) |
346
- | **Accept Review** | edge-only, auto | REVIEW.md committed + pending **non-checkbox** edits (human annotated REVIEW.md with comments / edited code) | seed TODO.md from the changeset, `git checkout` to discard the code edits, rm REVIEW.md; **all uncommitted** | Grilling |
347
- | **Await Review** | edge-only, auto | REVIEW.md present and **uncommitted** (freshly written by Clean) | commit REVIEW.md `gtd: awaiting review` | Done (auto, same run) |
348
- | **New Feature** | edge-only, auto | boundary HEAD + pending changes (code and/or a new uncommitted TODO.md), **or** HEAD `gtd: new task` + clean tree (lost-seed regen) | commit the raw input verbatim `gtd: new task` (unless already there), `git revert --no-commit` it back to a clean baseline, seed TODO.md from that diff — revert + seed left **uncommitted** | Grilling |
349
- | **Grilling** | agent (iterate) / STOP (answers) | TODO.md present, not New Feature | commit pending edits `gtd: grilling`. Open-question markers present → STOP for the human to answer inline; no markers but dirty → grilling agent iterates | converge (no markers, clean tree) → Grilled |
350
- | **Grilled** | agent, auto | TODO.md present, no markers, clean tree | commit pending `gtd: grilled` | decompose into `.gtd/` → Planning |
351
- | **Clean** | agent | no steering files, clean tree, boundary or `gtd: package done` HEAD, and the review base yields a **non-empty** diff | compute the review base (three rules — see below); agent writes REVIEW.md **uncommitted** with `# Review: <short-hash>` heading, `<!-- base: <full-hash> -->` marker, and per-hunk `- [ ]` checkboxes (ticking them signals approval → Done) | Await Review |
352
- | **Health check** | edge-only, auto | no steering files, clean tree, outside a process with no reviewable diff (any branch) — the `!reviewable` case from rule 8 | run `testCommand`: green + no prior `gtd: health-fix` → Idle (no commit); red below `fixAttemptCap` → write HEALTH.md, commit `gtd: health-check` → Health Fixing; red at cap → write ERRORS.md, commit `gtd: health-check` → Escalate; green + ≥1 `gtd: health-fix` → Squashing (if `squash`) or Idle | green → Idle or Squashing; red below cap → Health Fixing; red at cap → Escalate |
353
- | **Idle** | STOP | no steering files, clean tree, health check passed with no prior `gtd: health-fix` commits, and nothing to review | none (no commit — the health check edge terminates the driver loop directly) | — |
336
+ | State | Kind | Wins when | Action & commit | Advances to |
337
+ | ------------------ | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
338
+ | **Transport** | edge-only, auto | HEAD `gtd: transport` (hand-made handoff commit) | mixed-reset HEAD (`git reset HEAD~1`), keep work in tree; **no commit** | re-derive from the restored tree |
339
+ | **Escalate** | STOP | ERRORS.md present | none | held until the human deletes ERRORS.md |
340
+ | **Fixing** | agent, auto | non-empty FEEDBACK.md present | inline FEEDBACK into the prompt, remove FEEDBACK.md; commit its removal `gtd: fixing` (FEEDBACK was committed by Testing) or `gtd: feedback` (uncommitted, written by Agentic Review) | fixer edits → Testing |
341
+ | **Health Fixing** | agent, auto | HEALTH.md present (no `.gtd`, REVIEW.md, or FEEDBACK.md) | read HEALTH.md into the prompt, commit its removal `gtd: health-check` (HEALTH.md removed so next resolve re-enters `resolveCleanOrIdle`); fixer leaves edits **uncommitted** | fixer edits uncommitted next `gtd` invocation commits them `gtd: health-fix` → Health check |
342
+ | **Close package** | edge-only, auto | empty FEEDBACK.md present (clean review); also reached from Agentic Review force-approve | rm FEEDBACK.md, rm the first (finished) package dir (+ the now-empty `.gtd/`); commit `gtd: package done` | more packages → Building; `.gtd` gone → Clean |
343
+ | **Planning** | agent, auto | `.gtd` present **and modified**; HEAD `gtd: grilled` or `gtd: planning` | commit the `.gtd/` changes `gtd: planning` | continue decomposing, else → Building |
344
+ | **Testing** | edge-only, auto | `.gtd` present, no FEEDBACK/ERRORS, and a reason to test: code changes, a pending ERRORS.md deletion (human resume), or a clean tree under HEAD `gtd: fixing` (no-op fixer) | commit pending tree `gtd: building`, run `testCommand`; green → proceed; red → write FEEDBACK (below cap) or ERRORS (at cap), commit `gtd: errors`; if captured output is empty/whitespace, a sentinel string is written so the file is never empty (empty FEEDBACK remains reserved for agentic-review approval) | green → Agentic Review; FEEDBACK → Fixing; ERRORS → Escalate |
345
+ | **Building** | agent, auto | `.gtd` present and clean, clean tree; HEAD `gtd: planning` or `gtd: package done` | if HEAD `gtd: planning` and TODO.md present, delete TODO.md and commit (prefix unchanged, fires once); select the first package, inline its tasks; agent leaves work **uncommitted** | Testing |
346
+ | **Agentic Review** | agent, auto | `.gtd` present and clean, clean tree; HEAD `gtd: building` | reviewer writes FEEDBACK.md (empty = approval), uncommitted — **unless** force-approved (kill-switch off or review-fix threshold hit), which routes straight to Close package | empty FEEDBACK → Close package; non-empty → Fixing |
347
+ | **Done** | edge-only, auto | REVIEW.md committed + clean tree, **or** committed + checkbox-only edits (only `- [ ]`→`- [x]` flips in REVIEW.md = approval) | rm REVIEW.md, commit `gtd: done` | Squashing (if enabled) or Idle |
348
+ | **Squashing** | agent, auto | no steering files, HEAD `gtd: done` or green Health check with ≥1 `gtd: health-fix`, `squash` enabled, squash base present, no unrelated code dirty (a lone untracked `SQUASH_MSG.md` is allowed) | agent authors a conventional-commits message from the full `<base>..HEAD` diff, then runs `git reset --soft <base>` + `git commit` — collapses all intermediate `gtd: *` commits (including any interleaved non-gtd commits) into one; **gtd then STOPs** — post-squash review fires only on the next manual `gtd` run | Idle (STOP) |
349
+ | **Accept Review** | edge-only, auto | REVIEW.md committed + pending **non-checkbox** edits (human annotated REVIEW.md with comments / edited code) | seed TODO.md from the changeset, `git checkout` to discard the code edits, rm REVIEW.md; **all uncommitted** | Grilling |
350
+ | **Await Review** | edge-only, auto | REVIEW.md present and **uncommitted** (freshly written by Clean) | commit REVIEW.md `gtd: awaiting review` | Done (auto, same run) |
351
+ | **New Feature** | edge-only, auto | boundary HEAD + pending changes (code and/or a new uncommitted TODO.md), **or** HEAD `gtd: new task` + clean tree (lost-seed regen) | commit the raw input verbatim `gtd: new task` (unless already there), `git revert --no-commit` it back to a clean baseline, seed TODO.md from that diff — revert + seed left **uncommitted** | Grilling |
352
+ | **Grilling** | agent (iterate) / STOP (answers) | TODO.md present, not New Feature | commit pending edits `gtd: grilling`. Open-question markers present → STOP for the human to answer inline; no markers but dirty → grilling agent iterates | converge (no markers, clean tree) → Grilled |
353
+ | **Grilled** | agent, auto | TODO.md present, no markers, clean tree | commit pending `gtd: grilled` | decompose into `.gtd/` → Planning |
354
+ | **Clean** | agent | no steering files, clean tree, boundary or `gtd: package done` HEAD, and the review base yields a **non-empty** diff | compute the review base (three rules — see below); agent writes REVIEW.md **uncommitted** with `# Review: <short-hash>` heading, `<!-- base: <full-hash> -->` marker, and per-hunk `- [ ]` checkboxes (ticking them signals approval → Done) | Await Review |
355
+ | **Health check** | edge-only, auto | no steering files, outside a process with no reviewable diff (any branch) — the `!reviewable` case from rule 8. Two entry points: (a) clean tree under a boundary or `gtd: package done` HEAD; (b) **dirty tree under a `gtd: health-check` or `gtd: health-fix` HEAD with `!pendingErrorsDeletion`** (the fixer's uncommitted edits — commits them `gtd: health-fix` and re-runs the health check within the same `gtd` invocation; NOT corruption). | run `testCommand` (entry point a); or commit pending edits `gtd: health-fix`, then run `testCommand` (entry point b). green + no prior `gtd: health-fix` → Idle (no commit); red below `fixAttemptCap` → write HEALTH.md, commit `gtd: health-check` → Health Fixing; red at cap → write ERRORS.md, commit `gtd: health-check` → Escalate; green + ≥1 `gtd: health-fix` → Squashing (if `squash`) or Idle | green → Idle or Squashing; red below cap → Health Fixing; red at cap → Escalate |
356
+ | **Idle** | STOP | no steering files, clean tree, health check passed with no prior `gtd: health-fix` commits, and nothing to review | none (no commit — the health check edge terminates the driver loop directly) | — |
354
357
 
355
358
  Every prompt also embeds the current `git diff HEAD` (untracked files included)
356
359
  inline, plus the last commit subject and working-tree status, so the agent has
@@ -420,17 +423,25 @@ files, `gtd` runs `testCommand` instead of stopping. This reuses `fixAttemptCap`
420
423
  (default 3) and `squash` — no new config keys are introduced.
421
424
 
422
425
  ```
423
- Idle path → Health check(red) → Health Fixing → Health check(red) → … → Health check(green)
424
-
425
- └── below cap: HEALTH.md, gtd: health-check ─────────────────┘
426
+ Idle path → Health check(red) → Health Fixing → [fixer edits, uncommitted]
427
+
428
+ │ next gtd run: commit gtd: health-fix
429
+ │ │
430
+ │ Health check(red) → …
431
+ │ │
432
+ │ Health check(green)
433
+ │ │
434
+ └── below cap: HEALTH.md, gtd: health-check └── green + ≥1 health-fix → Squashing (if squash enabled) → Idle
426
435
  └── at/over the cap: ERRORS.md, gtd: health-check → Escalate
427
- green + ≥1 health-fix → Squashing (if squash enabled) → Idle
428
436
  ```
429
437
 
430
438
  - **green, no prior `gtd: health-fix`** → Idle immediately (no commit).
431
439
  - **red, below `fixAttemptCap`** → write test output to HEALTH.md, commit
432
- `gtd: health-check` → **Health Fixing** agent fixes, commits removal as
433
- `gtd: health-fix`, loops back to Health check.
440
+ `gtd: health-check` → **Health Fixing** agent fixes the code and leaves its
441
+ edits **uncommitted**. The next `gtd` invocation detects the dirty tree under
442
+ the `gtd: health-check` HEAD, commits the fixer's edits as `gtd: health-fix`
443
+ (an edge-only `health-check` state with a `commitPending` action), and
444
+ immediately re-runs the health check within that same invocation.
434
445
  - **red, at or over `fixAttemptCap`** → write test output to ERRORS.md, commit
435
446
  `gtd: health-check` → **Escalate** (human gate). Delete ERRORS.md to reset the
436
447
  budget and resume.
@@ -739,6 +750,27 @@ When there are genuinely no open questions left, the agent writes the sentinel
739
750
  line `no open questions — run gtd to plan` and leaves **no** markers — a clean
740
751
  tree with no markers is what advances the plan to **Grilled** and decomposition.
741
752
 
753
+ ## CLI flags
754
+
755
+ ```
756
+ Usage: gtd [command] [options]
757
+
758
+ Commands:
759
+ (default) Run the gtd driver loop — detect state, emit next prompt
760
+ format <file> Format a markdown file in place
761
+ review <target> Ad-hoc human review against a git ref or branch
762
+
763
+ Options:
764
+ --json Output structured JSON instead of plain text
765
+ --verbose Show verbose output (thinking deltas, tool events)
766
+ --debug Show debug-level internal information
767
+ --version, -v Print version and exit
768
+ --help, -h Print this help and exit
769
+ ```
770
+
771
+ `--version` (`-v`) and `--help` (`-h`) short-circuit before any git or
772
+ repository-state work — they run outside a repo and in any repo state.
773
+
742
774
  ## Subcommands
743
775
 
744
776
  gtd ships two subcommands: `format` and `review`.