@vibe-commit/capture 0.6.1 → 0.8.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.
Files changed (172) hide show
  1. package/README.md +191 -9
  2. package/dist/account_not_here.d.ts +15 -0
  3. package/dist/account_not_here.js +25 -0
  4. package/dist/account_not_here.js.map +1 -0
  5. package/dist/agent_hooks.d.ts +8 -0
  6. package/dist/agent_hooks.js +31 -1
  7. package/dist/agent_hooks.js.map +1 -1
  8. package/dist/agents/claude_code.d.ts +34 -0
  9. package/dist/agents/claude_code.js +141 -8
  10. package/dist/agents/claude_code.js.map +1 -1
  11. package/dist/agents/codex_cli.d.ts +13 -0
  12. package/dist/agents/codex_cli.js +241 -2
  13. package/dist/agents/codex_cli.js.map +1 -1
  14. package/dist/agents/cursor.d.ts +34 -0
  15. package/dist/agents/cursor.js +115 -1
  16. package/dist/agents/cursor.js.map +1 -1
  17. package/dist/agents/session_listing.d.ts +29 -0
  18. package/dist/agents/session_listing.js +49 -0
  19. package/dist/agents/session_listing.js.map +1 -0
  20. package/dist/agents/types.d.ts +118 -8
  21. package/dist/agents/types.js +17 -3
  22. package/dist/agents/types.js.map +1 -1
  23. package/dist/commands/approval_pending.d.ts +9 -0
  24. package/dist/commands/approval_pending.js +23 -0
  25. package/dist/commands/approval_pending.js.map +1 -0
  26. package/dist/commands/auth.d.ts +7 -0
  27. package/dist/commands/auth.js +52 -11
  28. package/dist/commands/auth.js.map +1 -1
  29. package/dist/commands/backfill.d.ts +160 -0
  30. package/dist/commands/backfill.js +748 -0
  31. package/dist/commands/backfill.js.map +1 -0
  32. package/dist/commands/browser_credential.d.ts +6 -2
  33. package/dist/commands/browser_credential.js +34 -14
  34. package/dist/commands/browser_credential.js.map +1 -1
  35. package/dist/commands/connect.d.ts +146 -0
  36. package/dist/commands/connect.js +216 -117
  37. package/dist/commands/connect.js.map +1 -1
  38. package/dist/commands/connect_account.d.ts +135 -0
  39. package/dist/commands/connect_account.js +321 -0
  40. package/dist/commands/connect_account.js.map +1 -0
  41. package/dist/commands/connect_picker.d.ts +27 -0
  42. package/dist/commands/connect_picker.js +549 -0
  43. package/dist/commands/connect_picker.js.map +1 -0
  44. package/dist/commands/context.d.ts +16 -0
  45. package/dist/commands/context.js +27 -0
  46. package/dist/commands/context.js.map +1 -1
  47. package/dist/commands/credential_problem.d.ts +15 -4
  48. package/dist/commands/credential_problem.js +29 -22
  49. package/dist/commands/credential_problem.js.map +1 -1
  50. package/dist/commands/device_credential.d.ts +5 -1
  51. package/dist/commands/device_credential.js +17 -14
  52. package/dist/commands/device_credential.js.map +1 -1
  53. package/dist/commands/finalize.d.ts +95 -0
  54. package/dist/commands/finalize.js +249 -74
  55. package/dist/commands/finalize.js.map +1 -1
  56. package/dist/commands/finish_mint.d.ts +30 -6
  57. package/dist/commands/finish_mint.js +26 -6
  58. package/dist/commands/finish_mint.js.map +1 -1
  59. package/dist/commands/report.js +38 -30
  60. package/dist/commands/report.js.map +1 -1
  61. package/dist/commands/scan.d.ts +162 -0
  62. package/dist/commands/scan.js +507 -0
  63. package/dist/commands/scan.js.map +1 -0
  64. package/dist/commands/status.d.ts +19 -1
  65. package/dist/commands/status.js +232 -26
  66. package/dist/commands/status.js.map +1 -1
  67. package/dist/commands/status_hooks.d.ts +14 -0
  68. package/dist/commands/status_hooks.js +81 -0
  69. package/dist/commands/status_hooks.js.map +1 -0
  70. package/dist/commands/status_machine.d.ts +27 -0
  71. package/dist/commands/status_machine.js +210 -0
  72. package/dist/commands/status_machine.js.map +1 -0
  73. package/dist/commands/sync_reason.d.ts +17 -0
  74. package/dist/commands/sync_reason.js +25 -0
  75. package/dist/commands/sync_reason.js.map +1 -0
  76. package/dist/commands/why.js +44 -31
  77. package/dist/commands/why.js.map +1 -1
  78. package/dist/consent.d.ts +217 -0
  79. package/dist/consent.js +400 -1
  80. package/dist/consent.js.map +1 -1
  81. package/dist/copy/error_codes.d.ts +222 -0
  82. package/dist/copy/error_codes.js +105 -0
  83. package/dist/copy/error_codes.js.map +1 -0
  84. package/dist/copy/index.d.ts +2 -2
  85. package/dist/copy/index.js +2 -2
  86. package/dist/copy/index.js.map +1 -1
  87. package/dist/copy/strings.d.ts +617 -30
  88. package/dist/copy/strings.js +741 -36
  89. package/dist/copy/strings.js.map +1 -1
  90. package/dist/copy/time.d.ts +11 -0
  91. package/dist/copy/time.js +18 -0
  92. package/dist/copy/time.js.map +1 -1
  93. package/dist/credential.d.ts +5 -1
  94. package/dist/credential.js +2 -2
  95. package/dist/credential.js.map +1 -1
  96. package/dist/git.d.ts +43 -0
  97. package/dist/git.js +95 -0
  98. package/dist/git.js.map +1 -1
  99. package/dist/grants_sync.d.ts +165 -0
  100. package/dist/grants_sync.js +289 -0
  101. package/dist/grants_sync.js.map +1 -0
  102. package/dist/grants_verb.d.ts +70 -0
  103. package/dist/grants_verb.js +121 -0
  104. package/dist/grants_verb.js.map +1 -0
  105. package/dist/hooks/entry.d.ts +18 -1
  106. package/dist/hooks/entry.js +117 -14
  107. package/dist/hooks/entry.js.map +1 -1
  108. package/dist/hooks/post_commit.js +3 -3
  109. package/dist/hooks/post_commit.js.map +1 -1
  110. package/dist/hooks/post_rewrite.js +6 -4
  111. package/dist/hooks/post_rewrite.js.map +1 -1
  112. package/dist/hooks/session_grants.d.ts +59 -0
  113. package/dist/hooks/session_grants.js +91 -0
  114. package/dist/hooks/session_grants.js.map +1 -0
  115. package/dist/hooks/session_start.d.ts +114 -0
  116. package/dist/hooks/session_start.js +243 -0
  117. package/dist/hooks/session_start.js.map +1 -0
  118. package/dist/index.d.ts +1 -1
  119. package/dist/index.js +76 -11
  120. package/dist/index.js.map +1 -1
  121. package/dist/install.d.ts +57 -0
  122. package/dist/install.js +54 -20
  123. package/dist/install.js.map +1 -1
  124. package/dist/json.d.ts +32 -9
  125. package/dist/json.js +35 -8
  126. package/dist/json.js.map +1 -1
  127. package/dist/machine_state.d.ts +52 -0
  128. package/dist/machine_state.js +63 -0
  129. package/dist/machine_state.js.map +1 -0
  130. package/dist/oauth/retire.d.ts +10 -0
  131. package/dist/oauth/retire.js +13 -0
  132. package/dist/oauth/retire.js.map +1 -1
  133. package/dist/oauth/session.d.ts +1 -0
  134. package/dist/org_pending.d.ts +52 -0
  135. package/dist/org_pending.js +109 -0
  136. package/dist/org_pending.js.map +1 -0
  137. package/dist/paths.d.ts +70 -0
  138. package/dist/paths.js +90 -0
  139. package/dist/paths.js.map +1 -1
  140. package/dist/pending_revoke.d.ts +117 -0
  141. package/dist/pending_revoke.js +233 -0
  142. package/dist/pending_revoke.js.map +1 -0
  143. package/dist/pending_revoke_file.d.ts +55 -0
  144. package/dist/pending_revoke_file.js +74 -0
  145. package/dist/pending_revoke_file.js.map +1 -0
  146. package/dist/picker.d.ts +208 -0
  147. package/dist/picker.js +526 -0
  148. package/dist/picker.js.map +1 -0
  149. package/dist/picker_checklist.d.ts +141 -0
  150. package/dist/picker_checklist.js +411 -0
  151. package/dist/picker_checklist.js.map +1 -0
  152. package/dist/policy.d.ts +70 -1
  153. package/dist/policy.js +68 -2
  154. package/dist/policy.js.map +1 -1
  155. package/dist/post.d.ts +91 -18
  156. package/dist/post.js +259 -27
  157. package/dist/post.js.map +1 -1
  158. package/dist/state.d.ts +6 -0
  159. package/dist/state.js +38 -1
  160. package/dist/state.js.map +1 -1
  161. package/dist/system_message.d.ts +32 -2
  162. package/dist/system_message.js +47 -5
  163. package/dist/system_message.js.map +1 -1
  164. package/dist/term.d.ts +28 -2
  165. package/dist/term.js +23 -2
  166. package/dist/term.js.map +1 -1
  167. package/dist/verb_help.d.ts +13 -0
  168. package/dist/verb_help.js +40 -0
  169. package/dist/verb_help.js.map +1 -0
  170. package/dist/version.d.ts +1 -1
  171. package/dist/version.js +1 -1
  172. package/package.json +5 -9
