@vibe-commit/capture 0.6.1 → 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/README.md +80 -5
- package/dist/agent_hooks.d.ts +8 -0
- package/dist/agent_hooks.js +31 -1
- package/dist/agent_hooks.js.map +1 -1
- package/dist/agents/claude_code.d.ts +34 -0
- package/dist/agents/claude_code.js +141 -8
- package/dist/agents/claude_code.js.map +1 -1
- package/dist/agents/codex_cli.d.ts +13 -0
- package/dist/agents/codex_cli.js +241 -2
- package/dist/agents/codex_cli.js.map +1 -1
- package/dist/agents/cursor.d.ts +34 -0
- package/dist/agents/cursor.js +115 -1
- package/dist/agents/cursor.js.map +1 -1
- package/dist/agents/session_listing.d.ts +29 -0
- package/dist/agents/session_listing.js +49 -0
- package/dist/agents/session_listing.js.map +1 -0
- package/dist/agents/types.d.ts +118 -8
- package/dist/agents/types.js +17 -3
- package/dist/agents/types.js.map +1 -1
- package/dist/commands/approval_pending.d.ts +9 -0
- package/dist/commands/approval_pending.js +23 -0
- package/dist/commands/approval_pending.js.map +1 -0
- package/dist/commands/auth.js +31 -11
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/backfill.d.ts +160 -0
- package/dist/commands/backfill.js +748 -0
- package/dist/commands/backfill.js.map +1 -0
- package/dist/commands/browser_credential.d.ts +2 -0
- package/dist/commands/browser_credential.js +31 -14
- package/dist/commands/browser_credential.js.map +1 -1
- package/dist/commands/connect.d.ts +137 -0
- package/dist/commands/connect.js +203 -109
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/connect_picker.d.ts +27 -0
- package/dist/commands/connect_picker.js +415 -0
- package/dist/commands/connect_picker.js.map +1 -0
- package/dist/commands/context.d.ts +16 -0
- package/dist/commands/context.js +27 -0
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/credential_problem.d.ts +15 -4
- package/dist/commands/credential_problem.js +29 -22
- package/dist/commands/credential_problem.js.map +1 -1
- package/dist/commands/device_credential.d.ts +2 -0
- package/dist/commands/device_credential.js +16 -14
- package/dist/commands/device_credential.js.map +1 -1
- package/dist/commands/finalize.d.ts +95 -0
- package/dist/commands/finalize.js +249 -74
- package/dist/commands/finalize.js.map +1 -1
- package/dist/commands/finish_mint.d.ts +2 -6
- package/dist/commands/finish_mint.js +10 -2
- package/dist/commands/finish_mint.js.map +1 -1
- package/dist/commands/report.js +38 -30
- package/dist/commands/report.js.map +1 -1
- package/dist/commands/scan.d.ts +162 -0
- package/dist/commands/scan.js +507 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/status.js +119 -22
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/status_hooks.d.ts +14 -0
- package/dist/commands/status_hooks.js +81 -0
- package/dist/commands/status_hooks.js.map +1 -0
- package/dist/commands/status_machine.d.ts +18 -0
- package/dist/commands/status_machine.js +149 -0
- package/dist/commands/status_machine.js.map +1 -0
- package/dist/commands/why.js +44 -31
- package/dist/commands/why.js.map +1 -1
- package/dist/consent.d.ts +111 -0
- package/dist/consent.js +203 -1
- package/dist/consent.js.map +1 -1
- package/dist/copy/error_codes.d.ts +222 -0
- package/dist/copy/error_codes.js +105 -0
- package/dist/copy/error_codes.js.map +1 -0
- package/dist/copy/index.d.ts +2 -2
- package/dist/copy/index.js +2 -2
- package/dist/copy/index.js.map +1 -1
- package/dist/copy/strings.d.ts +497 -29
- package/dist/copy/strings.js +601 -35
- package/dist/copy/strings.js.map +1 -1
- package/dist/copy/time.d.ts +11 -0
- package/dist/copy/time.js +18 -0
- package/dist/copy/time.js.map +1 -1
- package/dist/credential.d.ts +5 -1
- package/dist/credential.js +2 -2
- package/dist/credential.js.map +1 -1
- package/dist/git.d.ts +43 -0
- package/dist/git.js +95 -0
- package/dist/git.js.map +1 -1
- package/dist/hooks/entry.d.ts +18 -1
- package/dist/hooks/entry.js +110 -13
- package/dist/hooks/entry.js.map +1 -1
- package/dist/hooks/post_commit.js +3 -3
- package/dist/hooks/post_commit.js.map +1 -1
- package/dist/hooks/post_rewrite.js +6 -4
- package/dist/hooks/post_rewrite.js.map +1 -1
- package/dist/hooks/session_start.d.ts +93 -0
- package/dist/hooks/session_start.js +199 -0
- package/dist/hooks/session_start.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +56 -8
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts +57 -0
- package/dist/install.js +54 -20
- package/dist/install.js.map +1 -1
- package/dist/json.d.ts +32 -9
- package/dist/json.js +35 -8
- package/dist/json.js.map +1 -1
- package/dist/machine_state.d.ts +52 -0
- package/dist/machine_state.js +63 -0
- package/dist/machine_state.js.map +1 -0
- package/dist/oauth/session.d.ts +1 -0
- package/dist/org_pending.d.ts +52 -0
- package/dist/org_pending.js +109 -0
- package/dist/org_pending.js.map +1 -0
- package/dist/paths.d.ts +50 -0
- package/dist/paths.js +64 -0
- package/dist/paths.js.map +1 -1
- package/dist/picker.d.ts +180 -0
- package/dist/picker.js +477 -0
- package/dist/picker.js.map +1 -0
- package/dist/picker_checklist.d.ts +125 -0
- package/dist/picker_checklist.js +375 -0
- package/dist/picker_checklist.js.map +1 -0
- package/dist/policy.d.ts +54 -0
- package/dist/policy.js +47 -0
- package/dist/policy.js.map +1 -1
- package/dist/post.d.ts +50 -16
- package/dist/post.js +220 -16
- package/dist/post.js.map +1 -1
- package/dist/state.d.ts +6 -0
- package/dist/state.js +38 -1
- package/dist/state.js.map +1 -1
- package/dist/system_message.d.ts +8 -1
- package/dist/system_message.js +19 -1
- package/dist/system_message.js.map +1 -1
- package/dist/term.d.ts +28 -2
- package/dist/term.js +23 -2
- package/dist/term.js.map +1 -1
- package/dist/verb_help.d.ts +13 -0
- package/dist/verb_help.js +40 -0
- package/dist/verb_help.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -9
package/dist/agents/types.d.ts
CHANGED
|
@@ -137,13 +137,27 @@ export type RedactionProfile = "claude-code" | "codex-cli" | "cursor";
|
|
|
137
137
|
*/
|
|
138
138
|
export type DelegatedTranscripts = "discover" | "announce";
|
|
139
139
|
/**
|
|
140
|
-
* The
|
|
140
|
+
* The four hook events this client registers.
|
|
141
141
|
*
|
|
142
|
-
*
|
|
142
|
+
* Every member of this lane fires the same four; that is exactly why
|
|
143
143
|
* `hook_event_name` was REJECTED as an adapter selector (`CR-183`) — the events
|
|
144
144
|
* are shared, so they discriminate nothing.
|
|
145
|
+
*
|
|
146
|
+
* ⛔ **`SessionStart` is the fourth, and it is the one that never uploads** (0.7.0,
|
|
147
|
+
* eng review D3 · A). `Stop`, `PreCompact` and `SessionEnd` flow into the code
|
|
148
|
+
* that reads a transcript and sends it; `SessionStart` must only install git
|
|
149
|
+
* hooks and say so, so `hooks/entry.ts` resolves the canonical event FIRST and
|
|
150
|
+
* branches to its own handler before the consent gate and before anything reads
|
|
151
|
+
* `transcript_path`. It sits in this list, and not in a table of its own, so the
|
|
152
|
+
* compiler makes each dialect declare its budget and its spelling.
|
|
153
|
+
*
|
|
154
|
+
* event Claude Code Codex Cursor reads a transcript
|
|
155
|
+
* Stop Stop Stop stop yes
|
|
156
|
+
* PreCompact PreCompact PreCompact preCompact yes
|
|
157
|
+
* SessionEnd SessionEnd SessionEnd sessionEnd yes
|
|
158
|
+
* SessionStart SessionStart SessionStart sessionStart NEVER
|
|
145
159
|
*/
|
|
146
|
-
export declare const HOOK_EVENTS: readonly ["Stop", "PreCompact", "SessionEnd"];
|
|
160
|
+
export declare const HOOK_EVENTS: readonly ["Stop", "PreCompact", "SessionEnd", "SessionStart"];
|
|
147
161
|
export type HookEventName = (typeof HOOK_EVENTS)[number];
|
|
148
162
|
/**
|
|
149
163
|
* One event's two clocks, and the relation between them is the point.
|
|
@@ -173,6 +187,77 @@ export interface AgentHookConfig {
|
|
|
173
187
|
readonly path: (home: string, env: NodeJS.ProcessEnv) => string;
|
|
174
188
|
readonly shape: HookDocShape;
|
|
175
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* One transcript file a source adapter saw — `D11 · A`, `scan`.
|
|
192
|
+
*
|
|
193
|
+
* ⛔ **`stat`ed for its times and NEVER OPENED.** Everything the picker, the
|
|
194
|
+
* offer and the backfill count comes from names and times, because opening a
|
|
195
|
+
* transcript of a repo nobody granted is the read the consent design forbids. A
|
|
196
|
+
* field that could only be filled by reading the file does not belong here.
|
|
197
|
+
*/
|
|
198
|
+
export interface SourceSession {
|
|
199
|
+
readonly path: string;
|
|
200
|
+
readonly mtimeMs: number;
|
|
201
|
+
/**
|
|
202
|
+
* When the agent itself says the session began, where it keeps that. Codex's
|
|
203
|
+
* index does (`created_at`); the folder-keyed agents do not, and for them the
|
|
204
|
+
* file's mtime stands in everywhere a date is shown.
|
|
205
|
+
*/
|
|
206
|
+
readonly startedMs?: number;
|
|
207
|
+
}
|
|
208
|
+
/** One agent project folder: its encoded name, and the sessions found in it. */
|
|
209
|
+
export interface SourceFolder {
|
|
210
|
+
readonly name: string;
|
|
211
|
+
readonly sessions: readonly SourceSession[];
|
|
212
|
+
}
|
|
213
|
+
/** One index row: a session whose agent already recorded the folder it ran in. */
|
|
214
|
+
export interface SourceRow {
|
|
215
|
+
readonly cwd: string;
|
|
216
|
+
readonly origin: string | null;
|
|
217
|
+
readonly session: SourceSession;
|
|
218
|
+
}
|
|
219
|
+
/** Why a store could not be listed. Each is a different line in `Not listed here`. */
|
|
220
|
+
export type UnreadableReason = "unrecognised index" | "index locked" | "unreadable";
|
|
221
|
+
/**
|
|
222
|
+
* What one agent's store yields, without a transcript being opened.
|
|
223
|
+
*
|
|
224
|
+
* The two shapes are the two ways the three agents keep sessions, and they are
|
|
225
|
+
* not interchangeable: a FOLDER-keyed agent (Claude Code, Cursor) names the
|
|
226
|
+
* folder by lossy encoding, so the engine has to resolve it against the
|
|
227
|
+
* filesystem and can fail to (`encode` and `isHashed` are what that walk needs);
|
|
228
|
+
* an INDEXED agent (Codex) records the real `cwd`, so it is never ambiguous.
|
|
229
|
+
*
|
|
230
|
+
* ⛔ **`unreadable` is an answer, not an exception.** One agent's store failing
|
|
231
|
+
* hides that agent's rows and nothing else's, and `scan` reports it; a thrown
|
|
232
|
+
* error here would take the other two agents' rows down with it.
|
|
233
|
+
*/
|
|
234
|
+
export type SessionSource = {
|
|
235
|
+
readonly kind: "folders";
|
|
236
|
+
readonly folders: readonly SourceFolder[];
|
|
237
|
+
/** This dialect's `encodeProjectPath`, handed over so the walk uses the same one. */
|
|
238
|
+
readonly encode: (path: string) => string;
|
|
239
|
+
/** Is this folder name a truncated-and-hashed one, which cannot be inverted? */
|
|
240
|
+
readonly isHashed: (name: string) => boolean;
|
|
241
|
+
/**
|
|
242
|
+
* Paths the agent ITSELF recorded having run in — a second skip signal. A
|
|
243
|
+
* folder whose name encodes to a recorded path that no longer exists is one
|
|
244
|
+
* whose sessions may belong to that deleted path, whatever else now matches.
|
|
245
|
+
* Empty for an agent that keeps no such record.
|
|
246
|
+
*/
|
|
247
|
+
readonly recorded: readonly string[];
|
|
248
|
+
} | {
|
|
249
|
+
readonly kind: "rows";
|
|
250
|
+
readonly rows: readonly SourceRow[];
|
|
251
|
+
/**
|
|
252
|
+
* Rollout files on disk that no index row names — counted, never opened. Only
|
|
253
|
+
* the index's own agent has the notion; a folder-keyed agent has no index to
|
|
254
|
+
* be missing from.
|
|
255
|
+
*/
|
|
256
|
+
readonly unindexed: number;
|
|
257
|
+
} | {
|
|
258
|
+
readonly kind: "unreadable";
|
|
259
|
+
readonly reason: UnreadableReason;
|
|
260
|
+
};
|
|
176
261
|
/** Where `connect` found the session running right now. */
|
|
177
262
|
export interface LocatedTranscript {
|
|
178
263
|
readonly path: string;
|
|
@@ -260,11 +345,14 @@ export interface TranscriptDialect {
|
|
|
260
345
|
* (lost permanently — that event has no next invocation) and no gap-stamp
|
|
261
346
|
* reserve. Nothing raises and the hook still exits 0.
|
|
262
347
|
*
|
|
263
|
-
* ⚠ **Widening `HookEventName` was the
|
|
264
|
-
* The three map 1:1, so a
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
348
|
+
* ⚠ **Widening `HookEventName` was the wrong fix for a RENAME, and it is the right
|
|
349
|
+
* one for a new event** (0.7.0, eng review D3 · A). The first three map 1:1, so a
|
|
350
|
+
* rename belongs in a per-dialect table. `SessionStart` is a new event that ALL
|
|
351
|
+
* THREE agents deliver (Claude Code and Codex measured live, Cursor read out of
|
|
352
|
+
* the shipped bundle — see each dialect), so the argument that stopped the
|
|
353
|
+
* widening — "force every dialect to declare budgets for events it can never
|
|
354
|
+
* receive" — no longer holds, and the compiler is now the thing that makes a
|
|
355
|
+
* dialect added later declare its `SessionStart` spelling and budget.
|
|
268
356
|
*
|
|
269
357
|
* ## ⚠ MEASURED per dialect, and the two measurements differ in kind
|
|
270
358
|
*
|
|
@@ -304,6 +392,28 @@ export interface TranscriptDialect {
|
|
|
304
392
|
* is exactly the cap Codex silently clamps to — measured, not inferred.
|
|
305
393
|
*/
|
|
306
394
|
readonly hookConfig: AgentHookConfig;
|
|
395
|
+
/**
|
|
396
|
+
* ⛔ **WHAT SESSIONS DOES THIS AGENT HAVE ON DISK — without opening one.**
|
|
397
|
+
* `D11 · A`, `scan`, the picker and the backfill offer.
|
|
398
|
+
*
|
|
399
|
+
* Listed by NAME and TIME only (`SourceSession`). The consent design is that no
|
|
400
|
+
* path opens a transcript of an ungranted repo, so the thing that decides what
|
|
401
|
+
* to offer cannot be the thing that reads the transcripts. ⚠ Each adapter fails
|
|
402
|
+
* closed on its own: an unreadable store is `{ kind: "unreadable" }` and hides
|
|
403
|
+
* that agent's rows only.
|
|
404
|
+
*
|
|
405
|
+
* ⛔ **REQUIRED, not optional, and that is `admitsFile`'s device.** A dialect
|
|
406
|
+
* added later must ANSWER how its sessions are found, and the compiler is what
|
|
407
|
+
* asks; an agent that cannot answer without opening a transcript returns
|
|
408
|
+
* `unreadable` and says so, which is a decision a reviewer sees.
|
|
409
|
+
*
|
|
410
|
+
* ⚠ A MEASURED requirement and not a speculative one: Open Question 3 found the
|
|
411
|
+
* two folder-keyed agents encode a path DIFFERENTLY (Claude Code per UTF-16
|
|
412
|
+
* unit with no collapsing; Cursor collapsing runs and trimming the ends), and
|
|
413
|
+
* the shipped `connect` looked in the wrong folder for any repo path holding an
|
|
414
|
+
* `_` or a space because it assumed one rule.
|
|
415
|
+
*/
|
|
416
|
+
readonly sessionSource: (home: string, env: NodeJS.ProcessEnv) => SessionSource;
|
|
307
417
|
/** Per-event clocks. See `EventBudget` for the relation that binds them. */
|
|
308
418
|
readonly events: Readonly<Record<HookEventName, EventBudget>>;
|
|
309
419
|
readonly delegatedTranscripts: DelegatedTranscripts;
|
package/dist/agents/types.js
CHANGED
|
@@ -57,11 +57,25 @@
|
|
|
57
57
|
*/
|
|
58
58
|
export const UNKNOWN_AGENT_ID = "unknown";
|
|
59
59
|
/**
|
|
60
|
-
* The
|
|
60
|
+
* The four hook events this client registers.
|
|
61
61
|
*
|
|
62
|
-
*
|
|
62
|
+
* Every member of this lane fires the same four; that is exactly why
|
|
63
63
|
* `hook_event_name` was REJECTED as an adapter selector (`CR-183`) — the events
|
|
64
64
|
* are shared, so they discriminate nothing.
|
|
65
|
+
*
|
|
66
|
+
* ⛔ **`SessionStart` is the fourth, and it is the one that never uploads** (0.7.0,
|
|
67
|
+
* eng review D3 · A). `Stop`, `PreCompact` and `SessionEnd` flow into the code
|
|
68
|
+
* that reads a transcript and sends it; `SessionStart` must only install git
|
|
69
|
+
* hooks and say so, so `hooks/entry.ts` resolves the canonical event FIRST and
|
|
70
|
+
* branches to its own handler before the consent gate and before anything reads
|
|
71
|
+
* `transcript_path`. It sits in this list, and not in a table of its own, so the
|
|
72
|
+
* compiler makes each dialect declare its budget and its spelling.
|
|
73
|
+
*
|
|
74
|
+
* event Claude Code Codex Cursor reads a transcript
|
|
75
|
+
* Stop Stop Stop stop yes
|
|
76
|
+
* PreCompact PreCompact PreCompact preCompact yes
|
|
77
|
+
* SessionEnd SessionEnd SessionEnd sessionEnd yes
|
|
78
|
+
* SessionStart SessionStart SessionStart sessionStart NEVER
|
|
65
79
|
*/
|
|
66
|
-
export const HOOK_EVENTS = ["Stop", "PreCompact", "SessionEnd"];
|
|
80
|
+
export const HOOK_EVENTS = ["Stop", "PreCompact", "SessionEnd", "SessionStart"];
|
|
67
81
|
//# sourceMappingURL=types.js.map
|
package/dist/agents/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/agents/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AA4BH;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,SAAS,CAAC;AA6D1C
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/agents/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AA4BH;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,SAAS,CAAC;AA6D1C;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,CAAU,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The org-approval-pending block — style guide §10.2's "held" beat, D65 §DR6, D81. One definition for the two places that
|
|
3
|
+
* print it: `connect`, on the 403 its own test capture got, and `status`, for a repo whose last upload got that same 403.
|
|
4
|
+
*
|
|
5
|
+
* ⚠ EXISTING COPY ONLY. `status` adds no sentence of its own; it prints what `connect` prints, so the two cannot drift
|
|
6
|
+
* (`org_pending.ts` records that the 403 happened). The shared clause renders on EVERY branch and `owners_notified` `> 0`
|
|
7
|
+
* ADDS to it (D81); `null` and `0` never claim a notification.
|
|
8
|
+
*/
|
|
9
|
+
export declare function approvalPendingBlock(colour: boolean, repoSlug: string, ownersNotified: number | null): string[];
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The org-approval-pending block — style guide §10.2's "held" beat, D65 §DR6, D81. One definition for the two places that
|
|
3
|
+
* print it: `connect`, on the 403 its own test capture got, and `status`, for a repo whose last upload got that same 403.
|
|
4
|
+
*
|
|
5
|
+
* ⚠ EXISTING COPY ONLY. `status` adds no sentence of its own; it prints what `connect` prints, so the two cannot drift
|
|
6
|
+
* (`org_pending.ts` records that the 403 happened). The shared clause renders on EVERY branch and `owners_notified` `> 0`
|
|
7
|
+
* ADDS to it (D81); `null` and `0` never claim a notification.
|
|
8
|
+
*/
|
|
9
|
+
import { CONNECT, URLS } from "../copy/index.js";
|
|
10
|
+
import { renderErrorBlock } from "../term.js";
|
|
11
|
+
export function approvalPendingBlock(colour, repoSlug, ownersNotified) {
|
|
12
|
+
const why = ownersNotified !== null && ownersNotified > 0
|
|
13
|
+
? `${CONNECT.pendingRecorded} ${CONNECT.pendingNotified(ownersNotified)}`
|
|
14
|
+
: CONNECT.pendingRecorded;
|
|
15
|
+
return renderErrorBlock({
|
|
16
|
+
kind: "warn",
|
|
17
|
+
what: CONNECT.pendingWhat,
|
|
18
|
+
why: [CONNECT.pendingWhy(repoSlug), why, CONNECT.pendingBuffered],
|
|
19
|
+
fixLabel: CONNECT.pendingTrackLabel,
|
|
20
|
+
fixes: [URLS.captureAccess],
|
|
21
|
+
}, colour);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=approval_pending.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approval_pending.js","sourceRoot":"","sources":["../../src/commands/approval_pending.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,UAAU,oBAAoB,CAAC,MAAe,EAAE,QAAgB,EAAE,cAA6B;IACnG,MAAM,GAAG,GACP,cAAc,KAAK,IAAI,IAAI,cAAc,GAAG,CAAC;QAC3C,CAAC,CAAC,GAAG,OAAO,CAAC,eAAe,IAAI,OAAO,CAAC,eAAe,CAAC,cAAc,CAAC,EAAE;QACzE,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC;IAC9B,OAAO,gBAAgB,CACrB;QACE,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,OAAO,CAAC,WAAW;QACzB,GAAG,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,eAAe,CAAC;QACjE,QAAQ,EAAE,OAAO,CAAC,iBAAiB;QACnC,KAAK,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC;KAC5B,EACD,MAAM,CACP,CAAC;AACJ,CAAC"}
|
package/dist/commands/auth.js
CHANGED
|
@@ -73,11 +73,13 @@
|
|
|
73
73
|
* @provenance vibecommit-mcp src/transport/server.ts — POST /oauth/ingest-credential is the mint route, verified
|
|
74
74
|
* @provenance vibecommit-web app/api/ingest-credentials/route.ts — the dashboard producer the paste path still serves, verified
|
|
75
75
|
*/
|
|
76
|
-
import { AUTH,
|
|
77
|
-
import {
|
|
76
|
+
import { AUTH, DEVICE, PICKER, URLS } from "../copy/index.js";
|
|
77
|
+
import { renderVerbHelp } from "../verb_help.js";
|
|
78
|
+
import { authCommandFor, channelCommand } from "../install.js";
|
|
78
79
|
import { writeLines } from "./context.js";
|
|
79
80
|
import { EXIT } from "../exit.js";
|
|
80
81
|
import { INGEST_TOKEN_PREFIX, IngestCredential, saveCredential } from "../credential.js";
|
|
82
|
+
import { machineCapture, machineSummary } from "../machine_state.js";
|
|
81
83
|
import { credentialsPath } from "../paths.js";
|
|
82
84
|
import { resolveProjectKeys } from "../project.js";
|
|
83
85
|
import { paint, renderErrorBlock, tildePath, wrap } from "../term.js";
|
|
@@ -98,10 +100,11 @@ export async function auth(ctx, argv, deps = {}) {
|
|
|
98
100
|
if (positional.length > 0) {
|
|
99
101
|
writeLines(ctx.stderr, renderErrorBlock({
|
|
100
102
|
kind: "bad",
|
|
103
|
+
code: "CREDENTIAL_IN_ARGV",
|
|
101
104
|
what: AUTH.argvWhat,
|
|
102
105
|
why: [AUTH.argvWhy],
|
|
103
106
|
fixLabel: AUTH.argvFix,
|
|
104
|
-
fixes: [AUTH.argvFixPrompt, AUTH.argvFixStdin],
|
|
107
|
+
fixes: [channelCommand(ctx.env, ctx.selfPath, AUTH.argvFixPrompt), AUTH.argvFixStdin(authCommandFor(ctx.env, ctx.selfPath))],
|
|
105
108
|
}, ctx.colour));
|
|
106
109
|
return EXIT.usage;
|
|
107
110
|
}
|
|
@@ -110,7 +113,8 @@ export async function auth(ctx, argv, deps = {}) {
|
|
|
110
113
|
// exactly that a usage error) runs first. By the time this is reached, `positional.length === 0`, so
|
|
111
114
|
// `--help` still has no side effects — nothing below has read or written anything yet either way.
|
|
112
115
|
if (argv.includes("--help") || argv.includes("-h")) {
|
|
113
|
-
|
|
116
|
+
const helpVerb = "auth"; // an identifier, not a literal, at the writer: `copy-inline-literals` follows argument positions
|
|
117
|
+
writeLines(ctx.stdout, renderVerbHelp(helpVerb));
|
|
114
118
|
return EXIT.ok;
|
|
115
119
|
}
|
|
116
120
|
const piped = argv.includes(STDIN_FLAG) || !ctx.stdinIsTty;
|
|
@@ -119,6 +123,7 @@ export async function auth(ctx, argv, deps = {}) {
|
|
|
119
123
|
writeLines(ctx.stderr, renderErrorBlock(piped
|
|
120
124
|
? {
|
|
121
125
|
kind: "bad",
|
|
126
|
+
code: "SIGNIN_CODE_NEEDS_TTY",
|
|
122
127
|
what: DEVICE.needsTerminalWhat,
|
|
123
128
|
why: [DEVICE.needsTerminalWhy],
|
|
124
129
|
fixLabel: DEVICE.needsTerminalFix,
|
|
@@ -126,10 +131,11 @@ export async function auth(ctx, argv, deps = {}) {
|
|
|
126
131
|
}
|
|
127
132
|
: {
|
|
128
133
|
kind: "bad",
|
|
134
|
+
code: "AUTH_FLAGS_CONFLICT",
|
|
129
135
|
what: DEVICE.conflictWhat,
|
|
130
136
|
why: [DEVICE.conflictWhy],
|
|
131
137
|
fixLabel: DEVICE.conflictFix,
|
|
132
|
-
fixes: [
|
|
138
|
+
fixes: [authCommandFor(ctx.env, ctx.selfPath), `${authCommandFor(ctx.env, ctx.selfPath)} ${PASTE_FLAG}`],
|
|
133
139
|
}, ctx.colour));
|
|
134
140
|
return EXIT.usage;
|
|
135
141
|
}
|
|
@@ -161,10 +167,11 @@ export async function auth(ctx, argv, deps = {}) {
|
|
|
161
167
|
if (secret === "") {
|
|
162
168
|
writeLines(ctx.stderr, renderErrorBlock({
|
|
163
169
|
kind: "bad",
|
|
170
|
+
code: "CREDENTIAL_EMPTY",
|
|
164
171
|
what: AUTH.emptyWhat,
|
|
165
172
|
why: [AUTH.emptyWhy],
|
|
166
|
-
fixLabel: AUTH.
|
|
167
|
-
fixes:
|
|
173
|
+
fixLabel: AUTH.mintFix(URLS.settings),
|
|
174
|
+
fixes: AUTH.mintCommands(authCommandFor(ctx.env, ctx.selfPath)),
|
|
168
175
|
}, ctx.colour));
|
|
169
176
|
return EXIT.failure;
|
|
170
177
|
}
|
|
@@ -175,10 +182,11 @@ export async function auth(ctx, argv, deps = {}) {
|
|
|
175
182
|
if (!secret.startsWith(INGEST_TOKEN_PREFIX)) {
|
|
176
183
|
writeLines(ctx.stderr, renderErrorBlock({
|
|
177
184
|
kind: "bad",
|
|
185
|
+
code: "CREDENTIAL_NOT_INGEST",
|
|
178
186
|
what: AUTH.wrongClassWhat,
|
|
179
187
|
why: [AUTH.wrongClassWhy],
|
|
180
|
-
fixLabel: AUTH.
|
|
181
|
-
fixes:
|
|
188
|
+
fixLabel: AUTH.mintFix(URLS.settings),
|
|
189
|
+
fixes: AUTH.mintCommands(authCommandFor(ctx.env, ctx.selfPath)),
|
|
182
190
|
}, ctx.colour));
|
|
183
191
|
return EXIT.failure;
|
|
184
192
|
}
|
|
@@ -194,14 +202,26 @@ export async function auth(ctx, argv, deps = {}) {
|
|
|
194
202
|
* block and the exit are exactly what they were.
|
|
195
203
|
*/
|
|
196
204
|
async function saved(ctx, deps, piped, notes = []) {
|
|
197
|
-
|
|
205
|
+
// 0.7.0, D32 · 26A (supersedes only L6's "outside a repository" clause). Inside a work tree the chain is unchanged (L2).
|
|
206
|
+
// Outside one, the continuation is the picker flow, and only on a machine that has nothing captured yet; a machine that
|
|
207
|
+
// already captures prints one line and no picker. ⛔ BOTH of 0.6.0's other guards stay: `piped` (`--stdin`, or no
|
|
208
|
+
// terminal) NEVER continues, so a CI runner with no grant still saves the credential and exits 0 instead of reaching the
|
|
209
|
+
// non-terminal refusal and exiting 2; and the continuation gets no `browser` (`index.ts` hands `connect` none), so a
|
|
210
|
+
// second sign-in cannot start.
|
|
211
|
+
const inRepo = resolveProjectKeys(ctx.cwd) !== null;
|
|
212
|
+
const capture = inRepo || piped || deps.connect === undefined ? null : machineCapture(ctx.home);
|
|
213
|
+
const shouldConnect = !piped && deps.connect !== undefined && (inRepo || capture?.kind === "none");
|
|
214
|
+
const staysOn = capture?.kind === "on";
|
|
198
215
|
writeLines(ctx.stdout, [
|
|
199
216
|
...renderErrorBlock({
|
|
200
217
|
kind: "ok",
|
|
201
218
|
what: AUTH.savedWhat,
|
|
202
219
|
why: [AUTH.savedWhy(tildePath(credentialsPath(ctx.home), ctx.home)), ...notes],
|
|
203
|
-
...(shouldConnect
|
|
220
|
+
...(shouldConnect || staysOn
|
|
221
|
+
? {}
|
|
222
|
+
: { fixLabel: AUTH.nextLabel, fixes: [channelCommand(ctx.env, ctx.selfPath, AUTH.nextCommand)] }),
|
|
204
223
|
}, ctx.colour),
|
|
224
|
+
...(capture?.kind === "on" ? ["", ...wrap(PICKER.authStays(machineSummary(capture)), 2)] : []),
|
|
205
225
|
]);
|
|
206
226
|
if (shouldConnect && deps.connect !== undefined)
|
|
207
227
|
return await deps.connect(ctx);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0EG;AAEH,OAAO,EAAE,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `vibecommit backfill` — style guide §10.14, design review D14 · 8A, D15 · 9A; capture 0.7.0, PR 5.
|
|
3
|
+
*
|
|
4
|
+
* Claude Code keeps about 30 days of transcripts and then deletes them. This uploads the ones still on this machine,
|
|
5
|
+
* for the repositories the user chose, once they say yes — and says plainly that a backfilled session arrives WITHOUT
|
|
6
|
+
* commit links. It is offered by `connect` (`backfillForConnect`, for its seam) and is a verb in its own right.
|
|
7
|
+
*
|
|
8
|
+
* ## What it is made of
|
|
9
|
+
*
|
|
10
|
+
* - **Which sessions** come from the scan engine (`scanMachine`): folder names and Codex's index, no transcript opened.
|
|
11
|
+
* Only repos the consent gate admits (`isCaptureAllowed`) are offered, and only sessions with unsent bytes. A session in
|
|
12
|
+
* a clone with no reflog, over the 50 MiB cap, or from Cursor is left OUT of the count and named in a muted line, so the
|
|
13
|
+
* offer never promises an upload the run would skip.
|
|
14
|
+
* - **How one is sent** is `closeSession` (the code `finalize` runs): sub-agent streams first, then the main stream, then
|
|
15
|
+
* — only for a session quiet for 30 minutes — the seal. Through `deliver()` with `byHook: false`, each clone's own
|
|
16
|
+
* confinement roots, and the hooks' own offset ledger, so a re-run sends only what is new.
|
|
17
|
+
* - **Each session goes through its OWN agent's dialect** (transport, redaction profile, confinement root); the file is
|
|
18
|
+
* admitted only if it lies under that agent's transcript root (`admitsTranscript`), which for Codex is
|
|
19
|
+
* `~/.codex/sessions`.
|
|
20
|
+
* - **The consent gate runs again before EACH session.** The offer is a plan; `vibecommit off` in another terminal during a
|
|
21
|
+
* long run must stop the rest of that repo, so `uploadOne` asks `isCaptureAllowed` first.
|
|
22
|
+
*
|
|
23
|
+
* ## ⛔ The one transcript read before an upload (exception 1)
|
|
24
|
+
*
|
|
25
|
+
* Alexander ruled (2026-10-24 10:53 EST) that the deleted-sibling case — a folder whose original path is gone and whose
|
|
26
|
+
* encoded name now resolves to a different surviving repo — is CLOSED, not accepted. So, after both the grant y/N and the
|
|
27
|
+
* backfill y/N, one session at a time just before its upload, a Claude Code session has ONE value read from its
|
|
28
|
+
* transcript: the `cwd` of the first record that carries one (`firstRecordedCwd`). It uploads only if that path is
|
|
29
|
+
* absolute, exists, is a git work tree, and is the same clone (common dir) the folder was matched to. This is an exception
|
|
30
|
+
* to D60 §D6 (the client may display transcripts but not analyze them), and it is the ONLY one: the scan, the picker and
|
|
31
|
+
* the offer open no transcript, and nothing else is read from this one. Codex needs no check (its index already holds the
|
|
32
|
+
* real `cwd`). Cursor records no folder at all (measured, STATIC), so its sessions are never uploaded and are counted instead.
|
|
33
|
+
*/
|
|
34
|
+
import type { AgentId } from "../agents/types.js";
|
|
35
|
+
import { type CommandContext } from "./context.js";
|
|
36
|
+
import { closeSession } from "./finalize.js";
|
|
37
|
+
import { scanMachine, type ScanResult } from "./scan.js";
|
|
38
|
+
/** One session that may be uploaded: a file the scan attributed to a granted repo, with unsent bytes. */
|
|
39
|
+
interface Candidate {
|
|
40
|
+
readonly agent: AgentId;
|
|
41
|
+
/** The repo's slug as the plan names it — what the consent gate is asked about again before the upload. */
|
|
42
|
+
readonly slug: string;
|
|
43
|
+
readonly sessionId: string | null;
|
|
44
|
+
readonly path: string;
|
|
45
|
+
readonly dir: string;
|
|
46
|
+
readonly clone: string;
|
|
47
|
+
readonly commonDir: string;
|
|
48
|
+
readonly mtimeMs: number;
|
|
49
|
+
readonly startedMs: number;
|
|
50
|
+
readonly size: number;
|
|
51
|
+
}
|
|
52
|
+
interface RepoPlan {
|
|
53
|
+
readonly slug: string;
|
|
54
|
+
readonly candidates: readonly Candidate[];
|
|
55
|
+
}
|
|
56
|
+
export interface BackfillPlan {
|
|
57
|
+
readonly repos: readonly RepoPlan[];
|
|
58
|
+
/** Sessions that will be offered. */
|
|
59
|
+
readonly total: number;
|
|
60
|
+
/** Cursor sessions in the repos chosen that have unsent bytes. Never uploaded (OQ 7), so never in `total`. */
|
|
61
|
+
readonly cursorSessions: number;
|
|
62
|
+
/** Sessions over the 50 MiB cap, left out of `total` and named in one line. */
|
|
63
|
+
readonly overSize: number;
|
|
64
|
+
/** Sessions in a clone with no reflog, left out of `total`: the reflog test is the only guard against a reused path. */
|
|
65
|
+
readonly noReflog: readonly {
|
|
66
|
+
readonly path: string;
|
|
67
|
+
readonly sessions: number;
|
|
68
|
+
}[];
|
|
69
|
+
}
|
|
70
|
+
/** How `runBackfill` ended — what a caller (`connect`) needs to choose its closing URL. */
|
|
71
|
+
export type BackfillEnd = "uploaded" | "declined" | "nothing" | "interrupted" | "stopped" | "refused";
|
|
72
|
+
export interface BackfillResult {
|
|
73
|
+
readonly exit: number;
|
|
74
|
+
readonly end: BackfillEnd;
|
|
75
|
+
readonly uploaded: number;
|
|
76
|
+
}
|
|
77
|
+
/** What the folder check found. A transcript that cannot be opened is a different fact from one that records no folder. */
|
|
78
|
+
export type RecordedCwd = {
|
|
79
|
+
readonly kind: "found";
|
|
80
|
+
readonly cwd: string;
|
|
81
|
+
} | {
|
|
82
|
+
readonly kind: "none";
|
|
83
|
+
} | {
|
|
84
|
+
readonly kind: "unreadable";
|
|
85
|
+
};
|
|
86
|
+
export interface BackfillDeps {
|
|
87
|
+
readonly scanMachine?: typeof scanMachine;
|
|
88
|
+
readonly closeSession?: typeof closeSession;
|
|
89
|
+
/** Ctrl+C during the upload. Absent: a real SIGINT listener for the duration of the run. */
|
|
90
|
+
readonly signal?: AbortSignal;
|
|
91
|
+
/** How long a repo runs before its `…` line prints. A test seam. */
|
|
92
|
+
readonly slowAfterMs?: number;
|
|
93
|
+
/** The folder check's reader — a test seam. Defaults to `firstRecordedCwd`. */
|
|
94
|
+
readonly readCwd?: (path: string) => RecordedCwd;
|
|
95
|
+
/** Run inside `connect` (the repos are the ones it just showed). Absent: the verb on its own. */
|
|
96
|
+
readonly fromConnect?: boolean;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Plan the offer from a scan. ⛔ Opens no transcript: a session's size is its `lstat`, and "unsent" is a comparison with the
|
|
100
|
+
* offset ledger the hooks already keep — a state file, not a transcript.
|
|
101
|
+
*/
|
|
102
|
+
export declare function planBackfill(ctx: Pick<CommandContext, "home" | "env">, scanFn?: typeof scanMachine): BackfillPlan;
|
|
103
|
+
/**
|
|
104
|
+
* The offer, as lines (§10.14, as VQ redrew it after the PR 5 review). SGR roles: `text` the repo rows and the question,
|
|
105
|
+
* `muted` the folder rows and the not-offered lines. `nowMs` is an argument so a golden file pins the clock.
|
|
106
|
+
*
|
|
107
|
+
* ## Widths
|
|
108
|
+
*
|
|
109
|
+
* ⛔ A folder path is cut from the LEFT to fit 80 columns whatever the slug width (§13.4, D27): the folder column is never
|
|
110
|
+
* narrowed to the slug column. The right-hand text (counts, agents) starts at one shared column: the slug column, or further
|
|
111
|
+
* right if a path needs it, and never so far that a line passes 80.
|
|
112
|
+
*/
|
|
113
|
+
export declare function renderOffer(plan: BackfillPlan, options: {
|
|
114
|
+
colour: boolean;
|
|
115
|
+
home: string;
|
|
116
|
+
nowMs: number;
|
|
117
|
+
standalone?: boolean;
|
|
118
|
+
}): string[];
|
|
119
|
+
/**
|
|
120
|
+
* The `cwd` of the transcript's first record that has one. ⛔ ONE VALUE. The record is parsed to read its top-level `cwd`
|
|
121
|
+
* and nothing else is looked at, kept, returned or sent; a line that does not mention `"cwd"` is not parsed at all.
|
|
122
|
+
* `none` (no record carries one in the first `FOLDER_CHECK_MAX_BYTES`) and `unreadable` (the file cannot be opened) both
|
|
123
|
+
* fail closed — the session is skipped — but they are different facts and are told apart.
|
|
124
|
+
*/
|
|
125
|
+
export declare function firstRecordedCwd(path: string): RecordedCwd;
|
|
126
|
+
/**
|
|
127
|
+
* Ask, then upload. Everything `backfill` and `connect` share. `connect` calls it AFTER its own grant y/N and its
|
|
128
|
+
* "Capture is on" block (through `backfillForConnect`), and chooses its closing URL from `end`.
|
|
129
|
+
*/
|
|
130
|
+
export declare function runBackfill(ctx: CommandContext, deps?: BackfillDeps): Promise<BackfillResult>;
|
|
131
|
+
/**
|
|
132
|
+
* What `connect` needs back to choose its closing URL (D19). `stopped` means the run printed its stop block with the
|
|
133
|
+
* `vibecommit backfill` resume fix: `connect` still exits 0, because capture is already on (D18).
|
|
134
|
+
*/
|
|
135
|
+
export type BackfillForConnect = {
|
|
136
|
+
readonly kind: "declined";
|
|
137
|
+
} | {
|
|
138
|
+
readonly kind: "ran";
|
|
139
|
+
readonly uploaded: number;
|
|
140
|
+
} | {
|
|
141
|
+
readonly kind: "stopped";
|
|
142
|
+
readonly uploaded: number;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* `connect`'s backfill step. It is handed the repos `connect`'s own scan found (the picker's), asks the backfill y/N
|
|
146
|
+
* and runs, so the picker's scan is not repeated. It owns its Ctrl+C: stopping a backfill is `ran`, and the run has
|
|
147
|
+
* already printed the stop line. A no, nothing waiting, and a refusal are all `declined`: `connect` ends on `/app`.
|
|
148
|
+
*
|
|
149
|
+
* ⚠ The consent gate runs HERE, over what `connect` just granted, not over what the scan saw before the grant: a repo the
|
|
150
|
+
* user did not choose is dropped by `planBackfill` however it got into `repos`; so is a clone with no reflog, which the plan asks
|
|
151
|
+
* git about itself.
|
|
152
|
+
*/
|
|
153
|
+
export declare function backfillForConnect(ctx: CommandContext, repos: ScanResult["repos"], deps?: BackfillDeps): Promise<BackfillForConnect>;
|
|
154
|
+
/**
|
|
155
|
+
* `vibecommit backfill`. Exit `0` done (held sessions included: org-pending is 0, as in §10.2), `1` stopped with the resume
|
|
156
|
+
* fix, `2` no terminal, `3` not connected, `4` nothing to upload. It ends on the dashboard URL after a completed run or a
|
|
157
|
+
* no, and on its resume fix after a stop.
|
|
158
|
+
*/
|
|
159
|
+
export declare function backfill(ctx: CommandContext, argv?: readonly string[], deps?: BackfillDeps): Promise<number>;
|
|
160
|
+
export {};
|