@vibe-commit/capture 0.1.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/LICENSE +21 -0
- package/README.md +66 -0
- package/dist/agents/claude_code.d.ts +11 -0
- package/dist/agents/claude_code.js +162 -0
- package/dist/agents/claude_code.js.map +1 -0
- package/dist/agents/codex_cli.d.ts +15 -0
- package/dist/agents/codex_cli.js +67 -0
- package/dist/agents/codex_cli.js.map +1 -0
- package/dist/agents/cursor.d.ts +21 -0
- package/dist/agents/cursor.js +89 -0
- package/dist/agents/cursor.js.map +1 -0
- package/dist/agents/registry.d.ts +184 -0
- package/dist/agents/registry.js +212 -0
- package/dist/agents/registry.js.map +1 -0
- package/dist/agents/types.d.ts +279 -0
- package/dist/agents/types.js +67 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/commands/connect.d.ts +36 -0
- package/dist/commands/connect.js +499 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/context.d.ts +45 -0
- package/dist/commands/context.js +14 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/report.d.ts +105 -0
- package/dist/commands/report.js +430 -0
- package/dist/commands/report.js.map +1 -0
- package/dist/commands/status.d.ts +29 -0
- package/dist/commands/status.js +236 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/why.d.ts +349 -0
- package/dist/commands/why.js +937 -0
- package/dist/commands/why.js.map +1 -0
- package/dist/consent.d.ts +59 -0
- package/dist/consent.js +111 -0
- package/dist/consent.js.map +1 -0
- package/dist/copy/claims.d.ts +79 -0
- package/dist/copy/claims.js +343 -0
- package/dist/copy/claims.js.map +1 -0
- package/dist/copy/grades.d.ts +117 -0
- package/dist/copy/grades.js +96 -0
- package/dist/copy/grades.js.map +1 -0
- package/dist/copy/index.d.ts +12 -0
- package/dist/copy/index.js +13 -0
- package/dist/copy/index.js.map +1 -0
- package/dist/copy/strings.d.ts +1328 -0
- package/dist/copy/strings.js +1243 -0
- package/dist/copy/strings.js.map +1 -0
- package/dist/copy/time.d.ts +27 -0
- package/dist/copy/time.js +43 -0
- package/dist/copy/time.js.map +1 -0
- package/dist/credential.d.ts +211 -0
- package/dist/credential.js +298 -0
- package/dist/credential.js.map +1 -0
- package/dist/exit.d.ts +59 -0
- package/dist/exit.js +60 -0
- package/dist/exit.js.map +1 -0
- package/dist/git.d.ts +299 -0
- package/dist/git.js +653 -0
- package/dist/git.js.map +1 -0
- package/dist/hooks/entry.d.ts +277 -0
- package/dist/hooks/entry.js +1092 -0
- package/dist/hooks/entry.js.map +1 -0
- package/dist/hooks/post_commit.d.ts +59 -0
- package/dist/hooks/post_commit.js +160 -0
- package/dist/hooks/post_commit.js.map +1 -0
- package/dist/hooks/post_rewrite.d.ts +59 -0
- package/dist/hooks/post_rewrite.js +161 -0
- package/dist/hooks/post_rewrite.js.map +1 -0
- package/dist/hooks/session_end.d.ts +101 -0
- package/dist/hooks/session_end.js +120 -0
- package/dist/hooks/session_end.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +360 -0
- package/dist/index.js.map +1 -0
- package/dist/install.d.ts +153 -0
- package/dist/install.js +284 -0
- package/dist/install.js.map +1 -0
- package/dist/json.d.ts +100 -0
- package/dist/json.js +94 -0
- package/dist/json.js.map +1 -0
- package/dist/oauth/discovery.d.ts +96 -0
- package/dist/oauth/discovery.js +163 -0
- package/dist/oauth/discovery.js.map +1 -0
- package/dist/oauth/lock.d.ts +100 -0
- package/dist/oauth/lock.js +287 -0
- package/dist/oauth/lock.js.map +1 -0
- package/dist/oauth/loopback.d.ts +85 -0
- package/dist/oauth/loopback.js +124 -0
- package/dist/oauth/loopback.js.map +1 -0
- package/dist/oauth/pkce.d.ts +58 -0
- package/dist/oauth/pkce.js +77 -0
- package/dist/oauth/pkce.js.map +1 -0
- package/dist/oauth/read.d.ts +120 -0
- package/dist/oauth/read.js +144 -0
- package/dist/oauth/read.js.map +1 -0
- package/dist/oauth/session.d.ts +80 -0
- package/dist/oauth/session.js +112 -0
- package/dist/oauth/session.js.map +1 -0
- package/dist/oauth/signin.d.ts +178 -0
- package/dist/oauth/signin.js +225 -0
- package/dist/oauth/signin.js.map +1 -0
- package/dist/oauth/token.d.ts +139 -0
- package/dist/oauth/token.js +183 -0
- package/dist/oauth/token.js.map +1 -0
- package/dist/paths.d.ts +366 -0
- package/dist/paths.js +460 -0
- package/dist/paths.js.map +1 -0
- package/dist/policy.d.ts +195 -0
- package/dist/policy.js +244 -0
- package/dist/policy.js.map +1 -0
- package/dist/post.d.ts +302 -0
- package/dist/post.js +384 -0
- package/dist/post.js.map +1 -0
- package/dist/project.d.ts +99 -0
- package/dist/project.js +192 -0
- package/dist/project.js.map +1 -0
- package/dist/redact.d.ts +175 -0
- package/dist/redact.js +700 -0
- package/dist/redact.js.map +1 -0
- package/dist/runtime.d.ts +30 -0
- package/dist/runtime.js +37 -0
- package/dist/runtime.js.map +1 -0
- package/dist/spawn_budget.d.ts +101 -0
- package/dist/spawn_budget.js +124 -0
- package/dist/spawn_budget.js.map +1 -0
- package/dist/spool.d.ts +390 -0
- package/dist/spool.js +556 -0
- package/dist/spool.js.map +1 -0
- package/dist/state.d.ts +109 -0
- package/dist/state.js +217 -0
- package/dist/state.js.map +1 -0
- package/dist/system_message.d.ts +101 -0
- package/dist/system_message.js +141 -0
- package/dist/system_message.js.map +1 -0
- package/dist/term.d.ts +112 -0
- package/dist/term.js +134 -0
- package/dist/term.js.map +1 -0
- package/dist/version.d.ts +16 -0
- package/dist/version.js +17 -0
- package/dist/version.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The hook client — and the enforcement of the hook half of the exit contract.
|
|
3
|
+
*
|
|
4
|
+
* DESIGN.md §13.7, restated because every line below exists to hold it:
|
|
5
|
+
*
|
|
6
|
+
* exit ALWAYS 0. Every path: success, 401, 403, network failure,
|
|
7
|
+
* uncaught exception, unsupported Node, signal.
|
|
8
|
+
* stderr ALWAYS empty.
|
|
9
|
+
* wall clock ALWAYS under the hooks.json timeout for that event.
|
|
10
|
+
* stdout At most one well-formed JSON object carrying `systemMessage`;
|
|
11
|
+
* otherwise empty. If JSON construction fails for ANY reason →
|
|
12
|
+
* empty stdout. The fallback is always silence.
|
|
13
|
+
*
|
|
14
|
+
* ⚠ **That stdout line reads "EMPTY on the happy path" in DESIGN.md §13.7, and
|
|
15
|
+
* as of `CR-023d` it is no longer true.** Style guide §10.1's fourth state
|
|
16
|
+
* (`capture confirmed`) fires on a successful send, once per `(repo, day)` — so
|
|
17
|
+
* a populated stdout no longer implies something went wrong. §13.7 and §10.1
|
|
18
|
+
* disagreed on this before this task; the code now follows §10.1, which D65
|
|
19
|
+
* records as the executed ruling. DESIGN.md is orchestrator-owned (D66 §3), so
|
|
20
|
+
* the amendment there is reported, not made here.
|
|
21
|
+
*
|
|
22
|
+
* **A hook that exits non-zero feeds stderr back into the user's agent and
|
|
23
|
+
* derails the task they were actually doing.** That is the whole reason.
|
|
24
|
+
*
|
|
25
|
+
* ## Read this before trusting a green contract test
|
|
26
|
+
*
|
|
27
|
+
* `silenceStderr()` makes the stderr-empty assertion true STRUCTURALLY. That is
|
|
28
|
+
* the correct engineering choice — it is the only thing that holds when a
|
|
29
|
+
* dependency three levels down decides to warn — but it also means a green
|
|
30
|
+
* "stderr is empty" proves the hook never speaks, and proves **nothing** about
|
|
31
|
+
* whether the credential is handled carefully. The credential's own control is
|
|
32
|
+
* separate and lives in `credential.ts` (opaque wrapper + redaction), with its
|
|
33
|
+
* own red-proof in `test/credential.test.ts`. Do not read one as evidence for
|
|
34
|
+
* the other.
|
|
35
|
+
*/
|
|
36
|
+
import { type ProjectKeys } from "../project.js";
|
|
37
|
+
/**
|
|
38
|
+
* Default wall-clock budget. `CR-028` sets the real per-event `timeout` in
|
|
39
|
+
* `claude-plugin/hooks/hooks.json`; this is the client-side backstop, which must
|
|
40
|
+
* be the SMALLER of the two or the backstop never fires.
|
|
41
|
+
*
|
|
42
|
+
* ⚠ **That relation was prose and was checked by nothing until `CR-183`.** It is
|
|
43
|
+
* now asserted for every event of every dialect in `test/agent-registry.test.ts`,
|
|
44
|
+
* which also pins this constant against the `claude-code` dialect's own entry.
|
|
45
|
+
*/
|
|
46
|
+
export declare const DEFAULT_HOOK_BUDGET_MS = 5000;
|
|
47
|
+
/**
|
|
48
|
+
* What one send attempt may take, after the settle has taken its share.
|
|
49
|
+
*
|
|
50
|
+
* `consumedMs` is 0 on every event but `SessionEnd`, and at 0 this is exactly
|
|
51
|
+
* the expression that was inline here before `CR-020d`
|
|
52
|
+
* (`Math.floor(budgetMs * SEND_BUDGET_FRACTION)`) for any budget above ~84 ms —
|
|
53
|
+
* so `Stop` and `PreCompact` are unchanged in both timing and code path.
|
|
54
|
+
*/
|
|
55
|
+
export declare function sendTimeoutMs(budgetMs: number, consumedMs: number): number;
|
|
56
|
+
/**
|
|
57
|
+
* The budget the SENDS may spend — the whole budget, less the stamp's share.
|
|
58
|
+
*
|
|
59
|
+
* A function, and exported, for the reason `sendTimeoutMs` is: the carve-out is
|
|
60
|
+
* the thing this task changes, and a wall-clock test cannot pin it. Every
|
|
61
|
+
* discriminator that distinguishes reserve from no-reserve through a real
|
|
62
|
+
* process turned out to slide with per-send overhead — a 149 ms window that
|
|
63
|
+
* moves by 25 ms for every 10 ms of connect-and-compress cost — so pinning it
|
|
64
|
+
* there would be tuning a constant to one machine. Here it is arithmetic.
|
|
65
|
+
*
|
|
66
|
+
* ⛔ `budgetMs` itself still governs the SETTLE and the WATCHDOG. Only the sends
|
|
67
|
+
* are carved.
|
|
68
|
+
*/
|
|
69
|
+
export declare function sendBudgetMs(budgetMs: number, eventName: string): number;
|
|
70
|
+
export interface HookInput {
|
|
71
|
+
readonly sessionId: string;
|
|
72
|
+
readonly transcriptPath: string;
|
|
73
|
+
readonly cwd: string;
|
|
74
|
+
readonly eventName: string;
|
|
75
|
+
/**
|
|
76
|
+
* ⛔ **THE ANNOUNCED DELEGATED TRANSCRIPT — `CR-196`, D177 §9.**
|
|
77
|
+
*
|
|
78
|
+
* `agent_transcript_path`, which an `announce` dialect hands over on stdin
|
|
79
|
+
* instead of writing a directory to glob. Absent for `discover` dialects and
|
|
80
|
+
* absent on every event but the one that delegates, so `undefined` is the
|
|
81
|
+
* ordinary case rather than an error.
|
|
82
|
+
*
|
|
83
|
+
* ⛔ **INPUT, in the full `/cso` finding-1 sense.** It is a path that reaches
|
|
84
|
+
* a read whose result is uploaded, so it is confined exactly as the main
|
|
85
|
+
* transcript is — `admitsTranscript`, which is the registry-computed boundary
|
|
86
|
+
* plus the file gate. Being handed a path by the agent is not evidence about
|
|
87
|
+
* where the path points.
|
|
88
|
+
*/
|
|
89
|
+
readonly agentTranscriptPath?: string;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Parse hook stdin. Claude Code supplies `{ session_id, transcript_path, cwd,
|
|
93
|
+
* hook_event_name }` on stdin — NOT in the environment.
|
|
94
|
+
*
|
|
95
|
+
* ⚠ **And an `announce` dialect adds `agent_transcript_path` (`CR-196`).** It is
|
|
96
|
+
* OPTIONAL in both directions: a `discover` install never sends it, and reading
|
|
97
|
+
* it here rather than in a Cursor-specific parser is deliberate — stdin has one
|
|
98
|
+
* shape and one parser, and a second one would be a second place for the
|
|
99
|
+
* confinement boundary to be forgotten.
|
|
100
|
+
*
|
|
101
|
+
* Returns null on anything malformed. A hook cannot report a parse error (stderr
|
|
102
|
+
* is empty by contract), so the only honest response is to do nothing. ⚠ A
|
|
103
|
+
* malformed `agent_transcript_path` is NOT malformed input: it is dropped and
|
|
104
|
+
* the main transcript still goes, because losing the whole capture over a
|
|
105
|
+
* delegated extra would be the larger loss.
|
|
106
|
+
*/
|
|
107
|
+
export declare function parseHookInput(raw: string): HookInput | null;
|
|
108
|
+
/**
|
|
109
|
+
* Replace stderr with a sink for the rest of the process.
|
|
110
|
+
*
|
|
111
|
+
* Node writes uncaught exceptions, unhandled rejections and process warnings to
|
|
112
|
+
* `process.stderr`, so overriding `write` is what makes the contract hold on the
|
|
113
|
+
* paths we do not control. The handlers below stop the non-zero exit; this stops
|
|
114
|
+
* the bytes.
|
|
115
|
+
*/
|
|
116
|
+
export declare function silenceStderr(): void;
|
|
117
|
+
export interface HookEnvironment {
|
|
118
|
+
readonly env: NodeJS.ProcessEnv;
|
|
119
|
+
readonly home: string;
|
|
120
|
+
readonly nodeVersion: string;
|
|
121
|
+
/**
|
|
122
|
+
* ⛔ **WHICH AGENT REGISTERED THE HOOK — `--agent=<id>`, resolved in
|
|
123
|
+
* `index.ts`. NOT which agent produced the transcript.**
|
|
124
|
+
*
|
|
125
|
+
* ## The split, and it is load-bearing (`CR-204`, D177 §7)
|
|
126
|
+
*
|
|
127
|
+
* `agentId` answered two different questions until `CR-204`, and one of the
|
|
128
|
+
* two answers was routinely wrong. What each is derived from now:
|
|
129
|
+
*
|
|
130
|
+
* | use | derived from |
|
|
131
|
+
* |---|---|
|
|
132
|
+
* | wire `X-Agent` | ⛔ the CONTAINING ROOT (`agentForTranscript`) |
|
|
133
|
+
* | delegated-transcript discovery | ⛔ the CONTAINING ROOT — sub-agent LAYOUT is a property of the transcript |
|
|
134
|
+
* | the redaction profile | ⛔ the CONTAINING ROOT (`rulesForTranscript`, `CR-185`) |
|
|
135
|
+
* | ⛔ **hook budgets and timeouts** | ⛔ **THIS FIELD** |
|
|
136
|
+
*
|
|
137
|
+
* The budget is the one thing the flag is genuinely the oracle for: the clock
|
|
138
|
+
* belongs to the PROCESS THAT REGISTERED THE HOOK and is waiting on our exit,
|
|
139
|
+
* and it is armed before stdin is read — before any transcript path exists to
|
|
140
|
+
* ask a root about. The other three are properties of the FILE, and no install
|
|
141
|
+
* passes the flag anyway (`DEFAULT_AGENT_ID` is `claude-code`), so deriving
|
|
142
|
+
* them from it meant answering `claude-code` for everyone.
|
|
143
|
+
*
|
|
144
|
+
* ⛔ **HERE, and not on `HookInput`.** `HookInput` is parsed from stdin, which
|
|
145
|
+
* is the attacker-influenced input the confinement boundary exists to
|
|
146
|
+
* constrain; a selector read from there would be the rejected
|
|
147
|
+
* `transcript_path`-as-selector design wearing a different field name. This
|
|
148
|
+
* field arrives through the same injected seam as `home` and `nodeVersion`.
|
|
149
|
+
*
|
|
150
|
+
* The LITERAL, unnarrowed: an id we do not recognise falls back to the default
|
|
151
|
+
* dialect for BEHAVIOUR and is never coerced as a value (plan §D7). ⚠ That is
|
|
152
|
+
* also why it is a `string` and `SelectedAgentId` is not — the flag is not
|
|
153
|
+
* assignable to the value the wire is built from.
|
|
154
|
+
*/
|
|
155
|
+
readonly agentId: string;
|
|
156
|
+
readonly readStdin: () => Promise<string>;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Install every contract guard, then run the body.
|
|
160
|
+
*
|
|
161
|
+
* Guards go in FIRST, before any work, because the paths they cover include
|
|
162
|
+
* "the body threw on its first line".
|
|
163
|
+
*/
|
|
164
|
+
export declare function runHook(ctx: HookEnvironment): Promise<never>;
|
|
165
|
+
/**
|
|
166
|
+
* The wall clock this invocation gets.
|
|
167
|
+
*
|
|
168
|
+
* ⛔ **THE TIGHTEST BUDGET THE DIALECT REGISTERS, and the reason is the ORDER
|
|
169
|
+
* things happen in `runHook`** — the watchdog is armed BEFORE stdin is read, so
|
|
170
|
+
* the event name is not known yet and a per-event budget cannot be applied here
|
|
171
|
+
* without re-arming the guard. Taking the minimum is the direction that is safe
|
|
172
|
+
* to be wrong in: it can only finish early, never overrun a registered timeout
|
|
173
|
+
* and let the agent kill the process instead.
|
|
174
|
+
*
|
|
175
|
+
* ⚠ **Claude Code is unchanged, arithmetically** — its three events all carry
|
|
176
|
+
* `DEFAULT_HOOK_BUDGET_MS`, so the minimum IS that constant. What this costs is
|
|
177
|
+
* an agent whose events differ: it runs every event at its tightest one, which
|
|
178
|
+
* under-uses the wide ones. Stated rather than smuggled; widening it means
|
|
179
|
+
* re-arming the watchdog after the parse, which is its own change.
|
|
180
|
+
*
|
|
181
|
+
* `VIBECOMMIT_HOOK_TIMEOUT_MS` still wins outright, as it always has.
|
|
182
|
+
*/
|
|
183
|
+
export declare function hookBudgetMs(env: NodeJS.ProcessEnv, agentId: string): number;
|
|
184
|
+
/**
|
|
185
|
+
* ⛔ **The redaction confinement ROOT SET — `D184 §3`.**
|
|
186
|
+
*
|
|
187
|
+
* ```
|
|
188
|
+
* isInsideAny([worktree, mainToplevel], candidate)
|
|
189
|
+
* ```
|
|
190
|
+
*
|
|
191
|
+
* ## Why it is a set, and why the common dir is not in it
|
|
192
|
+
*
|
|
193
|
+
* `D184` moved the consent key to the git common dir so that a session inside a
|
|
194
|
+
* `git worktree` is admitted at all. ⛔ **The confinement root MUST NOT follow
|
|
195
|
+
* it there.** `isInside` realpaths both sides and fail-closes anything it cannot
|
|
196
|
+
* place to *outside* — which here means REDACT — so a root at `<main>/.git`
|
|
197
|
+
* would judge every file of an external worktree to be outside the main clone
|
|
198
|
+
* and replace its `content`, `oldString`, `newString` and `structuredPatch` with
|
|
199
|
+
* markers. **The capture still succeeds. The turn counts still look right. The
|
|
200
|
+
* content is gone**, and a test asserting *"worktree sessions capture now"*
|
|
201
|
+
* passes on an empty payload.
|
|
202
|
+
*
|
|
203
|
+
* Two roots, because both are genuinely the user's own tree: the worktree the
|
|
204
|
+
* session is running in, and the main clone it was cut from — a builder in a
|
|
205
|
+
* worktree reads the main clone's files constantly.
|
|
206
|
+
*
|
|
207
|
+
* ## ⛔ The `paths.ts:487-489` prohibition, answered — `D184 §5`
|
|
208
|
+
*
|
|
209
|
+
* > *"`roots` comes from the REGISTRY. It must never be derived from input."*
|
|
210
|
+
*
|
|
211
|
+
* **That prohibition is about PROVENANCE, and both members have the right one.**
|
|
212
|
+
* The named hazard is *anything on hook stdin* — attacker-supplied. Neither of
|
|
213
|
+
* these is: `keys` can only be produced by `resolveProjectKeys`, which is git's
|
|
214
|
+
* own answer about the directory the session runs in; `mainToplevel` is git's
|
|
215
|
+
* answer about the repository **the consent gate already approved**, and it is
|
|
216
|
+
* content-validated by `mainWorkTree` above. The worktree root has exactly the
|
|
217
|
+
* same provenance and has been used this way since `CR-024d`.
|
|
218
|
+
*
|
|
219
|
+
* ⚠ **Provenance is the whole argument, so this code preserves it:** nothing
|
|
220
|
+
* here is read from stdin, the derivation is validated by content, and a failure
|
|
221
|
+
* yields no second root rather than a fallback. An empty set would refuse
|
|
222
|
+
* everything (`paths.ts:491-492`), which is the correct direction — but this
|
|
223
|
+
* function cannot return one, because `keys.worktree` is always a member.
|
|
224
|
+
*
|
|
225
|
+
* ⚠ The dedup is cosmetic. `isInsideAny` over a repeated root is a union with
|
|
226
|
+
* itself; it is dropped so that a main-clone session reads as the single root it
|
|
227
|
+
* has always had, and so a cell asserting "no second root" is asserting
|
|
228
|
+
* something.
|
|
229
|
+
*/
|
|
230
|
+
export declare function confinementRoots(keys: ProjectKeys): readonly string[];
|
|
231
|
+
/**
|
|
232
|
+
* Read `[from, to)` of the transcript, REDACT it, and compress it.
|
|
233
|
+
*
|
|
234
|
+
* The path is already confined to the Claude Code transcript root by the caller
|
|
235
|
+
* (`/cso` finding 1) — this function must never be handed one that is not.
|
|
236
|
+
* Returns null on any failure, because a hook cannot report a read error.
|
|
237
|
+
*
|
|
238
|
+
* ## The one chokepoint
|
|
239
|
+
*
|
|
240
|
+
* This is the single place transcript bytes become a request body, which is why
|
|
241
|
+
* `CR-024d`'s redaction goes HERE and nowhere else — the same discipline
|
|
242
|
+
* `post.ts` applies to `expose()`: one call site, greppable, reviewable. Any
|
|
243
|
+
* future path that reads transcript bytes for upload must come through here or
|
|
244
|
+
* it silently bypasses the confidentiality boundary.
|
|
245
|
+
*
|
|
246
|
+
* `redactSpan` is length-preserving BY CONTRACT (see `redact.ts`), which the
|
|
247
|
+
* server's offset accounting depends on — so the compressed body still covers
|
|
248
|
+
* exactly `[from, to)`.
|
|
249
|
+
*
|
|
250
|
+
* ## ⛔ The SCRUBBER is chosen HERE, from the path, and never from `ctx.agentId`
|
|
251
|
+
*
|
|
252
|
+
* `CR-185`, D164 §5. This function knows the file it is about to read, so it is
|
|
253
|
+
* the one place that can answer *which registry root contains it* — and a
|
|
254
|
+
* caller therefore cannot pick the wrong profile for a file it hands over. The
|
|
255
|
+
* flag is not consulted: both no-flag install paths resolve to `claude-code`,
|
|
256
|
+
* and running Claude's key set over a Codex record redacts NOTHING.
|
|
257
|
+
*
|
|
258
|
+
* ⚠ **`home` and `env` are here for that lookup and nothing else.** They are
|
|
259
|
+
* passed rather than read from the process for the reason `paths.ts` states: a
|
|
260
|
+
* module that reads the real HOME cannot be tested without touching the
|
|
261
|
+
* developer's own transcripts.
|
|
262
|
+
*
|
|
263
|
+
* ## ⛔ `projectRoots` is a SET, and the consent key is not in it
|
|
264
|
+
*
|
|
265
|
+
* `D184 §3`. It was one string — the consented toplevel — while the consent key
|
|
266
|
+
* and the confinement boundary were the same value. They are not any more:
|
|
267
|
+
* `confinementRoots` above builds `[worktree, mainToplevel]` and the git common
|
|
268
|
+
* dir the consent gate approved is deliberately absent from it. A single-element
|
|
269
|
+
* set is the ordinary main-clone case and behaves exactly as the old parameter
|
|
270
|
+
* did.
|
|
271
|
+
*
|
|
272
|
+
* EXPORTED for `connect`'s test capture (`CR-025`), which reads a transcript on
|
|
273
|
+
* a path the hook never takes. It reuses this rather than opening one itself,
|
|
274
|
+
* because a second reader would bypass both the confinement and the redaction —
|
|
275
|
+
* exactly what the chokepoint note above warns about.
|
|
276
|
+
*/
|
|
277
|
+
export declare function readSpan(path: string, from: number, to: number, projectRoots: readonly string[], home: string, env: NodeJS.ProcessEnv): Uint8Array | null;
|