@@ -21,15 +21,72 @@ export declare const HELP: {
21
21
  readonly usage: "vibecommit <command> [options]";
22
22
  readonly tagline: "Record Claude Code sessions against the commits they produced.";
23
23
  readonly commands: {
24
- readonly auth: "Renew or replace this machine's credential. In a git repo it then connects that repo; elsewhere it only saves the credential.";
25
- readonly connect: "Connect this repo and capture the current session.";
26
- readonly status: "Show whether capture is on for this repo and when it last succeeded.";
24
+ readonly auth: "Renew or replace this machine's credential. On a terminal it then goes on to connect: in a git repo, or on a machine that captures nothing yet. Otherwise it only saves the credential.";
25
+ readonly connect: "Choose the repositories to capture, from any folder, and connect them. On a machine with no credential it signs you in after you say yes, unless you choose g, which signs in first to read your account's grants.";
26
+ readonly scan: "List the repositories coding agents have been used in on this machine. Uploads nothing and changes no setting.";
27
+ readonly backfill: "Upload earlier coding-agent sessions still on this machine, for the repositories you chose. Asks first; no commit links.";
28
+ readonly status: "Show whether capture is on for this repo, or for this machine outside a repo, and when it last succeeded.";
27
29
  readonly off: "Stop capturing for this repo.";
28
30
  readonly why: "Show the conversation turns recorded against the commit that last changed this line.";
29
31
  readonly report: "Summarise capture coverage over a time window.";
30
32
  readonly finalize: "Close a finished session's last turn so commits made in it can be recorded.";
31
33
  };
32
34
  readonly docsUrl: "https://vibecommit.ai/docs/what-we-upload";
35
+ /**
36
+ * PR 6 item 2 (devex review): what `<verb> --help` prints BEYOND the one sentence above, which stays the first
37
+ * paragraph. Agents read `--help` first, and until now the flags and exit codes existed only in the README.
38
+ *
39
+ * ⚠ Every flag here is one the verb's own argv reader acts on (`src/index.ts`, and each verb's parser), and every exit
40
+ * code is one the verb returns (`src/exit.ts`). A flag the verb ignores, or a code it never returns, would be copy no
41
+ * gate can check, so `test/verb-help.test.ts` ties each list to the source it describes.
42
+ */
43
+ readonly verbs: {
44
+ readonly connect: {
45
+ readonly usage: "vibecommit connect [--device] [--sign-in] [--typed]";
46
+ readonly options: readonly [readonly ["--device", "Sign in with a code approved on another device, for a machine with no browser."], readonly ["--sign-in", "Sign in through the browser before connecting."], readonly ["--typed", "Use the typed prompt even on a terminal, for a screen reader."]];
47
+ readonly exits: readonly [readonly ["0", "Done."], readonly ["1", "Failed, or a replacement credential was declined."], readonly ["2", "Bad arguments, or no person at a terminal to answer the consent question."], readonly ["3", "Not connected: this machine's credential is not accepted."]];
48
+ };
49
+ readonly auth: {
50
+ readonly usage: "vibecommit auth [--stdin | --paste | --device]";
51
+ readonly options: readonly [readonly ["--stdin", "Read the credential from standard input and stop after saving it."], readonly ["--paste", "Skip the browser and paste a credential made in Settings."], readonly ["--device", "Sign in with a code approved on another device."]];
52
+ readonly exits: readonly [readonly ["0", "Credential saved."], readonly ["1", "Nothing was saved."], readonly ["2", "Bad arguments, such as a credential passed as an argument."]];
53
+ };
54
+ readonly scan: {
55
+ readonly usage: "vibecommit scan [--json]";
56
+ readonly options: readonly [readonly ["--json", "Print one JSON document instead of text."]];
57
+ readonly exits: readonly [readonly ["0", "Repositories found."], readonly ["4", "None found."]];
58
+ };
59
+ readonly backfill: {
60
+ readonly usage: "vibecommit backfill";
61
+ readonly options: readonly [];
62
+ readonly exits: readonly [readonly ["0", "Done, declined at the question, or interrupted with Ctrl+C. Sessions held for an organization's approval count as done."], readonly ["1", "The server stopped the run, could not be reached or refused this machine's credential, or it could not run. Nothing already sent is lost; run it again to resume."], readonly ["2", "No terminal, or an argument was given."], readonly ["3", "Not connected."], readonly ["4", "Nothing to upload."]];
63
+ };
64
+ readonly status: {
65
+ readonly usage: "vibecommit status [--json]";
66
+ readonly options: readonly [readonly ["--json", "Print one JSON document instead of text."]];
67
+ readonly exits: readonly [readonly ["0", "Reported."], readonly ["1", "Failed."], readonly ["2", "Bad arguments."], readonly ["3", "Not connected."]];
68
+ };
69
+ readonly why: {
70
+ readonly usage: "vibecommit why <file>:<line> [--json]";
71
+ readonly options: readonly [readonly ["--json", "Print one JSON document instead of text."]];
72
+ readonly exits: readonly [readonly ["0", "Answered."], readonly ["1", "Failed."], readonly ["2", "Bad arguments."], readonly ["3", "Not connected."]];
73
+ };
74
+ readonly report: {
75
+ readonly usage: "vibecommit report --since <date> [--ref <ref>] [--json]";
76
+ readonly options: readonly [readonly ["--since", "Start of the window, as YYYY-MM-DD. Required."], readonly ["--ref", "The branch or commit to count. Default: the current branch."], readonly ["--json", "Print one JSON document instead of text."]];
77
+ readonly exits: readonly [readonly ["0", "Reported."], readonly ["1", "Failed."], readonly ["2", "Bad arguments."], readonly ["3", "Not connected."], readonly ["4", "The window is empty: nothing to report."]];
78
+ };
79
+ readonly finalize: {
80
+ readonly usage: "vibecommit finalize --session <id> | --latest [--force]";
81
+ readonly options: readonly [readonly ["--session", "The session to close."], readonly ["--latest", "The most recent session, when only one is recent."], readonly ["--force", "Skip the check that the transcript has stopped changing. Only for a session that is over."]];
82
+ readonly exits: readonly [readonly ["0", "Closed: the server confirmed the last turn is recorded."], readonly ["1", "Not confirmed closed: not a git repository, a transcript that cannot be read, a credential that is no longer accepted, or a delivery that failed."], readonly ["2", "Nothing was sent: bad arguments, an unknown or still-running session, or several recent sessions for --latest."], readonly ["3", "Not connected: this repo is not captured, or this machine has no credential."], readonly ["5", "Delivered, but the server did not confirm it. Treat it as not closed."]];
83
+ };
84
+ };
85
+ /** The two section labels of a verb's help. */
86
+ readonly optionsLabel: "Options:";
87
+ /** A verb with no flags of its own (`backfill`) says so under the label, so "Options:" never sits over nothing. */
88
+ readonly noOptions: "None. It takes no arguments.";
89
+ readonly exitCodesLabel: "Exit codes:";
33
90
  };
34
91
  /**
35
92
  * The ENTRY POINT's own chrome and its two usage failures — `CR-090d`.
@@ -62,8 +119,14 @@ export declare const USAGE: {
62
119
  readonly usageLabel: "Usage:";
63
120
  readonly commandsLabel: "Commands:";
64
121
  readonly docsLabel: "Docs:";
65
- /** The unknown-verb line. Help follows it, so this says only what went wrong. */
66
- readonly unknownCommand: (verb: string) => string;
122
+ /**
123
+ * The unknown-verb block (PR 7, Q6: `UNKNOWN_COMMAND`, routed through the shared renderer). The help text is no longer
124
+ * dumped after it, so the fix — the way to the list of commands — is the last thing on screen. The verb is whatever
125
+ * the user typed, so it is cut to a length the line can hold.
126
+ */
127
+ readonly unknownCommandWhat: (verb: string) => string;
128
+ readonly unknownCommandFix: "See the commands:";
129
+ readonly unknownCommandHelp: "vibecommit --help";
67
130
  };
