@vibe-commit/capture 0.6.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/README.md +191 -9
  2. package/dist/account_not_here.d.ts +15 -0
  3. package/dist/account_not_here.js +25 -0
  4. package/dist/account_not_here.js.map +1 -0
  5. package/dist/agent_hooks.d.ts +8 -0
  6. package/dist/agent_hooks.js +31 -1
  7. package/dist/agent_hooks.js.map +1 -1
  8. package/dist/agents/claude_code.d.ts +34 -0
  9. package/dist/agents/claude_code.js +141 -8
  10. package/dist/agents/claude_code.js.map +1 -1
  11. package/dist/agents/codex_cli.d.ts +13 -0
  12. package/dist/agents/codex_cli.js +241 -2
  13. package/dist/agents/codex_cli.js.map +1 -1
  14. package/dist/agents/cursor.d.ts +34 -0
  15. package/dist/agents/cursor.js +115 -1
  16. package/dist/agents/cursor.js.map +1 -1
  17. package/dist/agents/session_listing.d.ts +29 -0
  18. package/dist/agents/session_listing.js +49 -0
  19. package/dist/agents/session_listing.js.map +1 -0
  20. package/dist/agents/types.d.ts +118 -8
  21. package/dist/agents/types.js +17 -3
  22. package/dist/agents/types.js.map +1 -1
  23. package/dist/commands/approval_pending.d.ts +9 -0
  24. package/dist/commands/approval_pending.js +23 -0
  25. package/dist/commands/approval_pending.js.map +1 -0
  26. package/dist/commands/auth.d.ts +7 -0
  27. package/dist/commands/auth.js +52 -11
  28. package/dist/commands/auth.js.map +1 -1
  29. package/dist/commands/backfill.d.ts +160 -0
  30. package/dist/commands/backfill.js +748 -0
  31. package/dist/commands/backfill.js.map +1 -0
  32. package/dist/commands/browser_credential.d.ts +6 -2
  33. package/dist/commands/browser_credential.js +34 -14
  34. package/dist/commands/browser_credential.js.map +1 -1
  35. package/dist/commands/connect.d.ts +146 -0
  36. package/dist/commands/connect.js +216 -117
  37. package/dist/commands/connect.js.map +1 -1
  38. package/dist/commands/connect_account.d.ts +135 -0
  39. package/dist/commands/connect_account.js +321 -0
  40. package/dist/commands/connect_account.js.map +1 -0
  41. package/dist/commands/connect_picker.d.ts +27 -0
  42. package/dist/commands/connect_picker.js +549 -0
  43. package/dist/commands/connect_picker.js.map +1 -0
  44. package/dist/commands/context.d.ts +16 -0
  45. package/dist/commands/context.js +27 -0
  46. package/dist/commands/context.js.map +1 -1
  47. package/dist/commands/credential_problem.d.ts +15 -4
  48. package/dist/commands/credential_problem.js +29 -22
  49. package/dist/commands/credential_problem.js.map +1 -1
  50. package/dist/commands/device_credential.d.ts +5 -1
  51. package/dist/commands/device_credential.js +17 -14
  52. package/dist/commands/device_credential.js.map +1 -1
  53. package/dist/commands/finalize.d.ts +95 -0
  54. package/dist/commands/finalize.js +249 -74
  55. package/dist/commands/finalize.js.map +1 -1
  56. package/dist/commands/finish_mint.d.ts +30 -6
  57. package/dist/commands/finish_mint.js +26 -6
  58. package/dist/commands/finish_mint.js.map +1 -1
  59. package/dist/commands/report.js +38 -30
  60. package/dist/commands/report.js.map +1 -1
  61. package/dist/commands/scan.d.ts +162 -0
  62. package/dist/commands/scan.js +507 -0
  63. package/dist/commands/scan.js.map +1 -0
  64. package/dist/commands/status.d.ts +19 -1
  65. package/dist/commands/status.js +232 -26
  66. package/dist/commands/status.js.map +1 -1
  67. package/dist/commands/status_hooks.d.ts +14 -0
  68. package/dist/commands/status_hooks.js +81 -0
  69. package/dist/commands/status_hooks.js.map +1 -0
  70. package/dist/commands/status_machine.d.ts +27 -0
  71. package/dist/commands/status_machine.js +210 -0
  72. package/dist/commands/status_machine.js.map +1 -0
  73. package/dist/commands/sync_reason.d.ts +17 -0
  74. package/dist/commands/sync_reason.js +25 -0
  75. package/dist/commands/sync_reason.js.map +1 -0
  76. package/dist/commands/why.js +44 -31
  77. package/dist/commands/why.js.map +1 -1
  78. package/dist/consent.d.ts +217 -0
  79. package/dist/consent.js +400 -1
  80. package/dist/consent.js.map +1 -1
  81. package/dist/copy/error_codes.d.ts +222 -0
  82. package/dist/copy/error_codes.js +105 -0
  83. package/dist/copy/error_codes.js.map +1 -0
  84. package/dist/copy/index.d.ts +2 -2
  85. package/dist/copy/index.js +2 -2
  86. package/dist/copy/index.js.map +1 -1
  87. package/dist/copy/strings.d.ts +617 -30
  88. package/dist/copy/strings.js +741 -36
  89. package/dist/copy/strings.js.map +1 -1
  90. package/dist/copy/time.d.ts +11 -0
  91. package/dist/copy/time.js +18 -0
  92. package/dist/copy/time.js.map +1 -1
  93. package/dist/credential.d.ts +5 -1
  94. package/dist/credential.js +2 -2
  95. package/dist/credential.js.map +1 -1
  96. package/dist/git.d.ts +43 -0
  97. package/dist/git.js +95 -0
  98. package/dist/git.js.map +1 -1
  99. package/dist/grants_sync.d.ts +165 -0
  100. package/dist/grants_sync.js +289 -0
  101. package/dist/grants_sync.js.map +1 -0
  102. package/dist/grants_verb.d.ts +70 -0
  103. package/dist/grants_verb.js +121 -0
  104. package/dist/grants_verb.js.map +1 -0
  105. package/dist/hooks/entry.d.ts +18 -1
  106. package/dist/hooks/entry.js +117 -14
  107. package/dist/hooks/entry.js.map +1 -1
  108. package/dist/hooks/post_commit.js +3 -3
  109. package/dist/hooks/post_commit.js.map +1 -1
  110. package/dist/hooks/post_rewrite.js +6 -4
  111. package/dist/hooks/post_rewrite.js.map +1 -1
  112. package/dist/hooks/session_grants.d.ts +59 -0
  113. package/dist/hooks/session_grants.js +91 -0
  114. package/dist/hooks/session_grants.js.map +1 -0
  115. package/dist/hooks/session_start.d.ts +114 -0
  116. package/dist/hooks/session_start.js +243 -0
  117. package/dist/hooks/session_start.js.map +1 -0
  118. package/dist/index.d.ts +1 -1
  119. package/dist/index.js +76 -11
  120. package/dist/index.js.map +1 -1
  121. package/dist/install.d.ts +57 -0
  122. package/dist/install.js +54 -20
  123. package/dist/install.js.map +1 -1
  124. package/dist/json.d.ts +32 -9
  125. package/dist/json.js +35 -8
  126. package/dist/json.js.map +1 -1
  127. package/dist/machine_state.d.ts +52 -0
  128. package/dist/machine_state.js +63 -0
  129. package/dist/machine_state.js.map +1 -0
  130. package/dist/oauth/retire.d.ts +10 -0
  131. package/dist/oauth/retire.js +13 -0
  132. package/dist/oauth/retire.js.map +1 -1
  133. package/dist/oauth/session.d.ts +1 -0
  134. package/dist/org_pending.d.ts +52 -0
  135. package/dist/org_pending.js +109 -0
  136. package/dist/org_pending.js.map +1 -0
  137. package/dist/paths.d.ts +70 -0
  138. package/dist/paths.js +90 -0
  139. package/dist/paths.js.map +1 -1
  140. package/dist/pending_revoke.d.ts +117 -0
  141. package/dist/pending_revoke.js +233 -0
  142. package/dist/pending_revoke.js.map +1 -0
  143. package/dist/pending_revoke_file.d.ts +55 -0
  144. package/dist/pending_revoke_file.js +74 -0
  145. package/dist/pending_revoke_file.js.map +1 -0
  146. package/dist/picker.d.ts +208 -0
  147. package/dist/picker.js +526 -0
  148. package/dist/picker.js.map +1 -0
  149. package/dist/picker_checklist.d.ts +141 -0
  150. package/dist/picker_checklist.js +411 -0
  151. package/dist/picker_checklist.js.map +1 -0
  152. package/dist/policy.d.ts +70 -1
  153. package/dist/policy.js +68 -2
  154. package/dist/policy.js.map +1 -1
  155. package/dist/post.d.ts +91 -18
  156. package/dist/post.js +259 -27
  157. package/dist/post.js.map +1 -1
  158. package/dist/state.d.ts +6 -0
  159. package/dist/state.js +38 -1
  160. package/dist/state.js.map +1 -1
  161. package/dist/system_message.d.ts +32 -2
  162. package/dist/system_message.js +47 -5
  163. package/dist/system_message.js.map +1 -1
  164. package/dist/term.d.ts +28 -2
  165. package/dist/term.js +23 -2
  166. package/dist/term.js.map +1 -1
  167. package/dist/verb_help.d.ts +13 -0
  168. package/dist/verb_help.js +40 -0
  169. package/dist/verb_help.js.map +1 -0
  170. package/dist/version.d.ts +1 -1
  171. package/dist/version.js +1 -1
  172. package/package.json +5 -9
