@pmelab/gtd 1.9.0 → 1.9.1
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.
- package/README.md +58 -29
- package/dist/gtd.bundle.mjs +35 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -241,8 +241,8 @@ flowchart TD
|
|
|
241
241
|
P2 -->|"empty = approval"| Close["Close package — rm pkg dir, gtd: package done"]:::edge
|
|
242
242
|
P2 -->|"non-empty"| Fixing["Fixing — rm FEEDBACK, fixer agent"]:::agent
|
|
243
243
|
P2 -->|absent| P2b{"HEALTH.md?"}
|
|
244
|
-
P2b -->|"present"| HealthFix["Health Fixing — rm HEALTH.md, gtd: health-
|
|
245
|
-
HealthFix -.->|"re-resolve"| HealthCheck
|
|
244
|
+
P2b -->|"present"| HealthFix["Health Fixing — rm HEALTH.md, gtd: health-check, fixer agent (leaves edits uncommitted)"]:::agent
|
|
245
|
+
HealthFix -.->|"next gtd run: dirty health HEAD → commit gtd: health-fix, re-resolve"| HealthCheck
|
|
246
246
|
P2b -->|absent| P3{".gtd/?"}
|
|
247
247
|
P3 -->|"modified"| Planning["Planning — gtd: planning"]:::agent
|
|
248
248
|
P3 -->|"code dirty / resume / no-op fixer"| Testing["Testing — gtd: building, run tests"]:::edge
|
|
@@ -330,27 +330,27 @@ Each state has a **condition** (when it wins), a deterministic **action**, the
|
|
|
330
330
|
human; **edge-only** states render no prompt at all — the driver performs their
|
|
331
331
|
action and re-resolves silently.
|
|
332
332
|
|
|
333
|
-
| State | Kind | Wins when
|
|
334
|
-
| ------------------ | -------------------------------- |
|
|
335
|
-
| **Transport** | edge-only, auto | HEAD `gtd: transport` (hand-made handoff commit)
|
|
336
|
-
| **Escalate** | STOP | ERRORS.md present
|
|
337
|
-
| **Fixing** | agent, auto | non-empty FEEDBACK.md present
|
|
338
|
-
| **Health Fixing** | agent, auto | HEALTH.md present (no `.gtd`, REVIEW.md, or FEEDBACK.md)
|
|
339
|
-
| **Close package** | edge-only, auto | empty FEEDBACK.md present (clean review); also reached from Agentic Review force-approve
|
|
340
|
-
| **Planning** | agent, auto | `.gtd` present **and modified**; HEAD `gtd: grilled` or `gtd: planning`
|
|
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)
|
|
342
|
-
| **Building** | agent, auto | `.gtd` present and clean, clean tree; HEAD `gtd: planning` or `gtd: package done`
|
|
343
|
-
| **Agentic Review** | agent, auto | `.gtd` present and clean, clean tree; HEAD `gtd: building`
|
|
344
|
-
| **Done** | edge-only, auto | REVIEW.md committed + clean tree, **or** committed + checkbox-only edits (only `- [ ]`→`- [x]` flips in REVIEW.md = approval)
|
|
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)
|
|
346
|
-
| **Accept Review** | edge-only, auto | REVIEW.md committed + pending **non-checkbox** edits (human annotated REVIEW.md with comments / edited code)
|
|
347
|
-
| **Await Review** | edge-only, auto | REVIEW.md present and **uncommitted** (freshly written by Clean)
|
|
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)
|
|
349
|
-
| **Grilling** | agent (iterate) / STOP (answers) | TODO.md present, not New Feature
|
|
350
|
-
| **Grilled** | agent, auto | TODO.md present, no markers, clean tree
|
|
351
|
-
| **Clean** | agent | no steering files, clean tree, boundary or `gtd: package done` HEAD, and the review base yields a **non-empty** diff
|
|
352
|
-
| **Health check** | edge-only, auto | no steering files,
|
|
353
|
-
| **Idle** | STOP | no steering files, clean tree, health check passed with no prior `gtd: health-fix` commits, and nothing to review
|
|
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-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 |
|
|
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, 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 |
|
|
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) | — |
|
|
354
354
|
|
|
355
355
|
Every prompt also embeds the current `git diff HEAD` (untracked files included)
|
|
356
356
|
inline, plus the last commit subject and working-tree status, so the agent has
|
|
@@ -420,17 +420,25 @@ files, `gtd` runs `testCommand` instead of stopping. This reuses `fixAttemptCap`
|
|
|
420
420
|
(default 3) and `squash` — no new config keys are introduced.
|
|
421
421
|
|
|
422
422
|
```
|
|
423
|
-
Idle path → Health check(red) → Health Fixing →
|
|
424
|
-
│
|
|
425
|
-
|
|
423
|
+
Idle path → Health check(red) → Health Fixing → [fixer edits, uncommitted]
|
|
424
|
+
│ │
|
|
425
|
+
│ next gtd run: commit gtd: health-fix
|
|
426
|
+
│ │
|
|
427
|
+
│ Health check(red) → …
|
|
428
|
+
│ │
|
|
429
|
+
│ Health check(green)
|
|
430
|
+
│ │
|
|
431
|
+
└── below cap: HEALTH.md, gtd: health-check └── green + ≥1 health-fix → Squashing (if squash enabled) → Idle
|
|
426
432
|
└── at/over the cap: ERRORS.md, gtd: health-check → Escalate
|
|
427
|
-
green + ≥1 health-fix → Squashing (if squash enabled) → Idle
|
|
428
433
|
```
|
|
429
434
|
|
|
430
435
|
- **green, no prior `gtd: health-fix`** → Idle immediately (no commit).
|
|
431
436
|
- **red, below `fixAttemptCap`** → write test output to HEALTH.md, commit
|
|
432
|
-
`gtd: health-check` → **Health Fixing** agent fixes
|
|
433
|
-
`gtd
|
|
437
|
+
`gtd: health-check` → **Health Fixing** agent fixes the code and leaves its
|
|
438
|
+
edits **uncommitted**. The next `gtd` invocation detects the dirty tree under
|
|
439
|
+
the `gtd: health-check` HEAD, commits the fixer's edits as `gtd: health-fix`
|
|
440
|
+
(an edge-only `health-check` state with a `commitPending` action), and
|
|
441
|
+
immediately re-runs the health check within that same invocation.
|
|
434
442
|
- **red, at or over `fixAttemptCap`** → write test output to ERRORS.md, commit
|
|
435
443
|
`gtd: health-check` → **Escalate** (human gate). Delete ERRORS.md to reset the
|
|
436
444
|
budget and resume.
|
|
@@ -739,6 +747,27 @@ When there are genuinely no open questions left, the agent writes the sentinel
|
|
|
739
747
|
line `no open questions — run gtd to plan` and leaves **no** markers — a clean
|
|
740
748
|
tree with no markers is what advances the plan to **Grilled** and decomposition.
|
|
741
749
|
|
|
750
|
+
## CLI flags
|
|
751
|
+
|
|
752
|
+
```
|
|
753
|
+
Usage: gtd [command] [options]
|
|
754
|
+
|
|
755
|
+
Commands:
|
|
756
|
+
(default) Run the gtd driver loop — detect state, emit next prompt
|
|
757
|
+
format <file> Format a markdown file in place
|
|
758
|
+
review <target> Ad-hoc human review against a git ref or branch
|
|
759
|
+
|
|
760
|
+
Options:
|
|
761
|
+
--json Output structured JSON instead of plain text
|
|
762
|
+
--verbose Show verbose output (thinking deltas, tool events)
|
|
763
|
+
--debug Show debug-level internal information
|
|
764
|
+
--version, -v Print version and exit
|
|
765
|
+
--help, -h Print this help and exit
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
`--version` (`-v`) and `--help` (`-h`) short-circuit before any git or
|
|
769
|
+
repository-state work — they run outside a repo and in any repo state.
|
|
770
|
+
|
|
742
771
|
## Subcommands
|
|
743
772
|
|
|
744
773
|
gtd ships two subcommands: `format` and `review`.
|
package/dist/gtd.bundle.mjs
CHANGED
|
@@ -367980,6 +367980,9 @@ var TestRunner = class _TestRunner extends Context_exports.Tag("TestRunner")() {
|
|
|
367980
367980
|
);
|
|
367981
367981
|
};
|
|
367982
367982
|
|
|
367983
|
+
// src/program.ts
|
|
367984
|
+
import { createRequire as createRequire2 } from "module";
|
|
367985
|
+
|
|
367983
367986
|
// src/Events.ts
|
|
367984
367987
|
import { join as join11 } from "path";
|
|
367985
367988
|
|
|
@@ -389107,6 +389110,14 @@ var resolveGrilling = (p4, counters, head7) => {
|
|
|
389107
389110
|
};
|
|
389108
389111
|
var resolveCleanOrIdle = (p4, counters, head7) => {
|
|
389109
389112
|
const isHealthHead = head7 === "gtd: health-check" || head7 === "gtd: health-fix";
|
|
389113
|
+
if (!p4.workingTreeClean && !p4.pendingErrorsDeletion && isHealthHead) {
|
|
389114
|
+
return {
|
|
389115
|
+
state: "health-check",
|
|
389116
|
+
autoAdvance: true,
|
|
389117
|
+
edgeAction: { kind: "commitPending", prefix: "gtd: health-fix" },
|
|
389118
|
+
context: buildContext(p4, counters)
|
|
389119
|
+
};
|
|
389120
|
+
}
|
|
389110
389121
|
if (!p4.workingTreeClean && !p4.pendingErrorsDeletion) return null;
|
|
389111
389122
|
if (!p4.workingTreeClean && p4.pendingErrorsDeletion && p4.gtdDirExists) return null;
|
|
389112
389123
|
if (!p4.workingTreeClean && p4.pendingErrorsDeletion && !isBoundary(head7) && head7 !== "gtd: package done" && !isHealthHead)
|
|
@@ -389244,6 +389255,22 @@ var detect = () => Effect_exports.gen(function* () {
|
|
|
389244
389255
|
});
|
|
389245
389256
|
|
|
389246
389257
|
// src/program.ts
|
|
389258
|
+
var _require = createRequire2(import.meta.url);
|
|
389259
|
+
var GTD_VERSION = _require("../package.json").version;
|
|
389260
|
+
var HELP_TEXT = `Usage: gtd [command] [options]
|
|
389261
|
+
|
|
389262
|
+
Commands:
|
|
389263
|
+
(default) Run the gtd driver loop \u2014 detect state, emit next prompt
|
|
389264
|
+
format <file> Format a markdown file in place
|
|
389265
|
+
review <target> Ad-hoc human review against a git ref or branch
|
|
389266
|
+
|
|
389267
|
+
Options:
|
|
389268
|
+
--json Output structured JSON instead of plain text
|
|
389269
|
+
--verbose Show verbose output (thinking deltas, tool events)
|
|
389270
|
+
--debug Show debug-level internal information
|
|
389271
|
+
--version, -v Print version and exit
|
|
389272
|
+
--help, -h Print this help and exit
|
|
389273
|
+
`;
|
|
389247
389274
|
var IDLE_RESULT = {
|
|
389248
389275
|
state: "idle",
|
|
389249
389276
|
autoAdvance: false,
|
|
@@ -389264,6 +389291,14 @@ function makeProgram(opts = {}) {
|
|
|
389264
389291
|
const json2 = argv.includes("--json");
|
|
389265
389292
|
const positional = argv.slice(2).find((a5) => !a5.startsWith("--"));
|
|
389266
389293
|
return Effect_exports.gen(function* () {
|
|
389294
|
+
if (argv.includes("--version") || argv.includes("-v")) {
|
|
389295
|
+
write4(GTD_VERSION + "\n");
|
|
389296
|
+
return;
|
|
389297
|
+
}
|
|
389298
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
389299
|
+
write4(HELP_TEXT);
|
|
389300
|
+
return;
|
|
389301
|
+
}
|
|
389267
389302
|
const sub = positional;
|
|
389268
389303
|
if (sub === "format") {
|
|
389269
389304
|
if (json2) {
|