68
131
  export declare const STATUS: {
69
132
  readonly onForRepo: "Capture is on for this repository.";
@@ -76,6 +139,49 @@ export declare const STATUS: {
76
139
  * changed them to match the screen rather than changing the screen.
77
140
  */
78
141
  readonly repoLabel: "repo";
142
+ /** 0.7.0, D6 · 2A: why this repo is on. One row under `repo`, only inside a repo that is on. */
143
+ readonly basisLabel: "basis";
144
+ readonly basisOwner: (owner: string) => string;
145
+ readonly basisRepo: "repo grant";
146
+ readonly basisClone: "per clone";
147
+ /**
148
+ * Slice 2 (S4), brief §3.3: inside a repo that is NOT on, the account may still grant it. The account never admits a repo on
149
+ * its own (R3-22): naming it here is `connect`'s picker, and the action row already offers `connect`.
150
+ */
151
+ readonly basisAccountOnly: "granted on your account, not on this machine";
152
+ /**
153
+ * Slice 2 (S4), brief §3.3: the machine screen's account rows, after `off` and before `held`. `on account` lists what the
154
+ * user's account grants that THIS machine has not named (an owner as `owner/`); the second line says what to do about it.
155
+ */
156
+ readonly accountLabel: "on account";
157
+ readonly accountNotHere: (connect: string) => string;
158
+ /** Changes queued for the account that no sync has delivered yet. They go out with the next sync; only `connect`, `status`, `off` and a terminal `auth` sync. */
159
+ readonly pendingLabel: "pending";
160
+ readonly pendingValue: (n: number) => string;
161
+ /**
162
+ * VQ's ruling (ii): a queued change the server refused with 400 is kept (a consent statement is never dropped) but a retry
163
+ * fails again, so this row does not say "the next command retries". The URL is the one the web app's error state uses.
164
+ */
165
+ readonly pendingRejectedValue: (n: number) => string;
166
+ /**
167
+ * The first sync uploads what this machine already named (per-clone consents made under 0.6.x/0.7.0 reach the account, R3-21).
168
+ * Slugs only, never paths; more than three names shows two and "and N more", and the full list follows, one per line. The names arrive as ONE string, a name per line, because the copy corpus renders every template with string arguments.
169
+ */
170
+ readonly accountSaving: (namesOnePerLine: string) => string;
171
+ /** The machine-level screen (any folder that is not a work tree). */
172
+ readonly offMachine: "Capture is not on for any repository on this machine.";
173
+ readonly ownersLabel: "owners";
174
+ readonly reposLabel: "repos";
175
+ readonly offLabel: "off";
176
+ /**
177
+ * Machine-level `status`: the repos whose own last upload was refused because their org has not approved capture. §10.2's held
178
+ * vocabulary — the beat word `held`, and the backfill screen's "the org must approve capture" (Alexander, 2026-10-24 17:20).
179
+ */
180
+ readonly heldLabel: "held";
181
+ readonly heldReason: "the org must approve capture";
182
+ readonly ownerTail: "all its repos, including ones you clone later";
183
+ readonly changeLabel: "Change what is captured";
184
+ readonly turnOffInside: "Turn one repo off, run inside it";
79
185
  readonly lastSuccessLabel: "last sent";
80
186
  readonly dashboardLabel: "dashboard";
81
187
  /** `<slug> (git toplevel <path>)` — §10.3's repo row. */
@@ -96,6 +202,21 @@ export declare const STATUS: {
96
202
  * after the rows, with the glyph turned `warn`. The date is absolute and in UTC.
97
203
  */
98
204
  readonly credentialEnding: (date: string, authCommand: string) => string;
205
+ /**
206
+ * 0.7.0. A `grants.json` that is present and unreadable denies capture for every clone that has a remote
207
+ * (`consent.ts`'s `isCaptureAllowed`), and a hook cannot say so, so `status` does. The file name is the user's
208
+ * to fix; `connect` is where the next consent lands once it is readable.
209
+ */
210
+ readonly grantsUnreadable: (connect: string) => string;
211
+ /**
212
+ * 0.7.0, `SessionStart` (T21). `npm i -g` alone never adds the event to an agent's config, so a 0.6.x machine is
213
+ * missing it until `connect` runs. Only said on the npm channel: the plugin ships its own `hooks.json`, and its
214
+ * contract (no `SessionStart`, no git hooks) is unchanged.
215
+ */
216
+ readonly sessionStartMissing: (agents: string, connect: string) => string;
217
+ /** 0.7.0, D4 · A. A hook the user deleted stays deleted; `connect` is the watched way back. */
218
+ readonly commitHooksOff: (connect: string) => string;
219
+ readonly commitHooksForeign: (connect: string) => string;
99
220
  readonly credentialShadowed: "VIBECOMMIT_TOKEN is set and takes precedence over the credential saved on this machine. Unset it to use the saved one.";
100
221
  /**
101
222
  * `CR-228`, `TODOS[142]` — bytes the client ADVANCED PAST without delivering.
@@ -118,7 +239,7 @@ export declare const STATUS: {
118
239
  * turn only when a following prompt arrives, so nothing will ever seal this one and the commits made in
119
240
  * it cannot be recorded. States the consequence and the command; promises nothing about the commits.
120
241
  */
121
- readonly openTail: (sessions: number) => string;
242
+ readonly openTail: (sessions: number, finalizeLatest: string) => string;
122
243
  /**
123
244
  * `TODOS[145]` — commits the client has seen and is holding because no turn has closed yet. Normal
124
245
  * mid-session; shown as a fact, not as a fault.
@@ -189,7 +310,7 @@ export declare const STATUS: {
189
310
  * cannot tell a crashed session from one idle at lunch, and closing a session still in progress seals
190
311
  * a turn that was not actually over.
191
312
  */
192
- readonly heldIdle: (bytes: number, sessions: number, commits: number, ids?: readonly string[]) => string;
313
+ readonly heldIdle: (bytes: number, sessions: number, commits: number, finalizeSession: string, ids?: readonly string[]) => string;
193
314
  readonly fixCommandLabel: "To reconnect, run";
194
315
  /** §10.3's two trailing actions, rendered as an aligned pair. */
195
316
  readonly turnOffLabel: "Turn capture off for this repo";
@@ -220,7 +341,18 @@ export declare const CONNECT: {
220
341
  * the nouns are transcribed rather than reworded: *"the output of commands it
221
342
  * ran"*, never *"Bash tool results"*.
222
343
  */
223
- readonly consentHeading: "VibeCommit uploads your Claude Code transcripts for this repo.";
344
+ readonly consentHeading: "VibeCommit uploads your coding-agent transcripts for this repo.";
345
+ /**
346
+ * D23 · 17A: the picker path's heading (every `connect` that shows the picker, in a repo or not). `consentHeading`
347
+ * above remains only on the no-remote (`local:`) in-repo path, where there is nothing to pick (D35 · 29A: "Claude
348
+ * Code transcripts" understated what uploads once `connect` also wired Codex and Cursor hooks, 0.2.0).
349
+ */
350
+ readonly consentHeadingPicker: "VibeCommit uploads your coding-agent transcripts for the repositories you choose.";
351
+ /**
352
+ * ONE sentence, not a paragraph, added on the picker path only (design doc step 2, "The disclosure"): what the grant
353
+ * covers beyond the repos named on screen. The four paragraphs under either heading stay byte-identical.
354
+ */
355
+ readonly consentScope: "The choice covers future clones of these repositories too, adds commit hooks to each clone where it can, and is saved to your VibeCommit account so your other machines running VibeCommit 0.8.0 or later can offer it.";
224
356
  /**
225
357
  * ⚠ "private-repo paths" IS THE APPROVED WORDING, and it is the reason
226
358
  * `private` is deliberately NOT registered in `claims.ts`: a substring gate on
@@ -327,11 +459,33 @@ export declare const CONNECT: {
327
459
  readonly doneUrlLabel: "View this session";
328
460
  /** The `[y/N]` suffix. The capital is the default and the default is NO. */
329
461
  readonly consentAnswers: "[y/N]";
330
- /** Non-TTY refusal — DESIGN.md §13.7 exit 2, D65 §DR7. */
331
- readonly nonInteractiveWhat: "Consent needs an interactive terminal.";
332
- readonly nonInteractiveWhy: "Standard input is not a terminal, so the consent prompt cannot be answered. Nothing was read and nothing was uploaded.";
333
- readonly nonInteractiveFix: "Run this in a terminal:";
462
+ /**
463
+ * Non-TTY refusal — DESIGN.md §13.7 exit 2, D65 §DR7. PR 6 item 6: written for an AGENT that hit it, which is who reaches
464
+ * this branch. It says who must answer ("a person"), that an agent cannot, and what to relay, and it carries the code
465
+ * `CONSENT_NEEDS_TTY` for a wrapper to key on — PR 7 registered it and renders it on the block's own code line, so it is not
466
+ * repeated in the sentence. No `--yes`: that would bypass consent (D65 §DR7). The `what` line has no "you" (§13.6).
467
+ */
468
+ readonly nonInteractiveWhat: "Consent needs a person at a terminal.";
469
+ readonly nonInteractiveWhy: "An agent cannot answer it, and standard input is not a terminal. Nothing was read and nothing was uploaded.";
470
+ /** A repo with no remote has a folder to name; the label is the fix and the command follows it. */
471
+ readonly nonInteractiveFix: (folder: string) => string;
472
+ /**
473
+ * The picker path's refusal (VQ + VT, PR 6 item 6 fit): it names no folder (the picker is not about one repo), has no
474
+ * "you" in the `what` line, and is reached BEFORE the scan beat, so "Nothing was read and nothing was uploaded" stays
475
+ * literally true.
476
+ */
477
+ readonly pickerNonInteractiveWhat: "Choosing repositories needs a person at a terminal.";
478
+ readonly pickerNonInteractiveWhy: "An agent cannot answer it, and standard input is not a terminal, so no repository can be chosen and consent cannot be asked. Nothing was read and nothing was uploaded.";
479
+ readonly pickerNonInteractiveFix: "Ask the user to run this in a terminal:";
334
480
  readonly alreadyConnected: "Capture is already on for this repository.";
481
+ /**
482
+ * 0.7.0. `grants.json` is present and unreadable, which denies this repository whatever consent it has (see
483
+ * `consent.ts`'s `isCaptureAllowed`). Answering the consent prompt could not change that, so `connect` stops
484
+ * BEFORE asking rather than take a yes it cannot honour.
485
+ */
486
+ readonly grantsUnreadableWhat: "Capture can't be turned on: ~/.vibecommit/grants.json can't be read.";
487
+ readonly grantsUnreadableWhy: "Capture is stopped on this machine for every repository that has a remote until the file is readable. Nothing was changed.";
488
+ readonly grantsUnreadableFixLabel: "Fix the file or move it aside, then run:";
335
489
  /**
336
490
  * The browser sign-in beat (PKCE loopback → minted ingest credential) is the
337
491
  * oauth lane's, not this task's. Until it lands, the supported path is the one
@@ -449,12 +603,12 @@ export declare const COMMIT_HOOK: {
449
603
  readonly installed: (repo: string) => string;
450
604
  readonly chained: (repo: string) => string;
451
605
  readonly already: "Commit capture was already on for this clone.";
452
- readonly perClone: "Run `vibecommit connect` in each clone you want commits recorded for — git hooks are per-clone, not per-account.";
606
+ readonly perClone: (connect: string) => string;
453
607
  readonly hooksPathWhat: "Commit capture could NOT be installed for this clone.";
454
608
  readonly hooksPathWhy: (configured: string) => string;
455
609
  readonly hooksPathFixLabel: "Fix, either one:";
456
610
  readonly hooksPathFixUnset: "git config --unset core.hooksPath";
457
- readonly hooksPathFixManual: "or add `vibecommit post-commit` to your existing post-commit hook";
611
+ readonly hooksPathFixManual: (postCommit: string) => string;
458
612
  readonly failedWhat: "Commit capture could NOT be installed for this clone.";
459
613
  readonly failedWhy: (why: string) => string;
460
614
  };
@@ -480,7 +634,7 @@ export declare const AGENT_HOOKS: {
480
634
  readonly refusedWhat: (agent: string) => string;
481
635
  readonly refusedWhy: (path: string, why: string) => string;
482
636
  readonly refusedFixLabel: "Fix:";
483
- readonly refusedFix: (path: string) => string;
637
+ readonly refusedFix: (path: string, connect: string) => string;
484
638
  readonly failedWhat: (agent: string) => string;
485
639
  readonly failedWhy: (path: string, why: string) => string;
486
640
  };
@@ -608,10 +762,346 @@ export declare const SIGNIN: {
608
762
  readonly busyWhy: "Only one process may renew a sign-in at a time, and the one holding it did not finish. Nothing was read and the stored sign-in is unchanged.";
609
763
  readonly busyFix: "Run it again in a moment:";
610
764
  };
765
+ /**
766
+ * `vibecommit scan` — design review D17 · 11A, D26, D27, D33 · 27A, and the screen VQ drew for it
767
+ * (style guide §10.13) on 2026-10-24.
768
+ *
769
+ * ⛔ **The nouns are the agent-neutral ones** (D11 · A, D35): "coding agent", never "Claude Code
770
+ * session", because the scan covers three agents and the picker's heading says the same. The agent
771
+ * NAMES appear only on a repo's second line, where they are facts about which store a count came from.
772
+ *
773
+ * ⚠ **Every sentence here is a claims-register row** (the register is `code`'s, VR's PR). None says
774
+ * "every" or "all": the scan counts transcripts still on disk, and what `cleanupPeriodDays` already
775
+ * deleted is not among them.
776
+ */
777
+ export declare const SCAN: {
778
+ /** The beat line, drawn in the existing beat shape and overwritten once with `done` (D17). */
779
+ readonly beat: "Looking for repositories on this machine...";
780
+ readonly beatDone: "done";
781
+ readonly found: (count: number) => string;
782
+ readonly sessions: (count: number) => string;
783
+ readonly since: (date: string) => string;
784
+ /** What an agent is called on a repo's second line. The ids are wire values, not labels. */
785
+ readonly agent: {
786
+ readonly "claude-code": "Claude Code";
787
+ readonly "codex-cli": "Codex";
788
+ readonly cursor: "Cursor";
789
+ };
790
+ readonly notListed: "Not listed here:";
791
+ readonly noRemote: (count: number, connect: string) => string;
792
+ /**
793
+ * The picker's own line (PR 1 ruling 2): ONE count and ONE line for a folder with two or more
794
+ * candidate paths, a hashed name (cut, so it cannot be inverted) and a deleted sibling. Claude Code's
795
+ * and Cursor's only — a Codex row records its real `cwd` and is never ambiguous.
796
+ */
797
+ readonly ambiguous: (count: number) => string;
798
+ /** Scan-only (ruling 5a): a folder, or a Codex `cwd`, that exists but is not inside a git work tree. */
799
+ readonly nonRepo: (count: number) => string;
800
+ readonly missingFolder: (count: number) => string;
801
+ /**
802
+ * ⛔ CLAIMS ONLY WHAT GIT SHOWS (ruling 7). The test is a session's mtime against the OLDEST reflog entry,
803
+ * and `gc.reflogExpire` prunes a long-lived clone's oldest entries, so "older than the reflog" is the fact
804
+ * and "the folder was reused" is a possibility — the same repo deleted and cloned again reads the same.
805
+ */
806
+ readonly pathReused: (count: number) => string;
807
+ /** One clone: the path rides the line. More: this heading, then one indented path per clone. */
808
+ readonly noReflogOne: (path: string) => string;
809
+ readonly noReflogMany: (count: number) => string;
810
+ /** Rollouts on disk that no index row names (ruling 5c) — counted, never opened. */
811
+ readonly unindexed: (count: number) => string;
812
+ /**
813
+ * `Codex sessions couldn't be read (unrecognised index)`, one line per unreadable agent (R3-15). The
814
+ * bracket names a cause the user can act on; a plain read failure (ruling 6) has none to name, so it
815
+ * gets none. The `--json` `reason` is the same three words either way.
816
+ */
817
+ readonly unreadable: (agent: string, reason: string | null) => string;
818
+ readonly next: "Choose what is captured:";
819
+ /** Exit 4. Both screens end on the same command. */
820
+ readonly none: "No coding-agent sessions were found on this machine.";
821
+ /**
822
+ * Exit 4 with `Not listed here:` lines: sessions exist that could not be listed, so `none` would be
823
+ * untrue. `none` prints only when that block is empty, i.e. the scan saw no session at all (VQ, PR 1
824
+ * ruling 3).
825
+ */
826
+ readonly noneListable: "No repository could be listed from the sessions on this machine.";
827
+ readonly noneNext: "Choose owners or repos anyway:";
828
+ };
829
+ /**
830
+ * `vibecommit backfill` — style guide §10.14, design review D14 · 8A, D15 · 9A; capture 0.7.0, PR 5.
831
+ *
832
+ * Every sentence here is a claims-register row. ⛔ Three promises it must never make: that a backfilled session is
833
+ * LINKED to a commit (it arrives without links, and the copy says so), that "every" or "all" earlier sessions are
834
+ * uploaded (only the ones still on this machine and not yet sent), and that a held session will upload by itself (no
835
+ * hook fires for an old session, so the held line points at a re-run).
836
+ *
837
+ * The two folder reasons are different facts (VQ ruling): `folder differs` is a RECORDED folder that is not this clone,
838
+ * `folder not recorded` is a transcript that records none.
839
+ */
840
+ export declare const BACKFILL: {
841
+ /**
842
+ * Inside `connect` the repos are the ones it just showed, so "these"; run on its own there is no "these", so it names whose
843
+ * they are (VQ, PR 5 review).
844
+ */
845
+ readonly offerHeading: (repos: number, standalone: boolean) => string;
846
+ /** The count on a repo row. "Not yet uploaded", so it is never mistaken for the picker's total on disk. */
847
+ readonly notYetUploaded: (count: number) => string;
848
+ /**
849
+ * Cursor sessions are not offered (Alexander, 2026-10-24 13:54 EST: Cursor's transcripts record no folder, so the
850
+ * folder check cannot run). One muted line, only when a repo you chose has some.
851
+ */
852
+ readonly cursorNotUploaded: (count: number) => string;
853
+ /** Two lines, as §10.14 draws them. */
854
+ /**
855
+ * A session over the 50 MiB cap is left out of the count and named here, so the offer never promises an upload the run would
856
+ * skip on every re-run. (Sub-agent streams are not capped.)
857
+ */
858
+ readonly overSizeNote: (count: number) => string;
859
+ /**
860
+ * A clone with no reflog cannot be tested for a reused path (a transcript older than the clone's first reflog entry), and
861
+ * that test is the only guard against one, so its sessions are left out of the count and named here with the clone.
862
+ */
863
+ readonly noReflogNote: (count: number, path: string) => string;
864
+ readonly uploadNote: readonly ["They upload one at a time, the same way new sessions do, without", "commit links."];
865
+ readonly question: (sessions: number) => string;
866
+ /** A no. A completed consent flow (§13.7), not an error. */
867
+ readonly declined: (backfill: string) => string;
868
+ readonly nothingToUpload: "Nothing to upload: no earlier session on this machine is waiting for a repository you've chosen.";
869
+ readonly runHeading: (sessions: number) => string;
870
+ /** Outcome fragments on a repo line, joined by " · ". */
871
+ readonly uploaded: (count: number) => string;
872
+ readonly skipped: (count: number, reason: string) => string;
873
+ readonly held: (count: number) => string;
874
+ readonly failed: (count: number, reason: string) => string;
875
+ readonly stopped: "stopped";
876
+ /** Skip reasons. */
877
+ readonly overSize: "over 50 MiB";
878
+ readonly folderDiffers: "folder differs";
879
+ readonly folderNotRecorded: "folder not recorded";
880
+ /** The transcript could not be opened at all (permissions), which is a different fact from one that records no folder. */
881
+ readonly couldntBeRead: "couldn't be read";
882
+ /** The file vanished between the offer and its upload: a skip, not a refusal by the server. */
883
+ readonly fileGone: "the file is gone";
884
+ /** `vibecommit off` (or a grant removed) while the run was going: the rest of that repo is not sent. */
885
+ readonly turnedOff: "turned off while this ran";
886
+ readonly outsideAgentFolder: "not in the agent's session folder";
887
+ /** Failure reasons: a `never`. The server's own code is never shown (§13.6: no bare status, no raw error). */
888
+ readonly refusedByServer: "the server refused it";
889
+ readonly repositoryForbidden: "another organization owns this repository";
890
+ readonly noRepoIdentity: "no repository identity";
891
+ readonly unrecognisedFileName: "the file name isn't a session id";
892
+ /** The summary. The glyph is `ok` only when nothing was held, stopped or failed. */
893
+ readonly summary: (uploaded: number, total: number, skipped: number, held: number, failed: number) => string;
894
+ /** `owners` is the held repos' owners, already phrased ("acme-corp", "acme-corp or other-org"). */
895
+ readonly heldBlock: (owners: string) => string;
896
+ readonly heldThenRun: "Then run:";
897
+ /**
898
+ * The stop block: a server `later` (5xx, 429) stops the run, with the resume fix. ⛔ It states only what landed: `uploaded` is
899
+ * sessions the server took, not sessions looked at, and "not yet uploaded" is what a re-run will OFFER again (skipped and held
900
+ * sessions among them), not a promise of what it will send.
901
+ */
902
+ readonly stopWhat: (uploaded: number, total: number) => string;
903
+ readonly stopWhy: (notUploaded: number) => string;
904
+ /** No response at all (a refused connection, a timeout): not the server asking anything. */
905
+ readonly stopWhyUnreachable: (notUploaded: number) => string;
906
+ readonly stopFixLabel: "Resume:";
907
+ /** Ctrl+C at the y/N or during the upload. Exit 0: capture is on. */
908
+ readonly interrupted: (backfill: string) => string;
909
+ /** Exit 3. */
910
+ readonly notConnectedWhat: "This machine isn't connected.";
911
+ readonly notConnectedWhy: "`backfill` uploads with this machine's credential, and there isn't one. Nothing was read.";
912
+ readonly notConnectedFixLabel: "Connect first:";
913
+ /** `grants.json` is present and unreadable: every repo with a remote is denied, so there is nothing honest to offer. */
914
+ readonly grantsUnreadableWhat: "Backfill can't run: ~/.vibecommit/grants.json can't be read.";
915
+ readonly grantsUnreadableWhy: "Capture is stopped on this machine for every repository that has a remote until the file is readable. Nothing was read and nothing was uploaded.";
916
+ readonly grantsUnreadableFixLabel: "Fix the file or move it aside, then run:";
917
+ /** Exit 2. A prompt that proceeds when nobody can answer it is not a prompt. */
918
+ readonly nonInteractiveWhat: "`backfill` needs an interactive terminal.";
919
+ readonly nonInteractiveWhy: "Standard input is not a terminal, so the question before uploading cannot be answered. Nothing was read and nothing was uploaded.";
920
+ readonly nonInteractiveFix: "Run this in a terminal:";
921
+ /** The credential was rejected mid-run (a 401): the same block `finalize` shows, in this verb's words. */
922
+ readonly credentialStoppedWhat: "Upload stopped: this machine's credential is no longer accepted.";
923
+ readonly credentialStoppedWhy: "Nothing already sent is lost, and a re-run offers the sessions not yet uploaded.";
924
+ readonly credentialStoppedFixLabel: "Renew it, then run backfill again:";
925
+ readonly usageWhat: "That is not something `vibecommit backfill` understands.";
926
+ readonly usageWhy: "Nothing was read and nothing was uploaded. `backfill` takes no arguments.";
927
+ };
928
+ /**
929
+ * `vibecommit connect` from any folder — the picker, the grant block, the hooks step and the endings (0.7.0, PR 3).
930
+ * Style guide §10.12, copied from the merged guide and the design doc; the design doc wins where they differ.
931
+ */
932
+ export declare const PICKER: {
933
+ readonly onNow: "on now";
934
+ readonly turnedOff: "turned off";
935
+ /** Why an `on now` row is on (D5 · 1A), so a 0.6.x upgrader sees what is already captured. */
936
+ readonly reasonOwner: "owner";
937
+ readonly reasonRepo: "repo";
938
+ readonly reasonPerClone: "per clone";
939
+ /** The owner row ALWAYS states how many repos `aN` covers (D9), so a hidden repo is never covered unseen. */
940
+ readonly ownerAll: (count: number) => string;
941
+ readonly ownerOnReposHere: (count: number) => string;
942
+ readonly turnOnHint: "choose it to turn it back on";
943
+ /** Where the working folder is a repo, the row is marked so a pre-tick (or a `$HOME` dotfiles repo) is legible. */
944
+ readonly thisRepo: "this repo";
945
+ readonly thisFolder: "this folder";
946
+ readonly moreTyped: (count: number, owner: string) => string;
947
+ readonly moreChecklist: (count: number, owner: string) => string;
948
+ /** The typed prompt (D8). */
949
+ readonly choose: (hasOwners: boolean) => string;
950
+ readonly removeHint: "Remove one with -N, -owner/ or -owner/repo.";
951
+ readonly enterNothing: "Press Enter to change nothing.";
952
+ /** D34 in the typed prompt: the working folder's repo is pre-selected, so Enter leads to the (default No) y/N. */
953
+ readonly enterThisRepo: (slug: string) => string;
954
+ readonly promptMark: "> ";
955
+ /** `tokens` is the already-joined list (`9 (no row 9), acme, corp`): the corpus renders every template with a string. */
956
+ readonly notUnderstood: (tokens: string) => string;
957
+ readonly noRow: (n: string) => string;
958
+ readonly alreadyOn: (token: string, remove: string) => string;
959
+ readonly notOn: (token: string) => string;
960
+ /** The empty screen (D12 · 6A): a new laptop, no agent session on disk at all. */
961
+ readonly emptyNone: "No coding-agent sessions were found on this machine.";
962
+ readonly emptyExpected: "That's expected on a new machine. Type the owners or repos to capture; every clone of them is captured once Claude Code, Codex or Cursor runs in it.";
963
+ readonly emptyType: "Type owner/ or owner/repo, for example alexvibecommit/.";
964
+ /** Sessions exist but none could be listed (the `Not listed here:` block is not empty): scan's own wording. */
965
+ readonly emptyListable: "Type owner/ or owner/repo, for example alexvibecommit/, to capture a repository that is not listed.";
966
+ /** The checklist (D28). */
967
+ readonly hint: "↑↓ move · space choose · enter done · t typed prompt · ctrl+c cancel";
968
+ readonly hintTyped: (connectTyped: string) => string;
969
+ /** The enter-with-nothing lines (D5). */
970
+ readonly nothingGranted: (connect: string) => string;
971
+ readonly noChanges: (summary: string) => string;
972
+ readonly cancelled: "Cancelled. Nothing was changed.";
973
+ /** The grant block (D7 · 3A). */
974
+ readonly chose: "You chose:";
975
+ readonly labelOwners: "owners";
976
+ readonly labelRepos: "repos";
977
+ readonly labelTurnOn: "turn on";
978
+ readonly labelStop: "stop";
979
+ readonly ownerHere: (count: number) => string;
980
+ readonly noCloneHere: "(no clone here yet)";
981
+ readonly questionGrant: "Upload transcripts from these repositories?";
982
+ readonly questionStop: "Stop capturing these repositories?";
983
+ readonly stopped: "Stopped capturing the repositories above.";
984
+ /** "1 owner and 2 repos" — the on-now summary of Enter-with-grants, `auth`'s one line and the status heading. */
985
+ readonly summary: (owners: number, repos: number) => string;
986
+ readonly authStays: (summary: string) => string;
987
+ /** The hooks step (D13 · 7A). */
988
+ readonly hooksBeat: (clones: number) => string;
989
+ readonly hooksDone: "done";
990
+ readonly hooksCount: (added: number, chained: number, notAdded: number) => string;
991
+ readonly hooksNotAdded: (count: number) => string;
992
+ readonly hooksPathReason: "core.hooksPath is set";
993
+ /** A hook write that FAILED is a real exception with its own reason (VQ, item 9): neither dropped nor given `hooksPath`'s fix. */
994
+ readonly hooksFailedReason: "the hook could not be written";
995
+ readonly hooksStillCaptured: "Sessions there are still captured. To record commits too, either:";
996
+ readonly hooksStillCapturedOther: "Sessions there are still captured.";
997
+ readonly hooksFailedFixLabel: "Where the hook could not be written, try again:";
998
+ /** "Capture is on" (D18 · 12A, D19 · 13A). */
999
+ readonly onFor: (summary: string) => string;
1000
+ readonly onProof: "The next Claude Code, Codex or Cursor session in any of them is captured. In Claude Code, its first reply then shows \"VibeCommit captured this session.\"";
1001
+ readonly stopOne: "To stop one repo, run inside it:";
1002
+ /**
1003
+ * Alexander's "caveat for other owners" (2026-10-24; amended 17:20), on the "Capture is on" block. It prints for the owners the
1004
+ * test capture did NOT check: from `~` that is every granted owner (there is no session to probe), and in a repo it is every
1005
+ * granted owner except the one whose delta the server answered with a 2xx. For an owner that is not the signed-in person's own
1006
+ * account the client cannot know whether an org is yet to approve capture, so it says one may be. Never printed when every
1007
+ * such owner is the user's own account.
1008
+ */
1009
+ readonly ownerApproval: (status: string) => string;
1010
+ readonly onNewLaptop: (names: string) => string;
1011
+ readonly onNewLaptopProof: "No clone of it is here yet. Clone one and open a coding agent in it; that session is captured.";
1012
+ /** The group of account grants this machine has not named (§2): numbered, unticked until chosen, like any other row. */
1013
+ readonly onAccount: "on your account";
1014
+ readonly onAccountHint: "choose it to capture it here";
1015
+ /** A `turn on` row whose repo was turned off on the ACCOUNT (not only here): the yes re-includes it everywhere. */
1016
+ readonly turnedOffOnAccount: "(turned off on your account)";
1017
+ /** Screen 1a: the second line of the prompt block, on a machine with no credential, a terminal and a browser to sign in with. */
1018
+ readonly gLine: "Or type g for the repositories your account already grants. It signs in first.";
1019
+ /** The one token a mixed answer is refused for; `notUnderstood` wraps it in D8's line. */
1020
+ readonly gMixedToken: "g can't be combined with other choices";
1021
+ /** Screen 1b: the grant block's heading when the list is the account's, not the person's picks. */
1022
+ readonly accountGrants: "Your account grants:";
1023
+ /** Screen 1b, N: the credential `g` signed in with is revoked. The removed-here variant is a revoke that could not reach the server. */
1024
+ readonly gDeclinedRevoked: "Nothing is captured on this machine. The credential made for this was revoked.";
1025
+ readonly gDeclinedRemoved: "Nothing is captured on this machine. The credential made for this was removed here; the server will be told on the next vibecommit command that contacts the server.";
1026
+ /** Ctrl+C after a mint (VQ's correction): never "Nothing was changed", because a credential was made and then removed. */
1027
+ readonly gCancelledRevoked: "Cancelled. Nothing is captured on this machine. The credential made for this was revoked.";
1028
+ readonly gCancelledRemoved: "Cancelled. Nothing is captured on this machine. The credential made for this was removed here; the server will be told on the next vibecommit command that contacts the server.";
1029
+ /**
1030
+ * `g` stopped because this machine could not make the write-ahead record of the credential it had just been given (an unwritable,
1031
+ * unreadable or full queue). The credential is revoked at once (`REPLACE.declinedRevoked`), or `REPLACE.declinedOrphan` says where
1032
+ * to remove it. An insecure queue file gets the insecure-file block instead of this line.
1033
+ */
1034
+ readonly gNotRecorded: "g stopped: this machine couldn't keep a record of the credential it was just given.";
1035
+ /**
1036
+ * The yes found `g`'s own record of the credential UNUSABLE (the queue file became insecure or unreadable while the question was
1037
+ * open): nothing was revoked by anyone, this machine just cannot keep the record, so no credential is kept.
1038
+ */
1039
+ readonly gRecordUnusable: (connect: string) => string;
1040
+ /**
1041
+ * The yes found a `credentials.json` already there (another run saved one while the question was open): that one is kept, this run's
1042
+ * is not, and the grants the yes wrote are saved — capture IS on, so this never says nothing is captured. The fate of the
1043
+ * credential this run made follows on its own line (`REPLACE.declinedRevoked`, `gRemovedWillTell`, or `REPLACE.declinedOrphan`).
1044
+ */
1045
+ readonly gOccupied: (connect: string) => string;
1046
+ /** The fate line for `gOccupied` when a readable row still holds the credential this run made. */
1047
+ readonly gRemovedWillTell: "The credential just created was removed here; the server will be told on the next vibecommit command that contacts the server.";
1048
+ /**
1049
+ * The yes found `g`'s own record of the credential gone: another vibecommit command (a retry that ran while the question was open)
1050
+ * had already revoked it. No credential is kept, and the grants the yes wrote stay. `connect` is THIS install's command.
1051
+ */
1052
+ readonly gRevokedElsewhere: (connect: string) => string;
1053
+ /** Screen 1c: `g` found no grants on the account. The credential is kept and the person chooses here. */
1054
+ readonly gEmpty: "Your account doesn't grant any repositories yet. Choose them here instead:";
1055
+ /**
1056
+ * `g` signed in but the account's grants could not be read (the server did not answer, or answered off-contract). It must not
1057
+ * say the account is empty, and it says what to do: run `connect` again. `connect` is THIS install's command (a function of it).
1058
+ */
1059
+ readonly gUnavailable: (connect: string) => string;
1060
+ /** Screen 2: a machine joining an account by picking local repos is asked about the rest of the account's grants. */
1061
+ readonly joinAlso: (namesOnePerLine: string) => string;
1062
+ readonly joinQuestion: "Capture those here too?";
1063
+ /**
1064
+ * Under "Capture is on" when the sync after `connect`'s writes did not reach the server (VQ, on VT's question). Capture IS on —
1065
+ * local grants admit the repo — so this is not a warning; it only tells the truth about the account. Only `connect`, `status` and
1066
+ * `off` sync, so it names `status` (the install channel's command); a 400 and a 401 have their own lines (below and `ERRORS`).
1067
+ */
1068
+ readonly accountNotTold: (status: string) => string;
1069
+ /**
1070
+ * "0.8.0 truth fixes" F2: the same line on a machine that HAS SYNCED before. There a grant the account has not been told about
1071
+ * holds the repository's sessions on this machine (`isCaptureAllowed`, step 3), so "Capture is on" needs the truth about it.
1072
+ * A machine that has never synced holds nothing and keeps `accountNotTold`.
1073
+ */
1074
+ readonly accountNotToldHeld: (status: string) => string;
1075
+ readonly joinDeclined: (status: string) => string;
1076
+ };
611
1077
  /** `vibecommit off`. */
612
1078
  export declare const OFF: {
613
1079
  readonly done: "Capture is off for this repository.";
1080
+ /**
1081
+ * 0.7.0, a claims-register row. A repo with a remote is turned off BY SLUG, which reaches every clone of it on this
1082
+ * machine. Slice 2 extends the sentence to the other machines once they sync; until then it says only what is true.
1083
+ */
1084
+ readonly doneSlug: (slug: string) => string;
1085
+ /** D31: bare `off` outside a repository. The picker is where an owner or another repo is unticked. */
1086
+ readonly outsideRepoWhat: "`off` turns off the repository you're in.";
1087
+ readonly outsideRepoFixLabel: "To stop capturing an owner or another repo, untick it in the picker:";
1088
+ /** `grants.json` is unreadable, so the exclusion could not be recorded. The clone's own consent was still withdrawn. */
1089
+ readonly grantsUnreadableWhat: "The turn-off could not be recorded: ~/.vibecommit/grants.json can't be read.";
1090
+ readonly grantsUnreadableWhy: "Capture is already stopped for this repository while the file can't be read, and this clone's own consent was withdrawn.";
1091
+ readonly grantsUnreadableFixLabel: "Fix the file or move it aside, then run:";
614
1092
  readonly alreadyOff: "Capture was already off for this repository.";
1093
+ /**
1094
+ * Slice 2 (S4), brief §2 and §5. On a machine with a credential the exclusion is also queued for the account and synced
1095
+ * (3 s), so the success line says where else it reaches; `unsyncedOthers` says who keeps capturing until they sync; and
1096
+ * `notSentYet` is the design's sentence for a write that could not reach the server (it stays queued).
1097
+ */
1098
+ readonly doneSlugAccount: (slug: string) => string;
1099
+ readonly unsyncedOthers: (n: number) => string;
1100
+ readonly notSentYet: "Stopped here. Your other machines running VibeCommit 0.8.0 or later don't know yet; it will retry.";
1101
+ /** The write was stopped, not just unsent (a 400, a 401, too large, unreadable): "it will retry" would be false, so it does not say so. */
1102
+ readonly notSentStopped: "Stopped here. Your other machines running VibeCommit 0.8.0 or later don't know yet.";
1103
+ /** The account already had it turned off (another machine, or the dashboard); this machine now agrees. */
1104
+ readonly alreadyOffAccount: "Already off on your account; now off on this machine too.";
615
1105
  readonly note: "Sessions already recorded are unaffected.";
616
1106
  readonly unrecognizedArgWhat: "That is not something `vibecommit off` understands.";
617
1107
  readonly unrecognizedArgWhy: "Nothing was changed. `off` takes no arguments.";
@@ -892,7 +1382,10 @@ export declare const WHY: {
892
1382
  */
893
1383
  readonly skewWhat: "The record service sent an answer this version is too old to show.";
894
1384
  readonly skewWhy: "The service described this commit in a way this build does not recognise. The record itself is fine — this copy of the client cannot render it, so it showed nothing rather than guessing at part of it.";
1385
+ /** The PLUGIN channel's remedy (`COMMANDS.pluginInstall`). */
895
1386
  readonly skewFix: "Reinstall the VibeCommit plugin to pick up the current client, then run this again:";
1387
+ /** The npm channel's remedy (`COMMANDS.npmUpdate`): an npm install has no plugin to reinstall. */
1388
+ readonly skewFixNpm: "Update VibeCommit to pick up the current client, then run this again:";
896
1389
  /** The bearer is dead after one refresh and one retry. Exit 3, not 1. */
897
1390
  readonly signedOutWhat: "This machine is not signed in to VibeCommit.";
898
1391
  readonly signedOutWhy: "Reading a record needs a signed-in user, and no usable sign-in was found on this machine.";
@@ -1277,20 +1770,42 @@ export declare const ABSENCE: {
1277
1770
  * know were bound: `closed` says the last turn is recorded, not that any commit matched it.
1278
1771
  */
1279
1772
  export declare const FINALIZE: {
1280
- readonly needTarget: "Say which session to close: --session <id>, or --latest.";
1773
+ readonly needTarget: "Say which session to close.";
1774
+ readonly needTargetFix: "Name one, or take the latest:";
1281
1775
  readonly badSessionId: "That is not a session id (letters, digits, dot, dash and underscore only).";
1282
- readonly noRecentSession: "No session in this repository has delivered anything in the last 24 hours. Use --session <id>.";
1283
- readonly severalRecent: "More than one session in this repository is recent. Name one with --session <id>:";
1776
+ readonly noRecentSession: "No session in this repository has delivered anything in the last 24 hours.";
1777
+ readonly noRecentSessionFix: "Name a session:";
1778
+ readonly severalRecent: "More than one session in this repository is recent.";
1779
+ readonly severalRecentFix: "Name one:";
1780
+ /** `finalize --session <id>` for a session that is known, e.g. the one whose delivery just failed. */
1781
+ readonly commandSession: (id: string) => string;
1782
+ /** The same with the placeholder, for a fix line written before a session is known. */
1783
+ readonly commandSessionAny: "vibecommit finalize --session <id>";
1784
+ /** The command without its id, for a sentence that names the id itself (`status`'s held-idle line). */
1785
+ readonly commandSessionBase: "vibecommit finalize --session";
1786
+ readonly commandSessionForce: (id: string) => string;
1284
1787
  readonly recentRow: (id: string, minutesAgo: number) => string;
1285
1788
  readonly unknownSession: (id: string) => string;
1286
1789
  readonly transcriptMissing: (id: string) => string;
1287
- readonly stillWriting: "That session's transcript changed a moment ago. Wait for the session to finish, or pass --force if it is over.";
1790
+ readonly stillWriting: "That session's transcript changed a moment ago.";
1791
+ readonly stillWritingFix: "Wait for the session to finish, or if it is over, run:";
1288
1792
  readonly closed: (id: string) => string;
1289
1793
  readonly alreadyClosed: (id: string) => string;
1290
1794
  readonly notAcknowledged: "The server accepted the data but did not confirm that it closed the session; it may predate this command. The last turn may still be open.";
1291
- readonly refused: "The server declined to close the session on this attempt. Run the command again.";
1292
- readonly notDelivered: "Could not deliver the session. Nothing was closed. Run the command again.";
1293
- readonly credentialStopped: "VibeCommit stopped sending for this credential. Run `vibecommit auth` to replace it.";
1795
+ readonly refused: "The server declined to close the session on this attempt.";
1796
+ readonly retryFix: "Run it again:";
1797
+ readonly notDelivered: "Could not deliver the session. Nothing was closed.";
1798
+ readonly credentialStopped: "VibeCommit stopped sending for this credential.";
1799
+ readonly credentialStoppedFix: "Replace it:";
1800
+ /**
1801
+ * PR 7 (Q2, VQ's wording): the ingest address in the environment (`VIBECOMMIT_INGEST_URL`) is one this client refuses to
1802
+ * send to, so retrying cannot help. Shared by `finalize` and `backfill`, so the `why` says only "Nothing was sent": it must
1803
+ * not claim a session was or was not closed. The VALUE is never echoed (a URL can carry a secret).
1804
+ */
1805
+ readonly ingestUrlWhat: "The address VibeCommit sends sessions to can't be used.";
1806
+ readonly ingestUrlWhy: "VIBECOMMIT_INGEST_URL must be an https address, or an http address on this machine, and it isn't. Nothing was sent.";
1807
+ readonly ingestUrlFix: "Correct it, or remove it to use the default address:";
1808
+ readonly ingestUrlCommand: "unset VIBECOMMIT_INGEST_URL";
1294
1809
  /**
1295
1810
  * `TODOS[177]` follow-up (VL, 2026-10-08, VG's silent-loss finding) — ONE stderr line for the whole run when
1296
1811
  * `finalize` sets any inferred-squash pairs aside (the main delivery, the drain loop, or both, summed). Printed
@@ -1318,8 +1833,8 @@ export declare const REJECTED: {
1318
1833
  * command across lines; `unconfirmed` is their join, the sentence the plan wrote.
1319
1834
  */
1320
1835
  readonly unconfirmedWhat: "Couldn't confirm this machine's credential with the server.";
1321
- readonly unconfirmedFix: "Run `vibecommit status` later.";
1322
- readonly unconfirmed: "Couldn't confirm this machine's credential with the server. Run `vibecommit status` later.";
1836
+ readonly unconfirmedFix: (status: string) => string;
1837
+ readonly unconfirmed: (status: string) => string;
1323
1838
  };
1324
1839
  /** `TODOS[184]`-style one-sentence facts the retire step prints; every one is true whatever the server did. */
1325
1840
  export declare const RETIRE: {
@@ -1351,6 +1866,12 @@ export declare const REPLACE: {
1351
1866
  readonly questionUnconfirmed: "Upload this machine's transcripts to the workspace you signed in to?";
1352
1867
  readonly replacesValue: (org: string) => string;
1353
1868
  readonly question: (org: string) => string;
1869
+ /**
1870
+ * 0.7.0, D7 · 3A: on the PICKER path the question names the repos, not the machine, and is the second of at most three
1871
+ * questions in a run. The workspace is cut to 28 columns (not `question`'s 30) so the line stays within 80 with `[y/N]`.
1872
+ */
1873
+ readonly questionRepos: (org: string) => string;
1874
+ readonly questionReposUnconfirmed: "Upload transcripts from the repos above to your signed-in workspace?";
1354
1875
  readonly declined: "Nothing was saved. The approval is discarded.";
1355
1876
  /** Ctrl+C at the question (the prompt was aborted): the same outcome as N, said as what it was. */
1356
1877
  readonly cancelled: "Cancelled. Nothing was saved.";
@@ -1445,11 +1966,17 @@ export declare const UPDATE: {
1445
1966
  readonly plugin: (latest: string) => string;
1446
1967
  };
1447
1968
  export declare const ERRORS: {
1448
- readonly notConnected: "This repository is not connected. Run `vibecommit connect`.";
1969
+ readonly notConnected: "This repository is not connected.";
1970
+ /** PR 7 (Q7): the remedy was a sentence inside the `what` line; it is a command now, so it moves to the fix block. */
1971
+ readonly notConnectedFix: "Connect it:";
1449
1972
  readonly networkLater: "Could not reach VibeCommit. This session will be recorded on the next turn.";
1450
1973
  readonly authFatal: "This machine's credential is no longer accepted.";
1451
1974
  readonly payloadNever: "This session was too large to record and has been skipped.";
1452
1975
  readonly notAGitRepo: "Not a git repository.";
1976
+ /** PR 7 (VQ): names the folder, tilde-shortened and cut from the LEFT by the caller (`truncatePath`, §13.4). */
1977
+ readonly notAGitRepoWhy: (folder: string) => string;
1978
+ /** A fix with no command to give: the remedy is where to run it, so the block has a label and no commands. */
1979
+ readonly notAGitRepoFix: "Run it again inside a git repository.";
1453
1980
  };
1454
1981
  /**
1455
1982
  * The interactive top-level catch (CR-022).
@@ -1469,7 +1996,7 @@ export declare const INTERNAL: {
1469
1996
  readonly unexpectedWhat: "VibeCommit stopped on an unexpected error.";
1470
1997
  readonly unexpectedWhy: "The command did not finish.";
1471
1998
  readonly unexpectedFix: "Run it again with the error detail shown:";
1472
- readonly unexpectedDebugCommand: "VIBECOMMIT_DEBUG=1 vibecommit <command>";
1999
+ readonly unexpectedDebugCommand: (command: string) => string;
1473
2000
  };
1474
2001
  /**
1475
2002
  * Credential-loading failures (CR-016).
@@ -1497,6 +2024,10 @@ export declare const CREDENTIAL: {
1497
2024
  readonly insecureFileModeLabel: "mode";
1498
2025
  readonly insecureFileWhy: "It was not read. A credential file must be readable only by its owner.";
1499
2026
  readonly insecureFileFix: "Restore the mode, then reconnect:";
2027
+ /** The FOLDER (`~/.vibecommit`) is open to other accounts, not the file: same code, its own what, why and `chmod`. */
2028
+ readonly insecureDirWhat: "The folder that holds the credential file is open to other accounts on this machine.";
2029
+ readonly insecureDirWhyLabel: "folder";
2030
+ readonly insecureDirWhy: "The credential was not read. This folder must be accessible only to its owner.";
1500
2031
  readonly unreadableWhat: "The credential file could not be read.";
1501
2032
  readonly unreadableWhy: "It exists but does not contain a credential in the expected form.";
1502
2033
  /** `CR-216/U4`. Was "Replace it by reconnecting:" — see `wrongClassFix` above. */
@@ -1530,15 +2061,26 @@ export declare const AUTH: {
1530
2061
  readonly nextCommand: "vibecommit connect";
1531
2062
  readonly emptyWhat: "No credential was given.";
1532
2063
  readonly emptyWhy: "Nothing was read, so nothing was written.";
1533
- readonly emptyFix: "Mint one, then run:";
2064
+ /**
2065
+ * PR 6 item 1. Was "Mint one, then run:" over the URL alone, so the label promised a command and printed a link, and the
2066
+ * non-interactive path was named nowhere. The URL comes FIRST (inside the label, where it cannot be wrapped away from
2067
+ * its sentence) and the commands LAST, so the fix stays last (§13.6). A function because `URLS` is declared below.
2068
+ */
2069
+ readonly mintFix: (url: string) => string;
2070
+ /**
2071
+ * The two ways to hand it over: piped (a script or an agent), or typed at a terminal. `--stdin` never continues into `connect`
2072
+ * (D32 guard 1). `auth` is `authCommandFor(env, selfPath)`: a plugin-only machine has no `vibecommit` on PATH, so the line names
2073
+ * `node <path> auth` there (README, "Keeping a machine connected"), and handing it `vibecommit auth` would be a new wrong output.
2074
+ */
2075
+ readonly mintCommands: (auth: string) => readonly string[];
1534
2076
  readonly wrongClassWhat: "That is not a VibeCommit ingest credential.";
1535
2077
  readonly wrongClassWhy: "An ingest credential begins vcik_. Nothing was written and nothing was sent.";
1536
- readonly wrongClassFix: "Mint one, then run:";
1537
2078
  readonly argvWhat: "A credential must not be passed as an argument.";
1538
2079
  readonly argvWhy: "Arguments are written to your shell history and are readable by other processes on this machine while the command runs. Treat the one you just typed as exposed and revoke it.";
1539
2080
  readonly argvFix: "Read it from the terminal, or from a pipe:";
1540
2081
  readonly argvFixPrompt: "vibecommit auth";
1541
- readonly argvFixStdin: "printf %s \"$TOKEN\" | vibecommit auth --stdin";
2082
+ /** A pipe, so `channelCommand` cannot rewrite it: it takes the channel's `auth` (`authCommandFor`) instead. */
2083
+ readonly argvFixStdin: (auth: string) => string;
1542
2084
  /**
1543
2085
  * Printed before the request, naming the label the credential will carry in
1544
2086
  * `/app/settings` — the list a user revokes from, so the name they will look
@@ -1588,7 +2130,14 @@ export declare const RUNTIME: {
1588
2130
  * 4. No URL longer than the line.
1589
2131
  */
1590
2132
  export declare const SYSTEM_MESSAGE: {
1591
- readonly notConnected: "VibeCommit is installed but not connected. Run `vibecommit connect` to start capturing.";
2133
+ /**
2134
+ * State 1. The command is the channel's (`installChannel`): `vibecommit connect` on npm, `node <path> connect` for the plugin
2135
+ * bundle, which has no `vibecommit` on PATH (slice 2, design Next Steps 6, the mechanism state 2 already uses). On npm the line is
2136
+ * the same bytes it always was.
2137
+ */
2138
+ readonly notConnected: (connectCommand: string) => string;
2139
+ /** State 1 when the channel's command would blow `credentialRejectedBudget` (a long plugin realpath). */
2140
+ readonly notConnectedFallback: "VibeCommit is installed but not connected. Connect it: vibecommit.ai/install";
1592
2141
  /**
1593
2142
  * State 2 — `11A`. House prefix kept, ONE line, and the cause is no longer named: the server's 401
1594
2143
  * body is opaque on purpose (it cannot say "revoked" vs "expired"), so "revoked" was a guess that
@@ -1628,6 +2177,30 @@ export declare const SYSTEM_MESSAGE: {
1628
2177
  * users and its hash chain detects post-write tampering").
1629
2178
  */
1630
2179
  readonly captureConfirmed: (dashboardUrl: string) => string;
2180
+ /**
2181
+ * States 6-9 — style guide §10.1 (0.7.0, design review D16 · 10A), all emitted by the `SessionStart` hook. One
2182
+ * plain-text line each, ≤120 characters, no SGR. The wording is the design doc's and the merged style guide's,
2183
+ * byte for byte; `test/session-start.test.ts` pins the length of every one.
2184
+ *
2185
+ * 6 — hooks added, once per clone. 7 — `core.hooksPath` is set, once per clone. 8 — the clone has its own
2186
+ * commit hook, once per clone. 9 — `grants.json` is unreadable, once per (machine, day).
2187
+ */
2188
+ readonly hooksAdded: "VibeCommit added its post-commit and post-rewrite hooks to this clone, so commits can link to sessions.";
2189
+ readonly hooksPathSet: "VibeCommit captures sessions here, not commits: core.hooksPath is set. Run `vibecommit status` here for the fix.";
2190
+ readonly ownCommitHook: "VibeCommit didn't add its commit hook here: this clone has its own. Run `vibecommit connect` here to chain it.";
2191
+ readonly grantsUnreadable: "VibeCommit capture stopped on this machine: ~/.vibecommit/grants.json can't be read. Run `vibecommit status`.";
2192
+ /**
2193
+ * State 10 — slice 2 (`CR-259`, brief §3 item 4). Emitted by the `SessionStart` hook, once per (machine, account epoch), when its one
2194
+ * bounded `GET` found account grants this machine has not named. SessionStart-only like states 6-9 (the plugin registers no
2195
+ * SessionStart), so it names the CLI by its own name, in backticks as 7-9 do; ≤120 characters.
2196
+ *
2197
+ * The counts are of what `status` lists under "on account", split: `owners` are the account's owner grants this machine has not named
2198
+ * (`octocat/`), `repos` its repository grants not named here, not under a named owner, and not turned off. The forms: "2 repositories",
2199
+ * "1 owner and 3 repositories", "2 owners"; the singulars are "1 repository" and "1 owner".
2200
+ */
2201
+ readonly accountGrantsNotHere: (owners: number, repos: number) => string;
2202
+ /** State 10 when the counts would blow the ≤120 budget (an absurd number of grants): no counts, the same command. */
2203
+ readonly accountGrantsNotHereFallback: "Your account grants repositories not captured on this machine yet. Run `vibecommit status`.";
1631
2204
  };
1632
2205
  /**
1633
2206
  * The out-of-tree redaction marker — `CR-024d`, D57 §OV8d.
@@ -1658,6 +2231,10 @@ export declare const REDACTION: {
1658
2231
  /** Commands the copy points at. One definition, so a rename cannot half-land. */
1659
2232
  export declare const COMMANDS: {
1660
2233
  readonly connect: "vibecommit connect";
2234
+ /** `D33 · 27A`. */
2235
+ readonly scan: "vibecommit scan";
2236
+ /** `D14`/`D15`. */
2237
+ readonly backfill: "vibecommit backfill";
1661
2238
  /**
1662
2239
  * `CR-216/U2`. The only verb a credential FAULT's fix line may name — it can
1663
2240
  * replace the credential from any state. `CR-226` lets `connect` mint one
@@ -1678,6 +2255,10 @@ export declare const COMMANDS: {
1678
2255
  /** The ref form, for the detached-HEAD refusal. */
1679
2256
  readonly reportRef: "vibecommit report --since 2026-07-08 --ref main";
1680
2257
  readonly off: "vibecommit off";
2258
+ /** The picker's screen-reader flag: a FLAG on `connect`, like `signIn`. */
2259
+ readonly connectTyped: "vibecommit connect --typed";
2260
+ /** The git hook's own verb. `hooksPathFixManual` tells a user to add it to a hook they keep. */
2261
+ readonly postCommit: "vibecommit post-commit";
1681
2262
  /**
1682
2263
  * `CR-086`. The ARGUMENT SHAPE, shown once so the usage error and the retry
1683
2264
  * fix line cannot drift apart. There is no argument parser in this package —
@@ -1688,6 +2269,8 @@ export declare const COMMANDS: {
1688
2269
  */
1689
2270
  readonly why: "vibecommit why src/auth/session.ts:47";
1690
2271
  readonly chmodCredentials: "chmod 600 ~/.vibecommit/credentials.json";
2272
+ /** The folder's remedy, for `CREDENTIAL_FILE_INSECURE` when the folder is the one with the wrong mode. */
2273
+ readonly chmodDirectory: "chmod 700 ~/.vibecommit";
1691
2274
  /**
1692
2275
  * ⛔ THE INSTALL COMMAND, TRANSCRIBED FROM `claude-plugin/README.md:12` — and
1693
2276
  * it is deliberately NOT an invented update verb (`U1`, 2026-08-30).
@@ -1705,6 +2288,8 @@ export declare const COMMANDS: {
1705
2288
  * together — the wording and the command are one unit.
1706
2289
  */
1707
2290
  readonly pluginInstall: "/plugin install vibecommit@vibecommit-capture";
2291
+ /** The npm channel's way to a newer client: the package's own documented install, at `latest`. */
2292
+ readonly npmUpdate: "npm install -g @vibe-commit/capture@latest";
1708
2293
  };
1709
2294
  /**
1710
2295
  * Every URL the CLI prints. Here rather than inline for the same reason as the
@@ -1726,6 +2311,8 @@ export declare const URLS: {
1726
2311
  * deepening this constant is that task's, not a later guess.
1727
2312
  */
1728
2313
  readonly commits: "https://vibecommit.ai/app/commits";
2314
+ /** `/app/conversations`: where an uploaded backfill lands (D19). `/app` (`dashboard`) is the ending after a no. */
2315
+ readonly conversations: "https://vibecommit.ai/app/conversations";
1729
2316
  /**
1730
2317
  * One recorded session — the ending's link when the ingest 2xx carried a `conversation_id` (`DX D8`).
1731
2318
  * Verified by file: `vibecommit-web` `app/app/conversations/[id]/page.tsx` exists on `main`, and an