@@ -7,9 +7,10 @@
7
7
  * `commands/connect.ts`'s own `findCurrentTranscript` verbatim except for the
8
8
  * confinement call, which now runs against the registry's union.
9
9
  */
10
- import { readdirSync, statSync } from "node:fs";
10
+ import { readdirSync, readFileSync, statSync } from "node:fs";
11
11
  import { basename, join } from "node:path";
12
- import { claudeSettingsPath, isInside, isTranscriptFile, transcriptRoot } from "../paths.js";
12
+ import { claudeConfigPath, claudeSettingsPath, isInside, isTranscriptFile, transcriptRoot, } from "../paths.js";
13
+ import { readEntries, sessionFile, subdirectories } from "./session_listing.js";
13
14
  /**
14
15
  * The client-side backstop, per event.
15
16
  *
@@ -38,16 +39,66 @@ const CLAUDE_CLIENT_BUDGET_MS = 5_000;
38
39
  const CLAUDE_REGISTERED_STOP_MS = 8_000;
39
40
  const CLAUDE_REGISTERED_PRECOMPACT_MS = 8_000;
40
41
  const CLAUDE_REGISTERED_SESSION_END_MS = 10_000;
42
+ /**
43
+ * `SessionStart` reuses `Stop`'s two clocks and has no fast path of its own.
44
+ *
45
+ * ⛔ **A logged shortcut** — gstack-shortcut(dec-e650afbf), eng review D7 · B,
46
+ * Alexander's choice over a 1.5 s cap. The ceiling: a hung `SessionStart` can
47
+ * hold a session's start up by as long as the REGISTERED timeout (8 s here).
48
+ * Upgrade when a measurement or a user report shows session-start delay, or
49
+ * before slice 2's grants fetch is built into this handler.
50
+ */
51
+ const CLAUDE_REGISTERED_SESSION_START_MS = CLAUDE_REGISTERED_STOP_MS; // gstack-shortcut(dec-e650afbf)
52
+ /**
53
+ * The longest folder name Claude Code writes verbatim.
54
+ *
55
+ * ⛔ **MEASURED (Open Question 3, VS, 2026-10-24).** An encoded path that would
56
+ * pass 200 characters is cut to 200, then `-`, then 6 hash characters (a
57
+ * measured name was 207 long, `…-x911fg`). The hash is not invertible from here,
58
+ * so such a folder cannot be matched to a path — and so a name LONGER than this
59
+ * is always a hashed one, since a verbatim name never exceeds it.
60
+ */
61
+ export const CLAUDE_NAME_LIMIT = 200;
62
+ /**
63
+ * The folder name Claude Code gives a project path — Open Question 3.
64
+ *
65
+ * ⛔ **EVERY UTF-16 CODE UNIT OUTSIDE `[A-Za-z0-9]` BECOMES ONE `-`.** Measured by
66
+ * running throwaway sessions in folders named with `. _`, a space, `@ + ~ ( ) ' =
67
+ * , # % &`, `é` and an emoji: all of them, and the emoji TWICE, because the
68
+ * regular expression below runs over code units (no `u` flag) and an emoji is
69
+ * two. Runs do NOT collapse (`501/-Users` gave `501--Users`), a literal `-` stays
70
+ * itself, case is kept, and a leading `/` gives a leading `-`.
71
+ *
72
+ * ⚠ **This replaces `/[/.]/g`, which was the rule the first version of
73
+ * `locateCurrentTranscript` derived from 17 folders none of which held anything
74
+ * else.** For a repo whose path held an `_` or a space, `connect`'s test capture
75
+ * looked in a folder that does not exist and skipped the beat (a 0.6.x defect;
76
+ * `test/scan-encodings.test.ts` carries its regression cell).
77
+ *
78
+ * ⚠ **It returns the FULL encoding even past the limit**, and the callers decide
79
+ * what that means: `locateCurrentTranscript` cannot find a hashed folder, and the
80
+ * scan's walk compares PREFIXES of a name that is itself at most the limit, so a
81
+ * longer prefix simply never matches. One function, no second spelling of the rule.
82
+ */
83
+ export function encodeProjectPath(path) {
84
+ return path.replace(/[^A-Za-z0-9]/g, "-");
85
+ }
86
+ /** Is this folder name one Claude Code cut and hashed? See `CLAUDE_NAME_LIMIT`. */
87
+ export function isHashedProjectName(name) {
88
+ return name.length > CLAUDE_NAME_LIMIT;
89
+ }
41
90
  /**
42
91
  * The transcript for the session running right now.
43
92
  *
44
93
  * A hook is HANDED `transcript_path` on stdin. `connect` is typed by a human and
45
94
  * gets nothing, so it has to find one: Claude Code stores transcripts at
46
95
  * `<transcriptRoot>/<encoded-project-path>/<session-id>.jsonl`, where the
47
- * encoding replaces `/` and `.` with `-`. That was derived by comparing every
48
- * directory on this machine against the `cwd` its transcripts record — 15 of 17
49
- * matched exactly, and both misses were sessions whose `cwd` MOVED mid-session,
50
- * not a different encoding.
96
+ * encoding is `encodeProjectPath` above. The first version of that was derived
97
+ * by comparing every directory on this machine against the `cwd` its transcripts
98
+ * record — 15 of 17 matched exactly, and both misses were sessions whose `cwd`
99
+ * MOVED mid-session, not a different encoding. ⚠ Seventeen folders cannot
100
+ * contain a character none of them had: see `encodeProjectPath` for what that
101
+ * assumption cost.
51
102
  *
52
103
  * Which is also why this looks up the directory for THIS project rather than
53
104
  * taking the newest transcript anywhere: a session that started in another
@@ -70,7 +121,13 @@ const CLAUDE_REGISTERED_SESSION_END_MS = 10_000;
70
121
  */
