@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 @@
1
+ {"version":3,"file":"strings.js","sourceRoot":"","sources":["../../src/copy/strings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Relative ages, for the one row that has one — `CR-021`, style guide §10.3.
3
+ *
4
+ * In `copy/` and not in a command body because it produces USER-FACING TEXT,
5
+ * which is the whole rule this directory exists for (`strings.ts`'s header): a
6
+ * quoted string inside a verb is the CR-090 precondition-1 violation. It is a
7
+ * function rather than a constant for the same reason `unsupportedRuntime` is —
8
+ * the sentence is templated on a value.
9
+ *
10
+ * No `Intl.RelativeTimeFormat`. Its output is locale-dependent, and §13.4's rule
11
+ * that identical commands emit identical bytes is what makes screenshots, issue
12
+ * pastes and golden-file tests comparable. A fixed English phrase is the same
13
+ * choice `renderHelp` already makes by never reflowing to `stdout.columns`.
14
+ */
15
+ /**
16
+ * How long ago `thenMs` was, as one phrase.
17
+ *
18
+ * Deliberately coarse: the caller is a human asking "is capture working?", and a
19
+ * second-precision answer invites a precision the record does not have — the
20
+ * stamp is written when the client's POST returned, not when the server sealed
21
+ * the turn.
22
+ *
23
+ * A future timestamp (a clock that moved backwards, a state file copied between
24
+ * machines) reads as `just now` rather than as a negative age. It is the one
25
+ * answer that is never wrong in a way that misleads.
26
+ */
27
+ export declare function relativeAge(thenMs: number, nowMs: number): string;
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Relative ages, for the one row that has one — `CR-021`, style guide §10.3.
3
+ *
4
+ * In `copy/` and not in a command body because it produces USER-FACING TEXT,
5
+ * which is the whole rule this directory exists for (`strings.ts`'s header): a
6
+ * quoted string inside a verb is the CR-090 precondition-1 violation. It is a
7
+ * function rather than a constant for the same reason `unsupportedRuntime` is —
8
+ * the sentence is templated on a value.
9
+ *
10
+ * No `Intl.RelativeTimeFormat`. Its output is locale-dependent, and §13.4's rule
11
+ * that identical commands emit identical bytes is what makes screenshots, issue
12
+ * pastes and golden-file tests comparable. A fixed English phrase is the same
13
+ * choice `renderHelp` already makes by never reflowing to `stdout.columns`.
14
+ */
15
+ const MINUTE_MS = 60_000;
16
+ const HOUR_MS = 60 * MINUTE_MS;
17
+ const DAY_MS = 24 * HOUR_MS;
18
+ /**
19
+ * How long ago `thenMs` was, as one phrase.
20
+ *
21
+ * Deliberately coarse: the caller is a human asking "is capture working?", and a
22
+ * second-precision answer invites a precision the record does not have — the
23
+ * stamp is written when the client's POST returned, not when the server sealed
24
+ * the turn.
25
+ *
26
+ * A future timestamp (a clock that moved backwards, a state file copied between
27
+ * machines) reads as `just now` rather than as a negative age. It is the one
28
+ * answer that is never wrong in a way that misleads.
29
+ */
30
+ export function relativeAge(thenMs, nowMs) {
31
+ const elapsed = nowMs - thenMs;
32
+ if (elapsed < MINUTE_MS)
33
+ return "just now";
34
+ if (elapsed < HOUR_MS)
35
+ return plural(Math.floor(elapsed / MINUTE_MS), "minute");
36
+ if (elapsed < DAY_MS)
37
+ return plural(Math.floor(elapsed / HOUR_MS), "hour");
38
+ return plural(Math.floor(elapsed / DAY_MS), "day");
39
+ }
40
+ function plural(count, unit) {
41
+ return `${count} ${unit}${count === 1 ? "" : "s"} ago`;
42
+ }
43
+ //# sourceMappingURL=time.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.js","sourceRoot":"","sources":["../../src/copy/time.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,SAAS,GAAG,MAAM,CAAC;AACzB,MAAM,OAAO,GAAG,EAAE,GAAG,SAAS,CAAC;AAC/B,MAAM,MAAM,GAAG,EAAE,GAAG,OAAO,CAAC;AAE5B;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,KAAa;IACvD,MAAM,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;IAC/B,IAAI,OAAO,GAAG,SAAS;QAAE,OAAO,UAAU,CAAC;IAC3C,IAAI,OAAO,GAAG,OAAO;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAC;IAChF,IAAI,OAAO,GAAG,MAAM;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;IAC3E,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,MAAM,CAAC,KAAa,EAAE,IAAY;IACzC,OAAO,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;AACzD,CAAC"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * The ingest credential — load, carry, redact.
3
+ *
4
+ * THE INVARIANT, and the whole reason `/cso` is mandatory on this file: the
5
+ * credential is an **opaque secret**. Never parse it. Never log it.
6
+ *
7
+ * It is NOT a JWT and must never be treated as one. W2 (`CR-009`/`CR-010`/
8
+ * `CR-011`) found that a `vcik_` token already fails at `/mcp` for an entirely
9
+ * incidental reason — base64url has no dots, so the JWT verifier rejects it
10
+ * before any audience check runs. Any client that "validates" the credential by
11
+ * decomposing it inherits that trap: it would appear to work while checking
12
+ * something else entirely.
13
+ *
14
+ * ## How the plaintext is kept out of logs
15
+ *
16
+ * A bare `string` leaks through every ordinary path: template interpolation,
17
+ * `JSON.stringify`, `console.error(obj)`, an unhandled rejection whose message
18
+ * embedded it. So the plaintext never travels as a bare string — it travels
19
+ * inside `IngestCredential`, whose `toString`, `toJSON` and Node inspect hook
20
+ * all render `vcik_…redacted`. Reaching the plaintext requires calling
21
+ * `expose()`, which is deliberately ugly and greppable.
22
+ *
23
+ * That is a real control, not a ceremony: `test/credential.test.ts` proves it can
24
+ * go red by asserting each redaction path against the raw secret.
25
+ *
26
+ * ## Precedence
27
+ *
28
+ * `VIBECOMMIT_TOKEN` is read **BEFORE** `~/.vibecommit/credentials.json`, for
29
+ * headless and CI use (D56 plan, founder call).
30
+ *
31
+ * Wire contract retyped from `vibecommit-mcp/src/oauth/ingest_credential.ts`
32
+ * (prefix, opacity, no rotation). Nothing is imported from that package and
33
+ * nothing may be: it is closed source and this package is MIT (D60 §D1a).
34
+ *
35
+ * @provenance vibecommit-mcp src/oauth/ingest_credential.ts — wire contract, retyped
36
+ */
37
+ /**
38
+ * Retyped from `INGEST_CREDENTIAL_TOKEN_PREFIX` in the closed-source server.
39
+ * Its job there is to make a leaked credential greppable and to keep a plaintext
40
+ * from ever being mistaken for a hex digest. Its job HERE is narrower: refuse to
41
+ * put a credential of the wrong class on the ingest lane.
42
+ */
43
+ export declare const INGEST_TOKEN_PREFIX = "vcik_";
44
+ /** What a redacted credential renders as. Contains no bytes of the secret. */
45
+ export declare const REDACTED = "vcik_\u2026redacted";
46
+ /**
47
+ * An opaque ingest credential.
48
+ *
49
+ * Every ordinary way of turning a value into text renders `REDACTED`. The
50
+ * plaintext leaves only through `expose()`.
51
+ */
52
+ export declare class IngestCredential {
53
+ #private;
54
+ /** Where it came from. Safe to log — names a source, not a value. */
55
+ readonly source: CredentialSource;
56
+ constructor(secret: string, source: CredentialSource);
57
+ /** The plaintext. The ONLY exit. Call this at the request boundary, nowhere else. */
58
+ expose(): string;
59
+ toString(): string;
60
+ toJSON(): string;
61
+ get [Symbol.toStringTag](): string;
62
+ }
63
+ export type CredentialSource = "env" | "file";
64
+ export type CredentialLoad = {
65
+ readonly kind: "ok";
66
+ readonly credential: IngestCredential;
67
+ } | {
68
+ readonly kind: "absent";
69
+ }
70
+ /**
71
+ * Present but not an ingest credential. Refused CLIENT-side and never sent:
72
+ * a control-plane token put on the data plane would be a privilege class
73
+ * crossing a lane boundary, and the fact that the server's audience wall
74
+ * (`CR-010`) would also reject it is defence in depth, not a reason to try.
75
+ */
76
+ | {
77
+ readonly kind: "wrong-class";
78
+ readonly source: CredentialSource;
79
+ }
80
+ /** File exists but is readable by group or other. Refused rather than used. */
81
+ | {
82
+ readonly kind: "insecure-file";
83
+ readonly path: string;
84
+ readonly mode: string;
85
+ } | {
86
+ readonly kind: "unreadable";
87
+ readonly path: string;
88
+ };
89
+ export interface CredentialEnvironment {
90
+ readonly env: NodeJS.ProcessEnv;
91
+ readonly home: string;
92
+ }
93
+ /** What `readSecretFile` returns. The two not-ok cases are `CredentialLoad`'s. */
94
+ export type SecretFileRead = {
95
+ readonly kind: "ok";
96
+ readonly raw: string;
97
+ } | {
98
+ readonly kind: "absent";
99
+ } | {
100
+ readonly kind: "insecure-file";
101
+ readonly path: string;
102
+ readonly mode: string;
103
+ };
104
+ /**
105
+ * Read a file under `~/.vibecommit/` that holds a secret, refusing an insecure
106
+ * one — **the two checks the human lane INHERITS rather than copies**.
107
+ *
108
+ * It was inline in `loadCredential` while the ingest credential was the only
109
+ * secret on disk. `CR-084d` adds a second (the refresh token), and a second copy
110
+ * of a security check is a second thing to forget when the first one changes —
111
+ * so it is one function with two callers instead.
112
+ *
113
+ * `/cso` finding 3 (2026-08-09), MEDIUM, is the DIRECTORY half. The FILE's mode
114
+ * was checked and the directory's was not, and the directory is the one that
115
+ * matters for the interesting attack: a second local account cannot read a 0600
116
+ * credentials.json, but with a writable `~/.vibecommit` it can unlink it and
117
+ * drop in its own 0600 file. The victim's next hook then uploads their whole
118
+ * transcript stream into the attacker's org. `grantProject` chmods the directory
119
+ * to 0700 on first write, so a clean install is fine — this covers the directory
120
+ * that already existed.
121
+ */
122
+ export declare function readSecretFile(home: string, path: string): SecretFileRead;
123
+ /**
124
+ * Load the ingest credential. `VIBECOMMIT_TOKEN` first, then the credentials
125
+ * file.
126
+ *
127
+ * Returns a discriminated union rather than throwing: the hook path must not
128
+ * take an exception for a missing credential, and the interactive path wants to
129
+ * distinguish the four not-ok outcomes to print four different fixes.
130
+ */
131
+ export declare function loadCredential(ctx: CredentialEnvironment): CredentialLoad;
132
+ /**
133
+ * Belt and braces for the `inspect` path specifically.
134
+ *
135
+ * `util.inspect` honours the custom symbol on the instance, but a credential
136
+ * nested inside a plain object that someone stringifies with `%o` should also
137
+ * come out redacted. Exposed so tests can assert it rather than assume it.
138
+ */
139
+ export declare function describeCredential(value: unknown): string;
140
+ /** What a redacted refresh token renders as. Contains no bytes of the secret. */
141
+ export declare const REDACTED_REFRESH = "refresh\u2026redacted";
142
+ /** What a redacted access token renders as. Contains no bytes of the secret. */
143
+ export declare const REDACTED_ACCESS = "access\u2026redacted";
144
+ /**
145
+ * The base of both user-principal token types.
146
+ *
147
+ * A shared base rather than two copies: every redaction path is defined once, so
148
+ * a fifth rendering path discovered later is closed for both at once. The marker
149
+ * is per-subclass because a redacted string that could not say WHICH token it
150
+ * stood for would make a log line ambiguous exactly when someone is debugging an
151
+ * auth failure.
152
+ */
153
+ declare abstract class OpaqueToken {
154
+ #private;
155
+ protected constructor(secret: string);
156
+ protected abstract marker(): string;
157
+ /** The plaintext. The ONLY exit. Call this at the request boundary, nowhere else. */
158
+ expose(): string;
159
+ toString(): string;
160
+ toJSON(): string;
161
+ get [Symbol.toStringTag](): string;
162
+ }
163
+ /**
164
+ * The long-lived half of the human lane: rotated on every use, 90-day family cap.
165
+ *
166
+ * ⚠ Presenting one twice is a REPLAY to the server and revokes the whole family
167
+ * (`refresh.ts`'s `reuse_detected`). That is why `oauth/lock.ts` exists — see
168
+ * its module note, which is the single most consequential comment in this task.
169
+ */
170
+ export declare class RefreshToken extends OpaqueToken {
171
+ constructor(secret: string);
172
+ protected marker(): string;
173
+ }
174
+ /**
175
+ * The short-lived half: an RS256 JWT, `aud` = the `/mcp` audience, ~900 seconds.
176
+ *
177
+ * Held as an opaque token DESPITE being a JWT, and the distinction is worth
178
+ * stating: a JWT's payload is readable by anyone holding it, so "opaque" here is
179
+ * about not LOGGING it, not about not parsing it. Nothing in this client parses
180
+ * it — the expiry travels beside it as data from the token response, because
181
+ * trusting a claim inside a token to decide whether to refresh that token is
182
+ * asking the thing being validated to validate itself.
183
+ */
184
+ export declare class AccessToken extends OpaqueToken {
185
+ constructor(secret: string);
186
+ protected marker(): string;
187
+ }
188
+ /**
189
+ * Is this string a refresh token rather than something else in the wrong slot?
190
+ *
191
+ * The server mints it as 32 random bytes, base64url-encoded and unpadded
192
+ * (`refresh.ts`'s `mintRefreshToken`). It therefore has NO dots — so a JWT is
193
+ * refused — and it does not carry the ingest prefix, so a `vcik_` is refused.
194
+ *
195
+ * ⚠ This is a CLASS check, not a validity check. It answers "is this the right
196
+ * KIND of secret for this slot", which is a question the client can answer
197
+ * locally; whether the token is live is the server's answer and is never guessed
198
+ * here. Same discipline as the ingest credential: never parse the secret.
199
+ */
200
+ export declare function isRefreshTokenShape(value: string): boolean;
201
+ /**
202
+ * Is this string an access token rather than something else in the wrong slot?
203
+ *
204
+ * Three non-empty dot-separated base64url segments — the JWS Compact
205
+ * Serialization shape (RFC 7515 §3.1). This is the mirror of the trap recorded
206
+ * at the top of this file: a `vcik_` is base64url with NO dots, so it fails here
207
+ * for the same structural reason it fails the server's JWT verifier, and it
208
+ * cannot be smuggled into the bearer position of a read.
209
+ */
210
+ export declare function isAccessTokenShape(value: string): boolean;
211
+ export {};
@@ -0,0 +1,298 @@
1
+ /**
2
+ * The ingest credential — load, carry, redact.
3
+ *
4
+ * THE INVARIANT, and the whole reason `/cso` is mandatory on this file: the
5
+ * credential is an **opaque secret**. Never parse it. Never log it.
6
+ *
7
+ * It is NOT a JWT and must never be treated as one. W2 (`CR-009`/`CR-010`/
8
+ * `CR-011`) found that a `vcik_` token already fails at `/mcp` for an entirely
9
+ * incidental reason — base64url has no dots, so the JWT verifier rejects it
10
+ * before any audience check runs. Any client that "validates" the credential by
11
+ * decomposing it inherits that trap: it would appear to work while checking
12
+ * something else entirely.
13
+ *
14
+ * ## How the plaintext is kept out of logs
15
+ *
16
+ * A bare `string` leaks through every ordinary path: template interpolation,
17
+ * `JSON.stringify`, `console.error(obj)`, an unhandled rejection whose message
18
+ * embedded it. So the plaintext never travels as a bare string — it travels
19
+ * inside `IngestCredential`, whose `toString`, `toJSON` and Node inspect hook
20
+ * all render `vcik_…redacted`. Reaching the plaintext requires calling
21
+ * `expose()`, which is deliberately ugly and greppable.
22
+ *
23
+ * That is a real control, not a ceremony: `test/credential.test.ts` proves it can
24
+ * go red by asserting each redaction path against the raw secret.
25
+ *
26
+ * ## Precedence
27
+ *
28
+ * `VIBECOMMIT_TOKEN` is read **BEFORE** `~/.vibecommit/credentials.json`, for
29
+ * headless and CI use (D56 plan, founder call).
30
+ *
31
+ * Wire contract retyped from `vibecommit-mcp/src/oauth/ingest_credential.ts`
32
+ * (prefix, opacity, no rotation). Nothing is imported from that package and
33
+ * nothing may be: it is closed source and this package is MIT (D60 §D1a).
34
+ *
35
+ * @provenance vibecommit-mcp src/oauth/ingest_credential.ts — wire contract, retyped
36
+ */
37
+ import { lstatSync, readFileSync, statSync } from "node:fs";
38
+ import { inspect } from "node:util";
39
+ import { credentialsPath, rootDir } from "./paths.js";
40
+ /**
41
+ * Retyped from `INGEST_CREDENTIAL_TOKEN_PREFIX` in the closed-source server.
42
+ * Its job there is to make a leaked credential greppable and to keep a plaintext
43
+ * from ever being mistaken for a hex digest. Its job HERE is narrower: refuse to
44
+ * put a credential of the wrong class on the ingest lane.
45
+ */
46
+ export const INGEST_TOKEN_PREFIX = "vcik_";
47
+ /** What a redacted credential renders as. Contains no bytes of the secret. */
48
+ export const REDACTED = `${INGEST_TOKEN_PREFIX}…redacted`;
49
+ /**
50
+ * An opaque ingest credential.
51
+ *
52
+ * Every ordinary way of turning a value into text renders `REDACTED`. The
53
+ * plaintext leaves only through `expose()`.
54
+ */
55
+ export class IngestCredential {
56
+ #secret;
57
+ /** Where it came from. Safe to log — names a source, not a value. */
58
+ source;
59
+ constructor(secret, source) {
60
+ this.#secret = secret;
61
+ this.source = source;
62
+ }
63
+ /** The plaintext. The ONLY exit. Call this at the request boundary, nowhere else. */
64
+ expose() {
65
+ return this.#secret;
66
+ }
67
+ toString() {
68
+ return REDACTED;
69
+ }
70
+ toJSON() {
71
+ return REDACTED;
72
+ }
73
+ [Symbol.for("nodejs.util.inspect.custom")]() {
74
+ return REDACTED;
75
+ }
76
+ get [Symbol.toStringTag]() {
77
+ return REDACTED;
78
+ }
79
+ }
80
+ /**
81
+ * Read a file under `~/.vibecommit/` that holds a secret, refusing an insecure
82
+ * one — **the two checks the human lane INHERITS rather than copies**.
83
+ *
84
+ * It was inline in `loadCredential` while the ingest credential was the only
85
+ * secret on disk. `CR-084d` adds a second (the refresh token), and a second copy
86
+ * of a security check is a second thing to forget when the first one changes —
87
+ * so it is one function with two callers instead.
88
+ *
89
+ * `/cso` finding 3 (2026-08-09), MEDIUM, is the DIRECTORY half. The FILE's mode
90
+ * was checked and the directory's was not, and the directory is the one that
91
+ * matters for the interesting attack: a second local account cannot read a 0600
92
+ * credentials.json, but with a writable `~/.vibecommit` it can unlink it and
93
+ * drop in its own 0600 file. The victim's next hook then uploads their whole
94
+ * transcript stream into the attacker's org. `grantProject` chmods the directory
95
+ * to 0700 on first write, so a clean install is fine — this covers the directory
96
+ * that already existed.
97
+ */
98
+ export function readSecretFile(home, path) {
99
+ try {
100
+ const dir = rootDir(home);
101
+ const dirMode = statSync(dir).mode & 0o777;
102
+ if ((dirMode & 0o077) !== 0) {
103
+ return { kind: "insecure-file", path: dir, mode: dirMode.toString(8).padStart(3, "0") };
104
+ }
105
+ // `lstat`, not `stat`: `stat` follows a symlink and would report the
106
+ // TARGET's mode, so a link to an attacker-owned 0600 file would pass a
107
+ // check that exists to establish who can read this one.
108
+ const mode = lstatSync(path).mode & 0o777;
109
+ if ((mode & 0o077) !== 0) {
110
+ return { kind: "insecure-file", path, mode: mode.toString(8).padStart(3, "0") };
111
+ }
112
+ return { kind: "ok", raw: readFileSync(path, "utf8") };
113
+ }
114
+ catch {
115
+ // ENOENT is the overwhelmingly common case — not connected yet.
116
+ return { kind: "absent" };
117
+ }
118
+ }
119
+ /**
120
+ * Load the ingest credential. `VIBECOMMIT_TOKEN` first, then the credentials
121
+ * file.
122
+ *
123
+ * Returns a discriminated union rather than throwing: the hook path must not
124
+ * take an exception for a missing credential, and the interactive path wants to
125
+ * distinguish the four not-ok outcomes to print four different fixes.
126
+ */
127
+ export function loadCredential(ctx) {
128
+ const fromEnv = ctx.env.VIBECOMMIT_TOKEN;
129
+ if (fromEnv !== undefined && fromEnv.trim() !== "") {
130
+ const secret = fromEnv.trim();
131
+ if (!secret.startsWith(INGEST_TOKEN_PREFIX)) {
132
+ return { kind: "wrong-class", source: "env" };
133
+ }
134
+ return { kind: "ok", credential: new IngestCredential(secret, "env") };
135
+ }
136
+ const path = credentialsPath(ctx.home);
137
+ const read = readSecretFile(ctx.home, path);
138
+ if (read.kind !== "ok")
139
+ return read;
140
+ const raw = read.raw;
141
+ let token;
142
+ try {
143
+ // Parsing the FILE is not parsing the CREDENTIAL. The file is our own JSON
144
+ // envelope; the credential is the opaque string inside it and stays opaque.
145
+ token = JSON.parse(raw).token;
146
+ }
147
+ catch {
148
+ return { kind: "unreadable", path };
149
+ }
150
+ if (typeof token !== "string" || token.trim() === "") {
151
+ return { kind: "unreadable", path };
152
+ }
153
+ const secret = token.trim();
154
+ if (!secret.startsWith(INGEST_TOKEN_PREFIX)) {
155
+ return { kind: "wrong-class", source: "file" };
156
+ }
157
+ return { kind: "ok", credential: new IngestCredential(secret, "file") };
158
+ }
159
+ /**
160
+ * Belt and braces for the `inspect` path specifically.
161
+ *
162
+ * `util.inspect` honours the custom symbol on the instance, but a credential
163
+ * nested inside a plain object that someone stringifies with `%o` should also
164
+ * come out redacted. Exposed so tests can assert it rather than assume it.
165
+ */
166
+ export function describeCredential(value) {
167
+ return inspect(value, { depth: 3 });
168
+ }
169
+ // ---------------------------------------------------------------------------
170
+ // CR-084d — THE SECOND SLOT: the human lane's user-principal tokens.
171
+ //
172
+ // One sign-in, two token classes, and they are kept apart on purpose:
173
+ //
174
+ // * the OPAQUE ingest credential above (`vcik_`), long-lived, no rotation,
175
+ // machine-scoped, for the hook lane;
176
+ // * a REFRESH TOKEN and a short-lived ACCESS TOKEN below, user-scoped, for the
177
+ // read lane's `tools/call` against `/mcp`.
178
+ //
179
+ // ⚠ `loadCredential`'s `wrong-class` refusal above is NOT widened, and widening
180
+ // it is the obvious wrong move a later reader will make. `credential.ts:96-102`
181
+ // says why: a control-plane token on the data plane is a privilege class
182
+ // crossing a lane, and the server's audience wall rejecting it too is defence in
183
+ // depth rather than a reason to try. The refusal is now mirrored in BOTH
184
+ // directions — a `vcik_` put in the refresh slot is refused just as a JWT put in
185
+ // the ingest slot is — so neither lane can be fed the other's secret by a
186
+ // copy-paste into the wrong file.
187
+ //
188
+ // ⚠ AND THE REDACTION DISCIPLINE IS NOT CEREMONY HERE EITHER — it matters MORE.
189
+ // The module note at the top of this file lists the four leak paths a bare
190
+ // `string` has (template interpolation, `JSON.stringify`, `console.error(obj)`,
191
+ // an unhandled rejection whose message embedded it). A user-principal token has
192
+ // MORE authority than an ingest credential: it reads a user's history rather
193
+ // than appending to one org's. Shipping it as a bare string would reopen that
194
+ // whole leak class on the more dangerous secret, so both classes below carry the
195
+ // same four renderers and the same deliberately-ugly `expose()`.
196
+ //
197
+ // @provenance vibecommit-mcp src/oauth/refresh.ts — 32-byte base64url opaque refresh token, retyped
198
+ // @provenance vibecommit-mcp src/oauth/token.ts — RFC 6749 §5.1 token response shape, retyped
199
+ // ---------------------------------------------------------------------------
200
+ /** What a redacted refresh token renders as. Contains no bytes of the secret. */
201
+ export const REDACTED_REFRESH = "refresh…redacted";
202
+ /** What a redacted access token renders as. Contains no bytes of the secret. */
203
+ export const REDACTED_ACCESS = "access…redacted";
204
+ /**
205
+ * The base of both user-principal token types.
206
+ *
207
+ * A shared base rather than two copies: every redaction path is defined once, so
208
+ * a fifth rendering path discovered later is closed for both at once. The marker
209
+ * is per-subclass because a redacted string that could not say WHICH token it
210
+ * stood for would make a log line ambiguous exactly when someone is debugging an
211
+ * auth failure.
212
+ */
213
+ class OpaqueToken {
214
+ #secret;
215
+ constructor(secret) {
216
+ this.#secret = secret;
217
+ }
218
+ /** The plaintext. The ONLY exit. Call this at the request boundary, nowhere else. */
219
+ expose() {
220
+ return this.#secret;
221
+ }
222
+ toString() {
223
+ return this.marker();
224
+ }
225
+ toJSON() {
226
+ return this.marker();
227
+ }
228
+ [Symbol.for("nodejs.util.inspect.custom")]() {
229
+ return this.marker();
230
+ }
231
+ get [Symbol.toStringTag]() {
232
+ return this.marker();
233
+ }
234
+ }
235
+ /**
236
+ * The long-lived half of the human lane: rotated on every use, 90-day family cap.
237
+ *
238
+ * ⚠ Presenting one twice is a REPLAY to the server and revokes the whole family
239
+ * (`refresh.ts`'s `reuse_detected`). That is why `oauth/lock.ts` exists — see
240
+ * its module note, which is the single most consequential comment in this task.
241
+ */
242
+ export class RefreshToken extends OpaqueToken {
243
+ constructor(secret) {
244
+ super(secret);
245
+ }
246
+ marker() {
247
+ return REDACTED_REFRESH;
248
+ }
249
+ }
250
+ /**
251
+ * The short-lived half: an RS256 JWT, `aud` = the `/mcp` audience, ~900 seconds.
252
+ *
253
+ * Held as an opaque token DESPITE being a JWT, and the distinction is worth
254
+ * stating: a JWT's payload is readable by anyone holding it, so "opaque" here is
255
+ * about not LOGGING it, not about not parsing it. Nothing in this client parses
256
+ * it — the expiry travels beside it as data from the token response, because
257
+ * trusting a claim inside a token to decide whether to refresh that token is
258
+ * asking the thing being validated to validate itself.
259
+ */
260
+ export class AccessToken extends OpaqueToken {
261
+ constructor(secret) {
262
+ super(secret);
263
+ }
264
+ marker() {
265
+ return REDACTED_ACCESS;
266
+ }
267
+ }
268
+ /**
269
+ * Is this string a refresh token rather than something else in the wrong slot?
270
+ *
271
+ * The server mints it as 32 random bytes, base64url-encoded and unpadded
272
+ * (`refresh.ts`'s `mintRefreshToken`). It therefore has NO dots — so a JWT is
273
+ * refused — and it does not carry the ingest prefix, so a `vcik_` is refused.
274
+ *
275
+ * ⚠ This is a CLASS check, not a validity check. It answers "is this the right
276
+ * KIND of secret for this slot", which is a question the client can answer
277
+ * locally; whether the token is live is the server's answer and is never guessed
278
+ * here. Same discipline as the ingest credential: never parse the secret.
279
+ */
280
+ export function isRefreshTokenShape(value) {
281
+ if (value === "" || value.startsWith(INGEST_TOKEN_PREFIX))
282
+ return false;
283
+ return /^[A-Za-z0-9_-]+$/.test(value);
284
+ }
285
+ /**
286
+ * Is this string an access token rather than something else in the wrong slot?
287
+ *
288
+ * Three non-empty dot-separated base64url segments — the JWS Compact
289
+ * Serialization shape (RFC 7515 §3.1). This is the mirror of the trap recorded
290
+ * at the top of this file: a `vcik_` is base64url with NO dots, so it fails here
291
+ * for the same structural reason it fails the server's JWT verifier, and it
292
+ * cannot be smuggled into the bearer position of a read.
293
+ */
294
+ export function isAccessTokenShape(value) {
295
+ const parts = value.split(".");
296
+ return parts.length === 3 && parts.every((p) => /^[A-Za-z0-9_-]+$/.test(p));
297
+ }
298
+ //# sourceMappingURL=credential.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential.js","sourceRoot":"","sources":["../src/credential.ts"],"names":[],"mappings":"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"}