@pmelab/gtd 2.2.0 → 2.3.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 +114 -71
- package/dist/gtd.bundle.mjs +183 -37
- package/package.json +1 -1
- package/schema.json +3 -0
package/README.md
CHANGED
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
A git-aware CLI that drives a turn-taking loop between a human and an autonomous
|
|
8
8
|
coding agent: capture an idea, grill it into a plan, decompose it into work
|
|
9
9
|
packages, execute with parallel subagents, test, agentically review each
|
|
10
|
-
package,
|
|
11
|
-
into
|
|
10
|
+
package, walk a human through a review, distill durable lessons from the cycle
|
|
11
|
+
into the project's own docs, and finally squash the whole cycle into one
|
|
12
|
+
conventional-commits commit at the end.
|
|
12
13
|
|
|
13
14
|
Internally, gtd is a **pure fold** over git history. The decision core
|
|
14
15
|
(`src/Machine.ts`) is a single IO-free function, `resolve(events)` — **no
|
|
@@ -18,7 +19,7 @@ merge-base with the default branch (whole-history fallback when there is no
|
|
|
18
19
|
default branch, when HEAD equals the merge-base, or when there is no merge-base)
|
|
19
20
|
plus the working tree, turns them into a `COMMIT[]` + single terminal `RESOLVE`
|
|
20
21
|
event stream, and folds them through the machine. The fold lands on exactly
|
|
21
|
-
**one** of
|
|
22
|
+
**one** of 20 states, plus which actor (human or agent) is awaited there. A
|
|
22
23
|
single call resolves to a single state.
|
|
23
24
|
|
|
24
25
|
Steering is entirely **machine-authored commit subjects** — there are no marker
|
|
@@ -29,12 +30,12 @@ the machine performs itself between turns) looks like `gtd: tests green`.
|
|
|
29
30
|
|
|
30
31
|
All workflow state lives under **`.gtd/`**: the plan (`.gtd/TODO.md`), work
|
|
31
32
|
packages (`.gtd/01-…/`), review records (`.gtd/REVIEW.md`, `.gtd/FEEDBACK.md`),
|
|
32
|
-
and loop bookkeeping (`.gtd/ERRORS.md`, `.gtd/HEALTH.md`, `.gtd/
|
|
33
|
-
One rule follows for every agent in the loop: **never
|
|
34
|
-
single file a prompt explicitly grants. A `TODO.md`
|
|
35
|
-
repository root is the project's own file — gtd never
|
|
36
|
-
deletes it. (Corollary: don't gitignore `.gtd/` — the
|
|
37
|
-
through it.)
|
|
33
|
+
and loop bookkeeping (`.gtd/ERRORS.md`, `.gtd/HEALTH.md`, `.gtd/LEARNINGS.md`,
|
|
34
|
+
`.gtd/SQUASH_MSG.md`). One rule follows for every agent in the loop: **never
|
|
35
|
+
touch `.gtd/`** except the single file a prompt explicitly grants. A `TODO.md`
|
|
36
|
+
or `REVIEW.md` at the repository root is the project's own file — gtd never
|
|
37
|
+
reads, consumes, or deletes it. (Corollary: don't gitignore `.gtd/` — the
|
|
38
|
+
workflow commits its state through it.)
|
|
38
39
|
|
|
39
40
|
## Quick start: the two-beat loop
|
|
40
41
|
|
|
@@ -428,12 +429,14 @@ GTD_LOOP_AGENT_CMD='my-agent-cli --prompt "$GTD_LOOP_PROMPT"' gtd-loop
|
|
|
428
429
|
|
|
429
430
|
## States & subjects overview
|
|
430
431
|
|
|
431
|
-
`resolve()` lands on exactly one of **
|
|
432
|
+
`resolve()` lands on exactly one of **20 states**: `grilling`, `grilled`,
|
|
432
433
|
`planning`, `building`, `testing`, `fixing`, `escalate`, `agentic-review`,
|
|
433
|
-
`close-package`, `review`, `await-review`, `done`, `
|
|
434
|
-
`
|
|
435
|
-
`
|
|
436
|
-
|
|
434
|
+
`close-package`, `review`, `await-review`, `done`, `learning`,
|
|
435
|
+
`await-learning-review`, `learning-apply`, `learning-applied`, `squashing`,
|
|
436
|
+
`idle`, `health-check`, `health-fixing`. Each state has a fixed awaited actor
|
|
437
|
+
(see `awaitedActor` in `src/Machine.ts`): `idle`, `escalate`, `await-review`,
|
|
438
|
+
and `await-learning-review` await the **human**; every other state awaits the
|
|
439
|
+
**agent**.
|
|
437
440
|
|
|
438
441
|
For the full precedence ladder, illegal combinations, and the counter folds that
|
|
439
442
|
drive the fix loops, see [STATES.md](STATES.md) — this section is a summary.
|
|
@@ -452,6 +455,8 @@ The closed set of gates:
|
|
|
452
455
|
| `agentic-review` | agent (writes .gtd/FEEDBACK.md verdict) |
|
|
453
456
|
| `review` | agent (writes .gtd/REVIEW.md) / human (approves or gives feedback) |
|
|
454
457
|
| `squashing` | agent (overwrites .gtd/SQUASH_MSG.md) |
|
|
458
|
+
| `learning` | agent (overwrites .gtd/LEARNINGS.md) / human (accepts or edits) |
|
|
459
|
+
| `learning-apply` | agent (integrates .gtd/LEARNINGS.md into CLAUDE.md/AGENTS.md/docs) |
|
|
455
460
|
| `health-fixing` | agent (idle health-check repair) |
|
|
456
461
|
| `escalate` | human (deletes .gtd/ERRORS.md to resume) |
|
|
457
462
|
|
|
@@ -462,7 +467,8 @@ agent "wins": `gtd: grilled`, `gtd: planning`, `gtd: tests green`,
|
|
|
462
467
|
`gtd: errors`, `gtd: package done`, `gtd: awaiting review`,
|
|
463
468
|
`gtd: review feedback`, `gtd: done`, `gtd: squash template`,
|
|
464
469
|
`gtd: reviewing <hash>` (parameterized, from `gtd review`), `gtd: health-check`,
|
|
465
|
-
`gtd: health-fix
|
|
470
|
+
`gtd: health-fix`, `gtd: learning template`, `gtd: learning drafted`,
|
|
471
|
+
`gtd: learning approved`, `gtd: learning applied`.
|
|
466
472
|
|
|
467
473
|
Everything else — any non-`gtd` subject, and any `gtd: *` subject outside this
|
|
468
474
|
closed set — is a **boundary commit**: inert as far as the machine's grammar is
|
|
@@ -526,23 +532,25 @@ the threshold simply closes the package as usual.) Setting
|
|
|
526
532
|
|
|
527
533
|
A **do-nothing agent invocation** — `gtd step-agent` on a clean tree at ANY
|
|
528
534
|
agent-awaited rest whose move is a file artifact (`grilling`, `grilled`,
|
|
529
|
-
`building`, `fixing`, `agentic-review`, `review`,
|
|
530
|
-
`.gtd/SQUASH_MSG.md` still holds the unmodified template
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
535
|
+
`building`, `fixing`, `agentic-review`, `review`, `squashing` while
|
|
536
|
+
`.gtd/SQUASH_MSG.md` still holds the unmodified template, `learning` while
|
|
537
|
+
`.gtd/LEARNINGS.md` still holds the unmodified template, and `learning-apply`
|
|
538
|
+
unconditionally) — is inert: zero commits, no state consumed; `gtd next`
|
|
539
|
+
re-emits the same prompt. This is load-bearing for the loop protocol, whose
|
|
540
|
+
every iteration opens with `gtd step-agent` before the agent has acted: without
|
|
541
|
+
the guard that opening beat would author junk empty turns — and worse, consume
|
|
542
|
+
workflow state (an empty decompose turn would delete `.gtd/TODO.md` with no
|
|
543
|
+
packages written; an empty squashing turn would squash the cycle under the
|
|
544
|
+
placeholder template). The same guards hold at the classification layer for
|
|
545
|
+
histories that already carry such turns: a `gtd(agent): grilled` HEAD only
|
|
546
|
+
routes to `gtd: planning` when packages exist, a `gtd(agent): review` HEAD only
|
|
547
|
+
routes to `gtd: awaiting review` when `.gtd/REVIEW.md` exists, and a squashing
|
|
548
|
+
(or learning) turn only proceeds once its template has been overwritten. The one
|
|
549
|
+
deliberate exception is `health-fixing`, whose empty turn is meaningful (the
|
|
550
|
+
failure may have been environmental — the machine removes `.gtd/HEALTH.md` and
|
|
551
|
+
re-tests). Human gates are unaffected: an empty **human** turn stays a signal
|
|
552
|
+
(accept-defaults at grilling, clean approval at review, accept-the-draft-as-is
|
|
553
|
+
at the learning review gate).
|
|
546
554
|
|
|
547
555
|
### Human review gate
|
|
548
556
|
|
|
@@ -586,22 +594,46 @@ their commit message is discarded; linked `git worktree` checkouts are
|
|
|
586
594
|
unsupported. If you switch branches mid-review, gtd refuses to touch the foreign
|
|
587
595
|
branch and prints the manual recovery command.
|
|
588
596
|
|
|
597
|
+
### Learning
|
|
598
|
+
|
|
599
|
+
With `learning: true` (the default), `gtd: done` (or the health-fix path's green
|
|
600
|
+
re-test) is **not** a rest — the chain continues straight to
|
|
601
|
+
`gtd: learning template`, writing and committing a `.gtd/LEARNINGS.md` template,
|
|
602
|
+
running _before_ the squash decision so it still sees the pre-squash history.
|
|
603
|
+
`gtd next` then emits the learning prompt: the agent walks the cycle's test
|
|
604
|
+
failures, review feedback, and health-check rounds, keeps only
|
|
605
|
+
durable/generalizable lessons, and overwrites `.gtd/LEARNINGS.md` with them.
|
|
606
|
+
Once `gtd step-agent` captures that draft (`gtd(agent): learning`), it rests at
|
|
607
|
+
**await-learning-review** for a human — who either accepts the draft as-is (an
|
|
608
|
+
empty turn) or edits it; there is no reject path, so the very next `gtd step`
|
|
609
|
+
always proceeds (`gtd(human): learning` → `gtd: learning approved`), resting at
|
|
610
|
+
**learning-apply** for the agent. The agent integrates the approved learnings
|
|
611
|
+
into the project's own docs (`CLAUDE.md`/`AGENTS.md`/wherever fits, its
|
|
612
|
+
judgment); its turn (`gtd(agent): learning-apply`) removes `.gtd/LEARNINGS.md`
|
|
613
|
+
and lands at `gtd: learning applied`, which then runs the same squash decision
|
|
614
|
+
`gtd: done` runs today. With `learning: false`, `gtd: done` behaves exactly as
|
|
615
|
+
it does without this section: no `.gtd/LEARNINGS.md` is ever written. Learning
|
|
616
|
+
and squash are independent flags — either can be on without the other.
|
|
617
|
+
|
|
589
618
|
### Squash
|
|
590
619
|
|
|
591
|
-
With `squash: true` (the default), `gtd: done`
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
the
|
|
603
|
-
|
|
604
|
-
|
|
620
|
+
With `squash: true` (the default), `gtd: done` (or, once learning has run,
|
|
621
|
+
`gtd: learning applied`) is **not** a rest — the same chain continues straight
|
|
622
|
+
to `gtd: squash template`, writing and committing a `.gtd/SQUASH_MSG.md`
|
|
623
|
+
template. `gtd next` then emits the squashing prompt: the agent overwrites
|
|
624
|
+
`.gtd/SQUASH_MSG.md` with a real conventional-commits message (drawing on
|
|
625
|
+
grilling-round decisions from history) and finishes its turn. `gtd step-agent`
|
|
626
|
+
then performs the squash itself: `git reset --soft <base>` + `git commit`,
|
|
627
|
+
collapsing every intermediate `gtd: *` commit of the cycle into one — including
|
|
628
|
+
any review-feedback detours, and the learning phase's own commits if learning
|
|
629
|
+
ran: the squash base is the cycle's ORIGINAL start (the first grilling run since
|
|
630
|
+
the previous `gtd: done` boundary, or the `gtd: reviewing <hash>` anchor for an
|
|
631
|
+
ad-hoc review cycle), not the most recent re-grilling round — the collapse folds
|
|
632
|
+
the whole cycle into one, using the overwritten message's content verbatim (turn
|
|
633
|
+
position, not message content, triggers the squash). Doc edits made during
|
|
634
|
+
`learning-apply` survive in the squashed tree, not as their own commit. With
|
|
635
|
+
`squash: false`, `gtd: done` (or `gtd: learning applied`) is the resting
|
|
636
|
+
boundary and no template is ever written.
|
|
605
637
|
|
|
606
638
|
### Health check
|
|
607
639
|
|
|
@@ -610,9 +642,9 @@ runs `testCommand` as a health check rather than settling immediately. Green
|
|
|
610
642
|
settles idle with zero commits. Red below `fixAttemptCap` writes
|
|
611
643
|
`.gtd/HEALTH.md` and rests at **Health Fixing** for the agent; the fixer's own
|
|
612
644
|
turn (`gtd(agent): health-fixing`) removes `.gtd/HEALTH.md` and re-tests in the
|
|
613
|
-
same chain — a green re-test continues to
|
|
614
|
-
repeats the health-fix loop; red at the cap writes
|
|
615
|
-
escalates.
|
|
645
|
+
same chain — a green re-test continues to learning (if enabled), then squash (if
|
|
646
|
+
enabled), or idle; red repeats the health-fix loop; red at the cap writes
|
|
647
|
+
`.gtd/ERRORS.md` and escalates.
|
|
616
648
|
|
|
617
649
|
### Escalate / budget reset
|
|
618
650
|
|
|
@@ -624,24 +656,28 @@ fix-attempt budget to zero.
|
|
|
624
656
|
|
|
625
657
|
## States & subjects: overview table
|
|
626
658
|
|
|
627
|
-
| State
|
|
628
|
-
|
|
|
629
|
-
| `grilling`
|
|
630
|
-
| `grilled`
|
|
631
|
-
| `planning`
|
|
632
|
-
| `building`
|
|
633
|
-
| `testing`
|
|
634
|
-
| `fixing`
|
|
635
|
-
| `escalate`
|
|
636
|
-
| `agentic-review`
|
|
637
|
-
| `close-package`
|
|
638
|
-
| `review`
|
|
639
|
-
| `await-review`
|
|
640
|
-
| `done`
|
|
641
|
-
| `
|
|
642
|
-
| `
|
|
643
|
-
| `
|
|
644
|
-
| `
|
|
659
|
+
| State | Awaits | Turn/routing subject at rest |
|
|
660
|
+
| ----------------------- | -------------- | ---------------------------------------------------------------- |
|
|
661
|
+
| `grilling` | human or agent | `gtd(human): grilling` / `gtd(agent): grilling` |
|
|
662
|
+
| `grilled` | agent | `gtd: grilled` |
|
|
663
|
+
| `planning` | agent | `.gtd/` modified |
|
|
664
|
+
| `building` | agent | `gtd: planning` / `gtd: package done` |
|
|
665
|
+
| `testing` | — (edge-only) | mid-chain only |
|
|
666
|
+
| `fixing` | agent | `gtd: errors` |
|
|
667
|
+
| `escalate` | human | `.gtd/ERRORS.md` present |
|
|
668
|
+
| `agentic-review` | agent | `gtd: tests green` |
|
|
669
|
+
| `close-package` | — (edge-only) | mid-chain only |
|
|
670
|
+
| `review` | agent | `gtd: package done` (no more packages) / `gtd: reviewing <hash>` |
|
|
671
|
+
| `await-review` | human | `gtd: awaiting review` |
|
|
672
|
+
| `done` | — (edge-only) | `gtd: done` |
|
|
673
|
+
| `learning` | agent | `gtd: learning template` |
|
|
674
|
+
| `await-learning-review` | human | `gtd: learning drafted` |
|
|
675
|
+
| `learning-apply` | agent | `gtd: learning approved` |
|
|
676
|
+
| `learning-applied` | — (edge-only) | `gtd: learning applied` |
|
|
677
|
+
| `squashing` | agent | `gtd: squash template` |
|
|
678
|
+
| `idle` | human | no steering files, green health check |
|
|
679
|
+
| `health-check` | — (edge-only) | mid-chain only |
|
|
680
|
+
| `health-fixing` | agent | `.gtd/HEALTH.md` present |
|
|
645
681
|
|
|
646
682
|
See [STATES.md](STATES.md) for the full precedence ladder, the counter folds,
|
|
647
683
|
and every illegal steering-file combination.
|
|
@@ -674,13 +710,19 @@ built-in defaults apply. Supported filenames (searched in this order):
|
|
|
674
710
|
- **`agenticReview`** (boolean, default `true`) — kill-switch for the
|
|
675
711
|
per-package Agentic Review gate. Set `false` to force-approve every package
|
|
676
712
|
and proceed directly to human review.
|
|
677
|
-
- **`squash`** (boolean, default `true`) — after `gtd: done
|
|
678
|
-
cycle's `gtd: *` commits into
|
|
679
|
-
`false` to keep the granular
|
|
713
|
+
- **`squash`** (boolean, default `true`) — after `gtd: done` (or, once learning
|
|
714
|
+
has run, `gtd: learning applied`), collapse the cycle's `gtd: *` commits into
|
|
715
|
+
a single conventional-commits commit. Set `false` to keep the granular
|
|
716
|
+
history.
|
|
717
|
+
- **`learning`** (boolean, default `true`) — after `gtd: done` (or the
|
|
718
|
+
health-fix path's green re-test), distill durable lessons from the cycle into
|
|
719
|
+
`.gtd/LEARNINGS.md`, have a human review them, then integrate them into the
|
|
720
|
+
project's own docs before the squash decision runs. Set `false` to skip the
|
|
721
|
+
phase entirely — independent of `squash`.
|
|
680
722
|
- **`models`** — model selection for the subagent-spawning states:
|
|
681
723
|
- `planning` — high-reasoning tier (default `claude-opus-4-8`), used by
|
|
682
724
|
`decompose` (the `grilled`/`planning` states), `grilling`, `agentic-review`,
|
|
683
|
-
and `clean` (the `review`/`squashing` states).
|
|
725
|
+
and `clean` (the `review`/`squashing`/`learning`/`learning-apply` states).
|
|
684
726
|
- `execution` — everyday tier (default `claude-sonnet-4-8`), used by
|
|
685
727
|
`building` and `fixing`.
|
|
686
728
|
- `states.*` — per-state overrides keyed by `decompose`, `grilling`,
|
|
@@ -739,6 +781,7 @@ fixAttemptCap: 3
|
|
|
739
781
|
reviewThreshold: 3
|
|
740
782
|
agenticReview: true
|
|
741
783
|
squash: true
|
|
784
|
+
learning: true
|
|
742
785
|
models:
|
|
743
786
|
planning: claude-opus-4-8
|
|
744
787
|
execution: claude-sonnet-4-8
|
package/dist/gtd.bundle.mjs
CHANGED
|
@@ -367051,6 +367051,7 @@ var builtinTierDefault = {
|
|
|
367051
367051
|
var DEFAULT_TEST_COMMAND = "npm run test";
|
|
367052
367052
|
var DEFAULT_AGENTIC_REVIEW = true;
|
|
367053
367053
|
var DEFAULT_SQUASH = true;
|
|
367054
|
+
var DEFAULT_LEARNING = true;
|
|
367054
367055
|
var DEFAULT_FIX_ATTEMPT_CAP = 3;
|
|
367055
367056
|
var DEFAULT_REVIEW_THRESHOLD = 3;
|
|
367056
367057
|
var ModelStatesSchema = Schema_exports.Struct({
|
|
@@ -367071,6 +367072,7 @@ var ConfigSchema = Schema_exports.Struct({
|
|
|
367071
367072
|
models: Schema_exports.optional(ModelsSchema),
|
|
367072
367073
|
agenticReview: Schema_exports.optional(Schema_exports.Boolean),
|
|
367073
367074
|
squash: Schema_exports.optional(Schema_exports.Boolean),
|
|
367075
|
+
learning: Schema_exports.optional(Schema_exports.Boolean),
|
|
367074
367076
|
fixAttemptCap: Schema_exports.optional(Schema_exports.Int.pipe(Schema_exports.greaterThanOrEqualTo(0))),
|
|
367075
367077
|
reviewThreshold: Schema_exports.optional(Schema_exports.Int.pipe(Schema_exports.greaterThanOrEqualTo(1)))
|
|
367076
367078
|
});
|
|
@@ -367202,6 +367204,7 @@ var toOperations = (decoded) => {
|
|
|
367202
367204
|
resolveModel,
|
|
367203
367205
|
agenticReview: decoded.agenticReview ?? DEFAULT_AGENTIC_REVIEW,
|
|
367204
367206
|
squash: decoded.squash ?? DEFAULT_SQUASH,
|
|
367207
|
+
learning: decoded.learning ?? DEFAULT_LEARNING,
|
|
367205
367208
|
fixAttemptCap: decoded.fixAttemptCap ?? DEFAULT_FIX_ATTEMPT_CAP,
|
|
367206
367209
|
reviewThreshold: decoded.reviewThreshold ?? DEFAULT_REVIEW_THRESHOLD
|
|
367207
367210
|
};
|
|
@@ -387765,7 +387768,11 @@ var ROUTING_SUBJECT = {
|
|
|
387765
387768
|
done: "gtd: done",
|
|
387766
387769
|
"squash-template": "gtd: squash template",
|
|
387767
387770
|
"health-check": "gtd: health-check",
|
|
387768
|
-
"health-fix": "gtd: health-fix"
|
|
387771
|
+
"health-fix": "gtd: health-fix",
|
|
387772
|
+
"learning-template": "gtd: learning template",
|
|
387773
|
+
"learning-drafted": "gtd: learning drafted",
|
|
387774
|
+
"learning-approved": "gtd: learning approved",
|
|
387775
|
+
"learning-applied": "gtd: learning applied"
|
|
387769
387776
|
};
|
|
387770
387777
|
var reviewingSubject = (baseHash) => `gtd: reviewing ${baseHash}`;
|
|
387771
387778
|
var TURN_RE = /^gtd\((human|agent)\): (.+)$/;
|
|
@@ -387778,7 +387785,9 @@ var TURN_GATES = /* @__PURE__ */ new Set([
|
|
|
387778
387785
|
"review",
|
|
387779
387786
|
"squashing",
|
|
387780
387787
|
"health-fixing",
|
|
387781
|
-
"escalate"
|
|
387788
|
+
"escalate",
|
|
387789
|
+
"learning",
|
|
387790
|
+
"learning-apply"
|
|
387782
387791
|
]);
|
|
387783
387792
|
var ROUTING_SUBJECT_TO_PHASE = new Map(
|
|
387784
387793
|
Object.entries(ROUTING_SUBJECT).map(([phase, subject]) => [
|
|
@@ -387818,6 +387827,7 @@ var FEEDBACK_FILE = `${GTD_DIR}/FEEDBACK.md`;
|
|
|
387818
387827
|
var ERRORS_FILE = `${GTD_DIR}/ERRORS.md`;
|
|
387819
387828
|
var HEALTH_FILE = `${GTD_DIR}/HEALTH.md`;
|
|
387820
387829
|
var SQUASH_MSG_FILE = `${GTD_DIR}/SQUASH_MSG.md`;
|
|
387830
|
+
var LEARNINGS_FILE = `${GTD_DIR}/LEARNINGS.md`;
|
|
387821
387831
|
var LEGACY_FEEDBACK_FILE = "FEEDBACK.md";
|
|
387822
387832
|
var emptyFailureSentinel = (command, exitCode3) => `Test command \`${command}\` failed with exit code ${exitCode3} and produced no output.`;
|
|
387823
387833
|
var DONE_SUBJECT = "gtd: done";
|
|
@@ -387826,6 +387836,18 @@ var GATE_OWN_STEERING_FILE = {
|
|
|
387826
387836
|
grilling: TODO_FILE,
|
|
387827
387837
|
review: REVIEW_FILE
|
|
387828
387838
|
};
|
|
387839
|
+
var SQUASH_OR_LEARNING_ROUTING_PHASES = /* @__PURE__ */ new Set([
|
|
387840
|
+
"squash-template",
|
|
387841
|
+
"learning-template",
|
|
387842
|
+
"learning-drafted",
|
|
387843
|
+
"learning-approved",
|
|
387844
|
+
"learning-applied"
|
|
387845
|
+
]);
|
|
387846
|
+
var SQUASH_OR_LEARNING_TURN_GATES = /* @__PURE__ */ new Set([
|
|
387847
|
+
"squashing",
|
|
387848
|
+
"learning",
|
|
387849
|
+
"learning-apply"
|
|
387850
|
+
]);
|
|
387829
387851
|
var turnDiffExcludes = (gate) => {
|
|
387830
387852
|
const ownFile = GATE_OWN_STEERING_FILE[gate];
|
|
387831
387853
|
return ownFile ? [...WORKFLOW_FILE_EXCLUDES, `!${ownFile}`] : WORKFLOW_FILE_EXCLUDES;
|
|
@@ -388096,8 +388118,8 @@ var gatherEvents = (invoker) => (
|
|
|
388096
388118
|
let squashBase;
|
|
388097
388119
|
let squashDiff;
|
|
388098
388120
|
const headParsedForSquash = parseSubject(lastCommitSubject);
|
|
388099
|
-
const
|
|
388100
|
-
if (hasCommits &&
|
|
388121
|
+
const inSquashOrLearningChain = lastCommitSubject === DONE_SUBJECT || headParsedForSquash.kind === "routing" && SQUASH_OR_LEARNING_ROUTING_PHASES.has(headParsedForSquash.phase) || headParsedForSquash.kind === "turn" && SQUASH_OR_LEARNING_TURN_GATES.has(headParsedForSquash.gate);
|
|
388122
|
+
if (hasCommits && inSquashOrLearningChain && (config2.squash || config2.learning)) {
|
|
388101
388123
|
const squashHistory = history;
|
|
388102
388124
|
let lastDoneIdxForSquash = -1;
|
|
388103
388125
|
let prevDoneIdx = -1;
|
|
@@ -388143,11 +388165,13 @@ var gatherEvents = (invoker) => (
|
|
|
388143
388165
|
}
|
|
388144
388166
|
const squashMsgPresent = yield* fs9.exists(resolve5(SQUASH_MSG_FILE));
|
|
388145
388167
|
const squashMsgIsTemplate = squashMsgPresent && (yield* fs9.readFileString(resolve5(SQUASH_MSG_FILE))).trim() === SQUASH_TEMPLATE.trim();
|
|
388168
|
+
const learningMsgPresent = yield* fs9.exists(resolve5(LEARNINGS_FILE));
|
|
388169
|
+
const learningMsgIsTemplate = learningMsgPresent && (yield* fs9.readFileString(resolve5(LEARNINGS_FILE))).trim() === LEARNING_TEMPLATE.trim();
|
|
388146
388170
|
const healthPresent = yield* fs9.exists(resolve5(HEALTH_FILE));
|
|
388147
388171
|
const healthContent = healthPresent ? yield* fs9.readFileString(resolve5(HEALTH_FILE)) : "";
|
|
388148
388172
|
const healthCommitted = healthPresent && !isUncommitted(HEALTH_FILE);
|
|
388149
388173
|
let healthFixBase;
|
|
388150
|
-
if (config2.squash) {
|
|
388174
|
+
if (config2.squash || config2.learning) {
|
|
388151
388175
|
let firstHealthCheckHash;
|
|
388152
388176
|
let healthCheckCount = 0;
|
|
388153
388177
|
for (const commit3 of commitEvents) {
|
|
@@ -388221,7 +388245,10 @@ var gatherEvents = (invoker) => (
|
|
|
388221
388245
|
healthPresent,
|
|
388222
388246
|
healthContent,
|
|
388223
388247
|
healthCommitted,
|
|
388224
|
-
...healthFixBase !== void 0 ? { healthFixBase } : {}
|
|
388248
|
+
...healthFixBase !== void 0 ? { healthFixBase } : {},
|
|
388249
|
+
learningEnabled: config2.learning,
|
|
388250
|
+
learningMsgPresent,
|
|
388251
|
+
learningMsgIsTemplate
|
|
388225
388252
|
};
|
|
388226
388253
|
const resolveEvent = { type: "RESOLVE", payload };
|
|
388227
388254
|
return [...commitEvents, resolveEvent];
|
|
@@ -388245,6 +388272,15 @@ var SQUASH_TEMPLATE = [
|
|
|
388245
388272
|
"Longer description of the change, if needed.",
|
|
388246
388273
|
""
|
|
388247
388274
|
].join("\n");
|
|
388275
|
+
var LEARNING_TEMPLATE = [
|
|
388276
|
+
"<!-- gtd: replace this file's content with the actual distilled learnings for this cycle. -->",
|
|
388277
|
+
"<!-- Keep only durable, generalizable lessons \u2014 delete anything that's a one-off detail. -->",
|
|
388278
|
+
"",
|
|
388279
|
+
"## Learnings",
|
|
388280
|
+
"",
|
|
388281
|
+
"- ...",
|
|
388282
|
+
""
|
|
388283
|
+
].join("\n");
|
|
388248
388284
|
var perform = (action) => (
|
|
388249
388285
|
// fallow-ignore-next-line complexity
|
|
388250
388286
|
Effect_exports.gen(function* () {
|
|
@@ -388279,6 +388315,9 @@ var perform = (action) => (
|
|
|
388279
388315
|
if (action.removeHealth === true) {
|
|
388280
388316
|
yield* fs9.remove(resolve5(HEALTH_FILE)).pipe(Effect_exports.catchAll(() => Effect_exports.void));
|
|
388281
388317
|
}
|
|
388318
|
+
if (action.removeLearning === true) {
|
|
388319
|
+
yield* fs9.remove(resolve5(LEARNINGS_FILE)).pipe(Effect_exports.catchAll(() => Effect_exports.void));
|
|
388320
|
+
}
|
|
388282
388321
|
yield* git.commitAllWithPrefix(action.subject);
|
|
388283
388322
|
return { stop: false };
|
|
388284
388323
|
}
|
|
@@ -388326,6 +388365,14 @@ var perform = (action) => (
|
|
|
388326
388365
|
yield* git.commitAllWithPrefix("gtd: squash template");
|
|
388327
388366
|
return { stop: false };
|
|
388328
388367
|
}
|
|
388368
|
+
// Write the LEARNINGS.md template (a durable-lessons skeleton) and
|
|
388369
|
+
// commit routing `gtd: learning template`.
|
|
388370
|
+
case "writeLearningTemplate": {
|
|
388371
|
+
yield* ensureGtdDir;
|
|
388372
|
+
yield* fs9.writeFileString(resolve5(LEARNINGS_FILE), LEARNING_TEMPLATE);
|
|
388373
|
+
yield* git.commitAllWithPrefix("gtd: learning template");
|
|
388374
|
+
return { stop: false };
|
|
388375
|
+
}
|
|
388329
388376
|
// Squash: read SQUASH_MSG.md content (the real message authored by the
|
|
388330
388377
|
// squashing turn), rm it, soft-reset to squashBase, commit-all under the
|
|
388331
388378
|
// file's content as the message.
|
|
@@ -388337,10 +388384,11 @@ var perform = (action) => (
|
|
|
388337
388384
|
return { stop: false };
|
|
388338
388385
|
}
|
|
388339
388386
|
// Health check: run tests on an idle/clean tree.
|
|
388340
|
-
// Green, no squash-after chain queued → stop immediately, no
|
|
388341
|
-
//
|
|
388387
|
+
// Green, no learning/squash-after chain queued → stop immediately, no
|
|
388388
|
+
// commit/write.
|
|
388389
|
+
// Green, `chainAfterGreen` → commit routing `gtd: tests green` (the
|
|
388342
388390
|
// observable green marker) and continue — the resolver chains
|
|
388343
|
-
// `writeSquashTemplate` at that HEAD next.
|
|
388391
|
+
// `writeLearningTemplate` or `writeSquashTemplate` at that HEAD next.
|
|
388344
388392
|
// Red below cap → write HEALTH.md, commit routing `gtd: health-check` (the
|
|
388345
388393
|
// always-clean invariant: write-and-commit in the same chain).
|
|
388346
388394
|
// Red at cap → write ERRORS.md, commit routing `gtd: health-check`.
|
|
@@ -388348,7 +388396,7 @@ var perform = (action) => (
|
|
|
388348
388396
|
const runner = yield* TestRunner;
|
|
388349
388397
|
const result = yield* runner.run();
|
|
388350
388398
|
if (result.exitCode === 0) {
|
|
388351
|
-
if (action.
|
|
388399
|
+
if (action.chainAfterGreen) {
|
|
388352
388400
|
yield* git.commitAllWithPrefix("gtd: tests green");
|
|
388353
388401
|
return { stop: false };
|
|
388354
388402
|
}
|
|
@@ -388445,7 +388493,10 @@ var DEFAULT_PAYLOAD = {
|
|
|
388445
388493
|
squashMsgIsTemplate: false,
|
|
388446
388494
|
healthPresent: false,
|
|
388447
388495
|
healthContent: "",
|
|
388448
|
-
healthCommitted: false
|
|
388496
|
+
healthCommitted: false,
|
|
388497
|
+
learningEnabled: false,
|
|
388498
|
+
learningMsgPresent: false,
|
|
388499
|
+
learningMsgIsTemplate: false
|
|
388449
388500
|
};
|
|
388450
388501
|
var buildContext = (p4, counters) => ({
|
|
388451
388502
|
testFixCount: counters.testFixCount,
|
|
@@ -388476,6 +388527,32 @@ var healthFileConflictRules = [
|
|
|
388476
388527
|
message: ".gtd/HEALTH.md + .gtd/ERRORS.md"
|
|
388477
388528
|
}
|
|
388478
388529
|
];
|
|
388530
|
+
var learningFileConflictRules = [
|
|
388531
|
+
{
|
|
388532
|
+
isViolated: (p4) => p4.learningMsgPresent && p4.packagesPresent,
|
|
388533
|
+
message: ".gtd/LEARNINGS.md + packages"
|
|
388534
|
+
},
|
|
388535
|
+
{
|
|
388536
|
+
isViolated: (p4) => p4.learningMsgPresent && p4.reviewPresent,
|
|
388537
|
+
message: ".gtd/LEARNINGS.md + .gtd/REVIEW.md"
|
|
388538
|
+
},
|
|
388539
|
+
{
|
|
388540
|
+
isViolated: (p4) => p4.learningMsgPresent && p4.feedbackPresent,
|
|
388541
|
+
message: ".gtd/LEARNINGS.md + .gtd/FEEDBACK.md"
|
|
388542
|
+
},
|
|
388543
|
+
{
|
|
388544
|
+
isViolated: (p4) => p4.learningMsgPresent && p4.errorsPresent,
|
|
388545
|
+
message: ".gtd/LEARNINGS.md + .gtd/ERRORS.md"
|
|
388546
|
+
},
|
|
388547
|
+
{
|
|
388548
|
+
isViolated: (p4) => p4.learningMsgPresent && p4.healthPresent,
|
|
388549
|
+
message: ".gtd/LEARNINGS.md + .gtd/HEALTH.md"
|
|
388550
|
+
},
|
|
388551
|
+
{
|
|
388552
|
+
isViolated: (p4) => p4.learningMsgPresent && p4.squashMsgPresent,
|
|
388553
|
+
message: ".gtd/LEARNINGS.md + .gtd/SQUASH_MSG.md"
|
|
388554
|
+
}
|
|
388555
|
+
];
|
|
388479
388556
|
var isReviewPackagesConflict = (p4) => p4.reviewPresent && p4.packagesPresent;
|
|
388480
388557
|
var isReviewCommittedTodoConflict = (p4) => p4.reviewPresent && p4.todoCommitted;
|
|
388481
388558
|
var isUncommittedReviewWithTodoConflict = (p4) => p4.reviewPresent && !(p4.reviewCommitted || p4.reviewDirty) && p4.todoExists;
|
|
@@ -388500,12 +388577,53 @@ var reviewAndFeedbackRules = [
|
|
|
388500
388577
|
{ isViolated: isErrorsWithoutPackages, message: ".gtd/ERRORS.md without packages" }
|
|
388501
388578
|
];
|
|
388502
388579
|
var assertLegal = (p4) => {
|
|
388503
|
-
for (const rule of [
|
|
388580
|
+
for (const rule of [
|
|
388581
|
+
...healthFileConflictRules,
|
|
388582
|
+
...learningFileConflictRules,
|
|
388583
|
+
...reviewAndFeedbackRules
|
|
388584
|
+
]) {
|
|
388504
388585
|
if (rule.isViolated(p4)) {
|
|
388505
388586
|
throw new GtdStateError("illegal-combination", `illegal combination: ${rule.message}`);
|
|
388506
388587
|
}
|
|
388507
388588
|
}
|
|
388508
388589
|
};
|
|
388590
|
+
var nextAfterReviewOrLearning = (flags, state, learningAlreadyRan) => {
|
|
388591
|
+
if (!learningAlreadyRan && flags.learningEnabled && flags.hasSquashBase) {
|
|
388592
|
+
return { kind: "mid-chain", state, actor: "agent", action: { kind: "writeLearningTemplate" } };
|
|
388593
|
+
}
|
|
388594
|
+
return flags.squashEnabled && flags.hasSquashBase ? { kind: "mid-chain", state, actor: "agent", action: { kind: "writeSquashTemplate" } } : { kind: "rest", state: "idle", actor: "human" };
|
|
388595
|
+
};
|
|
388596
|
+
var classifyLearningTurn = (actor, gate, flags) => {
|
|
388597
|
+
if (actor === "agent" && gate === "learning") {
|
|
388598
|
+
return flags.hasSquashBase && !flags.learningMsgIsTemplate ? {
|
|
388599
|
+
kind: "mid-chain",
|
|
388600
|
+
state: "learning",
|
|
388601
|
+
actor: "agent",
|
|
388602
|
+
action: { kind: "commitRouting", subject: "gtd: learning drafted" }
|
|
388603
|
+
} : { kind: "rest", state: "learning", actor: "agent" };
|
|
388604
|
+
}
|
|
388605
|
+
if (actor === "human" && gate === "learning") {
|
|
388606
|
+
return {
|
|
388607
|
+
kind: "mid-chain",
|
|
388608
|
+
state: "learning",
|
|
388609
|
+
actor: "human",
|
|
388610
|
+
action: { kind: "commitRouting", subject: "gtd: learning approved" }
|
|
388611
|
+
};
|
|
388612
|
+
}
|
|
388613
|
+
if (actor === "agent" && gate === "learning-apply") {
|
|
388614
|
+
return {
|
|
388615
|
+
kind: "mid-chain",
|
|
388616
|
+
state: "learning-apply",
|
|
388617
|
+
actor: "agent",
|
|
388618
|
+
action: {
|
|
388619
|
+
kind: "commitRouting",
|
|
388620
|
+
subject: "gtd: learning applied",
|
|
388621
|
+
removeLearning: true
|
|
388622
|
+
}
|
|
388623
|
+
};
|
|
388624
|
+
}
|
|
388625
|
+
return null;
|
|
388626
|
+
};
|
|
388509
388627
|
var classifyHead = (subject, flags) => {
|
|
388510
388628
|
const parsed = parseSubject(subject);
|
|
388511
388629
|
if (parsed.kind === "turn") {
|
|
@@ -388578,6 +388696,8 @@ var classifyHead = (subject, flags) => {
|
|
|
388578
388696
|
// squashBase filled in by the caller
|
|
388579
388697
|
} : { kind: "rest", state: "squashing", actor: "agent" };
|
|
388580
388698
|
}
|
|
388699
|
+
const learningTurn = classifyLearningTurn(actor, gate, flags);
|
|
388700
|
+
if (learningTurn !== null) return learningTurn;
|
|
388581
388701
|
if (actor === "agent" && gate === "health-fixing") {
|
|
388582
388702
|
return {
|
|
388583
388703
|
kind: "mid-chain",
|
|
@@ -388611,12 +388731,7 @@ var classifyHead = (subject, flags) => {
|
|
|
388611
388731
|
action: { kind: "closePackage" }
|
|
388612
388732
|
} : { kind: "rest", state: "agentic-review", actor: "agent" };
|
|
388613
388733
|
}
|
|
388614
|
-
return flags
|
|
388615
|
-
kind: "mid-chain",
|
|
388616
|
-
state: "testing",
|
|
388617
|
-
actor: "agent",
|
|
388618
|
-
action: { kind: "writeSquashTemplate" }
|
|
388619
|
-
} : { kind: "rest", state: "idle", actor: "human" };
|
|
388734
|
+
return nextAfterReviewOrLearning(flags, "testing", false);
|
|
388620
388735
|
case "errors":
|
|
388621
388736
|
return flags.errorsPresent ? { kind: "rest", state: "escalate", actor: "human" } : { kind: "rest", state: "fixing", actor: "agent" };
|
|
388622
388737
|
case "package-done":
|
|
@@ -388626,16 +388741,19 @@ var classifyHead = (subject, flags) => {
|
|
|
388626
388741
|
case "review-feedback":
|
|
388627
388742
|
return { kind: "rest", state: "grilling", actor: "agent" };
|
|
388628
388743
|
case "done":
|
|
388629
|
-
return flags
|
|
388630
|
-
kind: "mid-chain",
|
|
388631
|
-
state: "done",
|
|
388632
|
-
actor: "agent",
|
|
388633
|
-
action: { kind: "writeSquashTemplate" }
|
|
388634
|
-
} : { kind: "rest", state: "idle", actor: "human" };
|
|
388744
|
+
return nextAfterReviewOrLearning(flags, "done", false);
|
|
388635
388745
|
case "squash-template":
|
|
388636
388746
|
return { kind: "rest", state: "squashing", actor: "agent" };
|
|
388637
388747
|
case "reviewing":
|
|
388638
388748
|
return { kind: "rest", state: "review", actor: "agent" };
|
|
388749
|
+
case "learning-template":
|
|
388750
|
+
return { kind: "rest", state: "learning", actor: "agent" };
|
|
388751
|
+
case "learning-drafted":
|
|
388752
|
+
return { kind: "rest", state: "await-learning-review", actor: "human" };
|
|
388753
|
+
case "learning-approved":
|
|
388754
|
+
return { kind: "rest", state: "learning-apply", actor: "agent" };
|
|
388755
|
+
case "learning-applied":
|
|
388756
|
+
return nextAfterReviewOrLearning(flags, "learning-applied", true);
|
|
388639
388757
|
case "health-check":
|
|
388640
388758
|
return flags.errorsPresent ? { kind: "rest", state: "escalate", actor: "human" } : { kind: "rest", state: "health-fixing", actor: "agent" };
|
|
388641
388759
|
case "health-fix":
|
|
@@ -388653,18 +388771,24 @@ var STATE_IS_OWN_GATE = /* @__PURE__ */ new Set([
|
|
|
388653
388771
|
"review",
|
|
388654
388772
|
"squashing",
|
|
388655
388773
|
"health-fixing",
|
|
388656
|
-
"escalate"
|
|
388774
|
+
"escalate",
|
|
388775
|
+
"learning",
|
|
388776
|
+
"learning-apply"
|
|
388657
388777
|
]);
|
|
388658
|
-
var
|
|
388778
|
+
var GATE_OVERRIDES = {
|
|
388779
|
+
"await-learning-review": "learning"
|
|
388780
|
+
};
|
|
388781
|
+
var gateForState = (state) => STATE_IS_OWN_GATE.has(state) ? state : GATE_OVERRIDES[state] ?? "review";
|
|
388659
388782
|
var INERT_EMPTY_AGENT_GATES = /* @__PURE__ */ new Set([
|
|
388660
388783
|
"grilling",
|
|
388661
388784
|
"grilled",
|
|
388662
388785
|
"building",
|
|
388663
388786
|
"fixing",
|
|
388664
388787
|
"agentic-review",
|
|
388665
|
-
"review"
|
|
388788
|
+
"review",
|
|
388789
|
+
"learning-apply"
|
|
388666
388790
|
]);
|
|
388667
|
-
var isInertEmptyAgentRest = (state, p4) => p4.workingTreeClean && (INERT_EMPTY_AGENT_GATES.has(state) || state === "squashing" && p4.squashMsgIsTemplate);
|
|
388791
|
+
var isInertEmptyAgentRest = (state, p4) => p4.workingTreeClean && (INERT_EMPTY_AGENT_GATES.has(state) || state === "squashing" && p4.squashMsgIsTemplate || state === "learning" && p4.learningMsgIsTemplate);
|
|
388668
388792
|
var resolveBaseline = (p4, counters, head7, corrupt, lastTurn) => {
|
|
388669
388793
|
const headIsFixerTurn = (() => {
|
|
388670
388794
|
const parsed = parseSubject(head7);
|
|
@@ -388693,7 +388817,6 @@ var resolveBaseline = (p4, counters, head7, corrupt, lastTurn) => {
|
|
|
388693
388817
|
action: { kind: "closePackage" }
|
|
388694
388818
|
} : { kind: "rest", state: "fixing", actor: "agent" };
|
|
388695
388819
|
}
|
|
388696
|
-
const squashAfterGreen = p4.squashEnabled && counters.healthFixCount > 0 && p4.healthFixBase !== void 0;
|
|
388697
388820
|
const reviewSubstantive = p4.headTurnReviewSubstantive !== void 0 ? p4.headTurnReviewSubstantive : p4.reviewDirty && !p4.reviewCheckboxOnly;
|
|
388698
388821
|
const flags = {
|
|
388699
388822
|
headTurnIsEmpty: p4.headTurnIsEmpty,
|
|
@@ -388701,7 +388824,8 @@ var resolveBaseline = (p4, counters, head7, corrupt, lastTurn) => {
|
|
|
388701
388824
|
agenticReviewForceApproved: forceApprove,
|
|
388702
388825
|
squashEnabled: p4.squashEnabled,
|
|
388703
388826
|
hasSquashBase: p4.squashBase !== void 0,
|
|
388704
|
-
|
|
388827
|
+
learningEnabled: p4.learningEnabled,
|
|
388828
|
+
learningMsgIsTemplate: p4.learningMsgIsTemplate,
|
|
388705
388829
|
reviewSubstantive,
|
|
388706
388830
|
// A pending (uncommitted) deletion of ERRORS.md still counts as "ERRORS.md
|
|
388707
388831
|
// was committed at this HEAD" for classification purposes: `fs.exists`
|
|
@@ -388739,7 +388863,7 @@ var resolveBaseline = (p4, counters, head7, corrupt, lastTurn) => {
|
|
|
388739
388863
|
kind: "runHealthCheck",
|
|
388740
388864
|
errorCount: counters.healthFixCount,
|
|
388741
388865
|
capReached: counters.healthFixCount >= p4.fixAttemptCap,
|
|
388742
|
-
|
|
388866
|
+
chainAfterGreen: classified.action.chainAfterGreen
|
|
388743
388867
|
}
|
|
388744
388868
|
};
|
|
388745
388869
|
}
|
|
@@ -388808,7 +388932,7 @@ var applyTurnTaking = (p4, counters, head7, baseline) => {
|
|
|
388808
388932
|
}
|
|
388809
388933
|
const healthCheckCapReached = head7 === "gtd: health-check" && counters.healthFixCount >= p4.fixAttemptCap;
|
|
388810
388934
|
if (head7 === "gtd: health-fix" && baseline.state === "idle" || healthCheckCapReached && baseline.state === "health-fixing") {
|
|
388811
|
-
const
|
|
388935
|
+
const chainAfterGreenAtHealthFix = (p4.squashEnabled || p4.learningEnabled) && counters.healthFixCount > 0 && p4.healthFixBase !== void 0;
|
|
388812
388936
|
return {
|
|
388813
388937
|
state: "idle",
|
|
388814
388938
|
actor: "agent",
|
|
@@ -388817,7 +388941,7 @@ var applyTurnTaking = (p4, counters, head7, baseline) => {
|
|
|
388817
388941
|
kind: "runHealthCheck",
|
|
388818
388942
|
errorCount: counters.healthFixCount,
|
|
388819
388943
|
capReached: counters.healthFixCount >= p4.fixAttemptCap,
|
|
388820
|
-
|
|
388944
|
+
chainAfterGreen: chainAfterGreenAtHealthFix
|
|
388821
388945
|
},
|
|
388822
388946
|
context: context10
|
|
388823
388947
|
};
|
|
@@ -388832,7 +388956,7 @@ var applyTurnTaking = (p4, counters, head7, baseline) => {
|
|
|
388832
388956
|
};
|
|
388833
388957
|
}
|
|
388834
388958
|
if (baseline.state === "idle" && invoker === "human") {
|
|
388835
|
-
const
|
|
388959
|
+
const chainAfterGreen = (p4.squashEnabled || p4.learningEnabled) && counters.healthFixCount > 0 && p4.healthFixBase !== void 0;
|
|
388836
388960
|
return {
|
|
388837
388961
|
state: "idle",
|
|
388838
388962
|
actor: "human",
|
|
@@ -388841,7 +388965,7 @@ var applyTurnTaking = (p4, counters, head7, baseline) => {
|
|
|
388841
388965
|
kind: "runHealthCheck",
|
|
388842
388966
|
errorCount: counters.healthFixCount,
|
|
388843
388967
|
capReached: counters.healthFixCount >= p4.fixAttemptCap,
|
|
388844
|
-
|
|
388968
|
+
chainAfterGreen
|
|
388845
388969
|
},
|
|
388846
388970
|
context: context10
|
|
388847
388971
|
};
|
|
@@ -389416,6 +389540,15 @@ var await_review_default = '<%~ include("@header") %>\n\n`.gtd/REVIEW.md` holds
|
|
|
389416
389540
|
// src/prompts/squashing.md
|
|
389417
389541
|
var squashing_default = '<%~ include("@header") %>\n\nThe process is **approved and done**. `.gtd/SQUASH_MSG.md` has already been\ncommitted with a template \u2014 your job is to overwrite it with the real\nconventional-commits squash message and finish your turn.\n\n### Step 1 \u2014 Extract decisions from grilling rounds\n\nScan the git history of recent `gtd: ...` / `gtd(agent): ...` /\n`gtd(human): ...` commits. Look for changes to `.gtd/TODO.md` \u2014 specifically the\n`## Captured input` sections and any edits to plan text. Extract **key\ndecisions, trade-offs, and design choices** made during grilling rounds. These\nwill appear in the commit body so the history is self-documenting.\n\n### Step 2 \u2014 Draft the commit message\n\nDraft ONE conventional-commits message:\n\n```\ntype(scope): subject\n\nbody (explain the why \u2014 motivation, trade-offs, key decisions from grilling)\n```\n\n- **type**: `feat` / `fix` / `refactor` / `chore` / `docs` / `test`\n- **subject**: imperative mood, \u2264 72 characters, lowercase after the colon\n- **body**: include the important decisions / trade-offs from grilling\n sessions. Omit if there were no meaningful decisions to capture.\n\n### Step 3 \u2014 Overwrite .gtd/SQUASH_MSG.md\n\nReplace the **entire content** of `.gtd/SQUASH_MSG.md` (plain text, no markdown\nwrapper, no leftover template scaffolding) with the message from Step 2, then\nleave it uncommitted and finish your turn \u2014 `gtd step-agent` performs the\nsquash using this file\'s content.\n<% if (it.context.squashDiff && it.context.squashDiff.trim()) { %>\n<%= it.context.squashBase !== undefined ? "\\nSquash base: " + it.context.squashBase + "\\n" : "" %>\n<%~ include("@diff", { heading: "Full-process diff (`git diff " + (it.context.squashBase !== undefined ? it.context.squashBase : "<squashBase>") + " HEAD`)", diff: it.context.squashDiff, fenceFor: it.fenceFor }) %>\n<% } %>\n\n<% if (it.tail) { %>\n<%~ include(it.tail) %>\n<% } %>\n';
|
|
389418
389542
|
|
|
389543
|
+
// src/prompts/learning.md
|
|
389544
|
+
var learning_default = '<%~ include("@header") %>\n\nThe process is **approved and done**, and headed for a squash. Before that\nhappens, `.gtd/LEARNINGS.md` has been committed with a template \u2014 your job is\nto overwrite it with the real, distilled learnings from this cycle so they\nsurvive the squash even though the granular history won\'t.\n\n### Step 1 \u2014 Walk the cycle\'s history\n\nScan the git history back to the cycle\'s start (the full-process diff is\ninlined below, and `git log` over the same range shows every `gtd: ...` /\n`gtd(agent): ...` / `gtd(human): ...` commit). Look specifically for:\n\n- **Test failures and fixes** \u2014 each `gtd: errors` round and the fix that\n followed it. What broke, and what actually made it pass?\n- **Review feedback** \u2014 human `.gtd/REVIEW.md` notes and `gtd: review\n feedback` detours. What did the human have to correct that the agent got\n wrong on its own?\n- **Health-check rounds** \u2014 any `gtd: health-check` / `gtd: health-fix`\n cycles. Environmental or systemic issues surfaced outside normal building?\n- **Grilling decisions** \u2014 `.gtd/TODO.md`\'s "## Captured input" sections and\n plan edits. Trade-offs or conventions the human specified that a future\n agent should already know.\n\n### Step 2 \u2014 Distill, don\'t transcribe\n\nFor each thing you found, ask: is this a **durable, generalizable lesson**\n(a convention, a gotcha, a pattern this project wants followed next time), or\na **one-off detail** specific to this change? Keep only the former. A future\nagent reading this should learn something that changes how it works on this\nproject, not a recap of what happened.\n\n### Step 3 \u2014 Overwrite .gtd/LEARNINGS.md\n\nReplace the **entire content** of `.gtd/LEARNINGS.md` with your distilled\nlearnings (plain markdown, no leftover template scaffolding). If nothing\ndurable surfaced this cycle, write a short explicit note saying so \u2014 don\'t\nleave the placeholder text in place. Leave the file uncommitted and finish\nyour turn; a human reviews it next before it\'s integrated into the project\'s\nown memory (CLAUDE.md/AGENTS.md/docs).\n<% if (it.context.squashDiff && it.context.squashDiff.trim()) { %>\n<%= it.context.squashBase !== undefined ? "\\nCycle base: " + it.context.squashBase + "\\n" : "" %>\n<%~ include("@diff", { heading: "Full-process diff (`git diff " + (it.context.squashBase !== undefined ? it.context.squashBase : "<squashBase>") + " HEAD`)", diff: it.context.squashDiff, fenceFor: it.fenceFor }) %>\n<% } %>\n\n<% if (it.tail) { %>\n<%~ include(it.tail) %>\n<% } %>\n';
|
|
389545
|
+
|
|
389546
|
+
// src/prompts/await-learning-review.md
|
|
389547
|
+
var await_learning_review_default = "<%~ include(\"@header\") %>\n\n`.gtd/LEARNINGS.md` holds the distilled learnings from this cycle, drafted by\nthe agent. This is a human gate; there is nothing for the agent to do.\n\nTell the user:\n\n- Read `.gtd/LEARNINGS.md`.\n- Delete anything not worth keeping, or edit/add anything the draft missed.\n- Run `gtd step` \u2014 with or without edits, either way proceeds: the agent\n integrates whatever remains into the project's own memory\n (CLAUDE.md/AGENTS.md/docs) next.\n\nThere is no reject path \u2014 this gate only refines what gets kept, it doesn't\nsend the cycle back for rework.\n\n<% if (it.tail) { %>\n<%~ include(it.tail) %>\n<% } %>\n";
|
|
389548
|
+
|
|
389549
|
+
// src/prompts/learning-apply.md
|
|
389550
|
+
var learning_apply_default = "<%~ include(\"@header\") %>\n\nThe human has approved (and possibly amended) `.gtd/LEARNINGS.md`. Your job is\nto integrate those learnings into the project's own memory, not to touch\n`.gtd/LEARNINGS.md` itself.\n\n1. **Read `.gtd/LEARNINGS.md`.**\n2. **Pick the right home for each point**, using your judgment and this\n project's existing convention:\n - An existing `CLAUDE.md` or `AGENTS.md` at the repo root (or a directory\n closer to what the learning concerns) is usually the right place.\n - If neither exists and the learnings warrant one, create `AGENTS.md` at\n the repo root.\n - A learning about a specific subsystem may fit better in that\n subsystem's own docs than a root-level file \u2014 use your judgment.\n3. **Integrate, don't just append** \u2014 merge each point into the relevant\n section of the target file(s); rephrase for clarity, dedupe against what's\n already documented, and keep the existing document's structure and tone.\n4. **Never delete or edit `.gtd/LEARNINGS.md`** \u2014 the machine removes it once\n your turn is captured.\n5. **Leave every change uncommitted and finish your turn.**\n\n<% if (it.tail) { %>\n<%~ include(it.tail) %>\n<% } %>\n";
|
|
389551
|
+
|
|
389419
389552
|
// src/prompts/escalate.md
|
|
389420
389553
|
var escalate_default = '<%~ include("@header") %>\n\nThe agent was not able to fix all errors on its own. The last error report is\nstored in `.gtd/ERRORS.md` for a human to investigate.\n\nNext steps for the human developer:\n\n1. Investigate and fix errors reported in `.gtd/ERRORS.md`\n2. Delete `.gtd/ERRORS.md`\n3. Run `gtd step` when you are ready to continue\n\n<% if (it.tail) { %>\n<%~ include(it.tail) %>\n<% } %>\n';
|
|
389421
389554
|
|
|
@@ -389432,6 +389565,9 @@ var PROMPT_STATES = /* @__PURE__ */ new Set([
|
|
|
389432
389565
|
"review",
|
|
389433
389566
|
"await-review",
|
|
389434
389567
|
"squashing",
|
|
389568
|
+
"learning",
|
|
389569
|
+
"await-learning-review",
|
|
389570
|
+
"learning-apply",
|
|
389435
389571
|
"escalate",
|
|
389436
389572
|
"idle",
|
|
389437
389573
|
"health-fixing"
|
|
@@ -389445,7 +389581,9 @@ var MODEL_STATE = {
|
|
|
389445
389581
|
"health-fixing": "fixing",
|
|
389446
389582
|
"agentic-review": "agentic-review",
|
|
389447
389583
|
review: "clean",
|
|
389448
|
-
squashing: "clean"
|
|
389584
|
+
squashing: "clean",
|
|
389585
|
+
learning: "clean",
|
|
389586
|
+
"learning-apply": "clean"
|
|
389449
389587
|
};
|
|
389450
389588
|
var builtinResolveModel = (state) => builtinTierDefault[stateTier[state]];
|
|
389451
389589
|
var fenceFor = (content) => {
|
|
@@ -389469,6 +389607,9 @@ eta.loadTemplate("@agentic-review", agentic_review_default);
|
|
|
389469
389607
|
eta.loadTemplate("@review", review_default);
|
|
389470
389608
|
eta.loadTemplate("@await-review", await_review_default);
|
|
389471
389609
|
eta.loadTemplate("@squashing", squashing_default);
|
|
389610
|
+
eta.loadTemplate("@learning", learning_default);
|
|
389611
|
+
eta.loadTemplate("@await-learning-review", await_learning_review_default);
|
|
389612
|
+
eta.loadTemplate("@learning-apply", learning_apply_default);
|
|
389472
389613
|
eta.loadTemplate("@escalate", escalate_default);
|
|
389473
389614
|
eta.loadTemplate("@idle", idle_default);
|
|
389474
389615
|
eta.readFile = null;
|
|
@@ -389481,6 +389622,9 @@ var STATE_TEMPLATE = {
|
|
|
389481
389622
|
review: "@review",
|
|
389482
389623
|
"await-review": "@await-review",
|
|
389483
389624
|
squashing: "@squashing",
|
|
389625
|
+
learning: "@learning",
|
|
389626
|
+
"await-learning-review": "@await-learning-review",
|
|
389627
|
+
"learning-apply": "@learning-apply",
|
|
389484
389628
|
escalate: "@escalate",
|
|
389485
389629
|
idle: "@idle",
|
|
389486
389630
|
"health-fixing": "@health-fixing"
|
|
@@ -389592,6 +389736,7 @@ var edgeActionHandlers = {
|
|
|
389592
389736
|
if (a5.removeReview) removed.push(".gtd/REVIEW.md");
|
|
389593
389737
|
if (a5.removeFeedback) removed.push(".gtd/FEEDBACK.md");
|
|
389594
389738
|
if (a5.removeHealth) removed.push(".gtd/HEALTH.md");
|
|
389739
|
+
if (a5.removeLearning) removed.push(".gtd/LEARNINGS.md");
|
|
389595
389740
|
if (removed.length > 0) msg += ` (removing ${removed.join(", ")})`;
|
|
389596
389741
|
return msg;
|
|
389597
389742
|
},
|
|
@@ -389599,7 +389744,8 @@ var edgeActionHandlers = {
|
|
|
389599
389744
|
closePackage: () => "close the active package",
|
|
389600
389745
|
writeSquashTemplate: () => "write the squash message template",
|
|
389601
389746
|
squashCommit: (a5) => `squash the cycle onto ${a5.squashBase}`,
|
|
389602
|
-
|
|
389747
|
+
writeLearningTemplate: () => "write the learnings template",
|
|
389748
|
+
runHealthCheck: (a5) => `run the health check (attempt ${a5.errorCount + 1}${a5.capReached ? ", cap reached" : ""}${a5.chainAfterGreen ? ", chain after green" : ""})`
|
|
389603
389749
|
};
|
|
389604
389750
|
var describeEdgeAction = (a5) => edgeActionHandlers[a5.kind](a5);
|
|
389605
389751
|
var describeStatus = (prediction) => ({
|
package/package.json
CHANGED