@pmelab/gtd 9.0.0 → 9.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.
- package/README.md +49 -27
- package/dist/gtd.bundle.mjs +15 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,25 +79,27 @@ carrying one piece of content (a script, a prompt, a message, or a squash commit
|
|
|
79
79
|
template), with an ordered set of change-patterns routing to the next state.
|
|
80
80
|
|
|
81
81
|
The loop is one beat, repeated: run `gtd next --json` and dispatch on `kind` —
|
|
82
|
-
`"message"` means it's a human's move (stop and hand off
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
`
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
82
|
+
`"message"` means it's a human's move (stop and hand off, unless it's the run's
|
|
83
|
+
opening beat, which the human triggered by re-running the driver: land that one,
|
|
84
|
+
since changing nothing is itself a declared outcome at some gates); `"capture"`
|
|
85
|
+
means a human gate the human already acted on (land it immediately); `"script"`
|
|
86
|
+
means the driver runs `content` itself, then lands it; `"prompt"` means feed
|
|
87
|
+
`content` to your agent — using the accompanying `session.id`/`session.resume`
|
|
88
|
+
to continue or start that agent conversation (see "Driving the loop" below) —
|
|
89
|
+
then run `gtd land` once it's done. gtd itself never executes anything — the
|
|
90
|
+
driver owns running scripts. Every `gtd next` call is strictly mutation-free,
|
|
91
|
+
safe to poll or peek at any time: `session.id`/`session.resume` are DERIVED,
|
|
92
|
+
never stored, so looking is free — nothing distinguishes a peek from a dispatch,
|
|
93
|
+
and there is no separate claiming form at all. A `prompt` beat whose turn
|
|
94
|
+
changes nothing still lands: `gtd land` commits an EMPTY `gtd(<actor>): <state>`
|
|
95
|
+
attempt instead of silently doing nothing, so the fruitless dispatch is visible
|
|
96
|
+
in history rather than invisible. `"kind": "stalled"` is derived from that
|
|
97
|
+
history — HEAD is an empty attempt at the resting state and the tree is clean —
|
|
98
|
+
so every `gtd next --json` call reports it, and it stays reported on a repeat
|
|
99
|
+
(there's no marker to consume) until something actually changes. The fix for a
|
|
100
|
+
repeated stall is either a better prompt, a `retry:` cap on the state that
|
|
101
|
+
redirects to an escalation state after N fruitless attempts, or — if the state
|
|
102
|
+
can legitimately finish with nothing to change — declaring a `C` (clean-tree)
|
|
101
103
|
pattern on it.
|
|
102
104
|
|
|
103
105
|
An `on` edge may also carry a short imperative `action` (e.g. `Accept plan`)
|
|
@@ -367,8 +369,19 @@ autonomous states (agent turns, check runs) and stops at the first
|
|
|
367
369
|
non-autonomous one: reaching a human gate it prints the gate's message and
|
|
368
370
|
exits. You act by editing files (answer a plan question, tick a review box, fix
|
|
369
371
|
code) and re-running it — your pending edit arrives as the loop's first beat
|
|
370
|
-
(`kind: "capture"`, landed immediately), so you never run `gtd land` by hand
|
|
371
|
-
|
|
372
|
+
(`kind: "capture"`, landed immediately), so you never run `gtd land` by hand.
|
|
373
|
+
|
|
374
|
+
Some gates accept by INACTION instead: the bundled template's `plan.await-plan`
|
|
375
|
+
routes its `"C"` (clean-tree) pattern onward, so changing nothing there means
|
|
376
|
+
"accept the plan". That reaches the driver as `kind: "message"`, which no
|
|
377
|
+
inspection can tell apart from a gate you have not read yet — so the driver
|
|
378
|
+
treats its OPENING beat as yours either way and lands it: you re-ran it while
|
|
379
|
+
resting there, and that invocation IS the decision. Every later beat halts as
|
|
380
|
+
usual, because a gate the driver produced mid-run is one you have not seen.
|
|
381
|
+
Landing an opening beat at a gate with no `"C"` pattern is harmless — a benign
|
|
382
|
+
no-op (see `gtd land`'s exit codes below) — and the gate then prints on the next
|
|
383
|
+
beat. A mid-process restart simply resumes driving from whatever beat is
|
|
384
|
+
actually next.
|
|
372
385
|
|
|
373
386
|
Anything richer at that boundary — opening your editor, desktop notifications,
|
|
374
387
|
terminal-multiplexer status — is the job of an outer wrapper around the driver,
|
|
@@ -642,13 +655,17 @@ gtd_land() {
|
|
|
642
655
|
return 0
|
|
643
656
|
}
|
|
644
657
|
|
|
658
|
+
beat=1
|
|
645
659
|
while :; do
|
|
646
660
|
next="$(gtd next --json)" || exit 1
|
|
647
661
|
kind="$(jq -r .kind <<<"$next")"
|
|
648
662
|
log="$(jq -r .log <<<"$next")"
|
|
649
663
|
case "$kind" in
|
|
650
664
|
stalled) jq -r .content <<<"$next" >&2; exit 1 ;;
|
|
651
|
-
|
|
665
|
+
# you re-ran us resting here: you either edited something or accepted by
|
|
666
|
+
# editing nothing, so land the opening beat either way. Later beats are
|
|
667
|
+
# gates we just produced and you have not read yet — hand off.
|
|
668
|
+
message) [ "$beat" = 1 ] || { jq -r .content <<<"$next"; exit 0; } ;;
|
|
652
669
|
capture) ;; # the human already acted — just land it
|
|
653
670
|
script) bash -c "$(jq -r .content <<<"$next")" >>"$log" 2>&1 || true ;;
|
|
654
671
|
prompt)
|
|
@@ -668,6 +685,7 @@ while :; do
|
|
|
668
685
|
done ;;
|
|
669
686
|
esac
|
|
670
687
|
gtd_land || exit 1
|
|
688
|
+
beat=$((beat + 1))
|
|
671
689
|
done
|
|
672
690
|
```
|
|
673
691
|
|
|
@@ -675,11 +693,15 @@ Line by line it is the protocol described above: no opening move at all — a
|
|
|
675
693
|
human's pending edit arrives as the `capture` beat, and a stray `gtd land`
|
|
676
694
|
outside a beat you acted on would author an empty attempt at a clean prompt rest
|
|
677
695
|
on purpose; one `gtd next --json` beat document read per loop (`kind: "stalled"`
|
|
678
|
-
guarding against a spinning agent); `message` halts
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
696
|
+
guarding against a spinning agent); `message` halts unless it is the opening
|
|
697
|
+
beat, which the human's own re-invocation authored and which therefore lands
|
|
698
|
+
like any other decision (see [Driving the loop](#driving-the-loop) above — this
|
|
699
|
+
is the one place the driver, not gtd, decides, because "has the human read this
|
|
700
|
+
gate" is run-scoped knowledge gtd deliberately does not keep); `capture` lands a
|
|
701
|
+
human's already-made edit outright, `script` runs in the driver, `prompt` goes
|
|
702
|
+
to the agent with the document's own `session.id`/`session.resume` mapped onto
|
|
703
|
+
the agent's session flags — trying `resume`'s hinted flag first and falling back
|
|
704
|
+
to the other on failure, since `session.id` is derived, not remembered (see
|
|
683
705
|
[Driving the loop](#driving-the-loop) above) — and its embedded `.validate`
|
|
684
706
|
script's output re-prompted verbatim on failure (the driver owns only the retry
|
|
685
707
|
cap); and every landed turn executed — and reported — by the emitted scripts
|
package/dist/gtd.bundle.mjs
CHANGED
|
@@ -207175,13 +207175,17 @@ gtd_land() {
|
|
|
207175
207175
|
return 0
|
|
207176
207176
|
}
|
|
207177
207177
|
|
|
207178
|
+
beat=1
|
|
207178
207179
|
while :; do
|
|
207179
207180
|
next="$(gtd next --json)" || exit 1
|
|
207180
207181
|
kind="$(jq -r .kind <<<"$next")"
|
|
207181
207182
|
log="$(jq -r .log <<<"$next")"
|
|
207182
207183
|
case "$kind" in
|
|
207183
207184
|
stalled) jq -r .content <<<"$next" >&2; exit 1 ;;
|
|
207184
|
-
|
|
207185
|
+
# you re-ran us resting here: you either edited something or accepted by
|
|
207186
|
+
# editing nothing, so land the opening beat either way. Later beats are
|
|
207187
|
+
# gates we just produced and you have not read yet — hand off.
|
|
207188
|
+
message) [ "$beat" = 1 ] || { jq -r .content <<<"$next"; exit 0; } ;;
|
|
207185
207189
|
capture) ;; # the human already acted — just land it
|
|
207186
207190
|
script) bash -c "$(jq -r .content <<<"$next")" >>"$log" 2>&1 || true ;;
|
|
207187
207191
|
prompt)
|
|
@@ -207201,6 +207205,7 @@ while :; do
|
|
|
207201
207205
|
done ;;
|
|
207202
207206
|
esac
|
|
207203
207207
|
gtd_land || exit 1
|
|
207208
|
+
beat=$((beat + 1))
|
|
207204
207209
|
done`;
|
|
207205
207210
|
const HEADER = () => `gtd ${GTD_VERSION$1} — driver protocol\n\ngtd decides and prints; the driver executes. gtd never runs git, never runs\nyour agent, and never runs a check script. The one subprocess gtd ever spawns\nitself is a steering mode's own format:/validate: command, during a\nland-capture guard.\n`;
|
|
207206
207211
|
const BEAT_PROTOCOL = `
|
|
@@ -207222,7 +207227,12 @@ The \`kind\` field selects what to do:
|
|
|
207222
207227
|
|
|
207223
207228
|
- \`stalled\` — print \`.content\` (a diagnosis) to stderr and exit non-zero.
|
|
207224
207229
|
Terminal: another dispatch would just repeat the same fruitless turn.
|
|
207225
|
-
- \`message\` — print \`.content\` and exit 0. This is a human gate.
|
|
207230
|
+
- \`message\` — print \`.content\` and exit 0. This is a human gate. EXCEPT on
|
|
207231
|
+
the run's opening beat: the human invoked you while resting there, so land
|
|
207232
|
+
it instead of printing. Some gates route a \`"C"\` (clean-tree) pattern
|
|
207233
|
+
onward, making "change nothing" a real decision that looks identical to a
|
|
207234
|
+
gate nobody has read yet; landing an opening beat at a gate without one is
|
|
207235
|
+
a benign no-op, and it prints on the next beat.
|
|
207226
207236
|
- \`capture\` — a human gate the human already acted on (the tree is dirty).
|
|
207227
207237
|
Land it immediately, no display needed.
|
|
207228
207238
|
- \`script\` — run \`bash -c .content\`, appending its output to \`.log\`, and
|
|
@@ -207289,7 +207299,9 @@ const DRIVER_OBLIGATIONS = `
|
|
|
207289
207299
|
no opening move: a human's pending edit arrives as a \`kind: "capture"\`
|
|
207290
207300
|
beat, which you land immediately without executing anything.
|
|
207291
207301
|
2. A \`kind: "stalled"\` beat halts the driver with a non-zero exit; a
|
|
207292
|
-
\`kind: "message"\` beat prints \`content\` and exits 0
|
|
207302
|
+
\`kind: "message"\` beat prints \`content\` and exits 0, unless it is the
|
|
207303
|
+
run's opening beat — land that one, since the human's re-invocation while
|
|
207304
|
+
resting there is itself their decision.
|
|
207293
207305
|
3. Run scripts with their output appended to \`.log\` — gtd never creates or
|
|
207294
207306
|
truncates that file itself; truncate it once per run. \`$GTD_LOOP_LOG\`
|
|
207295
207307
|
overrides its path.
|