@pmelab/gtd 2.1.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 +147 -71
- package/dist/gtd.bundle.mjs +278 -39
- 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
|
|
|
@@ -116,6 +117,12 @@ to cwd, so it refuses with a clear error if invoked from a subdirectory.
|
|
|
116
117
|
`--jsn`) is rejected with a usage error rather than silently ignored, so a
|
|
117
118
|
mistyped flag can never degrade a JSON caller to plain-text mode.
|
|
118
119
|
|
|
120
|
+
One nuance to "(no mutation)": `next` and `status` never author commits or
|
|
121
|
+
change workflow state, but while a human review is pending they do maintain the
|
|
122
|
+
review checkout window (closing it to read state, re-arming it on the way out —
|
|
123
|
+
see [Human review gate](#human-review-gate)), which transiently moves HEAD and
|
|
124
|
+
the index. The working tree is never touched.
|
|
125
|
+
|
|
119
126
|
### `gtd step` / `gtd step-agent`
|
|
120
127
|
|
|
121
128
|
Both drive the **same fixpoint loop** — gather → resolve → perform the returned
|
|
@@ -422,12 +429,14 @@ GTD_LOOP_AGENT_CMD='my-agent-cli --prompt "$GTD_LOOP_PROMPT"' gtd-loop
|
|
|
422
429
|
|
|
423
430
|
## States & subjects overview
|
|
424
431
|
|
|
425
|
-
`resolve()` lands on exactly one of **
|
|
432
|
+
`resolve()` lands on exactly one of **20 states**: `grilling`, `grilled`,
|
|
426
433
|
`planning`, `building`, `testing`, `fixing`, `escalate`, `agentic-review`,
|
|
427
|
-
`close-package`, `review`, `await-review`, `done`, `
|
|
428
|
-
`
|
|
429
|
-
`
|
|
430
|
-
|
|
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**.
|
|
431
440
|
|
|
432
441
|
For the full precedence ladder, illegal combinations, and the counter folds that
|
|
433
442
|
drive the fix loops, see [STATES.md](STATES.md) — this section is a summary.
|
|
@@ -446,6 +455,8 @@ The closed set of gates:
|
|
|
446
455
|
| `agentic-review` | agent (writes .gtd/FEEDBACK.md verdict) |
|
|
447
456
|
| `review` | agent (writes .gtd/REVIEW.md) / human (approves or gives feedback) |
|
|
448
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) |
|
|
449
460
|
| `health-fixing` | agent (idle health-check repair) |
|
|
450
461
|
| `escalate` | human (deletes .gtd/ERRORS.md to resume) |
|
|
451
462
|
|
|
@@ -456,7 +467,8 @@ agent "wins": `gtd: grilled`, `gtd: planning`, `gtd: tests green`,
|
|
|
456
467
|
`gtd: errors`, `gtd: package done`, `gtd: awaiting review`,
|
|
457
468
|
`gtd: review feedback`, `gtd: done`, `gtd: squash template`,
|
|
458
469
|
`gtd: reviewing <hash>` (parameterized, from `gtd review`), `gtd: health-check`,
|
|
459
|
-
`gtd: health-fix
|
|
470
|
+
`gtd: health-fix`, `gtd: learning template`, `gtd: learning drafted`,
|
|
471
|
+
`gtd: learning approved`, `gtd: learning applied`.
|
|
460
472
|
|
|
461
473
|
Everything else — any non-`gtd` subject, and any `gtd: *` subject outside this
|
|
462
474
|
closed set — is a **boundary commit**: inert as far as the machine's grammar is
|
|
@@ -520,23 +532,25 @@ the threshold simply closes the package as usual.) Setting
|
|
|
520
532
|
|
|
521
533
|
A **do-nothing agent invocation** — `gtd step-agent` on a clean tree at ANY
|
|
522
534
|
agent-awaited rest whose move is a file artifact (`grilling`, `grilled`,
|
|
523
|
-
`building`, `fixing`, `agentic-review`, `review`,
|
|
524
|
-
`.gtd/SQUASH_MSG.md` still holds the unmodified template
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
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).
|
|
540
554
|
|
|
541
555
|
### Human review gate
|
|
542
556
|
|
|
@@ -547,28 +561,79 @@ Once `.gtd/` is fully closed, the machine writes `.gtd/REVIEW.md` and rests at
|
|
|
547
561
|
plus routing `gtd: done`.
|
|
548
562
|
- Flipping only `- [ ]` → `- [x]` checkboxes in `.gtd/REVIEW.md` — checkbox-only
|
|
549
563
|
edits are also treated as clean approval.
|
|
564
|
+
- Deleting `.gtd/REVIEW.md` outright.
|
|
550
565
|
|
|
551
566
|
Any **substantive** edit — to `.gtd/REVIEW.md` prose, or to the reviewed code
|
|
552
567
|
itself — is feedback: `gtd(human): review` plus routing `gtd: review feedback`,
|
|
553
568
|
`.gtd/REVIEW.md` removed, and `gtd next` re-emits a grilling prompt to the agent
|
|
554
569
|
that inlines the human's finding.
|
|
555
570
|
|
|
571
|
+
**The review diff lives in your editor.** While the gate is pending, gtd holds
|
|
572
|
+
open a _review checkout window_: it saves the real head to
|
|
573
|
+
`refs/gtd/review-head`, then rewinds HEAD and the index to the review base with
|
|
574
|
+
`git reset --mixed`, leaving the working tree untouched. Every editor's standard
|
|
575
|
+
git integration now shows the entire reviewable diff as ordinary uncommitted
|
|
576
|
+
changes — SCM panel, gutter marks, per-file diffs. Review it there:
|
|
577
|
+
|
|
578
|
+
- **Edit** anything (code or `.gtd/REVIEW.md` prose) → feedback.
|
|
579
|
+
- **Discard a hunk** in the editor → that reversion IS the feedback: the agent
|
|
580
|
+
is re-grilled with it.
|
|
581
|
+
- **Delete a surfaced file** → reject-this-file feedback.
|
|
582
|
+
- Touch nothing (or tick checkboxes / delete `.gtd/REVIEW.md`) → approval.
|
|
583
|
+
|
|
584
|
+
Any gtd invocation closes the window first (restoring HEAD/index exactly, so
|
|
585
|
+
only your own edits remain dirty — they land as their own separate
|
|
586
|
+
`gtd(human): review` commit, never mixed into the reviewed work), and
|
|
587
|
+
`gtd next`/`gtd status` re-arm it on their way out. The mechanics are
|
|
588
|
+
crash-safe; details and invariants in STATES.md ("The review checkout window").
|
|
589
|
+
|
|
590
|
+
Caveats while a review is pending: don't push (the branch tip rests at the
|
|
591
|
+
review base — the real head is safe under `refs/gtd/review-head`); commits you
|
|
592
|
+
make manually survive as working-tree content and become review feedback, but
|
|
593
|
+
their commit message is discarded; linked `git worktree` checkouts are
|
|
594
|
+
unsupported. If you switch branches mid-review, gtd refuses to touch the foreign
|
|
595
|
+
branch and prints the manual recovery command.
|
|
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
|
+
|
|
556
618
|
### Squash
|
|
557
619
|
|
|
558
|
-
With `squash: true` (the default), `gtd: done`
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
the
|
|
570
|
-
|
|
571
|
-
|
|
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.
|
|
572
637
|
|
|
573
638
|
### Health check
|
|
574
639
|
|
|
@@ -577,9 +642,9 @@ runs `testCommand` as a health check rather than settling immediately. Green
|
|
|
577
642
|
settles idle with zero commits. Red below `fixAttemptCap` writes
|
|
578
643
|
`.gtd/HEALTH.md` and rests at **Health Fixing** for the agent; the fixer's own
|
|
579
644
|
turn (`gtd(agent): health-fixing`) removes `.gtd/HEALTH.md` and re-tests in the
|
|
580
|
-
same chain — a green re-test continues to
|
|
581
|
-
repeats the health-fix loop; red at the cap writes
|
|
582
|
-
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.
|
|
583
648
|
|
|
584
649
|
### Escalate / budget reset
|
|
585
650
|
|
|
@@ -591,24 +656,28 @@ fix-attempt budget to zero.
|
|
|
591
656
|
|
|
592
657
|
## States & subjects: overview table
|
|
593
658
|
|
|
594
|
-
| State
|
|
595
|
-
|
|
|
596
|
-
| `grilling`
|
|
597
|
-
| `grilled`
|
|
598
|
-
| `planning`
|
|
599
|
-
| `building`
|
|
600
|
-
| `testing`
|
|
601
|
-
| `fixing`
|
|
602
|
-
| `escalate`
|
|
603
|
-
| `agentic-review`
|
|
604
|
-
| `close-package`
|
|
605
|
-
| `review`
|
|
606
|
-
| `await-review`
|
|
607
|
-
| `done`
|
|
608
|
-
| `
|
|
609
|
-
| `
|
|
610
|
-
| `
|
|
611
|
-
| `
|
|
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 |
|
|
612
681
|
|
|
613
682
|
See [STATES.md](STATES.md) for the full precedence ladder, the counter folds,
|
|
614
683
|
and every illegal steering-file combination.
|
|
@@ -641,13 +710,19 @@ built-in defaults apply. Supported filenames (searched in this order):
|
|
|
641
710
|
- **`agenticReview`** (boolean, default `true`) — kill-switch for the
|
|
642
711
|
per-package Agentic Review gate. Set `false` to force-approve every package
|
|
643
712
|
and proceed directly to human review.
|
|
644
|
-
- **`squash`** (boolean, default `true`) — after `gtd: done
|
|
645
|
-
cycle's `gtd: *` commits into
|
|
646
|
-
`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`.
|
|
647
722
|
- **`models`** — model selection for the subagent-spawning states:
|
|
648
723
|
- `planning` — high-reasoning tier (default `claude-opus-4-8`), used by
|
|
649
724
|
`decompose` (the `grilled`/`planning` states), `grilling`, `agentic-review`,
|
|
650
|
-
and `clean` (the `review`/`squashing` states).
|
|
725
|
+
and `clean` (the `review`/`squashing`/`learning`/`learning-apply` states).
|
|
651
726
|
- `execution` — everyday tier (default `claude-sonnet-4-8`), used by
|
|
652
727
|
`building` and `fixing`.
|
|
653
728
|
- `states.*` — per-state overrides keyed by `decompose`, `grilling`,
|
|
@@ -706,6 +781,7 @@ fixAttemptCap: 3
|
|
|
706
781
|
reviewThreshold: 3
|
|
707
782
|
agenticReview: true
|
|
708
783
|
squash: true
|
|
784
|
+
learning: true
|
|
709
785
|
models:
|
|
710
786
|
planning: claude-opus-4-8
|
|
711
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
|
};
|
|
@@ -367862,6 +367865,10 @@ var makeGitImpl = (executor, root2) => {
|
|
|
367862
367865
|
(hash3) => /^[0-9a-f]{40}$/.test(hash3) ? Effect_exports.succeed(hash3) : Effect_exports.fail(new Error(`Invalid ref: ${ref}`))
|
|
367863
367866
|
)
|
|
367864
367867
|
),
|
|
367868
|
+
readRefOption: (ref) => exec2("git", "rev-parse", "--verify", "--quiet", ref).pipe(
|
|
367869
|
+
Effect_exports.map((s5) => Option_exports.some(s5.trim())),
|
|
367870
|
+
Effect_exports.catchAll(() => Effect_exports.succeed(Option_exports.none()))
|
|
367871
|
+
),
|
|
367865
367872
|
topLevel: () => exec2("git", "rev-parse", "--show-toplevel").pipe(Effect_exports.map((s5) => s5.trim())),
|
|
367866
367873
|
resolveDefaultBranch: () => exec2("git", "rev-parse", "--abbrev-ref", "origin/HEAD").pipe(
|
|
367867
367874
|
Effect_exports.map((s5) => s5.trim()),
|
|
@@ -367995,7 +368002,20 @@ var makeGitImpl = (executor, root2) => {
|
|
|
367995
368002
|
)
|
|
367996
368003
|
);
|
|
367997
368004
|
}).pipe(Effect_exports.asVoid),
|
|
367998
|
-
softResetTo: (ref) => exec2("git", "reset", "--soft", ref).pipe(Effect_exports.asVoid)
|
|
368005
|
+
softResetTo: (ref) => exec2("git", "reset", "--soft", ref).pipe(Effect_exports.asVoid),
|
|
368006
|
+
updateRef: (ref, hash3) => exec2("git", "update-ref", ref, hash3).pipe(Effect_exports.asVoid),
|
|
368007
|
+
deleteRef: (ref) => exec2("git", "update-ref", "-d", ref).pipe(
|
|
368008
|
+
Effect_exports.asVoid,
|
|
368009
|
+
Effect_exports.catchAll(() => Effect_exports.void)
|
|
368010
|
+
),
|
|
368011
|
+
mixedResetTo: (ref) => exec2("git", "reset", "--mixed", ref).pipe(Effect_exports.asVoid),
|
|
368012
|
+
restoreStagedFrom: (source2, paths) => paths.length === 0 ? Effect_exports.void : exec2("git", "restore", "--staged", `--source=${source2}`, "--", ...paths).pipe(
|
|
368013
|
+
Effect_exports.asVoid,
|
|
368014
|
+
// `git restore` errors when a pathspec matches nothing at either
|
|
368015
|
+
// side — for an optional dir like `.gtd/` that's a no-op, not a failure.
|
|
368016
|
+
Effect_exports.catchAll(() => Effect_exports.void)
|
|
368017
|
+
),
|
|
368018
|
+
addIntentToAdd: () => exec2("git", "add", "--intent-to-add", ".").pipe(Effect_exports.asVoid)
|
|
367999
368019
|
};
|
|
368000
368020
|
};
|
|
368001
368021
|
var makeLiveEffect = Effect_exports.gen(function* () {
|
|
@@ -387748,7 +387768,11 @@ var ROUTING_SUBJECT = {
|
|
|
387748
387768
|
done: "gtd: done",
|
|
387749
387769
|
"squash-template": "gtd: squash template",
|
|
387750
387770
|
"health-check": "gtd: health-check",
|
|
387751
|
-
"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"
|
|
387752
387776
|
};
|
|
387753
387777
|
var reviewingSubject = (baseHash) => `gtd: reviewing ${baseHash}`;
|
|
387754
387778
|
var TURN_RE = /^gtd\((human|agent)\): (.+)$/;
|
|
@@ -387761,7 +387785,9 @@ var TURN_GATES = /* @__PURE__ */ new Set([
|
|
|
387761
387785
|
"review",
|
|
387762
387786
|
"squashing",
|
|
387763
387787
|
"health-fixing",
|
|
387764
|
-
"escalate"
|
|
387788
|
+
"escalate",
|
|
387789
|
+
"learning",
|
|
387790
|
+
"learning-apply"
|
|
387765
387791
|
]);
|
|
387766
387792
|
var ROUTING_SUBJECT_TO_PHASE = new Map(
|
|
387767
387793
|
Object.entries(ROUTING_SUBJECT).map(([phase, subject]) => [
|
|
@@ -387801,6 +387827,7 @@ var FEEDBACK_FILE = `${GTD_DIR}/FEEDBACK.md`;
|
|
|
387801
387827
|
var ERRORS_FILE = `${GTD_DIR}/ERRORS.md`;
|
|
387802
387828
|
var HEALTH_FILE = `${GTD_DIR}/HEALTH.md`;
|
|
387803
387829
|
var SQUASH_MSG_FILE = `${GTD_DIR}/SQUASH_MSG.md`;
|
|
387830
|
+
var LEARNINGS_FILE = `${GTD_DIR}/LEARNINGS.md`;
|
|
387804
387831
|
var LEGACY_FEEDBACK_FILE = "FEEDBACK.md";
|
|
387805
387832
|
var emptyFailureSentinel = (command, exitCode3) => `Test command \`${command}\` failed with exit code ${exitCode3} and produced no output.`;
|
|
387806
387833
|
var DONE_SUBJECT = "gtd: done";
|
|
@@ -387809,6 +387836,18 @@ var GATE_OWN_STEERING_FILE = {
|
|
|
387809
387836
|
grilling: TODO_FILE,
|
|
387810
387837
|
review: REVIEW_FILE
|
|
387811
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
|
+
]);
|
|
387812
387851
|
var turnDiffExcludes = (gate) => {
|
|
387813
387852
|
const ownFile = GATE_OWN_STEERING_FILE[gate];
|
|
387814
387853
|
return ownFile ? [...WORKFLOW_FILE_EXCLUDES, `!${ownFile}`] : WORKFLOW_FILE_EXCLUDES;
|
|
@@ -388079,8 +388118,8 @@ var gatherEvents = (invoker) => (
|
|
|
388079
388118
|
let squashBase;
|
|
388080
388119
|
let squashDiff;
|
|
388081
388120
|
const headParsedForSquash = parseSubject(lastCommitSubject);
|
|
388082
|
-
const
|
|
388083
|
-
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)) {
|
|
388084
388123
|
const squashHistory = history;
|
|
388085
388124
|
let lastDoneIdxForSquash = -1;
|
|
388086
388125
|
let prevDoneIdx = -1;
|
|
@@ -388126,11 +388165,13 @@ var gatherEvents = (invoker) => (
|
|
|
388126
388165
|
}
|
|
388127
388166
|
const squashMsgPresent = yield* fs9.exists(resolve5(SQUASH_MSG_FILE));
|
|
388128
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();
|
|
388129
388170
|
const healthPresent = yield* fs9.exists(resolve5(HEALTH_FILE));
|
|
388130
388171
|
const healthContent = healthPresent ? yield* fs9.readFileString(resolve5(HEALTH_FILE)) : "";
|
|
388131
388172
|
const healthCommitted = healthPresent && !isUncommitted(HEALTH_FILE);
|
|
388132
388173
|
let healthFixBase;
|
|
388133
|
-
if (config2.squash) {
|
|
388174
|
+
if (config2.squash || config2.learning) {
|
|
388134
388175
|
let firstHealthCheckHash;
|
|
388135
388176
|
let healthCheckCount = 0;
|
|
388136
388177
|
for (const commit3 of commitEvents) {
|
|
@@ -388204,7 +388245,10 @@ var gatherEvents = (invoker) => (
|
|
|
388204
388245
|
healthPresent,
|
|
388205
388246
|
healthContent,
|
|
388206
388247
|
healthCommitted,
|
|
388207
|
-
...healthFixBase !== void 0 ? { healthFixBase } : {}
|
|
388248
|
+
...healthFixBase !== void 0 ? { healthFixBase } : {},
|
|
388249
|
+
learningEnabled: config2.learning,
|
|
388250
|
+
learningMsgPresent,
|
|
388251
|
+
learningMsgIsTemplate
|
|
388208
388252
|
};
|
|
388209
388253
|
const resolveEvent = { type: "RESOLVE", payload };
|
|
388210
388254
|
return [...commitEvents, resolveEvent];
|
|
@@ -388228,6 +388272,15 @@ var SQUASH_TEMPLATE = [
|
|
|
388228
388272
|
"Longer description of the change, if needed.",
|
|
388229
388273
|
""
|
|
388230
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");
|
|
388231
388284
|
var perform = (action) => (
|
|
388232
388285
|
// fallow-ignore-next-line complexity
|
|
388233
388286
|
Effect_exports.gen(function* () {
|
|
@@ -388262,6 +388315,9 @@ var perform = (action) => (
|
|
|
388262
388315
|
if (action.removeHealth === true) {
|
|
388263
388316
|
yield* fs9.remove(resolve5(HEALTH_FILE)).pipe(Effect_exports.catchAll(() => Effect_exports.void));
|
|
388264
388317
|
}
|
|
388318
|
+
if (action.removeLearning === true) {
|
|
388319
|
+
yield* fs9.remove(resolve5(LEARNINGS_FILE)).pipe(Effect_exports.catchAll(() => Effect_exports.void));
|
|
388320
|
+
}
|
|
388265
388321
|
yield* git.commitAllWithPrefix(action.subject);
|
|
388266
388322
|
return { stop: false };
|
|
388267
388323
|
}
|
|
@@ -388309,6 +388365,14 @@ var perform = (action) => (
|
|
|
388309
388365
|
yield* git.commitAllWithPrefix("gtd: squash template");
|
|
388310
388366
|
return { stop: false };
|
|
388311
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
|
+
}
|
|
388312
388376
|
// Squash: read SQUASH_MSG.md content (the real message authored by the
|
|
388313
388377
|
// squashing turn), rm it, soft-reset to squashBase, commit-all under the
|
|
388314
388378
|
// file's content as the message.
|
|
@@ -388320,10 +388384,11 @@ var perform = (action) => (
|
|
|
388320
388384
|
return { stop: false };
|
|
388321
388385
|
}
|
|
388322
388386
|
// Health check: run tests on an idle/clean tree.
|
|
388323
|
-
// Green, no squash-after chain queued → stop immediately, no
|
|
388324
|
-
//
|
|
388387
|
+
// Green, no learning/squash-after chain queued → stop immediately, no
|
|
388388
|
+
// commit/write.
|
|
388389
|
+
// Green, `chainAfterGreen` → commit routing `gtd: tests green` (the
|
|
388325
388390
|
// observable green marker) and continue — the resolver chains
|
|
388326
|
-
// `writeSquashTemplate` at that HEAD next.
|
|
388391
|
+
// `writeLearningTemplate` or `writeSquashTemplate` at that HEAD next.
|
|
388327
388392
|
// Red below cap → write HEALTH.md, commit routing `gtd: health-check` (the
|
|
388328
388393
|
// always-clean invariant: write-and-commit in the same chain).
|
|
388329
388394
|
// Red at cap → write ERRORS.md, commit routing `gtd: health-check`.
|
|
@@ -388331,7 +388396,7 @@ var perform = (action) => (
|
|
|
388331
388396
|
const runner = yield* TestRunner;
|
|
388332
388397
|
const result = yield* runner.run();
|
|
388333
388398
|
if (result.exitCode === 0) {
|
|
388334
|
-
if (action.
|
|
388399
|
+
if (action.chainAfterGreen) {
|
|
388335
388400
|
yield* git.commitAllWithPrefix("gtd: tests green");
|
|
388336
388401
|
return { stop: false };
|
|
388337
388402
|
}
|
|
@@ -388428,7 +388493,10 @@ var DEFAULT_PAYLOAD = {
|
|
|
388428
388493
|
squashMsgIsTemplate: false,
|
|
388429
388494
|
healthPresent: false,
|
|
388430
388495
|
healthContent: "",
|
|
388431
|
-
healthCommitted: false
|
|
388496
|
+
healthCommitted: false,
|
|
388497
|
+
learningEnabled: false,
|
|
388498
|
+
learningMsgPresent: false,
|
|
388499
|
+
learningMsgIsTemplate: false
|
|
388432
388500
|
};
|
|
388433
388501
|
var buildContext = (p4, counters) => ({
|
|
388434
388502
|
testFixCount: counters.testFixCount,
|
|
@@ -388459,6 +388527,32 @@ var healthFileConflictRules = [
|
|
|
388459
388527
|
message: ".gtd/HEALTH.md + .gtd/ERRORS.md"
|
|
388460
388528
|
}
|
|
388461
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
|
+
];
|
|
388462
388556
|
var isReviewPackagesConflict = (p4) => p4.reviewPresent && p4.packagesPresent;
|
|
388463
388557
|
var isReviewCommittedTodoConflict = (p4) => p4.reviewPresent && p4.todoCommitted;
|
|
388464
388558
|
var isUncommittedReviewWithTodoConflict = (p4) => p4.reviewPresent && !(p4.reviewCommitted || p4.reviewDirty) && p4.todoExists;
|
|
@@ -388483,12 +388577,53 @@ var reviewAndFeedbackRules = [
|
|
|
388483
388577
|
{ isViolated: isErrorsWithoutPackages, message: ".gtd/ERRORS.md without packages" }
|
|
388484
388578
|
];
|
|
388485
388579
|
var assertLegal = (p4) => {
|
|
388486
|
-
for (const rule of [
|
|
388580
|
+
for (const rule of [
|
|
388581
|
+
...healthFileConflictRules,
|
|
388582
|
+
...learningFileConflictRules,
|
|
388583
|
+
...reviewAndFeedbackRules
|
|
388584
|
+
]) {
|
|
388487
388585
|
if (rule.isViolated(p4)) {
|
|
388488
388586
|
throw new GtdStateError("illegal-combination", `illegal combination: ${rule.message}`);
|
|
388489
388587
|
}
|
|
388490
388588
|
}
|
|
388491
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
|
+
};
|
|
388492
388627
|
var classifyHead = (subject, flags) => {
|
|
388493
388628
|
const parsed = parseSubject(subject);
|
|
388494
388629
|
if (parsed.kind === "turn") {
|
|
@@ -388561,6 +388696,8 @@ var classifyHead = (subject, flags) => {
|
|
|
388561
388696
|
// squashBase filled in by the caller
|
|
388562
388697
|
} : { kind: "rest", state: "squashing", actor: "agent" };
|
|
388563
388698
|
}
|
|
388699
|
+
const learningTurn = classifyLearningTurn(actor, gate, flags);
|
|
388700
|
+
if (learningTurn !== null) return learningTurn;
|
|
388564
388701
|
if (actor === "agent" && gate === "health-fixing") {
|
|
388565
388702
|
return {
|
|
388566
388703
|
kind: "mid-chain",
|
|
@@ -388594,12 +388731,7 @@ var classifyHead = (subject, flags) => {
|
|
|
388594
388731
|
action: { kind: "closePackage" }
|
|
388595
388732
|
} : { kind: "rest", state: "agentic-review", actor: "agent" };
|
|
388596
388733
|
}
|
|
388597
|
-
return flags
|
|
388598
|
-
kind: "mid-chain",
|
|
388599
|
-
state: "testing",
|
|
388600
|
-
actor: "agent",
|
|
388601
|
-
action: { kind: "writeSquashTemplate" }
|
|
388602
|
-
} : { kind: "rest", state: "idle", actor: "human" };
|
|
388734
|
+
return nextAfterReviewOrLearning(flags, "testing", false);
|
|
388603
388735
|
case "errors":
|
|
388604
388736
|
return flags.errorsPresent ? { kind: "rest", state: "escalate", actor: "human" } : { kind: "rest", state: "fixing", actor: "agent" };
|
|
388605
388737
|
case "package-done":
|
|
@@ -388609,16 +388741,19 @@ var classifyHead = (subject, flags) => {
|
|
|
388609
388741
|
case "review-feedback":
|
|
388610
388742
|
return { kind: "rest", state: "grilling", actor: "agent" };
|
|
388611
388743
|
case "done":
|
|
388612
|
-
return flags
|
|
388613
|
-
kind: "mid-chain",
|
|
388614
|
-
state: "done",
|
|
388615
|
-
actor: "agent",
|
|
388616
|
-
action: { kind: "writeSquashTemplate" }
|
|
388617
|
-
} : { kind: "rest", state: "idle", actor: "human" };
|
|
388744
|
+
return nextAfterReviewOrLearning(flags, "done", false);
|
|
388618
388745
|
case "squash-template":
|
|
388619
388746
|
return { kind: "rest", state: "squashing", actor: "agent" };
|
|
388620
388747
|
case "reviewing":
|
|
388621
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);
|
|
388622
388757
|
case "health-check":
|
|
388623
388758
|
return flags.errorsPresent ? { kind: "rest", state: "escalate", actor: "human" } : { kind: "rest", state: "health-fixing", actor: "agent" };
|
|
388624
388759
|
case "health-fix":
|
|
@@ -388636,18 +388771,24 @@ var STATE_IS_OWN_GATE = /* @__PURE__ */ new Set([
|
|
|
388636
388771
|
"review",
|
|
388637
388772
|
"squashing",
|
|
388638
388773
|
"health-fixing",
|
|
388639
|
-
"escalate"
|
|
388774
|
+
"escalate",
|
|
388775
|
+
"learning",
|
|
388776
|
+
"learning-apply"
|
|
388640
388777
|
]);
|
|
388641
|
-
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";
|
|
388642
388782
|
var INERT_EMPTY_AGENT_GATES = /* @__PURE__ */ new Set([
|
|
388643
388783
|
"grilling",
|
|
388644
388784
|
"grilled",
|
|
388645
388785
|
"building",
|
|
388646
388786
|
"fixing",
|
|
388647
388787
|
"agentic-review",
|
|
388648
|
-
"review"
|
|
388788
|
+
"review",
|
|
388789
|
+
"learning-apply"
|
|
388649
388790
|
]);
|
|
388650
|
-
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);
|
|
388651
388792
|
var resolveBaseline = (p4, counters, head7, corrupt, lastTurn) => {
|
|
388652
388793
|
const headIsFixerTurn = (() => {
|
|
388653
388794
|
const parsed = parseSubject(head7);
|
|
@@ -388676,7 +388817,6 @@ var resolveBaseline = (p4, counters, head7, corrupt, lastTurn) => {
|
|
|
388676
388817
|
action: { kind: "closePackage" }
|
|
388677
388818
|
} : { kind: "rest", state: "fixing", actor: "agent" };
|
|
388678
388819
|
}
|
|
388679
|
-
const squashAfterGreen = p4.squashEnabled && counters.healthFixCount > 0 && p4.healthFixBase !== void 0;
|
|
388680
388820
|
const reviewSubstantive = p4.headTurnReviewSubstantive !== void 0 ? p4.headTurnReviewSubstantive : p4.reviewDirty && !p4.reviewCheckboxOnly;
|
|
388681
388821
|
const flags = {
|
|
388682
388822
|
headTurnIsEmpty: p4.headTurnIsEmpty,
|
|
@@ -388684,7 +388824,8 @@ var resolveBaseline = (p4, counters, head7, corrupt, lastTurn) => {
|
|
|
388684
388824
|
agenticReviewForceApproved: forceApprove,
|
|
388685
388825
|
squashEnabled: p4.squashEnabled,
|
|
388686
388826
|
hasSquashBase: p4.squashBase !== void 0,
|
|
388687
|
-
|
|
388827
|
+
learningEnabled: p4.learningEnabled,
|
|
388828
|
+
learningMsgIsTemplate: p4.learningMsgIsTemplate,
|
|
388688
388829
|
reviewSubstantive,
|
|
388689
388830
|
// A pending (uncommitted) deletion of ERRORS.md still counts as "ERRORS.md
|
|
388690
388831
|
// was committed at this HEAD" for classification purposes: `fs.exists`
|
|
@@ -388722,7 +388863,7 @@ var resolveBaseline = (p4, counters, head7, corrupt, lastTurn) => {
|
|
|
388722
388863
|
kind: "runHealthCheck",
|
|
388723
388864
|
errorCount: counters.healthFixCount,
|
|
388724
388865
|
capReached: counters.healthFixCount >= p4.fixAttemptCap,
|
|
388725
|
-
|
|
388866
|
+
chainAfterGreen: classified.action.chainAfterGreen
|
|
388726
388867
|
}
|
|
388727
388868
|
};
|
|
388728
388869
|
}
|
|
@@ -388791,7 +388932,7 @@ var applyTurnTaking = (p4, counters, head7, baseline) => {
|
|
|
388791
388932
|
}
|
|
388792
388933
|
const healthCheckCapReached = head7 === "gtd: health-check" && counters.healthFixCount >= p4.fixAttemptCap;
|
|
388793
388934
|
if (head7 === "gtd: health-fix" && baseline.state === "idle" || healthCheckCapReached && baseline.state === "health-fixing") {
|
|
388794
|
-
const
|
|
388935
|
+
const chainAfterGreenAtHealthFix = (p4.squashEnabled || p4.learningEnabled) && counters.healthFixCount > 0 && p4.healthFixBase !== void 0;
|
|
388795
388936
|
return {
|
|
388796
388937
|
state: "idle",
|
|
388797
388938
|
actor: "agent",
|
|
@@ -388800,7 +388941,7 @@ var applyTurnTaking = (p4, counters, head7, baseline) => {
|
|
|
388800
388941
|
kind: "runHealthCheck",
|
|
388801
388942
|
errorCount: counters.healthFixCount,
|
|
388802
388943
|
capReached: counters.healthFixCount >= p4.fixAttemptCap,
|
|
388803
|
-
|
|
388944
|
+
chainAfterGreen: chainAfterGreenAtHealthFix
|
|
388804
388945
|
},
|
|
388805
388946
|
context: context10
|
|
388806
388947
|
};
|
|
@@ -388815,7 +388956,7 @@ var applyTurnTaking = (p4, counters, head7, baseline) => {
|
|
|
388815
388956
|
};
|
|
388816
388957
|
}
|
|
388817
388958
|
if (baseline.state === "idle" && invoker === "human") {
|
|
388818
|
-
const
|
|
388959
|
+
const chainAfterGreen = (p4.squashEnabled || p4.learningEnabled) && counters.healthFixCount > 0 && p4.healthFixBase !== void 0;
|
|
388819
388960
|
return {
|
|
388820
388961
|
state: "idle",
|
|
388821
388962
|
actor: "human",
|
|
@@ -388824,7 +388965,7 @@ var applyTurnTaking = (p4, counters, head7, baseline) => {
|
|
|
388824
388965
|
kind: "runHealthCheck",
|
|
388825
388966
|
errorCount: counters.healthFixCount,
|
|
388826
388967
|
capReached: counters.healthFixCount >= p4.fixAttemptCap,
|
|
388827
|
-
|
|
388968
|
+
chainAfterGreen
|
|
388828
388969
|
},
|
|
388829
388970
|
context: context10
|
|
388830
388971
|
};
|
|
@@ -389399,6 +389540,15 @@ var await_review_default = '<%~ include("@header") %>\n\n`.gtd/REVIEW.md` holds
|
|
|
389399
389540
|
// src/prompts/squashing.md
|
|
389400
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';
|
|
389401
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
|
+
|
|
389402
389552
|
// src/prompts/escalate.md
|
|
389403
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';
|
|
389404
389554
|
|
|
@@ -389415,6 +389565,9 @@ var PROMPT_STATES = /* @__PURE__ */ new Set([
|
|
|
389415
389565
|
"review",
|
|
389416
389566
|
"await-review",
|
|
389417
389567
|
"squashing",
|
|
389568
|
+
"learning",
|
|
389569
|
+
"await-learning-review",
|
|
389570
|
+
"learning-apply",
|
|
389418
389571
|
"escalate",
|
|
389419
389572
|
"idle",
|
|
389420
389573
|
"health-fixing"
|
|
@@ -389428,7 +389581,9 @@ var MODEL_STATE = {
|
|
|
389428
389581
|
"health-fixing": "fixing",
|
|
389429
389582
|
"agentic-review": "agentic-review",
|
|
389430
389583
|
review: "clean",
|
|
389431
|
-
squashing: "clean"
|
|
389584
|
+
squashing: "clean",
|
|
389585
|
+
learning: "clean",
|
|
389586
|
+
"learning-apply": "clean"
|
|
389432
389587
|
};
|
|
389433
389588
|
var builtinResolveModel = (state) => builtinTierDefault[stateTier[state]];
|
|
389434
389589
|
var fenceFor = (content) => {
|
|
@@ -389452,6 +389607,9 @@ eta.loadTemplate("@agentic-review", agentic_review_default);
|
|
|
389452
389607
|
eta.loadTemplate("@review", review_default);
|
|
389453
389608
|
eta.loadTemplate("@await-review", await_review_default);
|
|
389454
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);
|
|
389455
389613
|
eta.loadTemplate("@escalate", escalate_default);
|
|
389456
389614
|
eta.loadTemplate("@idle", idle_default);
|
|
389457
389615
|
eta.readFile = null;
|
|
@@ -389464,6 +389622,9 @@ var STATE_TEMPLATE = {
|
|
|
389464
389622
|
review: "@review",
|
|
389465
389623
|
"await-review": "@await-review",
|
|
389466
389624
|
squashing: "@squashing",
|
|
389625
|
+
learning: "@learning",
|
|
389626
|
+
"await-learning-review": "@await-learning-review",
|
|
389627
|
+
"learning-apply": "@learning-apply",
|
|
389467
389628
|
escalate: "@escalate",
|
|
389468
389629
|
idle: "@idle",
|
|
389469
389630
|
"health-fixing": "@health-fixing"
|
|
@@ -389493,6 +389654,78 @@ var buildPrompt = (result, resolveModel = builtinResolveModel, output = "plain")
|
|
|
389493
389654
|
return raw.replace(/\n{3,}/g, "\n\n").trimEnd() + "\n";
|
|
389494
389655
|
};
|
|
389495
389656
|
|
|
389657
|
+
// src/ReviewWindow.ts
|
|
389658
|
+
var REVIEW_HEAD_REF = "refs/gtd/review-head";
|
|
389659
|
+
var REVIEW_BASE_REF = "refs/gtd/review-base";
|
|
389660
|
+
var AWAITING_REVIEW_SUBJECT = ROUTING_SUBJECT["awaiting-review"];
|
|
389661
|
+
var subjectOf2 = (message) => message.split("\n")[0] ?? "";
|
|
389662
|
+
var reviewWindowBase = (history) => {
|
|
389663
|
+
const beforeHead = history.slice(0, -1);
|
|
389664
|
+
let lastDoneIdx = -1;
|
|
389665
|
+
for (let i = 0; i < beforeHead.length; i++) {
|
|
389666
|
+
if (subjectOf2(beforeHead[i].message) === ROUTING_SUBJECT.done) lastDoneIdx = i;
|
|
389667
|
+
}
|
|
389668
|
+
const currentCycle = beforeHead.slice(lastDoneIdx + 1);
|
|
389669
|
+
let anchor;
|
|
389670
|
+
let lastAwaitingReview;
|
|
389671
|
+
let firstGrilling;
|
|
389672
|
+
for (const c7 of currentCycle) {
|
|
389673
|
+
const parsed = parseSubject(subjectOf2(c7.message));
|
|
389674
|
+
if (parsed.kind === "routing" && parsed.phase === "reviewing" && parsed.param !== void 0) {
|
|
389675
|
+
anchor = parsed.param;
|
|
389676
|
+
}
|
|
389677
|
+
if (parsed.kind === "routing" && parsed.phase === "awaiting-review") {
|
|
389678
|
+
lastAwaitingReview = c7.hash;
|
|
389679
|
+
}
|
|
389680
|
+
if (parsed.kind === "turn" && parsed.gate === "grilling" && firstGrilling === void 0) {
|
|
389681
|
+
firstGrilling = c7.hash;
|
|
389682
|
+
}
|
|
389683
|
+
}
|
|
389684
|
+
return anchor ?? lastAwaitingReview ?? firstGrilling;
|
|
389685
|
+
};
|
|
389686
|
+
var closeReviewWindow = Effect_exports.gen(
|
|
389687
|
+
function* () {
|
|
389688
|
+
const git = yield* GitService;
|
|
389689
|
+
const savedHead = yield* git.readRefOption(REVIEW_HEAD_REF);
|
|
389690
|
+
if (Option_exports.isNone(savedHead)) return { closed: false };
|
|
389691
|
+
const base = yield* git.readRefOption(REVIEW_BASE_REF);
|
|
389692
|
+
if (Option_exports.isSome(base)) {
|
|
389693
|
+
const onReviewedBranch = yield* git.isAncestor(base.value, "HEAD");
|
|
389694
|
+
if (!onReviewedBranch) {
|
|
389695
|
+
return yield* Effect_exports.fail(
|
|
389696
|
+
new Error(
|
|
389697
|
+
"a gtd review checkout window is open but HEAD has moved off the reviewed branch \u2014 return to it, or restore manually with `git reset --mixed refs/gtd/review-head && git update-ref -d refs/gtd/review-head && git update-ref -d refs/gtd/review-base`"
|
|
389698
|
+
)
|
|
389699
|
+
);
|
|
389700
|
+
}
|
|
389701
|
+
}
|
|
389702
|
+
yield* git.mixedResetTo(REVIEW_HEAD_REF);
|
|
389703
|
+
yield* git.deleteRef(REVIEW_HEAD_REF);
|
|
389704
|
+
yield* git.deleteRef(REVIEW_BASE_REF);
|
|
389705
|
+
return { closed: true };
|
|
389706
|
+
}
|
|
389707
|
+
);
|
|
389708
|
+
var openReviewWindow = Effect_exports.gen(
|
|
389709
|
+
function* () {
|
|
389710
|
+
const git = yield* GitService;
|
|
389711
|
+
const hasCommits = yield* git.hasCommits();
|
|
389712
|
+
if (!hasCommits) return { opened: false };
|
|
389713
|
+
const subject = yield* git.lastCommitSubject();
|
|
389714
|
+
if (subject !== AWAITING_REVIEW_SUBJECT) return { opened: false };
|
|
389715
|
+
const history = yield* git.commitHistory();
|
|
389716
|
+
const base = reviewWindowBase(history);
|
|
389717
|
+
if (base === void 0) return { opened: false };
|
|
389718
|
+
const headHash = yield* git.resolveRef("HEAD");
|
|
389719
|
+
if (base === headHash) return { opened: false };
|
|
389720
|
+
yield* git.updateRef(REVIEW_BASE_REF, base);
|
|
389721
|
+
yield* git.updateRef(REVIEW_HEAD_REF, headHash);
|
|
389722
|
+
yield* git.mixedResetTo(base);
|
|
389723
|
+
yield* git.restoreStagedFrom(REVIEW_HEAD_REF, [".gtd"]);
|
|
389724
|
+
yield* git.addIntentToAdd();
|
|
389725
|
+
return { opened: true };
|
|
389726
|
+
}
|
|
389727
|
+
);
|
|
389728
|
+
|
|
389496
389729
|
// src/State.ts
|
|
389497
389730
|
var edgeActionHandlers = {
|
|
389498
389731
|
captureTurn: (a5) => `capture the ${a5.actor} turn as "gtd(${a5.actor}): ${a5.gate}"`,
|
|
@@ -389503,6 +389736,7 @@ var edgeActionHandlers = {
|
|
|
389503
389736
|
if (a5.removeReview) removed.push(".gtd/REVIEW.md");
|
|
389504
389737
|
if (a5.removeFeedback) removed.push(".gtd/FEEDBACK.md");
|
|
389505
389738
|
if (a5.removeHealth) removed.push(".gtd/HEALTH.md");
|
|
389739
|
+
if (a5.removeLearning) removed.push(".gtd/LEARNINGS.md");
|
|
389506
389740
|
if (removed.length > 0) msg += ` (removing ${removed.join(", ")})`;
|
|
389507
389741
|
return msg;
|
|
389508
389742
|
},
|
|
@@ -389510,7 +389744,8 @@ var edgeActionHandlers = {
|
|
|
389510
389744
|
closePackage: () => "close the active package",
|
|
389511
389745
|
writeSquashTemplate: () => "write the squash message template",
|
|
389512
389746
|
squashCommit: (a5) => `squash the cycle onto ${a5.squashBase}`,
|
|
389513
|
-
|
|
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" : ""})`
|
|
389514
389749
|
};
|
|
389515
389750
|
var describeEdgeAction = (a5) => edgeActionHandlers[a5.kind](a5);
|
|
389516
389751
|
var describeStatus = (prediction) => ({
|
|
@@ -389807,9 +390042,13 @@ function makeProgram(opts = {}) {
|
|
|
389807
390042
|
const git = yield* GitService;
|
|
389808
390043
|
const fs9 = yield* FileSystem_exports.FileSystem;
|
|
389809
390044
|
yield* assertRunningFromRepoRoot(git, fs9);
|
|
390045
|
+
yield* closeReviewWindow;
|
|
389810
390046
|
yield* (yield* ConfigInit).ensure;
|
|
389811
390047
|
const config2 = yield* ConfigService;
|
|
389812
|
-
yield* dispatchKnownSubcommand(sub, argv, git, config2, json2, write4)
|
|
390048
|
+
yield* dispatchKnownSubcommand(sub, argv, git, config2, json2, write4).pipe(
|
|
390049
|
+
Effect_exports.tap(() => openReviewWindow),
|
|
390050
|
+
Effect_exports.tapError(() => openReviewWindow.pipe(Effect_exports.ignore))
|
|
390051
|
+
);
|
|
389813
390052
|
}).pipe(
|
|
389814
390053
|
json2 ? Effect_exports.catchAll(
|
|
389815
390054
|
(error) => Effect_exports.sync(
|
package/package.json
CHANGED