@open-tomato/rafa 0.45.0 → 0.46.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 +255 -23
- package/dist/PROMPT.md +18 -1
- package/dist/adapters/logger/settings.d.ts +132 -0
- package/dist/bugs/closest.d.ts +19 -0
- package/dist/bugs/fenced.d.ts +8 -0
- package/dist/bugs/places.d.ts +20 -0
- package/dist/bugs/record.d.ts +145 -0
- package/dist/bugs/title.d.ts +83 -0
- package/dist/bundled/agents/doc-updater.md +17 -3
- package/dist/bundled/agents/loop-implementer.md +14 -2
- package/dist/bundled/operators/skills/rafa-stretch-pit-stop/SKILL.md +10 -3
- package/dist/bundled/operators/skills/rafa-stretch-sweep/SKILL.md +5 -0
- package/dist/bundled/skills/dev-planner/SKILL.md +101 -18
- package/dist/cli.js +74726 -62960
- package/dist/config/entry.d.ts +119 -0
- package/dist/config/index.d.ts +36 -0
- package/dist/config/index.js +51 -0
- package/dist/config/shape.d.ts +232 -0
- package/dist/config-registry.d.ts +127 -0
- package/dist/config-schema-board-project.d.ts +157 -0
- package/dist/config-schema-bugs.d.ts +71 -0
- package/dist/config-schema-errors.d.ts +54 -0
- package/dist/config-schema-features.d.ts +64 -0
- package/dist/config-schema-hub.d.ts +150 -0
- package/dist/config-schema-issues.d.ts +95 -0
- package/dist/config-schema-logger.d.ts +91 -0
- package/dist/config-schema-loop-continue.d.ts +122 -0
- package/dist/config-schema-loop-retries.d.ts +94 -0
- package/dist/config-schema-release.d.ts +307 -0
- package/dist/config-schema-tests.d.ts +170 -0
- package/dist/config-schema-triage.d.ts +142 -0
- package/dist/config-schema-wrap-up.d.ts +96 -0
- package/dist/core/command/command.d.ts +228 -0
- package/dist/core/command/confirm.d.ts +67 -0
- package/dist/core/command/index.d.ts +112 -0
- package/dist/core/command/lazy.d.ts +54 -0
- package/dist/core/command/registry-types.d.ts +96 -0
- package/dist/core/command/running.d.ts +96 -0
- package/dist/core/command/spends.d.ts +39 -0
- package/dist/core/command/types.d.ts +92 -0
- package/dist/core/command/version.d.ts +4 -0
- package/dist/core/config/branch-template.d.ts +20 -0
- package/dist/core/config/config-items.d.ts +86 -0
- package/dist/core/config/config-load.d.ts +47 -0
- package/dist/core/config/config-origins.d.ts +57 -0
- package/dist/core/config/config-readers.d.ts +167 -0
- package/dist/core/config/config-schema.d.ts +207 -0
- package/dist/core/config/config-sections.d.ts +493 -0
- package/dist/core/config/config.d.ts +320 -0
- package/dist/core/config/core-section.d.ts +39 -0
- package/dist/core/config/dangerous.d.ts +58 -0
- package/dist/core/config/default-routing.d.ts +16 -0
- package/dist/core/config/index.d.ts +141 -0
- package/dist/core/config/scope.d.ts +42 -0
- package/dist/core/config/section.d.ts +206 -0
- package/dist/core/config/sections.d.ts +45 -0
- package/dist/core/config/standard-schema.d.ts +27 -0
- package/dist/core/git/commit.d.ts +232 -0
- package/dist/core/git/gh-runner.d.ts +24 -0
- package/dist/core/git/git.d.ts +22 -0
- package/dist/core/git/index.d.ts +85 -0
- package/dist/core/loop/claude.d.ts +388 -0
- package/dist/core/loop/hop-record.d.ts +52 -0
- package/dist/core/loop/index.d.ts +179 -0
- package/dist/core/loop/session-env.d.ts +20 -0
- package/dist/core/loop/session-record-parse.d.ts +63 -0
- package/dist/core/loop/sessions.d.ts +408 -0
- package/dist/core/loop/suite-failure.d.ts +25 -0
- package/dist/core/output/active.d.ts +100 -0
- package/dist/core/output/stream.d.ts +20 -0
- package/dist/core/output/text.d.ts +55 -0
- package/dist/core/plan/block-reader.d.ts +46 -0
- package/dist/core/plan/blocks.d.ts +139 -0
- package/dist/core/plan/declaration.d.ts +366 -0
- package/dist/core/plan/plan-stamp.d.ts +75 -0
- package/dist/core/runtime/identity.d.ts +21 -0
- package/dist/core/runtime/index.d.ts +46 -0
- package/dist/effort/store/bring-forward.d.ts +131 -0
- package/dist/effort/store/check-rows.d.ts +31 -0
- package/dist/effort/store/commit-stats.d.ts +42 -0
- package/dist/effort/store/copy.d.ts +35 -0
- package/dist/effort/store/development-build.d.ts +105 -0
- package/dist/effort/store/effort-levels.d.ts +13 -0
- package/dist/effort/store/findings.d.ts +214 -0
- package/dist/effort/store/fix-schema.d.ts +184 -0
- package/dist/effort/store/index.js +10 -7
- package/dist/effort/store/location.d.ts +44 -0
- package/dist/effort/store/merge-commit-gaps.d.ts +68 -0
- package/dist/effort/store/merge-conflicts.d.ts +91 -0
- package/dist/effort/store/merge-rules.d.ts +82 -0
- package/dist/effort/store/merge-store.d.ts +211 -0
- package/dist/effort/store/merge-union.d.ts +92 -0
- package/dist/effort/store/migrate.d.ts +146 -0
- package/dist/effort/store/migrations.d.ts +92 -0
- package/dist/effort/store/ndjson-files.d.ts +114 -0
- package/dist/effort/store/origins.d.ts +116 -0
- package/dist/effort/store/plan-stubs.d.ts +79 -0
- package/dist/effort/store/rebuild-aside.d.ts +172 -0
- package/dist/effort/store/schema-plan.d.ts +102 -0
- package/dist/effort/store/session-row-types.d.ts +64 -0
- package/dist/effort/store/settings.d.ts +13 -0
- package/dist/effort/store/sqlite.d.ts +340 -0
- package/dist/effort/store/store-generation.d.ts +17 -0
- package/dist/effort/store/store-identity.d.ts +220 -0
- package/dist/effort/store/store-meta.d.ts +305 -0
- package/dist/effort/store/store-replaced.d.ts +72 -0
- package/dist/effort/store/types.d.ts +223 -0
- package/dist/errors/codes.d.ts +56 -0
- package/dist/errors/rafa-codes.d.ts +36 -0
- package/dist/index-2a7nb3an.js +125 -0
- package/dist/{index-r28fzsvc.js → index-39kbcw68.js} +350 -165
- package/dist/{index-nv34ptht.js → index-77ajfffn.js} +14 -9
- package/dist/index-cy98y87p.js +2597 -0
- package/dist/index-gqz4jn6j.js +13447 -0
- package/dist/index-gvek4r8m.js +710 -0
- package/dist/index-j4k2vdz3.js +1125 -0
- package/dist/index-jh1r4kcn.js +1067 -0
- package/dist/{index-mgh2s9bj.js → index-ykggr043.js} +58 -455
- package/dist/index-z1w83f81.js +4 -0
- package/dist/index.js +14715 -21516
- package/dist/learning/index.js +5 -6
- package/dist/plan/index.js +12 -11
- package/dist/plan-prompt.md +3 -1
- package/dist/ports/index.d.ts +732 -0
- package/dist/ports/learning.d.ts +101 -0
- package/dist/ports/log-level.d.ts +13 -0
- package/dist/ports/spec-review.d.ts +66 -0
- package/dist/pr/checks.d.ts +133 -0
- package/dist/pr/types.d.ts +422 -0
- package/dist/ready-4f8edezt.js +2016 -0
- package/dist/release-templates/release-bot-fragment.yml +153 -0
- package/dist/release-templates/release-publish.yml +110 -0
- package/dist/release-templates/release-settle.yml +122 -0
- package/dist/release-templates/release-tag.yml +102 -0
- package/dist/report/parse.d.ts +415 -0
- package/dist/schema/project-id.d.ts +79 -0
- package/dist/schema/tiers.d.ts +107 -0
- package/package.json +41 -3
- package/dist/index-hf2k497d.js +0 -16
- package/dist/index-nsr78ct2.js +0 -8219
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spawning a Claude session, and reading how much of the plan's budget
|
|
3
|
+
* has gone.
|
|
4
|
+
*
|
|
5
|
+
* {@link runClaude} is the loop's door onto the CLI for a session whose
|
|
6
|
+
* output only the operator reads. It has one call site, the CI-repair
|
|
7
|
+
* session in `start/pr-lifecycle.ts`, which is not routed — one model,
|
|
8
|
+
* one effort, every tool. So the flags are a parameter with an EMPTY
|
|
9
|
+
* default: `runClaude(prompt, settingSources)` spawns the base
|
|
10
|
+
* arguments and the setting sources, and nothing a declaration could
|
|
11
|
+
* add.
|
|
12
|
+
*
|
|
13
|
+
* {@link runClaudeCaptured} is the door for a session whose output the
|
|
14
|
+
* LOOP reads as well. It has three callers: the per-task dispatch,
|
|
15
|
+
* through `runTaskSession` in `start/dispatch.ts`, the wrap-up session
|
|
16
|
+
* in `start/wrap-up.ts` and the backfill proposal pass in
|
|
17
|
+
* `backfill/propose.ts`. Plan generation in the `claude` planner,
|
|
18
|
+
* `adapters/planner/claude.ts`, which `plan.ts` makes, captures its
|
|
19
|
+
* session through the same spawner without that door, for the reason
|
|
20
|
+
* the search runner does below. Each of the four parses what its
|
|
21
|
+
* session wrote: a task session ends its final message
|
|
22
|
+
* with a `rafa:report` block, the wrap-up with a `rafa:promoted` one
|
|
23
|
+
* when it was listed lessons to promote (`start/promoted-check.ts`), a
|
|
24
|
+
* plan session ends its final message with a `rafa:spec-review` one,
|
|
25
|
+
* and a proposal session's answer goes through `parseSessionAnswer`.
|
|
26
|
+
* The wrap-up, like a task session, also hands over the flags serving
|
|
27
|
+
* it the rafa-tier winners (`start/serving.ts`), and is not routed.
|
|
28
|
+
* {@link spawnClaude} answers the exit code alone, so a loop holding
|
|
29
|
+
* that session's exit code holds nothing else. A task session's flags are
|
|
30
|
+
* the ones its routing declaration resolved to, with the
|
|
31
|
+
* `--session-id` the loop picked for that session ahead of them and
|
|
32
|
+
* its served flags (`start/serving.ts`) ahead of both, and the planner
|
|
33
|
+
* hands over none: its argument list is `claudeArgs(settingSources)`. The captured entry builds its argument
|
|
34
|
+
* list through the same {@link claudeArgs} and hands the prompt over the
|
|
35
|
+
* same way; only the spawner differs, {@link spawnClaudeCaptured} piping
|
|
36
|
+
* stdout, echoing it on to the operator as it arrives and keeping the
|
|
37
|
+
* same bytes for the answer. It sits BESIDE `runClaude` rather than
|
|
38
|
+
* replacing its spawner, so in text mode a session nothing parses keeps
|
|
39
|
+
* spawning exactly what it spawned before. What json mode changes is in
|
|
40
|
+
* the section "What reaches the operator" below.
|
|
41
|
+
*
|
|
42
|
+
* The search runner (`inventory/search/index.ts`) captures its one
|
|
43
|
+
* session through the same spawner without going through
|
|
44
|
+
* `runClaudeCaptured`: it builds its argument list with
|
|
45
|
+
* {@link claudeArgs} and hands the spawner its one option,
|
|
46
|
+
* {@link CapturedSpawnOptions.cwd}, since that session runs inside the
|
|
47
|
+
* scratch copy of its candidates. The epic verification runner
|
|
48
|
+
* (`epic/verify-run.ts`) does the same for each check session, which
|
|
49
|
+
* runs inside a worktree made for the run, and the `claude` planner for
|
|
50
|
+
* its plan session, which runs in the project root `rafa plan` resolved
|
|
51
|
+
* rather than in the caller's directory (#171). The loop's sessions
|
|
52
|
+
* name the same option through `runClaude` and `runClaudeCaptured`,
|
|
53
|
+
* which take it last: each task, wrap-up and CI repair session runs in
|
|
54
|
+
* the run's checkout (`start/checkout.ts`), a linked worktree's own
|
|
55
|
+
* directory when the loop runs in one, and never in the directory the
|
|
56
|
+
* process happens to stand in.
|
|
57
|
+
*
|
|
58
|
+
* The flags land AFTER {@link CLAUDE_BASE_ARGS} and the setting sources
|
|
59
|
+
* rather than before, and the ordering is load-bearing rather than
|
|
60
|
+
* cosmetic. `--tools` is
|
|
61
|
+
* VARIADIC in the CLI's own help (`--tools <tools...>`), so it keeps
|
|
62
|
+
* consuming tokens until one that starts with a dash. `--tools` is the
|
|
63
|
+
* LAST flag `resolveDeclarationFlags` emits, and the resolved flags are
|
|
64
|
+
* the last thing appended here, so its value is the final element of
|
|
65
|
+
* the argument list with nothing after it to be swallowed. Putting the
|
|
66
|
+
* resolved flags FIRST would put `-p` behind that variadic, which is
|
|
67
|
+
* the one arrangement that breaks. `-p` itself takes no value
|
|
68
|
+
* (`-p, --print` is a boolean in the same help text), so nothing after
|
|
69
|
+
* it is at risk either.
|
|
70
|
+
*
|
|
71
|
+
* ## Setting sources
|
|
72
|
+
*
|
|
73
|
+
* Every session, through either door, is spawned with
|
|
74
|
+
* {@link SETTING_SOURCES_FLAG} naming the run's `loop.settingSources`
|
|
75
|
+
* (`config.ts`), `project,local` unless a config names others. Finding
|
|
76
|
+
* 3 of `.rafa/specs/phase-1-installable.md` measured the user scope at about
|
|
77
|
+
* 14,900 tokens of a 58,989-token turn. The sources are a REQUIRED
|
|
78
|
+
* parameter of {@link claudeArgs} and of both doors. A default here
|
|
79
|
+
* would be a second one beside `CONFIG_DEFAULTS`, and a caller that
|
|
80
|
+
* forgot to hand on the value its config resolved to would spawn under
|
|
81
|
+
* that default with nothing to say so; with no default, that caller
|
|
82
|
+
* does not compile.
|
|
83
|
+
*
|
|
84
|
+
* They go between the base arguments and the flags. The CLI's help, on
|
|
85
|
+
* Claude Code 2.1.268, lists `--setting-sources <sources>` as one
|
|
86
|
+
* comma-separated value where `--tools <tools...>` is variadic, so the
|
|
87
|
+
* sources swallow nothing and `--tools` stays last. What they change is
|
|
88
|
+
* measurable without a model call: an `--agent` name no scope defines
|
|
89
|
+
* exits 1 and lists the agents it could have run. That list held this
|
|
90
|
+
* repo's `.claude/agents` and none of `~/.claude/agents` under
|
|
91
|
+
* `project,local`, both under `user,project,local`, and neither under
|
|
92
|
+
* `local`.
|
|
93
|
+
*
|
|
94
|
+
* The prompt goes on STDIN and never into the argument list. That is
|
|
95
|
+
* not a style choice: a plan's task prompt here is the injected
|
|
96
|
+
* instructions plus `PROMPT.md` plus the plan, the whole file under the
|
|
97
|
+
* `full` injection mode and in every wrap-up prompt, which is far past
|
|
98
|
+
* what an argument list can carry, and an argument list is also
|
|
99
|
+
* visible to every `ps` on the machine.
|
|
100
|
+
*
|
|
101
|
+
* {@link ClaudeSpawner} exists because the real spawn is
|
|
102
|
+
* `Bun.spawn` and the root suite runs vitest under NODE — measured,
|
|
103
|
+
* `globalThis.Bun` is `undefined` and `process.versions.bun` is null
|
|
104
|
+
* in that runtime. So the default spawner cannot be driven from a test
|
|
105
|
+
* at all, and the seam is what makes the argument list an assertion
|
|
106
|
+
* rather than something inferred from a session that appeared to work.
|
|
107
|
+
*
|
|
108
|
+
* ## What reaches the operator
|
|
109
|
+
*
|
|
110
|
+
* A session's stdout reaches the operator in the mode of the active
|
|
111
|
+
* output (`core/output/active.ts`). In text mode it is the bytes the
|
|
112
|
+
* session wrote, in the order it wrote them: {@link spawnClaude} inherits
|
|
113
|
+
* the stream, and {@link spawnClaudeCaptured} writes each chunk to
|
|
114
|
+
* `process.stdout` as it arrives. In json mode those bytes would put
|
|
115
|
+
* lines no NDJSON reader parses among the events, so neither door lets
|
|
116
|
+
* them through. {@link spawnClaudeCaptured} hands each line, its newline
|
|
117
|
+
* off, to the active output's `info`, which the `json` adapter writes as
|
|
118
|
+
* one `log` event. The `events` mode routes them the same way, and its
|
|
119
|
+
* adapter drops every `info`, so the screen keeps only its `rafa·` lines.
|
|
120
|
+
* {@link spawnClaude} spawns through
|
|
121
|
+
* {@link spawnClaudeCaptured} and answers its exit code alone. A last
|
|
122
|
+
* line with no newline goes once stdout closes, and a blank line is an
|
|
123
|
+
* event with an empty message, so the messages joined with newlines are
|
|
124
|
+
* the session's stdout. The argument list, the prompt, the environment
|
|
125
|
+
* and the inherited stderr are the same in both modes.
|
|
126
|
+
*
|
|
127
|
+
* The environment is `sessionSpawnEnv(process.env)` at both doors
|
|
128
|
+
* (`session-env.ts`), the one function a reading of the session's
|
|
129
|
+
* environment calls too, so neither door spells an entry of its own.
|
|
130
|
+
* That puts the running entry's `bundled/bin` at the front of every
|
|
131
|
+
* session's `PATH`.
|
|
132
|
+
*
|
|
133
|
+
* ## Interrupting a running session
|
|
134
|
+
*
|
|
135
|
+
* Both doors hold the process they spawn among the live sessions until it
|
|
136
|
+
* has exited, and {@link interruptClaudeSessions} sends each of those
|
|
137
|
+
* SIGINT. `loop start` calls it from its own SIGINT handler (`src/start.ts`).
|
|
138
|
+
* A terminal's Ctrl-C reaches the loop and its session at once, as one
|
|
139
|
+
* process group, but `rafa loop stop` signals the loop's pid alone, and a
|
|
140
|
+
* signal to that pid never reaches the session. Measured on 2026-09-15 by
|
|
141
|
+
* spawning `loop start` over a stand-in `claude` sleeping 20 seconds: a
|
|
142
|
+
* SIGINT to the loop's pid ended the run after 20.06 s, once the session
|
|
143
|
+
* had run to its own end, and one to its process group after 0.03 s.
|
|
144
|
+
*
|
|
145
|
+
* A signalled session has ended once its process exits, but the captured
|
|
146
|
+
* door reads the session's stdout to its end first, and a process the
|
|
147
|
+
* session left behind holding that stdout keeps it open. Measured on
|
|
148
|
+
* 2026-09-15 with a stand-in that trapped SIGINT and exited 130 while a
|
|
149
|
+
* sleep it had put in the background held the pipe: `rafa loop stop` took
|
|
150
|
+
* 19.9 s, ending when the sleep did, against 0.28 s with the sleep's output
|
|
151
|
+
* sent to `/dev/null`. Both doors answered 130 for a stand-in the signal
|
|
152
|
+
* ended, under bun 1.3.14.
|
|
153
|
+
*
|
|
154
|
+
* ## The spend guard
|
|
155
|
+
*
|
|
156
|
+
* Both doors warn when the running command's `spends` declaration
|
|
157
|
+
* (`packages/rafa/src/core/command/spends.ts`) does not cover the session they start,
|
|
158
|
+
* and start it anyway: usage is never a gate. The running command is the
|
|
159
|
+
* one the dispatcher recorded with its parsed flags
|
|
160
|
+
* (`packages/rafa/src/core/command/running.ts`).
|
|
161
|
+
* The check runs once per session, before `Bun.spawn`: {@link spawnClaude}
|
|
162
|
+
* in json mode hands its session to the same unchecked spawner
|
|
163
|
+
* {@link spawnClaudeCaptured} uses rather than to that door, and so does
|
|
164
|
+
* not warn a second time.
|
|
165
|
+
*
|
|
166
|
+
* A run is covered when its command declares `always` or `through`, a
|
|
167
|
+
* `with` declaration and the run carries the flag, or an `unless`
|
|
168
|
+
* declaration and the run does not. `through` covers a run because the
|
|
169
|
+
* command runs another's action in-process (`rafa next`,
|
|
170
|
+
* `src/next/actions.ts`), and the recorded command stays the outer one.
|
|
171
|
+
* A flag is matched by its name without the dashes, and `--no-<name>`
|
|
172
|
+
* also as the parser keys it, `<name>` set to `false`; a flag recorded
|
|
173
|
+
* as `false` is not carried. With no command recorded, as for a caller
|
|
174
|
+
* that never went through the dispatcher, nothing is warned.
|
|
175
|
+
*
|
|
176
|
+
* The warning is one `warn` line at the active output, `⚠️ ` and then
|
|
177
|
+
* {@link spendWarning}'s sentence, which names the command as typed
|
|
178
|
+
* after `rafa` and says to declare `spends` on it, with the flag missing
|
|
179
|
+
* for a `with` form and the flag present for an `unless` one. It changes
|
|
180
|
+
* no exit code. In text mode it is a `warn:` line on the output's one
|
|
181
|
+
* stream (`packages/rafa/src/core/output/text.ts`); in json mode a `log` event at
|
|
182
|
+
* level `warn`; in events mode nothing, since that output drops `warn`.
|
|
183
|
+
*/
|
|
184
|
+
import type { RunningCommand } from '../command/running.js';
|
|
185
|
+
import type { ClaudeSettingSource } from '../config/config-sections.js';
|
|
186
|
+
/**
|
|
187
|
+
* The executable every session is spawned as.
|
|
188
|
+
*
|
|
189
|
+
* Resolved on PATH rather than by absolute path, which is what lets a
|
|
190
|
+
* version manager or a shim answer for it.
|
|
191
|
+
*/
|
|
192
|
+
export declare const CLAUDE_BIN = "claude";
|
|
193
|
+
/**
|
|
194
|
+
* Arguments every session gets, before any resolved flag.
|
|
195
|
+
*
|
|
196
|
+
* `-p` prints and exits, which is what makes the session
|
|
197
|
+
* non-interactive; `--dangerously-skip-permissions` is what lets it
|
|
198
|
+
* run unattended. Neither is a task's to choose, so neither is
|
|
199
|
+
* reachable from a declaration.
|
|
200
|
+
*/
|
|
201
|
+
export declare const CLAUDE_BASE_ARGS: readonly string[];
|
|
202
|
+
/**
|
|
203
|
+
* The flag every session names its setting sources with. See the
|
|
204
|
+
* module note.
|
|
205
|
+
*/
|
|
206
|
+
export declare const SETTING_SOURCES_FLAG = "--setting-sources";
|
|
207
|
+
/**
|
|
208
|
+
* Builds the argument list for one session: the base arguments, the
|
|
209
|
+
* setting sources, the served flags, then the flags.
|
|
210
|
+
*
|
|
211
|
+
* `settingSources` is the run's resolved `loop.settingSources`, joined
|
|
212
|
+
* with commas in the order given. `config.ts` has already refused a
|
|
213
|
+
* source the CLI does not name, a repeat and an empty list, so nothing
|
|
214
|
+
* is checked again here.
|
|
215
|
+
*
|
|
216
|
+
* `flags` is whatever a task's declaration resolved to, already
|
|
217
|
+
* validated and already ordered by its own resolver. Nothing is
|
|
218
|
+
* reordered, deduped or filtered here: this module has no opinion on
|
|
219
|
+
* which flags are legal, and one that did would be a second authority
|
|
220
|
+
* for a decision `core/plan/declaration.ts` already makes.
|
|
221
|
+
*
|
|
222
|
+
* `served` is `ServedSet.flags` from `serveResolution`
|
|
223
|
+
* (`src/tiers/serve.ts`), the session-only flags handing the run's
|
|
224
|
+
* served directory over, and is taken as it is for the same reason.
|
|
225
|
+
* It defaults to empty, so a caller that serves nothing spawns what it
|
|
226
|
+
* spawned before. It goes BEFORE `flags`, never after: `--tools` has to
|
|
227
|
+
* stay the last element (see the module note), and the served flags
|
|
228
|
+
* are safe ahead of the resolved ones, since `serve.ts` ends them with
|
|
229
|
+
* `--agents <json>` when an agent is served and every resolved flag
|
|
230
|
+
* starts with a dash, which is where the variadic `--add-dir` stops.
|
|
231
|
+
*/
|
|
232
|
+
export declare function claudeArgs(settingSources: readonly ClaudeSettingSource[], flags?: readonly string[], served?: readonly string[]): string[];
|
|
233
|
+
/**
|
|
234
|
+
* Runs `claude` with an argument list and a prompt on stdin, and
|
|
235
|
+
* answers the exit code.
|
|
236
|
+
*
|
|
237
|
+
* The seam every test drives, since the default {@link spawnClaude}
|
|
238
|
+
* cannot run under the root suite's runtime.
|
|
239
|
+
*/
|
|
240
|
+
export type ClaudeSpawner = (args: readonly string[], prompt: string, options?: CapturedSpawnOptions) => Promise<number>;
|
|
241
|
+
/**
|
|
242
|
+
* Sends SIGINT to every session either door spawned and has not yet seen
|
|
243
|
+
* exit, and answers how many that is. A process that exited before its
|
|
244
|
+
* door saw it is signalled too, which does nothing: measured under bun
|
|
245
|
+
* 1.3.14, `kill` on a subprocess that has exited throws nothing. See the
|
|
246
|
+
* module note.
|
|
247
|
+
*/
|
|
248
|
+
export declare function interruptClaudeSessions(): number;
|
|
249
|
+
/**
|
|
250
|
+
* True when `flags` carry `flag`, written as typed with its dashes: its
|
|
251
|
+
* name is recorded as anything but `false`, or, for a `--no-<name>`
|
|
252
|
+
* flag, `<name>` is recorded as `false`, which is how the parser keys it.
|
|
253
|
+
*/
|
|
254
|
+
export declare function carriesFlag(flags: RunningCommand['flags'], flag: string): boolean;
|
|
255
|
+
/**
|
|
256
|
+
* Why `running`'s declaration does not cover the session it starts, as a
|
|
257
|
+
* sentence, or null when it does or nothing is recorded.
|
|
258
|
+
*/
|
|
259
|
+
export declare function spendWarning(running: RunningCommand | null): string | null;
|
|
260
|
+
/**
|
|
261
|
+
* The real spawner: `Bun.spawn`, streams inherited so the session's
|
|
262
|
+
* output reaches the operator as it happens, in the working directory
|
|
263
|
+
* `options.cwd` names, or the loop's own when it names none.
|
|
264
|
+
*
|
|
265
|
+
* In json or events mode it spawns through {@link spawnClaudeCaptured}
|
|
266
|
+
* instead and answers that session's exit code, so the session's stdout
|
|
267
|
+
* reaches the active output's `info` and never the screen as bytes; see
|
|
268
|
+
* the module note.
|
|
269
|
+
*
|
|
270
|
+
* An exit code of `undefined` — which is what a signalled process
|
|
271
|
+
* answers — is reported as 1, because every caller here treats a
|
|
272
|
+
* non-zero as a failed session and a killed one is not a success.
|
|
273
|
+
*
|
|
274
|
+
* Warns, and spawns anyway, when the running command's `spends` does not
|
|
275
|
+
* cover the run; see the module note.
|
|
276
|
+
*/
|
|
277
|
+
export declare function spawnClaude(args: readonly string[], prompt: string, options?: CapturedSpawnOptions): Promise<number>;
|
|
278
|
+
/**
|
|
279
|
+
* Spawns one Claude session with `prompt` on stdin, loading settings
|
|
280
|
+
* from `settingSources`.
|
|
281
|
+
*
|
|
282
|
+
* `flags` defaults to empty, so the CI-repair session, which hands
|
|
283
|
+
* over none, cannot be routed by accident: it spawns the base arguments
|
|
284
|
+
* and its setting sources with no routing flag. `settingSources` has
|
|
285
|
+
* no default; see the module note.
|
|
286
|
+
*
|
|
287
|
+
* `served` is the flags handing a served directory over, which
|
|
288
|
+
* {@link claudeArgs} places between the setting sources and `flags`. It
|
|
289
|
+
* defaults to empty, and the CI repair hands none. `options` is where
|
|
290
|
+
* the session runs, handed to the spawner as it is; the CI repair names
|
|
291
|
+
* the run's checkout there (`start/pr-lifecycle.ts`). Both come last so
|
|
292
|
+
* that no call written before they existed has to change.
|
|
293
|
+
*/
|
|
294
|
+
export declare function runClaude(prompt: string, settingSources: readonly ClaudeSettingSource[], flags?: readonly string[], spawn?: ClaudeSpawner, served?: readonly string[], options?: CapturedSpawnOptions): Promise<number>;
|
|
295
|
+
/**
|
|
296
|
+
* What a captured session answers: its exit code, and everything it
|
|
297
|
+
* wrote to stdout, decoded as UTF-8.
|
|
298
|
+
*/
|
|
299
|
+
export interface CapturedSession {
|
|
300
|
+
readonly exitCode: number;
|
|
301
|
+
readonly stdout: string;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Where a captured session runs. Every field is optional, and an empty
|
|
305
|
+
* object spawns exactly what no options spawn.
|
|
306
|
+
*/
|
|
307
|
+
export interface CapturedSpawnOptions {
|
|
308
|
+
/**
|
|
309
|
+
* The session's working directory, or the loop's own when absent. The
|
|
310
|
+
* search session (`src/inventory/search/index.ts`) names the scratch
|
|
311
|
+
* copy of its candidates, each check session of the epic verification
|
|
312
|
+
* run (`src/epic/verify-run.ts`) a detached worktree of main, the plan
|
|
313
|
+
* session of the `claude` planner (`src/adapters/planner/claude.ts`)
|
|
314
|
+
* the project root it writes the plan under, and the loop's task,
|
|
315
|
+
* wrap-up and CI repair sessions the run's checkout
|
|
316
|
+
* (`src/start/checkout.ts`).
|
|
317
|
+
*/
|
|
318
|
+
readonly cwd?: string;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Runs `claude` with an argument list and a prompt on stdin, and
|
|
322
|
+
* answers the exit code together with the session's stdout.
|
|
323
|
+
*
|
|
324
|
+
* A seam of its own rather than a widened {@link ClaudeSpawner}:
|
|
325
|
+
* widening that one would change what every existing `runClaude`
|
|
326
|
+
* double has to answer, for sessions whose output nothing reads. The
|
|
327
|
+
* third parameter is optional for the same reason: a double written
|
|
328
|
+
* for `(args, prompt)` is still a `CapturingSpawner`.
|
|
329
|
+
*/
|
|
330
|
+
export type CapturingSpawner = (args: readonly string[], prompt: string, options?: CapturedSpawnOptions) => Promise<CapturedSession>;
|
|
331
|
+
/**
|
|
332
|
+
* The capturing spawner: `Bun.spawn` with stdout PIPED, each chunk
|
|
333
|
+
* written on to the operator's stdout as it arrives and kept for the
|
|
334
|
+
* answer.
|
|
335
|
+
*
|
|
336
|
+
* Everything else matches {@link spawnClaude}: the executable, the
|
|
337
|
+
* prompt on stdin, the environment. The working directory is the
|
|
338
|
+
* loop's own unless `options.cwd` names another, as it is for
|
|
339
|
+
* {@link spawnClaude}. Stderr stays inherited, so the
|
|
340
|
+
* operator sees it and the capture never holds it, and a report parsed
|
|
341
|
+
* out of `stdout` cannot have been a warning line.
|
|
342
|
+
*
|
|
343
|
+
* The bytes go through ONE streaming `TextDecoder`, never a decode per
|
|
344
|
+
* chunk, because a pipe read can end inside a character. Measured on
|
|
345
|
+
* bun 1.3.14, a `€` written in two halves arrived as the chunks
|
|
346
|
+
* `78 e2` and `82 ac 79`; decoded chunk by chunk that is three U+FFFD
|
|
347
|
+
* replacement characters where the streaming decoder answers the `€`.
|
|
348
|
+
* The decoder is not `fatal`, so bytes that are not UTF-8 at all
|
|
349
|
+
* become U+FFFD rather than a rejection.
|
|
350
|
+
*
|
|
351
|
+
* The answer waits for stdout to CLOSE as well as for the exit, which
|
|
352
|
+
* is what reading a pipe to its end means: a process the session left
|
|
353
|
+
* behind that still holds the pipe holds the answer too. Measured, a
|
|
354
|
+
* shell that backgrounded a `sleep 1.5` exited at 17ms and closed its
|
|
355
|
+
* stdout at 1,530ms.
|
|
356
|
+
*
|
|
357
|
+
* A signalled session needs no fallback here. Measured on bun 1.3.14,
|
|
358
|
+
* `exited` answers 128 plus the signal number (137 for a SIGKILL)
|
|
359
|
+
* while `exitCode` is null, so a killed session is already a non-zero,
|
|
360
|
+
* which every caller reads as a failure.
|
|
361
|
+
*
|
|
362
|
+
* When a write to the operator throws, the call rejects with that
|
|
363
|
+
* error, but only once the session has EXITED. Stopping the read does
|
|
364
|
+
* not stop the process: measured, a shell writing into a pipe whose
|
|
365
|
+
* reader had quit kept running, each write failing with `Broken pipe`,
|
|
366
|
+
* until it was killed 3s later. Rejecting at once would hand the loop
|
|
367
|
+
* back a tree that a session is still changing.
|
|
368
|
+
*
|
|
369
|
+
* Warns, and spawns anyway, when the running command's `spends` does not
|
|
370
|
+
* cover the run; see the module note.
|
|
371
|
+
*/
|
|
372
|
+
export declare function spawnClaudeCaptured(args: readonly string[], prompt: string, options?: CapturedSpawnOptions): Promise<CapturedSession>;
|
|
373
|
+
/**
|
|
374
|
+
* Spawns one Claude session with `prompt` on stdin, and answers its
|
|
375
|
+
* exit code together with everything it wrote to stdout.
|
|
376
|
+
*
|
|
377
|
+
* The argument list is the one {@link runClaude} builds for the same
|
|
378
|
+
* setting sources and flags, both going through {@link claudeArgs}, so
|
|
379
|
+
* capturing a session changes where its stdout goes and nothing about
|
|
380
|
+
* what is run. The operator still sees that output as it is written,
|
|
381
|
+
* through the tee in {@link spawnClaudeCaptured}.
|
|
382
|
+
*
|
|
383
|
+
* `served` and `options` are taken as {@link runClaude} takes them. The
|
|
384
|
+
* task session (`runTaskSession` in `start/dispatch.ts`) and the wrap-up
|
|
385
|
+
* (`start/wrap-up.ts`) are the two callers that hand any, and both name
|
|
386
|
+
* the run's checkout as the session's working directory.
|
|
387
|
+
*/
|
|
388
|
+
export declare function runClaudeCaptured(prompt: string, settingSources: readonly ClaudeSettingSource[], flags?: readonly string[], spawn?: CapturingSpawner, served?: readonly string[], options?: CapturedSpawnOptions): Promise<CapturedSession>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shapes of the hop record and of a place, with the checks that read
|
|
3
|
+
* them from parsed JSON: the part of `src/next/hop-record.ts` and
|
|
4
|
+
* `src/project/position.ts` a session record needs (`sessions.ts` keeps a
|
|
5
|
+
* hop record in its `hop` field).
|
|
6
|
+
*
|
|
7
|
+
* It sits in core so `sessions.ts` reads them without importing above
|
|
8
|
+
* core. `src/project/position.ts` re-exports `Place` and `asPlace`, and
|
|
9
|
+
* `src/next/hop-record.ts` re-exports `HopKind`, `HopState`, `HopRecord`
|
|
10
|
+
* and `asHopRecord`, each under the same name; the reading and writing of
|
|
11
|
+
* `.rafa/position.json` and `.rafa/hop.json`, and the module notes that
|
|
12
|
+
* describe both files, stay there. `isRecord` is exported for the
|
|
13
|
+
* position's own check in `position.ts`.
|
|
14
|
+
*
|
|
15
|
+
* The file imports nothing.
|
|
16
|
+
*/
|
|
17
|
+
/** A (board, epic) pair of issue numbers; `epic` is null on a board with no epic chosen. */
|
|
18
|
+
export interface Place {
|
|
19
|
+
readonly board: number;
|
|
20
|
+
readonly epic: number | null;
|
|
21
|
+
}
|
|
22
|
+
/** Why the hop went: H's blocker, or a home epic that ran dry. */
|
|
23
|
+
export type HopKind = 'blocker' | 'dry';
|
|
24
|
+
/** Where the hop stands: working its target, back home waiting on it or with it merged, or back home from a halt. */
|
|
25
|
+
export type HopState = 'away' | 'waiting' | 'merged' | 'halted';
|
|
26
|
+
/** The record `.rafa/hop.json` holds; see the module note of `src/next/hop-record.ts`. */
|
|
27
|
+
export interface HopRecord {
|
|
28
|
+
readonly kind: HopKind;
|
|
29
|
+
readonly home: Place;
|
|
30
|
+
readonly from: Place;
|
|
31
|
+
/** H, the home issue its blocker stopped; null on a dry hop. */
|
|
32
|
+
readonly blocked: number | null;
|
|
33
|
+
/** C, H's blocker the hop works; null on a dry hop. */
|
|
34
|
+
readonly target: number | null;
|
|
35
|
+
readonly targetEpic: number;
|
|
36
|
+
readonly targetBoard: number;
|
|
37
|
+
readonly state: HopState;
|
|
38
|
+
/** The target's pull request, null before it is opened. */
|
|
39
|
+
readonly pullRequest: number | null;
|
|
40
|
+
/** ISO 8601. */
|
|
41
|
+
readonly startedAt: string;
|
|
42
|
+
}
|
|
43
|
+
/** True for a plain object. */
|
|
44
|
+
export declare function isRecord(value: unknown): value is Record<string, unknown>;
|
|
45
|
+
/** `value` as a place, or null when it is not one; the hop record reads its places through it. */
|
|
46
|
+
export declare function asPlace(value: unknown): Place | null;
|
|
47
|
+
/**
|
|
48
|
+
* `value` as a hop record, or null when it is not one: the check
|
|
49
|
+
* `readHopRecord` (`src/next/hop-record.ts`) makes on the parsed file,
|
|
50
|
+
* which the session record makes on its `hop` field (`sessions.ts`).
|
|
51
|
+
*/
|
|
52
|
+
export declare function asHopRecord(value: unknown): HopRecord | null;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The barrel over the loop's session records and its doors onto the
|
|
3
|
+
* Claude CLI: every name `sessions.ts`, `claude.ts`, `session-env.ts` and
|
|
4
|
+
* `suite-failure.ts` export, and nothing else.
|
|
5
|
+
*
|
|
6
|
+
* A file outside `packages/rafa/src/core/` imports this file and never the two behind
|
|
7
|
+
* it (`scripts/survey/core-barrels.ts` measures that, and
|
|
8
|
+
* `src/tests/core-barrels.sweep.test.ts` holds it against the tree). A
|
|
9
|
+
* file inside `packages/rafa/src/core/` imports the two directly and never this file:
|
|
10
|
+
* `session-readings.ts` and the six test files of `sessions.ts` import
|
|
11
|
+
* that file, and `packages/rafa/src/core/adapters/registry.ts` and
|
|
12
|
+
* `claude.test.ts` import `claude.ts`. `index.test.ts`, this file's own
|
|
13
|
+
* test, is the one file of `packages/rafa/src/core/` that imports it.
|
|
14
|
+
*
|
|
15
|
+
* ## What sits behind it
|
|
16
|
+
*
|
|
17
|
+
* - `sessions.ts`: the session records of `loop start`, one JSON file
|
|
18
|
+
* per run under `<root>/.rafa/runs/`, with their reads, the state a
|
|
19
|
+
* record reads as, the refusal of a second run of a plan, and the
|
|
20
|
+
* writes;
|
|
21
|
+
* - `claude.ts`: the two doors a Claude session is spawned through,
|
|
22
|
+
* the argument list both build, the spawners behind them, the
|
|
23
|
+
* interrupt of the sessions still running, and the spend guard's
|
|
24
|
+
* sentence;
|
|
25
|
+
* - `session-env.ts`: the environment a Claude session is spawned
|
|
26
|
+
* with, which `claude.ts` imports by path;
|
|
27
|
+
* - `suite-failure.ts`: the type of one failing test, which
|
|
28
|
+
* `sessions.ts` imports by path and `src/suite/run.ts` re-exports.
|
|
29
|
+
*
|
|
30
|
+
* The four files share no name, and only `sessions.ts` imports
|
|
31
|
+
* `suite-failure.ts`, for a type. One
|
|
32
|
+
* import of this barrel loads both: a file that takes `isPidAlive`
|
|
33
|
+
* alone loads `claude.ts` with it.
|
|
34
|
+
*
|
|
35
|
+
* The reading of one record is `session-record-parse.ts`, beside
|
|
36
|
+
* `sessions.ts`, which imports it by path: the sets a record's fields
|
|
37
|
+
* are checked against, `parseSessionRecord`, `SessionRecordError` and
|
|
38
|
+
* the readers of the optional fields. It was
|
|
39
|
+
* `src/loop/session-record-parse.ts` until it moved here, and a
|
|
40
|
+
* re-export stays at that path. `sessions.ts` re-exports what a caller
|
|
41
|
+
* of a record reads from there, four types and thirteen runtime names,
|
|
42
|
+
* and this barrel carries them with the rest, so the parser takes no
|
|
43
|
+
* line of its own here. So a file outside `packages/rafa/src/core/` that reads a
|
|
44
|
+
* record needs this one import, as it needed `sessions.ts` alone before
|
|
45
|
+
* the move.
|
|
46
|
+
*
|
|
47
|
+
* ## Why `claude.ts` is here
|
|
48
|
+
*
|
|
49
|
+
* A barrel is split when it would close a runtime cycle, and never
|
|
50
|
+
* otherwise. `claude.ts` was the third file to move into this folder,
|
|
51
|
+
* and it closes none behind this barrel, so it took no barrel of its
|
|
52
|
+
* own. The section "Why the barrel closes no cycle" holds the
|
|
53
|
+
* measurement.
|
|
54
|
+
*
|
|
55
|
+
* ## Why the session readings are not here
|
|
56
|
+
*
|
|
57
|
+
* `packages/rafa/src/core/loop/` has three barrels, all listed under `CORE_BARRELS` in
|
|
58
|
+
* `scripts/survey/core-moves.ts`. `session-readings.ts`, the second
|
|
59
|
+
* file that moved here, sits alone behind `readings.ts`. It reaches
|
|
60
|
+
* `packages/rafa/src/effort/store/development-build.ts` by value, through
|
|
61
|
+
* `packages/rafa/src/effort/store/task-finishes.ts`, and that file imports three
|
|
62
|
+
* runtime names from this barrel. With `session-readings.ts` behind
|
|
63
|
+
* this barrel the store would import this file, and this file the
|
|
64
|
+
* store: a cycle of six files. `readings.ts` records the measurement,
|
|
65
|
+
* and `readings.test.ts` holds that no name is on both barrels.
|
|
66
|
+
*
|
|
67
|
+
* ## Why the hop record is not here
|
|
68
|
+
*
|
|
69
|
+
* `hop-record.ts`, the shapes of the hop record and of a place, sits
|
|
70
|
+
* alone behind `hops.ts`. `src/next/hop-record.ts` and
|
|
71
|
+
* `src/project/position.ts` re-export its names, so they import a
|
|
72
|
+
* barrel over it by value, and `src/loop/session-record-parse.ts`,
|
|
73
|
+
* which `sessions.ts` imported by value, imported `asHopRecord` from
|
|
74
|
+
* `src/next/hop-record.ts` by value when the split was made; it has
|
|
75
|
+
* since moved here and imports `hop-record.ts` by path. With `hop-record.ts` behind this
|
|
76
|
+
* barrel that is a cycle of four files: this one, `sessions.ts`, the
|
|
77
|
+
* parser and `src/next/hop-record.ts`. `hops.ts` records the
|
|
78
|
+
* measurement, and `hops.test.ts` holds that no name is on two loop
|
|
79
|
+
* barrels. `sessions.ts` imports `hop-record.ts` by path, for
|
|
80
|
+
* `HopRecord`.
|
|
81
|
+
*
|
|
82
|
+
* ## Why the barrel closes no cycle
|
|
83
|
+
*
|
|
84
|
+
* A barrel that groups a file with a file outside `packages/rafa/src/core/` that
|
|
85
|
+
* imports the barrel back by value is a runtime cycle. `sessions.ts`
|
|
86
|
+
* imported three files by value when it moved:
|
|
87
|
+
* `packages/rafa/src/core/config/config-sections.ts`, for `messageOf`, and two outside
|
|
88
|
+
* `packages/rafa/src/core/`, `src/loop/session-record-parse.ts` and
|
|
89
|
+
* `src/project/scope.ts`. Through them it reached 38 files by value, and
|
|
90
|
+
* none of the 38 imported it by value. Both have since moved into
|
|
91
|
+
* `packages/rafa/src/core/`, as `session-record-parse.ts` beside it and
|
|
92
|
+
* `packages/rafa/src/core/config/scope.ts`.
|
|
93
|
+
*
|
|
94
|
+
* The parser, then `src/loop/session-record-parse.ts`, imported this
|
|
95
|
+
* barrel for the record's interfaces with `import type` alone, which is
|
|
96
|
+
* erased before anything loads; since it moved here as
|
|
97
|
+
* `session-record-parse.ts` it imports `sessions.ts` by path, the same
|
|
98
|
+
* way. Its own note says why its sets, its error and its id check live
|
|
99
|
+
* on its side: so that it takes no value from `sessions.ts`. That rule
|
|
100
|
+
* holds this barrel as well.
|
|
101
|
+
*
|
|
102
|
+
* Measured when the file moved: the value imports of the non-test files
|
|
103
|
+
* under `src/` and `packages/` held six cycles before the move and the
|
|
104
|
+
* same six after it, none through a file of this folder. The control,
|
|
105
|
+
* the same tree with `src/loop/session-record-parse.ts` taking one
|
|
106
|
+
* function (`errorCode`) from this barrel and calling it inside a
|
|
107
|
+
* function, held a seventh: this file, `sessions.ts` and that one.
|
|
108
|
+
*
|
|
109
|
+
* That seventh loaded in the three orders tried: this file,
|
|
110
|
+
* `sessions.ts` and `src/loop/session-record-parse.ts` each imported
|
|
111
|
+
* first in a fresh `bun` process, then one record parsed through this
|
|
112
|
+
* barrel. A second control took a `const` (`RUNS_DIR`) instead and read
|
|
113
|
+
* it at the top level of `src/loop/session-record-parse.ts`. It loaded
|
|
114
|
+
* when that file came first, and failed with
|
|
115
|
+
* `ReferenceError: Cannot access 'RUNS_DIR' before initialization.`
|
|
116
|
+
* when this file or `sessions.ts` did. The barrel holds the rule rather
|
|
117
|
+
* than the first reading.
|
|
118
|
+
*
|
|
119
|
+
* `src/tests/import-cycle.sweep.test.ts` would have refused both
|
|
120
|
+
* controls. It fails on a cycle across two clusters of
|
|
121
|
+
* `docs/survey/cluster-map.json`, which places `sessions.ts` in c2 and
|
|
122
|
+
* `src/loop/session-record-parse.ts` in c3; this file, which the map
|
|
123
|
+
* does not name, lands in c2 by its folder. Read the way the sweep
|
|
124
|
+
* reads the graph, each control held one cross-cluster cycle and the
|
|
125
|
+
* tree as moved held none.
|
|
126
|
+
*
|
|
127
|
+
* `claude.ts` imports four files by value: three of `packages/rafa/src/core/`,
|
|
128
|
+
* `packages/rafa/src/core/command/command.ts` for `commandSpelling`,
|
|
129
|
+
* `packages/rafa/src/core/command/running.ts` for the running command and
|
|
130
|
+
* `packages/rafa/src/core/output/active.ts` for the active output, and one outside
|
|
131
|
+
* it, `src/utils/session-env.ts`, which has since moved here as
|
|
132
|
+
* `session-env.ts`. When it moved, `running.ts` was still
|
|
133
|
+
* `src/cli/running.ts`; through the four it reached 13 files by value, and none of the 13
|
|
134
|
+
* imported this barrel or `claude.ts` by value. None of the 38 files
|
|
135
|
+
* `sessions.ts` reached did either. Eleven non-test files imported
|
|
136
|
+
* `claude.ts` by value before the move and import this barrel since.
|
|
137
|
+
*
|
|
138
|
+
* Measured when `claude.ts` moved: the same six cycles before the move
|
|
139
|
+
* and after it, none through a file of this folder, with this barrel
|
|
140
|
+
* reaching 46 files by value. The control, the same tree with
|
|
141
|
+
* `src/utils/session-env.ts` taking `CLAUDE_BIN` from this barrel and
|
|
142
|
+
* returning it from a function, held a seventh of three files: this
|
|
143
|
+
* file, `claude.ts` and that one.
|
|
144
|
+
*
|
|
145
|
+
* That seventh loaded in the three orders tried: each of the three
|
|
146
|
+
* files imported first in a fresh `bun` process, then `claudeArgs`
|
|
147
|
+
* called and `CLAUDE_BIN` and `RUNS_DIR` read through this barrel. A
|
|
148
|
+
* second control read `CLAUDE_BIN` at the top level of
|
|
149
|
+
* `src/utils/session-env.ts` instead. It loaded when that file came
|
|
150
|
+
* first, and failed with
|
|
151
|
+
* `ReferenceError: Cannot access 'CLAUDE_BIN' before initialization.`
|
|
152
|
+
* when this file or `claude.ts` did.
|
|
153
|
+
*
|
|
154
|
+
* The map places `claude.ts` in c3 and `src/utils/session-env.ts` in
|
|
155
|
+
* c4. The folder's two mapped files now tie, one in c2 and one in c3,
|
|
156
|
+
* and a tie goes to the name that sorts first, so this file still lands
|
|
157
|
+
* in c2. Read the way the sweep reads the graph, the first control held
|
|
158
|
+
* one cross-cluster cycle, c2 with c3 and c4, and the tree as moved
|
|
159
|
+
* held none.
|
|
160
|
+
*
|
|
161
|
+
* ## What it exports
|
|
162
|
+
*
|
|
163
|
+
* Each name is spelled, types apart from values, as the other core
|
|
164
|
+
* barrels spell theirs. No name here is part of the published surface:
|
|
165
|
+
* `src/index.ts` re-exports nothing from this file.
|
|
166
|
+
*
|
|
167
|
+
* `index.test.ts` holds the list to the four files: every name each
|
|
168
|
+
* exports is here once, as the same binding, the first three share no name, the
|
|
169
|
+
* names `sessions.ts` re-exports are the bindings
|
|
170
|
+
* `session-record-parse.ts` declares, and no other name is
|
|
171
|
+
* here.
|
|
172
|
+
*/
|
|
173
|
+
export type { PidProbe, SessionChange, SessionConflict, SessionConflictReason, SessionDecision, SessionDraft, SessionPhase, SessionReadSeams, SessionRecord, SessionState, SessionStep, SessionStepKind, SessionStepOnly, SessionStepReason, SessionTask, SessionTaskRef, } from './sessions.js';
|
|
174
|
+
export type { CapturedSession, CapturedSpawnOptions, CapturingSpawner, ClaudeSpawner } from './claude.js';
|
|
175
|
+
export type { SpawnEnv } from './session-env.js';
|
|
176
|
+
export type { SuiteFailure } from './suite-failure.js';
|
|
177
|
+
export { beginSession, errorCode, isPidAlive, isPositiveWhole, isSessionId, parseSessionRecord, readSession, readSessions, readState, RECORD_EXTENSION, RUNS_DIR, runsDir, samePlan, SESSION_DECISION_STRATEGIES, SESSION_PHASES, SESSION_STATES, SESSION_STEP_KINDS, SESSION_STEP_REASONS, SessionConflictError, sessionConflicts, sessionDecisions, sessionFilePath, sessionPhase, SessionRecordError, SessionStateError, sessionSteps, updateSession, } from './sessions.js';
|
|
178
|
+
export { carriesFlag, CLAUDE_BASE_ARGS, CLAUDE_BIN, claudeArgs, interruptClaudeSessions, runClaude, runClaudeCaptured, SETTING_SOURCES_FLAG, spawnClaude, spawnClaudeCaptured, spendWarning, } from './claude.js';
|
|
179
|
+
export { sessionPath, sessionSpawnEnv } from './session-env.js';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** An environment as `process.env` and `Bun.spawn` spell it. */
|
|
2
|
+
export type SpawnEnv = Record<string, string | undefined>;
|
|
3
|
+
/**
|
|
4
|
+
* `base`'s `PATH` with `binDir` in front, or `binDir` alone for a base
|
|
5
|
+
* with no `PATH` or an empty one. See "`bundled/bin` goes first on
|
|
6
|
+
* `PATH`".
|
|
7
|
+
*/
|
|
8
|
+
export declare function sessionPath(base: string | undefined, binDir: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* The environment every session is spawned with: `base`, plus the two
|
|
11
|
+
* entries a session must see whichever spawner started it.
|
|
12
|
+
*
|
|
13
|
+
* `PATH` is `binDir`, the running entry's `bundled/bin` unless another
|
|
14
|
+
* is handed, in front of `base`'s own ({@link sessionPath}).
|
|
15
|
+
* `CLAUDE_CODE_ENTRYPOINT` is set to `cli` over whatever `base` holds
|
|
16
|
+
* for it, so a shell that already carries another value still spawns
|
|
17
|
+
* `cli`. Every other entry of `base` is handed on as it is, an entry
|
|
18
|
+
* holding `undefined` included.
|
|
19
|
+
*/
|
|
20
|
+
export declare function sessionSpawnEnv(base: Readonly<SpawnEnv>, binDir?: string): SpawnEnv;
|