@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.
Files changed (141) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +66 -0
  3. package/dist/agents/claude_code.d.ts +11 -0
  4. package/dist/agents/claude_code.js +162 -0
  5. package/dist/agents/claude_code.js.map +1 -0
  6. package/dist/agents/codex_cli.d.ts +15 -0
  7. package/dist/agents/codex_cli.js +67 -0
  8. package/dist/agents/codex_cli.js.map +1 -0
  9. package/dist/agents/cursor.d.ts +21 -0
  10. package/dist/agents/cursor.js +89 -0
  11. package/dist/agents/cursor.js.map +1 -0
  12. package/dist/agents/registry.d.ts +184 -0
  13. package/dist/agents/registry.js +212 -0
  14. package/dist/agents/registry.js.map +1 -0
  15. package/dist/agents/types.d.ts +279 -0
  16. package/dist/agents/types.js +67 -0
  17. package/dist/agents/types.js.map +1 -0
  18. package/dist/commands/connect.d.ts +36 -0
  19. package/dist/commands/connect.js +499 -0
  20. package/dist/commands/connect.js.map +1 -0
  21. package/dist/commands/context.d.ts +45 -0
  22. package/dist/commands/context.js +14 -0
  23. package/dist/commands/context.js.map +1 -0
  24. package/dist/commands/report.d.ts +105 -0
  25. package/dist/commands/report.js +430 -0
  26. package/dist/commands/report.js.map +1 -0
  27. package/dist/commands/status.d.ts +29 -0
  28. package/dist/commands/status.js +236 -0
  29. package/dist/commands/status.js.map +1 -0
  30. package/dist/commands/why.d.ts +349 -0
  31. package/dist/commands/why.js +937 -0
  32. package/dist/commands/why.js.map +1 -0
  33. package/dist/consent.d.ts +59 -0
  34. package/dist/consent.js +111 -0
  35. package/dist/consent.js.map +1 -0
  36. package/dist/copy/claims.d.ts +79 -0
  37. package/dist/copy/claims.js +343 -0
  38. package/dist/copy/claims.js.map +1 -0
  39. package/dist/copy/grades.d.ts +117 -0
  40. package/dist/copy/grades.js +96 -0
  41. package/dist/copy/grades.js.map +1 -0
  42. package/dist/copy/index.d.ts +12 -0
  43. package/dist/copy/index.js +13 -0
  44. package/dist/copy/index.js.map +1 -0
  45. package/dist/copy/strings.d.ts +1328 -0
  46. package/dist/copy/strings.js +1243 -0
  47. package/dist/copy/strings.js.map +1 -0
  48. package/dist/copy/time.d.ts +27 -0
  49. package/dist/copy/time.js +43 -0
  50. package/dist/copy/time.js.map +1 -0
  51. package/dist/credential.d.ts +211 -0
  52. package/dist/credential.js +298 -0
  53. package/dist/credential.js.map +1 -0
  54. package/dist/exit.d.ts +59 -0
  55. package/dist/exit.js +60 -0
  56. package/dist/exit.js.map +1 -0
  57. package/dist/git.d.ts +299 -0
  58. package/dist/git.js +653 -0
  59. package/dist/git.js.map +1 -0
  60. package/dist/hooks/entry.d.ts +277 -0
  61. package/dist/hooks/entry.js +1092 -0
  62. package/dist/hooks/entry.js.map +1 -0
  63. package/dist/hooks/post_commit.d.ts +59 -0
  64. package/dist/hooks/post_commit.js +160 -0
  65. package/dist/hooks/post_commit.js.map +1 -0
  66. package/dist/hooks/post_rewrite.d.ts +59 -0
  67. package/dist/hooks/post_rewrite.js +161 -0
  68. package/dist/hooks/post_rewrite.js.map +1 -0
  69. package/dist/hooks/session_end.d.ts +101 -0
  70. package/dist/hooks/session_end.js +120 -0
  71. package/dist/hooks/session_end.js.map +1 -0
  72. package/dist/index.d.ts +34 -0
  73. package/dist/index.js +360 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/install.d.ts +153 -0
  76. package/dist/install.js +284 -0
  77. package/dist/install.js.map +1 -0
  78. package/dist/json.d.ts +100 -0
  79. package/dist/json.js +94 -0
  80. package/dist/json.js.map +1 -0
  81. package/dist/oauth/discovery.d.ts +96 -0
  82. package/dist/oauth/discovery.js +163 -0
  83. package/dist/oauth/discovery.js.map +1 -0
  84. package/dist/oauth/lock.d.ts +100 -0
  85. package/dist/oauth/lock.js +287 -0
  86. package/dist/oauth/lock.js.map +1 -0
  87. package/dist/oauth/loopback.d.ts +85 -0
  88. package/dist/oauth/loopback.js +124 -0
  89. package/dist/oauth/loopback.js.map +1 -0
  90. package/dist/oauth/pkce.d.ts +58 -0
  91. package/dist/oauth/pkce.js +77 -0
  92. package/dist/oauth/pkce.js.map +1 -0
  93. package/dist/oauth/read.d.ts +120 -0
  94. package/dist/oauth/read.js +144 -0
  95. package/dist/oauth/read.js.map +1 -0
  96. package/dist/oauth/session.d.ts +80 -0
  97. package/dist/oauth/session.js +112 -0
  98. package/dist/oauth/session.js.map +1 -0
  99. package/dist/oauth/signin.d.ts +178 -0
  100. package/dist/oauth/signin.js +225 -0
  101. package/dist/oauth/signin.js.map +1 -0
  102. package/dist/oauth/token.d.ts +139 -0
  103. package/dist/oauth/token.js +183 -0
  104. package/dist/oauth/token.js.map +1 -0
  105. package/dist/paths.d.ts +366 -0
  106. package/dist/paths.js +460 -0
  107. package/dist/paths.js.map +1 -0
  108. package/dist/policy.d.ts +195 -0
  109. package/dist/policy.js +244 -0
  110. package/dist/policy.js.map +1 -0
  111. package/dist/post.d.ts +302 -0
  112. package/dist/post.js +384 -0
  113. package/dist/post.js.map +1 -0
  114. package/dist/project.d.ts +99 -0
  115. package/dist/project.js +192 -0
  116. package/dist/project.js.map +1 -0
  117. package/dist/redact.d.ts +175 -0
  118. package/dist/redact.js +700 -0
  119. package/dist/redact.js.map +1 -0
  120. package/dist/runtime.d.ts +30 -0
  121. package/dist/runtime.js +37 -0
  122. package/dist/runtime.js.map +1 -0
  123. package/dist/spawn_budget.d.ts +101 -0
  124. package/dist/spawn_budget.js +124 -0
  125. package/dist/spawn_budget.js.map +1 -0
  126. package/dist/spool.d.ts +390 -0
  127. package/dist/spool.js +556 -0
  128. package/dist/spool.js.map +1 -0
  129. package/dist/state.d.ts +109 -0
  130. package/dist/state.js +217 -0
  131. package/dist/state.js.map +1 -0
  132. package/dist/system_message.d.ts +101 -0
  133. package/dist/system_message.js +141 -0
  134. package/dist/system_message.js.map +1 -0
  135. package/dist/term.d.ts +112 -0
  136. package/dist/term.js +134 -0
  137. package/dist/term.js.map +1 -0
  138. package/dist/version.d.ts +16 -0
  139. package/dist/version.js +17 -0
  140. package/dist/version.js.map +1 -0
  141. package/package.json +50 -0