71
122
  function locateCurrentTranscript(home, env, projectKey) {
72
123
  const root = transcriptRoot(home, env);
73
- const dir = join(root, projectKey.replace(/[/.]/g, "-"));
124
+ const name = encodeProjectPath(projectKey);
125
+ // A hashed folder name cannot be derived from the path, so there is nothing to
126
+ // look in. `connect` then skips the test-capture beat, as it does for an agent
127
+ // with no locator, rather than guessing a sibling.
128
+ if (isHashedProjectName(name))
129
+ return null;
130
+ const dir = join(root, name);
74
131
  let entries;
75
132
  try {
76
133
  entries = readdirSync(dir);
@@ -129,6 +186,70 @@ function claudeSessionIdFromEnv(env) {
129
186
  const value = raw.trim();
130
187
  return value === "" ? null : value;
131
188
  }
189
+ /**
190
+ * The folders Claude Code has recorded running in: the KEYS of `~/.claude.json`'s
191
+ * `projects` map, and nothing else.
192
+ *
193
+ * ⛔ **Keys only.** The file also holds account and onboarding state, none of
194
+ * which this client has any use for. Nothing but the key strings leaves this
195
+ * function, and a failure of any kind is an empty list: the signal then simply
196
+ * does not fire, which skips less. ⚠ **No error is ever surfaced or logged** — Node
197
+ * 22's `JSON.parse` message quotes the text it failed on, and this file is not
198
+ * one whose text belongs on a screen.
199
+ */
200
+ function recordedProjectPaths(home, env) {
201
+ try {
202
+ const parsed = JSON.parse(readFileSync(claudeConfigPath(home, env), "utf8"));
203
+ const projects = typeof parsed === "object" && parsed !== null
204
+ ? parsed.projects
205
+ : undefined;
206
+ return typeof projects === "object" && projects !== null ? Object.keys(projects) : [];
207
+ }
208
+ catch {
209
+ return [];
210
+ }
211
+ }
212
+ /**
213
+ * Claude Code's sessions, by folder — `D11 · A`, `scan`.
214
+ *
215
+ * `<root>/<encoded path>/<session-id>.jsonl`. Only the files DIRECTLY in a
216
+ * project folder are sessions: `<session-id>/subagents/…` holds delegated work
217
+ * that belongs to a parent session (`CR-124`), and counting it would turn one
218
+ * session into several. A legacy `agent-*.jsonl` sidechain at this level is
219
+ * excluded for the same reason.
220
+ *
221
+ * ⛔ **Names and times only.** The folder name is returned still ENCODED; whether
222
+ * it resolves to a path is the scan engine's walk, against the filesystem, never
223
+ * against a transcript's own `cwd` record (D60 §D6).
224
+ */
225
+ function claudeSessionSource(home, env) {
226
+ const root = transcriptRoot(home, env);
227
+ const folders = [];
228
+ try {
229
+ for (const folder of subdirectories(root)) {
230
+ const sessions = [];
231
+ for (const entry of readEntries(folder.path) ?? []) {
232
+ if (!entry.name.endsWith(".jsonl") || entry.name.startsWith("agent-"))
233
+ continue;
234
+ const session = sessionFile(join(folder.path, entry.name));
235
+ if (session !== null)
236
+ sessions.push(session);
237
+ }
238
+ if (sessions.length > 0)
239
+ folders.push({ name: folder.name, sessions });
240
+ }
241
+ }
242
+ catch {
243
+ return { kind: "unreadable", reason: "unreadable" };
244
+ }
245
+ return {
246
+ kind: "folders",
247
+ folders,
248
+ encode: encodeProjectPath,
249
+ isHashed: isHashedProjectName,
250
+ recorded: recordedProjectPaths(home, env),
251
+ };
252
+ }
132
253
  export const CLAUDE_CODE = {
133
254
  id: "claude-code",
134
255
  transport: "ndjson",
@@ -143,7 +264,12 @@ export const CLAUDE_CODE = {
143
264
  // agent the client was built for. Declared explicitly rather than defaulted so
144
265
  // that a dialect added later must ANSWER the question; a default would let a
145
266
  // camelCase agent inherit Claude's spellings and match nothing (`CR-195`).
146
- eventNames: { Stop: "Stop", PreCompact: "PreCompact", SessionEnd: "SessionEnd" },
267
+ eventNames: {
268
+ Stop: "Stop",
269
+ PreCompact: "PreCompact",
270
+ SessionEnd: "SessionEnd",
271
+ SessionStart: "SessionStart",
272
+ },
147
273
  // ⛔ `~/.claude/settings.json`, honouring `CLAUDE_CONFIG_DIR`. ⚠ This is the
148
274
  // file the PLUGIN path does not need — the plugin ships its own `hooks.json`
149
275
  // — and the npm path had no writer at all, which is the defect `/install`
@@ -162,12 +288,19 @@ export const CLAUDE_CODE = {
162
288
  registeredTimeoutMs: CLAUDE_REGISTERED_SESSION_END_MS,
163
289
  clientBudgetMs: CLAUDE_CLIENT_BUDGET_MS,
164
290
  },
291
+ // MEASURED (Open Question 1, 2.1.309): fires before the first prompt in `-p`
292
+ // and the TUI, and accepts `systemMessage`. gstack-shortcut(dec-e650afbf).
293
+ SessionStart: {
294
+ registeredTimeoutMs: CLAUDE_REGISTERED_SESSION_START_MS,
295
+ clientBudgetMs: CLAUDE_CLIENT_BUDGET_MS,
296
+ },
165
297
  },
166
298
  // `<session>/subagents/agent-*.jsonl`, globbed — the paths are never handed
167
299
  // over. `CR-124`, D76.
168
300
  delegatedTranscripts: "discover",
169
301
  redaction: "claude-code",
170
302
  sessionIdFromEnv: claudeSessionIdFromEnv,
303
+ sessionSource: claudeSessionSource,
171
304
  locateCurrentTranscript,
172
305
  };
173
306
  //# sourceMappingURL=claude_code.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"claude_code.js","sourceRoot":"","sources":["../../src/agents/claude_code.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"claude_code.js","sourceRoot":"","sources":["../../src/agents/claude_code.ts"],"names":[],"mappings":"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"}
@@ -12,4 +12,17 @@
12
12
  * reader can check them against the product rather than against this file.
13
13
  */
14
14
  import type { TranscriptDialect } from "./types.js";
15
+ /**
16
+ * ⛔ **THE FOUR COLUMNS, AND NO OTHER — `D11 · A`, Alexander's approved read.**
17
+ *
18
+ * The thread index also holds `first_user_message`, `title`, `preview` and more,
19
+ * which are CONTENT. Selecting one would turn a metadata read into a transcript
20
+ * read, so the statement names exactly these four and `test/scan-codex-index.test.ts`
21
+ * asserts the SQL carries nothing else. ⚠ **`archived` is not here either, on
22
+ * purpose** (VQ, 2026-10-24): an archived thread's `rollout_path` is decided by
23
+ * the admission below, and a fifth column would change the approved read surface.
24
+ */
25
+ export declare const CODEX_INDEX_COLUMNS: readonly ["cwd", "git_origin_url", "rollout_path", "created_at"];
26
+ /** The one statement the adapter runs against a thread row. */
27
+ export declare const CODEX_INDEX_SQL: string;
15
28
  export declare const CODEX_CLI: TranscriptDialect;
@@ -11,7 +11,11 @@
11
11
  * measured by this task.** They are recorded as the brief stated them so a later
12
12
  * reader can check them against the product rather than against this file.
13
13
  */
14
- import { codexHooksPath, codexTranscriptRoot, isTranscriptFile } from "../paths.js";
14
+ import { readdirSync, realpathSync } from "node:fs";
15
+ import { createRequire } from "node:module";
16
+ import { join } from "node:path";
17
+ import { CODEX_INDEX_FILE, codexHooksPath, codexIndexDir, codexTranscriptRoot, isInside, isTranscriptFile, } from "../paths.js";
18
+ import { readEntries, sessionFile } from "./session_listing.js";
15
19
  /**
16
20
  * `SessionEnd` is the tight one — 3 s registered, 2.2 s client.
17
21
  *
@@ -24,6 +28,226 @@ const CODEX_SESSION_END_CLIENT_MS = 2_200;
24
28
  /** `Stop` and `PreCompact` are registered far wider — 30 s, client 8 s. */
25
29
  const CODEX_TURN_REGISTERED_MS = 30_000;
26
30
  const CODEX_TURN_CLIENT_MS = 8_000;
31
+ /**
32
+ * `SessionStart` takes the turn clocks, with no fast path of its own.
33
+ *
34
+ * ⛔ **A logged shortcut** — gstack-shortcut(dec-e650afbf), eng review D7 · B.
35
+ * The ceiling: a hung `SessionStart` can hold a session's start up by as long as
36
+ * the REGISTERED timeout (30 s here). Upgrade when a measurement or a user report
37
+ * shows session-start delay, or before slice 2's grants fetch lands in this handler.
38
+ */
39
+ const CODEX_SESSION_START_REGISTERED_MS = CODEX_TURN_REGISTERED_MS; // gstack-shortcut(dec-e650afbf)
40
+ const CODEX_SESSION_START_CLIENT_MS = CODEX_TURN_CLIENT_MS; // gstack-shortcut(dec-e650afbf)
41
+ /**
42
+ * ⛔ **THE FOUR COLUMNS, AND NO OTHER — `D11 · A`, Alexander's approved read.**
43
+ *
44
+ * The thread index also holds `first_user_message`, `title`, `preview` and more,
45
+ * which are CONTENT. Selecting one would turn a metadata read into a transcript
46
+ * read, so the statement names exactly these four and `test/scan-codex-index.test.ts`
47
+ * asserts the SQL carries nothing else. ⚠ **`archived` is not here either, on
48
+ * purpose** (VQ, 2026-10-24): an archived thread's `rollout_path` is decided by
49
+ * the admission below, and a fifth column would change the approved read surface.
50
+ */
51
+ export const CODEX_INDEX_COLUMNS = ["cwd", "git_origin_url", "rollout_path", "created_at"];
52
+ /** The one statement the adapter runs against a thread row. */
53
+ export const CODEX_INDEX_SQL = `SELECT ${CODEX_INDEX_COLUMNS.join(", ")} FROM threads`;
54
+ /** How long a locked index is waited for before the adapter gives up (eng review D2). */
55
+ const CODEX_BUSY_TIMEOUT_MS = 1_000;
56
+ /**
57
+ * `node:sqlite`, loaded here and nowhere else, with ITS warning and only its
58
+ * warning dropped — eng review D2 · A.
59
+ *
60
+ * Node 22 prints `ExperimentalWarning: SQLite is an experimental feature…` to
61
+ * stderr the first time the module loads, which would land mid-screen in the
62
+ * picker and breaks DESIGN.md §13's output rules. `process.emitWarning` is
63
+ * wrapped for the duration of the one `require` and restored in a `finally`;
64
+ * any OTHER warning, in that window or after it, still prints. Measured on
65
+ * node 22.17.0.
66
+ *
67
+ * ⚠ **A `require` and not a dynamic `import()`**, so the whole adapter stays
68
+ * synchronous like every other lister (`scan` is a chain of `execFileSync`
69
+ * anyway) and the wrapped window is exactly the load, not a promise turn that
70
+ * something else could emit a warning inside. Lazy: a machine with no Codex
71
+ * never loads the module at all.
72
+ */
73
+ function loadSqlite() {
74
+ const original = process.emitWarning;
75
+ process.emitWarning = ((warning, ...rest) => {
76
+ const type = typeof warning === "string" ? rest[0] : warning.name;
77
+ const message = typeof warning === "string" ? warning : warning.message;
78
+ if (type === "ExperimentalWarning" && message.startsWith("SQLite"))
79
+ return;
80
+ return original.call(process, warning, ...rest);
81
+ });
82
+ try {
83
+ return createRequire(import.meta.url)("node:sqlite");
84
+ }
85
+ finally {
86
+ process.emitWarning = original;
87
+ }
88
+ }
89
+ /** Does the `threads` table carry all four columns? A bare name test, nothing deeper. */
90
+ function hasIndexColumns(db) {
91
+ const present = new Set(db.prepare("PRAGMA table_info(threads)").all().map((c) => String(c.name)));
92
+ return CODEX_INDEX_COLUMNS.every((column) => present.has(column));
93
+ }
94
+ /** A locked database is a different line from an unrecognised one. */
95
+ function readFailure(err) {
96
+ return /locked|busy/i.test(err instanceof Error ? err.message : "")
97
+ ? "index locked"
98
+ : "unreadable";
99
+ }
100
+ /**
101
+ * Rollout files under `sessions/` that NO index row names — counted, never opened.
102
+ *
103
+ * Open Question 6's text, as VQ ruled (PR 1 ruling 5c): an index which cannot see a
104
+ * session is a thing to REPORT, not to guess about. The walk lists directory entries — names
105
+ * and file types, nothing else — and counts each regular `.jsonl`; a symlink is
106
+ * not a file here (`Dirent.isFile` is false for it).
107
+ *
108
+ * Compared as REALPATHS on both sides, because the index stores the path Codex
109
+ * wrote and the walk builds its own from `home`; a symlinked home would otherwise
110
+ * make every rollout look unindexed. A row whose rollout has gone cannot be
111
+ * resolved and names nothing, which is correct: it is not on disk to be matched.
112
+ */
113
+ function countUnindexed(root, rolloutPaths) {
114
+ const named = new Set();
115
+ for (const path of rolloutPaths) {
116
+ try {
117
+ named.add(realpathSync(path));
118
+ }
119
+ catch {
120
+ // Gone from disk: it names no file that the walk could find.
121
+ }
122
+ }
123
+ let base;
124
+ try {
125
+ base = realpathSync(root);
126
+ }
127
+ catch {
128
+ return 0;
129
+ }
130
+ let count = 0;
131
+ const visit = (dir) => {
132
+ let entries;
133
+ try {
134
+ entries = readEntries(dir);
135
+ }
136
+ catch {
137
+ return;
138
+ }
139
+ for (const entry of entries ?? []) {
140
+ const path = join(dir, entry.name);
141
+ if (entry.isDirectory())
142
+ visit(path);
143
+ else if (entry.isFile() && entry.name.endsWith(".jsonl") && !named.has(path))
144
+ count += 1;
145
+ }
146
+ };
147
+ visit(base);
148
+ return count;
149
+ }
150
+ /**
151
+ * Codex's sessions, from its thread index — `D11 · A`, eng review D2, `scan`.
152
+ *
153
+ * Codex keeps rollouts DATE-keyed (`sessions/YYYY/MM/DD/`), so a folder walk
154
+ * cannot say which repo one belongs to; its `threads` table can, because it
155
+ * records the real `cwd`. That row is the whole reason this adapter exists and
156
+ * the reason a Codex row is never ambiguous.
157
+ *
158
+ * ## ⛔ What is read, and how
159
+ *
160
+ * - **exactly `state_5.sqlite`**, and any other `state_N` is `unrecognised
161
+ * index` (Open Question 6; see `codexIndexDir`).
162
+ * - **`readOnly`, never `immutable`.** Codex keeps everything since its last
163
+ * checkpoint in the `-wal` file (on the author's machine, every thread since
164
+ * Sep 30), and an `immutable` open ignores it.
165
+ * - **the four columns only** (`CODEX_INDEX_SQL`), after a `PRAGMA table_info`
166
+ * check, and a 1000 ms busy timeout. Any failure is this agent's
167
+ * `unreadable` answer, so the other two agents' rows are untouched.
168
+ *
169
+ * ## ⛔ The rollout file is `lstat`ed, never opened
170
+ *
171
+ * A row is admitted only if its `rollout_path` lies under the sessions root and
172
+ * is a regular file there. That is also what decides an ARCHIVED thread, whose
173
+ * rollout is not under `sessions/`. The row's `git_origin_url` is carried but is
174
+ * not the slug source: the scan names a repo from the CLONE (`resolveRepoSlug`),
175
+ * so there is one normalisation and not two.
176
+ */
177
+ function codexSessionSource(home, env) {
178
+ const dir = codexIndexDir(home, env);
179
+ const file = join(dir, CODEX_INDEX_FILE);
180
+ let present;
181
+ try {
182
+ present = readdirSync(dir);
183
+ }
184
+ catch (err) {
185
+ const code = err.code;
186
+ return code === "ENOENT" || code === "ENOTDIR"
187
+ ? { kind: "rows", rows: [], unindexed: 0 }
188
+ : { kind: "unreadable", reason: "unreadable" };
189
+ }
190
+ if (!present.includes(CODEX_INDEX_FILE)) {
191
+ // A Codex that keeps its index under another generation's name is a store
192
+ // this client was not checked against. One with no index at all has simply
193
+ // never recorded a thread — and its rollouts, if any, are all unindexed.
194
+ return present.some((name) => /^state_\d+\.sqlite$/.test(name))
195
+ ? { kind: "unreadable", reason: "unrecognised index" }
196
+ : { kind: "rows", rows: [], unindexed: countUnindexed(codexTranscriptRoot(home, env), []) };
197
+ }
198
+ let sqlite;
199
+ try {
200
+ sqlite = loadSqlite();
201
+ }
202
+ catch {
203
+ return { kind: "unreadable", reason: "unreadable" };
204
+ }
205
+ let db = null;
206
+ try {
207
+ // ⚠ `readOnly` stops THIS CODE writing the index and does not stop SQLite creating its own
208
+ // `-wal`/`-shm` files beside it, which any reader of a WAL database whose writer has closed does
209
+ // (measured by VQ on node 22.17, PR 1 F1). Nothing is written to `state_5.sqlite` itself.
210
+ db = new sqlite.DatabaseSync(file, { readOnly: true });
211
+ db.exec(`PRAGMA busy_timeout = ${CODEX_BUSY_TIMEOUT_MS}`);
212
+ if (!hasIndexColumns(db))
213
+ return { kind: "unreadable", reason: "unrecognised index" };
214
+ const root = codexTranscriptRoot(home, env);
215
+ const rows = [];
216
+ const named = [];
217
+ for (const row of db.prepare(CODEX_INDEX_SQL).all()) {
218
+ const { cwd, git_origin_url: origin, rollout_path: rollout, created_at: created } = row;
219
+ if (typeof cwd !== "string" || typeof rollout !== "string")
220
+ continue;
221
+ // Every path an index row names counts as INDEXED, admitted or not: an archived thread's rollout
222
+ // is not "missing from the index", it is simply not capturable (`D11 · A`).
223
+ named.push(rollout);
224
+ if (!isInside(root, rollout) || !isTranscriptFile(root, rollout))
225
+ continue;
226
+ const session = sessionFile(rollout);
227
+ if (session === null)
228
+ continue;
229
+ rows.push({
230
+ cwd,
231
+ origin: typeof origin === "string" ? origin : null,
232
+ // `created_at` is whole SECONDS (measured), the rest of this client's
233
+ // times are milliseconds.
234
+ session: typeof created === "number" ? { ...session, startedMs: created * 1000 } : session,
235
+ });
236
+ }
237
+ return { kind: "rows", rows, unindexed: countUnindexed(root, named) };
238
+ }
239
+ catch (err) {
240
+ return { kind: "unreadable", reason: readFailure(err) };
241
+ }
242
+ finally {
243
+ try {
244
+ db?.close();
245
+ }
246
+ catch {
247
+ // Closing a read-only handle that failed to open is not a second finding.
248
+ }
249
+ }
250
+ }
27
251
  export const CODEX_CLI = {
28
252
  id: "codex-cli",
29
253
  transport: "ndjson",
@@ -46,7 +270,17 @@ export const CODEX_CLI = {
46
270
  // against three throwaway `CODEX_HOME`s settled it: `SessionEnd` is recognised
47
271
  // and says so by clamping, while `session_end` and a bogus key produce NO
48
272
  // diagnostic — a file that parses, registers nothing, and reports success.
49
- eventNames: { Stop: "Stop", PreCompact: "PreCompact", SessionEnd: "SessionEnd" },
273
+ // `SessionStart` is in that schema list too, spelled the same way, and MEASURED
274
+ // live (Open Question 1, Codex 0.148.0): it fires before the first prompt — in
275
+ // the TUI lazily, when the first prompt is submitted — and accepts a
276
+ // `systemMessage`. ⚠ Those runs were under cmux's `--dangerously-bypass-hook-trust`;
277
+ // stock Codex >= 0.131.0 runs a user-level hook only after the user trusts it.
278
+ eventNames: {
279
+ Stop: "Stop",
280
+ PreCompact: "PreCompact",
281
+ SessionEnd: "SessionEnd",
282
+ SessionStart: "SessionStart",
283
+ },
50
284
  // ⛔ `~/.codex/hooks.json`, honouring `CODEX_HOME` — MEASURED, since every
51
285
  // probe in this unit drove a real `codex` through a throwaway `CODEX_HOME`
52
286
  // and it read the `hooks.json` there. The NESTED shape, also measured: a
@@ -66,6 +300,10 @@ export const CODEX_CLI = {
66
300
  registeredTimeoutMs: CODEX_SESSION_END_REGISTERED_MS,
67
301
  clientBudgetMs: CODEX_SESSION_END_CLIENT_MS,
68
302
  },
303
+ SessionStart: {
304
+ registeredTimeoutMs: CODEX_SESSION_START_REGISTERED_MS,
305
+ clientBudgetMs: CODEX_SESSION_START_CLIENT_MS,
306
+ },
69
307
  },
70
308
  // The delegated path ARRIVES on stdin as `agent_transcript_path` — there is no
71
309
  // directory to glob. Nothing parses it yet; the discriminator is here so the
@@ -79,6 +317,7 @@ export const CODEX_CLI = {
79
317
  // of a measurement, not as a fact about the agent. Measuring it is a change to
80
318
  // this line and nothing else.
81
319
  sessionIdFromEnv: () => null,
320
+ sessionSource: codexSessionSource,
82
321
  // ⛔ NO `locateCurrentTranscript`, and the omission is the decision. Finding
83
322
  // the repository would mean reading a `cwd` out of the transcript's own
84
323
  // records — ANALYSIS, which D60 §D6 forbids this client. `connect` therefore
@@ -1 +1 @@
1
- {"version":3,"file":"codex_cli.js","sourceRoot":"","sources":["../../src/agents/codex_cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGpF;;;;;;GAMG;AACH,MAAM,+BAA+B,GAAG,KAAK,CAAC;AAC9C,MAAM,2BAA2B,GAAG,KAAK,CAAC;AAE1C,2EAA2E;AAC3E,MAAM,wBAAwB,GAAG,MAAM,CAAC;AACxC,MAAM,oBAAoB,GAAG,KAAK,CAAC;AAEnC,MAAM,CAAC,MAAM,SAAS,GAAsB;IAC1C,EAAE,EAAE,WAAW;IACf,SAAS,EAAE,QAAQ;IACnB,cAAc,EAAE,mBAAmB;IACnC,yEAAyE;IACzE,4EAA4E;IAC5E,0EAA0E;IAC1E,+DAA+D;IAC/D,UAAU,EAAE,gBAAgB;IAC5B,4EAA4E;IAC5E,8EAA8E;IAC9E,6EAA6E;IAC7E,8EAA8E;IAC9E,+EAA+E;IAC/E,mEAAmE;IACnE,EAAE;IACF,kEAAkE;IAClE,4EAA4E;IAC5E,+EAA+E;IAC/E,+EAA+E;IAC/E,0EAA0E;IAC1E,2EAA2E;IAC3E,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE;IAChF,0EAA0E;IAC1E,2EAA2E;IAC3E,yEAAyE;IACzE,yEAAyE;IACzE,gEAAgE;IAChE,UAAU,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,QAAQ,EAAE;IACrD,MAAM,EAAE;QACN,IAAI,EAAE;YACJ,mBAAmB,EAAE,wBAAwB;YAC7C,cAAc,EAAE,oBAAoB;SACrC;QACD,UAAU,EAAE;YACV,mBAAmB,EAAE,wBAAwB;YAC7C,cAAc,EAAE,oBAAoB;SACrC;QACD,UAAU,EAAE;YACV,mBAAmB,EAAE,+BAA+B;YACpD,cAAc,EAAE,2BAA2B;SAC5C;KACF;IACD,+EAA+E;IAC/E,6EAA6E;IAC7E,oEAAoE;IACpE,oBAAoB,EAAE,UAAU;IAChC,SAAS,EAAE,WAAW;IACtB,8EAA8E;IAC9E,0EAA0E;IAC1E,8EAA8E;IAC9E,6EAA6E;IAC7E,+EAA+E;IAC/E,8BAA8B;IAC9B,gBAAgB,EAAE,GAAG,EAAE,CAAC,IAAI;IAC5B,4EAA4E;IAC5E,wEAAwE;IACxE,6EAA6E;IAC7E,oDAAoD;CACrD,CAAC"}
1
+ {"version":3,"file":"codex_cli.js","sourceRoot":"","sources":["../../src/agents/codex_cli.ts"],"names":[],"mappings":"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"}
@@ -18,4 +18,38 @@
18
18
  * difference is marked on each member below rather than left to a reader.
19
19
  */
20
20
  import type { TranscriptDialect } from "./types.js";
21
+ /**
22
+ * The longest folder name Cursor writes verbatim.
23
+ *
24
+ * ⛔ **MEASURED (Open Question 3, VS, 2026-10-24), with `cursor-agent`, which
25
+ * creates the project folder even when it is not logged in.** A name up to 61
26
+ * characters is kept; a longer one becomes its first 53 characters, `-`, and 7
27
+ * hex characters (the hash varied with the input, so it is not a constant).
28
+ */
29
+ export declare const CURSOR_NAME_LIMIT = 61;
30
+ /**
31
+ * The folder name Cursor gives a workspace path — Open Question 3.
32
+ *
33
+ * ⛔ **THIS IS NOT CLAUDE CODE'S RULE, and the difference is the measurement.**
34
+ * Every RUN of non-alphanumerics, a literal `--` included, collapses to ONE `-`;
35
+ * leading and trailing separators are dropped (so `/tmp/q/trail.` is `…-trail`
36
+ * and there is no leading `-`); case is kept. An emoji and `é'` each gave a single
37
+ * dash where Claude Code gives two.
38
+ *
39
+ * ⚠ **Which makes Cursor's names collide far more:** `a-b`, `a.b`, `a--b` and
40
+ * `a.b.` are all one folder. The scan's walk encodes every directory entry with
41
+ * THIS function and matches on the result, so the collapsing applies to every
42
+ * candidate rather than being assumed away.
43
+ */
44
+ export declare function encodeProjectPath(path: string): string;
45
+ /**
46
+ * Is this folder name one Cursor cut and hashed? See `CURSOR_NAME_LIMIT`.
47
+ *
48
+ * ⚠ **A hashed name is always exactly 61 long, and so is a verbatim name that
49
+ * happens to be 61 long** — length alone cannot tell them apart. The test is the
50
+ * hash's shape too (`-` and 7 hex). A verbatim 61-character name that ends the
51
+ * same way is read as hashed, which is the safe error: it is skipped and
52
+ * counted, never matched to a path it might not be.
53
+ */
54
+ export declare function isHashedProjectName(name: string): boolean;
21
55
  export declare const CURSOR: TranscriptDialect;