codedeck 0.4.2 → 0.5.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.
@@ -0,0 +1,357 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ const execFileAsync = promisify(execFile);
6
+ export const REVIEW_MAX_FILES = 500;
7
+ export const REVIEW_MAX_FILE_BYTES = 200 * 1024;
8
+ export const REVIEW_PATCH_MAX_BYTES = 2 * 1024 * 1024;
9
+ const HUNK_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$/;
10
+ function unquoteGitPath(raw) {
11
+ const t = raw.trim();
12
+ if (t.startsWith('"') && t.endsWith('"')) {
13
+ try {
14
+ return JSON.parse(t);
15
+ }
16
+ catch {
17
+ return t.slice(1, -1);
18
+ }
19
+ }
20
+ return t;
21
+ }
22
+ function stripPrefix(p) {
23
+ if (p === "/dev/null")
24
+ return p;
25
+ if (p.startsWith("a/") || p.startsWith("b/"))
26
+ return p.slice(2);
27
+ return p;
28
+ }
29
+ /** Split `diff --git a/x b/y` into its two raw paths (quote-aware). */
30
+ function splitDiffGitArgs(rest) {
31
+ // Walk two tokens manually so quoted paths with spaces survive; anything
32
+ // that does not yield exactly two tokens is not a file header we parse.
33
+ const tokens = [];
34
+ let i = 0;
35
+ while (i < rest.length && tokens.length < 2) {
36
+ while (i < rest.length && rest[i] === " ")
37
+ i++;
38
+ if (i >= rest.length)
39
+ break;
40
+ if (rest[i] === '"') {
41
+ let j = i + 1;
42
+ while (j < rest.length && rest[j] !== '"')
43
+ j += rest[j] === "\\" ? 2 : 1;
44
+ tokens.push(rest.slice(i, j + 1));
45
+ i = j + 1;
46
+ }
47
+ else {
48
+ let j = i;
49
+ while (j < rest.length && rest[j] !== " ")
50
+ j++;
51
+ tokens.push(rest.slice(i, j));
52
+ i = j;
53
+ }
54
+ }
55
+ if (tokens.length !== 2)
56
+ return null;
57
+ return [tokens[0], tokens[1]];
58
+ }
59
+ /**
60
+ * Parse a unified diff into per-file hunks with old/new line numbers.
61
+ * Pure: no git, no fs. Unknown preamble lines are skipped.
62
+ */
63
+ export function parseUnifiedDiff(patch) {
64
+ const files = [];
65
+ let cur = null;
66
+ let hunk = null;
67
+ let oldNo = 0;
68
+ let newNo = 0;
69
+ let oldName = null;
70
+ let newName = null;
71
+ const flushFile = () => {
72
+ if (cur) {
73
+ // Status refinement from ---/+++ when no name-status map is available.
74
+ if (oldName === "/dev/null" && newName !== "/dev/null")
75
+ cur.status = "added";
76
+ else if (newName === "/dev/null" && oldName !== "/dev/null")
77
+ cur.status = "deleted";
78
+ files.push(cur);
79
+ }
80
+ cur = null;
81
+ hunk = null;
82
+ oldName = null;
83
+ newName = null;
84
+ };
85
+ for (const raw of patch.split("\n")) {
86
+ const line = raw.endsWith("\r") ? raw.slice(0, -1) : raw;
87
+ if (line.startsWith("diff --git ")) {
88
+ flushFile();
89
+ const args = splitDiffGitArgs(line.slice("diff --git ".length));
90
+ const a = args ? stripPrefix(unquoteGitPath(args[0])) : "unknown";
91
+ const b = args ? stripPrefix(unquoteGitPath(args[1])) : "unknown";
92
+ cur = { path: b, oldPath: a, status: "modified", hunks: [], binary: false, tooLarge: false };
93
+ continue;
94
+ }
95
+ if (!cur)
96
+ continue;
97
+ if (line.startsWith("Binary files ")) {
98
+ cur.binary = true;
99
+ continue;
100
+ }
101
+ if (line.startsWith("--- ")) {
102
+ oldName = stripPrefix(unquoteGitPath(line.slice(4).split("\t")[0]));
103
+ continue;
104
+ }
105
+ if (line.startsWith("+++ ")) {
106
+ newName = stripPrefix(unquoteGitPath(line.slice(4).split("\t")[0]));
107
+ if (oldName !== null && newName !== null) {
108
+ if (oldName !== "/dev/null" && newName !== "/dev/null" && oldName !== newName) {
109
+ cur.oldPath = oldName;
110
+ cur.path = newName;
111
+ cur.status = "renamed";
112
+ }
113
+ else if (newName !== "/dev/null") {
114
+ cur.path = newName;
115
+ }
116
+ }
117
+ continue;
118
+ }
119
+ const hm = HUNK_RE.exec(line);
120
+ if (hm) {
121
+ const oldStart = Number(hm[1]);
122
+ const oldCount = hm[2] === undefined ? 1 : Number(hm[2]);
123
+ const newStart = Number(hm[3]);
124
+ const newCount = hm[4] === undefined ? 1 : Number(hm[4]);
125
+ hunk = { header: line, oldStart, oldCount, newStart, newCount, lines: [] };
126
+ cur.hunks.push(hunk);
127
+ oldNo = oldStart;
128
+ newNo = newStart;
129
+ continue;
130
+ }
131
+ if (!hunk)
132
+ continue;
133
+ if (line.startsWith("\\"))
134
+ continue; // ""
135
+ const marker = line[0];
136
+ const text = line.slice(1);
137
+ if (marker === " ") {
138
+ hunk.lines.push({ type: "context", oldNo, newNo, text });
139
+ oldNo++;
140
+ newNo++;
141
+ }
142
+ else if (marker === "+") {
143
+ hunk.lines.push({ type: "add", oldNo: null, newNo, text });
144
+ newNo++;
145
+ }
146
+ else if (marker === "-") {
147
+ hunk.lines.push({ type: "del", oldNo, newNo: null, text });
148
+ oldNo++;
149
+ }
150
+ // Anything else inside a hunk body is ignored (defensive, not a guess:
151
+ // malformed hunks simply yield fewer lines rather than wrong numbers).
152
+ }
153
+ flushFile();
154
+ return files;
155
+ }
156
+ const LANG_BY_EXT = {
157
+ ts: "ts",
158
+ tsx: "tsx",
159
+ js: "js",
160
+ jsx: "jsx",
161
+ mjs: "js",
162
+ cjs: "js",
163
+ mts: "ts",
164
+ cts: "ts",
165
+ py: "py",
166
+ go: "go",
167
+ rs: "rust",
168
+ java: "java",
169
+ rb: "ruby",
170
+ php: "php",
171
+ swift: "swift",
172
+ kt: "kotlin",
173
+ cs: "csharp",
174
+ c: "c",
175
+ h: "c",
176
+ cpp: "cpp",
177
+ hpp: "cpp",
178
+ css: "css",
179
+ scss: "scss",
180
+ html: "html",
181
+ xml: "xml",
182
+ json: "json",
183
+ yaml: "yaml",
184
+ yml: "yaml",
185
+ toml: "toml",
186
+ md: "md",
187
+ sh: "bash",
188
+ sql: "sql",
189
+ };
190
+ export function languageForPath(p) {
191
+ const base = p.split("/").pop() ?? p;
192
+ if (base === "Dockerfile" || base.startsWith("Dockerfile."))
193
+ return "dockerfile";
194
+ const dot = base.lastIndexOf(".");
195
+ if (dot < 0)
196
+ return "";
197
+ return LANG_BY_EXT[base.slice(dot + 1).toLowerCase()] ?? "";
198
+ }
199
+ /**
200
+ * One copyable block per line comment: `file:line` anchor, quoted code,
201
+ * free text. The line anchor uses the new-file number (what the reader
202
+ * sees in the working tree); deleted lines fall back to the old number
203
+ * and are marked with a `-` in the quote. A multi-line selection anchors
204
+ * as `file:start-end` with the selected lines quoted in order.
205
+ */
206
+ export function formatReviewComment(input) {
207
+ const lang = languageForPath(input.file);
208
+ const quoted = input.code
209
+ .replace(/\n$/, "")
210
+ .split("\n")
211
+ .map((l) => `> ${l}`)
212
+ .join("\n");
213
+ const span = input.endLine !== undefined && input.endLine !== input.line ? `${input.line}-${input.endLine}` : `${input.line}`;
214
+ const head = `\`${input.file}:${span}\``;
215
+ const fence = `\`\`\`${lang}`.replace(/\s+$/, "");
216
+ const mark = input.deleted ? "> - (deleted line)\n" : "";
217
+ const body = input.body.trim();
218
+ return `${head}\n${mark}> ${fence}\n${quoted}\n> \`\`\`\n${body}`;
219
+ }
220
+ async function sh(file, args, cwd) {
221
+ const { stdout } = await execFileAsync(file, args, { cwd, maxBuffer: 16 * 1024 * 1024 });
222
+ return stdout;
223
+ }
224
+ /** `git diff --name-status -z` → status map (new path → entry). */
225
+ async function readStatusMap(root, ref) {
226
+ const map = new Map();
227
+ let out;
228
+ try {
229
+ out = await sh("git", ["diff", "--name-status", "-z", ref, "--"], root);
230
+ }
231
+ catch {
232
+ return map;
233
+ }
234
+ const parts = out.split("\0").filter((p) => p.length > 0);
235
+ for (let i = 0; i < parts.length; i++) {
236
+ const code = parts[i];
237
+ if (code.startsWith("R")) {
238
+ const oldPath = parts[i + 1] ?? "";
239
+ const newPath = parts[i + 2] ?? "";
240
+ map.set(newPath, { status: "renamed", oldPath });
241
+ i += 2;
242
+ }
243
+ else {
244
+ const p = parts[i + 1] ?? "";
245
+ const status = code.startsWith("A") ? "added" : code.startsWith("D") ? "deleted" : "modified";
246
+ map.set(p, { status, oldPath: p });
247
+ i += 1;
248
+ }
249
+ }
250
+ return map;
251
+ }
252
+ function synthesizeUntracked(root, rel) {
253
+ const abs = path.join(root, rel);
254
+ let stat;
255
+ try {
256
+ stat = fs.statSync(abs);
257
+ }
258
+ catch {
259
+ return null;
260
+ }
261
+ if (!stat.isFile())
262
+ return null;
263
+ if (stat.size > REVIEW_MAX_FILE_BYTES) {
264
+ return { path: rel, oldPath: rel, status: "added", hunks: [], binary: false, tooLarge: true };
265
+ }
266
+ let content;
267
+ try {
268
+ content = fs.readFileSync(abs, "utf8");
269
+ }
270
+ catch {
271
+ return { path: rel, oldPath: rel, status: "added", hunks: [], binary: true, tooLarge: false };
272
+ }
273
+ if (content.includes("\0")) {
274
+ return { path: rel, oldPath: rel, status: "added", hunks: [], binary: true, tooLarge: false };
275
+ }
276
+ const items = content.replace(/\n$/, "").split("\n");
277
+ const lines = items.map((text, idx) => ({ type: "add", oldNo: null, newNo: idx + 1, text }));
278
+ return {
279
+ path: rel,
280
+ oldPath: rel,
281
+ status: "added",
282
+ hunks: [{ header: `@@ -0,0 +1,${lines.length} @@`, oldStart: 0, oldCount: 0, newStart: 1, newCount: lines.length, lines }],
283
+ binary: false,
284
+ tooLarge: false,
285
+ };
286
+ }
287
+ /**
288
+ * Local review source of truth: `git diff <ref>` (working tree vs ref,
289
+ * which already covers staged + unstaged) plus untracked files.
290
+ * Throws when cwd is not inside a git repo.
291
+ */
292
+ export async function getLocalReview(cwd, opts = {}) {
293
+ const ref = (opts.ref ?? "HEAD").trim() || "HEAD";
294
+ if (ref.startsWith("-") || ref.length > 128 || /[\0\n]/.test(ref)) {
295
+ throw new Error(`invalid ref: ${ref}`);
296
+ }
297
+ let root;
298
+ try {
299
+ root = (await sh("git", ["rev-parse", "--show-toplevel"], cwd)).trim();
300
+ }
301
+ catch {
302
+ throw new Error(`not a git repository: ${cwd}`);
303
+ }
304
+ let base = null;
305
+ try {
306
+ base = (await sh("git", ["rev-parse", "--verify", `${ref}^{commit}`], root)).trim();
307
+ }
308
+ catch {
309
+ base = null;
310
+ }
311
+ const fileArgs = opts.file ? ["--", opts.file] : ["--"];
312
+ let patch = "";
313
+ try {
314
+ // Forced prefixes: user-level diff.srcPrefix/dstPrefix/noprefix config
315
+ // must not leak into the parse (seen in the wild as c//w/ prefixes).
316
+ patch = await sh("git", ["-c", "diff.noprefix=false", "diff", "--no-color", "--no-ext-diff", "--unified=3", "--src-prefix=a/", "--dst-prefix=b/", ref, ...fileArgs], root);
317
+ }
318
+ catch {
319
+ patch = "";
320
+ }
321
+ if (patch.length > REVIEW_PATCH_MAX_BYTES) {
322
+ return { root, ref, base, files: [], truncated: true };
323
+ }
324
+ const statusMap = opts.file ? new Map() : await readStatusMap(root, ref);
325
+ let files = parseUnifiedDiff(patch);
326
+ for (const f of files) {
327
+ const entry = statusMap.get(f.path);
328
+ if (entry) {
329
+ f.status = entry.status;
330
+ f.oldPath = entry.oldPath;
331
+ }
332
+ }
333
+ if (!opts.file) {
334
+ try {
335
+ const out = await sh("git", ["ls-files", "--others", "--exclude-standard", "-z"], root);
336
+ const untracked = out.split("\0").filter(Boolean);
337
+ for (const rel of untracked) {
338
+ if (files.some((f) => f.path === rel))
339
+ continue;
340
+ const synth = synthesizeUntracked(root, rel);
341
+ if (synth)
342
+ files.push(synth);
343
+ }
344
+ }
345
+ catch {
346
+ // Untracked listing is best-effort; tracked diff above still stands.
347
+ }
348
+ }
349
+ files.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
350
+ let truncated = false;
351
+ if (files.length > REVIEW_MAX_FILES) {
352
+ files = files.slice(0, REVIEW_MAX_FILES);
353
+ truncated = true;
354
+ }
355
+ return { root, ref, base, files, truncated };
356
+ }
357
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/git/review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,236 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { detectBinary } from "../../drivers/helpers.js";
5
+ import { getRegistry } from "../../drivers/registry.js";
6
+ import { getCachedOrDiscoverModels } from "../../core/models.js";
7
+ import { parseEffort } from "../../core/driver.js";
8
+ import { DISPATCHER_PRESET } from "../../config/orchestrator-mode.js";
9
+ import { catalogWarning, judgeModelIn, resolveRoleContract, } from "../contract.js";
10
+ import { composeOrchestratorProse } from "../orchestrator-prose.js";
11
+ import { SESSION_ID_PATTERN } from "../runtime.js";
12
+ /**
13
+ * Codex has no system-prompt flag on its interactive TUI (no equivalent of
14
+ * Claude's --append-system-prompt-file), so the role contract travels as a
15
+ * `-c developer_instructions` override instead of the session's first prompt.
16
+ * Probed against codex-cli 0.154.0: the key lands as the opening `developer`
17
+ * message (visible via `codex debug prompt-input`), the TUI starts empty, and
18
+ * no turn is spent. `model_instructions_file` is deliberately avoided: it
19
+ * replaces the sanctioned model instructions instead of appending to them.
20
+ */
21
+ export function initialPrompt(pluginDir, role, mode = DISPATCHER_PRESET) {
22
+ const { agentBody, ultra } = resolveRoleContract(pluginDir, role, mode);
23
+ const orchestratorProse = role === "orchestrator" ? composeOrchestratorProse(mode) : "";
24
+ const body = orchestratorProse ? `${agentBody}\n\n${orchestratorProse}` : agentBody;
25
+ return `${ultra.trimEnd()}\n\n${body}`;
26
+ }
27
+ /**
28
+ * TOML-escape a contract for `-c developer_instructions="""..."""`. The value
29
+ * is parsed as TOML, so a raw `"` or `\` would break out of the string and
30
+ * inject a second config assignment. LF stays raw, which multiline basic
31
+ * strings allow; every other C0 control and DEL goes as `\uXXXX`, which has
32
+ * no raw form. No control literal appears in the source below: the branch is
33
+ * on the char code, so linters that flag control escapes stay quiet.
34
+ */
35
+ export function developerInstructionsOverride(prompt) {
36
+ let escaped = "";
37
+ for (const c of prompt) {
38
+ const code = c.codePointAt(0) ?? 0;
39
+ if (c === "\\")
40
+ escaped += "\\\\";
41
+ else if (c === '"')
42
+ escaped += '\\"';
43
+ else if (c === "\n")
44
+ escaped += c;
45
+ else if (code < 0x20 || code === 0x7f) {
46
+ escaped += `\\u${code.toString(16).padStart(4, "0").toUpperCase()}`;
47
+ }
48
+ else
49
+ escaped += c;
50
+ }
51
+ return `developer_instructions="""${escaped}"""`;
52
+ }
53
+ /**
54
+ * Approximate role permissions with the only knob codex offers: the sandbox.
55
+ * Codex cannot deny reads while allowing dispatch the way the opencode
56
+ * permission map can, so the read-only roles land on read-only and everything
57
+ * that dispatches work lands on workspace-write. With the default bypass this
58
+ * mapping is dormant; it only binds under --no-bypass.
59
+ */
60
+ export function roleSandbox(role) {
61
+ switch (role) {
62
+ case "reviewer":
63
+ case "auditor":
64
+ return "read-only";
65
+ case "general":
66
+ case "orchestrator":
67
+ return "workspace-write";
68
+ }
69
+ }
70
+ /**
71
+ * Interactive codex argv. Mirrors the exec driver's flag spellings (measured
72
+ * against codex-cli 0.154.0): resume is a subcommand, a resumed thread keeps
73
+ * its policy and working root, and effort is a TOML config override.
74
+ *
75
+ * The role contract travels as `-c developer_instructions`, never as the
76
+ * positional [PROMPT]: the TUI starts empty and no turn is spent. Multiple
77
+ * `-c` flags coexist (effort + instructions), each kept adjacent to its
78
+ * value or codex reads the next flag as the value.
79
+ *
80
+ * No model default is pinned here: without an explicit model the flag is
81
+ * omitted and the codex config.toml answers.
82
+ */
83
+ export function buildOpenArgs(role, flags, pluginDir, passthrough, openCwd, mode = DISPATCHER_PRESET) {
84
+ const isResume = flags.resume !== undefined;
85
+ const args = [];
86
+ if (isResume)
87
+ args.push("resume", flags.resume);
88
+ if (flags.model)
89
+ args.push("-m", flags.model);
90
+ if (!isResume)
91
+ args.push("-s", roleSandbox(role));
92
+ if (flags.bypass !== false)
93
+ args.push("--dangerously-bypass-approvals-and-sandbox");
94
+ // Validated, never interpolated raw: the value lands inside a TOML string
95
+ // and an unescaped quote would inject a second config assignment.
96
+ if (flags.effort)
97
+ args.push("-c", `model_reasoning_effort="${parseEffort(flags.effort)}"`);
98
+ // The resume slot takes an optional follow-up prompt, so a resumed thread
99
+ // never gets the role contract re-injected as a new message.
100
+ if (!isResume)
101
+ args.push("-c", developerInstructionsOverride(initialPrompt(pluginDir, role, mode)));
102
+ if (!isResume)
103
+ args.push("-C", openCwd);
104
+ args.push(...passthrough);
105
+ return args;
106
+ }
107
+ export const CODEX_NOT_FOUND = "Codex was not found on PATH. Install Codex and ensure `codex` is available.";
108
+ /**
109
+ * The codex half of the split: find this harness's catalog, judge it with
110
+ * the shared pure verdict. Kept while the suite pins this shape.
111
+ */
112
+ export function judgeModel(model, catalogs, fromConfig) {
113
+ return judgeModelIn(catalogs?.find((item) => item.agent === "codex"), model, fromConfig, "Codex");
114
+ }
115
+ export async function preflight(model, fromConfig) {
116
+ let catalogs;
117
+ try {
118
+ catalogs = await getCachedOrDiscoverModels(getRegistry(), { agent: "codex" });
119
+ }
120
+ catch (error) {
121
+ // A catalog that cannot be reached is not evidence against the model, so
122
+ // this warns and lets the launch decide.
123
+ const text = error instanceof Error ? error.message : String(error);
124
+ console.warn(catalogWarning("Codex", model, `unavailable (${text})`));
125
+ return;
126
+ }
127
+ const verdict = judgeModel(model, catalogs, fromConfig);
128
+ if (verdict.kind === "ok")
129
+ return;
130
+ if (verdict.kind === "unknown-catalog") {
131
+ console.warn(verdict.warning);
132
+ return;
133
+ }
134
+ throw new Error(verdict.error);
135
+ }
136
+ /**
137
+ * Returns the resolved path rather than a boolean so everything downstream
138
+ * launches the exact binary that was checked.
139
+ */
140
+ export async function resolveBinary() {
141
+ const installation = await detectBinary("codex");
142
+ if (!installation.installed || !installation.path) {
143
+ throw new Error(CODEX_NOT_FOUND);
144
+ }
145
+ return installation.path;
146
+ }
147
+ /**
148
+ * Where the TUI persists rollout files, honouring CODEX_HOME like the harness
149
+ * does. Day directories use the local date, matching the filenames codex
150
+ * writes.
151
+ */
152
+ export function codexSessionsDir(now = new Date(), home = os.homedir(), codexHome = process.env.CODEX_HOME) {
153
+ const base = codexHome && codexHome.length > 0 ? codexHome : path.join(home, ".codex");
154
+ const pad = (n) => String(n).padStart(2, "0");
155
+ return path.join(base, "sessions", String(now.getFullYear()), pad(now.getMonth() + 1), pad(now.getDate()));
156
+ }
157
+ /**
158
+ * Best-effort snapshot of the day's rollout files. A missing directory means
159
+ * no rollouts yet, not a failed capture; any other read failure stays
160
+ * undefined so the close path refuses the diff instead of guessing.
161
+ */
162
+ export function readCodexRollouts(dir = codexSessionsDir()) {
163
+ try {
164
+ return fs
165
+ .readdirSync(dir)
166
+ .filter((file) => file.startsWith("rollout-") && file.endsWith(".jsonl"))
167
+ .sort();
168
+ }
169
+ catch {
170
+ try {
171
+ if (!fs.existsSync(dir))
172
+ return [];
173
+ }
174
+ catch { }
175
+ return undefined;
176
+ }
177
+ }
178
+ /**
179
+ * Who a rollout file belongs to, read off its opening session_meta line.
180
+ * Anything unparseable means "cannot tell", and a missing hint beats a
181
+ * wrong one.
182
+ */
183
+ export function rolloutIdentity(file) {
184
+ try {
185
+ const first = fs.readFileSync(file, "utf8").split("\n", 1)[0] ?? "";
186
+ const line = JSON.parse(first);
187
+ const id = line?.payload?.id;
188
+ if (typeof id !== "string" || !SESSION_ID_PATTERN.test(id))
189
+ return undefined;
190
+ const cwd = line?.payload?.cwd;
191
+ return { id, ...(typeof cwd === "string" && cwd ? { cwd } : {}) };
192
+ }
193
+ catch {
194
+ return undefined;
195
+ }
196
+ }
197
+ /**
198
+ * The thread id a rollout file belongs to. When the launching cwd is known
199
+ * it must match the rollout's own cwd: two concurrent launches in different
200
+ * directories must never record each other's session.
201
+ */
202
+ export function threadIdFromRollout(file, expectedCwd) {
203
+ const identity = rolloutIdentity(file);
204
+ if (!identity)
205
+ return undefined;
206
+ if (expectedCwd !== undefined && identity.cwd !== expectedCwd)
207
+ return undefined;
208
+ return identity.id;
209
+ }
210
+ /**
211
+ * The id of the session created between snapshots, or undefined. Zero or
212
+ * ambiguous new files mean "cannot tell". Snapshots span directories so a
213
+ * session crossing midnight is still found; a resumed thread appends to its
214
+ * existing rollout, so resumes fall back to the --resume value at the close
215
+ * path instead of this diff.
216
+ */
217
+ export function diffCodexRolloutsAcross(before, snapshots, expectedCwd) {
218
+ const known = new Set(before);
219
+ const fresh = [];
220
+ for (const snapshot of snapshots) {
221
+ for (const file of snapshot.files) {
222
+ if (!known.has(file))
223
+ fresh.push({ dir: snapshot.dir, file });
224
+ }
225
+ }
226
+ if (fresh.length !== 1)
227
+ return undefined;
228
+ return threadIdFromRollout(path.join(fresh[0].dir, fresh[0].file), expectedCwd);
229
+ }
230
+ /**
231
+ * Single-day form of the across-directories diff.
232
+ */
233
+ export function diffCodexRollouts(dir, before, after, expectedCwd) {
234
+ return diffCodexRolloutsAcross(before, [{ dir, files: after }], expectedCwd);
235
+ }
236
+ //# sourceMappingURL=codex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../../src/open/launchers/codex.ts"],"names":[],"mappings":"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"}