@@ -0,0 +1,105 @@
1
+ /**
2
+ * `vibecommit report --since` — coverage and grade mix. `CR-108`, W10.
3
+ *
4
+ * ─────────────────────────────────────────────────────────────────────────────
5
+ * ## ⚠ THE STRONGEST CLAIM IN THE PRODUCT, ON ITS WEAKEST FOOTING
6
+ *
7
+ * §PS6 blocked this surface outright, and **D67 cleared it on stated terms**.
8
+ * The terms are the build, not advice — shipping the number without them does
9
+ * not lift the block:
10
+ *
11
+ * 1. **Definition, coverage % and grade mix render TOGETHER or NOT AT ALL.**
12
+ * 2. **Per grade, never blended**, and the **ref is named inline** — a bare
13
+ * percentage is meaningless because the number is ref-relative.
14
+ * 3. **Only exact `commit_sha_successors` rows count toward the numerator**;
15
+ * patch-id matches render as a **separate labelled line**, never folded in.
16
+ * 4. **On a shallow clone it REFUSES**, and that refusal is load-bearing.
17
+ * 5. **The denominator is "commits we hold an edge for", NEVER "commits the
18
+ * agent made"** — that number does not exist in the schema, and inventing
19
+ * it turns a coverage report into a cooperation-rate claim.
20
+ *
21
+ * ## ⚠ THE RATE IS COMPUTED HERE, AND THAT IS AN AUTHORISED DEVIATION
22
+ *
23
+ * D60 §D1a says the client may render and may not analyze. **D67 puts the
24
+ * reachability computation on the client ON PURPOSE**, because the server has
25
+ * no repository: `commit_coverage` returns the shas we hold an edge for and
26
+ * **deliberately no rate**, since *"a null rate invites a renderer to print
27
+ * something."* So this module runs `git` and divides. Cited so a later reader
28
+ * does not read it as a D1a violation.
29
+ *
30
+ * ## ⚠⚠ WHAT `--since` CAN AND CANNOT BOUND — READ THIS BEFORE CHANGING IT
31
+ *
32
+ * **`commit_coverage` ACCEPTS NO WINDOW.** Its input schema is `{repo |
33
+ * repository_id, ref}` and `ref` is the only required field; there is no
34
+ * `since`. So the server's `edges_held` and `captured_shas` are
35
+ * **repository-wide**, and the rate computed from them is repository-wide too.
36
+ *
37
+ * `--since` therefore bounds **the local half only** — the commit list this
38
+ * module reads out of the user's own clone, which is what selects the two empty
39
+ * states (both of which name the window, because both are local facts). **The
40
+ * rate's sentence claims no window, deliberately**, because claiming one would
41
+ * be the plausible-wrong-answer class (D98) on the product's most load-bearing
42
+ * number.
43
+ *
44
+ * That split is a real gap, it is reported rather than smoothed, and closing it
45
+ * needs a `since` on the server tool — a row in a repo this task may not write.
46
+ *
47
+ * @provenance vibecommit-mcp src/read/coverage.ts — the payload shape, retyped
48
+ */
49
+ import { readWithSession } from "../oauth/signin.js";
50
+ import { type CommandContext } from "./context.js";
51
+ /**
52
+ * What `report` requires of `commit_coverage`.
53
+ *
54
+ * ⚠ **TWO FIELDS ON THIS PAYLOAD ARE USER-FACING PROSE MINTED IN
55
+ * `vibecommit-mcp`, AND NEITHER IS READ HERE.** `probable_line.label` carries
56
+ * *"probable (patch-id match) — reported separately, not counted in the rate"*
57
+ * and `reachability.reason` carries a sentence explaining the split. **D112 §3
58
+ * ruled on exactly this shape** for `TOOL_UNKNOWN`: a user-facing string minted
59
+ * in another repository bypasses every copy gate this one has —
60
+ * `test/copy-claims.test.ts` maps exports of `strings.ts`, and a wire string is
61
+ * in no export. **THE WIRE CARRIES THE FACT, THE CLIENT OWNS THE WORDS.** That
62
+ * ruling was measured in `src/read/blame.ts`; finding the same shape in
63
+ * `src/read/coverage.ts` means the class is NOT closed, and it is reported.
64
+ *
65
+ * So this type deliberately does not carry `label` or `reason`: a field that is
66
+ * not parsed cannot be printed by accident.
67
+ */
68
+ export interface CoveragePayload {
69
+ /** ⚠ REQUIRED and it goes in the sentence. The number is ref-relative. */
70
+ readonly ref: string;
71
+ /** THE DENOMINATOR: distinct commit shas we hold an edge for. */
72
+ readonly edgesHeld: number;
73
+ /** Every legal grade, including any with a permanent zero. */
74
+ readonly byGrade: Readonly<Record<string, number>>;
75
+ /** The shas whose reachability this module tests against the local clone. */
76
+ readonly capturedShas: readonly string[];
77
+ /** ⚠ ONLY THESE count toward the numerator (D67). */
78
+ readonly exactSuccessors: number;
79
+ /** ⚠ NEVER folded into the rate. Rendered on its own line, in OUR words. */
80
+ readonly probableCount: number;
81
+ }
82
+ /** The whole document. `null` means malformed, and malformed renders as malformed. */
83
+ export declare function parseCoveragePayload(document: unknown): CoveragePayload | null;
84
+ export interface ReportArgs {
85
+ readonly since: string;
86
+ readonly ref: string | null;
87
+ }
88
+ /**
89
+ * `--since <YYYY-MM-DD> [--ref <ref>]`.
90
+ *
91
+ * There is no argument parser in this package and `why` deliberately did not
92
+ * add one; this matches that restraint — two flags, read positionally after
93
+ * their names, and anything else is a usage error.
94
+ *
95
+ * ⚠ **THE DATE SHAPE IS ENFORCED RATHER THAN PASSED THROUGH.** `git log
96
+ * --since` accepts almost anything and silently widens the window on input it
97
+ * cannot read — *"yesterdya"* is not an error, it is a different answer. That is
98
+ * D98's class on the field that bounds the whole report.
99
+ */
100
+ export declare function parseArgs(argv: readonly string[]): ReportArgs | "usage" | "bad-date";
101
+ export interface ReportDeps {
102
+ /** Injected so the suite can drive every arm without a server — there is none. */
103
+ readonly read?: typeof readWithSession;
104
+ }
105
+ export declare function report(ctx: CommandContext, argv: readonly string[], deps?: ReportDeps): Promise<number>;
@@ -0,0 +1,430 @@
1
+ /**
2
+ * `vibecommit report --since` — coverage and grade mix. `CR-108`, W10.
3
+ *
4
+ * ─────────────────────────────────────────────────────────────────────────────
5
+ * ## ⚠ THE STRONGEST CLAIM IN THE PRODUCT, ON ITS WEAKEST FOOTING
6
+ *
7
+ * §PS6 blocked this surface outright, and **D67 cleared it on stated terms**.
8
+ * The terms are the build, not advice — shipping the number without them does
9
+ * not lift the block:
10
+ *
11
+ * 1. **Definition, coverage % and grade mix render TOGETHER or NOT AT ALL.**
12
+ * 2. **Per grade, never blended**, and the **ref is named inline** — a bare
13
+ * percentage is meaningless because the number is ref-relative.
14
+ * 3. **Only exact `commit_sha_successors` rows count toward the numerator**;
15
+ * patch-id matches render as a **separate labelled line**, never folded in.
16
+ * 4. **On a shallow clone it REFUSES**, and that refusal is load-bearing.
17
+ * 5. **The denominator is "commits we hold an edge for", NEVER "commits the
18
+ * agent made"** — that number does not exist in the schema, and inventing
19
+ * it turns a coverage report into a cooperation-rate claim.
20
+ *
21
+ * ## ⚠ THE RATE IS COMPUTED HERE, AND THAT IS AN AUTHORISED DEVIATION
22
+ *
23
+ * D60 §D1a says the client may render and may not analyze. **D67 puts the
24
+ * reachability computation on the client ON PURPOSE**, because the server has
25
+ * no repository: `commit_coverage` returns the shas we hold an edge for and
26
+ * **deliberately no rate**, since *"a null rate invites a renderer to print
27
+ * something."* So this module runs `git` and divides. Cited so a later reader
28
+ * does not read it as a D1a violation.
29
+ *
30
+ * ## ⚠⚠ WHAT `--since` CAN AND CANNOT BOUND — READ THIS BEFORE CHANGING IT
31
+ *
32
+ * **`commit_coverage` ACCEPTS NO WINDOW.** Its input schema is `{repo |
33
+ * repository_id, ref}` and `ref` is the only required field; there is no
34
+ * `since`. So the server's `edges_held` and `captured_shas` are
35
+ * **repository-wide**, and the rate computed from them is repository-wide too.
36
+ *
37
+ * `--since` therefore bounds **the local half only** — the commit list this
38
+ * module reads out of the user's own clone, which is what selects the two empty
39
+ * states (both of which name the window, because both are local facts). **The
40
+ * rate's sentence claims no window, deliberately**, because claiming one would
41
+ * be the plausible-wrong-answer class (D98) on the product's most load-bearing
42
+ * number.
43
+ *
44
+ * That split is a real gap, it is reported rather than smoothed, and closing it
45
+ * needs a `since` on the server tool — a row in a repo this task may not write.
46
+ *
47
+ * @provenance vibecommit-mcp src/read/coverage.ts — the payload shape, retyped
48
+ */
49
+ import { ABSENCE, COMMANDS, ERRORS, REPORT, SIGNIN, WHY, } from "../copy/index.js";
50
+ import { EXIT } from "../exit.js";
51
+ import { currentBranch, gitProbe, isReachable, isShallowClone, resolveRepoSlug } from "../git.js";
52
+ import { emitJson } from "../json.js";
53
+ import { mcpUrl } from "../oauth/discovery.js";
54
+ import { readWithSession } from "../oauth/signin.js";
55
+ import { resolveProjectKey } from "../project.js";
56
+ import { renderErrorBlock, wrap } from "../term.js";
57
+ import { writeLines } from "./context.js";
58
+ /** §10.3 indents the body two columns, the same as `why`'s screens. */
59
+ const BODY_INDENT = 2;
60
+ /** One read, one POST. Generous because it contains a server-side join. */
61
+ const READ_TIMEOUT_MS = 15_000;
62
+ /** `--since` is a calendar date and nothing else — see `parseArgs`. */
63
+ const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
64
+ const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
65
+ function asCount(value) {
66
+ return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : null;
67
+ }
68
+ /** The whole document. `null` means malformed, and malformed renders as malformed. */
69
+ export function parseCoveragePayload(document) {
70
+ if (!isRecord(document))
71
+ return null;
72
+ const ref = document.ref;
73
+ if (typeof ref !== "string" || ref.trim() === "")
74
+ return null;
75
+ const edgesHeld = asCount(document.edges_held);
76
+ const exactSuccessors = asCount(document.exact_successors);
77
+ if (edgesHeld === null || exactSuccessors === null)
78
+ return null;
79
+ if (!Array.isArray(document.captured_shas))
80
+ return null;
81
+ const capturedShas = document.captured_shas;
82
+ if (!capturedShas.every((s) => typeof s === "string" && s.trim() !== ""))
83
+ return null;
84
+ // ⚠ EVERY GRADE IS A NON-NEGATIVE INTEGER, and an unrecognised grade name is
85
+ // MALFORMED rather than skipped. A fourth grade appearing on the wire means
86
+ // the two repos disagree about an enum that lives in three of them with
87
+ // nothing verifying they agree — dropping it silently would render a mix that
88
+ // does not add up and looks fine.
89
+ if (!isRecord(document.by_grade))
90
+ return null;
91
+ const byGrade = {};
92
+ for (const [name, raw] of Object.entries(document.by_grade)) {
93
+ const count = asCount(raw);
94
+ if (count === null || !GRADE_ORDER.includes(name))
95
+ return null;
96
+ byGrade[name] = count;
97
+ }
98
+ // ⚠ `probable_line` is read for its COUNT ONLY. `label` is deliberately not
99
+ // parsed — see the docblock above.
100
+ if (!isRecord(document.probable_line))
101
+ return null;
102
+ const probableCount = asCount(document.probable_line.count);
103
+ if (probableCount === null)
104
+ return null;
105
+ return { ref, edgesHeld, byGrade, capturedShas, exactSuccessors, probableCount };
106
+ }
107
+ /**
108
+ * The order the grade mix renders in, and the ONLY place a grade name appears.
109
+ *
110
+ * ⚠ Strongest first, which is also `ALL_GRADES`' order. The NAMES are used to
111
+ * look up copy and are never printed — DESIGN.md §13.3 puts grade words in
112
+ * `--json` only, D65 §DR4 keeps them off the screen, and `test/why.test.ts`
113
+ * already enforces that for the other read verb.
114
+ */
115
+ const GRADE_ORDER = ["derived", "observed", "declared"];
116
+ const GRADE_LABEL = {
117
+ derived: REPORT.gradeDerivedLabel,
118
+ observed: REPORT.gradeObservedLabel,
119
+ declared: REPORT.gradeDeclaredLabel,
120
+ };
121
+ /**
122
+ * `--since <YYYY-MM-DD> [--ref <ref>]`.
123
+ *
124
+ * There is no argument parser in this package and `why` deliberately did not
125
+ * add one; this matches that restraint — two flags, read positionally after
126
+ * their names, and anything else is a usage error.
127
+ *
128
+ * ⚠ **THE DATE SHAPE IS ENFORCED RATHER THAN PASSED THROUGH.** `git log
129
+ * --since` accepts almost anything and silently widens the window on input it
130
+ * cannot read — *"yesterdya"* is not an error, it is a different answer. That is
131
+ * D98's class on the field that bounds the whole report.
132
+ */
133
+ export function parseArgs(argv) {
134
+ let since = null;
135
+ let ref = null;
136
+ for (let i = 0; i < argv.length; i += 1) {
137
+ const arg = argv[i];
138
+ if (arg === "--since") {
139
+ const value = argv[i + 1];
140
+ if (value === undefined || value.startsWith("-"))
141
+ return "usage";
142
+ since = value;
143
+ i += 1;
144
+ }
145
+ else if (arg === "--ref") {
146
+ const value = argv[i + 1];
147
+ if (value === undefined || value.startsWith("-"))
148
+ return "usage";
149
+ ref = value;
150
+ i += 1;
151
+ }
152
+ else if (!arg.startsWith("-")) {
153
+ // A bare positional is not part of this verb's grammar, and accepting one
154
+ // would let `report 2026-07-08` look like it worked.
155
+ return "usage";
156
+ }
157
+ }
158
+ if (since === null)
159
+ return "usage";
160
+ return ISO_DATE.test(since) ? { since, ref } : "bad-date";
161
+ }
162
+ // ---------------------------------------------------------------------------
163
+ // Rendering.
164
+ // ---------------------------------------------------------------------------
165
+ function errorCopy(what, why, fixLabel, fix) {
166
+ return { what, why: [why], fixLabel, fixes: [fix] };
167
+ }
168
+ function fail(ctx, copy, code) {
169
+ writeLines(ctx.stderr, renderErrorBlock({ kind: "bad", ...copy }, ctx.colour));
170
+ return code;
171
+ }
172
+ /**
173
+ * An ABSENCE state — `CR-112`'s grammar, exit code riding with the copy.
174
+ *
175
+ * Rendered to STDOUT: absence is an ANSWER. ⚠ And the `fix` sentence renders
176
+ * even with no command beside it — `renderErrorBlock` drops `fixLabel` when
177
+ * `fixes` is empty, which is how state 5's remedy silently vanished for a whole
178
+ * wave (`CR-109d`). Both `report` states DO have a command, so they take the
179
+ * ordinary path; the shape is written this way so they cannot lose it later.
180
+ */
181
+ function absence(ctx, what, why, fixLabel, fixes) {
182
+ const block = fixes.length > 0
183
+ ? { kind: "warn", what, why: [why], fixLabel, fixes }
184
+ : { kind: "warn", what, why: [why] };
185
+ const lines = [...renderErrorBlock(block, ctx.colour)];
186
+ if (fixes.length === 0)
187
+ lines.push("", ...wrap(fixLabel, 4));
188
+ writeLines(ctx.stdout, lines);
189
+ return EXIT.empty;
190
+ }
191
+ /** `notAuthorized`'s six outcomes, the same six `why` renders. */
192
+ function notAuthorized(ctx, authorized) {
193
+ switch (authorized.kind) {
194
+ case "no-session":
195
+ return fail(ctx, errorCopy(WHY.signedOutWhat, WHY.signedOutWhy, WHY.signedOutFix, COMMANDS.signIn), EXIT.notConnected);
196
+ case "expired":
197
+ return fail(ctx, errorCopy(SIGNIN.expiredWhat, SIGNIN.expiredWhy, SIGNIN.expiredFix, COMMANDS.signIn), EXIT.notConnected);
198
+ case "busy":
199
+ return fail(ctx, errorCopy(SIGNIN.busyWhat, SIGNIN.busyWhy, SIGNIN.busyFix, COMMANDS.report), EXIT.failure);
200
+ case "unreachable":
201
+ return fail(ctx, errorCopy(WHY.unreachableWhat, WHY.unreachableWhy, WHY.readFix, COMMANDS.report), EXIT.failure);
202
+ case "malformed":
203
+ case "ok":
204
+ // `ok` is unreachable by construction — `readWithSession` only wraps a
205
+ // NON-ok outcome. Rendered rather than thrown: a crash here would be a
206
+ // worse answer than an honest failure.
207
+ return fail(ctx, errorCopy(WHY.malformedWhat, WHY.malformedWhy, WHY.readFix, COMMANDS.report), EXIT.failure);
208
+ }
209
+ }
210
+ /**
211
+ * D67's three-part unit. **Together or not at all.**
212
+ *
213
+ * ⚠ The grade mix omits a grade whose count is ZERO, and the total still
214
+ * reconciles against `edgesHeld`. A `0` beside a grade is a measurement claim,
215
+ * not an absence — and `observed` has no producer in any repo (D104 §2a), so
216
+ * rendering `observed: 0` would illustrate a screen the data can never fill.
217
+ */
218
+ function coverageScreen(payload, reachable, percent) {
219
+ const lines = [
220
+ ...wrap(REPORT.definition(payload.ref), BODY_INDENT),
221
+ "",
222
+ ...wrap(REPORT.rate(String(reachable), String(payload.edgesHeld), payload.ref, String(percent)), BODY_INDENT),
223
+ ];
224
+ const parts = GRADE_ORDER.filter((g) => (payload.byGrade[g] ?? 0) > 0).map((g) => REPORT.gradeCount(String(payload.byGrade[g]), GRADE_LABEL[g]));
225
+ if (parts.length > 0) {
226
+ lines.push(...wrap(`${REPORT.gradeMixIntro} ${parts.join(", ")}.`, BODY_INDENT));
227
+ }
228
+ // ⚠ ITS OWN LINE, IN OUR WORDS, NEVER ADDED TO THE RATE ABOVE (D67).
229
+ if (payload.probableCount > 0) {
230
+ const text = payload.probableCount === 1 ? REPORT.probableOne : REPORT.probable(String(payload.probableCount));
231
+ lines.push("", ...wrap(text, BODY_INDENT));
232
+ }
233
+ return lines;
234
+ }
235
+ export async function report(ctx, argv, deps = {}) {
236
+ // §13.3 — `--json` emits nothing but the JSON document on stdout, and D122 §2
237
+ // rules that §13.3 REQUIRES it here. Every FAILURE below is unchanged (§13.6
238
+ // to stderr, nothing on stdout); the three ANSWER states branch.
239
+ const json = argv.includes("--json");
240
+ const args = parseArgs(argv);
241
+ if (args === "usage") {
242
+ return fail(ctx, errorCopy(REPORT.usageWhat, REPORT.usageWhy, REPORT.usageFix, COMMANDS.report), EXIT.usage);
243
+ }
244
+ if (args === "bad-date") {
245
+ return fail(ctx, errorCopy(REPORT.sinceWhat, REPORT.sinceWhy, REPORT.sinceFix, COMMANDS.report), EXIT.usage);
246
+ }
247
+ const projectKey = resolveProjectKey(ctx.cwd);
248
+ if (projectKey === null) {
249
+ writeLines(ctx.stderr, renderErrorBlock({ kind: "bad", what: ERRORS.notAGitRepo, why: [] }, ctx.colour));
250
+ return EXIT.failure;
251
+ }
252
+ // ⚠⚠ THE SHALLOW REFUSAL FIRES FIRST, BEFORE THE REF, BEFORE THE LOCAL LOG
253
+ // AND BEFORE ANY NETWORK CALL. D67 makes it load-bearing rather than
254
+ // defensive, and `strings.ts` addresses a contract to this verb BY NAME: *"the
255
+ // caller MUST establish that the clone is complete before selecting either
256
+ // `report` empty state"* — because on a shallow clone *"no commits in this
257
+ // window"* is a claim the clone cannot support. State 3's sentence is written
258
+ // unqualified precisely because this refusal guarantees it.
259
+ if (isShallowClone(projectKey)) {
260
+ return fail(ctx, errorCopy(REPORT.shallowWhat, REPORT.shallowWhy, WHY.shallowFix, WHY.shallowFixCommand), EXIT.failure);
261
+ }
262
+ const ref = args.ref ?? currentBranch(projectKey);
263
+ if (ref === null) {
264
+ return fail(ctx, errorCopy(REPORT.refWhat, REPORT.refWhy, REPORT.refFix, COMMANDS.reportRef), EXIT.usage);
265
+ }
266
+ // ⚠ THE WINDOW IS A LOCAL FACT, and so are both empty states. `git log`
267
+ // answers "what commits are on this ref in this window" without a server,
268
+ // which is what lets state 3 render before anything is read.
269
+ const log = gitProbe(projectKey, ["log", "--format=%H", `--since=${args.since}`, ref, "--"]);
270
+ if (log === null) {
271
+ return fail(ctx, errorCopy(REPORT.refWhat, REPORT.refWhy, REPORT.refFix, COMMANDS.reportRef), EXIT.usage);
272
+ }
273
+ const windowShas = log.split("\n").filter((line) => line.trim() !== "");
274
+ const window = REPORT.window(args.since);
275
+ if (windowShas.length === 0) {
276
+ // STATE 3 — no commits at all. Different fact from state 4, and collapsing
277
+ // them would read as a coverage claim we cannot make.
278
+ //
279
+ // ⛔ THE SERVER WAS NEVER ASKED ON THIS PATH, so every counted field is
280
+ // `null` — NOT KNOWN — and not `0`. A zero here would be a measurement claim
281
+ // about a measurement that was never taken (`CR-129a`), and it is exactly
282
+ // what makes this state distinguishable from state 4 below, where the server
283
+ // DID answer and DID say zero. That distinction is the whole of "not known"
284
+ // vs "none" on this verb.
285
+ if (json) {
286
+ emitJson(ctx.stdout, "report", "no_commits", {
287
+ since: args.since,
288
+ ref,
289
+ window_commits: 0,
290
+ edges_held: null,
291
+ by_grade: null,
292
+ reachable: null,
293
+ exact_successors: null,
294
+ counted: null,
295
+ percent: null,
296
+ probable_count: null,
297
+ });
298
+ return EXIT.empty;
299
+ }
300
+ return absence(ctx, ABSENCE.reportNoCommits.what(ref, window), ABSENCE.reportNoCommits.why(ref), ABSENCE.reportNoCommits.fix, [COMMANDS.report]);
301
+ }
302
+ const endpoint = mcpUrl(ctx.env);
303
+ if (endpoint === null) {
304
+ return fail(ctx, errorCopy(SIGNIN.noServerWhat, SIGNIN.noServerRefusedWhy, WHY.readFix, COMMANDS.report), EXIT.failure);
305
+ }
306
+ const read = deps.read ?? readWithSession;
307
+ const outcome = await read(endpoint, "commit_coverage",
308
+ // ⚠ `repo` (the slug) — NOT `repository_id`. `CR-142` gave the tool a slug
309
+ // form because this client holds a slug and nothing else, and the two are
310
+ // EXACTLY-ONE: supplying both is refused rather than resolved by precedence.
311
+ { repo: resolveRepoSlug(projectKey), ref }, {
312
+ home: ctx.home,
313
+ fetch,
314
+ nowMs: () => ctx.now().getTime(),
315
+ read: { fetch, timeoutMs: READ_TIMEOUT_MS },
316
+ });
317
+ return render(ctx, outcome, projectKey, ref, window, windowShas.length, {
318
+ json,
319
+ since: args.since,
320
+ });
321
+ }
322
+ /** Every arm of `Read`, and every arm of `Authorized` inside one of them. */
323
+ function render(ctx, outcome, projectKey, ref, window, windowCommits, opts) {
324
+ switch (outcome.kind) {
325
+ case "not-authorized":
326
+ return notAuthorized(ctx, outcome.authorized);
327
+ case "unauthorized":
328
+ return fail(ctx, errorCopy(WHY.signedOutWhat, WHY.signedOutWhy, WHY.signedOutFix, COMMANDS.signIn), EXIT.notConnected);
329
+ case "unreachable":
330
+ return fail(ctx, errorCopy(WHY.unreachableWhat, WHY.unreachableWhy, WHY.readFix, COMMANDS.report), EXIT.failure);
331
+ case "rpc-error":
332
+ // ⚠ Never a bare HTTP status or a raw JSON-RPC code on screen (§13.6).
333
+ return fail(ctx, errorCopy(WHY.serverErrorWhat, WHY.serverErrorWhy, WHY.readFix, COMMANDS.report), EXIT.failure);
334
+ case "malformed":
335
+ return fail(ctx, errorCopy(WHY.malformedWhat, WHY.malformedWhy, WHY.readFix, COMMANDS.report), EXIT.failure);
336
+ case "ok": {
337
+ // ⚠ `isError` rides the SAME envelope as a success. A caller that only
338
+ // branched on the transport would read a tool failure as a record.
339
+ if (outcome.isError) {
340
+ return fail(ctx, errorCopy(WHY.serverErrorWhat, WHY.serverErrorWhy, WHY.readFix, COMMANDS.report), EXIT.failure);
341
+ }
342
+ const payload = parseCoveragePayload(outcome.document);
343
+ if (payload === null) {
344
+ return fail(ctx, errorCopy(WHY.malformedWhat, WHY.malformedWhy, WHY.readFix, COMMANDS.report), EXIT.failure);
345
+ }
346
+ return renderPayload(ctx, payload, projectKey, ref, window, windowCommits, opts);
347
+ }
348
+ }
349
+ }
350
+ function renderPayload(ctx, payload, projectKey, ref, window, windowCommits, opts) {
351
+ // STATE 4 — commits exist and we hold no session for any of them. The counted
352
+ // commits are the whole difference from state 3.
353
+ if (payload.edgesHeld === 0) {
354
+ // ⚠ `edges_held` IS `0` HERE AND `null` IN STATE 3, and the difference is
355
+ // the point: the server answered and said none, where state 3 never asked.
356
+ // `percent` stays `null` because the denominator is zero — 0/0 is not 0%,
357
+ // and printing `0` would be a coverage claim from no data.
358
+ //
359
+ // ⛔ `by_grade` IS ECHOED, NEVER WIDENED TO THE ENUM. `observed` has no
360
+ // producer in any repo (D104 §2a), so a key the payload did not carry stays
361
+ // absent rather than becoming a zero we never counted.
362
+ if (opts.json) {
363
+ emitJson(ctx.stdout, "report", "no_sessions", {
364
+ since: opts.since,
365
+ ref: payload.ref,
366
+ window_commits: windowCommits,
367
+ edges_held: 0,
368
+ by_grade: payload.byGrade,
369
+ reachable: null,
370
+ exact_successors: payload.exactSuccessors,
371
+ counted: null,
372
+ percent: null,
373
+ probable_count: payload.probableCount,
374
+ });
375
+ return EXIT.empty;
376
+ }
377
+ return absence(ctx, ABSENCE.reportNoSessions.what(String(windowCommits), window), ABSENCE.reportNoSessions.why, ABSENCE.reportNoSessions.fix, [COMMANDS.report]);
378
+ }
379
+ // ⚠ THE CLIENT HALF OF D67's SPLIT. Reachability is a question about the
380
+ // user's clone and the server has no repository, so it is asked here.
381
+ let reachable = 0;
382
+ for (const sha of payload.capturedShas) {
383
+ const answer = isReachable(projectKey, sha, ref);
384
+ // ⚠ FAILS CLOSED. An unanswerable probe is not a "no": counting it as
385
+ // unreachable would DEFLATE the rate and present a smaller number as a
386
+ // complete one, which is D98's class on the number that matters most.
387
+ if (answer === null) {
388
+ return fail(ctx, errorCopy(REPORT.unknownReachabilityWhat, REPORT.unknownReachabilityWhy, REPORT.unknownReachabilityFix, WHY.shallowFixCommand), EXIT.failure);
389
+ }
390
+ if (answer)
391
+ reachable += 1;
392
+ }
393
+ // ⚠ ONLY EXACT SUCCESSORS JOIN THE NUMERATOR (D67). A commit that was
394
+ // rewritten is still reachable through the successor we hold a recorded row
395
+ // for; a patch-id guess is NOT, and it renders on its own line instead.
396
+ const numerator = reachable + payload.exactSuccessors;
397
+ if (numerator > payload.edgesHeld) {
398
+ // The payload disagrees with the clone about its own totals. A rate over
399
+ // 100% is not a number to print, and clamping it would hide the disagreement
400
+ // behind a plausible figure.
401
+ return fail(ctx, errorCopy(WHY.malformedWhat, WHY.malformedWhy, WHY.readFix, COMMANDS.report), EXIT.failure);
402
+ }
403
+ const percent = Math.round((numerator / payload.edgesHeld) * 100);
404
+ // §13.3 — the machine surface, and THE ONE PLACE THE GRADE MIX IS READABLE AS
405
+ // GRADES. `coverageScreen` renders D67's three-part unit through the copy
406
+ // labels and prints no grade word at all; here the wire's own map is echoed.
407
+ //
408
+ // ⚠ `reachable` and `exact_successors` are reported SEPARATELY as well as in
409
+ // `counted`, because D67 forbids folding a patch-id guess into the rate and a
410
+ // consumer that only saw the total could not tell the halves apart.
411
+ // `probable_count` rides alongside for the same reason and is never added in.
412
+ if (opts.json) {
413
+ emitJson(ctx.stdout, "report", "coverage", {
414
+ since: opts.since,
415
+ ref: payload.ref,
416
+ window_commits: windowCommits,
417
+ edges_held: payload.edgesHeld,
418
+ by_grade: payload.byGrade,
419
+ reachable,
420
+ exact_successors: payload.exactSuccessors,
421
+ counted: numerator,
422
+ percent,
423
+ probable_count: payload.probableCount,
424
+ });
425
+ return EXIT.ok;
426
+ }
427
+ writeLines(ctx.stdout, coverageScreen(payload, numerator, percent));
428
+ return EXIT.ok;
429
+ }
430
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/commands/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * `vibecommit status` and `vibecommit off` — the screen, `CR-021`.
3
+ *
4
+ * Style guide §10.3 draws it and D65 makes that drawing the ruling, so this
5
+ * module renders it rather than designing it: four questions in fixed order
6
+ * (on for *this* repo? last successful send? where do I look? what do I type to
7
+ * fix it?), then the revoke link, on §13.5's `LABEL_GUTTER`.
8
+ *
9
+ * ## What is deliberately NOT on the screen
10
+ *
11
+ * §10.3's `last sent` row reads `4 minutes ago · 3 turns · seq 41`. **The turn
12
+ * count is not rendered and must not be.** Counting turns means parsing the
13
+ * transcript's NDJSON and deciding what a turn is, and that is the analysis the
14
+ * client is barred from holding — D60 §D6: *the client may render; it may not
15
+ * analyze, hash, or canonicalize*. The one recorded deviation is `CR-024d`'s
16
+ * redaction parse, authorised by name; there is no such authorisation here, and
17
+ * the server is the only thing holding sealed turns to count. The age and the
18
+ * `seq` are both facts this client already wrote down, so both render.
19
+ *
20
+ * ## Absence is not a blank
21
+ *
22
+ * When nothing has been delivered for this repo the row is OMITTED and
23
+ * `STATUS.neverSent` says so in a sentence. No sixth absence phrasing is
24
+ * invented here: `CR-112` (W8) owns the five-absence grammar as one set, and
25
+ * adding a variant now is what that task exists to prevent.
26
+ */
27
+ import { type CommandContext } from "./context.js";
28
+ export declare function status(ctx: CommandContext, argv?: readonly string[]): number;
29
+ export declare function off(ctx: CommandContext): number;