tldr-experts 0.6.0 → 0.7.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 +425 -0
- package/README.md +4 -2
- package/dist/hooks/answer-capture.js +7 -7
- package/dist/hooks/budget-gate.js +8 -8
- package/dist/hooks/{chunk-x6n8b5fp.js → chunk-2y3kwfrx.js} +1 -1
- package/dist/hooks/{chunk-97ncnegd.js → chunk-37fwvg3x.js} +1 -1
- package/dist/hooks/{chunk-g4db8rbs.js → chunk-5w5eg00k.js} +1 -1
- package/dist/hooks/{chunk-v4ay50nq.js → chunk-6405vkzk.js} +1 -1
- package/dist/hooks/{chunk-h7151g8w.js → chunk-b9rjx4qc.js} +3 -2
- package/dist/hooks/{chunk-dhbxzjfs.js → chunk-cf4az0j5.js} +1 -1
- package/dist/hooks/{chunk-17gv74sr.js → chunk-ecfqpeyj.js} +3 -3
- package/dist/hooks/{chunk-7eqhfddw.js → chunk-md1c7z7q.js} +3 -3
- package/dist/hooks/{chunk-5k4dggq0.js → chunk-pf9d8ag8.js} +5 -5
- package/dist/hooks/{chunk-ka6bkb64.js → chunk-rk1nm39z.js} +1 -1
- package/dist/hooks/{chunk-vrhczzxs.js → chunk-x3zy7zrn.js} +1 -1
- package/dist/hooks/{chunk-9w64mxdh.js → chunk-y3cxqvnx.js} +154 -12
- package/dist/hooks/claim-sources.js +5 -5
- package/dist/hooks/dod-gate.js +6 -6
- package/dist/hooks/no-reask.js +8 -8
- package/dist/hooks/session-start.js +10 -10
- package/dist/hooks/statusline.js +7 -7
- package/dist/tldrx.js +1786 -1029
- package/env.yml +9 -1
- package/package.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/stages/how/stage.yml +9 -2
- package/stages/plan/stage.yml +26 -0
- package/templates/experts/delivery.md +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,430 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.0 — 2026-09-03
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **Codex is now a second honest automated runner.** Set `TLDRX_AGENT_PROVIDER=codex` to
|
|
8
|
+
run plain `codex exec --json` through the existing facilitator seam; `TLDRX_CODEX_BIN`
|
|
9
|
+
selects a wrapper or pinned executable. The adapter is pinned to a real codex-cli 0.152.0
|
|
10
|
+
JSONL transcript and a real executable stub, preserves thread identity and token usage,
|
|
11
|
+
feeds the existing structured envelopes, runs developers in `workspace-write`, and makes
|
|
12
|
+
Build reviewers mechanically `read-only`. Because Codex exposes neither provider-metered
|
|
13
|
+
USD nor a provider-side USD cap, every Codex turn is recorded `cost_usd: null,
|
|
14
|
+
metered: false`; no Codex prices were added and dollar totals remain lower bounds. Agent
|
|
15
|
+
gate provenance uses the measured Codex thread id as `executed_by.id`. Claude remains the
|
|
16
|
+
byte-identical default. File formats remain `version: 1`; `DASHBOARD_MODEL_VERSION` remains
|
|
17
|
+
`3`.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- **A citation to a file that exists only on the run's unmerged epic branch passed unflagged, or broke,
|
|
22
|
+
depending on whether a temp directory still existed (#140).** Live evidence, run
|
|
23
|
+
`260830-money-and-payments` (aparece-v2, closed 2026-09-03): `retro.md` was committed to `main` carrying
|
|
24
|
+
96 `[src: src/Modules/Payments/…:28]` citations to files that exist on `epic/money-and-payments` and on
|
|
25
|
+
no merged ref. The driver's words: *"cuatro de mis citas apuntaban a archivos que solo existen en el epic.
|
|
26
|
+
Nadie me las señaló."* #16 had made those resolve against the epic WORKTREE
|
|
27
|
+
(`.tldrx/worktrees/<repo>/_epic-<run>-<epic>`), and that is a temp directory, so the same citation had two
|
|
28
|
+
silent answers — measured on `24e9358` with the new fixture:
|
|
29
|
+
- worktree **present** (the state the retro was written in): the whole check detail read
|
|
30
|
+
`1 handoff(s) sourced`, with no mention of the branch the path is only on;
|
|
31
|
+
- worktree **gone** (the state `main` is always in, and the state after cleanup):
|
|
32
|
+
`no such file: src/Modules/Payments/CreateChargeHandler.cs — tried repo \`api\` (api)` — the stage's own
|
|
33
|
+
evidence refused for being true.
|
|
34
|
+
- **A `file` src now gets one more chance after every base on disk: the branches the run RECORDED.**
|
|
35
|
+
`run.yml`'s `build.epic_branch` — the same record `tldrx ship` opens its PR from — read as a git blob with
|
|
36
|
+
`git cat-file blob <ref>:<path>` in each declared repo. No worktree, and no retention policy needed for
|
|
37
|
+
this purpose. `cat-file blob` and not `show`: `git show <ref>:<dir>` prints a tree listing and exits 0, so
|
|
38
|
+
`show` would resolve a citation to a directory as though it were a file (measured 2026-09-03: `cat-file blob`
|
|
39
|
+
exits 0 for a blob, 128 for a tree, 128 for a path the ref does not have).
|
|
40
|
+
- **It resolves, and it is NAMED.** A citation whose only home is unmerged is `ok` — refusing it would refuse
|
|
41
|
+
a stage for reporting its own evidence — and the resolution carries the ref, so `claim-sources` prints
|
|
42
|
+
`on unmerged refs: 96 (epic/money-and-payments — unmerged)` in the one detail string the gate, `tldrx next`
|
|
43
|
+
and the run record all read. A reader of `main` is told which branch to look on. A hit on the epic
|
|
44
|
+
worktree is named the same way, so the "passes in silence" half is closed too.
|
|
45
|
+
- **Still refused:** a path on no ref at all (the failure now admits it tried the recorded branches), and a
|
|
46
|
+
cited line past the end of the epic's blob — which names the ref and the length the file has there. Only
|
|
47
|
+
branches `build.epic_branch` records are tried; a branch that merely exists in the repo is not a base.
|
|
48
|
+
An `absent:` src deliberately does NOT reach for the refs: an absence is a claim about where somebody
|
|
49
|
+
looked, and a branch nobody checked out is not somewhere anybody looked.
|
|
50
|
+
- **The blob read is opt-in, and the `claim-sources` hook does not opt in.** It is the one subprocess the
|
|
51
|
+
§2.8 reader spawns, and that hook runs on every PreToolUse write inside the 50 ms budget of spec §0. The
|
|
52
|
+
guard is reachability rather than a cap: `toSrcContext(workspace, runDir)` — the hook's spelling — leaves
|
|
53
|
+
`epicRefs` empty, so no handoff can reach a `spawnSync` from a write. Measured 2026-09-03 on 96 epic-only
|
|
54
|
+
citations: **0.36 ms** on the hook path, **1166 ms** cold on the gate path with all 96 reads paid, **0.36 ms**
|
|
55
|
+
warm (memoised per repo/ref/path, capped at 256 reads per process). `tldrx approve`, the stage/gate
|
|
56
|
+
`claim-sources` check, `tldrx next`'s auto gate, `tldrx watch` and `watch arm` opt in — every one of them a
|
|
57
|
+
boundary that already spawns git.
|
|
58
|
+
- **It behaves like `noted`, not like `unverified`:** it passes the stage and it does not block an auto gate
|
|
59
|
+
(spec §5, condition 5). It is a check that ran and came back true, of a branch nothing has merged.
|
|
60
|
+
- **The auto gate's NOTE carries the ref too.** `claimSourcesCondition` carried `outcome.detail` into its
|
|
61
|
+
note only when the unchecked-absence count was non-zero — #110's rule reading one of the two things that
|
|
62
|
+
detail now holds. So a stage whose handoff cited nothing but the epic and held no absence at all
|
|
63
|
+
auto-signed with a note that read, in full, `claim-sources=passed`. Both counts are consulted now, and
|
|
64
|
+
the branch reaches the sentence a person actually reads when a stage signs itself.
|
|
65
|
+
- **A watcher card could cite a path only the unmerged epic has, and say nothing (#143).** The one artefact
|
|
66
|
+
#140's annotation did not reach. `watcherFile.ts` recorded an issue only when a resolution was NOT `ok`,
|
|
67
|
+
and every issue it records makes the card fail — so "true, and true only on `epic/…`" could not be said
|
|
68
|
+
without failing a card that is not wrong. Since `tldrx watch`, `watch arm` and the Watch executor opt into
|
|
69
|
+
the recorded epic refs (`toSrcContext(…, { epicRefs: true })`), such a citation resolved in silence, and a
|
|
70
|
+
card committed to the trunk could point a reader at paths no merged ref has. Measured RED, on a card whose
|
|
71
|
+
four checked sections all cite `epic/money-and-payments`: `watch check` said `ok — verified; every source
|
|
72
|
+
resolves` and `watch list`'s footer said `1 card(s): 1 verified, 0 draft`, neither naming the branch.
|
|
73
|
+
- The card now carries a **separate, non-fatal `epicOnly` list** — the shape `handoff.ts` already uses for
|
|
74
|
+
the same reason, rather than a third `WatcherIssueKind`, because `ok` reads `issues` and nothing else, so
|
|
75
|
+
the annotation cannot fail a card however long it gets.
|
|
76
|
+
- It is printed in the words `claim-sources` already uses at a gate — `on unmerged refs: 4
|
|
77
|
+
(epic/money-and-payments — unmerged)` — beside the card's status in `watch check`, as a footer under the
|
|
78
|
+
`watch list` table, as `unmerged_refs` (plus an `unmerged` count) in `watch list --json`, and on the Watch
|
|
79
|
+
executor's own per-card line, which is where the driver reads a card's status.
|
|
80
|
+
- Three guards say it is not a rubber stamp, and all three were green before the change: a path on a
|
|
81
|
+
**merged** ref gets no annotation, a citation that resolves **nowhere** is still a failing `source` issue,
|
|
82
|
+
and with epic refs **off** — the context the PreToolUse hook builds — nothing resolves and nothing is
|
|
83
|
+
annotated.
|
|
84
|
+
- **A run could close with a question nobody ever answered, and nothing said so (#141).** Filed from the
|
|
85
|
+
driver of `260830-money-and-payments` (aparece-v2) as *"D7.6 nunca recibió respuesta ni disparó su
|
|
86
|
+
default"*, labelled INFERRED. **Measured first, and the reported mechanism does not exist:**
|
|
87
|
+
- `D7.6` was never a question. The §2.7 heading grammar is `^## (Q\d{1,6}) · ` — `D7.6` is a
|
|
88
|
+
Definition-of-Done criterion in that run's own seeded documents
|
|
89
|
+
(`docs/domain-design/docs/12-DEFINITION-OF-DONE.md:118-125`). The run's `questions.md` files hold exactly
|
|
90
|
+
three blocks — `Q1`, `Q2`, `Q3` — and every one is `status: answered`.
|
|
91
|
+
- A question **cannot declare** a default. §2.7's metadata keys are `id status area asked_by asked_at` plus
|
|
92
|
+
the optional `affects:`; there is no `default:` and no `timeout:`.
|
|
93
|
+
- **Nothing fires one.** The only thing in the codebase called a default is `tldrx interview
|
|
94
|
+
--yes-to-defaults`, which an operator invokes by hand, takes option A, and is labelled `[assumption]` in
|
|
95
|
+
its own implementation. No timer, no gate and no close applies anything to an open question.
|
|
96
|
+
|
|
97
|
+
The fail-open the report was reaching for is real, and narrower guards had hidden it: the auto gate's
|
|
98
|
+
`questions` condition reads only the CURRENT stage's declared file, a human `approve` does not look at
|
|
99
|
+
questions at all, and `closeRun` read `run.yml` and git and nothing else. A question raised in `01-what`
|
|
100
|
+
could age through every later stage, past a signed gate and out of the run in silence. Measured RED, on a
|
|
101
|
+
run cancelled with `Q1` open: `cancelled 260828-demo — 1 stage(s) closed: 01-what/alpha` and not one word
|
|
102
|
+
about the question. **All three close paths** — `tldrx next` closing the last stage, `tldrx approve` signing
|
|
103
|
+
the last gate, `tldrx run cancel` — now name every open block by id, title and file, plus any heading the
|
|
104
|
+
§2.7 parser cannot read (worse than open: the block was never visible to anything). The sentence ends by
|
|
105
|
+
saying that nothing was going to answer them, because that belief is what produced the report. It is a
|
|
106
|
+
report and nothing else: no exit code changes, no close is refused, not one byte is written.
|
|
107
|
+
|
|
108
|
+
## 0.6.1 — 2026-09-03
|
|
109
|
+
|
|
110
|
+
### Fixed
|
|
111
|
+
|
|
112
|
+
- **The Build handoff's `Cost:` header was invocation-scoped, so a re-entered stage reported
|
|
113
|
+
`$0.00` for a phase that had spent `$0.44` (#138).** The sibling of #137's two sections, one
|
|
114
|
+
line higher up, on a document whose own docstring says it "describes the phase, not the
|
|
115
|
+
invocation". `writeHandoff` fed the header `this.spent()` — the sum of the tasks THIS process
|
|
116
|
+
spawned — so a `tldrx next` → `tldrx reject` → `tldrx next` rewrote the same file's
|
|
117
|
+
`Cost: $0.44 of $200.00 ceiling` as `Cost: $0.00`: the second invocation settled nothing,
|
|
118
|
+
spent nothing, and said so about the whole phase. Measured on `f5936d2` with the `TWO_WAVES`
|
|
119
|
+
fixture at `FAKE_BUILD_COST=0.11`.
|
|
120
|
+
- **`FAKE_BUILD_COST=0` is why nobody saw it.** Every other re-entry test in
|
|
121
|
+
`test/build-executor.test.ts` pins the cost to zero, where both writes read `$0.00` and
|
|
122
|
+
agree. The new block does not, and buys the headroom that needs with a $200 stage ceiling —
|
|
123
|
+
the budget gate refuses to RESTART a stage whose estimate no longer fits, so a fixture whose
|
|
124
|
+
stage estimate IS the phase ceiling cannot re-enter once a cent is recorded. Raising the
|
|
125
|
+
default in the shared fixture instead was rejected: it would have rewritten the pinned
|
|
126
|
+
expectations of every re-entry test in the file for a defect one block now covers head-on.
|
|
127
|
+
- **The durable source is `run.yml`'s `stage.cost_usd`**, plus what this invocation has spent
|
|
128
|
+
and not yet handed back (`phaseCostToDate`, exported from `executors/build.ts`). Chosen over
|
|
129
|
+
the `agent.result` events because it is the ledger the budget is derived from AND it
|
|
130
|
+
validates its own arithmetic: `rollUp` recomputes it from `stage.tasks` on every save,
|
|
131
|
+
`rollUpBudget` mirrors it into `budget.yml`, `run status` and the dashboard read it, and
|
|
132
|
+
`validateRunFile` refuses a `run.yml` whose `budget.spent_usd` drifts from the sum of its
|
|
133
|
+
task rows by more than a cent. The events carry the same numbers — every `recordTask` is
|
|
134
|
+
paired with an `agent.result` written from the same task in the same loop — but nothing
|
|
135
|
+
checks that they still do.
|
|
136
|
+
- **Three properties it rests on, verified rather than assumed.** `tldrx reject` does not touch
|
|
137
|
+
the number (it rewrites `status`, `ended_at` and `gate` and nothing else), which answers the
|
|
138
|
+
open question in the issue: a re-run reports the earlier spend, because the money was spent.
|
|
139
|
+
This invocation is not in `run.yml` yet, because `recordExecutorTasks` runs after the
|
|
140
|
+
executor returns — so adding the two cannot double-count, and a re-entry that DOES spend is
|
|
141
|
+
pinned at `$0.22 + $0.11 = $0.33`. And opening the store mid-stage is the shape the executor
|
|
142
|
+
already uses twice, not a new coupling.
|
|
143
|
+
- **`ExecutorOutcome.costUsd` stays invocation-scoped.** It is what the facilitator adds to the
|
|
144
|
+
run budget; a phase-to-date figure there would double-count on every re-entry.
|
|
145
|
+
- **Unreadable is not zero.** No `run.yml`, one that fails schema validation, or a stage id
|
|
146
|
+
that does not resolve gives this invocation's own spend with the reason in brackets — never
|
|
147
|
+
a confident total. A stage that has genuinely spent nothing still reads `$0.00` with no note.
|
|
148
|
+
|
|
149
|
+
- **That same header was a LOWER BOUND whenever a turn ran in-session, and nothing on the line
|
|
150
|
+
said so (#139).** A host session driving `--prepare` / `--commit` without `--cost-usd` is
|
|
151
|
+
recorded as `cost_usd: null` + `metered: false`, and `rollUp` sums it as nothing — so the phase
|
|
152
|
+
figure is what the METERED turns cost, not what the phase cost. The dashboard has marked
|
|
153
|
+
exactly this case as a `lower bound` since #103 and `tldrx budget show` prints it in words; the
|
|
154
|
+
handoff header was the one cost surface that stayed silent, on the FIRST write as well as a
|
|
155
|
+
re-entry. Filed as *inferred* and **measured before it was fixed**, which is what the issue
|
|
156
|
+
asked for: a fixture driving the real host path — `--prepare`, a `result.json` with no
|
|
157
|
+
`cost_usd`, `--commit` — put one unmetered turn beside one `$0.11` spawn and wrote
|
|
158
|
+
`Cost: $0.11 of $200.00 ceiling`, a bare figure indistinguishable from a fully metered phase.
|
|
159
|
+
- **One derivation, three surfaces.** The counting and the sentence moved out of
|
|
160
|
+
`dashboard/model.ts` into `core/budget/spendBasis.ts`, and the header prints what it returns.
|
|
161
|
+
The dashboard's model imports the page renderer, so the executor could not import IT — and
|
|
162
|
+
fixing the wording in place is how two spellings of one caveat get born, which the issue
|
|
163
|
+
named as the reason not to. Only the SUBJECT differs: a stage-scoped header says "the stage".
|
|
164
|
+
Dashboard output is unchanged.
|
|
165
|
+
- **The counts come from the same rows the sum does** — `run.yml`'s `stage.tasks`, plus this
|
|
166
|
+
invocation's, for the same reason `invocationUsd` is added to the total: `recordExecutorTasks`
|
|
167
|
+
runs after the executor returns, so counting `run.yml` alone would report the first write of a
|
|
168
|
+
host-driven handoff as fully metered.
|
|
169
|
+
- **A fully metered stage keeps its clean line.** `measured` is the one basis with nothing to
|
|
170
|
+
caveat. A turn counts as having produced no dollars if it is `metered: false` OR a metered
|
|
171
|
+
`cost_usd` of exactly `0` — the wider of the two readings, inherited unchanged from #103, so
|
|
172
|
+
the two surfaces cannot classify the same turn differently. It is also the conservative
|
|
173
|
+
direction: #138 and #139 both flattered the number.
|
|
174
|
+
- **Both caveats when both apply.** An unreadable `run.yml` (#138) and an unmetered turn (#139)
|
|
175
|
+
are different facts about the same figure, and the note now carries both rather than one.
|
|
176
|
+
|
|
177
|
+
- **`test/attempt-cost.test.ts` proved "carries no format refusal" with the bare word
|
|
178
|
+
`REFUSED`, and unrelated prompt prose turned it red (#135).** The thing it means to detect
|
|
179
|
+
is `renderFormatRefusal`'s heading; what it detected was an eight-letter English word,
|
|
180
|
+
anywhere in a ~14 KB document. #133 added one sentence elsewhere in the same prompt that
|
|
181
|
+
happened to use it and the assertion went red over prose that has nothing to do with a
|
|
182
|
+
refusal — a wrong-instrument failure, not a behaviour change.
|
|
183
|
+
- The heading is now exported as `FORMAT_REFUSAL_HEADING` from `src/core/build/review.ts`
|
|
184
|
+
and asserted in place of the word, so the renderer and its test cannot spell it
|
|
185
|
+
differently. Same idiom, and same reason, as `SRC_GRAMMAR_HEADING` and
|
|
186
|
+
`REVIEWER_FOCUS_HEADING`. A test pins that the constant IS the rendered first line.
|
|
187
|
+
- The workaround went with it: `payloadCapLines`' docstring told the next author not to use
|
|
188
|
+
the word. A comment asking people to avoid an English word was never a guard, and the
|
|
189
|
+
prose is free to say `REFUSED` again.
|
|
190
|
+
- **03-plan had NO map at all on a single-repo workspace (#136).** Its one map declaration was
|
|
191
|
+
`.tldrx/map/workspace.md`, which `buildMap.ts:83-88` writes only in multi-repo mode — so on
|
|
192
|
+
a single-repo workspace Plan's entire map input resolved to nothing, while all six
|
|
193
|
+
`MAP_DOCS` sat unread under `.tldrx/map/<repo>/`. Measured on a single-repo fixture with a
|
|
194
|
+
real map: `map PRESENT: []`, and the prompt carried no map content whatsoever.
|
|
195
|
+
- Plan now also declares `.tldrx/map/{repo}/commands.md`. This is a GATE, not a preference:
|
|
196
|
+
Plan writes each story's `dod.commands`, the `plan` check validates every one against the
|
|
197
|
+
workspace allowlist and refuses the story when it cannot ("an empty allowlist is not a
|
|
198
|
+
permit", `src/core/schemas/commandAllowlist.ts:33`) — and Plan was shown that allowlist
|
|
199
|
+
nowhere. `.tldrx/workspace.yml` is not one of its inputs, the generic stage prompt renders
|
|
200
|
+
no commands section (only the DEVELOPER prompt does, `prompts.ts:175`), and multi-repo's
|
|
201
|
+
`workspace.md` carries repo name, path, stack, branch and confidence, not commands. The
|
|
202
|
+
map document that mirrors the allowlist (`renderMap.ts:27`) was declared by no stage.
|
|
203
|
+
- **One document, not six.** Plan decomposes a design 02-how has already placed on real
|
|
204
|
+
paths, so architecture stays upstream; six documents per repo on a stage whose job is
|
|
205
|
+
splitting and ordering is the context nobody asked for that the wave-N lesson in
|
|
206
|
+
`seedInputs.ts` is about. Measured cost: +120 B on a 20,777 B prompt, against budgets of
|
|
207
|
+
98,304 (`inputs_max_bytes`) and 163,840 (`prompt_max_bytes`).
|
|
208
|
+
- **Multi-repo semantics are unchanged** — `workspace.md` stays, and stays without `{repo}`.
|
|
209
|
+
Its absence on a single-repo workspace is still SAID rather than performed (#131): there
|
|
210
|
+
is no cross-repo view of one repo, and the `absent:` block reports exactly that.
|
|
211
|
+
|
|
212
|
+
- **A re-entered Build stage OVERWROTE its own handoff with a degraded reconstruction (#137).**
|
|
213
|
+
`04-build/handoff.md` is rewritten by every `tldrx next` that reaches the end of the stage, and
|
|
214
|
+
its own docstring says it "describes the phase, not the invocation" — but two of its sections
|
|
215
|
+
were fed from what THIS process did. So the second write over a re-entered stage (`tldrx reject`
|
|
216
|
+
then `tldrx next`, or any run whose stories did not all settle at once) replaced true statements
|
|
217
|
+
with false ones. Measured on `340fb91`: an Evidence ledger of two green DoD rows became
|
|
218
|
+
`- no Definition of Done ran [src: absent:03-plan/stories]`, and a Gate row reading
|
|
219
|
+
`(S1, S2 merged)` became `(no story merged)` while `git log epic/e1` carried both merge commits
|
|
220
|
+
throughout. The Gate section is the one a human reads before merging an epic by hand, so this is
|
|
221
|
+
the 2026-08-30 empty-merge defect arriving from the other side; a third section degraded quietly
|
|
222
|
+
with them, Findings losing each story's merged sha to `at (no commit)`.
|
|
223
|
+
- **Reconstructed where the truth is durable.** The row `fromDisk` builds for a story an earlier
|
|
224
|
+
invocation settled now READS its DoD results and its merged commit from `events.jsonl` via
|
|
225
|
+
`readReviewLedger` — the same reader `rereview` already trusts when it declines to re-run a
|
|
226
|
+
DoD, so nothing new is being asserted. The Gate section learns what is on an epic branch from
|
|
227
|
+
both sources instead of one: this process's own merges, plus the stories disk says reached
|
|
228
|
+
`done`, which in this pipeline is a status only a merged story reaches.
|
|
229
|
+
- **Said as absent, with its reason, where it is not.** What a merge CARRIED is counted before
|
|
230
|
+
the merge and stored nowhere, and afterwards cannot be measured at all — a merged story branch
|
|
231
|
+
is an ancestor of the epic either way. Those stories get a third list of their own and a row
|
|
232
|
+
that names the gap and the command that closes it — *S1, S2 merged by an earlier `tldrx next`
|
|
233
|
+
— what each carried was not re-measured here, run `git log epic/e1`*. Folding them into
|
|
234
|
+
`merged` would overclaim; dropping them is what printed `no story merged`. A declared dod
|
|
235
|
+
command whose result is in no event is named the same way against its own log, and the negative
|
|
236
|
+
`- no Definition of Done ran` is now written only when the stories declare no commands.
|
|
237
|
+
- The degraded handoff PASSED the claim-sources check the whole time — it reads citations, not
|
|
238
|
+
truth — so nothing downstream was ever going to catch this. Five tests now pin it.
|
|
239
|
+
- Answered and filed, not fixed: the header's `Cost:` line is invocation-scoped too, so the
|
|
240
|
+
second write reports `$0.00` for a stage that spent `$0.44` (measured). Different seam — the
|
|
241
|
+
number is not in the ledger this fix reads — so it is #138.
|
|
242
|
+
|
|
243
|
+
- **The `feature` preset declared map inputs without `{repo}`, so 02-how and 03-plan ran with
|
|
244
|
+
no map at all (#131).** `stages/how/stage.yml` asked for `.tldrx/map/architecture.md` and
|
|
245
|
+
`.tldrx/map/conventions.md`. `tldrx init` writes the map PER REPO —
|
|
246
|
+
`.tldrx/map/<repo>/architecture.md`, one folder per repo, six `MAP_DOCS` documents each
|
|
247
|
+
(`src/core/map/buildMap.ts:74-79`) — so nothing on disk could ever answer either
|
|
248
|
+
declaration. They are OPTIONAL inputs, `declaredInputsOf` drops an optional input that is
|
|
249
|
+
not present, and the two stages the map exists FOR were dispatched without it on every
|
|
250
|
+
feature-scope run. 01-what and 05-watch carried the token the whole time, which is why two
|
|
251
|
+
stages of five went wrong quietly for as long as they did.
|
|
252
|
+
- Both paths gain `{repo}`. `03-plan`'s `.tldrx/map/workspace.md` deliberately does NOT:
|
|
253
|
+
it is the one map document written at the map ROOT, and only in multi-repo mode
|
|
254
|
+
(`buildMap.ts:83-88`), so the token would point it at a file that never exists. The
|
|
255
|
+
reasoning is now a comment in the file so the next sweep leaves it alone too.
|
|
256
|
+
- **Swept all thirteen scope presets.** `workflows/*.yml` compose the same five stage files
|
|
257
|
+
and declare no `inputs:` of their own, so `how` was the only offender — and both facts are
|
|
258
|
+
now pinned: one test asserts no shipped stage declares a `MAP_DOCS` document without
|
|
259
|
+
`{repo}` (derived from `MAP_DOCS`, so a seventh document is covered the day it is added),
|
|
260
|
+
another asserts no preset grows stage inputs that would bypass it.
|
|
261
|
+
- **And an absence is now SAID rather than performed.** A declared input that resolves to
|
|
262
|
+
nothing is named twice: as a `### Declared, but not on disk` block in the prompt's
|
|
263
|
+
`## Inputs`, carrying that path's own `[src: absent:<path>]` token so the stage's handoff
|
|
264
|
+
can source a negative claim on it, and as one line on stdout. This is the half that turns
|
|
265
|
+
the next such typo into a first-run report instead of a live incident — a sub-agent that is
|
|
266
|
+
not told what is missing cannot tell "the map says nothing about this" from "I was never
|
|
267
|
+
shown the map", and its handoff records the second as the first.
|
|
268
|
+
|
|
269
|
+
- **The reviewer prompt described the result envelope in prose beside the schema that defines
|
|
270
|
+
it (#133).** `REVIEW_SCHEMA` is handed to `claude --json-schema` on the spawned path and
|
|
271
|
+
written verbatim into the bundle as `pending.json` → `result_schema` on the host path, so
|
|
272
|
+
both halves of the handshake already answered the same question — and the prompt then
|
|
273
|
+
described the same envelope again, key by key, in the one document a model reads most
|
|
274
|
+
carefully. Two live reviews lost cycles to it, one because the host dictated the shape from
|
|
275
|
+
memory, which is exactly what a prose paraphrase invites.
|
|
276
|
+
- `## Produce` now points at `result_schema` (and at `--json-schema` for a spawn) as the
|
|
277
|
+
single authority and states no field of it. The verdicts moved to their own `## Verdict`
|
|
278
|
+
section, because WHICH verdict to return is judgement and judgement is what the prompt is
|
|
279
|
+
for; #77's `refuted`-needs-a-citation contract is judgement too and is untouched.
|
|
280
|
+
- **The 4096-byte payload cap is now named.** The verdict's prose is copied into a
|
|
281
|
+
`check.passed`/`check.failed` payload, `validateEvent` refuses any payload over
|
|
282
|
+
`MAX_PAYLOAD_BYTES` (`src/core/events/Event.ts:121`) and `EventLog.append` THROWS rather
|
|
283
|
+
than writing a shortened line — so an essay-length verdict does not arrive trimmed, it
|
|
284
|
+
takes the ledger entry down with it. The number is imported into the prompt, never typed,
|
|
285
|
+
so changing the cap changes the promise.
|
|
286
|
+
- Pinned by a test that asserts the prompt REFERENCES rather than RESTATES, off the schema
|
|
287
|
+
itself: every field name in `REVIEW_SCHEMA` — top level and inside a `fixlist` row, minus
|
|
288
|
+
the verdict words — must not appear in the rendered prompt. A field added to the schema is
|
|
289
|
+
covered without anyone remembering to add it here.
|
|
290
|
+
- **Pruning a blocked story's worktree destroyed the work inside it (#129).** Measured live
|
|
291
|
+
2026-09-02 on run `260830-money-and-payments` (aparece-v2), reported by the unattended
|
|
292
|
+
driver: a story's Definition of Done failed, the executor settled it `blocked`, and
|
|
293
|
+
`cleanUp` ran `git worktree remove --force` over a tree that still held the developer's
|
|
294
|
+
fix, uncommitted. There was no branch, no stash and no reflog to get it back from. `blocked`
|
|
295
|
+
is precisely the state a human is going to want to inspect, and it was the one state that
|
|
296
|
+
destroyed the evidence first.
|
|
297
|
+
- The invariant, and it has no exceptions in it: **the framework never deletes a worktree
|
|
298
|
+
holding changes that reached no ref.** Before any prune, `settle` commits whatever the
|
|
299
|
+
tree still holds to the STORY branch as
|
|
300
|
+
`wip(<id>): rescued from a story that settled \`blocked\`` — an honest subject naming the
|
|
301
|
+
verdict, the reason in the body, and "nothing reviewed this and nothing merged it" said
|
|
302
|
+
out loud, because a rescue commit that read like a delivery would be #130 in another file.
|
|
303
|
+
- Commit-then-prune rather than never-prune, because *recoverable* has to mean recoverable
|
|
304
|
+
**by sha**: a kept directory survives until the next `run close` or temp sweep, a commit
|
|
305
|
+
on the story branch survives a year. If the commit cannot be made, the worktree is KEPT
|
|
306
|
+
instead and the review log names its path.
|
|
307
|
+
- The sha is recorded where a human looks, not only where a terminal scrolls: a
|
|
308
|
+
`## Uncommitted work rescued` section in `04-build/log/<id>.md`, and a new
|
|
309
|
+
`story.work_rescued` event (§2.9) carrying story, repo, branch, sha and the settled
|
|
310
|
+
status. It is the second event in the enum that records tldrx touching git on the
|
|
311
|
+
operator's behalf, and it is appended only when a commit was really made.
|
|
312
|
+
- `--keep-worktrees`, a story parked at `review`, and a parked developer failure are
|
|
313
|
+
untouched: nothing is about to be deleted on any of those paths, so there is nothing to
|
|
314
|
+
rescue from. A green story rescues nothing either — `commitIfDirty` has already put every
|
|
315
|
+
byte on the branch.
|
|
316
|
+
- Red first, in `test/blocked-prune.test.ts`: on `14f01ec` a blocked story's `s1.txt`
|
|
317
|
+
existed nowhere — `git cat-file -e story/<run>/S1:s1.txt` exited non-zero and the tip of
|
|
318
|
+
the story branch was still `chore: fixture repo`. Five tests, including the
|
|
319
|
+
commit-cannot-be-made path (a `pre-commit` hook that exits 1), which asserts the tree is
|
|
320
|
+
still there with the file in it.
|
|
321
|
+
|
|
322
|
+
- **The fix list recorded `Resolved: yes` over a fix that did not exist (#130).** Same
|
|
323
|
+
incident, and the driver called it the most dangerous of the four because it fails silently
|
|
324
|
+
and in the wrong direction: `04-build/fixlist/S4-1.md` ended with **`Resolved: yes`** and a
|
|
325
|
+
`result.json` describing the fix in detail, while the code did not contain it — the worktree
|
|
326
|
+
holding it had been pruned (#129) before anything reached a ref. The audit trail said a
|
|
327
|
+
defect was closed while it was alive, and one approval away from carrying the story to
|
|
328
|
+
`done`. Root: the accounting was written from an agent's REPORT rather than from a verified
|
|
329
|
+
code state, which is the one thing this framework refuses everywhere else and had never
|
|
330
|
+
applied to its own bookkeeping.
|
|
331
|
+
- **A close now carries the sha the fix landed as**: the line is `Resolved: yes <sha>`, and
|
|
332
|
+
the sha is CHECKED before a story may settle — it must resolve to a commit in the story's
|
|
333
|
+
repo (`git rev-parse --verify <sha>^{commit}`) and be reachable from the story branch
|
|
334
|
+
(`git merge-base --is-ancestor`). A bare `yes` closes nothing; `isOpen` treats an
|
|
335
|
+
unevidenced claim as an open finding.
|
|
336
|
+
- **The record stops lying about itself.** A claim that does not check out is rewritten in
|
|
337
|
+
place to `Resolved: claimed-unverified — <why>`, keeping the fact that somebody reported a
|
|
338
|
+
fix while withdrawing the assertion that it landed. Three refusals, each named: no commit
|
|
339
|
+
to point at, a sha that is not a commit in the repo, a commit that is not on the branch.
|
|
340
|
+
- One-directional by construction: verification can only move a finding from closed to
|
|
341
|
+
OPEN. Nothing here closes one, and a `Resolved: no` is never touched. Every `Resolved: yes`
|
|
342
|
+
is checked whatever its disposition — a `defer-with-log` claim over a fix that does not
|
|
343
|
+
exist is a smaller problem and the same lie — while only a `fix-now` gates `done`.
|
|
344
|
+
- The artifact teaches the form: its preamble now says `Resolved: yes <sha>`, says a bare
|
|
345
|
+
`yes` closes nothing, and says the sha is checked. So do the router's lines in a
|
|
346
|
+
`--prepare --fixlist` bundle and the block message on a refused `done`.
|
|
347
|
+
- Red first, in `test/fixlist.test.ts`: on `14f01ec` a fix list edited to `Resolved: yes`
|
|
348
|
+
with nothing landed settled the story `status: done`, evidence `commit 3380cca`, over two
|
|
349
|
+
live `fix-now` findings — and `Resolved: yes deadbeefdeadbeef` did the same. Two existing
|
|
350
|
+
tests that encoded the old contract were updated to name a real commit on the story branch;
|
|
351
|
+
they still prove that closing every finding lets the same approve settle `done`.
|
|
352
|
+
|
|
353
|
+
- **The Build handoff cited a story branch that does not exist (#134).** Any run whose stories
|
|
354
|
+
did not all settle in ONE `tldrx next` — the ordinary shape once a stage is re-entered — got
|
|
355
|
+
a Findings row reading ``done — repo `app`, `story/S1`, merged into `epic/e1` ``, and
|
|
356
|
+
`git show story/S1` fails, because the branch the executor cut and merged is
|
|
357
|
+
`story/<run-id>/S1`. The run id in that name is a deliberate invariant (§"Build branch and
|
|
358
|
+
worktree names carry the run id", after the 2026-08-29 audit and #40); the handoff's
|
|
359
|
+
reconstruction path for a story settled by an earlier invocation had its own copy of the
|
|
360
|
+
formula and the copy predated the invariant.
|
|
361
|
+
- Fixed as **one derivation, not two**: `storyBranchOf(runId, storyId)` in
|
|
362
|
+
`src/core/plan/branchModel.ts` is now the only place the name is written, and all three
|
|
363
|
+
callers — the cut in `openStory`, the reconstruction in `fromDisk`, and the
|
|
364
|
+
`--discard-pending` evidence check on an implicit plan — go through it. A second formula
|
|
365
|
+
that matched would only postpone this; the name is a pure function of two ids that are
|
|
366
|
+
both in scope, exactly like `integrationBranchFor` and `epicWorktreeName`, so there is
|
|
367
|
+
nothing to persist and re-read.
|
|
368
|
+
- **Reporting only, and checked rather than assumed.** `StoryOutcome.branch` has three
|
|
369
|
+
consumers and all three render text: the handoff's `finding()`, the review log's
|
|
370
|
+
`- Branch:` line, and the retro's merge-conflict line. Every git operation and every
|
|
371
|
+
command a host is handed to run — `addWorktree`, `commitsBetween`, the reviewer bundle's
|
|
372
|
+
`diff`, the fix list's `diff` — reads `StoryContext.branch`, which `openStory` cut. No
|
|
373
|
+
ref was resolved from the wrong name, so nothing merged, moved or deleted wrongly; it was
|
|
374
|
+
a wrong name in an audit document.
|
|
375
|
+
- Red first, in `test/build-executor.test.ts`: on `30737a5` a second invocation's handoff
|
|
376
|
+
contained ``story/S1`` where `story/260829-build/S1` was expected, and
|
|
377
|
+
`git rev-parse --verify story/S1` exited 128 (`fatal: Needed a single revision`). The test
|
|
378
|
+
now asserts every `story/…` ref the handoff cites resolves in the repo, and a second one
|
|
379
|
+
asserts the template is written nowhere in the executor.
|
|
380
|
+
|
|
381
|
+
### Added
|
|
382
|
+
|
|
383
|
+
- **The Plan prompt now says how to make a `touches` list COMPLETE (#132).** Measured on one
|
|
384
|
+
live run: 3 of 5 stories needed their write surface extended after the fact. S2 could not
|
|
385
|
+
write the failing test its own test plan promised, because the test file was outside
|
|
386
|
+
`touches`. S4 added two enum members and left out the switch sites, so the branch did not
|
|
387
|
+
compile. S8's security criterion read a file the story never declared, so the criterion
|
|
388
|
+
would have passed on nothing. The developers caught all three — at the cost of a round each
|
|
389
|
+
time. Every other rule in `## Output schemas` is generated from a validator, because a
|
|
390
|
+
validator refuses what breaks it and says why; under-declaration breaks no rule at all.
|
|
391
|
+
`["src/thing.ts"]` is a well-formed list, `validateStory` passes it, and the bill arrives
|
|
392
|
+
one stage later at the developer prompt's "change only what `touches` names" and at
|
|
393
|
+
auto-gate condition 7 `boundary`.
|
|
394
|
+
- A `### Completing \`touches\`` sub-section in `renderPlanSchemaContract()`, ~1.3 KB in the
|
|
395
|
+
cached, most-stable part of a prompt whose stage budget is $4: three sweeps, one per real
|
|
396
|
+
failure — its tests · every switch, registration, factory, DI container or barrel a new
|
|
397
|
+
name has to reach · every file a gated criterion reads — plus what omitting one costs, so
|
|
398
|
+
the reason is in the prompt rather than in an issue. The `touches` row of the generated
|
|
399
|
+
table now points at it instead of restating it.
|
|
400
|
+
- Prose on purpose, and the only prose in that file: no compiler runs at Plan time, so
|
|
401
|
+
nothing can compute this list. **Compile simulation stays the escalation path** if the
|
|
402
|
+
checklist measures poorly on the next runs.
|
|
403
|
+
- Red-first in two places: `test/plan-schema-contract.test.ts` pins the three rules and the
|
|
404
|
+
cost statement against the rendered contract, and `test/plan-contract.test.ts` pins them
|
|
405
|
+
against the prompt the real `tldrx next --prepare` bundle writes — a contract that renders
|
|
406
|
+
correctly and is spliced into no prompt is the `templates/story.md` failure again (#48).
|
|
407
|
+
6 red before, green after. `docs/spec.md` §2.13 and the `delivery` expert each carry one
|
|
408
|
+
line pointing at the checklist.
|
|
409
|
+
- **The landing page now sells the unattended flow it never mentioned (#128).** Measured at
|
|
410
|
+
`95a39db`: `grep -c 'tldrx drive' docs-site/index.md` returned `0`, and so did its Spanish
|
|
411
|
+
twin — a bare `grep drive` exited `1` on both. `tldrx drive` is the star command for handing
|
|
412
|
+
a run over for the night; it has a guide in each locale and a chapter behind that, and the
|
|
413
|
+
front door had still never named it. The landing walked a reader from `run new` through
|
|
414
|
+
`next` / `approve` / `reject` to `run auto` and stopped, which is where the reader stopped
|
|
415
|
+
too — the one flow that most needs explaining was reachable only by someone who already
|
|
416
|
+
knew to go looking for it.
|
|
417
|
+
- One compact section per locale — "When nobody is watching" / "Cuando nadie está viendo" —
|
|
418
|
+
led by the outcome rather than the flags: hand a run over inside boundaries you wrote
|
|
419
|
+
down, and get the run itself back instead of a summary you have to believe. It shows the
|
|
420
|
+
three-command path (`tldrx init` → `tldrx run new … --attended-by host --gates …` →
|
|
421
|
+
`tldrx drive --unattended`) and links to the guide for the rest.
|
|
422
|
+
- The hero is untouched in both locales, and both pages are pure insertions — no existing
|
|
423
|
+
line was edited.
|
|
424
|
+
- Pinned in `test/public-surface-consistency.test.ts`: each landing must name `tldrx drive`
|
|
425
|
+
and link to its guide. Red on both locales before the change, green after. The pin is on
|
|
426
|
+
the entry point, not the prose — heading, wording and placement stay free to change.
|
|
427
|
+
|
|
3
428
|
## 0.6.0 — 2026-09-02
|
|
4
429
|
|
|
5
430
|
### Added
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/tldr-experts) [](https://github.com/ederwii/tldr-experts/actions/workflows/ci.yml) 
|
|
4
4
|
|
|
5
|
-
**An evidence-first, file-based AI development framework: five stages, a gate on every one, and every claim cited or refused.** Open source. The workflow and the persisted state format are provider-independent; the automated runner currently supports Claude Code. **Beta:** every command is implemented and verified by running it, the `version: 1` file formats only grow from here, and `tldrx --help` is the authoritative command surface.
|
|
5
|
+
**An evidence-first, file-based AI development framework: five stages, a gate on every one, and every claim cited or refused.** Open source. The workflow and the persisted state format are provider-independent; the automated runner currently supports Claude Code and Codex. **Beta:** every command is implemented and verified by running it, the `version: 1` file formats only grow from here, and `tldrx --help` is the authoritative command surface.
|
|
6
6
|
|
|
7
7
|
One loop — *Investigate → Handoff → Interview → Gate* — five phases, **what · how · plan · build ·
|
|
8
8
|
watch**, one stage per command, each stopping at a gate you own; the files ARE the state, the
|
|
@@ -59,7 +59,7 @@ and names the `--prepare` command instead.
|
|
|
59
59
|
|
|
60
60
|
| | who executes each turn | what a turn costs | where it stops |
|
|
61
61
|
|---|---|---|---|
|
|
62
|
-
| `tldrx run auto` | the framework —
|
|
62
|
+
| `tldrx run auto` | the framework — Claude Code by default, or `codex exec` when selected | Claude reports metered USD; Codex reports tokens and is unmetered in dollars | the first human gate or open question (`4`), stage failure (`5`), ceiling (`2`) |
|
|
63
63
|
| `tldrx run attend host`, driven from a session | your session's own sub-agents | host-billed; the framework records `cost_usd: null, metered: false` | every turn — `--prepare` writes the bundle, `--commit` settles it |
|
|
64
64
|
| the same, under a **mandate** | your session's own sub-agents | host-billed | a new product decision, a ceiling raise, a boundary exit — nothing else |
|
|
65
65
|
|
|
@@ -298,6 +298,8 @@ back on the registry is 0.3.0.
|
|
|
298
298
|
|
|
299
299
|
| Version | Date | Status | Contains |
|
|
300
300
|
|---|---|---|---|
|
|
301
|
+
| 0.7.0 | 2026-09-03 | `beta` | Codex as a second honest automated runner: recorded JSONL contract, structured envelopes, role-based sandboxes, token/session provenance, and explicitly unmetered USD accounting; Claude remains the default and the pilot harness. Also absorbs the citation-honesty work previously staged as 0.6.2: a `file` src resolves against the branches the run RECORDED and NAMES the unmerged ref instead of passing in silence or breaking with the temp dir (#140), watcher cards name it the same way (#143), and every run close reports the questions nobody answered (#141) |
|
|
302
|
+
| 0.6.1 | 2026-09-03 | `beta` | dogfooding fixes from the first fully-unattended runs: blocked stories never lose uncommitted work (rescue commits + `story.work_rescued`), a fix is only Resolved with a reachable sha, re-entered stages reconstruct their handoff from the ledger instead of degrading it, the Cost header reports the phase and names its lower bound (shared `spendBasis`), feature presets resolve their per-repo maps, Plan sees the command allowlist its gate enforces, the landing sells the unattended flow |
|
|
301
303
|
| 0.6.0 | 2026-09-02 | `beta` | the dashboard suite — a "Now" hero strip, `--serve` live refresh, stage durations and gate notes on page and CLI, and a public demo generated from fixtures; honest dual-economy spend (metered + host, lower-bound named); gate provenance — `executed_by` + `authority` so a delegated signature never reads as a personal one, machine-signed reporting fixed; ONE `absent:` semantic shared by claim-sources and the auto gate; superseded stamps when an owner answer flips an earlier phase doc; run close commits its state and `ship` refuses a state-carrying epic; merge-wave gates `docs:build`, survives interruption and self-rewrite; a public-surface drift guard; env.yml validation (unique ids, tool cap) |
|
|
302
304
|
| 0.5.0 | 2026-09-02 | `beta` | `tldrx drive` and its own preflight, `watch check` / `watch arm`, `questions cards`, `plan schema`, `retro --all` (with its findings fed back into every reviewer prompt) and `story reopen --for-fix`; `tldrx update` plus a cached newer-version notice; the dashboard reads `budget.yml` and `events.jsonl` — operator notes, reopens and retries, the per-phase budget panel, and a host-attended run metered in tokens against `ceiling_host_tokens`; a rejected review envelope no longer burns a story attempt; `ship` opens one PR per repo; merge-wave lock + ref guard; five golden-transcript evals, one per stage; `CONTRIBUTING.md` and a model-provider contract |
|
|
303
305
|
| 0.4.0 | 2026-09-01 | `beta` | FIRST BETA — 40-issue hardening burn (DoD pre-flight + `plan sync-dod`, merge-wave lock + gated-HEAD, load-aware tests, claim-sources across all outputs), `tldrx learn` 8-chapter sandbox tutorial (cold-player QA), `tldrx ship` / `tldrx note` / `run gates set`, budget policies + dual-economy wiring, single integration branch for chained epics, epic worktrees live to run close, bilingual docs site |
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
FactsStore
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ecfqpeyj.js";
|
|
5
5
|
import {
|
|
6
6
|
parseHookInput,
|
|
7
7
|
readStdin
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-x3zy7zrn.js";
|
|
9
9
|
import {
|
|
10
10
|
EventLog,
|
|
11
11
|
PHASE_ID_RE
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import"./chunk-
|
|
14
|
-
import"./chunk-
|
|
12
|
+
} from "./chunk-b9rjx4qc.js";
|
|
13
|
+
import"./chunk-5w5eg00k.js";
|
|
14
|
+
import"./chunk-6405vkzk.js";
|
|
15
15
|
import {
|
|
16
16
|
MAX_FACT_CHARS,
|
|
17
17
|
detectAnswered,
|
|
@@ -19,12 +19,12 @@ import {
|
|
|
19
19
|
recordAnswer,
|
|
20
20
|
replaceBlock,
|
|
21
21
|
serializeQuestions
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-37fwvg3x.js";
|
|
23
23
|
import"./chunk-39zh2e44.js";
|
|
24
24
|
import {
|
|
25
25
|
PROJECT_WORK_DIR,
|
|
26
26
|
factsPath
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-y3cxqvnx.js";
|
|
28
28
|
|
|
29
29
|
// src/hooks/answer-capture.ts
|
|
30
30
|
import { existsSync as existsSync3 } from "fs";
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
budgetGateDeny
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-cf4az0j5.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-2y3kwfrx.js";
|
|
12
|
+
import"./chunk-x3zy7zrn.js";
|
|
13
13
|
import {
|
|
14
14
|
asRunBudget,
|
|
15
15
|
currentActor,
|
|
@@ -29,15 +29,15 @@ import {
|
|
|
29
29
|
validateRunBudget,
|
|
30
30
|
wouldExceed,
|
|
31
31
|
wouldExceedHostTokens
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-md1c7z7q.js";
|
|
33
33
|
import {
|
|
34
34
|
EventLog
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-b9rjx4qc.js";
|
|
36
36
|
import"./chunk-rrkdfk7s.js";
|
|
37
|
-
import"./chunk-
|
|
37
|
+
import"./chunk-5w5eg00k.js";
|
|
38
38
|
import {
|
|
39
39
|
noteDeprecations
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-37fwvg3x.js";
|
|
41
41
|
import"./chunk-39zh2e44.js";
|
|
42
42
|
import {
|
|
43
43
|
PROJECT_WORK_DIR,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
locateWork,
|
|
46
46
|
parseYaml,
|
|
47
47
|
stageYamlPath
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-y3cxqvnx.js";
|
|
49
49
|
|
|
50
50
|
// src/hooks/budget-gate.ts
|
|
51
51
|
import { existsSync as existsSync2, readFileSync as readFileSync2, statSync } from "node:fs";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PROJECT_FRAMEWORK_DIR,
|
|
3
3
|
PROJECT_WORK_DIR
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-y3cxqvnx.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";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
parseFrontMatter
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-5w5eg00k.js";
|
|
4
4
|
import {
|
|
5
5
|
asDocument,
|
|
6
6
|
isRecord,
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
} from "./chunk-39zh2e44.js";
|
|
15
15
|
import {
|
|
16
16
|
parseHandoff
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-y3cxqvnx.js";
|
|
18
18
|
|
|
19
19
|
// src/core/events/EventLog.ts
|
|
20
20
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
@@ -47,6 +47,7 @@ var EVENT_TYPES = [
|
|
|
47
47
|
"story.reopened",
|
|
48
48
|
"story.base_fastforwarded",
|
|
49
49
|
"story.review_retried",
|
|
50
|
+
"story.work_rescued",
|
|
50
51
|
"result.unreadable",
|
|
51
52
|
"operator_note",
|
|
52
53
|
"check.passed",
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
EMPTY_SECTION_RULE,
|
|
4
4
|
noneBullet,
|
|
5
5
|
srcRule
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-y3cxqvnx.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>]";
|