@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/copy/strings.js
CHANGED
|
@@ -28,12 +28,20 @@ export const HELP = {
|
|
|
28
28
|
commands: {
|
|
29
29
|
// `CR-216/U2`. FIRST in the list by habit, not by sequence: that "nothing for `connect` to use until
|
|
30
30
|
// this has run" reason has been false since `CR-226` (`connect` signs in itself on a machine with no
|
|
31
|
-
// credential). `connect` is the golden path; this verb renews or replaces the credential, and
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
auth: "Renew or replace this machine's credential.
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
// credential). `connect` is the golden path; this verb renews or replaces the credential, and on a terminal it
|
|
32
|
+
// then continues into `connect` — inside a git work tree, or (0.7.0, D32) outside one on a machine that captures
|
|
33
|
+
// nothing yet. With `--stdin` or no terminal it saves the credential and stops there.
|
|
34
|
+
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.",
|
|
35
|
+
// 0.7.0 (D34): from any folder. A repo with a remote is chosen in the picker; a repo with no remote keeps the old flow.
|
|
36
|
+
connect: "Choose the repositories to capture, from any folder, and connect them. On a machine with no credential it signs in first.",
|
|
37
|
+
// `D33 · 27A`. A public verb so an AI agent can list capturable repos without entering a consent
|
|
38
|
+
// flow. It opens no session file and changes no setting, which is what lets it be run before `connect`.
|
|
39
|
+
// ⚠ NOT "changes nothing" (PR 1 F1): opening Codex's index read-only makes SQLite create its own
|
|
40
|
+
// `-wal`/`-shm` journal files beside it, as any SQLite reader does, so the line claims only what is true.
|
|
41
|
+
scan: "List the repositories coding agents have been used in on this machine. Uploads nothing and changes no setting.",
|
|
42
|
+
// `D14`/`D15`. Offered by `connect` too. Asks first (default N) and says what it will not do.
|
|
43
|
+
backfill: "Upload earlier coding-agent sessions still on this machine, for the repositories you chose. Asks first; no commit links.",
|
|
44
|
+
status: "Show whether capture is on for this repo, or for this machine outside a repo, and when it last succeeded.",
|
|
37
45
|
off: "Stop capturing for this repo.",
|
|
38
46
|
// VERBATIM-APPROVED (D61 §PS6). Any reword needs a new claims-register row.
|
|
39
47
|
why: "Show the conversation turns recorded against the commit that last changed this line.",
|
|
@@ -42,6 +50,117 @@ export const HELP = {
|
|
|
42
50
|
finalize: "Close a finished session's last turn so commits made in it can be recorded.",
|
|
43
51
|
},
|
|
44
52
|
docsUrl: "https://vibecommit.ai/docs/what-we-upload",
|
|
53
|
+
/**
|
|
54
|
+
* PR 6 item 2 (devex review): what `<verb> --help` prints BEYOND the one sentence above, which stays the first
|
|
55
|
+
* paragraph. Agents read `--help` first, and until now the flags and exit codes existed only in the README.
|
|
56
|
+
*
|
|
57
|
+
* ⚠ Every flag here is one the verb's own argv reader acts on (`src/index.ts`, and each verb's parser), and every exit
|
|
58
|
+
* code is one the verb returns (`src/exit.ts`). A flag the verb ignores, or a code it never returns, would be copy no
|
|
59
|
+
* gate can check, so `test/verb-help.test.ts` ties each list to the source it describes.
|
|
60
|
+
*/
|
|
61
|
+
verbs: {
|
|
62
|
+
connect: {
|
|
63
|
+
usage: "vibecommit connect [--device] [--sign-in] [--typed]",
|
|
64
|
+
options: [
|
|
65
|
+
["--device", "Sign in with a code approved on another device, for a machine with no browser."],
|
|
66
|
+
["--sign-in", "Sign in through the browser before connecting."],
|
|
67
|
+
["--typed", "Use the typed prompt even on a terminal, for a screen reader."],
|
|
68
|
+
],
|
|
69
|
+
exits: [
|
|
70
|
+
["0", "Done."],
|
|
71
|
+
["1", "Failed, or a replacement credential was declined."],
|
|
72
|
+
["2", "Bad arguments, or no person at a terminal to answer the consent question."],
|
|
73
|
+
["3", "Not connected: this machine's credential is not accepted."],
|
|
74
|
+
],
|
|
75
|
+
},
|
|
76
|
+
auth: {
|
|
77
|
+
usage: "vibecommit auth [--stdin | --paste | --device]",
|
|
78
|
+
options: [
|
|
79
|
+
["--stdin", "Read the credential from standard input and stop after saving it."],
|
|
80
|
+
["--paste", "Skip the browser and paste a credential made in Settings."],
|
|
81
|
+
["--device", "Sign in with a code approved on another device."],
|
|
82
|
+
],
|
|
83
|
+
exits: [
|
|
84
|
+
["0", "Credential saved."],
|
|
85
|
+
["1", "Nothing was saved."],
|
|
86
|
+
["2", "Bad arguments, such as a credential passed as an argument."],
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
scan: {
|
|
90
|
+
usage: "vibecommit scan [--json]",
|
|
91
|
+
options: [["--json", "Print one JSON document instead of text."]],
|
|
92
|
+
exits: [
|
|
93
|
+
["0", "Repositories found."],
|
|
94
|
+
["4", "None found."],
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
backfill: {
|
|
98
|
+
usage: "vibecommit backfill",
|
|
99
|
+
options: [],
|
|
100
|
+
exits: [
|
|
101
|
+
["0", "Done, declined at the question, or interrupted with Ctrl+C. Sessions held for an organization's approval count as done."],
|
|
102
|
+
["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."],
|
|
103
|
+
["2", "No terminal, or an argument was given."],
|
|
104
|
+
["3", "Not connected."],
|
|
105
|
+
["4", "Nothing to upload."],
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
status: {
|
|
109
|
+
usage: "vibecommit status [--json]",
|
|
110
|
+
options: [["--json", "Print one JSON document instead of text."]],
|
|
111
|
+
exits: [
|
|
112
|
+
["0", "Reported."],
|
|
113
|
+
["1", "Failed."],
|
|
114
|
+
["2", "Bad arguments."],
|
|
115
|
+
["3", "Not connected."],
|
|
116
|
+
],
|
|
117
|
+
},
|
|
118
|
+
why: {
|
|
119
|
+
usage: "vibecommit why <file>:<line> [--json]",
|
|
120
|
+
options: [["--json", "Print one JSON document instead of text."]],
|
|
121
|
+
exits: [
|
|
122
|
+
["0", "Answered."],
|
|
123
|
+
["1", "Failed."],
|
|
124
|
+
["2", "Bad arguments."],
|
|
125
|
+
["3", "Not connected."],
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
report: {
|
|
129
|
+
usage: "vibecommit report --since <date> [--ref <ref>] [--json]",
|
|
130
|
+
options: [
|
|
131
|
+
["--since", "Start of the window, as YYYY-MM-DD. Required."],
|
|
132
|
+
["--ref", "The branch or commit to count. Default: the current branch."],
|
|
133
|
+
["--json", "Print one JSON document instead of text."],
|
|
134
|
+
],
|
|
135
|
+
exits: [
|
|
136
|
+
["0", "Reported."],
|
|
137
|
+
["1", "Failed."],
|
|
138
|
+
["2", "Bad arguments."],
|
|
139
|
+
["3", "Not connected."],
|
|
140
|
+
["4", "The window is empty: nothing to report."],
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
finalize: {
|
|
144
|
+
usage: "vibecommit finalize --session <id> | --latest [--force]",
|
|
145
|
+
options: [
|
|
146
|
+
["--session", "The session to close."],
|
|
147
|
+
["--latest", "The most recent session, when only one is recent."],
|
|
148
|
+
["--force", "Skip the check that the transcript has stopped changing. Only for a session that is over."],
|
|
149
|
+
],
|
|
150
|
+
exits: [
|
|
151
|
+
["0", "Closed: the server confirmed the last turn is recorded."],
|
|
152
|
+
["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."],
|
|
153
|
+
["2", "Nothing was sent: bad arguments, an unknown or still-running session, or several recent sessions for --latest."],
|
|
154
|
+
["3", "Not connected: this repo is not captured, or this machine has no credential."],
|
|
155
|
+
["5", "Delivered, but the server did not confirm it. Treat it as not closed."],
|
|
156
|
+
],
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
/** The two section labels of a verb's help. */
|
|
160
|
+
optionsLabel: "Options:",
|
|
161
|
+
/** A verb with no flags of its own (`backfill`) says so under the label, so "Options:" never sits over nothing. */
|
|
162
|
+
noOptions: "None. It takes no arguments.",
|
|
163
|
+
exitCodesLabel: "Exit codes:",
|
|
45
164
|
};
|
|
46
165
|
/**
|
|
47
166
|
* The ENTRY POINT's own chrome and its two usage failures — `CR-090d`.
|
|
@@ -74,8 +193,14 @@ export const USAGE = {
|
|
|
74
193
|
usageLabel: "Usage:",
|
|
75
194
|
commandsLabel: "Commands:",
|
|
76
195
|
docsLabel: "Docs:",
|
|
77
|
-
/**
|
|
78
|
-
|
|
196
|
+
/**
|
|
197
|
+
* The unknown-verb block (PR 7, Q6: `UNKNOWN_COMMAND`, routed through the shared renderer). The help text is no longer
|
|
198
|
+
* dumped after it, so the fix — the way to the list of commands — is the last thing on screen. The verb is whatever
|
|
199
|
+
* the user typed, so it is cut to a length the line can hold.
|
|
200
|
+
*/
|
|
201
|
+
unknownCommandWhat: (verb) => `\`${verb.length > 40 ? `${verb.slice(0, 39)}…` : verb}\` is not a vibecommit command.`,
|
|
202
|
+
unknownCommandFix: "See the commands:",
|
|
203
|
+
unknownCommandHelp: "vibecommit --help",
|
|
79
204
|
};
|
|
80
205
|
/** `vibecommit status` (CR-021). */
|
|
81
206
|
/**
|
|
@@ -108,6 +233,25 @@ export const STATUS = {
|
|
|
108
233
|
* changed them to match the screen rather than changing the screen.
|
|
109
234
|
*/
|
|
110
235
|
repoLabel: "repo",
|
|
236
|
+
/** 0.7.0, D6 · 2A: why this repo is on. One row under `repo`, only inside a repo that is on. */
|
|
237
|
+
basisLabel: "basis",
|
|
238
|
+
basisOwner: (owner) => `owner grant ${owner}/`,
|
|
239
|
+
basisRepo: "repo grant",
|
|
240
|
+
basisClone: "per clone",
|
|
241
|
+
/** The machine-level screen (any folder that is not a work tree). */
|
|
242
|
+
offMachine: "Capture is not on for any repository on this machine.",
|
|
243
|
+
ownersLabel: "owners",
|
|
244
|
+
reposLabel: "repos",
|
|
245
|
+
offLabel: "off",
|
|
246
|
+
/**
|
|
247
|
+
* Machine-level `status`: the repos whose own last upload was refused because their org has not approved capture. §10.2's held
|
|
248
|
+
* vocabulary — the beat word `held`, and the backfill screen's "the org must approve capture" (Alexander, 2026-10-24 17:20).
|
|
249
|
+
*/
|
|
250
|
+
heldLabel: "held",
|
|
251
|
+
heldReason: "the org must approve capture",
|
|
252
|
+
ownerTail: "all its repos, including ones you clone later",
|
|
253
|
+
changeLabel: "Change what is captured",
|
|
254
|
+
turnOffInside: "Turn one repo off, run inside it",
|
|
111
255
|
lastSuccessLabel: "last sent",
|
|
112
256
|
dashboardLabel: "dashboard",
|
|
113
257
|
/** `<slug> (git toplevel <path>)` — §10.3's repo row. */
|
|
@@ -128,6 +272,21 @@ export const STATUS = {
|
|
|
128
272
|
* after the rows, with the glyph turned `warn`. The date is absolute and in UTC.
|
|
129
273
|
*/
|
|
130
274
|
credentialEnding: (date, authCommand) => `This machine's credential ends ${date}. Run \`${authCommand}\` to renew it.`,
|
|
275
|
+
/**
|
|
276
|
+
* 0.7.0. A `grants.json` that is present and unreadable denies capture for every clone that has a remote
|
|
277
|
+
* (`consent.ts`'s `isCaptureAllowed`), and a hook cannot say so, so `status` does. The file name is the user's
|
|
278
|
+
* to fix; `connect` is where the next consent lands once it is readable.
|
|
279
|
+
*/
|
|
280
|
+
grantsUnreadable: (connect) => `~/.vibecommit/grants.json can't be read, so capture is stopped on this machine for every repository that has a remote. Fix the file or move it aside, then run \`${connect}\`.`,
|
|
281
|
+
/**
|
|
282
|
+
* 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
|
|
283
|
+
* missing it until `connect` runs. Only said on the npm channel: the plugin ships its own `hooks.json`, and its
|
|
284
|
+
* contract (no `SessionStart`, no git hooks) is unchanged.
|
|
285
|
+
*/
|
|
286
|
+
sessionStartMissing: (agents, connect) => `${agents} will not add commit hooks to a new clone: VibeCommit's SessionStart hook is not registered there. Run \`${connect}\` to register it.`,
|
|
287
|
+
/** 0.7.0, D4 · A. A hook the user deleted stays deleted; `connect` is the watched way back. */
|
|
288
|
+
commitHooksOff: (connect) => `Commit hooks are off in this repository: sessions are captured, commits are not linked to them. Run \`${connect}\` here to add them.`,
|
|
289
|
+
commitHooksForeign: (connect) => `This clone has its own commit hook, so VibeCommit's is not installed here. Run \`${connect}\` here to chain it.`,
|
|
131
290
|
credentialShadowed: "VIBECOMMIT_TOKEN is set and takes precedence over the credential saved on this machine. Unset it to use the saved one.",
|
|
132
291
|
/**
|
|
133
292
|
* `CR-228`, `TODOS[142]` — bytes the client ADVANCED PAST without delivering.
|
|
@@ -154,8 +313,8 @@ export const STATUS = {
|
|
|
154
313
|
* turn only when a following prompt arrives, so nothing will ever seal this one and the commits made in
|
|
155
314
|
* it cannot be recorded. States the consequence and the command; promises nothing about the commits.
|
|
156
315
|
*/
|
|
157
|
-
openTail: (sessions) => `${sessions === 1 ? "1 session has" : `${sessions} sessions have`} ended with the last turn still ` +
|
|
158
|
-
|
|
316
|
+
openTail: (sessions, finalizeLatest) => `${sessions === 1 ? "1 session has" : `${sessions} sessions have`} ended with the last turn still ` +
|
|
317
|
+
`open, so commits made in that turn are not recorded. Run \`${finalizeLatest}\` to close it.`,
|
|
159
318
|
/**
|
|
160
319
|
* `TODOS[145]` — commits the client has seen and is holding because no turn has closed yet. Normal
|
|
161
320
|
* mid-session; shown as a fact, not as a fault.
|
|
@@ -259,12 +418,12 @@ export const STATUS = {
|
|
|
259
418
|
* cannot tell a crashed session from one idle at lunch, and closing a session still in progress seals
|
|
260
419
|
* a turn that was not actually over.
|
|
261
420
|
*/
|
|
262
|
-
heldIdle: (bytes, sessions, commits, ids = []) => {
|
|
421
|
+
heldIdle: (bytes, sessions, commits, finalizeSession, ids = []) => {
|
|
263
422
|
const who = sessions === 1 ? `session ${namedIds(ids)}` : `${sessions} sessions (${namedIds(ids)})`;
|
|
264
423
|
const commitsClause = commits > 0 ? `, including ${commits} ${commits === 1 ? "commit" : "commits"}` : "";
|
|
265
424
|
const action = sessions === 1
|
|
266
|
-
? `If that session is finished,
|
|
267
|
-
:
|
|
425
|
+
? `If that session is finished, \`${finalizeSession} ${ids[0]}\` tries to send them and, if that works, closes it`
|
|
426
|
+
: `If a session above is finished, \`${finalizeSession} <id>\` tries to send its bytes and, if that works, closes it`;
|
|
268
427
|
return (`${BYTE_COUNT.format(bytes)} ${bytes === 1 ? "byte" : "bytes"} held from ${who}${commitsClause}, with no hook in over 30 ` +
|
|
269
428
|
`minutes. ${action}; anything held past 24 hours is written off instead.`);
|
|
270
429
|
},
|
|
@@ -299,7 +458,18 @@ export const CONNECT = {
|
|
|
299
458
|
* the nouns are transcribed rather than reworded: *"the output of commands it
|
|
300
459
|
* ran"*, never *"Bash tool results"*.
|
|
301
460
|
*/
|
|
302
|
-
consentHeading: "VibeCommit uploads your
|
|
461
|
+
consentHeading: "VibeCommit uploads your coding-agent transcripts for this repo.",
|
|
462
|
+
/**
|
|
463
|
+
* D23 · 17A: the picker path's heading (every `connect` that shows the picker, in a repo or not). `consentHeading`
|
|
464
|
+
* above remains only on the no-remote (`local:`) in-repo path, where there is nothing to pick (D35 · 29A: "Claude
|
|
465
|
+
* Code transcripts" understated what uploads once `connect` also wired Codex and Cursor hooks, 0.2.0).
|
|
466
|
+
*/
|
|
467
|
+
consentHeadingPicker: "VibeCommit uploads your coding-agent transcripts for the repositories you choose.",
|
|
468
|
+
/**
|
|
469
|
+
* ONE sentence, not a paragraph, added on the picker path only (design doc step 2, "The disclosure"): what the grant
|
|
470
|
+
* covers beyond the repos named on screen. The four paragraphs under either heading stay byte-identical.
|
|
471
|
+
*/
|
|
472
|
+
consentScope: "The choice covers future clones of these repositories too, and adds commit hooks to each clone where it can.",
|
|
303
473
|
/**
|
|
304
474
|
* ⚠ "private-repo paths" IS THE APPROVED WORDING, and it is the reason
|
|
305
475
|
* `private` is deliberately NOT registered in `claims.ts`: a substring gate on
|
|
@@ -407,11 +577,33 @@ export const CONNECT = {
|
|
|
407
577
|
// --- Mechanism copy (CR-016). ---
|
|
408
578
|
/** The `[y/N]` suffix. The capital is the default and the default is NO. */
|
|
409
579
|
consentAnswers: "[y/N]",
|
|
410
|
-
/**
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
580
|
+
/**
|
|
581
|
+
* 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
|
|
582
|
+
* this branch. It says who must answer ("a person"), that an agent cannot, and what to relay, and it carries the code
|
|
583
|
+
* `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
|
|
584
|
+
* repeated in the sentence. No `--yes`: that would bypass consent (D65 §DR7). The `what` line has no "you" (§13.6).
|
|
585
|
+
*/
|
|
586
|
+
nonInteractiveWhat: "Consent needs a person at a terminal.",
|
|
587
|
+
nonInteractiveWhy: "An agent cannot answer it, and standard input is not a terminal. Nothing was read and nothing was uploaded.",
|
|
588
|
+
/** A repo with no remote has a folder to name; the label is the fix and the command follows it. */
|
|
589
|
+
nonInteractiveFix: (folder) => `Ask the user to run this in ${folder}:`,
|
|
590
|
+
/**
|
|
591
|
+
* 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
|
|
592
|
+
* "you" in the `what` line, and is reached BEFORE the scan beat, so "Nothing was read and nothing was uploaded" stays
|
|
593
|
+
* literally true.
|
|
594
|
+
*/
|
|
595
|
+
pickerNonInteractiveWhat: "Choosing repositories needs a person at a terminal.",
|
|
596
|
+
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.",
|
|
597
|
+
pickerNonInteractiveFix: "Ask the user to run this in a terminal:",
|
|
414
598
|
alreadyConnected: "Capture is already on for this repository.",
|
|
599
|
+
/**
|
|
600
|
+
* 0.7.0. `grants.json` is present and unreadable, which denies this repository whatever consent it has (see
|
|
601
|
+
* `consent.ts`'s `isCaptureAllowed`). Answering the consent prompt could not change that, so `connect` stops
|
|
602
|
+
* BEFORE asking rather than take a yes it cannot honour.
|
|
603
|
+
*/
|
|
604
|
+
grantsUnreadableWhat: "Capture can't be turned on: ~/.vibecommit/grants.json can't be read.",
|
|
605
|
+
grantsUnreadableWhy: "Capture is stopped on this machine for every repository that has a remote until the file is readable. Nothing was changed.",
|
|
606
|
+
grantsUnreadableFixLabel: "Fix the file or move it aside, then run:",
|
|
415
607
|
/**
|
|
416
608
|
* The browser sign-in beat (PKCE loopback → minted ingest credential) is the
|
|
417
609
|
* oauth lane's, not this task's. Until it lands, the supported path is the one
|
|
@@ -531,12 +723,12 @@ export const COMMIT_HOOK = {
|
|
|
531
723
|
installed: (repo) => `Commit capture is on for this clone (${repo}). Commits are recorded as they happen, including ones made by \`make\`, \`gh\`, an alias or a script.`,
|
|
532
724
|
chained: (repo) => `Commit capture is on for this clone (${repo}). You already had a \`post-commit\` hook — it was kept and still runs first; ours runs after it.`,
|
|
533
725
|
already: "Commit capture was already on for this clone.",
|
|
534
|
-
perClone:
|
|
726
|
+
perClone: (connect) => `Run \`${connect}\` in each clone you want commits recorded for — git hooks are per-clone, not per-account.`,
|
|
535
727
|
hooksPathWhat: "Commit capture could NOT be installed for this clone.",
|
|
536
728
|
hooksPathWhy: (configured) => `This repository sets \`core.hooksPath\` to ${configured}, so git ignores \`.git/hooks\` entirely and a hook installed there would never run. Transcript capture is unaffected; only commit observation is.`,
|
|
537
729
|
hooksPathFixLabel: "Fix, either one:",
|
|
538
730
|
hooksPathFixUnset: "git config --unset core.hooksPath",
|
|
539
|
-
hooksPathFixManual:
|
|
731
|
+
hooksPathFixManual: (postCommit) => `or add \`${postCommit}\` to your existing post-commit hook`,
|
|
540
732
|
failedWhat: "Commit capture could NOT be installed for this clone.",
|
|
541
733
|
failedWhy: (why) => `Writing the \`post-commit\` hook failed: ${why}. Transcript capture is unaffected; only commit observation is.`,
|
|
542
734
|
};
|
|
@@ -567,7 +759,7 @@ export const AGENT_HOOKS = {
|
|
|
567
759
|
refusedWhat: (agent) => `Session capture could NOT be set up for ${agent}.`,
|
|
568
760
|
refusedWhy: (path, why) => `${path} could not be read as JSON (${why}), and it was left exactly as it is. Overwriting a file we cannot parse would discard settings we cannot see.`,
|
|
569
761
|
refusedFixLabel: "Fix:",
|
|
570
|
-
refusedFix: (path) => `check ${path} for a syntax error, then run
|
|
762
|
+
refusedFix: (path, connect) => `check ${path} for a syntax error, then run \`${connect}\` again`,
|
|
571
763
|
failedWhat: (agent) => `Session capture could NOT be set up for ${agent}.`,
|
|
572
764
|
failedWhy: (path, why) => `Writing ${path} failed: ${why}. Commit capture and any agent already configured are unaffected.`,
|
|
573
765
|
};
|
|
@@ -697,9 +889,302 @@ export const SIGNIN = {
|
|
|
697
889
|
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.",
|
|
698
890
|
busyFix: "Run it again in a moment:",
|
|
699
891
|
};
|
|
892
|
+
/**
|
|
893
|
+
* `vibecommit scan` — design review D17 · 11A, D26, D27, D33 · 27A, and the screen VQ drew for it
|
|
894
|
+
* (style guide §10.13) on 2026-10-24.
|
|
895
|
+
*
|
|
896
|
+
* ⛔ **The nouns are the agent-neutral ones** (D11 · A, D35): "coding agent", never "Claude Code
|
|
897
|
+
* session", because the scan covers three agents and the picker's heading says the same. The agent
|
|
898
|
+
* NAMES appear only on a repo's second line, where they are facts about which store a count came from.
|
|
899
|
+
*
|
|
900
|
+
* ⚠ **Every sentence here is a claims-register row** (the register is `code`'s, VR's PR). None says
|
|
901
|
+
* "every" or "all": the scan counts transcripts still on disk, and what `cleanupPeriodDays` already
|
|
902
|
+
* deleted is not among them.
|
|
903
|
+
*/
|
|
904
|
+
export const SCAN = {
|
|
905
|
+
/** The beat line, drawn in the existing beat shape and overwritten once with `done` (D17). */
|
|
906
|
+
beat: "Looking for repositories on this machine...",
|
|
907
|
+
beatDone: "done",
|
|
908
|
+
found: (count) => `Found ${count} ${count === 1 ? "repository" : "repositories"} you've used a coding agent in on this machine.`,
|
|
909
|
+
sessions: (count) => `${count} ${count === 1 ? "session" : "sessions"}`,
|
|
910
|
+
since: (date) => `since ${date}`,
|
|
911
|
+
/** What an agent is called on a repo's second line. The ids are wire values, not labels. */
|
|
912
|
+
agent: { "claude-code": "Claude Code", "codex-cli": "Codex", cursor: "Cursor" },
|
|
913
|
+
notListed: "Not listed here:",
|
|
914
|
+
noRemote: (count, connect) => count === 1 ? `1 repo with no remote: run \`${connect}\` inside it` : `${count} repos with no remote: run \`${connect}\` inside each`,
|
|
915
|
+
/**
|
|
916
|
+
* The picker's own line (PR 1 ruling 2): ONE count and ONE line for a folder with two or more
|
|
917
|
+
* candidate paths, a hashed name (cut, so it cannot be inverted) and a deleted sibling. Claude Code's
|
|
918
|
+
* and Cursor's only — a Codex row records its real `cwd` and is never ambiguous.
|
|
919
|
+
*/
|
|
920
|
+
ambiguous: (count) => count === 1
|
|
921
|
+
? "1 session in a folder that can't be matched to one repo"
|
|
922
|
+
: `${count} sessions in folders that can't be matched to one repo`,
|
|
923
|
+
/** Scan-only (ruling 5a): a folder, or a Codex `cwd`, that exists but is not inside a git work tree. */
|
|
924
|
+
nonRepo: (count) => count === 1
|
|
925
|
+
? "1 session in a folder that isn't a git repository"
|
|
926
|
+
: `${count} sessions in folders that aren't git repositories`,
|
|
927
|
+
missingFolder: (count) => count === 1
|
|
928
|
+
? "1 session in a folder that no longer exists"
|
|
929
|
+
: `${count} sessions in folders that no longer exist`,
|
|
930
|
+
/**
|
|
931
|
+
* ⛔ CLAIMS ONLY WHAT GIT SHOWS (ruling 7). The test is a session's mtime against the OLDEST reflog entry,
|
|
932
|
+
* and `gc.reflogExpire` prunes a long-lived clone's oldest entries, so "older than the reflog" is the fact
|
|
933
|
+
* and "the folder was reused" is a possibility — the same repo deleted and cloned again reads the same.
|
|
934
|
+
*/
|
|
935
|
+
pathReused: (count) => count === 1
|
|
936
|
+
? "1 session older than its clone's reflog (possibly a reused folder)"
|
|
937
|
+
: `${count} sessions older than their clone's reflog (possibly a reused folder)`,
|
|
938
|
+
/** One clone: the path rides the line. More: this heading, then one indented path per clone. */
|
|
939
|
+
noReflogOne: (path) => `1 clone with no reflog: ${path} (backfill skips it)`,
|
|
940
|
+
noReflogMany: (count) => `${count} clones with no reflog (backfill skips them):`,
|
|
941
|
+
/** Rollouts on disk that no index row names (ruling 5c) — counted, never opened. */
|
|
942
|
+
unindexed: (count) => count === 1
|
|
943
|
+
? "1 Codex session missing from its thread index"
|
|
944
|
+
: `${count} Codex sessions missing from its thread index`,
|
|
945
|
+
/**
|
|
946
|
+
* `Codex sessions couldn't be read (unrecognised index)`, one line per unreadable agent (R3-15). The
|
|
947
|
+
* bracket names a cause the user can act on; a plain read failure (ruling 6) has none to name, so it
|
|
948
|
+
* gets none. The `--json` `reason` is the same three words either way.
|
|
949
|
+
*/
|
|
950
|
+
unreadable: (agent, reason) => reason === null
|
|
951
|
+
? `${agent} sessions couldn't be read`
|
|
952
|
+
: `${agent} sessions couldn't be read (${reason})`,
|
|
953
|
+
next: "Choose what is captured:",
|
|
954
|
+
/** Exit 4. Both screens end on the same command. */
|
|
955
|
+
none: "No coding-agent sessions were found on this machine.",
|
|
956
|
+
/**
|
|
957
|
+
* Exit 4 with `Not listed here:` lines: sessions exist that could not be listed, so `none` would be
|
|
958
|
+
* untrue. `none` prints only when that block is empty, i.e. the scan saw no session at all (VQ, PR 1
|
|
959
|
+
* ruling 3).
|
|
960
|
+
*/
|
|
961
|
+
noneListable: "No repository could be listed from the sessions on this machine.",
|
|
962
|
+
noneNext: "Choose owners or repos anyway:",
|
|
963
|
+
};
|
|
964
|
+
/**
|
|
965
|
+
* `vibecommit backfill` — style guide §10.14, design review D14 · 8A, D15 · 9A; capture 0.7.0, PR 5.
|
|
966
|
+
*
|
|
967
|
+
* Every sentence here is a claims-register row. ⛔ Three promises it must never make: that a backfilled session is
|
|
968
|
+
* LINKED to a commit (it arrives without links, and the copy says so), that "every" or "all" earlier sessions are
|
|
969
|
+
* uploaded (only the ones still on this machine and not yet sent), and that a held session will upload by itself (no
|
|
970
|
+
* hook fires for an old session, so the held line points at a re-run).
|
|
971
|
+
*
|
|
972
|
+
* The two folder reasons are different facts (VQ ruling): `folder differs` is a RECORDED folder that is not this clone,
|
|
973
|
+
* `folder not recorded` is a transcript that records none.
|
|
974
|
+
*/
|
|
975
|
+
export const BACKFILL = {
|
|
976
|
+
/**
|
|
977
|
+
* Inside `connect` the repos are the ones it just showed, so "these"; run on its own there is no "these", so it names whose
|
|
978
|
+
* they are (VQ, PR 5 review).
|
|
979
|
+
*/
|
|
980
|
+
offerHeading: (repos, standalone) => standalone
|
|
981
|
+
? `Earlier sessions are still on this machine for ${repos} ${repos === 1 ? "repository" : "repositories"} you chose.`
|
|
982
|
+
: `Earlier sessions are still on this machine for ${repos} of these repos.`,
|
|
983
|
+
/** The count on a repo row. "Not yet uploaded", so it is never mistaken for the picker's total on disk. */
|
|
984
|
+
notYetUploaded: (count) => `${count} not yet uploaded`,
|
|
985
|
+
/**
|
|
986
|
+
* Cursor sessions are not offered (Alexander, 2026-10-24 13:54 EST: Cursor's transcripts record no folder, so the
|
|
987
|
+
* folder check cannot run). One muted line, only when a repo you chose has some.
|
|
988
|
+
*/
|
|
989
|
+
cursorNotUploaded: (count) => count === 1
|
|
990
|
+
? "1 Cursor session isn't uploaded: Cursor doesn't record the folder a session started in."
|
|
991
|
+
: `${count} Cursor sessions aren't uploaded: Cursor doesn't record the folder a session started in.`,
|
|
992
|
+
/** Two lines, as §10.14 draws them. */
|
|
993
|
+
/**
|
|
994
|
+
* 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
|
|
995
|
+
* skip on every re-run. (Sub-agent streams are not capped.)
|
|
996
|
+
*/
|
|
997
|
+
overSizeNote: (count) => count === 1 ? "1 session over 50 MiB isn't uploaded." : `${count} sessions over 50 MiB aren't uploaded.`,
|
|
998
|
+
/**
|
|
999
|
+
* A clone with no reflog cannot be tested for a reused path (a transcript older than the clone's first reflog entry), and
|
|
1000
|
+
* that test is the only guard against one, so its sessions are left out of the count and named here with the clone.
|
|
1001
|
+
*/
|
|
1002
|
+
noReflogNote: (count, path) => count === 1
|
|
1003
|
+
? `1 session in a clone with no reflog isn't uploaded: ${path}`
|
|
1004
|
+
: `${count} sessions in a clone with no reflog aren't uploaded: ${path}`,
|
|
1005
|
+
uploadNote: ["They upload one at a time, the same way new sessions do, without", "commit links."],
|
|
1006
|
+
question: (sessions) => sessions === 1 ? "Upload this session now? [y/N] " : `Upload these ${sessions} sessions now? [y/N] `,
|
|
1007
|
+
/** A no. A completed consent flow (§13.7), not an error. */
|
|
1008
|
+
declined: (backfill) => `Nothing was uploaded. Run \`${backfill}\` any time.`,
|
|
1009
|
+
nothingToUpload: "Nothing to upload: no earlier session on this machine is waiting for a repository you've chosen.",
|
|
1010
|
+
runHeading: (sessions) => sessions === 1 ? "Uploading 1 session..." : `Uploading ${sessions} sessions, one at a time...`,
|
|
1011
|
+
/** Outcome fragments on a repo line, joined by " · ". */
|
|
1012
|
+
uploaded: (count) => `${count} uploaded`,
|
|
1013
|
+
skipped: (count, reason) => `${count} skipped, ${reason}`,
|
|
1014
|
+
held: (count) => `${count} held, the org must approve capture`,
|
|
1015
|
+
failed: (count, reason) => `${count} failed, ${reason}`,
|
|
1016
|
+
stopped: "stopped",
|
|
1017
|
+
/** Skip reasons. */
|
|
1018
|
+
overSize: "over 50 MiB",
|
|
1019
|
+
folderDiffers: "folder differs",
|
|
1020
|
+
folderNotRecorded: "folder not recorded",
|
|
1021
|
+
/** The transcript could not be opened at all (permissions), which is a different fact from one that records no folder. */
|
|
1022
|
+
couldntBeRead: "couldn't be read",
|
|
1023
|
+
/** The file vanished between the offer and its upload: a skip, not a refusal by the server. */
|
|
1024
|
+
fileGone: "the file is gone",
|
|
1025
|
+
/** `vibecommit off` (or a grant removed) while the run was going: the rest of that repo is not sent. */
|
|
1026
|
+
turnedOff: "turned off while this ran",
|
|
1027
|
+
outsideAgentFolder: "not in the agent's session folder",
|
|
1028
|
+
/** Failure reasons: a `never`. The server's own code is never shown (§13.6: no bare status, no raw error). */
|
|
1029
|
+
refusedByServer: "the server refused it",
|
|
1030
|
+
repositoryForbidden: "another organization owns this repository",
|
|
1031
|
+
noRepoIdentity: "no repository identity",
|
|
1032
|
+
unrecognisedFileName: "the file name isn't a session id",
|
|
1033
|
+
/** The summary. The glyph is `ok` only when nothing was held, stopped or failed. */
|
|
1034
|
+
summary: (uploaded, total, skipped, held, failed) => {
|
|
1035
|
+
const noun = total === 1 ? "session" : "sessions";
|
|
1036
|
+
const tail = [
|
|
1037
|
+
skipped > 0 ? `${skipped} skipped` : null,
|
|
1038
|
+
held > 0 ? `${held} held` : null,
|
|
1039
|
+
failed > 0 ? `${failed} failed` : null,
|
|
1040
|
+
].filter((part) => part !== null);
|
|
1041
|
+
return `Uploaded ${uploaded} of ${total} ${noun}.${tail.length > 0 ? ` ${tail.join(", ")}.` : ""}`;
|
|
1042
|
+
},
|
|
1043
|
+
/** `owners` is the held repos' owners, already phrased ("acme-corp", "acme-corp or other-org"). */
|
|
1044
|
+
heldBlock: (owners) => `Held sessions wait for ${owners} to approve capture:`,
|
|
1045
|
+
heldThenRun: "Then run:",
|
|
1046
|
+
/**
|
|
1047
|
+
* The stop block: a server `later` (5xx, 429) stops the run, with the resume fix. ⛔ It states only what landed: `uploaded` is
|
|
1048
|
+
* sessions the server took, not sessions looked at, and "not yet uploaded" is what a re-run will OFFER again (skipped and held
|
|
1049
|
+
* sessions among them), not a promise of what it will send.
|
|
1050
|
+
*/
|
|
1051
|
+
stopWhat: (uploaded, total) => `Upload stopped: ${uploaded} of ${total} ${total === 1 ? "session" : "sessions"} uploaded.`,
|
|
1052
|
+
stopWhy: (notUploaded) => `The server asked the client to try again later. Nothing already sent is lost, and a re-run offers the ${notUploaded} ${notUploaded === 1 ? "session" : "sessions"} not yet uploaded.`,
|
|
1053
|
+
/** No response at all (a refused connection, a timeout): not the server asking anything. */
|
|
1054
|
+
stopWhyUnreachable: (notUploaded) => `The server could not be reached. Nothing already sent is lost, and a re-run offers the ${notUploaded} ${notUploaded === 1 ? "session" : "sessions"} not yet uploaded.`,
|
|
1055
|
+
stopFixLabel: "Resume:",
|
|
1056
|
+
/** Ctrl+C at the y/N or during the upload. Exit 0: capture is on. */
|
|
1057
|
+
interrupted: (backfill) => `Stopped. A re-run of ${backfill} sends what is left.`,
|
|
1058
|
+
/** Exit 3. */
|
|
1059
|
+
notConnectedWhat: "This machine isn't connected.",
|
|
1060
|
+
notConnectedWhy: "`backfill` uploads with this machine's credential, and there isn't one. Nothing was read.",
|
|
1061
|
+
notConnectedFixLabel: "Connect first:",
|
|
1062
|
+
/** `grants.json` is present and unreadable: every repo with a remote is denied, so there is nothing honest to offer. */
|
|
1063
|
+
grantsUnreadableWhat: "Backfill can't run: ~/.vibecommit/grants.json can't be read.",
|
|
1064
|
+
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.",
|
|
1065
|
+
grantsUnreadableFixLabel: "Fix the file or move it aside, then run:",
|
|
1066
|
+
/** Exit 2. A prompt that proceeds when nobody can answer it is not a prompt. */
|
|
1067
|
+
nonInteractiveWhat: "`backfill` needs an interactive terminal.",
|
|
1068
|
+
nonInteractiveWhy: "Standard input is not a terminal, so the question before uploading cannot be answered. Nothing was read and nothing was uploaded.",
|
|
1069
|
+
nonInteractiveFix: "Run this in a terminal:",
|
|
1070
|
+
/** The credential was rejected mid-run (a 401): the same block `finalize` shows, in this verb's words. */
|
|
1071
|
+
credentialStoppedWhat: "Upload stopped: this machine's credential is no longer accepted.",
|
|
1072
|
+
credentialStoppedWhy: "Nothing already sent is lost, and a re-run offers the sessions not yet uploaded.",
|
|
1073
|
+
credentialStoppedFixLabel: "Renew it, then run backfill again:",
|
|
1074
|
+
usageWhat: "That is not something `vibecommit backfill` understands.",
|
|
1075
|
+
usageWhy: "Nothing was read and nothing was uploaded. `backfill` takes no arguments.",
|
|
1076
|
+
};
|
|
1077
|
+
/**
|
|
1078
|
+
* `vibecommit connect` from any folder — the picker, the grant block, the hooks step and the endings (0.7.0, PR 3).
|
|
1079
|
+
* Style guide §10.12, copied from the merged guide and the design doc; the design doc wins where they differ.
|
|
1080
|
+
*/
|
|
1081
|
+
export const PICKER = {
|
|
1082
|
+
onNow: "on now",
|
|
1083
|
+
turnedOff: "turned off",
|
|
1084
|
+
/** Why an `on now` row is on (D5 · 1A), so a 0.6.x upgrader sees what is already captured. */
|
|
1085
|
+
reasonOwner: "owner",
|
|
1086
|
+
reasonRepo: "repo",
|
|
1087
|
+
reasonPerClone: "per clone",
|
|
1088
|
+
/** The owner row ALWAYS states how many repos `aN` covers (D9), so a hidden repo is never covered unseen. */
|
|
1089
|
+
ownerAll: (count) => `all ${count} ${count === 1 ? "repo" : "repos"} here, including repos you clone later`,
|
|
1090
|
+
ownerOnReposHere: (count) => `${count} ${count === 1 ? "repo" : "repos"} here`,
|
|
1091
|
+
turnOnHint: "choose it to turn it back on",
|
|
1092
|
+
/** Where the working folder is a repo, the row is marked so a pre-tick (or a `$HOME` dotfiles repo) is legible. */
|
|
1093
|
+
thisRepo: "this repo",
|
|
1094
|
+
thisFolder: "this folder",
|
|
1095
|
+
moreTyped: (count, owner) => `${count} more in ${owner}/ · type more to list them`,
|
|
1096
|
+
moreChecklist: (count, owner) => `${count} more in ${owner}/`,
|
|
1097
|
+
/** The typed prompt (D8). */
|
|
1098
|
+
choose: (hasOwners) => hasOwners
|
|
1099
|
+
? "Choose a1, numbers (1 2), owner/ or owner/repo."
|
|
1100
|
+
: "Choose numbers (1 2), owner/ or owner/repo.",
|
|
1101
|
+
removeHint: "Remove one with -N, -owner/ or -owner/repo.",
|
|
1102
|
+
enterNothing: "Press Enter to change nothing.",
|
|
1103
|
+
/** D34 in the typed prompt: the working folder's repo is pre-selected, so Enter leads to the (default No) y/N. */
|
|
1104
|
+
enterThisRepo: (slug) => `Press Enter to choose ${slug}, this repo.`,
|
|
1105
|
+
promptMark: "> ",
|
|
1106
|
+
/** `tokens` is the already-joined list (`9 (no row 9), acme, corp`): the corpus renders every template with a string. */
|
|
1107
|
+
notUnderstood: (tokens) => `Not understood: ${tokens}. Nothing was chosen.`,
|
|
1108
|
+
noRow: (n) => `${n} (no row ${n})`,
|
|
1109
|
+
alreadyOn: (token, remove) => `${token} (already on; ${remove} stops it)`,
|
|
1110
|
+
notOn: (token) => `${token} (not on)`,
|
|
1111
|
+
/** The empty screen (D12 · 6A): a new laptop, no agent session on disk at all. */
|
|
1112
|
+
emptyNone: "No coding-agent sessions were found on this machine.",
|
|
1113
|
+
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.",
|
|
1114
|
+
emptyType: "Type owner/ or owner/repo, for example alexvibecommit/.",
|
|
1115
|
+
/** Sessions exist but none could be listed (the `Not listed here:` block is not empty): scan's own wording. */
|
|
1116
|
+
emptyListable: "Type owner/ or owner/repo, for example alexvibecommit/, to capture a repository that is not listed.",
|
|
1117
|
+
/** The checklist (D28). */
|
|
1118
|
+
hint: "↑↓ move · space choose · enter done · t typed prompt · ctrl+c cancel",
|
|
1119
|
+
hintTyped: (connectTyped) => `For a screen reader, run: ${connectTyped}`,
|
|
1120
|
+
/** The enter-with-nothing lines (D5). */
|
|
1121
|
+
nothingGranted: (connect) => `Nothing granted. Run \`${connect}\` again any time.`,
|
|
1122
|
+
noChanges: (summary) => `No changes. Capture stays on for ${summary}.`,
|
|
1123
|
+
cancelled: "Cancelled. Nothing was changed.",
|
|
1124
|
+
/** The grant block (D7 · 3A). */
|
|
1125
|
+
chose: "You chose:",
|
|
1126
|
+
labelOwners: "owners",
|
|
1127
|
+
labelRepos: "repos",
|
|
1128
|
+
labelTurnOn: "turn on",
|
|
1129
|
+
labelStop: "stop",
|
|
1130
|
+
ownerHere: (count) => `(${count} here, and later clones)`,
|
|
1131
|
+
noCloneHere: "(no clone here yet)",
|
|
1132
|
+
questionGrant: "Upload transcripts from these repositories?",
|
|
1133
|
+
questionStop: "Stop capturing these repositories?",
|
|
1134
|
+
stopped: "Stopped capturing the repositories above.",
|
|
1135
|
+
/** "1 owner and 2 repos" — the on-now summary of Enter-with-grants, `auth`'s one line and the status heading. */
|
|
1136
|
+
summary: (owners, repos) => {
|
|
1137
|
+
const o = `${owners} ${owners === 1 ? "owner" : "owners"}`;
|
|
1138
|
+
const r = `${repos} ${repos === 1 ? "repo" : "repos"}`;
|
|
1139
|
+
if (owners > 0 && repos > 0)
|
|
1140
|
+
return `${o} and ${r}`;
|
|
1141
|
+
return owners > 0 ? o : r;
|
|
1142
|
+
},
|
|
1143
|
+
authStays: (summary) => `Capture stays on for ${summary} on this machine.`,
|
|
1144
|
+
/** The hooks step (D13 · 7A). */
|
|
1145
|
+
hooksBeat: (clones) => `Adding commit hooks to ${clones} ${clones === 1 ? "clone" : "clones"}...`,
|
|
1146
|
+
hooksDone: "done",
|
|
1147
|
+
hooksCount: (added, chained, notAdded) => {
|
|
1148
|
+
const head = `${added} added${chained > 0 ? `, ${chained} of them after your own hook` : ""}`;
|
|
1149
|
+
return notAdded > 0 ? `${head} · ${notAdded} not added` : head;
|
|
1150
|
+
},
|
|
1151
|
+
hooksNotAdded: (count) => `Commit hooks were not added to ${count} ${count === 1 ? "clone" : "clones"}:`,
|
|
1152
|
+
hooksPathReason: "core.hooksPath is set",
|
|
1153
|
+
/** A hook write that FAILED is a real exception with its own reason (VQ, item 9): neither dropped nor given `hooksPath`'s fix. */
|
|
1154
|
+
hooksFailedReason: "the hook could not be written",
|
|
1155
|
+
hooksStillCaptured: "Sessions there are still captured. To record commits too, either:",
|
|
1156
|
+
hooksStillCapturedOther: "Sessions there are still captured.",
|
|
1157
|
+
hooksFailedFixLabel: "Where the hook could not be written, try again:",
|
|
1158
|
+
/** "Capture is on" (D18 · 12A, D19 · 13A). */
|
|
1159
|
+
onFor: (summary) => `Capture is on for ${summary} on this machine.`,
|
|
1160
|
+
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.\"",
|
|
1161
|
+
stopOne: "To stop one repo, run inside it:",
|
|
1162
|
+
/**
|
|
1163
|
+
* Alexander's "caveat for other owners" (2026-10-24; amended 17:20), on the "Capture is on" block. It prints for the owners the
|
|
1164
|
+
* test capture did NOT check: from `~` that is every granted owner (there is no session to probe), and in a repo it is every
|
|
1165
|
+
* 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
|
|
1166
|
+
* account the client cannot know whether an org is yet to approve capture, so it says one may be. Never printed when every
|
|
1167
|
+
* such owner is the user's own account.
|
|
1168
|
+
*/
|
|
1169
|
+
ownerApproval: (status) => `An organization can require an owner's approval before its repos are captured; once a session in one of its repos has tried to upload, ${status} shows any that are waiting.`,
|
|
1170
|
+
onNewLaptop: (names) => `Capture is on for ${names} on this machine.`,
|
|
1171
|
+
onNewLaptopProof: "No clone of it is here yet. Clone one and open a coding agent in it; that session is captured.",
|
|
1172
|
+
};
|
|
700
1173
|
/** `vibecommit off`. */
|
|
701
1174
|
export const OFF = {
|
|
702
1175
|
done: "Capture is off for this repository.",
|
|
1176
|
+
/**
|
|
1177
|
+
* 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
|
|
1178
|
+
* machine. Slice 2 extends the sentence to the other machines once they sync; until then it says only what is true.
|
|
1179
|
+
*/
|
|
1180
|
+
doneSlug: (slug) => `Turned off ${slug} for every clone on this machine.`,
|
|
1181
|
+
/** D31: bare `off` outside a repository. The picker is where an owner or another repo is unticked. */
|
|
1182
|
+
outsideRepoWhat: "`off` turns off the repository you're in.",
|
|
1183
|
+
outsideRepoFixLabel: "To stop capturing an owner or another repo, untick it in the picker:",
|
|
1184
|
+
/** `grants.json` is unreadable, so the exclusion could not be recorded. The clone's own consent was still withdrawn. */
|
|
1185
|
+
grantsUnreadableWhat: "The turn-off could not be recorded: ~/.vibecommit/grants.json can't be read.",
|
|
1186
|
+
grantsUnreadableWhy: "Capture is already stopped for this repository while the file can't be read, and this clone's own consent was withdrawn.",
|
|
1187
|
+
grantsUnreadableFixLabel: "Fix the file or move it aside, then run:",
|
|
703
1188
|
alreadyOff: "Capture was already off for this repository.",
|
|
704
1189
|
note: "Sessions already recorded are unaffected.",
|
|
705
1190
|
// `TODOS[184]`. `off` used to ignore `argv` entirely and always run — a stray
|
|
@@ -989,7 +1474,10 @@ export const WHY = {
|
|
|
989
1474
|
*/
|
|
990
1475
|
skewWhat: "The record service sent an answer this version is too old to show.",
|
|
991
1476
|
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.",
|
|
1477
|
+
/** The PLUGIN channel's remedy (`COMMANDS.pluginInstall`). */
|
|
992
1478
|
skewFix: "Reinstall the VibeCommit plugin to pick up the current client, then run this again:",
|
|
1479
|
+
/** The npm channel's remedy (`COMMANDS.npmUpdate`): an npm install has no plugin to reinstall. */
|
|
1480
|
+
skewFixNpm: "Update VibeCommit to pick up the current client, then run this again:",
|
|
993
1481
|
/** The bearer is dead after one refresh and one retry. Exit 3, not 1. */
|
|
994
1482
|
signedOutWhat: "This machine is not signed in to VibeCommit.",
|
|
995
1483
|
signedOutWhy: "Reading a record needs a signed-in user, and no usable sign-in was found on this machine.",
|
|
@@ -1276,20 +1764,44 @@ export const ABSENCE = {
|
|
|
1276
1764
|
* know were bound: `closed` says the last turn is recorded, not that any commit matched it.
|
|
1277
1765
|
*/
|
|
1278
1766
|
export const FINALIZE = {
|
|
1279
|
-
|
|
1767
|
+
// PR 7 (Q7): where the remedy is a command it sits in the §13.6 fix block, not inside the `what` line. The `what` lines
|
|
1768
|
+
// below lost exactly the clause that moved; the fix commands are the ones the old sentence named.
|
|
1769
|
+
needTarget: "Say which session to close.",
|
|
1770
|
+
needTargetFix: "Name one, or take the latest:",
|
|
1280
1771
|
badSessionId: "That is not a session id (letters, digits, dot, dash and underscore only).",
|
|
1281
|
-
noRecentSession: "No session in this repository has delivered anything in the last 24 hours.
|
|
1282
|
-
|
|
1772
|
+
noRecentSession: "No session in this repository has delivered anything in the last 24 hours.",
|
|
1773
|
+
noRecentSessionFix: "Name a session:",
|
|
1774
|
+
severalRecent: "More than one session in this repository is recent.",
|
|
1775
|
+
severalRecentFix: "Name one:",
|
|
1776
|
+
/** `finalize --session <id>` for a session that is known, e.g. the one whose delivery just failed. */
|
|
1777
|
+
commandSession: (id) => `vibecommit finalize --session ${id}`,
|
|
1778
|
+
/** The same with the placeholder, for a fix line written before a session is known. */
|
|
1779
|
+
commandSessionAny: "vibecommit finalize --session <id>",
|
|
1780
|
+
/** The command without its id, for a sentence that names the id itself (`status`'s held-idle line). */
|
|
1781
|
+
commandSessionBase: "vibecommit finalize --session",
|
|
1782
|
+
commandSessionForce: (id) => `vibecommit finalize --session ${id} --force`,
|
|
1283
1783
|
recentRow: (id, minutesAgo) => `${id} (${minutesAgo} min ago)`,
|
|
1284
1784
|
unknownSession: (id) => `This repository has no captured session ${id}.`,
|
|
1285
1785
|
transcriptMissing: (id) => `Could not find the transcript for session ${id}.`,
|
|
1286
|
-
stillWriting: "That session's transcript changed a moment ago.
|
|
1786
|
+
stillWriting: "That session's transcript changed a moment ago.",
|
|
1787
|
+
stillWritingFix: "Wait for the session to finish, or if it is over, run:",
|
|
1287
1788
|
closed: (id) => `Closed session ${id}: its last turn is recorded, so commits made in it can now be recorded.`,
|
|
1288
1789
|
alreadyClosed: (id) => `Session ${id} had nothing left open. Nothing changed.`,
|
|
1289
1790
|
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.",
|
|
1290
|
-
refused: "The server declined to close the session on this attempt.
|
|
1291
|
-
|
|
1292
|
-
|
|
1791
|
+
refused: "The server declined to close the session on this attempt.",
|
|
1792
|
+
retryFix: "Run it again:",
|
|
1793
|
+
notDelivered: "Could not deliver the session. Nothing was closed.",
|
|
1794
|
+
credentialStopped: "VibeCommit stopped sending for this credential.",
|
|
1795
|
+
credentialStoppedFix: "Replace it:",
|
|
1796
|
+
/**
|
|
1797
|
+
* PR 7 (Q2, VQ's wording): the ingest address in the environment (`VIBECOMMIT_INGEST_URL`) is one this client refuses to
|
|
1798
|
+
* send to, so retrying cannot help. Shared by `finalize` and `backfill`, so the `why` says only "Nothing was sent": it must
|
|
1799
|
+
* not claim a session was or was not closed. The VALUE is never echoed (a URL can carry a secret).
|
|
1800
|
+
*/
|
|
1801
|
+
ingestUrlWhat: "The address VibeCommit sends sessions to can't be used.",
|
|
1802
|
+
ingestUrlWhy: "VIBECOMMIT_INGEST_URL must be an https address, or an http address on this machine, and it isn't. Nothing was sent.",
|
|
1803
|
+
ingestUrlFix: "Correct it, or remove it to use the default address:",
|
|
1804
|
+
ingestUrlCommand: "unset VIBECOMMIT_INGEST_URL",
|
|
1293
1805
|
/**
|
|
1294
1806
|
* `TODOS[177]` follow-up (VL, 2026-10-08, VG's silent-loss finding) — ONE stderr line for the whole run when
|
|
1295
1807
|
* `finalize` sets any inferred-squash pairs aside (the main delivery, the drain loop, or both, summed). Printed
|
|
@@ -1317,8 +1829,8 @@ export const REJECTED = {
|
|
|
1317
1829
|
* command across lines; `unconfirmed` is their join, the sentence the plan wrote.
|
|
1318
1830
|
*/
|
|
1319
1831
|
unconfirmedWhat: "Couldn't confirm this machine's credential with the server.",
|
|
1320
|
-
unconfirmedFix:
|
|
1321
|
-
unconfirmed:
|
|
1832
|
+
unconfirmedFix: (status) => `Run \`${status}\` later.`,
|
|
1833
|
+
unconfirmed: (status) => `Couldn't confirm this machine's credential with the server. Run \`${status}\` later.`,
|
|
1322
1834
|
};
|
|
1323
1835
|
/** `TODOS[184]`-style one-sentence facts the retire step prints; every one is true whatever the server did. */
|
|
1324
1836
|
export const RETIRE = {
|
|
@@ -1350,6 +1862,12 @@ export const REPLACE = {
|
|
|
1350
1862
|
questionUnconfirmed: "Upload this machine's transcripts to the workspace you signed in to?",
|
|
1351
1863
|
replacesValue: (org) => `credential for ${org}`,
|
|
1352
1864
|
question: (org) => `Upload this machine's transcripts to ${org}?`,
|
|
1865
|
+
/**
|
|
1866
|
+
* 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
|
|
1867
|
+
* questions in a run. The workspace is cut to 28 columns (not `question`'s 30) so the line stays within 80 with `[y/N]`.
|
|
1868
|
+
*/
|
|
1869
|
+
questionRepos: (org) => `Upload transcripts from the repos above to ${org}?`,
|
|
1870
|
+
questionReposUnconfirmed: "Upload transcripts from the repos above to your signed-in workspace?",
|
|
1353
1871
|
declined: "Nothing was saved. The approval is discarded.",
|
|
1354
1872
|
/** Ctrl+C at the question (the prompt was aborted): the same outcome as N, said as what it was. */
|
|
1355
1873
|
cancelled: "Cancelled. Nothing was saved.",
|
|
@@ -1444,13 +1962,19 @@ export const UPDATE = {
|
|
|
1444
1962
|
plugin: (latest) => `capture ${latest} is available: update the VibeCommit plugin in Claude Code.`,
|
|
1445
1963
|
};
|
|
1446
1964
|
export const ERRORS = {
|
|
1447
|
-
notConnected: "This repository is not connected.
|
|
1965
|
+
notConnected: "This repository is not connected.",
|
|
1966
|
+
/** PR 7 (Q7): the remedy was a sentence inside the `what` line; it is a command now, so it moves to the fix block. */
|
|
1967
|
+
notConnectedFix: "Connect it:",
|
|
1448
1968
|
networkLater: "Could not reach VibeCommit. This session will be recorded on the next turn.",
|
|
1449
1969
|
// `11A`. The `what` of the §13.6 rejected-credential block (`REJECTED`), not a second sentence: the
|
|
1450
1970
|
// old line sent users to `connect`, which printed "Connected" over the same dead credential (G1).
|
|
1451
1971
|
authFatal: "This machine's credential is no longer accepted.",
|
|
1452
1972
|
payloadNever: "This session was too large to record and has been skipped.",
|
|
1453
1973
|
notAGitRepo: "Not a git repository.",
|
|
1974
|
+
/** PR 7 (VQ): names the folder, tilde-shortened and cut from the LEFT by the caller (`truncatePath`, §13.4). */
|
|
1975
|
+
notAGitRepoWhy: (folder) => `${folder} is not inside a git work tree.`,
|
|
1976
|
+
/** A fix with no command to give: the remedy is where to run it, so the block has a label and no commands. */
|
|
1977
|
+
notAGitRepoFix: "Run it again inside a git repository.",
|
|
1454
1978
|
};
|
|
1455
1979
|
/**
|
|
1456
1980
|
* The interactive top-level catch (CR-022).
|
|
@@ -1470,7 +1994,8 @@ export const INTERNAL = {
|
|
|
1470
1994
|
unexpectedWhat: "VibeCommit stopped on an unexpected error.",
|
|
1471
1995
|
unexpectedWhy: "The command did not finish.",
|
|
1472
1996
|
unexpectedFix: "Run it again with the error detail shown:",
|
|
1473
|
-
|
|
1997
|
+
// The command is this install's own (PR 7): `node <path> <command>` on a plugin-only machine, which has no `vibecommit`.
|
|
1998
|
+
unexpectedDebugCommand: (command) => `VIBECOMMIT_DEBUG=1 ${command} <command>`,
|
|
1474
1999
|
};
|
|
1475
2000
|
/**
|
|
1476
2001
|
* Credential-loading failures (CR-016).
|
|
@@ -1498,6 +2023,10 @@ export const CREDENTIAL = {
|
|
|
1498
2023
|
insecureFileModeLabel: "mode",
|
|
1499
2024
|
insecureFileWhy: "It was not read. A credential file must be readable only by its owner.",
|
|
1500
2025
|
insecureFileFix: "Restore the mode, then reconnect:",
|
|
2026
|
+
/** The FOLDER (`~/.vibecommit`) is open to other accounts, not the file: same code, its own what, why and `chmod`. */
|
|
2027
|
+
insecureDirWhat: "The folder that holds the credential file is open to other accounts on this machine.",
|
|
2028
|
+
insecureDirWhyLabel: "folder",
|
|
2029
|
+
insecureDirWhy: "The credential was not read. This folder must be accessible only to its owner.",
|
|
1501
2030
|
unreadableWhat: "The credential file could not be read.",
|
|
1502
2031
|
unreadableWhy: "It exists but does not contain a credential in the expected form.",
|
|
1503
2032
|
/** `CR-216/U4`. Was "Replace it by reconnecting:" — see `wrongClassFix` above. */
|
|
@@ -1531,15 +2060,26 @@ export const AUTH = {
|
|
|
1531
2060
|
nextCommand: "vibecommit connect",
|
|
1532
2061
|
emptyWhat: "No credential was given.",
|
|
1533
2062
|
emptyWhy: "Nothing was read, so nothing was written.",
|
|
1534
|
-
|
|
2063
|
+
/**
|
|
2064
|
+
* 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
|
|
2065
|
+
* non-interactive path was named nowhere. The URL comes FIRST (inside the label, where it cannot be wrapped away from
|
|
2066
|
+
* its sentence) and the commands LAST, so the fix stays last (§13.6). A function because `URLS` is declared below.
|
|
2067
|
+
*/
|
|
2068
|
+
mintFix: (url) => `Mint one at ${url}, then run either:`,
|
|
2069
|
+
/**
|
|
2070
|
+
* The two ways to hand it over: piped (a script or an agent), or typed at a terminal. `--stdin` never continues into `connect`
|
|
2071
|
+
* (D32 guard 1). `auth` is `authCommandFor(env, selfPath)`: a plugin-only machine has no `vibecommit` on PATH, so the line names
|
|
2072
|
+
* `node <path> auth` there (README, "Keeping a machine connected"), and handing it `vibecommit auth` would be a new wrong output.
|
|
2073
|
+
*/
|
|
2074
|
+
mintCommands: (auth) => [`printf %s "$TOKEN" | ${auth} --stdin`, auth],
|
|
1535
2075
|
wrongClassWhat: "That is not a VibeCommit ingest credential.",
|
|
1536
2076
|
wrongClassWhy: `An ingest credential begins ${INGEST_TOKEN_PREFIX}. Nothing was written and nothing was sent.`,
|
|
1537
|
-
wrongClassFix: "Mint one, then run:",
|
|
1538
2077
|
argvWhat: "A credential must not be passed as an argument.",
|
|
1539
2078
|
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.",
|
|
1540
2079
|
argvFix: "Read it from the terminal, or from a pipe:",
|
|
1541
2080
|
argvFixPrompt: "vibecommit auth",
|
|
1542
|
-
|
|
2081
|
+
/** A pipe, so `channelCommand` cannot rewrite it: it takes the channel's `auth` (`authCommandFor`) instead. */
|
|
2082
|
+
argvFixStdin: (auth) => `printf %s "$TOKEN" | ${auth} --stdin`,
|
|
1543
2083
|
// --- `CR-226`: the browser mint, and the paste it falls back to. ---
|
|
1544
2084
|
/**
|
|
1545
2085
|
* Printed before the request, naming the label the credential will carry in
|
|
@@ -1630,6 +2170,18 @@ export const SYSTEM_MESSAGE = {
|
|
|
1630
2170
|
* users and its hash chain detects post-write tampering").
|
|
1631
2171
|
*/
|
|
1632
2172
|
captureConfirmed: (dashboardUrl) => `VibeCommit captured this session. ${dashboardUrl}`,
|
|
2173
|
+
/**
|
|
2174
|
+
* States 6-9 — style guide §10.1 (0.7.0, design review D16 · 10A), all emitted by the `SessionStart` hook. One
|
|
2175
|
+
* plain-text line each, ≤120 characters, no SGR. The wording is the design doc's and the merged style guide's,
|
|
2176
|
+
* byte for byte; `test/session-start.test.ts` pins the length of every one.
|
|
2177
|
+
*
|
|
2178
|
+
* 6 — hooks added, once per clone. 7 — `core.hooksPath` is set, once per clone. 8 — the clone has its own
|
|
2179
|
+
* commit hook, once per clone. 9 — `grants.json` is unreadable, once per (machine, day).
|
|
2180
|
+
*/
|
|
2181
|
+
hooksAdded: "VibeCommit added its post-commit and post-rewrite hooks to this clone, so commits can link to sessions.",
|
|
2182
|
+
hooksPathSet: "VibeCommit captures sessions here, not commits: core.hooksPath is set. Run `vibecommit status` here for the fix.",
|
|
2183
|
+
ownCommitHook: "VibeCommit didn't add its commit hook here: this clone has its own. Run `vibecommit connect` here to chain it.",
|
|
2184
|
+
grantsUnreadable: "VibeCommit capture stopped on this machine: ~/.vibecommit/grants.json can't be read. Run `vibecommit status`.",
|
|
1633
2185
|
};
|
|
1634
2186
|
/**
|
|
1635
2187
|
* The out-of-tree redaction marker — `CR-024d`, D57 §OV8d.
|
|
@@ -1660,6 +2212,10 @@ export const REDACTION = {
|
|
|
1660
2212
|
/** Commands the copy points at. One definition, so a rename cannot half-land. */
|
|
1661
2213
|
export const COMMANDS = {
|
|
1662
2214
|
connect: "vibecommit connect",
|
|
2215
|
+
/** `D33 · 27A`. */
|
|
2216
|
+
scan: "vibecommit scan",
|
|
2217
|
+
/** `D14`/`D15`. */
|
|
2218
|
+
backfill: "vibecommit backfill",
|
|
1663
2219
|
/**
|
|
1664
2220
|
* `CR-216/U2`. The only verb a credential FAULT's fix line may name — it can
|
|
1665
2221
|
* replace the credential from any state. `CR-226` lets `connect` mint one
|
|
@@ -1680,6 +2236,10 @@ export const COMMANDS = {
|
|
|
1680
2236
|
/** The ref form, for the detached-HEAD refusal. */
|
|
1681
2237
|
reportRef: "vibecommit report --since 2026-07-08 --ref main",
|
|
1682
2238
|
off: "vibecommit off",
|
|
2239
|
+
/** The picker's screen-reader flag: a FLAG on `connect`, like `signIn`. */
|
|
2240
|
+
connectTyped: "vibecommit connect --typed",
|
|
2241
|
+
/** The git hook's own verb. `hooksPathFixManual` tells a user to add it to a hook they keep. */
|
|
2242
|
+
postCommit: "vibecommit post-commit",
|
|
1683
2243
|
/**
|
|
1684
2244
|
* `CR-086`. The ARGUMENT SHAPE, shown once so the usage error and the retry
|
|
1685
2245
|
* fix line cannot drift apart. There is no argument parser in this package —
|
|
@@ -1690,6 +2250,8 @@ export const COMMANDS = {
|
|
|
1690
2250
|
*/
|
|
1691
2251
|
why: "vibecommit why src/auth/session.ts:47",
|
|
1692
2252
|
chmodCredentials: "chmod 600 ~/.vibecommit/credentials.json",
|
|
2253
|
+
/** The folder's remedy, for `CREDENTIAL_FILE_INSECURE` when the folder is the one with the wrong mode. */
|
|
2254
|
+
chmodDirectory: "chmod 700 ~/.vibecommit",
|
|
1693
2255
|
/**
|
|
1694
2256
|
* ⛔ THE INSTALL COMMAND, TRANSCRIBED FROM `claude-plugin/README.md:12` — and
|
|
1695
2257
|
* it is deliberately NOT an invented update verb (`U1`, 2026-08-30).
|
|
@@ -1707,6 +2269,8 @@ export const COMMANDS = {
|
|
|
1707
2269
|
* together — the wording and the command are one unit.
|
|
1708
2270
|
*/
|
|
1709
2271
|
pluginInstall: "/plugin install vibecommit@vibecommit-capture",
|
|
2272
|
+
/** The npm channel's way to a newer client: the package's own documented install, at `latest`. */
|
|
2273
|
+
npmUpdate: "npm install -g @vibe-commit/capture@latest",
|
|
1710
2274
|
};
|
|
1711
2275
|
/**
|
|
1712
2276
|
* Every URL the CLI prints. Here rather than inline for the same reason as the
|
|
@@ -1730,6 +2294,8 @@ export const URLS = {
|
|
|
1730
2294
|
* deepening this constant is that task's, not a later guess.
|
|
1731
2295
|
*/
|
|
1732
2296
|
commits: "https://vibecommit.ai/app/commits",
|
|
2297
|
+
/** `/app/conversations`: where an uploaded backfill lands (D19). `/app` (`dashboard`) is the ending after a no. */
|
|
2298
|
+
conversations: "https://vibecommit.ai/app/conversations",
|
|
1733
2299
|
/**
|
|
1734
2300
|
* One recorded session — the ending's link when the ingest 2xx carried a `conversation_id` (`DX D8`).
|
|
1735
2301
|
* Verified by file: `vibecommit-web` `app/app/conversations/[id]/page.tsx` exists on `main`, and an
|