@vibe-commit/capture 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +66 -0
- package/dist/agents/claude_code.d.ts +11 -0
- package/dist/agents/claude_code.js +162 -0
- package/dist/agents/claude_code.js.map +1 -0
- package/dist/agents/codex_cli.d.ts +15 -0
- package/dist/agents/codex_cli.js +67 -0
- package/dist/agents/codex_cli.js.map +1 -0
- package/dist/agents/cursor.d.ts +21 -0
- package/dist/agents/cursor.js +89 -0
- package/dist/agents/cursor.js.map +1 -0
- package/dist/agents/registry.d.ts +184 -0
- package/dist/agents/registry.js +212 -0
- package/dist/agents/registry.js.map +1 -0
- package/dist/agents/types.d.ts +279 -0
- package/dist/agents/types.js +67 -0
- package/dist/agents/types.js.map +1 -0
- package/dist/commands/connect.d.ts +36 -0
- package/dist/commands/connect.js +499 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/context.d.ts +45 -0
- package/dist/commands/context.js +14 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/report.d.ts +105 -0
- package/dist/commands/report.js +430 -0
- package/dist/commands/report.js.map +1 -0
- package/dist/commands/status.d.ts +29 -0
- package/dist/commands/status.js +236 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/why.d.ts +349 -0
- package/dist/commands/why.js +937 -0
- package/dist/commands/why.js.map +1 -0
- package/dist/consent.d.ts +59 -0
- package/dist/consent.js +111 -0
- package/dist/consent.js.map +1 -0
- package/dist/copy/claims.d.ts +79 -0
- package/dist/copy/claims.js +343 -0
- package/dist/copy/claims.js.map +1 -0
- package/dist/copy/grades.d.ts +117 -0
- package/dist/copy/grades.js +96 -0
- package/dist/copy/grades.js.map +1 -0
- package/dist/copy/index.d.ts +12 -0
- package/dist/copy/index.js +13 -0
- package/dist/copy/index.js.map +1 -0
- package/dist/copy/strings.d.ts +1328 -0
- package/dist/copy/strings.js +1243 -0
- package/dist/copy/strings.js.map +1 -0
- package/dist/copy/time.d.ts +27 -0
- package/dist/copy/time.js +43 -0
- package/dist/copy/time.js.map +1 -0
- package/dist/credential.d.ts +211 -0
- package/dist/credential.js +298 -0
- package/dist/credential.js.map +1 -0
- package/dist/exit.d.ts +59 -0
- package/dist/exit.js +60 -0
- package/dist/exit.js.map +1 -0
- package/dist/git.d.ts +299 -0
- package/dist/git.js +653 -0
- package/dist/git.js.map +1 -0
- package/dist/hooks/entry.d.ts +277 -0
- package/dist/hooks/entry.js +1092 -0
- package/dist/hooks/entry.js.map +1 -0
- package/dist/hooks/post_commit.d.ts +59 -0
- package/dist/hooks/post_commit.js +160 -0
- package/dist/hooks/post_commit.js.map +1 -0
- package/dist/hooks/post_rewrite.d.ts +59 -0
- package/dist/hooks/post_rewrite.js +161 -0
- package/dist/hooks/post_rewrite.js.map +1 -0
- package/dist/hooks/session_end.d.ts +101 -0
- package/dist/hooks/session_end.js +120 -0
- package/dist/hooks/session_end.js.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +360 -0
- package/dist/index.js.map +1 -0
- package/dist/install.d.ts +153 -0
- package/dist/install.js +284 -0
- package/dist/install.js.map +1 -0
- package/dist/json.d.ts +100 -0
- package/dist/json.js +94 -0
- package/dist/json.js.map +1 -0
- package/dist/oauth/discovery.d.ts +96 -0
- package/dist/oauth/discovery.js +163 -0
- package/dist/oauth/discovery.js.map +1 -0
- package/dist/oauth/lock.d.ts +100 -0
- package/dist/oauth/lock.js +287 -0
- package/dist/oauth/lock.js.map +1 -0
- package/dist/oauth/loopback.d.ts +85 -0
- package/dist/oauth/loopback.js +124 -0
- package/dist/oauth/loopback.js.map +1 -0
- package/dist/oauth/pkce.d.ts +58 -0
- package/dist/oauth/pkce.js +77 -0
- package/dist/oauth/pkce.js.map +1 -0
- package/dist/oauth/read.d.ts +120 -0
- package/dist/oauth/read.js +144 -0
- package/dist/oauth/read.js.map +1 -0
- package/dist/oauth/session.d.ts +80 -0
- package/dist/oauth/session.js +112 -0
- package/dist/oauth/session.js.map +1 -0
- package/dist/oauth/signin.d.ts +178 -0
- package/dist/oauth/signin.js +225 -0
- package/dist/oauth/signin.js.map +1 -0
- package/dist/oauth/token.d.ts +139 -0
- package/dist/oauth/token.js +183 -0
- package/dist/oauth/token.js.map +1 -0
- package/dist/paths.d.ts +366 -0
- package/dist/paths.js +460 -0
- package/dist/paths.js.map +1 -0
- package/dist/policy.d.ts +195 -0
- package/dist/policy.js +244 -0
- package/dist/policy.js.map +1 -0
- package/dist/post.d.ts +302 -0
- package/dist/post.js +384 -0
- package/dist/post.js.map +1 -0
- package/dist/project.d.ts +99 -0
- package/dist/project.js +192 -0
- package/dist/project.js.map +1 -0
- package/dist/redact.d.ts +175 -0
- package/dist/redact.js +700 -0
- package/dist/redact.js.map +1 -0
- package/dist/runtime.d.ts +30 -0
- package/dist/runtime.js +37 -0
- package/dist/runtime.js.map +1 -0
- package/dist/spawn_budget.d.ts +101 -0
- package/dist/spawn_budget.js +124 -0
- package/dist/spawn_budget.js.map +1 -0
- package/dist/spool.d.ts +390 -0
- package/dist/spool.js +556 -0
- package/dist/spool.js.map +1 -0
- package/dist/state.d.ts +109 -0
- package/dist/state.js +217 -0
- package/dist/state.js.map +1 -0
- package/dist/system_message.d.ts +101 -0
- package/dist/system_message.js +141 -0
- package/dist/system_message.js.map +1 -0
- package/dist/term.d.ts +112 -0
- package/dist/term.js +134 -0
- package/dist/term.js.map +1 -0
- package/dist/version.d.ts +16 -0
- package/dist/version.js +17 -0
- package/dist/version.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,1328 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The copy catalogue — CR-090 precondition (1).
|
|
3
|
+
*
|
|
4
|
+
* EVERY user-facing string in this package lives here. Command bodies contain
|
|
5
|
+
* NO inline string literals. This is not a style preference: the claims gate can
|
|
6
|
+
* only check copy it can find, and a literal inside a command body is invisible
|
|
7
|
+
* to it. The capture client is greenfield exactly once, so this constraint is
|
|
8
|
+
* free now and a refactor later.
|
|
9
|
+
*
|
|
10
|
+
* Commit headers are NOT here — they come from `grades.ts`, which is the single
|
|
11
|
+
* renderer that takes the grade. Adding a header string to this file would
|
|
12
|
+
* create the second path that the structural adjacency rule exists to forbid.
|
|
13
|
+
*
|
|
14
|
+
* @provenance vibecommit-mcp src/scrubber/index.ts — [REDACTED:<kind>] marker shape, borrowed
|
|
15
|
+
* @provenance vibecommit-web app/app/commits/page.tsx — route existence, verified
|
|
16
|
+
* @provenance vibecommit-schema capture_turns column list — MEASURED ABSENCE, cited (CR-086)
|
|
17
|
+
*/
|
|
18
|
+
import { EXIT } from "../exit.js";
|
|
19
|
+
/** `--help` copy. The `why` line is verbatim-approved (D61 §PS6) — do not reword. */
|
|
20
|
+
export declare const HELP: {
|
|
21
|
+
readonly usage: "vibecommit <command> [options]";
|
|
22
|
+
readonly tagline: "Record Claude Code sessions against the commits they produced.";
|
|
23
|
+
readonly commands: {
|
|
24
|
+
readonly connect: "Connect this repo and capture the current session.";
|
|
25
|
+
readonly status: "Show whether capture is on for this repo and when it last succeeded.";
|
|
26
|
+
readonly off: "Stop capturing for this repo.";
|
|
27
|
+
readonly why: "Show the conversation turns recorded against the commit that last changed this line.";
|
|
28
|
+
readonly report: "Summarise capture coverage over a time window.";
|
|
29
|
+
};
|
|
30
|
+
readonly docsUrl: "https://vibecommit.ai/docs/what-we-upload";
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* The ENTRY POINT's own chrome and its two usage failures — `CR-090d`.
|
|
34
|
+
*
|
|
35
|
+
* These five strings were inline literals in `src/index.ts` (`:74`, `:76`, `:87`,
|
|
36
|
+
* `:146`, `:163`) — user-facing, and invisible to the claims gate for six waves
|
|
37
|
+
* because the gate can only check copy it can find.
|
|
38
|
+
*
|
|
39
|
+
* ## Why a separate object rather than three more fields on `HELP`
|
|
40
|
+
*
|
|
41
|
+
* `HELP` is the help SCREEN's content — the tagline, the usage line, the per-verb
|
|
42
|
+
* descriptions, the docs URL — and the claims corpus tags the whole object with
|
|
43
|
+
* one surface, `help`. Only three of these five render there. `unknownCommand` is
|
|
44
|
+
* the usage-error path, so folding it into `HELP` would tag a §13.6 error
|
|
45
|
+
* message as help copy and check it against the wrong surface.
|
|
46
|
+
*
|
|
47
|
+
* ⚠ `notImplemented` LIVED HERE AND IS GONE, REMOVED BY `CR-108`. It was what
|
|
48
|
+
* `why` and `report` printed while unbuilt, and `report` was its last caller —
|
|
49
|
+
* **every verb in `VERBS` is now implemented**, so the string had no route to a
|
|
50
|
+
* screen. Copy that cannot be reached is copy no gate can check, and leaving it
|
|
51
|
+
* would have invited the next reader to wire a sixth verb to it silently. The surface map is only as
|
|
52
|
+
* honest as the objects it keys on, so the entry point gets its own.
|
|
53
|
+
*
|
|
54
|
+
* ⚠ The three labels are LABELS, not sentences: `renderHelp()` composes each with
|
|
55
|
+
* a single space and the result must stay byte-identical at 80 columns
|
|
56
|
+
* (`DESIGN.md` §13.4, `test/help.golden.txt`). A trailing space moved in here
|
|
57
|
+
* would be invisible in review and would move the golden file.
|
|
58
|
+
*/
|
|
59
|
+
export declare const USAGE: {
|
|
60
|
+
readonly usageLabel: "Usage:";
|
|
61
|
+
readonly commandsLabel: "Commands:";
|
|
62
|
+
readonly docsLabel: "Docs:";
|
|
63
|
+
/** The unknown-verb line. Help follows it, so this says only what went wrong. */
|
|
64
|
+
readonly unknownCommand: (verb: string) => string;
|
|
65
|
+
};
|
|
66
|
+
/** `vibecommit status` (CR-021). */
|
|
67
|
+
export declare const STATUS: {
|
|
68
|
+
readonly onForRepo: "Capture is on for this repository.";
|
|
69
|
+
readonly offForRepo: "Capture is off for this repository.";
|
|
70
|
+
readonly neverSent: "No session has been recorded yet.";
|
|
71
|
+
/**
|
|
72
|
+
* The §13.5 gutter keys. LOWERCASE because style guide §10.3 draws them that
|
|
73
|
+
* way, and §10.3 is the ruling (D65) — `lastSuccessLabel` and
|
|
74
|
+
* `dashboardLabel` were title-case and referenced by nothing, so `CR-021`
|
|
75
|
+
* changed them to match the screen rather than changing the screen.
|
|
76
|
+
*/
|
|
77
|
+
readonly repoLabel: "repo";
|
|
78
|
+
readonly lastSuccessLabel: "last sent";
|
|
79
|
+
readonly dashboardLabel: "dashboard";
|
|
80
|
+
/** `<slug> (git toplevel <path>)` — §10.3's repo row. */
|
|
81
|
+
readonly repoToplevel: (slug: string, path: string) => string;
|
|
82
|
+
/** `4 minutes ago · seq 41`. No turn count — see the module note in status.ts. */
|
|
83
|
+
readonly lastSuccessValue: (age: string, seq: number) => string;
|
|
84
|
+
readonly fixCommandLabel: "To reconnect, run";
|
|
85
|
+
/** §10.3's two trailing actions, rendered as an aligned pair. */
|
|
86
|
+
readonly turnOffLabel: "Turn capture off for this repo";
|
|
87
|
+
readonly revokeLabel: "Revoke this machine's credential";
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* `vibecommit connect` (CR-025 owns the live-capture ending).
|
|
91
|
+
*
|
|
92
|
+
* ⚠ THE DISCLOSURE PARAGRAPHS ARE NOW HERE — `CR-111d` landed them, transcribed
|
|
93
|
+
* from style guide §10.2 rather than paraphrased. They replaced three
|
|
94
|
+
* placeholder one-liners. D64 falsified the trust argument the earlier draft
|
|
95
|
+
* leaned on: this repo is PRIVATE with MIT intact, so "read the source" is false
|
|
96
|
+
* and BLOCKED by the register. What survives is `Vibe-Commit/claude-plugin`,
|
|
97
|
+
* which vendors the exact binary — and "inspect the build" is WEAKER than "read
|
|
98
|
+
* the source" and may not be dressed up as it (D65 §DR7).
|
|
99
|
+
*
|
|
100
|
+
* The MECHANISM copy sits beside them and belongs to other rows: the prompt, the
|
|
101
|
+
* two answers, the refusals, `CR-025`'s ending and `CR-110`'s fifth beat.
|
|
102
|
+
*
|
|
103
|
+
* Also locked and enforced by the mechanism, not by these strings: default `N`,
|
|
104
|
+
* non-TTY refuses with exit 2, and no reassurance adjectives (*secure, safe,
|
|
105
|
+
* protected, private, encrypted*) anywhere on the screen (D65 §DR7).
|
|
106
|
+
*/
|
|
107
|
+
export declare const CONNECT: {
|
|
108
|
+
/**
|
|
109
|
+
* ⚠ NOT PARAPHRASED. §10.2's rule 4 — *every noun names something actually
|
|
110
|
+
* uploaded, in the USER's vocabulary* — is the one rule no gate can check, so
|
|
111
|
+
* the nouns are transcribed rather than reworded: *"the output of commands it
|
|
112
|
+
* ran"*, never *"Bash tool results"*.
|
|
113
|
+
*/
|
|
114
|
+
readonly consentHeading: "VibeCommit uploads your Claude Code transcripts for this repo.";
|
|
115
|
+
/**
|
|
116
|
+
* ⚠ "private-repo paths" IS THE APPROVED WORDING, and it is the reason
|
|
117
|
+
* `private` is deliberately NOT registered in `claims.ts`: a substring gate on
|
|
118
|
+
* it would fire on this very sentence on day one, and the register's own
|
|
119
|
+
* §Lintable-unit section says a gate dies at its third false positive. So
|
|
120
|
+
* `private`-as-reassurance is a HUMAN review item here. This use is
|
|
121
|
+
* descriptive — it names what the paths ARE — and is the opposite of a
|
|
122
|
+
* reassurance.
|
|
123
|
+
*/
|
|
124
|
+
readonly consentDetail: "That means the full text of the session: your prompts, the agent's replies, the arguments to every tool call, the file contents inside Edit records, and the output of commands it ran. File paths include private-repo paths.";
|
|
125
|
+
/**
|
|
126
|
+
* ⚠ THE NUMBER AND ITS QUALIFIER ARE ONE UNIT.
|
|
127
|
+
*
|
|
128
|
+
* **12 is `CR-042`'s counted figure** (merged, `6d8ec68`), taken rather than
|
|
129
|
+
* recounted: the patterns live in `vibecommit-mcp/src/scrubber/patterns.ts`,
|
|
130
|
+
* which is closed source and another chain's repo. `CR-042` exists precisely
|
|
131
|
+
* because the draft said 10 — a number is a claim, and this one is counted
|
|
132
|
+
* from code.
|
|
133
|
+
*
|
|
134
|
+
* The qualifier is as load-bearing as the number. Without *"it is a pattern
|
|
135
|
+
* list, not a general secret detector"* and *"a secret it has no pattern for
|
|
136
|
+
* is uploaded"*, the count reads as PROTECTION — which is the reassurance D65
|
|
137
|
+
* §DR7 bans, arriving as arithmetic instead of as an adjective.
|
|
138
|
+
*/
|
|
139
|
+
readonly consentScrubber: "A scrubber removes 12 known secret formats (AWS keys, GitHub tokens, and similar). It is a pattern list, not a general secret detector: a secret it has no pattern for is uploaded. Command output is not path-filtered.";
|
|
140
|
+
/**
|
|
141
|
+
* ⛔ **THE SECOND DATA CLASS, AND THE DISCLOSURE DID NOT MENTION IT AT ALL —
|
|
142
|
+
* `T15`, `D190`.**
|
|
143
|
+
*
|
|
144
|
+
* The three paragraphs above enumerate TRANSCRIPT CONTENT. They were the whole
|
|
145
|
+
* disclosure, and commit SHAs have gone on the wire since `CR-170` without a
|
|
146
|
+
* word here. `D190` adds two more headers, one of which is a genuinely new
|
|
147
|
+
* class, so the copy is extended rather than the send being scoped — scoping
|
|
148
|
+
* the send would gut the feature.
|
|
149
|
+
*
|
|
150
|
+
* ## ⛔ WHAT IS HERE IS MEASURED FROM `buildIngestHeaders`, NOT FROM THE PLAN
|
|
151
|
+
*
|
|
152
|
+
* | said here | header | since |
|
|
153
|
+
* |---|---|---|
|
|
154
|
+
* | the commit ID | `x-commits` | `CR-170` |
|
|
155
|
+
* | the branch name | `x-head-branch` | `CR-170` |
|
|
156
|
+
* | the session it was linked to | `x-session-id` | pre-`CR-170` |
|
|
157
|
+
* | how that link was made | `x-commit-attributions` | `D190`, NEW |
|
|
158
|
+
* | the replaced commit's ID | `x-rewrites` | `D190`, NEW |
|
|
159
|
+
*
|
|
160
|
+
* ⛔ **AND WHAT IS DELIBERATELY NOT HERE, BECAUSE IT DOES NOT LEAVE THE
|
|
161
|
+
* MACHINE.** `post_commit.ts` gathers the changed-file list and the committer
|
|
162
|
+
* date because they are free at that moment, and `capSpool` returns only
|
|
163
|
+
* `{shas, attributions, count}`. **Describing them as uploaded would be a FALSE
|
|
164
|
+
* DISCLOSURE, which is as much a claims defect as a missing one** — and it is
|
|
165
|
+
* the easier mistake, because over-disclosing feels safe.
|
|
166
|
+
*
|
|
167
|
+
* ⚠ **`SpoolEntry.branch` and `delta.head.branch` are NOT the same noun.** The
|
|
168
|
+
* per-commit one stays local; the repo's CURRENT branch goes out on every
|
|
169
|
+
* delta as `x-head-branch` (`post.ts:228`, `entry.ts:612`). The branch name is
|
|
170
|
+
* named here on the strength of the second, never the first.
|
|
171
|
+
*
|
|
172
|
+
* ## ⛔ THE REWRITE SENTENCE IS THE ONE THIS STRING EXISTS FOR
|
|
173
|
+
*
|
|
174
|
+
* `x-rewrites` carries LOCAL, UNPUSHED REWRITE HISTORY — `ancestor:successor`
|
|
175
|
+
* pairs whose ancestor is unreachable from every branch and gone after
|
|
176
|
+
* `gc --prune=now`. Telling a user "we upload your transcripts" does not cover
|
|
177
|
+
* "we upload a record of the commits you rewrote before pushing". **Someone who
|
|
178
|
+
* squashes to bury a false start is entitled to know that the false start's ID
|
|
179
|
+
* left the machine.**
|
|
180
|
+
*
|
|
181
|
+
* ⚠ *"may never have left this machine"*, not *"was never pushed"*: you can
|
|
182
|
+
* amend a commit that WAS pushed and force-push it, so the stronger sentence is
|
|
183
|
+
* false in a real case.
|
|
184
|
+
*
|
|
185
|
+
* ## ⛔ NO NEGATIVE LIST, AND THAT IS A DECISION
|
|
186
|
+
*
|
|
187
|
+
* An earlier draft closed with *"commit messages, authors, dates and the
|
|
188
|
+
* changed-file list are not uploaded."* True today (`post.ts:166-174`), and
|
|
189
|
+
* CUT: `D190 §6` says this wire has **no compiler, no schema and no shared
|
|
190
|
+
* type**, so a negative claim in shipping copy goes false the first time anyone
|
|
191
|
+
* adds a header — silently, with no gate able to see it. Positive claims only.
|
|
192
|
+
*
|
|
193
|
+
* ⚠ Opens *"Not only the transcript"* because `consentHeading` still says
|
|
194
|
+
* *"uploads your Claude Code transcripts"*, which is now narrower than the
|
|
195
|
+
* truth. Repairing the scope where a skimmer meets it; the heading itself is a
|
|
196
|
+
* bigger copy change than this task was scoped for.
|
|
197
|
+
*/
|
|
198
|
+
readonly consentCommits: "Not only the transcript. Commits you make while a session is recording are uploaded too: the commit ID, the branch name, the session it was linked to, and how that link was made. If you amend or rebase, the ID of the commit you replaced goes with them — that commit may never have left this machine, and git will eventually delete it from here.";
|
|
199
|
+
/** §10.2's first labelled link. Points at `HELP.docsUrl` — one definition. */
|
|
200
|
+
readonly consentDocsLabel: "Read the full list:";
|
|
201
|
+
/**
|
|
202
|
+
* ⚠ THE REPLACEMENT FOR THE OPEN-SOURCE CLAIM, and the ceiling on what it may
|
|
203
|
+
* say. D64 created this repo PRIVATE with MIT intact, so *"read the source"*
|
|
204
|
+
* is FALSE — the register's own signed-receipts failure mode, copy describing
|
|
205
|
+
* a mechanism that does not exist. What survives is `claude-plugin`, which D20
|
|
206
|
+
* keeps public non-negotiably and which vendors the exact binary that runs.
|
|
207
|
+
*
|
|
208
|
+
* **"Inspect the build" is WEAKER than "read the source" and may not be
|
|
209
|
+
* dressed up as it** (D65 §DR7). This line offers the artefact and claims
|
|
210
|
+
* nothing about readable source. All four phrasings are registered BLOCKED on
|
|
211
|
+
* the `connect` surface, so the gate refuses the smuggled version too.
|
|
212
|
+
*/
|
|
213
|
+
readonly consentBundleLabel: "The binary that runs is here:";
|
|
214
|
+
readonly consentPrompt: "Continue?";
|
|
215
|
+
readonly declined: "Not connected. Nothing was uploaded.";
|
|
216
|
+
readonly capturing: "Recording this session…";
|
|
217
|
+
readonly doneHeading: "Connected.";
|
|
218
|
+
readonly doneUrlLabel: "View this session";
|
|
219
|
+
/** The `[y/N]` suffix. The capital is the default and the default is NO. */
|
|
220
|
+
readonly consentAnswers: "[y/N]";
|
|
221
|
+
/** Non-TTY refusal — DESIGN.md §13.7 exit 2, D65 §DR7. */
|
|
222
|
+
readonly nonInteractiveWhat: "Consent needs an interactive terminal.";
|
|
223
|
+
readonly nonInteractiveWhy: "Standard input is not a terminal, so the consent prompt cannot be answered. Nothing was read and nothing was uploaded.";
|
|
224
|
+
readonly nonInteractiveFix: "Run this in a terminal:";
|
|
225
|
+
readonly alreadyConnected: "Capture is already on for this repository.";
|
|
226
|
+
/**
|
|
227
|
+
* The browser sign-in beat (PKCE loopback → minted ingest credential) is the
|
|
228
|
+
* oauth lane's, not this task's. Until it lands, the supported path is the one
|
|
229
|
+
* `VIBECOMMIT_TOKEN` exists for. This copy states a mechanism, not a promise.
|
|
230
|
+
*/
|
|
231
|
+
readonly credentialNeededWhat: "This machine has no ingest credential.";
|
|
232
|
+
readonly credentialNeededWhy: "Consent is recorded for this repository, but nothing can be uploaded without a credential for this machine.";
|
|
233
|
+
readonly credentialNeededFix: "Set one, then run connect again:";
|
|
234
|
+
readonly credentialNeededCommand: "export VIBECOMMIT_TOKEN=…";
|
|
235
|
+
/** `Capture is on for <repo>. Nothing else to do.` */
|
|
236
|
+
readonly doneForRepo: (repo: string) => string;
|
|
237
|
+
readonly stopLabel: "To stop";
|
|
238
|
+
/**
|
|
239
|
+
* No transcript to record. ONE state — `CR-112` (W8) owns the five-absence
|
|
240
|
+
* grammar as a set, and a sixth phrasing invented here is what that task
|
|
241
|
+
* exists to prevent.
|
|
242
|
+
*/
|
|
243
|
+
readonly noTranscriptWhat: "No Claude Code session was found for this repository.";
|
|
244
|
+
readonly noTranscriptWhy: "Consent is recorded, but connect had nothing to record: no transcript exists yet for this project. Capture starts on its own the next time Claude Code runs here.";
|
|
245
|
+
readonly noTranscriptFix: "Nothing to fix. Start a session, then check:";
|
|
246
|
+
/**
|
|
247
|
+
* ⚠ `warn`, NEVER `bad`, and **EXIT 0, never 1**. That 403 means *later*, not
|
|
248
|
+
* *failed*: the offset holds and the backlog uploads in order on approval. A
|
|
249
|
+
* red exit tells a correctly-installed user they broke something, which moves
|
|
250
|
+
* the confusion report's T+9:00 give-up to T+0:45. `held` and `armed` are the
|
|
251
|
+
* two words doing the work — both mean *ready, not running*.
|
|
252
|
+
*
|
|
253
|
+
* `capture_policy` defaults to `approval_required`, so a member of a
|
|
254
|
+
* multi-member org sees this every time; solo orgs auto-approve inside the
|
|
255
|
+
* insert and never meet it.
|
|
256
|
+
*/
|
|
257
|
+
readonly pendingWhat: "Your org needs to approve capture first.";
|
|
258
|
+
/**
|
|
259
|
+
* ⚠ NAMES THE REPO, NOT THE ORG — and that is a deviation from the style
|
|
260
|
+
* guide's drawn example, made deliberately. §10.2 renders *"acohan/repo
|
|
261
|
+
* belongs to the `vibecommit` org"*, and the client cannot produce that name:
|
|
262
|
+
* the 403 body discloses nothing (no org id, no owner list, by design), and
|
|
263
|
+
* `resolveRepoSlug` yields the GIT owner, which is a different thing from the
|
|
264
|
+
* VibeCommit org that holds the capture policy. Inventing one would be a
|
|
265
|
+
* confident lie; the link resolves it, which is what the link is for.
|
|
266
|
+
*/
|
|
267
|
+
readonly pendingWhy: (repo: string) => string;
|
|
268
|
+
/**
|
|
269
|
+
* ⚠ THE SHARED CLAUSE, and it renders on EVERY branch. D81: `owners_notified`
|
|
270
|
+
* `null` = NOT DETERMINABLE, `0` = determinable and nobody was told, `> 0` =
|
|
271
|
+
* N notified — and **`> 0` ADDS to this sentence rather than replacing it**.
|
|
272
|
+
* One shared clause is why the two branches cannot drift apart later; a pair
|
|
273
|
+
* of independent paragraphs is how the false version gets reintroduced.
|
|
274
|
+
*
|
|
275
|
+
* It is also TRUE, and checked rather than inherited: the server upserts a
|
|
276
|
+
* `capture_requests` row BEFORE it emits the 403.
|
|
277
|
+
*/
|
|
278
|
+
readonly pendingRecorded: "Your request is recorded.";
|
|
279
|
+
/**
|
|
280
|
+
* ⚠ THE ONLY BRANCH THAT MAY CLAIM A NOTIFICATION, and it is reachable only
|
|
281
|
+
* when the server says `> 0`. Today it never does — the field is hardcoded
|
|
282
|
+
* `null` until `CR-036`, which is provisioning-blocked — so this sentence is
|
|
283
|
+
* built and unreachable ON PURPOSE. **Never render it on the null branch.**
|
|
284
|
+
* D81: a hardcoded *"we notified the owners"* installs the most damaging
|
|
285
|
+
* possible mental model at the moment of highest trust — *the owner knows, so
|
|
286
|
+
* I just wait* — so the pending state would suppress its own workaround. A
|
|
287
|
+
* user told nothing at least asks in Slack.
|
|
288
|
+
*
|
|
289
|
+
* The branch is PERMANENT, not a stopgap: addresses bounce, domains land on
|
|
290
|
+
* suppression lists, and a sole owner's address can be dead. `CR-036` landing
|
|
291
|
+
* does not delete the other branch; it only makes this one reachable.
|
|
292
|
+
*/
|
|
293
|
+
readonly pendingNotified: (owners: number) => string;
|
|
294
|
+
/** True by construction: 403 is `later`, so the offset holds and bytes stay on disk. */
|
|
295
|
+
readonly pendingBuffered: "Nothing is lost while you wait — turns are buffered on this machine and upload in order once an owner approves.";
|
|
296
|
+
readonly pendingTrackLabel: "Track it:";
|
|
297
|
+
/** `armed` = ready, not running. The install is correct; capture is waiting. */
|
|
298
|
+
readonly pendingArmed: (repo: string) => string;
|
|
299
|
+
};
|
|
300
|
+
/**
|
|
301
|
+
* The PATH clash — `CR-025`, and `DESIGN.md` §13.6's worked example is the spec.
|
|
302
|
+
*
|
|
303
|
+
* D55 accepted a residual bin collision as unlikely; the register corrects that
|
|
304
|
+
* to *closer to certain*, because the squatting package (`vibecommit@1.0.6`) is
|
|
305
|
+
* itself a commit CLI, so the overlap population is exactly developers who
|
|
306
|
+
* install commit tooling. **This detects the collision D55 accepted. It does not
|
|
307
|
+
* reopen the naming decision** — the bin name stays.
|
|
308
|
+
*
|
|
309
|
+
* ⚠ The plugin path in the fix line depends on `CR-027e` (renames the plugin
|
|
310
|
+
* directory to `vibecommit`) and `CR-028` (creates `bin/` at all), both W6, both
|
|
311
|
+
* in `claude-plugin`, both another builder's. Written as §13.6 draws it rather
|
|
312
|
+
* than softened to dodge the dependency.
|
|
313
|
+
*/
|
|
314
|
+
/**
|
|
315
|
+
* The `post-commit` install report — `CR-170`, D154.
|
|
316
|
+
*
|
|
317
|
+
* ⛔ **EVERY OUTCOME SAYS SOMETHING, INCLUDING THE GOOD ONE.** Three of this
|
|
318
|
+
* path's failure modes are silent no-ops (D98's class): `core.hooksPath` makes
|
|
319
|
+
* `.git/hooks` dead, an existing hook must not be clobbered, and neither is
|
|
320
|
+
* visible without a line of output. A user who is told nothing cannot tell a
|
|
321
|
+
* working install from one that observes no commits for the life of the clone.
|
|
322
|
+
*
|
|
323
|
+
* ⚠ **AND IT SAYS "THIS CLONE", EVERY TIME.** Per-clone installation is the real
|
|
324
|
+
* cost of this design and the one thing a user will be surprised by later, so it
|
|
325
|
+
* is stated at the moment they can act on it rather than buried in documentation.
|
|
326
|
+
*/
|
|
327
|
+
export declare const COMMIT_HOOK: {
|
|
328
|
+
readonly installed: (repo: string) => string;
|
|
329
|
+
readonly chained: (repo: string) => string;
|
|
330
|
+
readonly already: "Commit capture was already on for this clone.";
|
|
331
|
+
readonly perClone: "Run `vibecommit connect` in each clone you want commits recorded for — git hooks are per-clone, not per-account.";
|
|
332
|
+
readonly hooksPathWhat: "Commit capture could NOT be installed for this clone.";
|
|
333
|
+
readonly hooksPathWhy: (configured: string) => string;
|
|
334
|
+
readonly hooksPathFixLabel: "Fix, either one:";
|
|
335
|
+
readonly hooksPathFixUnset: "git config --unset core.hooksPath";
|
|
336
|
+
readonly hooksPathFixManual: "or add `vibecommit post-commit` to your existing post-commit hook";
|
|
337
|
+
readonly failedWhat: "Commit capture could NOT be installed for this clone.";
|
|
338
|
+
readonly failedWhy: (why: string) => string;
|
|
339
|
+
};
|
|
340
|
+
export declare const PATH_CLASH: {
|
|
341
|
+
readonly foreignWhat: "Another program owns the `vibecommit` command.";
|
|
342
|
+
readonly foreignWhy: (resolved: string) => string;
|
|
343
|
+
readonly absentWhat: "The `vibecommit` command is not on your PATH.";
|
|
344
|
+
readonly absentWhy: "Hook capture is unaffected — the plugin runs the binary by path — but typing `vibecommit status`, `why` or `report` will not find it.";
|
|
345
|
+
readonly fixLabel: "Fix, either one:";
|
|
346
|
+
/**
|
|
347
|
+
* FOREIGN only. The uninstall half is wrong for the absent case — telling
|
|
348
|
+
* someone to uninstall a package they demonstrably do not have is the kind of
|
|
349
|
+
* fix line that teaches users to stop reading fix lines. Found by running it.
|
|
350
|
+
*/
|
|
351
|
+
readonly fixReplace: "npm uninstall -g vibecommit && npm i -g @vibe-commit/capture";
|
|
352
|
+
/** ABSENT: there is nothing to remove, only something to add. */
|
|
353
|
+
readonly fixInstall: "npm i -g @vibe-commit/capture";
|
|
354
|
+
readonly fixDirectLabel: "or invoke ours directly:";
|
|
355
|
+
/**
|
|
356
|
+
* `node …/bin/index.js`, not `…/bin/vibecommit`, and the difference is not
|
|
357
|
+
* cosmetic: `claude-plugin`'s `bin/` contains `index.js` and no file named
|
|
358
|
+
* `vibecommit`, and `index.js` carries a shebang but is NOT executable — so
|
|
359
|
+
* the shorter form fails twice over. `hooks.json` invokes it exactly this
|
|
360
|
+
* way, which is the shape that demonstrably works.
|
|
361
|
+
*
|
|
362
|
+
* This line asked for something impossible until DESIGN.md §13.6 was
|
|
363
|
+
* corrected — the same defect as the absent case above telling users to
|
|
364
|
+
* uninstall a package they do not have. **A fix line must be runnable, and
|
|
365
|
+
* the way you know is that you ran it.**
|
|
366
|
+
*/
|
|
367
|
+
readonly fixDirect: "node ~/.claude/plugins/vibecommit/bin/index.js connect";
|
|
368
|
+
};
|
|
369
|
+
/**
|
|
370
|
+
* Browser sign-in — `CR-084d`, the beat `connect.ts:175-176` deferred to "the
|
|
371
|
+
* oauth lane" and this task is that lane.
|
|
372
|
+
*
|
|
373
|
+
* ⚠ Two rules these strings are written to, both from the claims register:
|
|
374
|
+
*
|
|
375
|
+
* 1. **No reassurance adjective anywhere** (D65 §DR7 registers *secure, safe,
|
|
376
|
+
* protected, encrypted* on the `connect` surface, which is where every
|
|
377
|
+
* string below renders). A sign-in screen is exactly where the temptation
|
|
378
|
+
* is strongest, and "we'll securely sign you in" says nothing a user can
|
|
379
|
+
* check.
|
|
380
|
+
* 2. **The `what` line never has "you" as its subject** and never carries a
|
|
381
|
+
* bare HTTP status (DESIGN.md §13.6). "Sign-in did not finish", not "you
|
|
382
|
+
* failed to sign in"; the CAUSE goes in the `why` line, in a noun the user
|
|
383
|
+
* recognises.
|
|
384
|
+
*
|
|
385
|
+
* `browserDone` and `browserRefused` are the only strings in this package a
|
|
386
|
+
* BROWSER renders rather than a terminal, which is why they carry no §13.5
|
|
387
|
+
* gutter and no §13.2 glyph: there is no terminal to degrade to. They are still
|
|
388
|
+
* copy, so they still live here and are still scanned by the claims gate.
|
|
389
|
+
*/
|
|
390
|
+
export declare const SIGNIN: {
|
|
391
|
+
/** Printed before the browser opens, so the user knows what just happened. */
|
|
392
|
+
readonly opening: "Opening your browser to sign in…";
|
|
393
|
+
/**
|
|
394
|
+
* The headless fallback. NOT an error: a machine with no browser is an
|
|
395
|
+
* ordinary place to run this, and the URL is a complete substitute.
|
|
396
|
+
*/
|
|
397
|
+
readonly manualLabel: "Open this URL to finish signing in:";
|
|
398
|
+
readonly waiting: "Waiting for the browser…";
|
|
399
|
+
readonly done: "Signed in.";
|
|
400
|
+
/** What the browser tab shows. One line each — nothing is styled. */
|
|
401
|
+
readonly browserDone: "Signed in. You can close this tab and return to your terminal.";
|
|
402
|
+
readonly browserRefused: "This request did not match the sign-in waiting in your terminal.";
|
|
403
|
+
readonly noServerWhat: "VibeCommit could not find the sign-in service.";
|
|
404
|
+
/** `unreachable` — nothing answered. Says what was tried, not what is wrong. */
|
|
405
|
+
readonly noServerUnreachableWhy: "The server did not answer the request that says where to sign in. It may be down, or this machine may have no route to it.";
|
|
406
|
+
/** Any `malformed` fault. One sentence, because the user's move is the same. */
|
|
407
|
+
readonly noServerMalformedWhy: "The server answered, but the document that says where to sign in is not one this version can use.";
|
|
408
|
+
/**
|
|
409
|
+
* The override was refused before anything was sent. Names the variable and
|
|
410
|
+
* the rule, because this one is entirely in the user's hands to fix.
|
|
411
|
+
*/
|
|
412
|
+
readonly noServerRefusedWhy: "VIBECOMMIT_MCP_URL is set to an address this client will not send a sign-in to. Only https, or http on the loopback, is allowed.";
|
|
413
|
+
readonly noServerFix: "Check the service, then run:";
|
|
414
|
+
readonly deniedWhat: "Sign-in was declined.";
|
|
415
|
+
readonly deniedWhy: "The sign-in screen returned without granting access. Nothing was changed on this machine.";
|
|
416
|
+
readonly deniedFix: "To try again, run:";
|
|
417
|
+
readonly timeoutWhat: "Sign-in did not finish in time.";
|
|
418
|
+
readonly timeoutWhy: "The browser did not come back before the deadline. Nothing was changed on this machine.";
|
|
419
|
+
readonly timeoutFix: "To try again, run:";
|
|
420
|
+
readonly rejectedWhat: "The sign-in service refused this client.";
|
|
421
|
+
/**
|
|
422
|
+
* ⚠ `unauthorized_client` is the expected answer TODAY: this CLI's client id
|
|
423
|
+
* is not in the server's registered set (see `src/oauth/token.ts`). The copy
|
|
424
|
+
* names the state without promising when it changes — a date here would be a
|
|
425
|
+
* claim the register would have to carry.
|
|
426
|
+
*/
|
|
427
|
+
readonly rejectedWhy: "The service did not accept this client's sign-in request.";
|
|
428
|
+
readonly rejectedFix: "Report this, with the command you ran:";
|
|
429
|
+
readonly unreachableWhat: "VibeCommit could not reach the sign-in service.";
|
|
430
|
+
readonly unreachableWhy: "The request did not complete. Nothing was changed on this machine.";
|
|
431
|
+
readonly unreachableFix: "Check the connection, then run:";
|
|
432
|
+
readonly malformedWhat: "The sign-in service returned an unexpected answer.";
|
|
433
|
+
readonly malformedWhy: "The response was not in the form this version can use. No session was stored.";
|
|
434
|
+
readonly malformedFix: "Report this, with the command you ran:";
|
|
435
|
+
/** A session already exists, so sign-in is a no-op. */
|
|
436
|
+
readonly alreadySignedIn: "Already signed in on this machine.";
|
|
437
|
+
/**
|
|
438
|
+
* ⚠ THE COPY THIS OBJECT DEFERRED BY TASK NUMBER, now written by the first
|
|
439
|
+
* renderer. `why` is that renderer; `report` (`CR-108`, W10) is the second and
|
|
440
|
+
* inherits these rather than inventing a second phrasing.
|
|
441
|
+
*
|
|
442
|
+
* ⚠ AND THIS EXPORT NOW RENDERS ON TWO SURFACES. `SURFACES` in
|
|
443
|
+
* `test/copy-claims.test.ts` gained `why` beside `connect` for exactly these
|
|
444
|
+
* four strings — a surface map that still said `connect` alone would be
|
|
445
|
+
* checking them against the wrong blocked set.
|
|
446
|
+
*
|
|
447
|
+
* `expired` — the refresh grant was REFUSED. The session is over; only a new
|
|
448
|
+
* sign-in fixes it. Distinct from `busy`, which is a wait.
|
|
449
|
+
*/
|
|
450
|
+
readonly expiredWhat: "This machine's sign-in has ended.";
|
|
451
|
+
readonly expiredWhy: "The stored sign-in could not be renewed, so nothing could be read. It may have been revoked, or it may simply have run out.";
|
|
452
|
+
readonly expiredFix: "Sign in again, then run the command again:";
|
|
453
|
+
/**
|
|
454
|
+
* `busy` — another process holds the refresh lock and did not release it in
|
|
455
|
+
* time. NOT a failure of the session: the fix is to run it again, and saying
|
|
456
|
+
* "sign in again" here would send a user to re-authenticate over a lock.
|
|
457
|
+
*
|
|
458
|
+
* ⚠ The `what` line's subject is the state, never "you" (DESIGN.md §13.6).
|
|
459
|
+
*/
|
|
460
|
+
readonly busyWhat: "Another VibeCommit command is renewing this machine's sign-in.";
|
|
461
|
+
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.";
|
|
462
|
+
readonly busyFix: "Run it again in a moment:";
|
|
463
|
+
};
|
|
464
|
+
/** `vibecommit off`. */
|
|
465
|
+
export declare const OFF: {
|
|
466
|
+
readonly done: "Capture is off for this repository.";
|
|
467
|
+
readonly alreadyOff: "Capture was already off for this repository.";
|
|
468
|
+
readonly note: "Sessions already recorded are unaffected.";
|
|
469
|
+
};
|
|
470
|
+
/**
|
|
471
|
+
* `vibecommit why` — `CR-086`, W9.
|
|
472
|
+
*
|
|
473
|
+
* The screen is drawn in style guide §10.4 (layout), §10.5 (sub-agent
|
|
474
|
+
* attribution) and §10.6-A/B (the two absences this verb owns), and the copy is
|
|
475
|
+
* NORMATIVELY §R3's decision table in `docs/designs/claims-audit-why.md`. §10.4
|
|
476
|
+
* is explicit that §R3 governs and that it must not be paraphrased here, so the
|
|
477
|
+
* per-grade sentences live in `grades.ts` behind the one header renderer and
|
|
478
|
+
* this object holds only what §R3 tables SEPARATELY from the grade.
|
|
479
|
+
*
|
|
480
|
+
* ## ⚠ THE HOLE THIS SURFACE SHIPS WITH, HELD OPEN AND NAMED — `CR-129`
|
|
481
|
+
*
|
|
482
|
+
* §R3's sub-agent attribution table has three rows and **two of them read data
|
|
483
|
+
* nothing produces**. Measured at `vibecommit-schema` `2c77400`,
|
|
484
|
+
* `vibecommit-mcp` `eeda878` and here at `4dcf47d`, every tracked blob read as
|
|
485
|
+
* utf8 (never `grep` — `src/redact.ts` carries literal NUL bytes and `grep -I`
|
|
486
|
+
* skips it silently):
|
|
487
|
+
*
|
|
488
|
+
* - `capture_turns.subagent_count` — **0 hits in all three repos** at those
|
|
489
|
+
* SHAs. `TODOS[74]` assumed the column; nothing had added it.
|
|
490
|
+
* ⚠ **UPDATED BY `CR-129d` (W10): THE COLUMN NOW EXISTS AND STILL HAS NO
|
|
491
|
+
* PRODUCER.** `CR-129a` added it at `vibecommit-schema` `f3022c5` —
|
|
492
|
+
* `integer`, nullable, no default. Nothing writes it (mcp's
|
|
493
|
+
* `insertCaptureTurns` is a seven-key literal) and nothing emits it
|
|
494
|
+
* (`blame_commit` selects `position, turn_hash`), so the marker still
|
|
495
|
+
* cannot render from real data. The measurement above is kept because it
|
|
496
|
+
* is dated and was true; **this note is the correction, not a rewrite.**
|
|
497
|
+
* ⚠ A six-column tally stood here and is gone — it was an exact
|
|
498
|
+
* transcription of the original `create table` that three later
|
|
499
|
+
* migrations emptied, including one renaming `workspace_id` to `org_id`.
|
|
500
|
+
* D101: write the predicate, never the count.
|
|
501
|
+
* - `commit_file_attribution` EXISTS (`CR-070`,
|
|
502
|
+
* `20260814000000_cr070_commit_graph.sql:278`) and **has no writer**:
|
|
503
|
+
* `CR-072` shipped the edge only and said so
|
|
504
|
+
* (`vibecommit-mcp/src/conversation/edge_derivation.ts:56-64`). That table
|
|
505
|
+
* is where `agent_id` lives.
|
|
506
|
+
*
|
|
507
|
+
* So `agent_id` is a column on a table nothing writes, and `subagent_count` is
|
|
508
|
+
* not a column at all. `TODOS[74]` says of that minimum: *"E1 cannot ship
|
|
509
|
+
* without it… silence about a delegated edit is an overclaim about who wrote
|
|
510
|
+
* the code."* Both halves are true, and the resolution is neither to omit the
|
|
511
|
+
* requirement nor to fake it: **the absence renders, in the absence grammar,
|
|
512
|
+
* naming what it is and what would change it.**
|
|
513
|
+
*
|
|
514
|
+
* ⚠ `agent_id` NULL is SEMANTIC — the schema comment says *"NULL = the main
|
|
515
|
+
* thread. The empty string is refused because '' would render as an unnamed
|
|
516
|
+
* sub-agent — a plausible wrong answer rather than an error."* **`null` and
|
|
517
|
+
* ABSENT are therefore different facts**: `null` means we know it was the main
|
|
518
|
+
* thread; absent means we know nothing. An unmarked turn rendered from an
|
|
519
|
+
* absent field is the overclaim, so `why.ts` requires the field to be PRESENT
|
|
520
|
+
* before it renders a turn unmarked, and marks every turn otherwise.
|
|
521
|
+
*
|
|
522
|
+
* ## What is deliberately NOT here
|
|
523
|
+
*
|
|
524
|
+
* No grade word. §13.3: *"Grade words appear in `--json` only. Prose never
|
|
525
|
+
* prints a bare grade"* — the two-tier structural summary plus the per-edge
|
|
526
|
+
* evidence sentence render instead, and the evidence sentence is `grades.ts`'s.
|
|
527
|
+
*
|
|
528
|
+
* No `⛓` / `◇` glyphs. §10.5 draws them for the WEB surface; `DESIGN.md` §13.2's
|
|
529
|
+
* `GLYPH` table has exactly three entries (`ok` / `warn` / `bad`) and neither is
|
|
530
|
+
* in it. The CLI's binding requirement is §R3's prose evidence line, which
|
|
531
|
+
* renders. Inventing a fourth glyph is a report to the orchestrator, not an edit
|
|
532
|
+
* to `term.ts`.
|
|
533
|
+
*
|
|
534
|
+
* No colour on the attribution marker or on the grade (D65 §DR3, §DR4).
|
|
535
|
+
* `agent_id` is an ACTOR IDENTITY, the same class as a branch name, and a
|
|
536
|
+
* green/yellow/red grade ramp asserts a ranking §R3 forbids.
|
|
537
|
+
*/
|
|
538
|
+
export declare const WHY: {
|
|
539
|
+
/**
|
|
540
|
+
* ⚠ THIS is where D61 §PS6's file scope lives, and the reason it moved here.
|
|
541
|
+
* `commit_file_attribution` has no line ranges, so every sentence that
|
|
542
|
+
* INTRODUCES TURNS is file-scoped — and §PS6 requires the file scope to render
|
|
543
|
+
* on the same screen as the line number, which it does: the identity line
|
|
544
|
+
* above carries the line, this sentence carries the file.
|
|
545
|
+
*
|
|
546
|
+
* ⚠ §R3 bans a causal vocabulary on this sentence at all grades — *produced,
|
|
547
|
+
* caused, wrote this line, because, the reason, responsible for, explains, led
|
|
548
|
+
* to*. "Touched" is the approved verb and it is the weakest true one.
|
|
549
|
+
*/
|
|
550
|
+
readonly turnsIntro: (file: string) => string;
|
|
551
|
+
/**
|
|
552
|
+
* §R3's `match_kind` table, the `probable` row — `CR-138d` / `CR-109d`.
|
|
553
|
+
*
|
|
554
|
+
* ⚠ **THE ONLY DIFFERENCE BETWEEN THE TWO VARIANTS, AND IT MUST STAY VISIBLE.**
|
|
555
|
+
* §R3: `exact` renders the squash copy *unqualified* — the pair came from a
|
|
556
|
+
* recorded successor row — while `probable` renders it **plus a stated
|
|
557
|
+
* basis**. Rendering them identically is the folding D67 forbids: *"the
|
|
558
|
+
* disclosure would become the thing that hides the distinction."*
|
|
559
|
+
*
|
|
560
|
+
* ⚠ D105 makes this permanent rather than cosmetic: `match_kind` is in
|
|
561
|
+
* `commit_sha_successors`' primary key and `reject_history_mutation` raises
|
|
562
|
+
* on every UPDATE including `service_role`, **so a wrong row cannot be
|
|
563
|
+
* corrected.** A guess labelled as a guess is the only honest rendering.
|
|
564
|
+
*
|
|
565
|
+
* ⚠ `witnessed` is §R3's own word and the choice is deliberate. The obvious
|
|
566
|
+
* phrasing would have reached for the `observed` family, which is BLOCKED on
|
|
567
|
+
* this surface because it names a mechanism that exists in no repo (D113 §1)
|
|
568
|
+
* — a blocked claim arriving through a synonym nobody was checking. This
|
|
569
|
+
* comment names the trap without spelling the phrase, so a source-text scan
|
|
570
|
+
* does not fire on the note explaining the avoidance.
|
|
571
|
+
*/
|
|
572
|
+
readonly squashProbableBasis: "These two commits were matched by patch id rather than by a recorded successor row, so the pairing is read off the commits themselves and is not something capture witnessed.";
|
|
573
|
+
/**
|
|
574
|
+
* ⚠ WHY THE TWO SHAS ON THE SQUASH SCREEN ARE DIFFERENT LENGTHS.
|
|
575
|
+
*
|
|
576
|
+
* Two builders — this one and `CR-101`'s on the web surface — read the
|
|
577
|
+
* asymmetry as a bug, and **the ruling was to explain it rather than remove
|
|
578
|
+
* it** (D120 §1 as revised). Web keeps parity by carrying the full value in
|
|
579
|
+
* the DOM; a terminal line has nowhere to put it, so the line says why.
|
|
580
|
+
*
|
|
581
|
+
* ⚠ **THE SENTENCE DOES NOT TELL THE READER TO RUN `git show` ON IT**, and
|
|
582
|
+
* that restraint is measured rather than cautious: cloned over the git
|
|
583
|
+
* transport after a squash-merge with branch delete, the original object is
|
|
584
|
+
* ABSENT and `git show` fails on the full sha as surely as on a short one.
|
|
585
|
+
* What the full value keeps is that it stays a complete identifier somebody
|
|
586
|
+
* else can look up. Promising a local command that fails in exactly the case
|
|
587
|
+
* this state exists for would be the plausible-wrong-answer class in copy.
|
|
588
|
+
*/
|
|
589
|
+
readonly squashShaLengths: "The recorded commit is written out in full because a squashed commit is often missing from a working copy, and a shortened id cannot be looked up once the commit is gone.";
|
|
590
|
+
/** §10.4's turn row: `turn 12 [Edit] session.ts`. */
|
|
591
|
+
readonly turnLabel: "turn";
|
|
592
|
+
/** §10.4: excerpts are `muted` and `>`-prefixed — verbatim, never a summary. */
|
|
593
|
+
readonly excerptPrefix: ">";
|
|
594
|
+
/** Row 1 — `agent_id IS NOT NULL`. An identity, rendered plain (D65 §DR3). */
|
|
595
|
+
readonly subAgentMarker: (agentId: string) => string;
|
|
596
|
+
/**
|
|
597
|
+
* Row 2 — `capture_turns.subagent_count > 0`.
|
|
598
|
+
*
|
|
599
|
+
* ⚠ **NO PRODUCER EXISTS FOR THIS AND THE COLUMN IS NOT IN ANY SCHEMA.** It is
|
|
600
|
+
* implemented against a validated OPTIONAL payload field so that the day the
|
|
601
|
+
* column exists the row renders, and it is exercised in the suite against a
|
|
602
|
+
* synthetic payload — but nothing on the wire can populate it today, and this
|
|
603
|
+
* comment is the only honest place to say so. It is NOT rendered from a zero
|
|
604
|
+
* and NOT rendered from an absent field.
|
|
605
|
+
*/
|
|
606
|
+
readonly subAgentCountMarker: (count: number) => string;
|
|
607
|
+
/**
|
|
608
|
+
* The marker for a turn whose actor we cannot name — `CR-129`'s hole, on the
|
|
609
|
+
* turn itself rather than only in a footnote. §10.5: *"the turn header and the
|
|
610
|
+
* file-attribution table ALWAYS name the actor… hiding an actor"* is the thing
|
|
611
|
+
* that makes a claim. When we cannot name one, we say that, per turn.
|
|
612
|
+
*/
|
|
613
|
+
readonly actorUnrecordedMarker: "· actor not recorded";
|
|
614
|
+
/**
|
|
615
|
+
* The `CR-129` note, in the absence grammar — absence, cause, remedy.
|
|
616
|
+
*
|
|
617
|
+
* ⚠ NOT an `ABSENCE` state and it may not become one. Those five are
|
|
618
|
+
* whole-screen empty states that all exit 4; this is a caveat on a screen that
|
|
619
|
+
* HAS content, and `test/copy-absence.test.ts` asserts the set is exactly
|
|
620
|
+
* five. Same ruling the `ABSENCE` docblock already makes for the
|
|
621
|
+
* shallow-clone refusal: not every absence sentence is an absence STATE.
|
|
622
|
+
*/
|
|
623
|
+
readonly attributionWhat: "Sub-agent attribution is not recorded for these turns.";
|
|
624
|
+
/**
|
|
625
|
+
* ⚠ "on this screen", not "below" — caught by rendering it. The note sits
|
|
626
|
+
* AFTER the turn list, so a positional word was pointing the wrong way. A
|
|
627
|
+
* sentence that describes its own layout breaks silently when the layout
|
|
628
|
+
* moves; one that names the screen does not.
|
|
629
|
+
*/
|
|
630
|
+
readonly attributionWhy: "The per-turn attribution this marker reads has no writer yet, so no turn on this screen can be shown as main-thread work or as delegated work.";
|
|
631
|
+
/**
|
|
632
|
+
* ⚠ THE SECOND SENTENCE IS THE LOAD-BEARING ONE. Without it, an unmarked turn
|
|
633
|
+
* reads as a finding that the main thread wrote it — which is the inversion
|
|
634
|
+
* the register permanently BLOCKS, arriving through silence instead of through
|
|
635
|
+
* a sentence.
|
|
636
|
+
*/
|
|
637
|
+
readonly attributionNotAFinding: "An unmarked turn here is a missing record, not a finding about who wrote the code.";
|
|
638
|
+
readonly attributionFix: "Nothing to fix on this machine. The marker renders once attribution is recorded.";
|
|
639
|
+
/**
|
|
640
|
+
* §R3, verbatim. ⚠ **The selection rule is ORDINAL AND STATED** — *"in turn
|
|
641
|
+
* order"*, never *"most relevant"*, which is a ranking, which is server-side
|
|
642
|
+
* analysis and reverses D48–D51.
|
|
643
|
+
*
|
|
644
|
+
* ⚠ **Every number here comes from the PAYLOAD.** D60 §D1a: *"the client may
|
|
645
|
+
* render; it may not analyze."* Windowing an already-ordered list for display
|
|
646
|
+
* is rendering; DERIVING the numbers is not, so `why.ts` never counts the
|
|
647
|
+
* array it was handed.
|
|
648
|
+
*/
|
|
649
|
+
readonly truncation: (from: string, to: string, total: string) => string;
|
|
650
|
+
/** §R3's L2: files in the commit whose `turn_hash` is NULL are COUNTED, never dropped. */
|
|
651
|
+
readonly filesWithoutTurn: (count: string) => string;
|
|
652
|
+
/** The one-file form. `1 more files` is the tell that a count was never read. */
|
|
653
|
+
readonly fileWithoutTurn: "1 more file in this commit has no linked turn.";
|
|
654
|
+
readonly usageWhat: "This command needs a file and a line number.";
|
|
655
|
+
readonly usageWhy: "`why` answers for one line, so it cannot run without one. Nothing was read and nothing was sent.";
|
|
656
|
+
readonly usageFix: "Name the file and the line:";
|
|
657
|
+
/**
|
|
658
|
+
* `--json` — the REFUSAL COPY THAT STOOD HERE IS GONE, and its removal is the
|
|
659
|
+
* deliverable rather than a tidy-up (`CR-149`, D122 §2).
|
|
660
|
+
*
|
|
661
|
+
* It read *"`why` cannot produce JSON yet"*, and its docblock argued the
|
|
662
|
+
* refusal was *"the honest minimum rather than a gap"*. That was honest as a
|
|
663
|
+
* STOPGAP and false as a claim about design intent: **§13.3 REQUIRES `--json`
|
|
664
|
+
* on the read verbs**, so the flag was an UNBUILT FEATURE wearing the shape of
|
|
665
|
+
* a designed position — which is the harder defect to see, because a refusal
|
|
666
|
+
* reads as a decision. `src/json.ts` is the document; `status`, `why` and
|
|
667
|
+
* `report` all emit one.
|
|
668
|
+
*
|
|
669
|
+
* Nothing replaces these three constants. A verb that CAN answer the flag has
|
|
670
|
+
* no refusal to word.
|
|
671
|
+
*/
|
|
672
|
+
/**
|
|
673
|
+
* The shallow-clone REFUSAL (D67's posture, D98's hazard class).
|
|
674
|
+
*
|
|
675
|
+
* ⚠ A REFUSAL IS NOT AN ABSENCE. `git blame` on a shallow clone attributes to
|
|
676
|
+
* the graft boundary and returns a plausible WRONG commit — a call that fails
|
|
677
|
+
* announces itself; a call that returns a plausible answer is absorbed by the
|
|
678
|
+
* caller. Shallow clones live in CI containers, which is exactly where nobody
|
|
679
|
+
* is watching. The `ABSENCE` docblock already rules on this for `report`: it
|
|
680
|
+
* is not a sixth state and one may not be written there.
|
|
681
|
+
*/
|
|
682
|
+
readonly shallowWhat: "This is a shallow clone, so `git blame` cannot be trusted here.";
|
|
683
|
+
readonly shallowWhy: "A shallow clone stops at its graft boundary and attributes every older line to the oldest commit it holds. That answer looks ordinary and is wrong, so it is refused rather than shown.";
|
|
684
|
+
readonly shallowFix: "Fetch the full history, then run this again:";
|
|
685
|
+
readonly shallowFixCommand: "git fetch --unshallow";
|
|
686
|
+
/** `git blame` itself failed — no such file, no such line, or git said no. */
|
|
687
|
+
readonly blameWhat: "`git blame` could not attribute that line.";
|
|
688
|
+
readonly blameWhy: "git did not return a commit for it. The path may not be tracked in this repository, or the file may have fewer lines than the one named.";
|
|
689
|
+
readonly blameFix: "Check the path and the line, then run this again:";
|
|
690
|
+
/**
|
|
691
|
+
* ⚠ A READ-LANE FAILURE MUST PRINT AND EXIT NON-ZERO. The whole reason the
|
|
692
|
+
* exit contract was split is that the hook rule — exit 0, stdout empty — would
|
|
693
|
+
* have made this verb fail SILENTLY on a 5xx. `src/exit.ts` says so at the top.
|
|
694
|
+
*
|
|
695
|
+
* ⚠ And never a bare HTTP status (§13.6). The status is what we know; it is
|
|
696
|
+
* not what the user can act on.
|
|
697
|
+
*/
|
|
698
|
+
readonly unreachableWhat: "VibeCommit could not reach the record service.";
|
|
699
|
+
readonly unreachableWhy: "The request did not complete, so no answer was read. The service may be down, or this machine may have no route to it.";
|
|
700
|
+
readonly serverErrorWhat: "The record service could not answer that.";
|
|
701
|
+
readonly serverErrorWhy: "The request reached the service and it returned a failure instead of a record. Nothing on this machine was changed.";
|
|
702
|
+
readonly malformedWhat: "The record service returned an answer this version cannot read.";
|
|
703
|
+
readonly malformedWhy: "The response was not in the form this version expects, so none of it was rendered rather than part of it being guessed at.";
|
|
704
|
+
readonly readFix: "Try again, and report it if it continues:";
|
|
705
|
+
/**
|
|
706
|
+
* ⛔ VERSION SKEW — DISTINCT FROM `malformed`, AND THE DISTINCTION IS THE
|
|
707
|
+
* WHOLE POINT (`U1`, 2026-08-30).
|
|
708
|
+
*
|
|
709
|
+
* `parseBlameCommitPayload` is a STRICT ALLOWLIST on `state`: a value it does
|
|
710
|
+
* not know returns null, and null rendered as "malformed". So the day the
|
|
711
|
+
* server added a state, every client older than that day told the user its
|
|
712
|
+
* ANSWER WAS BROKEN — when the answer was fine and the CLIENT was old.
|
|
713
|
+
* `edge_unreadable` is the first such addition and it would have been the
|
|
714
|
+
* first casualty.
|
|
715
|
+
*
|
|
716
|
+
* ⚠ THE ROOT CAUSE, NOT THE SYMPTOM. Without this, every future state the
|
|
717
|
+
* server adds needs a lockstep client release FOREVER, and the coupling is
|
|
718
|
+
* invisible until a user hits it — worse here than in most protocols, because
|
|
719
|
+
* the vendored bundle in `claude-plugin/bin/` lags this source (10 commits at
|
|
720
|
+
* the time of writing) so "old client" is the NORMAL case, not the edge one.
|
|
721
|
+
*
|
|
722
|
+
* ## Why this is not a sixth ABSENCE state
|
|
723
|
+
*
|
|
724
|
+
* It is not an absence. Nothing is missing from the record — the server
|
|
725
|
+
* answered, and this build cannot render what it said. Same reason the
|
|
726
|
+
* shallow-clone refusal is not one: a REFUSAL and a SKEW are both about this
|
|
727
|
+
* client's limits, and `ABSENCE` is about the record's contents.
|
|
728
|
+
*
|
|
729
|
+
* ⚠ It still follows CR-112's grammar (absence · cause · remedy), because
|
|
730
|
+
* that grammar is what makes a dead end actionable, and here — unlike most of
|
|
731
|
+
* `ABSENCE` — the remedy is real: upgrading genuinely fixes it.
|
|
732
|
+
*
|
|
733
|
+
* ⚠ THE COPY MAY NOT NAME THE STATE IT COULD NOT READ. The whole premise is
|
|
734
|
+
* that this build does not know what that value means; printing it would
|
|
735
|
+
* invite the reader to interpret a token this client cannot interpret either.
|
|
736
|
+
*/
|
|
737
|
+
readonly skewWhat: "The record service sent an answer this version is too old to show.";
|
|
738
|
+
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.";
|
|
739
|
+
readonly skewFix: "Reinstall the VibeCommit plugin to pick up the current client, then run this again:";
|
|
740
|
+
/** The bearer is dead after one refresh and one retry. Exit 3, not 1. */
|
|
741
|
+
readonly signedOutWhat: "This machine is not signed in to VibeCommit.";
|
|
742
|
+
readonly signedOutWhy: "Reading a record needs a signed-in user, and no usable sign-in was found on this machine.";
|
|
743
|
+
readonly signedOutFix: "Sign in, then run the command again:";
|
|
744
|
+
};
|
|
745
|
+
/**
|
|
746
|
+
* `vibecommit report` (CR-108).
|
|
747
|
+
*
|
|
748
|
+
* NOTE: this surface ships NO durability copy until the E2 metric is defined
|
|
749
|
+
* (D61 §PS6, and the claims-register `Durable / survives / durability` row).
|
|
750
|
+
*
|
|
751
|
+
* ⚠ THE TWO EMPTY-WINDOW STATES MOVED. They were `emptyNoCommits` and
|
|
752
|
+
* `emptyNoCapture` here, and they were the absence clause and NOTHING ELSE — no
|
|
753
|
+
* cause, no remedy. `CR-112` re-homed both into `ABSENCE` below, where they
|
|
754
|
+
* carry the full grammar and sit beside the three `why` states they have to
|
|
755
|
+
* agree with. Do not reintroduce a short form here: two half-states in one
|
|
756
|
+
* module and five whole ones in another is the drift `CR-112` exists to stop.
|
|
757
|
+
*/
|
|
758
|
+
export declare const REPORT: {
|
|
759
|
+
readonly coverageLabel: "Commits with a recorded session";
|
|
760
|
+
readonly gradeMixLabel: "Evidence";
|
|
761
|
+
/**
|
|
762
|
+
* ⚠ **THE DEFINITION IS PART OF THE NUMBER, NOT A PREFACE.** D67 cleared
|
|
763
|
+
* §PS6's durability block on stated terms, and the first is that the
|
|
764
|
+
* definition, the percentage and the grade mix render together — *"without
|
|
765
|
+
* them, `observed` correlation-in-time is laundered into a KPI."* A build
|
|
766
|
+
* that ships the number alone does not lift the block.
|
|
767
|
+
*
|
|
768
|
+
* ⚠ **THE REF IS IN THE SENTENCE, ALWAYS** — *"a bare percentage is
|
|
769
|
+
* meaningless because the number is ref-relative."* `commit_coverage` makes
|
|
770
|
+
* `ref` a REQUIRED payload field for exactly this reason.
|
|
771
|
+
*/
|
|
772
|
+
readonly definition: (ref: string) => string;
|
|
773
|
+
readonly rate: (reachable: string, held: string, ref: string, percent: string) => string;
|
|
774
|
+
/** §10.3 draws `Of those:` and then the per-grade split. */
|
|
775
|
+
readonly gradeMixIntro: "Of those:";
|
|
776
|
+
/**
|
|
777
|
+
* ⚠ **THE GRADE WORDS THEMSELVES MAY NOT REACH THE SCREEN**, so the mix is
|
|
778
|
+
* rendered through these labels — DESIGN.md §13.3 (grade words in `--json`
|
|
779
|
+
* only), D65 §DR4 (no grade word on screen), and `test/why.test.ts` already
|
|
780
|
+
* enforces it for the other read verb.
|
|
781
|
+
*
|
|
782
|
+
* ⚠ §10.3's DRAWING VIOLATES THAT RULE and this deliberately departs from it:
|
|
783
|
+
* it draws *"41 observed during a session"*, which prints the bare grade
|
|
784
|
+
* word. D113 §1 makes it worse than a style slip — `observed` is BLOCKED
|
|
785
|
+
* because it names **a mechanism that exists in no repo**, and its listed
|
|
786
|
+
* phrasings include *seen during the session* and *watched*, which are the
|
|
787
|
+
* two shortenings anyone would reach for next. The `observed` label below
|
|
788
|
+
* mirrors `grades.ts`'s own approved sentence, *"This commit appeared while
|
|
789
|
+
* the session was running"*, which says the same fact and claims no witness.
|
|
790
|
+
* The §10.3 fix is owed in `code/` and is not this package's to write.
|
|
791
|
+
*/
|
|
792
|
+
readonly gradeDerivedLabel: "recorded in the transcript";
|
|
793
|
+
readonly gradeObservedLabel: "appeared while the session ran";
|
|
794
|
+
readonly gradeDeclaredLabel: "reported by the agent";
|
|
795
|
+
/** `<n> <label>`, joined by the renderer. Singular and plural read alike. */
|
|
796
|
+
readonly gradeCount: (count: string, label: string) => string;
|
|
797
|
+
/**
|
|
798
|
+
* ⚠ **THE SEPARATE LABELLED LINE, IN OUR WORDS** — D67: *"only exact
|
|
799
|
+
* `commit_sha_successors` rows count toward the numerator; patch-id matches
|
|
800
|
+
* render as a SEPARATE LABELLED 'probable' LINE and are never folded into the
|
|
801
|
+
* rate."*
|
|
802
|
+
*
|
|
803
|
+
* ⚠ **AND IT IS NOT THE SERVER'S SENTENCE.** `vibecommit-mcp`
|
|
804
|
+
* `src/read/coverage.ts` emits `probable_line.label` — a user-facing string
|
|
805
|
+
* minted in another repository, on this payload. D112 §3 ruled on exactly
|
|
806
|
+
* that shape: **the wire carries the fact, the client owns the words.** That
|
|
807
|
+
* ruling was measured in `src/read/blame.ts` and the class is NOT closed one
|
|
808
|
+
* file over, so this renders here and the wire's label is never printed.
|
|
809
|
+
*/
|
|
810
|
+
readonly probable: (count: string) => string;
|
|
811
|
+
readonly probableOne: "1 more matched by patch id, reported separately and not counted above.";
|
|
812
|
+
/**
|
|
813
|
+
* ⚠ **A SEPARATE PHRASING FROM `WHY.shallowWhat`, AND THE REASON IS THAT IT
|
|
814
|
+
* IS A DIFFERENT FACT.** `why`'s says *"`git blame` cannot be trusted here"*,
|
|
815
|
+
* which is true of blame and says nothing about reachability. On a shallow
|
|
816
|
+
* clone the commits that would answer *"is this sha still reachable"* may
|
|
817
|
+
* simply not be present, so the rate would be wrong rather than missing. The
|
|
818
|
+
* REMEDY is genuinely the same fact, so `shallowFix` and `shallowFixCommand`
|
|
819
|
+
* are SHARED rather than re-worded — that is the duplication to avoid.
|
|
820
|
+
*/
|
|
821
|
+
readonly shallowWhat: "This is a shallow clone, so coverage cannot be computed here.";
|
|
822
|
+
readonly shallowWhy: "Coverage asks which recorded commits are still reachable, and a shallow clone does not hold the history that answers it. The number would be wrong rather than missing.";
|
|
823
|
+
/**
|
|
824
|
+
* ⚠ FAILS CLOSED. If git cannot answer reachability for a commit we hold, the
|
|
825
|
+
* rate would be computed over a set we do not actually know — so it refuses.
|
|
826
|
+
* Counting an unanswerable probe as unreachable would DEFLATE the number
|
|
827
|
+
* silently, which is D98's class: no obviously-broken shape.
|
|
828
|
+
*/
|
|
829
|
+
readonly unknownReachabilityWhat: "Coverage could not be computed for every recorded commit.";
|
|
830
|
+
readonly unknownReachabilityWhy: "Git could not say whether some recorded commits are still reachable from this ref. A share computed over the rest would be a smaller number presented as a complete one.";
|
|
831
|
+
readonly unknownReachabilityFix: "Fetch the full history, then run this again:";
|
|
832
|
+
readonly refWhat: "This command needs a ref it can name.";
|
|
833
|
+
readonly refWhy: "Coverage is relative to a ref, so the answer is meaningless without one, and HEAD is detached here. Nothing was read and nothing was sent.";
|
|
834
|
+
readonly refFix: "Name the ref:";
|
|
835
|
+
/**
|
|
836
|
+
* The window, as the two empty states name it.
|
|
837
|
+
*
|
|
838
|
+
* ⚠ **THE WINDOW BOUNDS THE LOCAL HALF ONLY.** `commit_coverage` accepts no
|
|
839
|
+
* `since`, so the server's totals are repository-wide and the RATE claims no
|
|
840
|
+
* window — see `report.ts`. This string appears only on the two empty states,
|
|
841
|
+
* which are answered from the clone.
|
|
842
|
+
*/
|
|
843
|
+
readonly window: (since: string) => string;
|
|
844
|
+
readonly usageWhat: "This command needs a start date.";
|
|
845
|
+
readonly usageWhy: "The window bounds which commits are counted, so the answer is not defined without one. Nothing was read and nothing was sent.";
|
|
846
|
+
readonly usageFix: "Name the date the window starts:";
|
|
847
|
+
readonly sinceWhat: "That start date could not be read.";
|
|
848
|
+
readonly sinceWhy: "The window must be a calendar date, written as YYYY-MM-DD. A date git cannot read would silently widen the window.";
|
|
849
|
+
readonly sinceFix: "Write the date as YYYY-MM-DD:";
|
|
850
|
+
};
|
|
851
|
+
/**
|
|
852
|
+
* THE FIVE ABSENCE STATES, AS ONE SET — `CR-112`, D65.
|
|
853
|
+
*
|
|
854
|
+
* Five screens, owned by four different tasks, written by different builders at
|
|
855
|
+
* different times: cold start and no-edge (`CR-086`, W9), the two `report` empty
|
|
856
|
+
* windows (`CR-108`, W10), and squash-resolved (`CR-109`). D65 put them in one
|
|
857
|
+
* row so they are ONE set with ONE grammar rather than four people's four ways
|
|
858
|
+
* of saying nothing was found.
|
|
859
|
+
*
|
|
860
|
+
* ## The grammar, and it is the three fields
|
|
861
|
+
*
|
|
862
|
+
* **State the absence (`what`), state the cause (`why`), state what would change
|
|
863
|
+
* it (`fix`). NEVER "nothing found".** The fields ARE the grammar — they are
|
|
864
|
+
* `renderErrorBlock`'s shape (`src/term.ts`) and `DESIGN.md` §13.6's *what, why,
|
|
865
|
+
* fix — fix last, always, because the last thing on screen is what gets copied*.
|
|
866
|
+
* **A state with a blank `why` is a state that says "nothing found" with extra
|
|
867
|
+
* steps**, which is why `test/copy-absence.test.ts` asserts every field of every
|
|
868
|
+
* state explicitly and scans all of them for the empty-result vocabulary.
|
|
869
|
+
*
|
|
870
|
+
* That test is the mechanism. This docblock is not: `CR-090d` is one wave old
|
|
871
|
+
* and its whole lesson is that `strings.ts` DECLARED "no inline literals" while
|
|
872
|
+
* five sat in `src/index.ts` for six waves, because a docblock is not a gate.
|
|
873
|
+
*
|
|
874
|
+
* ## `exit` rides WITH the copy, deliberately
|
|
875
|
+
*
|
|
876
|
+
* `EXIT.empty` (4) already exists and its docblock already carries the reason:
|
|
877
|
+
* collapsing an empty window into `1` teaches a wrapper that absence of a record
|
|
878
|
+
* means the tool broke — one `||` away from the permanently BLOCKED claim that
|
|
879
|
+
* absence of an edge means no agent was involved. This task adds no exit code;
|
|
880
|
+
* it makes five screens use the one that exists. Binding it to the state is the
|
|
881
|
+
* only way that survives four builders across three waves — a builder who
|
|
882
|
+
* renders the state gets the code with it, instead of reading a sentence that
|
|
883
|
+
* asks them to remember.
|
|
884
|
+
*
|
|
885
|
+
* ## ⚠ AN EMPTY WINDOW RENDERS NO NUMBER — D67 RESOLVED FOR THIS CASE
|
|
886
|
+
*
|
|
887
|
+
* D67 cleared the §PS6 durability block *on its stated terms*: the metric, the
|
|
888
|
+
* coverage percentage and the grade mix render **TOGETHER**, per grade, never
|
|
889
|
+
* blended, ref named inline. **On an empty window there is no metric, so
|
|
890
|
+
* "together or not at all" resolves to NOT AT ALL.** Neither `report` state
|
|
891
|
+
* carries a percentage, a grade mix, or any durability vocabulary:
|
|
892
|
+
*
|
|
893
|
+
* - **State 3's denominator is zero.** A percentage over an empty denominator
|
|
894
|
+
* is not a small number, it is NOT A NUMBER — and `0%` there would be a
|
|
895
|
+
* coverage claim manufactured from no data. That is D98's plausible-wrong-
|
|
896
|
+
* answer class exactly: a call that fails announces itself, a call that
|
|
897
|
+
* returns a plausible answer is absorbed by the caller, and `0%` has no
|
|
898
|
+
* obviously-broken shape.
|
|
899
|
+
* - **State 4's numerator is zero over a real denominator**, so `0%` is
|
|
900
|
+
* arithmetically defensible — and there is still no grade mix to render
|
|
901
|
+
* beside it, because a grade mix over zero edges is empty. D67's rule is
|
|
902
|
+
* that the three render together or the block does not lift. They cannot.
|
|
903
|
+
* So state 4 renders no number either.
|
|
904
|
+
*
|
|
905
|
+
* Consequently `claims.ts`'s `durable` / `durability` / `survives` rows stay
|
|
906
|
+
* BLOCKED on the `report` surface and that is correct, not an oversight.
|
|
907
|
+
*
|
|
908
|
+
* ## ⚠ A CONTRACT ON THE CALLER (`CR-108`, W10): ESTABLISH THE CLONE IS COMPLETE
|
|
909
|
+
*
|
|
910
|
+
* **The caller MUST establish that the clone is complete before selecting either
|
|
911
|
+
* `report` empty state.** D67: on a shallow clone the metric REFUSES to render,
|
|
912
|
+
* and that refusal is load-bearing rather than defensive — it is what keeps the
|
|
913
|
+
* number from being quietly wrong in CI containers, which is where shallow
|
|
914
|
+
* clones live. The refusal fires BEFORE either empty state is reachable, and it
|
|
915
|
+
* has to: on a shallow clone *"no commits in this window"* is a claim the clone
|
|
916
|
+
* cannot support, because the window may simply predate the graft boundary.
|
|
917
|
+
*
|
|
918
|
+
* State 3's sentence is therefore written UNQUALIFIED, as if the clone were
|
|
919
|
+
* complete — because the refusal guarantees it is. `test/copy-absence.test.ts`
|
|
920
|
+
* pins both halves: that this contract is stated here, and that no state hedges
|
|
921
|
+
* about clones.
|
|
922
|
+
*
|
|
923
|
+
* ⚠ **A shallow-clone refusal is a REFUSAL, not an absence. It is NOT a state
|
|
924
|
+
* here and one may not be written for it.** Inventing a phrasing for something
|
|
925
|
+
* that is not an empty RESULT is the thing this set exists to prevent.
|
|
926
|
+
*
|
|
927
|
+
* ⚠⚠ THIS PARAGRAPH SAID "NOT A SIXTH STATE" AND THE SET IS NOW SIX. The
|
|
928
|
+
* sentence was right about its subject and wrong as a general rule, so it is
|
|
929
|
+
* narrowed rather than deleted — the bar is not "five forever", it is that a
|
|
930
|
+
* state here must be an EMPTY RESULT the server actually reports, not a local
|
|
931
|
+
* refusal and not a rephrasing of one that exists. `edgeUnreadable` (`U1`,
|
|
932
|
+
* 2026-08-30) clears that bar: mcp emits `edge_unreadable` as a distinct wire
|
|
933
|
+
* state, and no other entry can render it without asserting something false.
|
|
934
|
+
* A shallow-clone refusal still fails the bar, for the reason above.
|
|
935
|
+
*/
|
|
936
|
+
/**
|
|
937
|
+
* The six states. A name per state, so the set can be asserted exactly.
|
|
938
|
+
*
|
|
939
|
+
* ⚠ Adding one means updating `EXPECTED_STATES` in `test/copy-absence.test.ts`
|
|
940
|
+
* in the same commit, which is deliberate: that cell exists so a state cannot
|
|
941
|
+
* appear without a reviewer reading the argument for it.
|
|
942
|
+
*/
|
|
943
|
+
export type AbsenceStateName = "coldStart" | "noEdge" | "edgeUnreadable" | "reportNoCommits" | "reportNoSessions" | "squashResolved";
|
|
944
|
+
/**
|
|
945
|
+
* A field is a plain string, or a template when the grammar needs a value
|
|
946
|
+
* interpolated — the cause clause is window- and ref-relative, so two states
|
|
947
|
+
* cannot be plain strings without dropping the very thing that makes them a
|
|
948
|
+
* cause. **That is the GRAMMAR's requirement (state the cause), not D67's metric
|
|
949
|
+
* rule**: a named ref here is not a smuggled durability claim, and a later
|
|
950
|
+
* reader should not mistake it for one.
|
|
951
|
+
*/
|
|
952
|
+
export type AbsenceField = string | ((...args: string[]) => string);
|
|
953
|
+
export interface AbsenceState {
|
|
954
|
+
/** The absence. What is not there. */
|
|
955
|
+
readonly what: AbsenceField;
|
|
956
|
+
/** The cause. Why it is not there. Never blank. */
|
|
957
|
+
readonly why: AbsenceField;
|
|
958
|
+
/** What would change it. "Nothing to fix" is a legitimate answer; blank is not. */
|
|
959
|
+
readonly fix: AbsenceField;
|
|
960
|
+
/** Always `EXIT.empty`. Absence is not failure — see the note above. */
|
|
961
|
+
readonly exit: typeof EXIT.empty;
|
|
962
|
+
}
|
|
963
|
+
export declare const ABSENCE: {
|
|
964
|
+
/**
|
|
965
|
+
* 1 — COLD START. Owner: `CR-086` (W9), and `CR-086` CORRECTED ITS SCOPE.
|
|
966
|
+
*
|
|
967
|
+
* ## ⚠ It said MACHINE; the state it names is a REPOSITORY
|
|
968
|
+
*
|
|
969
|
+
* The shipped text was *"No sessions have been recorded on this MACHINE
|
|
970
|
+
* yet"*, and neither half of that survived measurement. `why`'s answer is
|
|
971
|
+
* repository-scoped — the payload that selects this state answers for one
|
|
972
|
+
* repo — and a developer with capture running in three repos and none here
|
|
973
|
+
* would have been told capture had never run at all. Nothing in the client
|
|
974
|
+
* holds a machine-wide "never captured" fact either: `state.ts` keys sends by
|
|
975
|
+
* project.
|
|
976
|
+
*
|
|
977
|
+
* ## Why it does not render §10.6-A's two extra facts, and that is deliberate
|
|
978
|
+
*
|
|
979
|
+
* §10.6-A and §R3 draw *"That commit predates capture on this repo (first
|
|
980
|
+
* capture 2026-08-08). … 14 commits captured since."* **Both numbers are
|
|
981
|
+
* facts this client does not hold.** `state.ts` records `lastSendForRepo` —
|
|
982
|
+
* the LAST send, never a FIRST-capture date — and the commit count is
|
|
983
|
+
* `commit_coverage`'s, a server figure behind `CR-085`. D81's order applies:
|
|
984
|
+
* make the claim honest before building the mechanism.
|
|
985
|
+
*
|
|
986
|
+
* So the state says the thing that IMPLIES §10.6-A's headline without
|
|
987
|
+
* asserting either number: **if no session was ever recorded for this
|
|
988
|
+
* repository, then every commit in it predates capture** — including this
|
|
989
|
+
* one. That is §10.6-A's meaning, carried by a fact the payload can state.
|
|
990
|
+
* The date and the count are registered as owed (see the PR) rather than
|
|
991
|
+
* approximated, because a first-capture date guessed from a last-send record
|
|
992
|
+
* is D98's plausible-wrong-answer class exactly.
|
|
993
|
+
*
|
|
994
|
+
* ⚠ NO SIXTH STATE WAS ADDED, and none may be: `test/copy-absence.test.ts`
|
|
995
|
+
* asserts the EXACT set of five.
|
|
996
|
+
*/
|
|
997
|
+
readonly coldStart: {
|
|
998
|
+
readonly what: "No session has been recorded for this repository yet.";
|
|
999
|
+
readonly why: "Capture has not sent anything for this repository, so no commit in it has a conversation record — including this one.";
|
|
1000
|
+
readonly fix: "Connect this repository, then work as usual:";
|
|
1001
|
+
readonly exit: 4;
|
|
1002
|
+
};
|
|
1003
|
+
/**
|
|
1004
|
+
* 2 — NO-EDGE EMPTY. Capture is working; the commit `git blame` returned has
|
|
1005
|
+
* no edge. Owner: `CR-086` (W9).
|
|
1006
|
+
*
|
|
1007
|
+
* ⚠ The `why` states a DEFINITION, not a diagnosis. "This commit was made
|
|
1008
|
+
* without an agent" is the permanently BLOCKED claim (see `exit.ts`), and a
|
|
1009
|
+
* sentence guessing at the cause of one absent record is one edit away from
|
|
1010
|
+
* it. What is safe is what makes a record exist at all.
|
|
1011
|
+
*/
|
|
1012
|
+
readonly noEdge: {
|
|
1013
|
+
readonly what: "No recorded session is linked to this commit.";
|
|
1014
|
+
readonly why: "A commit is linked to a session only when capture was running for the session that produced it. This is a missing record, not a finding about the commit.";
|
|
1015
|
+
readonly fix: "Nothing to fix. A record cannot be added to a commit after the fact.";
|
|
1016
|
+
readonly exit: 4;
|
|
1017
|
+
};
|
|
1018
|
+
/**
|
|
1019
|
+
* 3 — `report` EMPTY WINDOW A: NO COMMITS. Owner: `CR-108` (W10).
|
|
1020
|
+
*
|
|
1021
|
+
* Names the WINDOW and the REF, because the answer is relative to both: there
|
|
1022
|
+
* may be commits on another branch, or outside these dates, and a sentence
|
|
1023
|
+
* that named neither would read as a claim about the repository.
|
|
1024
|
+
*
|
|
1025
|
+
* Written unqualified — see the clone contract above.
|
|
1026
|
+
*/
|
|
1027
|
+
readonly reportNoCommits: {
|
|
1028
|
+
readonly what: (ref: string, window: string) => string;
|
|
1029
|
+
readonly why: (ref: string) => string;
|
|
1030
|
+
readonly fix: "Widen the window, or name a different ref, and run this again.";
|
|
1031
|
+
readonly exit: 4;
|
|
1032
|
+
};
|
|
1033
|
+
/**
|
|
1034
|
+
* 4 — `report` EMPTY WINDOW B: COMMITS, NO SESSIONS. Owner: `CR-108` (W10).
|
|
1035
|
+
*
|
|
1036
|
+
* ⚠ 3 and 4 are DIFFERENT FACTS and collapsing them reads as a coverage claim
|
|
1037
|
+
* we cannot make. The counted commits are the whole difference: this window
|
|
1038
|
+
* has them and has no session for them, which is not the same as having
|
|
1039
|
+
* nothing in it.
|
|
1040
|
+
*/
|
|
1041
|
+
readonly reportNoSessions: {
|
|
1042
|
+
readonly what: (count: string, window: string) => string;
|
|
1043
|
+
readonly why: "A commit has a recorded session only when capture was running for the session that produced it. The window bounds this answer.";
|
|
1044
|
+
readonly fix: "Work with capture on, then run this again over a window that includes those commits.";
|
|
1045
|
+
readonly exit: 4;
|
|
1046
|
+
};
|
|
1047
|
+
/**
|
|
1048
|
+
* 5 — SQUASH-RESOLVED. `git blame` returns the squashed SHA on `main` while
|
|
1049
|
+
* every edge we hold binds a pre-squash original. Owner: `CR-109`.
|
|
1050
|
+
*
|
|
1051
|
+
* ⚠ D65 §DR5: if the blamed SHA is not a SHA we hold an edge for, the header
|
|
1052
|
+
* MAY NOT claim the transcript recorded it. **Both SHAs render** — a
|
|
1053
|
+
* single-SHA sentence here is exactly the overclaim this state exists to
|
|
1054
|
+
* prevent. This is GitHub's DEFAULT merge button, so it is the common path.
|
|
1055
|
+
*/
|
|
1056
|
+
readonly squashResolved: {
|
|
1057
|
+
readonly what: (blamed: string, recorded: string) => string;
|
|
1058
|
+
readonly why: (blamed: string) => string;
|
|
1059
|
+
readonly fix: "Nothing to fix. Read the session as the record of the original commit.";
|
|
1060
|
+
readonly exit: 4;
|
|
1061
|
+
};
|
|
1062
|
+
/**
|
|
1063
|
+
* 6 — EDGE UNREADABLE. ⛔ THE SET IS NOW SIX, AND THIS IS THE FIRST ADDITION.
|
|
1064
|
+
* Owner: `U1`. ⛔ **FOUNDER-RATIFIED, 2026-08-31 — `D203`.** Not an
|
|
1065
|
+
* implementer's judgement call: three independent tripwires forbade a sixth
|
|
1066
|
+
* state, they all fired, and the decision to clear them was put to the
|
|
1067
|
+
* founder and ruled rather than argued past. `D203` carries the reasoning and
|
|
1068
|
+
* the cost that was spent (reversibility — a field promotes to a state later,
|
|
1069
|
+
* a shipped state does not un-ship).
|
|
1070
|
+
*
|
|
1071
|
+
* ⚠ The tripwires are CLOSURE TRIPWIRES, not a cap, and they did exactly what
|
|
1072
|
+
* they exist for: this state could not enter the set without a reviewer being
|
|
1073
|
+
* made to read the argument for it.
|
|
1074
|
+
*
|
|
1075
|
+
* ## ⚠ THIS IS THE ONE ABSENCE STATE THAT IS NOT AN ABSENCE OF RECORD
|
|
1076
|
+
*
|
|
1077
|
+
* The other five say some version of "we hold nothing here". This one says
|
|
1078
|
+
* the OPPOSITE: **we hold a link for this commit and could not render the
|
|
1079
|
+
* conversation behind it.** Reading it as "no session" inverts it.
|
|
1080
|
+
*
|
|
1081
|
+
* It exists because mcp used to return `no_edge` for this case, which
|
|
1082
|
+
* reported "this repository is captured and this commit has no linked
|
|
1083
|
+
* session" about a commit we demonstrably hold a link for — a false negative
|
|
1084
|
+
* on the only question `why` asks. `blame.ts` now emits `edge_unreadable`
|
|
1085
|
+
* and this is its rendering.
|
|
1086
|
+
*
|
|
1087
|
+
* ⚠ IT IS THE DIRECT-EDGE TWIN OF `squashResolved`, which already carries
|
|
1088
|
+
* exactly this shape one hop later (a mapping we resolved whose evidence will
|
|
1089
|
+
* not render). Same fact, different route to it. That symmetry is the reason
|
|
1090
|
+
* this is a sixth state rather than a caveat note: `attributionNote`'s shape
|
|
1091
|
+
* is a caveat on a screen WITH content, and this screen has none.
|
|
1092
|
+
*
|
|
1093
|
+
* ## ⚠ THE `fix` MAY NOT PROMISE A REPAIR
|
|
1094
|
+
*
|
|
1095
|
+
* CR-112 requires the remedy to say what would CHANGE the state, and here the
|
|
1096
|
+
* honest answer is often "nothing the reader can do": if the turn content was
|
|
1097
|
+
* erased, or was never uploaded, the evidence is gone and the link stays.
|
|
1098
|
+
* Saying "re-run capture" would be a plausible-wrong-answer (D98) — it
|
|
1099
|
+
* repairs neither case. So the line states the two conditions and stops.
|
|
1100
|
+
*
|
|
1101
|
+
* ⚠ NOT "corrupt", "lost", or "missing data" — all three are diagnoses of a
|
|
1102
|
+
* cause this client did not measure. What we know is that the server held a
|
|
1103
|
+
* link and returned no readable turns; the reason is the server's and is not
|
|
1104
|
+
* on the wire.
|
|
1105
|
+
*/
|
|
1106
|
+
readonly edgeUnreadable: {
|
|
1107
|
+
readonly what: "A recorded session is linked to this commit, but its conversation could not be read.";
|
|
1108
|
+
readonly why: "The link between this commit and a session is on record. The turns behind that link came back without readable content, so there is a record here and no conversation to show for it. This is a gap in what can be displayed, not a missing link.";
|
|
1109
|
+
readonly fix: "Nothing to fix from here. Turn content can be unreadable because it was erased on request or was never uploaded, and neither is repaired by re-running capture.";
|
|
1110
|
+
readonly exit: 4;
|
|
1111
|
+
};
|
|
1112
|
+
};
|
|
1113
|
+
/** Failure-class copy (CR-018). Three classes: later / never / fatal. */
|
|
1114
|
+
export declare const ERRORS: {
|
|
1115
|
+
readonly notConnected: "This repository is not connected. Run `vibecommit connect`.";
|
|
1116
|
+
readonly networkLater: "Could not reach VibeCommit. This session will be recorded on the next turn.";
|
|
1117
|
+
readonly authFatal: "VibeCommit could not authenticate. Run `vibecommit connect` to reconnect.";
|
|
1118
|
+
readonly payloadNever: "This session was too large to record and has been skipped.";
|
|
1119
|
+
readonly notAGitRepo: "Not a git repository.";
|
|
1120
|
+
};
|
|
1121
|
+
/**
|
|
1122
|
+
* The interactive top-level catch (CR-022).
|
|
1123
|
+
*
|
|
1124
|
+
* **The hook half of the contract does not apply here** (D61 round 3 §D8). A hook
|
|
1125
|
+
* swallows everything and exits 0 because a non-zero hook derails the developer's
|
|
1126
|
+
* live turn; an interactive verb that did the same would report success for work
|
|
1127
|
+
* it did not do. So an unexpected exception gets §13.6's shape — what, why, fix —
|
|
1128
|
+
* and exit 1.
|
|
1129
|
+
*
|
|
1130
|
+
* ⚠ The `why` line says only what we actually know. "Nothing was uploaded" would
|
|
1131
|
+
* be a claim, not a fact: an exception can land after a send, and copy that
|
|
1132
|
+
* guesses in the reassuring direction is the failure the claims register exists
|
|
1133
|
+
* to stop.
|
|
1134
|
+
*/
|
|
1135
|
+
export declare const INTERNAL: {
|
|
1136
|
+
readonly unexpectedWhat: "VibeCommit stopped on an unexpected error.";
|
|
1137
|
+
readonly unexpectedWhy: "The command did not finish.";
|
|
1138
|
+
readonly unexpectedFix: "Run it again with the error detail shown:";
|
|
1139
|
+
readonly unexpectedDebugCommand: "VIBECOMMIT_DEBUG=1 vibecommit <command>";
|
|
1140
|
+
};
|
|
1141
|
+
/**
|
|
1142
|
+
* Credential-loading failures (CR-016).
|
|
1143
|
+
*
|
|
1144
|
+
* §13.6's shape — what, why, fix, fix last. **The `what` line never has "you" as
|
|
1145
|
+
* its subject** and never carries a bare HTTP status. None of these strings
|
|
1146
|
+
* contains any part of a credential, and none can: the plaintext only leaves
|
|
1147
|
+
* `IngestCredential` through `expose()`, which no copy path calls.
|
|
1148
|
+
*/
|
|
1149
|
+
export declare const CREDENTIAL: {
|
|
1150
|
+
readonly wrongClassWhat: "The credential set for this machine is not an ingest credential.";
|
|
1151
|
+
readonly wrongClassEnvWhy: "VIBECOMMIT_TOKEN is set, but its value is not a VibeCommit ingest credential. It was not sent anywhere.";
|
|
1152
|
+
readonly wrongClassFileWhy: "The credential on disk is not a VibeCommit ingest credential. It was not sent anywhere.";
|
|
1153
|
+
readonly wrongClassFix: "Mint a fresh one:";
|
|
1154
|
+
readonly insecureFileWhat: "The credential file is readable by other accounts on this machine.";
|
|
1155
|
+
readonly insecureFileWhyLabel: "file";
|
|
1156
|
+
readonly insecureFileModeLabel: "mode";
|
|
1157
|
+
readonly insecureFileWhy: "It was not read. A credential file must be readable only by its owner.";
|
|
1158
|
+
readonly insecureFileFix: "Restore the mode, then reconnect:";
|
|
1159
|
+
readonly unreadableWhat: "The credential file could not be read.";
|
|
1160
|
+
readonly unreadableWhy: "It exists but does not contain a credential in the expected form.";
|
|
1161
|
+
readonly unreadableFix: "Replace it by reconnecting:";
|
|
1162
|
+
};
|
|
1163
|
+
/**
|
|
1164
|
+
* The Node floor (D57 plan §DX11). `NODE_FLOOR_TEXT` and the running version are
|
|
1165
|
+
* interpolated by the caller so there is still exactly one copy of the sentence.
|
|
1166
|
+
*/
|
|
1167
|
+
export declare const RUNTIME: {
|
|
1168
|
+
readonly floorWhat: "VibeCommit needs a newer Node.";
|
|
1169
|
+
readonly floorWhyPrefix: "This package requires Node";
|
|
1170
|
+
readonly floorWhyMiddle: "or newer. It is running on Node";
|
|
1171
|
+
readonly floorFix: "Upgrade Node, then run:";
|
|
1172
|
+
};
|
|
1173
|
+
/**
|
|
1174
|
+
* The `systemMessage` channel — style guide §10.1, three states, once per
|
|
1175
|
+
* session (D57 plan §DX3).
|
|
1176
|
+
*
|
|
1177
|
+
* ⚠ Four rules that are easy to break and expensive to notice:
|
|
1178
|
+
* 1. ONE LINE each. Two lines in an agent transcript reads as tool noise and
|
|
1179
|
+
* gets tuned out, which returns us to the failure DX3 exists to fix.
|
|
1180
|
+
* 2. NO SGR ESCAPES, ever. This is a JSON string field rendered by Claude
|
|
1181
|
+
* Code's own UI; embedded escapes are undefined behaviour (DESIGN.md §13.9).
|
|
1182
|
+
* 3. All three are FAILURE states. The positive fourth state (`capture
|
|
1183
|
+
* confirmed`) is `CR-023`, and it is a two-clause amendment — it inverts
|
|
1184
|
+
* "stdout empty on the happy path". Do not add it here as if it were a
|
|
1185
|
+
* shape-preserving addition.
|
|
1186
|
+
* 4. No URL longer than the line.
|
|
1187
|
+
*/
|
|
1188
|
+
export declare const SYSTEM_MESSAGE: {
|
|
1189
|
+
readonly notConnected: "VibeCommit is installed but not connected. Run `vibecommit connect` to start capturing.";
|
|
1190
|
+
readonly credentialRevoked: "VibeCommit capture stopped: this machine's credential was revoked. Run `vibecommit connect`.";
|
|
1191
|
+
/** Templated on both versions — style guide §10.1 state 3. */
|
|
1192
|
+
readonly unsupportedRuntime: (floor: string, running: string) => string;
|
|
1193
|
+
/**
|
|
1194
|
+
* State 4 — style guide §10.1, and the ONLY positive one. `CR-023d`.
|
|
1195
|
+
*
|
|
1196
|
+
* Templated on the URL rather than inlining it, for the same reason
|
|
1197
|
+
* `unsupportedRuntime` is templated: `URLS` is declared below this object, so
|
|
1198
|
+
* a direct reference would read it in its temporal dead zone.
|
|
1199
|
+
*
|
|
1200
|
+
* ⚠ The style guide's example ends `.../app/commits/a8f2c91`, which is
|
|
1201
|
+
* ILLUSTRATIVE and not constructible here. A hook cannot know which commit a
|
|
1202
|
+
* session will resolve to — that mapping happens server-side and
|
|
1203
|
+
* asynchronously, long after this process has exited — so the generic
|
|
1204
|
+
* dashboard URL is substituted. See the PR.
|
|
1205
|
+
*
|
|
1206
|
+
* Claims-register: "captured" is not a blocked phrase, and it is a weaker
|
|
1207
|
+
* claim than the register's own boundary line ("the record is append-only for
|
|
1208
|
+
* users and its hash chain detects post-write tampering").
|
|
1209
|
+
*/
|
|
1210
|
+
readonly captureConfirmed: (dashboardUrl: string) => string;
|
|
1211
|
+
};
|
|
1212
|
+
/**
|
|
1213
|
+
* The out-of-tree redaction marker — `CR-024d`, D57 §OV8d.
|
|
1214
|
+
*
|
|
1215
|
+
* User-visible: it lands in the record a customer reads back, so it clears
|
|
1216
|
+
* `docs/claims-register.md`. It says WHAT HAPPENED and nothing about how safe
|
|
1217
|
+
* anything is — no *secure / safe / protected / private / encrypted* — and it
|
|
1218
|
+
* claims no completeness, because OV8d's redaction is explicitly PARTIAL
|
|
1219
|
+
* (`capture-refactor-three-buyers.md`:387) and "complete / all / every" is a
|
|
1220
|
+
* blocked claim unless the count and the selection rule render inline.
|
|
1221
|
+
*
|
|
1222
|
+
* The byte count IS the count rendering inline, and "outside this repository"
|
|
1223
|
+
* is the selection rule. Both are literally true of the span replaced.
|
|
1224
|
+
*
|
|
1225
|
+
* Shape borrowed from the server scrubber's `[REDACTED:<kind>]` — read for its
|
|
1226
|
+
* shape only, never imported: this package is MIT and `vibecommit-mcp` is
|
|
1227
|
+
* closed, so lifting code across would be a licensing violation (D60 §D1a).
|
|
1228
|
+
*/
|
|
1229
|
+
export declare const REDACTION: {
|
|
1230
|
+
/** Padded to the exact byte length of what it replaces — see `redact.ts`. */
|
|
1231
|
+
readonly head: (bytes: number) => string;
|
|
1232
|
+
/** Fill between head and tail. ASCII, one byte per column. */
|
|
1233
|
+
readonly fill: ".";
|
|
1234
|
+
readonly tail: "]";
|
|
1235
|
+
/** For spans too short for the counted form. */
|
|
1236
|
+
readonly short: "[OUT-OF-TREE]";
|
|
1237
|
+
};
|
|
1238
|
+
/** Commands the copy points at. One definition, so a rename cannot half-land. */
|
|
1239
|
+
export declare const COMMANDS: {
|
|
1240
|
+
readonly connect: "vibecommit connect";
|
|
1241
|
+
/** `CR-084d`. A FLAG, not a verb — `--help`'s verb list and its golden file do not move. */
|
|
1242
|
+
readonly signIn: "vibecommit connect --sign-in";
|
|
1243
|
+
readonly status: "vibecommit status";
|
|
1244
|
+
/**
|
|
1245
|
+
* `CR-108`. The ARGUMENT SHAPE, shown once so the usage error and the retry
|
|
1246
|
+
* fix line cannot drift apart — the same convention `why` uses.
|
|
1247
|
+
*/
|
|
1248
|
+
readonly report: "vibecommit report --since 2026-07-08";
|
|
1249
|
+
/** The ref form, for the detached-HEAD refusal. */
|
|
1250
|
+
readonly reportRef: "vibecommit report --since 2026-07-08 --ref main";
|
|
1251
|
+
readonly off: "vibecommit off";
|
|
1252
|
+
/**
|
|
1253
|
+
* `CR-086`. The ARGUMENT SHAPE, shown once so the usage error and the retry
|
|
1254
|
+
* fix line cannot drift apart. There is no argument parser in this package —
|
|
1255
|
+
* `connect` reads `argv.includes("--sign-in")` and that is the whole
|
|
1256
|
+
* convention — so `file:line` is the smallest shape that satisfies the
|
|
1257
|
+
* verbatim-approved `--help` sentence, and it is the form editors and `grep`
|
|
1258
|
+
* already print.
|
|
1259
|
+
*/
|
|
1260
|
+
readonly why: "vibecommit why src/auth/session.ts:47";
|
|
1261
|
+
readonly chmodCredentials: "chmod 600 ~/.vibecommit/credentials.json";
|
|
1262
|
+
/**
|
|
1263
|
+
* ⛔ THE INSTALL COMMAND, TRANSCRIBED FROM `claude-plugin/README.md:12` — and
|
|
1264
|
+
* it is deliberately NOT an invented update verb (`U1`, 2026-08-30).
|
|
1265
|
+
*
|
|
1266
|
+
* The skew remedy wants "get a newer client". There is **no documented update
|
|
1267
|
+
* command anywhere in this product**: grepped `claude-plugin/README.md`, its
|
|
1268
|
+
* manifests, and this package — the README documents `marketplace add` and
|
|
1269
|
+
* `install`, and nothing else. Printing `/plugin update vibecommit` because it
|
|
1270
|
+
* reads plausibly is D98's class exactly: a command-shaped string that may not
|
|
1271
|
+
* exist, handed to a user who is already stuck.
|
|
1272
|
+
*
|
|
1273
|
+
* So the fix line names the install command that IS documented, and
|
|
1274
|
+
* `WHY.skewFix` is worded as REINSTALL rather than update, which is true of
|
|
1275
|
+
* this string. ⚠ If a real update verb is ever documented, change both
|
|
1276
|
+
* together — the wording and the command are one unit.
|
|
1277
|
+
*/
|
|
1278
|
+
readonly pluginInstall: "/plugin install vibecommit@vibecommit-capture";
|
|
1279
|
+
};
|
|
1280
|
+
/**
|
|
1281
|
+
* Every URL the CLI prints. Here rather than inline for the same reason as the
|
|
1282
|
+
* rest: a link is user-visible copy, the claims gate can only check what it can
|
|
1283
|
+
* find, and `CR-114` is moving `/app`'s information architecture underneath us.
|
|
1284
|
+
*/
|
|
1285
|
+
export declare const URLS: {
|
|
1286
|
+
readonly dashboard: "https://vibecommit.ai/app";
|
|
1287
|
+
readonly settings: "https://vibecommit.ai/app/settings";
|
|
1288
|
+
/**
|
|
1289
|
+
* The captures INDEX — `CR-025`. Style guide §10.2 draws
|
|
1290
|
+
* `/app/commits/<a-sha>`, and that route DOES NOT EXIST: `CR-114` (W3) created
|
|
1291
|
+
* `app/app/commits/page.tsx`, a flat index, with no `[sha]` segment and no
|
|
1292
|
+
* rewrite, so a per-commit URL 404s. Verified against `vibecommit-web`
|
|
1293
|
+
* `origin/main` rather than assumed.
|
|
1294
|
+
*
|
|
1295
|
+
* Printing a URL that 404s at the moment of highest trust is the specific
|
|
1296
|
+
* failure this ending exists to avoid. `CR-101` (W10) adds the detail page;
|
|
1297
|
+
* deepening this constant is that task's, not a later guess.
|
|
1298
|
+
*/
|
|
1299
|
+
readonly commits: "https://vibecommit.ai/app/commits";
|
|
1300
|
+
/**
|
|
1301
|
+
* Where an org member goes to see their pending capture request — `CR-110`.
|
|
1302
|
+
*
|
|
1303
|
+
* ⚠ VERIFIED BY FILE, NOT BY PROBE. Every `/app/*` path on that site returns
|
|
1304
|
+
* an identical 307 whether or not the route exists, so a 307 is NEVER evidence
|
|
1305
|
+
* a route is real. This one was confirmed by reading
|
|
1306
|
+
* `vibecommit-web/app/app/settings/capture-access/page.tsx` on `origin/main`,
|
|
1307
|
+
* with `app/api/capture-access/{policy,decide}/route.ts` beside it (`CR-035c`).
|
|
1308
|
+
*
|
|
1309
|
+
* Deeper than the style guide's drawn `/app`, deliberately: the beat's whole
|
|
1310
|
+
* job is to be actionable, and the generic dashboard does not show the request.
|
|
1311
|
+
*/
|
|
1312
|
+
readonly captureAccess: "https://vibecommit.ai/app/settings/capture-access";
|
|
1313
|
+
/**
|
|
1314
|
+
* The public bundle that vendors the exact binary — `CR-111d`, D20, D64.
|
|
1315
|
+
*
|
|
1316
|
+
* ⚠ THE ONLY HONEST TRUST OFFER LEFT. D64 made `vibecommit-capture` PRIVATE
|
|
1317
|
+
* (MIT intact — the licence is the invariant, the visibility is not), so
|
|
1318
|
+
* linking this repo would be linking a 404 and claiming readable source would
|
|
1319
|
+
* be false. D20 keeps `claude-plugin` public non-negotiably.
|
|
1320
|
+
*
|
|
1321
|
+
* ⚠ AND THE SENTENCE BESIDE IT IS ONLY TRUE ONCE `CR-029e` LANDS. Measured at
|
|
1322
|
+
* `claude-plugin` `1349896`, `bin/` was vendored from `vibecommit-capture`
|
|
1323
|
+
* `8e772f1` — nine commits and eight tasks behind, with no `redact.js` at all.
|
|
1324
|
+
* `CR-029e` re-vendors it. Written as §10.2 draws it, with the dependency
|
|
1325
|
+
* disclosed in the PR rather than silently shipped.
|
|
1326
|
+
*/
|
|
1327
|
+
readonly pluginBundle: "https://github.com/Vibe-Commit/claude-plugin";
|
|
1328
|
+
};
|