tldr-experts 0.30.0 → 0.31.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/CHANGELOG.md +198 -0
- package/README.md +1 -0
- package/dist/hooks/answer-capture.js +9 -8
- package/dist/hooks/budget-gate.js +9 -9
- package/dist/hooks/{chunk-fbmj1bk6.js → chunk-04kpbhvk.js} +3 -3
- package/dist/hooks/{chunk-pne7afnf.js → chunk-27v2rwa9.js} +1 -1
- package/dist/hooks/{chunk-przta0a0.js → chunk-3r0hhgcf.js} +7 -6
- package/dist/hooks/{chunk-857jhjmb.js → chunk-5kv2vtha.js} +1 -1
- package/dist/hooks/{chunk-7xascvee.js → chunk-72et1xzx.js} +1 -1
- package/dist/hooks/{chunk-0d4csx4s.js → chunk-8ds2ret8.js} +1 -1
- package/dist/hooks/{chunk-qmp5p77c.js → chunk-9bd6b3xf.js} +1 -0
- package/dist/hooks/chunk-ae6bkfs5.js +0 -0
- package/dist/hooks/{chunk-77x6v0gg.js → chunk-akemhezh.js} +3 -2
- package/dist/hooks/{chunk-gr83pq7x.js → chunk-f9d2efhb.js} +3 -3
- package/dist/hooks/{chunk-zpch8e2j.js → chunk-me0kzc6k.js} +2 -2
- package/dist/hooks/{chunk-mg3aj0sa.js → chunk-q1ge3nex.js} +1 -1
- package/dist/hooks/{chunk-yanmz0vz.js → chunk-x1f4dxwk.js} +1 -1
- package/dist/hooks/{chunk-g4d2v4jc.js → chunk-yyhwf3bp.js} +1 -1
- package/dist/hooks/{chunk-z9hv47ps.js → chunk-zyz0fbz5.js} +1 -1
- package/dist/hooks/claim-sources.js +5 -5
- package/dist/hooks/dod-gate.js +7 -7
- package/dist/hooks/no-reask.js +8 -8
- package/dist/hooks/session-start.js +13 -12
- package/dist/hooks/statusline.js +9 -8
- package/dist/tldrx.js +1234 -827
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/stages/how/stage.md +0 -1
- package/stages/how/stage.yml +31 -2
- package/workflows/bugfix.yml +5 -1
- package/workflows/feature.yml +5 -1
- package/workflows/integration.yml +5 -1
- package/workflows/performance.yml +5 -1
- package/workflows/refactor.yml +5 -1
- package/workflows/upgrade.yml +5 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,203 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.31.0 — 2026-09-16
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **A `[src:]` citation on a Watch card that only has a punctuation slip — the marker missing its
|
|
8
|
+
space, a token sitting mid-sentence, an ASCII `->` in place of the real arrow — is repaired
|
|
9
|
+
locally, for $0.00, before the card is judged, instead of failing the stage over formatting a
|
|
10
|
+
script already knew how to fix (#345, watch-card half). Measured over two field audits: 10 of 54
|
|
11
|
+
failed tasks across 22 runs in one workspace were malformed watch cards — caught only after a
|
|
12
|
+
full paid turn wrote the card, by the same `parseWatcherCard` this repair now runs ahead of.
|
|
13
|
+
`repairSrcSyntax` (`src/core/text/srcToken.ts`) only accepts a fix it can VERIFY
|
|
14
|
+
re-parses clean (mirrors `parseYamlRepairing`'s own rule) and only touches the three rules that
|
|
15
|
+
are pure syntax — `marker-spelling`, `trailing-position`, `cmd-arrow` — never a rule that would
|
|
16
|
+
need an invented line number, path or fact id (AGENTS.md §7). The repair is written back to disk
|
|
17
|
+
whether or not the card ends up valid, and it is never silent: named in the stage's own report
|
|
18
|
+
when it clears the card, and in the failure reason when a genuine defect remains — the file on
|
|
19
|
+
disk already carries the fix, so a retry's `previousCard` prompt (`watchPrompt.ts`) shows a writer
|
|
20
|
+
only the part a script could not repair (owner decision 2026-09-15: auto-repair is visible, never
|
|
21
|
+
silent).
|
|
22
|
+
|
|
23
|
+
- **`how` is skipped when the seed already declares its own technical solution, and `plan` reads
|
|
24
|
+
that section instead (#346).** Owner decision, measured against three samples where `how`
|
|
25
|
+
reworked a seed that already carried the answer: 11.4-45% of a run's spend and 43-53% of its
|
|
26
|
+
own bytes went unread downstream. The trigger is one exact, documented marker — an H2 `##
|
|
27
|
+
Solution` or `## Technical approach` in a seed document — never inferred from prose:
|
|
28
|
+
`src/core/facilitator/seedSolution.ts` reuses `seed/seedClaims.ts`'s fence-aware heading reader
|
|
29
|
+
rather than a second regex, and exposes it to the existing `skip_if` grammar as a new
|
|
30
|
+
`seed_solution` predicate (`skipIf.ts`, `(stories|repos|questions|seed_solution)<op>N`). Since no
|
|
31
|
+
shipped `workflows/*.yml` uses the §2.4 record shape a workflow-level `skip_if` needs, a stage's
|
|
32
|
+
own top-level `skip_if:` in `stage.yml` is now read as its built-in default when the workflow
|
|
33
|
+
names none (`stageSpec.ts`'s `overlay`, a workflow's own `skip_if` for that stage id still wins);
|
|
34
|
+
the shipped `stages/how/stage.yml` sets `skip_if: "seed_solution==1"` this way. The skip is
|
|
35
|
+
recorded exactly like any other `skip_if` (`stage.skipped`, named on the run), and — because this
|
|
36
|
+
is the one skip that would otherwise leave `plan` reading a `02-how/design.md` that silently
|
|
37
|
+
looks empty — `tldrx next` additionally materialises that file from the seed's declared section
|
|
38
|
+
verbatim, cited back to the seed, the moment the skip fires.
|
|
39
|
+
|
|
40
|
+
- **A failed sub-agent turn now carries a named `failure_kind`** — `timeout`, `rate_limit`
|
|
41
|
+
(reusing #298's own quota-frame detection), `process_killed`, `empty_result`, `non_zero_exit`,
|
|
42
|
+
`result_error`, `malformed_result`, or `unclassified` (with the raw signal still in `error`) —
|
|
43
|
+
on the task row and the `agent.result` event, additive and absent on every ordinary/successful
|
|
44
|
+
turn and on a read-cap kill (`stopped_by` already names that one). `result_error` is
|
|
45
|
+
`non_zero_exit`'s exitCode-0 sibling (pre-merge review, 2026-09-15): the result document itself
|
|
46
|
+
reports `is_error: true` with a named reason while the process exited `0`, which used to read
|
|
47
|
+
`non_zero_exit` — a label contradicting its own exit code. Measured, one field audit (workspace
|
|
48
|
+
B, 2026-09-15): 24 of 54 failed tasks in that sample were an undifferentiated "timeout / generic
|
|
49
|
+
error" — the largest single bucket, unnamed until now. Classification only: no new retry
|
|
50
|
+
budgets, and nothing decides a retry off this field (#348, the family of #341/#298).
|
|
51
|
+
|
|
52
|
+
### Changed
|
|
53
|
+
|
|
54
|
+
- **`watch` now follows `build`'s gate policy in every shipped scope where `build` is already
|
|
55
|
+
`auto` — `feature`, `bugfix`, `integration`, `refactor` and `performance` (#349, owner decision
|
|
56
|
+
2026-09-16).** Every one of these scopes shipped `build: auto` with `watch: human` regardless,
|
|
57
|
+
so a run that trusted Build's own auto-gate still stopped a person at the very next stage over
|
|
58
|
+
a transcription job with a validator behind it. The reasoning is field evidence, not a guess:
|
|
59
|
+
auto-gating `what`/`how`/`plan` in a real workspace since 2026-09-12 produced zero measured
|
|
60
|
+
auto-gate incidents across 26 runs (77 `gate.rejected`, 100% human, 0 auto-rejections). The
|
|
61
|
+
mechanism is unchanged — `evaluateAutoGate` (`src/core/run/autoGate.ts`) already closes any
|
|
62
|
+
stage's gate the same way once its policy is `auto`, and a self-signed `watch` gate is
|
|
63
|
+
announced through the exact same `gate.requested`/`gate.approved`/`stage.done` events an
|
|
64
|
+
auto-signed `what`/`how`/`plan` gate already is — this does not widen the notify-window gap
|
|
65
|
+
tracked separately in #250, it only extends the existing behavior to one more stage. `upgrade`
|
|
66
|
+
is the one shipped scope excluded: `what`/`plan`/`build` are already all `auto` there, and
|
|
67
|
+
following `build` would leave it with no human gate at all, which spec.md's "no all-auto
|
|
68
|
+
preset" guarantee forbids — its `watch` stays `human`. `hotfix`/`security-patch`/`migration`
|
|
69
|
+
are unaffected: their `build` gate is `human`, so the "build already signed" condition never
|
|
70
|
+
applies. The tutorial's attended chapter (`tldrx learn`, chapter 7) ran its `next --commit` on
|
|
71
|
+
a `feature`-scope run expecting the Watch gate to still stop it (`expectExit: [4]`) — now that
|
|
72
|
+
`watch` self-signs there, the chapter sets it back to `human` explicitly first
|
|
73
|
+
(`run gates set watch:human --note …`), because the lesson is the attended human handoff, not
|
|
74
|
+
the shipped default.
|
|
75
|
+
|
|
76
|
+
- **`how`'s default model is `sonnet`, not `opus`** (#346). Owner decision, measured across a
|
|
77
|
+
single-run analysis and two workspace audits: `how` cost $10.40-$269.90 per sample, 11.4-45% of
|
|
78
|
+
the run's total spend. A workspace or a single invocation that wants the strong model back
|
|
79
|
+
overrides it exactly as before — `.tldrx/stages/how/stage.yml` with `model: opus`, or
|
|
80
|
+
`tldrx next --model opus` / `tldrx run auto --model opus` for one invocation.
|
|
81
|
+
|
|
82
|
+
- **`how` stops generating `risks.md`** (#350). Owner decision 2026-09-16 — "stop generating,"
|
|
83
|
+
not "generate and drop from the bundle" — because nothing downstream ever read it: measured
|
|
84
|
+
on a real run, `risks.md` (8,025 bytes) was excluded by `stages/plan/stage.yml`'s own
|
|
85
|
+
`inputs:` (only `design.md`, `contracts.md`, `test-strategy.md`) and a repo-wide grep found no
|
|
86
|
+
other reader. `handoff.md` and `questions.md` are unchanged — they carry no bundle content
|
|
87
|
+
either, but they are load-bearing elsewhere (the auto gate, `claim-sources`, `boundary`'s
|
|
88
|
+
`SURFACE_HANDOFFS`, the dashboard). `validateOutputs` only ever checks the DECLARED output
|
|
89
|
+
list, so a run directory written before this change that still has `02-how/risks.md` on disk
|
|
90
|
+
is unaffected — the file is simply not asked for anymore, never flagged as missing or
|
|
91
|
+
re-demanded on resume.
|
|
92
|
+
|
|
93
|
+
### Fixed
|
|
94
|
+
|
|
95
|
+
- **A headless turn whose parent `tldrx` process is SIGKILL-class killed mid-spawn now banks its
|
|
96
|
+
cost as unmetered rather than nowhere at all (#337, the remaining half of #246).** #246's field
|
|
97
|
+
case: a `run auto` process died while blocked in `spawnAgent`'s `await` (`runNext.ts`); the
|
|
98
|
+
orphaned `claude` child kept running to completion, but `run.yml`'s `budget.spent_usd` stayed
|
|
99
|
+
`0.00` forever, because `demoteStaleRunning` — the code that finds the dead `.lock` and puts the
|
|
100
|
+
stage back to `ready` — wrote no task row for that attempt at all, not even an unmetered one. A
|
|
101
|
+
confident `0.00` for money a provider may really have charged is the one answer AGENTS.md §7
|
|
102
|
+
rules out. `demoteStaleRunning` now reads `startedHeadless` (`run/lastStart.ts`, the one
|
|
103
|
+
derivation of which mode opened a stage's last turn — already used by the Ctrl-C path) and, for
|
|
104
|
+
a genuinely orphaned HEADLESS spawn (never a `--prepare` bundle waiting for a human, and never a
|
|
105
|
+
Build executor phase, both of which are `preparedRefusal`'s and the executor's own business),
|
|
106
|
+
records a `status: "failed"` task with `cost_usd: null, metered: false` and
|
|
107
|
+
`error: "turn outlived its parent; no result line was read"` before demoting the stage — so
|
|
108
|
+
`spendBasis`/`tallyOf` (the one derivation, unchanged) count it as a LOWER BOUND, and `run
|
|
109
|
+
status`/`budget show`/the dashboard say so instead of printing a silent `$0.00`.
|
|
110
|
+
|
|
111
|
+
- **`run auto` now names `--wait-gates` as the fix, at the moment an all-`auto` gate's only
|
|
112
|
+
blocking questions are answered but nothing will sign it (#342).** Measured live on a
|
|
113
|
+
`--gates none --questions none` run launched with no `--wait-gates`/`--wait-answers`: the
|
|
114
|
+
loop answers a blocking question itself (`questions_policy: recommended`) or once
|
|
115
|
+
`--wait-answers` polls one in, but the ONLY thing that ever self-closes a parked `auto`
|
|
116
|
+
gate is `selfCloseAutoGate`, reached only from `waitForGate`'s poll — so the next `next`
|
|
117
|
+
call reports the stage as `awaiting_gate` with a generic `gate pending: tldrx approve`,
|
|
118
|
+
never saying the gate would have closed itself with one more flag. `settleDeferredGate`
|
|
119
|
+
(`runAuto.ts`) now says so, by name, at the exact moment the gap is decided. The deeper fix
|
|
120
|
+
— `next` re-evaluating a parked `auto` gate on its own, so this holds even for a `next`
|
|
121
|
+
launched by hand — is recommendation (1) on the issue and stays open there; it touches
|
|
122
|
+
`runNext.ts`, out of scope for this change.
|
|
123
|
+
|
|
124
|
+
- **The base-tree DoD refusal now names the workspace's own declared `install:` as the fix
|
|
125
|
+
(#343).** Measured on a fresh clone where a multi-step installer had only partly run: the
|
|
126
|
+
refusal reported `eslint`/`tsc`/`vitest` all `command not found`, identical in shape to a
|
|
127
|
+
genuinely broken repo, even though the same `WorkspaceContext` the refusal already reads
|
|
128
|
+
carries the workspace's own `install:` line. `baseRefusalLines` (`preflight.ts`) now names
|
|
129
|
+
it, once per repo — never runs it: running an installer against the operator's own
|
|
130
|
+
checkout, unasked, ahead of a refusal that has not yet told them anything, is exactly the
|
|
131
|
+
side effect the base-measurement design already avoids for gate commands. The zero-touch
|
|
132
|
+
first-run guide (EN/ES) now says explicitly to run the declared `install:` in the checkout
|
|
133
|
+
itself before the first `run auto`, not only in a story's worktree.
|
|
134
|
+
|
|
135
|
+
- **`run status` now warns NO-RETRY on a phase that cannot afford a second attempt of its own
|
|
136
|
+
stage, not only `budget show` (#232).** The narrowed #232 asked for this at both screens;
|
|
137
|
+
`budget show` shipped it in `bd19763`/`efb4eee` and this closes the other half. `run status`
|
|
138
|
+
computed no retry verdict at all, so a pre-#170 run (sized for exactly one attempt) read every
|
|
139
|
+
phase as an ordinary progress bar right up to the refusal — the exact "operator discovers it at
|
|
140
|
+
the retry" failure the issue is about, just on the screen that gets opened more often. Shares
|
|
141
|
+
the one `retrySizing` derivation and the one `NO-RETRY` sentence (`noRetryBlock`, now exported
|
|
142
|
+
from `budgetView.ts`) that `budget show` already used, so the two screens cannot disagree about
|
|
143
|
+
the same measured shortfall. `buildStatus` takes an optional `root` (both CLI and `run auto`'s
|
|
144
|
+
heartbeat now pass it) to resolve the next stage's own `attempts:` the same tolerant way
|
|
145
|
+
`budget show` does; omitted, it falls back to the shipped default, so a caller that does not pass
|
|
146
|
+
it behaves exactly as before.
|
|
147
|
+
|
|
148
|
+
- **A fix list dispositioned away from `fix-now` by hand, after the story already parked `review`
|
|
149
|
+
behind it, now settles `done` with no agent spawned instead of buying a fresh developer round and
|
|
150
|
+
a full DoD re-run for nothing (#218).** Measured live: a reviewer signed `fixlist` with an open
|
|
151
|
+
finding, parking the story at `review`; the finding was later re-routed away from `fix-now`
|
|
152
|
+
outside the audited auto-close (which only ever closes what a spawned reviewer's approve was
|
|
153
|
+
shown); nothing else re-read the file, so the next `--prepare`/headless pass read `fixlistFor`'s
|
|
154
|
+
unnamed door returning `null` (0 open — correctly, it is not to be re-rendered) as "no fix list
|
|
155
|
+
ever happened" and dispatched a plain developer bundle for a story nothing faulted — one
|
|
156
|
+
developer task and one full DoD re-run over an unchanged tree. `closedFixlistCandidates` /
|
|
157
|
+
`settleClosedFixlists` (gh #329's pre-pass) now also recognizes a `review` story parked on a spent
|
|
158
|
+
`fixlist` verdict, alongside the `blocked`/`approve` shape it already settled, and asks
|
|
159
|
+
`openFixNow` before either. `--fixlist <path>` naming a file with 0 open findings is now a refusal
|
|
160
|
+
that names the file and the count, not a silent downgrade to a bundle.
|
|
161
|
+
|
|
162
|
+
- **A fix list the parser could not fully read — a typo'd `Disposition:` word, or a round file
|
|
163
|
+
emptied by a crash or a disk-full write — can no longer settle a story `done` (#218, pre-merge
|
|
164
|
+
review).** Reviewer-measured: `**fix-now**` mistyped `**fix-noww**` is silently dropped by
|
|
165
|
+
`parseFixlistFile` (by design — a heading with no readable disposition is not a finding, and
|
|
166
|
+
inventing `fix-now` for it would block a story over a typo), so `openFindings(...).length` read 0
|
|
167
|
+
exactly as it would for a genuinely closed round, and a plain `--prepare` settled the story `done`
|
|
168
|
+
with no spawn and no re-review over a live, undetected defect. `parseFixlistFile`'s parse now also
|
|
169
|
+
reports what it could not read (`unreadableFindings`/`fixlistFullyParsed`, `fixlist.ts`), and
|
|
170
|
+
`openFixNow`/`closedFixlistCandidates` (both the `blocked`/`approve` shape and the `review`/
|
|
171
|
+
`fixlist` shape above share this one check) hold rather than settle when a round parsed
|
|
172
|
+
uncleanly, naming the exact heading and line that could not be read.
|
|
173
|
+
|
|
174
|
+
- **`--fixlist <path>` naming a file this framework cannot fully parse — corrupted, truncated, or
|
|
175
|
+
another story's misnamed file — refuses with exit 1 (usage), not exit 5 (agent failed) (#218,
|
|
176
|
+
pre-merge review).** The refusal used to throw out of `fixlistFor` and land in the generic
|
|
177
|
+
executor `catch`, which reads any thrown `Error` as a STAGE failure: `run.yml`'s stage was stamped
|
|
178
|
+
`status: failed` with `cost_usd: 0.00`, and the next `tldrx next` printed "retrying … (cost already
|
|
179
|
+
spent is not refunded)" — a lie, since the refusal fires before anything is opened or spent. It
|
|
180
|
+
now returns the same `refusedOnSequence` precondition-refusal `offerAtFrontier`'s dependency wait
|
|
181
|
+
already uses: exit 1, `run.yml` untouched, no false retry line. The unnamed door's own corruption
|
|
182
|
+
check is scoped to `--prepare` only (the one caller with a `try`/`catch` around it) — the headless
|
|
183
|
+
in-session fix-round spawn keeps the pre-#218 fallback (a corrupted round is treated as absent
|
|
184
|
+
rather than crashing the run mid-wave), since the correctness half above already closes the
|
|
185
|
+
dangerous direction independently of this door.
|
|
186
|
+
|
|
187
|
+
- **A relaunch of `tldrx run auto <runId>` resuming its OWN already-claimed epic branch now
|
|
188
|
+
verifies it instead of trusting it silently (#347).** `run auto` does not expose `--reuse-epic`
|
|
189
|
+
(there is nobody present to type it), so `foreignEpicRefusal`'s `claimed.has(branch)` case — this
|
|
190
|
+
run's own `build.epic_branch` already naming the branch a killed attempt cut and claimed before
|
|
191
|
+
it died — was a bare `continue`: no check that the branch head still resolved, no gate, and no
|
|
192
|
+
record that anything had been resumed at all. It now confirms the branch is still reachable and,
|
|
193
|
+
when the repo declares a `typecheck` command, runs it once in a throwaway detached worktree
|
|
194
|
+
(removed immediately after) before trusting the claim; a repo with no `typecheck` role is
|
|
195
|
+
adopted with that said explicitly (`typecheck: absent`) rather than assumed green. Recorded
|
|
196
|
+
honestly either way — an `epic.resumed` line and event carrying the sha and the typecheck
|
|
197
|
+
verdict — and a typecheck that FAILS refuses the stage by name instead of building on a possibly
|
|
198
|
+
broken branch (`tldrx next --reuse-epic` still adopts it deliberately, unchanged). A claim
|
|
199
|
+
another run wrote is refused exactly as before — nothing here relaxes that guard.
|
|
200
|
+
|
|
3
201
|
## 0.30.0 — 2026-09-15
|
|
4
202
|
|
|
5
203
|
### Fixed
|
package/README.md
CHANGED
|
@@ -335,6 +335,7 @@ back on the registry is 0.3.0.
|
|
|
335
335
|
|
|
336
336
|
| Version | Date | Status | Contains |
|
|
337
337
|
|---|---|---|---|
|
|
338
|
+
| 0.31.0 | 2026-09-16 | `beta` | Ten efficiency adjustments, ranked from a measured audit of 48 runs, so an unattended run spends less and stalls less. `how` is skipped when the seed already declares its own solution, and runs on `sonnet` when it does run (#346); `risks.md` is no longer generated (#350); `watch` follows `build`'s gate policy, so an all-auto run signs itself (#349); a Watch card's `[src:]` punctuation slip is repaired locally instead of costing a turn (#345); a fix list with zero open findings settles the round, an unreadable one holds it by name (#218); `run status` warns NO-RETRY before a retry the budget refuses (#232); a failed headless turn carries a named `failure_kind`, so the loop stops buying the same retry for every death (#348); an orphaned turn is banked as unmetered instead of a confident zero (#337); a relaunch resumes its own epic branch instead of restarting it (#347); the base-tree DoD refusal names the workspace `install:` (#343) and `run auto` names `--wait-gates` (#342). |
|
|
338
339
|
| 0.30.0 | 2026-09-15 | `beta` | Seventeen changes that keep an unattended run moving instead of stranding. A cached Build refusal says so and a relaunch re-measures it (#339); a rate-limit warning is read instead of dropped, so a Build parks before the wall (#298); the plan-over-stage advisory speaks only past 2× (#302); a stage death stops recommending a retry the budget refuses (#232); a DoD command is measured twice, a fix-list finding is checked against the epic tip, and an over-long sha is refused by name (#163); a formatting slip gets one bounded repair turn (#288); five Checks stop asking the reviewer for what it can't do (#195); a Codex review no longer dies before it runs (#148); `tldrx init` probes four commands at once (#180); `tldrx ship` refuses a merged diff nobody judged (#311). Docs: the zero-touch recipe pairs `run auto` with `--wait-gates`/`--wait-answers` (#342). |
|
|
339
340
|
| 0.29.0 | 2026-09-15 | `beta` | Sixteen changes that make an unattended run trust its own gates and its own numbers. Verdict integrity: a reviewer's `changes` must cite evidence (#326), a re-reviewed story's `changes` is consumed instead of parking it (#327), and a story blocked on a stale fix list settles `done` once resolved (#329). Fix-list flow: a headless fix list now buys its own fix round, and an approving reviewer's signature closes what it was shown (#327). Money and phase sizing: `run auto` rebalances a blocked phase's shortfall out of finished phases by default (#330), the `budget-gate` hook stops denying the launch that would fix the shortfall (#321), a Build gate no longer stops on paths outside the declared surface but carries them into the PR instead (#331), a parallel wave no longer hands two developers the same unspent money (#325), `budget show`/`run estimate`/the budget-gate hook price remaining work off the stage's own `attempts:` (#214), `run auto --until-done` states a token refusal in tokens rather than invented dollar words (#270), a Watch turn is recorded as unmetered rather than a false `$0.00` (#224), and a Watch spawn now records the ceiling it was given (#190). Dependency and safety: a Build gate names the story a dependent waits on (#303), the conflict-turn marker guard names unreadable paths, bounds its scan, and covers modified files too (#324), a developer's array-valued `notes` is joined instead of silently dropped (#217), and the Plan prompt states its per-item character cap where each field is described so an over-cap finding survives into the retry (#328). |
|
|
340
341
|
| 0.28.1 | 2026-09-15 | `beta` | Two fixes so a reopened story's reason reaches the agents that need it. The developer and reviewer prompts now carry `## Why this story was reopened` — who signed it, whether it's a fix round, the note verbatim — off the same ledger value #308 reads, instead of the note reaching only a report line and #308's check (closes #322). `tldrx note --help` now says an operator note reaches no agent and names `dispatch-notes.md` as the channel that does (closes #151). |
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
conflictOf
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-04kpbhvk.js";
|
|
5
5
|
import {
|
|
6
6
|
FactsStore,
|
|
7
7
|
formatJaccard
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-f9d2efhb.js";
|
|
9
9
|
import {
|
|
10
10
|
parseHookInput,
|
|
11
11
|
readStdin
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-zyz0fbz5.js";
|
|
13
|
+
import"./chunk-ae6bkfs5.js";
|
|
13
14
|
import {
|
|
14
15
|
EventLog,
|
|
15
16
|
PHASE_ID_RE
|
|
16
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-akemhezh.js";
|
|
17
18
|
import {
|
|
18
19
|
PHASE_IDS
|
|
19
|
-
} from "./chunk-
|
|
20
|
-
import"./chunk-
|
|
20
|
+
} from "./chunk-yyhwf3bp.js";
|
|
21
|
+
import"./chunk-5kv2vtha.js";
|
|
21
22
|
import {
|
|
22
23
|
ADVISORY_KEY,
|
|
23
24
|
MAX_FACT_CHARS,
|
|
@@ -27,7 +28,7 @@ import {
|
|
|
27
28
|
renderQuestionBlock,
|
|
28
29
|
replaceBlock,
|
|
29
30
|
serializeQuestions
|
|
30
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-x1f4dxwk.js";
|
|
31
32
|
import {
|
|
32
33
|
ITERATION_ONLY_SLOT,
|
|
33
34
|
PROJECT_FRAMEWORK_DIR,
|
|
@@ -37,7 +38,7 @@ import {
|
|
|
37
38
|
isScopedTemplate,
|
|
38
39
|
parseYaml,
|
|
39
40
|
scopedSlotOf
|
|
40
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-9bd6b3xf.js";
|
|
41
42
|
|
|
42
43
|
// src/hooks/answer-capture.ts
|
|
43
44
|
import { existsSync as existsSync5 } from "fs";
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
budgetGateDeny
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-q1ge3nex.js";
|
|
5
5
|
import {
|
|
6
6
|
allow,
|
|
7
7
|
deny,
|
|
8
8
|
readPayload,
|
|
9
9
|
runHook,
|
|
10
10
|
toolInput
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import"./chunk-
|
|
11
|
+
} from "./chunk-27v2rwa9.js";
|
|
12
|
+
import"./chunk-zyz0fbz5.js";
|
|
13
13
|
import {
|
|
14
14
|
REBALANCE_SOURCE,
|
|
15
15
|
applyRebalance,
|
|
@@ -27,10 +27,10 @@ import {
|
|
|
27
27
|
validateRunBudget,
|
|
28
28
|
wouldExceed,
|
|
29
29
|
wouldExceedHostTokens
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-me0kzc6k.js";
|
|
31
31
|
import {
|
|
32
32
|
EventLog
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-akemhezh.js";
|
|
34
34
|
import {
|
|
35
35
|
cursorStage,
|
|
36
36
|
hostTokensIn,
|
|
@@ -39,20 +39,20 @@ import {
|
|
|
39
39
|
newestActiveRun,
|
|
40
40
|
renderRunEconomies,
|
|
41
41
|
runSpend
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-8ds2ret8.js";
|
|
43
43
|
import {
|
|
44
44
|
buildStageDefaults
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-yyhwf3bp.js";
|
|
46
46
|
import {
|
|
47
47
|
noteDeprecations
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-x1f4dxwk.js";
|
|
49
49
|
import {
|
|
50
50
|
PROJECT_WORK_DIR,
|
|
51
51
|
findWorkspaceRoot,
|
|
52
52
|
locateWork,
|
|
53
53
|
parseYaml,
|
|
54
54
|
stageYamlPath
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-9bd6b3xf.js";
|
|
56
56
|
|
|
57
57
|
// src/hooks/budget-gate.ts
|
|
58
58
|
import { existsSync as existsSync2, readFileSync as readFileSync2, statSync } from "node:fs";
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
findDuplicate
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-f9d2efhb.js";
|
|
4
4
|
import {
|
|
5
5
|
evidencePath,
|
|
6
6
|
gateEvidencePath,
|
|
7
7
|
parseEvidence
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-akemhezh.js";
|
|
9
9
|
import {
|
|
10
10
|
openBlocks,
|
|
11
11
|
parseQuestions
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-x1f4dxwk.js";
|
|
13
13
|
|
|
14
14
|
// src/core/distill/distill.ts
|
|
15
15
|
var CONFLICT_THRESHOLD = 0.6;
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
spentBasis,
|
|
10
10
|
tallyOf,
|
|
11
11
|
validateRunBudget
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-me0kzc6k.js";
|
|
13
13
|
import {
|
|
14
14
|
EventLog,
|
|
15
15
|
OUTCOME_NOT_RECORDED,
|
|
@@ -22,12 +22,12 @@ import {
|
|
|
22
22
|
isTerminal,
|
|
23
23
|
stageAt,
|
|
24
24
|
validateRunFile
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-akemhezh.js";
|
|
26
26
|
import {
|
|
27
27
|
cursorStage,
|
|
28
28
|
isAttendedByHostView,
|
|
29
29
|
openRunViews
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-8ds2ret8.js";
|
|
31
31
|
import {
|
|
32
32
|
backupPathFor,
|
|
33
33
|
isAlive,
|
|
@@ -36,13 +36,13 @@ import {
|
|
|
36
36
|
workspaceRootOfRunDir,
|
|
37
37
|
writeAtomic,
|
|
38
38
|
yamlScalar
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-5kv2vtha.js";
|
|
40
40
|
import {
|
|
41
41
|
isAdvisory,
|
|
42
42
|
noteDeprecations,
|
|
43
43
|
openBlocks,
|
|
44
44
|
parseQuestions
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-x1f4dxwk.js";
|
|
46
46
|
import {
|
|
47
47
|
FRAMEWORK_ROOT,
|
|
48
48
|
MAX_ITEM_CHARS,
|
|
@@ -50,7 +50,7 @@ import {
|
|
|
50
50
|
listRunDirs,
|
|
51
51
|
parseYaml,
|
|
52
52
|
parseYamlRepairing
|
|
53
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-9bd6b3xf.js";
|
|
54
54
|
|
|
55
55
|
// src/core/statusline/runSnapshot.ts
|
|
56
56
|
import { existsSync as existsSync3, readFileSync as readFileSync4 } from "node:fs";
|
|
@@ -134,6 +134,7 @@ function task(t, indent) {
|
|
|
134
134
|
`${inner}error: ${yamlScalar(t.error)}, session_id: ${yamlScalar(t.session_id)},`,
|
|
135
135
|
`${inner}started_at: ${yamlScalar(t.started_at)}, ended_at: ${yamlScalar(t.ended_at)},`,
|
|
136
136
|
...t.stopped_by === undefined || t.stopped_by === null ? [] : [`${inner}stopped_by: ${yamlScalar(t.stopped_by)},`],
|
|
137
|
+
...t.failure_kind === undefined || t.failure_kind === null ? [] : [`${inner}failure_kind: ${yamlScalar(t.failure_kind)},`],
|
|
137
138
|
...t.banked_before_refusal === undefined ? [] : [`${inner}banked_before_refusal: true,`],
|
|
138
139
|
...t.dedupe === undefined ? [] : [`${inner}dedupe: ${yamlScalar(t.dedupe)},`],
|
|
139
140
|
...t.duration_ms === undefined ? [] : [`${inner}duration_ms: ${String(Math.round(t.duration_ms))}, ` + `duration_basis: ${yamlScalar(t.duration_basis ?? null)},`],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PROJECT_FRAMEWORK_DIR,
|
|
3
3
|
PROJECT_WORK_DIR
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-9bd6b3xf.js";
|
|
5
5
|
|
|
6
6
|
// src/core/lock/workspaceLock.ts
|
|
7
7
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, openSync, readFileSync as readFileSync2, rmSync as rmSync2, writeSync, closeSync } from "node:fs";
|
|
@@ -7969,6 +7969,7 @@ function diagnoseSrcToken(line, repos) {
|
|
|
7969
7969
|
}
|
|
7970
7970
|
return { rule: srcRule(id), line: quotable(line), piece: null };
|
|
7971
7971
|
}
|
|
7972
|
+
var MECHANICALLY_REPAIRABLE = new Set(["marker-spelling", "trailing-position", "cmd-arrow"]);
|
|
7972
7973
|
function parseSrcToken(line, repos) {
|
|
7973
7974
|
const trimmed = trimTrailingClosers(line);
|
|
7974
7975
|
const match = TRAILING_TOKEN_RE.exec(trimmed);
|
|
File without changes
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
GATE_POLICIES,
|
|
3
3
|
validateGatesPolicy,
|
|
4
4
|
validateStagePolicy
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-yyhwf3bp.js";
|
|
6
6
|
import {
|
|
7
7
|
asDocument,
|
|
8
8
|
isRecord,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
requireString,
|
|
16
16
|
requireVersion,
|
|
17
17
|
result
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-9bd6b3xf.js";
|
|
19
19
|
|
|
20
20
|
// src/core/events/EventLog.ts
|
|
21
21
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
@@ -57,6 +57,7 @@ var EVENT_TYPES = [
|
|
|
57
57
|
"story.touches_widened",
|
|
58
58
|
"plan.fix_round",
|
|
59
59
|
"epic.released",
|
|
60
|
+
"epic.resumed",
|
|
60
61
|
"worktree.foreign_work_aside",
|
|
61
62
|
"worktree.foreign_work_restored",
|
|
62
63
|
"result.unreadable",
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
withWorkspaceLock,
|
|
4
4
|
workspaceRootOfFactsPath,
|
|
5
5
|
writeAtomic
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-5kv2vtha.js";
|
|
7
7
|
import {
|
|
8
8
|
FACT_CONFIDENCES,
|
|
9
9
|
FACT_DECIDERS,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
isLive,
|
|
16
16
|
isRetired,
|
|
17
17
|
noteDeprecations
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-x1f4dxwk.js";
|
|
19
19
|
import {
|
|
20
20
|
SRC_PATTERNS,
|
|
21
21
|
asDocument,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
requireString,
|
|
29
29
|
requireVersion,
|
|
30
30
|
result
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-9bd6b3xf.js";
|
|
32
32
|
|
|
33
33
|
// src/core/facts/FactsStore.ts
|
|
34
34
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
STAGE_TUNING_DEFAULTS
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-yyhwf3bp.js";
|
|
4
4
|
import {
|
|
5
5
|
MAX_PLAN_STORIES,
|
|
6
6
|
MAX_STORIES_PER_WAVE,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
requireVersion,
|
|
26
26
|
requireVersion1,
|
|
27
27
|
result
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-9bd6b3xf.js";
|
|
29
29
|
|
|
30
30
|
// src/hooks/lib/actor.ts
|
|
31
31
|
function currentActor() {
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
EMPTY_SECTION_RULE,
|
|
4
4
|
noneBullet,
|
|
5
5
|
srcRule
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-9bd6b3xf.js";
|
|
7
7
|
|
|
8
8
|
// src/hooks/lib/messages.ts
|
|
9
9
|
var GRAMMAR = "[src: <repo:path:line> | https://… | Q<n> | F<n> | $ <cmd> → exit <n> | graph:<node> | absent:<path>]";
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
wouldBeContent
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-72et1xzx.js";
|
|
5
5
|
import {
|
|
6
6
|
claimSourcesDeny,
|
|
7
7
|
claimSourcesEmptySectionDeny,
|
|
8
8
|
claimSourcesMalformedDeny,
|
|
9
9
|
claimSourcesUnresolvedDeny
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-q1ge3nex.js";
|
|
11
11
|
import {
|
|
12
12
|
allow,
|
|
13
13
|
deny,
|
|
@@ -16,8 +16,8 @@ import {
|
|
|
16
16
|
postContext,
|
|
17
17
|
readPayload,
|
|
18
18
|
runHook
|
|
19
|
-
} from "./chunk-
|
|
20
|
-
import"./chunk-
|
|
19
|
+
} from "./chunk-27v2rwa9.js";
|
|
20
|
+
import"./chunk-zyz0fbz5.js";
|
|
21
21
|
import {
|
|
22
22
|
isHandoff,
|
|
23
23
|
loadWorkspace,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
toSrcContext,
|
|
26
26
|
validateCitations,
|
|
27
27
|
validateHandoff
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-9bd6b3xf.js";
|
|
29
29
|
|
|
30
30
|
// src/hooks/claim-sources.ts
|
|
31
31
|
await runHook("claim-sources", async () => {
|
package/dist/hooks/dod-gate.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
wouldBeContent
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-72et1xzx.js";
|
|
5
5
|
import {
|
|
6
6
|
dodGateDeny,
|
|
7
7
|
dodGateInternalErrorDeny,
|
|
8
8
|
dodGateMissingBlockDeny,
|
|
9
9
|
dodGateRefusedCommandDeny
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-q1ge3nex.js";
|
|
11
11
|
import {
|
|
12
12
|
allow,
|
|
13
13
|
deny,
|
|
@@ -15,15 +15,15 @@ import {
|
|
|
15
15
|
filePathOf,
|
|
16
16
|
isWriteOrEdit,
|
|
17
17
|
readPayload
|
|
18
|
-
} from "./chunk-
|
|
19
|
-
import"./chunk-
|
|
18
|
+
} from "./chunk-27v2rwa9.js";
|
|
19
|
+
import"./chunk-zyz0fbz5.js";
|
|
20
20
|
import {
|
|
21
21
|
loadRunView
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-8ds2ret8.js";
|
|
23
23
|
import {
|
|
24
24
|
DEFAULT_TIMEOUT_S,
|
|
25
25
|
buildStageDefaults
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-yyhwf3bp.js";
|
|
27
27
|
import {
|
|
28
28
|
DodCommandRefused,
|
|
29
29
|
loadWorkspace,
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
readStory,
|
|
32
32
|
repoPath,
|
|
33
33
|
runDodCommand
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-9bd6b3xf.js";
|
|
35
35
|
|
|
36
36
|
// src/hooks/dod-gate.ts
|
|
37
37
|
import { basename, join } from "node:path";
|