ytimesy 0.1.1 → 0.1.2

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 (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +76 -15
  3. package/dist/ytimesy.mjs +424 -424
  4. package/package.json +35 -5
package/dist/ytimesy.mjs CHANGED
@@ -9,7 +9,260 @@ import { randomBytes } from "node:crypto";
9
9
  import fs16 from "node:fs";
10
10
  import path20 from "node:path";
11
11
 
12
- // ../../src/domain/local-import-view.ts
12
+ // src/api.ts
13
+ var ApiError = class extends Error {
14
+ constructor(message, status, path21) {
15
+ super(message);
16
+ this.status = status;
17
+ this.path = path21;
18
+ }
19
+ status;
20
+ path;
21
+ };
22
+ var TIMEOUT_MS = 12e4;
23
+ async function errorMessage(response) {
24
+ const text = (await response.text().catch(() => "")).trim();
25
+ try {
26
+ const json = JSON.parse(text);
27
+ if (typeof json.error === "string") return json.error;
28
+ } catch {
29
+ }
30
+ return text.slice(0, 500) || `HTTP ${response.status}`;
31
+ }
32
+ var ImportApi = class {
33
+ constructor(base, token = null, userAgent = "ytimesy-cli") {
34
+ this.base = base;
35
+ this.token = token;
36
+ this.userAgent = userAgent;
37
+ }
38
+ base;
39
+ token;
40
+ userAgent;
41
+ setToken(token) {
42
+ this.token = token;
43
+ }
44
+ async request(path21, init) {
45
+ const url = new URL(path21, this.base).toString();
46
+ let response;
47
+ try {
48
+ response = await fetch(url, {
49
+ method: init.method,
50
+ body: init.body,
51
+ headers: {
52
+ "user-agent": this.userAgent,
53
+ ...init.contentType ? { "content-type": init.contentType } : {},
54
+ ...this.token ? { authorization: `Bearer ${this.token}` } : {}
55
+ },
56
+ signal: AbortSignal.timeout(TIMEOUT_MS)
57
+ });
58
+ } catch (error) {
59
+ throw new ApiError(
60
+ `Could not reach ${new URL(this.base).host}: ${error.message}`,
61
+ 0,
62
+ path21
63
+ );
64
+ }
65
+ if (!response.ok)
66
+ throw new ApiError(await errorMessage(response), response.status, path21);
67
+ return await response.json();
68
+ }
69
+ json(path21, body) {
70
+ return this.request(path21, {
71
+ method: "POST",
72
+ body: JSON.stringify(body),
73
+ contentType: "application/json"
74
+ });
75
+ }
76
+ start(body) {
77
+ return this.json("/api/local-import/start", body);
78
+ }
79
+ plan(groups) {
80
+ return this.json("/api/local-import/plan", {
81
+ groups
82
+ });
83
+ }
84
+ /** A project for a repository the ytimesy app reaches (409: it cannot see it yet). */
85
+ createProject(body) {
86
+ return this.json(
87
+ "/api/local-import/create-project",
88
+ body
89
+ );
90
+ }
91
+ secrets(body) {
92
+ return this.json("/api/local-import/secrets", body);
93
+ }
94
+ session(body) {
95
+ return this.json("/api/local-import/sessions", body);
96
+ }
97
+ transcript(uploadPath, archive) {
98
+ return this.request(uploadPath, {
99
+ method: "PUT",
100
+ body: new Blob([new Uint8Array(archive)]),
101
+ contentType: "application/gzip"
102
+ });
103
+ }
104
+ finish(body) {
105
+ return this.json("/api/local-import/finish", body);
106
+ }
107
+ cancel() {
108
+ return this.json("/api/local-import/cancel", {});
109
+ }
110
+ };
111
+
112
+ // src/env-file.ts
113
+ import fs from "node:fs";
114
+ import path from "node:path";
115
+ var ENV_FILES = [".env", ".env.local"];
116
+ var NAME = /^[A-Za-z_][A-Za-z0-9_.-]*$/;
117
+ function unescapeDouble(text) {
118
+ return text.replace(
119
+ /\\([nrt"\\$])/g,
120
+ (_, char) => char === "n" ? "\n" : char === "r" ? "\r" : char === "t" ? " " : char
121
+ );
122
+ }
123
+ function parseEnvText(text) {
124
+ const variables = /* @__PURE__ */ new Map();
125
+ const source = text.replace(/^\uFEFF/, "").replace(/\r\n?/g, "\n");
126
+ let index = 0;
127
+ while (index < source.length) {
128
+ const lineEnd = source.indexOf("\n", index);
129
+ const end = lineEnd === -1 ? source.length : lineEnd;
130
+ const line = source.slice(index, end);
131
+ const match = /^\s*(?:export\s+)?([^=\s]+)\s*=\s*/.exec(line);
132
+ if (!match || line.trimStart().startsWith("#")) {
133
+ index = end + 1;
134
+ continue;
135
+ }
136
+ const name = match[1];
137
+ const valueStart = index + match[0].length;
138
+ const quote = source[valueStart];
139
+ let value;
140
+ if (quote === '"' || quote === "'" || quote === "`") {
141
+ const close = source.indexOf(quote, valueStart + 1);
142
+ let at = close;
143
+ while (quote === '"' && at !== -1) {
144
+ let slashes = 0;
145
+ for (let back = at - 1; source[back] === "\\"; back--) slashes++;
146
+ if (slashes % 2 === 0) break;
147
+ at = source.indexOf(quote, at + 1);
148
+ }
149
+ if (at === -1) {
150
+ value = line.slice(match[0].length).trim();
151
+ index = end + 1;
152
+ } else {
153
+ const raw = source.slice(valueStart + 1, at);
154
+ value = quote === '"' ? unescapeDouble(raw) : raw;
155
+ const after = source.indexOf("\n", at);
156
+ index = after === -1 ? source.length : after + 1;
157
+ }
158
+ } else {
159
+ value = line.slice(match[0].length).replace(/(^|\s)#.*$/, "").trim();
160
+ index = end + 1;
161
+ }
162
+ if (NAME.test(name)) variables.set(name, value);
163
+ }
164
+ return [...variables].map(([name, value]) => ({ name, value }));
165
+ }
166
+ function readEnvFiles(folder) {
167
+ const variables = [];
168
+ for (const source of ENV_FILES) {
169
+ let text;
170
+ try {
171
+ const file = path.join(folder, source);
172
+ if (!fs.statSync(file).isFile()) continue;
173
+ text = fs.readFileSync(file, "utf8");
174
+ } catch {
175
+ continue;
176
+ }
177
+ for (const variable of parseEnvText(text))
178
+ variables.push({ ...variable, source });
179
+ }
180
+ return variables;
181
+ }
182
+ var TOO_COMMON = /^(?:true|false|yes|no|null|none|on|off|development|production|staging|test|localhost|127\.0\.0\.1|0\.0\.0\.0|\d+(?:\.\d+)?)$/i;
183
+ function redactionValues(variables) {
184
+ const values = /* @__PURE__ */ new Set();
185
+ for (const { value } of variables) {
186
+ const trimmed = value.trim();
187
+ if (trimmed.length >= 8 && !TOO_COMMON.test(trimmed)) values.add(trimmed);
188
+ if (value.length >= 8 && value !== trimmed && !TOO_COMMON.test(value))
189
+ values.add(value);
190
+ }
191
+ return [...values];
192
+ }
193
+
194
+ // src/github-cli.ts
195
+ import { execFileSync } from "node:child_process";
196
+ var GithubCliError = class extends Error {
197
+ };
198
+ function gh(args, env) {
199
+ return execFileSync("gh", args, {
200
+ env: {
201
+ ...env,
202
+ GH_PROMPT_DISABLED: "1",
203
+ NO_COLOR: "1"
204
+ },
205
+ encoding: "utf8",
206
+ timeout: 6e4,
207
+ stdio: ["ignore", "pipe", "pipe"]
208
+ });
209
+ }
210
+ function githubCliStatus(env) {
211
+ try {
212
+ gh(["--version"], env);
213
+ } catch {
214
+ return { ready: false, reason: "missing" };
215
+ }
216
+ try {
217
+ gh(["auth", "status", "--hostname", "github.com"], env);
218
+ return { ready: true };
219
+ } catch {
220
+ return { ready: false, reason: "signed-out" };
221
+ }
222
+ }
223
+ function githubCliNextStep(status) {
224
+ const otherwise = "or create the repository at https://github.com/new, make it this folder's origin remote (git init first if needed) and re-run without --create-repo";
225
+ return status.ready ? "" : status.reason === "missing" ? `Install the GitHub CLI (https://cli.github.com) and run \`gh auth login\`, then re-run the same command; ${otherwise}.` : `Run \`gh auth login\` to sign in to GitHub, then re-run the same command; ${otherwise}.`;
226
+ }
227
+ function createPrivateRepository(name, env) {
228
+ let output;
229
+ try {
230
+ output = gh(
231
+ [
232
+ "api",
233
+ "--method",
234
+ "POST",
235
+ "user/repos",
236
+ "-f",
237
+ `name=${name}`,
238
+ "-F",
239
+ "private=true"
240
+ ],
241
+ env
242
+ );
243
+ } catch (error) {
244
+ const failure = error;
245
+ const text = `${String(failure.stdout ?? "")} ${String(failure.stderr ?? "")}`;
246
+ if (/name already exists/i.test(text))
247
+ throw new GithubCliError(
248
+ `A repository named ${name} already exists on your GitHub account.`
249
+ );
250
+ throw new GithubCliError(
251
+ `gh could not create ${name}: ${text.trim().split("\n").slice(-2).join(" ") || error.message}`
252
+ );
253
+ }
254
+ const created = JSON.parse(output);
255
+ if (!created.full_name)
256
+ throw new GithubCliError(`gh did not return the new repository ${name}.`);
257
+ return {
258
+ fullName: created.full_name,
259
+ defaultBranch: created.default_branch || "main",
260
+ cloneUrl: created.clone_url || `https://github.com/${created.full_name}.git`,
261
+ sshUrl: created.ssh_url || `git@github.com:${created.full_name}.git`
262
+ };
263
+ }
264
+
265
+ // src/local-agents.ts
13
266
  var LOCAL_AGENT_NAMES = {
14
267
  claude: "Claude Code",
15
268
  codex: "Codex",
@@ -20,9 +273,9 @@ var LOCAL_AGENT_NAMES = {
20
273
  cursor: "Cursor"
21
274
  };
22
275
 
23
- // ../../src/local-sessions/io.ts
24
- import fs from "node:fs";
25
- import path from "node:path";
276
+ // src/local-sessions/io.ts
277
+ import fs2 from "node:fs";
278
+ import path2 from "node:path";
26
279
  import zlib from "node:zlib";
27
280
  var NEWLINE = 10;
28
281
  var DEFAULT_CHUNK_BYTES = 256 * 1024;
@@ -51,14 +304,14 @@ function asArray(value) {
51
304
  }
52
305
  function fileMtimeMs(file) {
53
306
  try {
54
- return fs.statSync(file).mtimeMs;
307
+ return fs2.statSync(file).mtimeMs;
55
308
  } catch {
56
309
  return void 0;
57
310
  }
58
311
  }
59
312
  function listDirectory(dir) {
60
313
  try {
61
- return fs.readdirSync(dir, { withFileTypes: true });
314
+ return fs2.readdirSync(dir, { withFileTypes: true });
62
315
  } catch {
63
316
  return [];
64
317
  }
@@ -66,24 +319,24 @@ function listDirectory(dir) {
66
319
  function readHeadText(file, maxBytes) {
67
320
  let fd;
68
321
  try {
69
- fd = fs.openSync(file, "r");
322
+ fd = fs2.openSync(file, "r");
70
323
  const buffer = Buffer.alloc(maxBytes);
71
- const bytesRead = fs.readSync(fd, buffer, 0, maxBytes, 0);
324
+ const bytesRead = fs2.readSync(fd, buffer, 0, maxBytes, 0);
72
325
  const head = buffer.subarray(0, bytesRead);
73
326
  if (!isCompressedFile(file)) return head.toString("utf8");
74
327
  return zstdPrefix(head).subarray(0, maxBytes).toString("utf8");
75
328
  } catch {
76
329
  return "";
77
330
  } finally {
78
- if (fd !== void 0) fs.closeSync(fd);
331
+ if (fd !== void 0) fs2.closeSync(fd);
79
332
  }
80
333
  }
81
334
  function readCompressedHead(file, compressedBytes) {
82
335
  let fd;
83
336
  try {
84
- fd = fs.openSync(file, "r");
337
+ fd = fs2.openSync(file, "r");
85
338
  const buffer = Buffer.alloc(compressedBytes);
86
- const bytesRead = fs.readSync(fd, buffer, 0, compressedBytes, 0);
339
+ const bytesRead = fs2.readSync(fd, buffer, 0, compressedBytes, 0);
87
340
  return {
88
341
  text: zstdPrefix(buffer.subarray(0, bytesRead)).toString("utf8"),
89
342
  compressedRead: bytesRead
@@ -91,7 +344,7 @@ function readCompressedHead(file, compressedBytes) {
91
344
  } catch {
92
345
  return { text: "", compressedRead: 0 };
93
346
  } finally {
94
- if (fd !== void 0) fs.closeSync(fd);
347
+ if (fd !== void 0) fs2.closeSync(fd);
95
348
  }
96
349
  }
97
350
  function isCompressedFile(file) {
@@ -116,7 +369,7 @@ function decompressedFile(file) {
116
369
  const decompress = zlib.zstdDecompressSync;
117
370
  if (!decompress) return void 0;
118
371
  try {
119
- const data = decompress(fs.readFileSync(file));
372
+ const data = decompress(fs2.readFileSync(file));
120
373
  decompressedCache = { key, data };
121
374
  return data;
122
375
  } catch {
@@ -141,14 +394,14 @@ function openByteSource(file) {
141
394
  }
142
395
  let fd;
143
396
  try {
144
- fd = fs.openSync(file, "r");
397
+ fd = fs2.openSync(file, "r");
145
398
  } catch {
146
399
  return void 0;
147
400
  }
148
401
  return {
149
- size: fs.fstatSync(fd).size,
150
- read: (target, length, position) => fs.readSync(fd, target, 0, length, position),
151
- close: () => fs.closeSync(fd)
402
+ size: fs2.fstatSync(fd).size,
403
+ read: (target, length, position) => fs2.readSync(fd, target, 0, length, position),
404
+ close: () => fs2.closeSync(fd)
152
405
  };
153
406
  }
154
407
  function readFirstLine(file) {
@@ -231,23 +484,23 @@ function* linesBackward(file, chunkBytes = DEFAULT_CHUNK_BYTES) {
231
484
  }
232
485
  }
233
486
  function canonicalPath(input) {
234
- const resolved = path.resolve(input);
487
+ const resolved = path2.resolve(input);
235
488
  try {
236
- return fs.realpathSync.native(resolved);
489
+ return fs2.realpathSync.native(resolved);
237
490
  } catch {
238
491
  return resolved;
239
492
  }
240
493
  }
241
494
  function isPathInside(candidate, root) {
242
495
  if (candidate === root) return true;
243
- const prefix = root.endsWith(path.sep) ? root : root + path.sep;
496
+ const prefix = root.endsWith(path2.sep) ? root : root + path2.sep;
244
497
  return candidate.startsWith(prefix);
245
498
  }
246
499
  function findGitRoot(start) {
247
500
  let current = canonicalPath(start);
248
501
  while (true) {
249
- if (fs.existsSync(path.join(current, ".git"))) return current;
250
- const parent = path.dirname(current);
502
+ if (fs2.existsSync(path2.join(current, ".git"))) return current;
503
+ const parent = path2.dirname(current);
251
504
  if (parent === current) return void 0;
252
505
  current = parent;
253
506
  }
@@ -256,17 +509,17 @@ function fileUrlToPath(value) {
256
509
  return value.startsWith("file://") ? decodeURIComponent(value.slice("file://".length)) : value;
257
510
  }
258
511
 
259
- // ../../src/local-sessions/machine.ts
260
- import fs8 from "node:fs";
512
+ // src/local-sessions/machine.ts
513
+ import fs9 from "node:fs";
261
514
  import os9 from "node:os";
262
- import path11 from "node:path";
515
+ import path12 from "node:path";
263
516
  import { performance } from "node:perf_hooks";
264
517
 
265
- // ../../src/local-sessions/claude.ts
518
+ // src/local-sessions/claude.ts
266
519
  import os from "node:os";
267
- import path2 from "node:path";
520
+ import path3 from "node:path";
268
521
 
269
- // ../../src/local-sessions/tool-calls.ts
522
+ // src/local-sessions/tool-calls.ts
270
523
  var MAX_TOOL_OUTPUT_CHARS = 3e3;
271
524
  var MAX_TOOL_INPUT_CHARS = 8e3;
272
525
  var SHELL_TOOLS = /* @__PURE__ */ new Set([
@@ -458,7 +711,7 @@ function setToolOutput(call, output) {
458
711
  if (text) call.output = truncateText(text, MAX_TOOL_OUTPUT_CHARS);
459
712
  }
460
713
 
461
- // ../../src/local-sessions/transcript.ts
714
+ // src/local-sessions/transcript.ts
462
715
  var BUDGET_SLACK_RATIO = 0.25;
463
716
  var TURN_ALIGNMENT_LIMIT_CHARS = 4e5;
464
717
  function visitTranscriptRecords(file, scan, mode, visit) {
@@ -634,7 +887,7 @@ function titleFromPrompt(prompt, maxChars = 80) {
634
887
  return `${(lastSpace > maxChars / 2 ? cut.slice(0, lastSpace) : cut).trimEnd()}\u2026`;
635
888
  }
636
889
 
637
- // ../../src/local-sessions/claude.ts
890
+ // src/local-sessions/claude.ts
638
891
  var HEAD_SCAN_LINES = 40;
639
892
  var MAX_FILES_VERIFIED_PER_DIRECTORY = 5;
640
893
  var INJECTED_USER_TEXT_PREFIXES = [
@@ -652,7 +905,7 @@ var INJECTED_USER_TEXT_PREFIXES = [
652
905
  "Caveat: The messages below were generated by the user while running local commands"
653
906
  ];
654
907
  function claudeProjectsDirectory(home = os.homedir()) {
655
- return path2.join(home, ".claude", "projects");
908
+ return path3.join(home, ".claude", "projects");
656
909
  }
657
910
  function encodeClaudeProjectDirectory(cwd) {
658
911
  return cwd.replace(/[^A-Za-z0-9]/g, "-");
@@ -682,9 +935,9 @@ function discoverClaudeSessions(repoRoot, home = os.homedir(), limit = 1) {
682
935
  if (!entry.isDirectory()) continue;
683
936
  if (entry.name !== encodedRoot && !entry.name.startsWith(`${encodedRoot}-`))
684
937
  continue;
685
- const directory = path2.join(projectsDirectory, entry.name);
938
+ const directory = path3.join(projectsDirectory, entry.name);
686
939
  const files = listDirectory(directory).filter((file) => file.isFile() && file.name.endsWith(".jsonl")).map((file) => {
687
- const location = path2.join(directory, file.name);
940
+ const location = path3.join(directory, file.name);
688
941
  return {
689
942
  location,
690
943
  id: file.name.slice(0, -".jsonl".length),
@@ -894,42 +1147,42 @@ function claudeSessionRefForFile(file) {
894
1147
  if (!cwd) return void 0;
895
1148
  return {
896
1149
  tool: "claude",
897
- id: path2.basename(file, ".jsonl"),
1150
+ id: path3.basename(file, ".jsonl"),
898
1151
  cwd,
899
1152
  updatedAt: fileMtimeMs(file) ?? 0,
900
1153
  location: file
901
1154
  };
902
1155
  }
903
1156
 
904
- // ../../src/local-sessions/codex.ts
1157
+ // src/local-sessions/codex.ts
905
1158
  import os2 from "node:os";
906
- import path4 from "node:path";
1159
+ import path5 from "node:path";
907
1160
 
908
- // ../../src/local-sessions/git.ts
909
- import fs2 from "node:fs";
910
- import path3 from "node:path";
1161
+ // src/local-sessions/git.ts
1162
+ import fs3 from "node:fs";
1163
+ import path4 from "node:path";
911
1164
  function readText(file) {
912
1165
  try {
913
- return fs2.readFileSync(file, "utf8");
1166
+ return fs3.readFileSync(file, "utf8");
914
1167
  } catch {
915
1168
  return void 0;
916
1169
  }
917
1170
  }
918
1171
  function gitDirectoryOf(root) {
919
- const dotGit = path3.join(root, ".git");
1172
+ const dotGit = path4.join(root, ".git");
920
1173
  let stat;
921
1174
  try {
922
- stat = fs2.statSync(dotGit);
1175
+ stat = fs3.statSync(dotGit);
923
1176
  } catch {
924
1177
  return void 0;
925
1178
  }
926
1179
  if (stat.isDirectory()) return dotGit;
927
1180
  const match = /^gitdir:\s*(.+)$/m.exec(readText(dotGit) ?? "");
928
- return match?.[1] ? path3.resolve(root, match[1].trim()) : void 0;
1181
+ return match?.[1] ? path4.resolve(root, match[1].trim()) : void 0;
929
1182
  }
930
1183
  function commonDirectoryOf(gitDirectory) {
931
- const pointer = readText(path3.join(gitDirectory, "commondir"))?.trim();
932
- return pointer ? canonicalPath(path3.resolve(gitDirectory, pointer)) : canonicalPath(gitDirectory);
1184
+ const pointer = readText(path4.join(gitDirectory, "commondir"))?.trim();
1185
+ return pointer ? canonicalPath(path4.resolve(gitDirectory, pointer)) : canonicalPath(gitDirectory);
933
1186
  }
934
1187
  function originUrlFromConfig(config) {
935
1188
  let inOrigin = false;
@@ -971,7 +1224,7 @@ function normalizeRemote(url) {
971
1224
  return `${host.toLowerCase()}/${cleaned}`;
972
1225
  }
973
1226
  function branchOf(gitDirectory) {
974
- const head = readText(path3.join(gitDirectory, "HEAD"))?.trim();
1227
+ const head = readText(path4.join(gitDirectory, "HEAD"))?.trim();
975
1228
  const match = head ? /^ref:\s*refs\/heads\/(.+)$/.exec(head) : null;
976
1229
  return match?.[1];
977
1230
  }
@@ -988,7 +1241,7 @@ function gitIdentity(folder) {
988
1241
  }
989
1242
  const commonDir = commonDirectoryOf(gitDirectory);
990
1243
  const remoteUrl = originUrlFromConfig(
991
- readText(path3.join(commonDir, "config")) ?? ""
1244
+ readText(path4.join(commonDir, "config")) ?? ""
992
1245
  );
993
1246
  const identity = {
994
1247
  root,
@@ -1006,7 +1259,7 @@ function sameRepository(a, b) {
1006
1259
  return a.remote !== void 0 && a.remote === b.remote;
1007
1260
  }
1008
1261
 
1009
- // ../../src/local-sessions/codex.ts
1262
+ // src/local-sessions/codex.ts
1010
1263
  var HEAD_BYTES_FOR_CWD = 512 * 1024;
1011
1264
  var ITEM_EVENT_PROBE_BYTES = 1024 * 1024;
1012
1265
  var BARE_RESPONSE_ITEM_TYPES = /* @__PURE__ */ new Set([
@@ -1029,8 +1282,8 @@ var INJECTED_USER_PREFIXES = [
1029
1282
  var IDE_CONTEXT_PREFIX = "# Context from my IDE";
1030
1283
  var IDE_REQUEST_HEADING = "## My request for Codex:";
1031
1284
  function codexSessionsDirectory(home = os2.homedir()) {
1032
- const codexHome = process.env.CODEX_HOME?.trim() || path4.join(home, ".codex");
1033
- return path4.join(codexHome, "sessions");
1285
+ const codexHome = process.env.CODEX_HOME?.trim() || path5.join(home, ".codex");
1286
+ return path5.join(codexHome, "sessions");
1034
1287
  }
1035
1288
  function readCodexSessionMeta(file) {
1036
1289
  const firstLine = readFirstLine(file);
@@ -1059,7 +1312,7 @@ function rolloutIdFromFileName(file) {
1059
1312
  const match = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl(?:\.zst)?$/.exec(
1060
1313
  file
1061
1314
  );
1062
- return match?.[1] ?? path4.basename(file).replace(/\.jsonl(?:\.zst)?$/, "");
1315
+ return match?.[1] ?? path5.basename(file).replace(/\.jsonl(?:\.zst)?$/, "");
1063
1316
  }
1064
1317
  function isRolloutFileName(name) {
1065
1318
  return name.endsWith(".jsonl") || name.endsWith(".jsonl.zst");
@@ -1068,7 +1321,7 @@ function listCodexRolloutFiles(sessionsDirectory) {
1068
1321
  const files = [];
1069
1322
  const walk = (directory, depth) => {
1070
1323
  for (const entry of listDirectory(directory)) {
1071
- const full = path4.join(directory, entry.name);
1324
+ const full = path5.join(directory, entry.name);
1072
1325
  if (entry.isDirectory() && depth < 3) walk(full, depth + 1);
1073
1326
  else if (entry.isFile() && isRolloutFileName(entry.name))
1074
1327
  files.push({ file: full, mtime: fileMtimeMs(full) ?? 0 });
@@ -1089,7 +1342,7 @@ function codexSessionRefForFile(file, mtime = fileMtimeMs(file) ?? 0) {
1089
1342
  };
1090
1343
  }
1091
1344
  function codexWorktreesDirectory(home = os2.homedir()) {
1092
- return path4.join(path4.dirname(codexSessionsDirectory(home)), "worktrees");
1345
+ return path5.join(path5.dirname(codexSessionsDirectory(home)), "worktrees");
1093
1346
  }
1094
1347
  function codexWorktreeMatches(cwd, file, repo, worktreesDirectory) {
1095
1348
  if (!repo || !isPathInside(cwd, worktreesDirectory)) return false;
@@ -1233,7 +1486,7 @@ function parseCallOutput(output) {
1233
1486
  return { text };
1234
1487
  }
1235
1488
  function relativeTo(base, file) {
1236
- return base && !path4.isAbsolute(file) ? path4.join(base, file) : file;
1489
+ return base && !path5.isAbsolute(file) ? path5.join(base, file) : file;
1237
1490
  }
1238
1491
  function toolCallFromItem(item) {
1239
1492
  const status = asString(item.status);
@@ -1473,13 +1726,13 @@ function readCodexSession(ref, options = {}) {
1473
1726
  };
1474
1727
  }
1475
1728
 
1476
- // ../../src/local-sessions/cursor-agent.ts
1729
+ // src/local-sessions/cursor-agent.ts
1477
1730
  import crypto from "node:crypto";
1478
- import fs3 from "node:fs";
1731
+ import fs4 from "node:fs";
1479
1732
  import os3 from "node:os";
1480
- import path5 from "node:path";
1733
+ import path6 from "node:path";
1481
1734
 
1482
- // ../../src/local-sessions/cursor-blobs.ts
1735
+ // src/local-sessions/cursor-blobs.ts
1483
1736
  function decodeProtobuf(buffer) {
1484
1737
  const fields = [];
1485
1738
  let offset = 0;
@@ -1655,7 +1908,7 @@ function* blobMessageEvents(message) {
1655
1908
  }
1656
1909
  }
1657
1910
 
1658
- // ../../src/local-sessions/events.ts
1911
+ // src/local-sessions/events.ts
1659
1912
  function turnsFromEvents(events, activityOnly = false) {
1660
1913
  const assembler = new TurnAssembler(activityOnly);
1661
1914
  const pending = [];
@@ -1705,7 +1958,7 @@ function firstUserText(events) {
1705
1958
  return void 0;
1706
1959
  }
1707
1960
 
1708
- // ../../src/local-sessions/sqlite.ts
1961
+ // src/local-sessions/sqlite.ts
1709
1962
  var SQLITE_MIN_NODE = "22.13";
1710
1963
  function loadSqlite() {
1711
1964
  try {
@@ -1719,22 +1972,22 @@ function sqliteAvailable() {
1719
1972
  return loadSqlite() !== void 0;
1720
1973
  }
1721
1974
 
1722
- // ../../src/local-sessions/cursor-agent.ts
1975
+ // src/local-sessions/cursor-agent.ts
1723
1976
  var PLACEHOLDER_TITLES = /* @__PURE__ */ new Set(["New Agent", "New Chat", "New chat"]);
1724
1977
  function cursorConfigDirectory(home = os3.homedir()) {
1725
1978
  const override = process.env.CURSOR_CONFIG_DIR?.trim();
1726
1979
  if (override) return override;
1727
1980
  const xdg = process.env.XDG_CONFIG_HOME?.trim();
1728
- return xdg ? path5.join(xdg, "cursor") : path5.join(home, ".cursor");
1981
+ return xdg ? path6.join(xdg, "cursor") : path6.join(home, ".cursor");
1729
1982
  }
1730
1983
  function cursorChatsDirectory(home = os3.homedir()) {
1731
- return path5.join(cursorConfigDirectory(home), "chats");
1984
+ return path6.join(cursorConfigDirectory(home), "chats");
1732
1985
  }
1733
1986
  function cursorChatFolderHash(cwd) {
1734
- return crypto.createHash("md5").update(path5.resolve(cwd)).digest("hex");
1987
+ return crypto.createHash("md5").update(path6.resolve(cwd)).digest("hex");
1735
1988
  }
1736
1989
  function openSqliteReadOnly(file) {
1737
- if (!fs3.existsSync(file)) return void 0;
1990
+ if (!fs4.existsSync(file)) return void 0;
1738
1991
  const sqlite = loadSqlite();
1739
1992
  if (!sqlite) return void 0;
1740
1993
  try {
@@ -1746,7 +1999,7 @@ function openSqliteReadOnly(file) {
1746
1999
  function readChatMeta(chatDirectory) {
1747
2000
  let text;
1748
2001
  try {
1749
- text = fs3.readFileSync(path5.join(chatDirectory, "meta.json"), "utf8");
2002
+ text = fs4.readFileSync(path6.join(chatDirectory, "meta.json"), "utf8");
1750
2003
  } catch {
1751
2004
  return void 0;
1752
2005
  }
@@ -1798,7 +2051,7 @@ function rootWorkspace(storeFile) {
1798
2051
  }
1799
2052
  }
1800
2053
  function cursorAgentSessionRefForDirectory(chatDirectory, folderCwd) {
1801
- const storeFile = path5.join(chatDirectory, "store.db");
2054
+ const storeFile = path6.join(chatDirectory, "store.db");
1802
2055
  const storeMtime = fileMtimeMs(storeFile);
1803
2056
  if (storeMtime === void 0) return void 0;
1804
2057
  const meta = readChatMeta(chatDirectory);
@@ -1807,7 +2060,7 @@ function cursorAgentSessionRefForDirectory(chatDirectory, folderCwd) {
1807
2060
  if (!cwd) return void 0;
1808
2061
  return {
1809
2062
  tool: "cursor-agent",
1810
- id: path5.basename(chatDirectory),
2063
+ id: path6.basename(chatDirectory),
1811
2064
  cwd,
1812
2065
  updatedAt: meta?.updatedAtMs ?? storeMtime,
1813
2066
  location: chatDirectory
@@ -1821,11 +2074,11 @@ function listCursorAgentSessionRefs(home = os3.homedir(), candidates = []) {
1821
2074
  const refs = [];
1822
2075
  for (const folder of listDirectory(chats)) {
1823
2076
  if (!folder.isDirectory()) continue;
1824
- const folderDirectory = path5.join(chats, folder.name);
2077
+ const folderDirectory = path6.join(chats, folder.name);
1825
2078
  for (const chat of listDirectory(folderDirectory)) {
1826
2079
  if (!chat.isDirectory()) continue;
1827
2080
  const ref = cursorAgentSessionRefForDirectory(
1828
- path5.join(folderDirectory, chat.name),
2081
+ path6.join(folderDirectory, chat.name),
1829
2082
  byHash.get(folder.name)
1830
2083
  );
1831
2084
  if (ref) refs.push(ref);
@@ -1838,7 +2091,7 @@ function discoverCursorAgentSessions(repoRoot, home = os3.homedir(), limit = 1)
1838
2091
  return listCursorAgentSessionRefs(home, [repoRoot, root]).filter((ref) => isPathInside(canonicalPath(ref.cwd), root)).slice(0, limit);
1839
2092
  }
1840
2093
  function cursorAgentConversation(chatDirectory) {
1841
- const database = openSqliteReadOnly(path5.join(chatDirectory, "store.db"));
2094
+ const database = openSqliteReadOnly(path6.join(chatDirectory, "store.db"));
1842
2095
  if (!database)
1843
2096
  return { events: [], unparsed: 0, unsupported: "store.db not readable" };
1844
2097
  try {
@@ -1901,7 +2154,7 @@ function readCursorAgentSession(ref, options = {}) {
1901
2154
  };
1902
2155
  }
1903
2156
  function cursorAgentMessageCount(chatDirectory) {
1904
- const database = openSqliteReadOnly(path5.join(chatDirectory, "store.db"));
2157
+ const database = openSqliteReadOnly(path6.join(chatDirectory, "store.db"));
1905
2158
  if (!database) return void 0;
1906
2159
  try {
1907
2160
  const rootId = asString(readStoreMeta(database)?.latestRootBlobId);
@@ -1913,28 +2166,28 @@ function cursorAgentMessageCount(chatDirectory) {
1913
2166
  }
1914
2167
  }
1915
2168
 
1916
- // ../../src/local-sessions/cursor-app.ts
1917
- import fs4 from "node:fs";
2169
+ // src/local-sessions/cursor-app.ts
2170
+ import fs5 from "node:fs";
1918
2171
  import os4 from "node:os";
1919
- import path6 from "node:path";
2172
+ import path7 from "node:path";
1920
2173
  var NEWEST_KNOWN_COMPOSER_VERSION = 18;
1921
2174
  var SHELL_TOOLS2 = /* @__PURE__ */ new Set(["run_terminal_command_v2", "run_terminal_cmd"]);
1922
2175
  function cursorUserDirectories(home = os4.homedir()) {
1923
2176
  const candidates = [
1924
- path6.join(home, "Library", "Application Support", "Cursor", "User"),
1925
- path6.join(
1926
- process.env.XDG_CONFIG_HOME?.trim() || path6.join(home, ".config"),
2177
+ path7.join(home, "Library", "Application Support", "Cursor", "User"),
2178
+ path7.join(
2179
+ process.env.XDG_CONFIG_HOME?.trim() || path7.join(home, ".config"),
1927
2180
  "Cursor",
1928
2181
  "User"
1929
2182
  ),
1930
- path6.join(
1931
- process.env.APPDATA?.trim() || path6.join(home, "AppData", "Roaming"),
2183
+ path7.join(
2184
+ process.env.APPDATA?.trim() || path7.join(home, "AppData", "Roaming"),
1932
2185
  "Cursor",
1933
2186
  "User"
1934
2187
  )
1935
2188
  ];
1936
2189
  return [...new Set(candidates)].filter(
1937
- (directory) => fs4.existsSync(path6.join(directory, "globalStorage", "state.vscdb"))
2190
+ (directory) => fs5.existsSync(path7.join(directory, "globalStorage", "state.vscdb"))
1938
2191
  );
1939
2192
  }
1940
2193
  function uriToFolder(uri) {
@@ -1947,7 +2200,7 @@ function uriToFolder(uri) {
1947
2200
  }
1948
2201
  function readJson(file) {
1949
2202
  try {
1950
- return parseJsonObject(fs4.readFileSync(file, "utf8"));
2203
+ return parseJsonObject(fs5.readFileSync(file, "utf8"));
1951
2204
  } catch {
1952
2205
  return void 0;
1953
2206
  }
@@ -1959,19 +2212,19 @@ function workspaceFolder(workspaceJson) {
1959
2212
  if (!workspaceFile) return void 0;
1960
2213
  const first = asObject(asArray(readJson(workspaceFile)?.folders)[0]);
1961
2214
  const relative = asString(first?.path) ?? uriToFolder(asString(first?.uri));
1962
- return relative ? path6.resolve(path6.dirname(workspaceFile), relative) : void 0;
2215
+ return relative ? path7.resolve(path7.dirname(workspaceFile), relative) : void 0;
1963
2216
  }
1964
2217
  function listCursorWorkspaces(userDirectory) {
1965
- const storage = path6.join(userDirectory, "workspaceStorage");
2218
+ const storage = path7.join(userDirectory, "workspaceStorage");
1966
2219
  const workspaces = [];
1967
2220
  for (const entry of listDirectory(storage)) {
1968
2221
  if (!entry.isDirectory()) continue;
1969
- const directory = path6.join(storage, entry.name);
1970
- const json = readJson(path6.join(directory, "workspace.json"));
2222
+ const directory = path7.join(storage, entry.name);
2223
+ const json = readJson(path7.join(directory, "workspace.json"));
1971
2224
  workspaces.push({
1972
2225
  id: entry.name,
1973
2226
  folder: json ? workspaceFolder(json) : void 0,
1974
- stateFile: path6.join(directory, "state.vscdb")
2227
+ stateFile: path7.join(directory, "state.vscdb")
1975
2228
  });
1976
2229
  }
1977
2230
  return workspaces;
@@ -2024,7 +2277,7 @@ SELECT id,
2024
2277
  FROM composer`;
2025
2278
  function listCursorComposers(userDirectory, options = {}) {
2026
2279
  const database = openSqliteReadOnly(
2027
- path6.join(userDirectory, "globalStorage", "state.vscdb")
2280
+ path7.join(userDirectory, "globalStorage", "state.vscdb")
2028
2281
  );
2029
2282
  if (!database)
2030
2283
  return {
@@ -2118,7 +2371,7 @@ function listCursorComposers(userDirectory, options = {}) {
2118
2371
  }
2119
2372
  }
2120
2373
  function composerRef(userDirectory, composer) {
2121
- const stateFile = path6.join(userDirectory, "globalStorage", "state.vscdb");
2374
+ const stateFile = path7.join(userDirectory, "globalStorage", "state.vscdb");
2122
2375
  return {
2123
2376
  tool: "cursor",
2124
2377
  id: composer.composerId,
@@ -2355,32 +2608,32 @@ function readCursorSession(ref, options = {}) {
2355
2608
  };
2356
2609
  }
2357
2610
 
2358
- // ../../src/local-sessions/gemini.ts
2611
+ // src/local-sessions/gemini.ts
2359
2612
  import crypto2 from "node:crypto";
2360
- import fs5 from "node:fs";
2613
+ import fs6 from "node:fs";
2361
2614
  import os5 from "node:os";
2362
- import path7 from "node:path";
2615
+ import path8 from "node:path";
2363
2616
  var SHELL_TOOL = "run_shell_command";
2364
2617
  function geminiDirectory(home = os5.homedir()) {
2365
2618
  const override = process.env.GEMINI_CLI_HOME?.trim();
2366
- return path7.join(override || home, ".gemini");
2619
+ return path8.join(override || home, ".gemini");
2367
2620
  }
2368
2621
  function geminiTempDirectory(home = os5.homedir()) {
2369
- return path7.join(geminiDirectory(home), "tmp");
2622
+ return path8.join(geminiDirectory(home), "tmp");
2370
2623
  }
2371
2624
  function geminiProjectHash(projectRoot) {
2372
2625
  return crypto2.createHash("sha256").update(projectRoot).digest("hex");
2373
2626
  }
2374
2627
  function readText2(file) {
2375
2628
  try {
2376
- return fs5.readFileSync(file, "utf8");
2629
+ return fs6.readFileSync(file, "utf8");
2377
2630
  } catch {
2378
2631
  return void 0;
2379
2632
  }
2380
2633
  }
2381
2634
  function registeredProjects(home) {
2382
2635
  const registry = parseJsonObject(
2383
- readText2(path7.join(geminiDirectory(home), "projects.json")) ?? ""
2636
+ readText2(path8.join(geminiDirectory(home), "projects.json")) ?? ""
2384
2637
  );
2385
2638
  const bySlug = /* @__PURE__ */ new Map();
2386
2639
  for (const [projectPath, slug] of Object.entries(
@@ -2399,7 +2652,7 @@ function listGeminiProjects(home = os5.homedir(), candidates = []) {
2399
2652
  for (const candidate of [...bySlug.values(), ...candidates]) {
2400
2653
  for (const variant of /* @__PURE__ */ new Set([
2401
2654
  candidate,
2402
- path7.resolve(candidate),
2655
+ path8.resolve(candidate),
2403
2656
  canonicalPath(candidate)
2404
2657
  ]))
2405
2658
  byHash.set(geminiProjectHash(variant), canonicalPath(variant));
@@ -2410,8 +2663,8 @@ function listGeminiProjects(home = os5.homedir(), candidates = []) {
2410
2663
  const projects = [];
2411
2664
  for (const entry of listDirectory(temp)) {
2412
2665
  if (!entry.isDirectory() || entry.name === "bin") continue;
2413
- const directory = path7.join(temp, entry.name);
2414
- const marker = readText2(path7.join(directory, ".project_root"))?.trim();
2666
+ const directory = path8.join(temp, entry.name);
2667
+ const marker = readText2(path8.join(directory, ".project_root"))?.trim();
2415
2668
  const registered = bySlug.get(entry.name);
2416
2669
  let cwd = marker || (registered ? canonicalPath(registered) : void 0);
2417
2670
  if (!cwd && /^[0-9a-f]{64}$/.test(entry.name)) cwd = hashLookup(entry.name);
@@ -2440,25 +2693,25 @@ function readGeminiSessionHead(file) {
2440
2693
  };
2441
2694
  }
2442
2695
  function sessionFiles(project) {
2443
- const chats = path7.join(project.directory, "chats");
2696
+ const chats = path8.join(project.directory, "chats");
2444
2697
  return listDirectory(chats).filter(
2445
2698
  (entry) => entry.isFile() && entry.name.startsWith("session-") && (entry.name.endsWith(".jsonl") || entry.name.endsWith(".json"))
2446
- ).map((entry) => path7.join(chats, entry.name));
2699
+ ).map((entry) => path8.join(chats, entry.name));
2447
2700
  }
2448
2701
  function geminiSessionRefForFile(file, cwd) {
2449
2702
  const head = readGeminiSessionHead(file);
2450
2703
  if (!head || head.kind === "subagent") return void 0;
2451
2704
  return {
2452
2705
  tool: "gemini",
2453
- id: head.sessionId ?? path7.basename(file).replace(/^session-|\.jsonl?$/g, ""),
2706
+ id: head.sessionId ?? path8.basename(file).replace(/^session-|\.jsonl?$/g, ""),
2454
2707
  cwd,
2455
2708
  updatedAt: fileMtimeMs(file) ?? 0,
2456
2709
  location: file
2457
2710
  };
2458
2711
  }
2459
2712
  function promptLogRefs(project, cwd) {
2460
- const logFile = path7.join(project.directory, "logs.json");
2461
- if (!fs5.existsSync(logFile)) return [];
2713
+ const logFile = path8.join(project.directory, "logs.json");
2714
+ if (!fs6.existsSync(logFile)) return [];
2462
2715
  let entries;
2463
2716
  try {
2464
2717
  entries = asArray(JSON.parse(readText2(logFile) ?? "[]"));
@@ -2467,7 +2720,7 @@ function promptLogRefs(project, cwd) {
2467
2720
  }
2468
2721
  const recorded = new Set(
2469
2722
  sessionFiles(project).map(
2470
- (file) => path7.basename(file).replace(/\.jsonl?$/, "").slice(-8)
2723
+ (file) => path8.basename(file).replace(/\.jsonl?$/, "").slice(-8)
2471
2724
  )
2472
2725
  );
2473
2726
  const latest = /* @__PURE__ */ new Map();
@@ -2665,7 +2918,7 @@ function readJsonFile(file) {
2665
2918
  }
2666
2919
  function parseGeminiSession(ref) {
2667
2920
  const file = ref.location;
2668
- const base = path7.basename(file);
2921
+ const base = path8.basename(file);
2669
2922
  if (base === "logs.json") {
2670
2923
  const events2 = [];
2671
2924
  for (const raw of asArray(readJsonFile(file))) {
@@ -2725,12 +2978,12 @@ function readGeminiSession(ref, options = {}) {
2725
2978
  };
2726
2979
  }
2727
2980
 
2728
- // ../../src/local-sessions/grok.ts
2729
- import fs6 from "node:fs";
2981
+ // src/local-sessions/grok.ts
2982
+ import fs7 from "node:fs";
2730
2983
  import os6 from "node:os";
2731
- import path8 from "node:path";
2984
+ import path9 from "node:path";
2732
2985
  function grokSessionsDirectory(home = os6.homedir()) {
2733
- return path8.join(home, ".grok", "sessions");
2986
+ return path9.join(home, ".grok", "sessions");
2734
2987
  }
2735
2988
  function decodeDirectoryName(name) {
2736
2989
  try {
@@ -2740,7 +2993,7 @@ function decodeDirectoryName(name) {
2740
2993
  }
2741
2994
  }
2742
2995
  function sessionUpdatedAt(sessionDirectory) {
2743
- const times = ["updates.jsonl", "chat_history.jsonl"].map((name) => fileMtimeMs(path8.join(sessionDirectory, name))).filter((time) => time !== void 0);
2996
+ const times = ["updates.jsonl", "chat_history.jsonl"].map((name) => fileMtimeMs(path9.join(sessionDirectory, name))).filter((time) => time !== void 0);
2744
2997
  return times.length > 0 ? Math.max(...times) : void 0;
2745
2998
  }
2746
2999
  function discoverGrokSessions(repoRoot, home = os6.homedir(), limit = 1) {
@@ -2750,12 +3003,12 @@ function discoverGrokSessions(repoRoot, home = os6.homedir(), limit = 1) {
2750
3003
  for (const cwdEntry of listDirectory(sessionsDirectory)) {
2751
3004
  if (!cwdEntry.isDirectory()) continue;
2752
3005
  const cwd = decodeDirectoryName(cwdEntry.name);
2753
- if (!cwd || !path8.isAbsolute(cwd) || !isPathInside(canonicalPath(cwd), root))
3006
+ if (!cwd || !path9.isAbsolute(cwd) || !isPathInside(canonicalPath(cwd), root))
2754
3007
  continue;
2755
- const cwdDirectory = path8.join(sessionsDirectory, cwdEntry.name);
3008
+ const cwdDirectory = path9.join(sessionsDirectory, cwdEntry.name);
2756
3009
  for (const sessionEntry of listDirectory(cwdDirectory)) {
2757
3010
  if (!sessionEntry.isDirectory()) continue;
2758
- const location = path8.join(cwdDirectory, sessionEntry.name);
3011
+ const location = path9.join(cwdDirectory, sessionEntry.name);
2759
3012
  const updatedAt = sessionUpdatedAt(location);
2760
3013
  if (updatedAt === void 0) continue;
2761
3014
  refs.push({
@@ -2817,12 +3070,12 @@ function applyToolUpdate(assembler, update) {
2817
3070
  }
2818
3071
  function readGrokSession(ref, options = {}) {
2819
3072
  const summary = readSummary(ref.location);
2820
- const updatesFile = path8.join(ref.location, "updates.jsonl");
3073
+ const updatesFile = path9.join(ref.location, "updates.jsonl");
2821
3074
  const assembler = new TurnAssembler(options.activityOnly);
2822
3075
  let recap;
2823
3076
  let firstPrompt;
2824
3077
  let result;
2825
- if (fs6.existsSync(updatesFile)) {
3078
+ if (fs7.existsSync(updatesFile)) {
2826
3079
  let assistantChunks = "";
2827
3080
  let assistantAt;
2828
3081
  const flushAssistant = () => {
@@ -2866,7 +3119,7 @@ function readGrokSession(ref, options = {}) {
2866
3119
  );
2867
3120
  flushAssistant();
2868
3121
  } else {
2869
- const chatFile = path8.join(ref.location, "chat_history.jsonl");
3122
+ const chatFile = path9.join(ref.location, "chat_history.jsonl");
2870
3123
  result = visitTranscriptRecords(
2871
3124
  chatFile,
2872
3125
  chatHistoryScan,
@@ -2925,7 +3178,7 @@ function readGrokSession(ref, options = {}) {
2925
3178
  function readSummary(sessionDirectory) {
2926
3179
  try {
2927
3180
  return parseJsonObject(
2928
- fs6.readFileSync(path8.join(sessionDirectory, "summary.json"), "utf8")
3181
+ fs7.readFileSync(path9.join(sessionDirectory, "summary.json"), "utf8")
2929
3182
  );
2930
3183
  } catch {
2931
3184
  return void 0;
@@ -2933,33 +3186,33 @@ function readSummary(sessionDirectory) {
2933
3186
  }
2934
3187
  function grokSessionRefForDirectory(sessionDirectory) {
2935
3188
  const summary = readSummary(sessionDirectory);
2936
- const cwd = asString(asObject(summary?.info)?.cwd) ?? decodeDirectoryName(path8.basename(path8.dirname(sessionDirectory)));
3189
+ const cwd = asString(asObject(summary?.info)?.cwd) ?? decodeDirectoryName(path9.basename(path9.dirname(sessionDirectory)));
2937
3190
  const updatedAt = sessionUpdatedAt(sessionDirectory);
2938
3191
  if (!cwd || updatedAt === void 0) return void 0;
2939
3192
  return {
2940
3193
  tool: "grok",
2941
- id: path8.basename(sessionDirectory),
3194
+ id: path9.basename(sessionDirectory),
2942
3195
  cwd,
2943
3196
  updatedAt,
2944
3197
  location: sessionDirectory
2945
3198
  };
2946
3199
  }
2947
3200
 
2948
- // ../../src/local-sessions/opencode.ts
2949
- import fs7 from "node:fs";
3201
+ // src/local-sessions/opencode.ts
3202
+ import fs8 from "node:fs";
2950
3203
  import os7 from "node:os";
2951
- import path9 from "node:path";
3204
+ import path10 from "node:path";
2952
3205
  var NEW_SESSION_PLACEHOLDER = /^New session - \d{4}-\d{2}-\d{2}/;
2953
3206
  function opencodeDataDirectory(home = os7.homedir()) {
2954
3207
  const xdg = process.env.XDG_DATA_HOME?.trim();
2955
- return path9.join(xdg || path9.join(home, ".local", "share"), "opencode");
3208
+ return path10.join(xdg || path10.join(home, ".local", "share"), "opencode");
2956
3209
  }
2957
3210
  function opencodeDatabasePath(home = os7.homedir()) {
2958
3211
  const override = process.env.OPENCODE_DB?.trim();
2959
- return override || path9.join(opencodeDataDirectory(home), "opencode.db");
3212
+ return override || path10.join(opencodeDataDirectory(home), "opencode.db");
2960
3213
  }
2961
3214
  function openOpencodeDatabase(databasePath) {
2962
- if (!fs7.existsSync(databasePath)) return void 0;
3215
+ if (!fs8.existsSync(databasePath)) return void 0;
2963
3216
  const sqlite = loadSqlite();
2964
3217
  if (!sqlite) return void 0;
2965
3218
  try {
@@ -2978,7 +3231,7 @@ function sessionColumns(database) {
2978
3231
  }
2979
3232
  }
2980
3233
  function likePrefix(directory) {
2981
- return `${directory.replace(/[\\%_]/g, (character) => `\\${character}`)}${path9.sep}%`;
3234
+ return `${directory.replace(/[\\%_]/g, (character) => `\\${character}`)}${path10.sep}%`;
2982
3235
  }
2983
3236
  function discoverInDatabase(database, root, rawRoot, databasePath, limit) {
2984
3237
  const columns = sessionColumns(database);
@@ -3002,24 +3255,24 @@ function discoverInDatabase(database, root, rawRoot, databasePath, limit) {
3002
3255
  }
3003
3256
  }
3004
3257
  function legacyStorageDirectory(home) {
3005
- return path9.join(opencodeDataDirectory(home), "storage");
3258
+ return path10.join(opencodeDataDirectory(home), "storage");
3006
3259
  }
3007
3260
  function readJsonFile2(file) {
3008
3261
  try {
3009
- return parseJsonObject(fs7.readFileSync(file, "utf8"));
3262
+ return parseJsonObject(fs8.readFileSync(file, "utf8"));
3010
3263
  } catch {
3011
3264
  return void 0;
3012
3265
  }
3013
3266
  }
3014
3267
  function discoverInLegacyStorage(root, home) {
3015
- const sessionsDirectory = path9.join(legacyStorageDirectory(home), "session");
3268
+ const sessionsDirectory = path10.join(legacyStorageDirectory(home), "session");
3016
3269
  let newest;
3017
3270
  for (const project of listDirectory(sessionsDirectory)) {
3018
3271
  if (!project.isDirectory()) continue;
3019
- const projectDirectory = path9.join(sessionsDirectory, project.name);
3272
+ const projectDirectory = path10.join(sessionsDirectory, project.name);
3020
3273
  for (const entry of listDirectory(projectDirectory)) {
3021
3274
  if (!entry.name.endsWith(".json")) continue;
3022
- const file = path9.join(projectDirectory, entry.name);
3275
+ const file = path10.join(projectDirectory, entry.name);
3023
3276
  const session = readJsonFile2(file);
3024
3277
  const directory = asString(session?.directory);
3025
3278
  if (!session || !directory || asString(session.parentID)) continue;
@@ -3047,7 +3300,7 @@ function discoverOpencodeSessions(repoRoot, home = os7.homedir(), limit = 1) {
3047
3300
  return discoverInDatabase(
3048
3301
  database,
3049
3302
  root,
3050
- path9.resolve(repoRoot),
3303
+ path10.resolve(repoRoot),
3051
3304
  databasePath,
3052
3305
  limit
3053
3306
  );
@@ -3055,7 +3308,7 @@ function discoverOpencodeSessions(repoRoot, home = os7.homedir(), limit = 1) {
3055
3308
  database.close();
3056
3309
  }
3057
3310
  }
3058
- if (fs7.existsSync(databasePath)) return [];
3311
+ if (fs8.existsSync(databasePath)) return [];
3059
3312
  return discoverInLegacyStorage(root, home);
3060
3313
  }
3061
3314
  var OpencodeTurnBuilder = class {
@@ -3135,14 +3388,14 @@ function* databaseMessages(database, sessionId, toolPartsOnly) {
3135
3388
  }
3136
3389
  function* legacyMessages(home, sessionId) {
3137
3390
  const storage = legacyStorageDirectory(home);
3138
- const messageDirectory = path9.join(storage, "message", sessionId);
3391
+ const messageDirectory = path10.join(storage, "message", sessionId);
3139
3392
  const messageFiles = listDirectory(messageDirectory).filter((entry) => entry.name.endsWith(".json")).map((entry) => entry.name).sort();
3140
3393
  for (const name of messageFiles) {
3141
- const data = readJsonFile2(path9.join(messageDirectory, name));
3394
+ const data = readJsonFile2(path10.join(messageDirectory, name));
3142
3395
  if (!data) continue;
3143
3396
  const messageId = asString(data.id) ?? name.slice(0, -5);
3144
- const partDirectory = path9.join(storage, "part", messageId);
3145
- const parts = listDirectory(partDirectory).filter((entry) => entry.name.endsWith(".json")).map((entry) => entry.name).sort().map((partName) => readJsonFile2(path9.join(partDirectory, partName))).filter((part) => part !== void 0);
3397
+ const partDirectory = path10.join(storage, "part", messageId);
3398
+ const parts = listDirectory(partDirectory).filter((entry) => entry.name.endsWith(".json")).map((entry) => entry.name).sort().map((partName) => readJsonFile2(path10.join(partDirectory, partName))).filter((part) => part !== void 0);
3146
3399
  yield { data, parts, createdAt: asNumber(asObject(data.time)?.created) };
3147
3400
  }
3148
3401
  }
@@ -3204,9 +3457,9 @@ function readOpencodeSession(ref, options = {}, home = os7.homedir()) {
3204
3457
  };
3205
3458
  }
3206
3459
 
3207
- // ../../src/local-sessions/pi.ts
3460
+ // src/local-sessions/pi.ts
3208
3461
  import os8 from "node:os";
3209
- import path10 from "node:path";
3462
+ import path11 from "node:path";
3210
3463
  var MAX_FILES_VERIFIED_PER_DIRECTORY2 = 5;
3211
3464
  var RELEVANT_ENTRY_TYPES = /* @__PURE__ */ new Set([
3212
3465
  "session",
@@ -3216,7 +3469,7 @@ var RELEVANT_ENTRY_TYPES = /* @__PURE__ */ new Set([
3216
3469
  ]);
3217
3470
  function piSessionsDirectory(home = os8.homedir()) {
3218
3471
  const agentDirectory = process.env.PI_CODING_AGENT_DIR?.trim();
3219
- return agentDirectory ? path10.join(agentDirectory, "sessions") : path10.join(home, ".pi", "agent", "sessions");
3472
+ return agentDirectory ? path11.join(agentDirectory, "sessions") : path11.join(home, ".pi", "agent", "sessions");
3220
3473
  }
3221
3474
  function encodePiSessionDirectory(cwd) {
3222
3475
  const withoutLeadingSeparator = cwd.replace(/^[/\\]/, "");
@@ -3238,7 +3491,7 @@ function piSessionRefForFile(file) {
3238
3491
  if (!header2?.cwd) return void 0;
3239
3492
  return {
3240
3493
  tool: "pi",
3241
- id: header2.id ?? path10.basename(file, ".jsonl"),
3494
+ id: header2.id ?? path11.basename(file, ".jsonl"),
3242
3495
  cwd: header2.cwd,
3243
3496
  updatedAt: fileMtimeMs(file) ?? 0,
3244
3497
  location: file
@@ -3254,8 +3507,8 @@ function discoverPiSessions(repoRoot, home = os8.homedir(), limit = 1) {
3254
3507
  if (!entry.isDirectory()) continue;
3255
3508
  if (entry.name !== encodedRoot && !(entry.name.startsWith(childPrefix) && entry.name.endsWith("--")))
3256
3509
  continue;
3257
- const directory = path10.join(sessionsDirectory, entry.name);
3258
- const files = listDirectory(directory).filter((file) => file.isFile() && file.name.endsWith(".jsonl")).map((file) => path10.join(directory, file.name)).map((file) => ({ file, mtime: fileMtimeMs(file) ?? 0 })).sort((a, b) => b.mtime - a.mtime).slice(0, Math.max(MAX_FILES_VERIFIED_PER_DIRECTORY2, limit));
3510
+ const directory = path11.join(sessionsDirectory, entry.name);
3511
+ const files = listDirectory(directory).filter((file) => file.isFile() && file.name.endsWith(".jsonl")).map((file) => path11.join(directory, file.name)).map((file) => ({ file, mtime: fileMtimeMs(file) ?? 0 })).sort((a, b) => b.mtime - a.mtime).slice(0, Math.max(MAX_FILES_VERIFIED_PER_DIRECTORY2, limit));
3259
3512
  let found = 0;
3260
3513
  for (const { file } of files) {
3261
3514
  const ref = piSessionRefForFile(file);
@@ -3396,7 +3649,7 @@ function readPiSession(ref, options = {}) {
3396
3649
  };
3397
3650
  }
3398
3651
 
3399
- // ../../src/local-sessions/types.ts
3652
+ // src/local-sessions/types.ts
3400
3653
  var AGENT_TOOLS = [
3401
3654
  "claude",
3402
3655
  "codex",
@@ -3408,14 +3661,14 @@ var AGENT_TOOLS = [
3408
3661
  "cursor"
3409
3662
  ];
3410
3663
 
3411
- // ../../src/local-sessions/machine.ts
3664
+ // src/local-sessions/machine.ts
3412
3665
  var HEAD_BYTES = 256 * 1024;
3413
3666
  var TITLE_TAIL_BYTES = 64 * 1024;
3414
3667
  function sqliteStoresPresent(home) {
3415
3668
  const present = [];
3416
- if (fs8.existsSync(opencodeDatabasePath(home))) present.push("opencode");
3669
+ if (fs9.existsSync(opencodeDatabasePath(home))) present.push("opencode");
3417
3670
  if (cursorUserDirectories(home).length) present.push("cursor");
3418
- if (fs8.existsSync(cursorChatsDirectory(home))) present.push("cursor-agent");
3671
+ if (fs9.existsSync(cursorChatsDirectory(home))) present.push("cursor-agent");
3419
3672
  return present;
3420
3673
  }
3421
3674
  function sqliteWarning(tools, nodeVersion = process.versions.node) {
@@ -3431,7 +3684,7 @@ function sqliteWarning(tools, nodeVersion = process.versions.node) {
3431
3684
  }
3432
3685
  function fileSize(file) {
3433
3686
  try {
3434
- return fs8.statSync(file).size;
3687
+ return fs9.statSync(file).size;
3435
3688
  } catch {
3436
3689
  return 0;
3437
3690
  }
@@ -3472,7 +3725,7 @@ function estimate(count, sample) {
3472
3725
  return { count: Math.round(count / sample.coverage), exact: false };
3473
3726
  }
3474
3727
  function gitOf(cwd) {
3475
- if (!cwd || !path11.isAbsolute(cwd)) return "none";
3728
+ if (!cwd || !path12.isAbsolute(cwd)) return "none";
3476
3729
  const identity = gitIdentity(cwd);
3477
3730
  if (!identity) return "none";
3478
3731
  return {
@@ -3487,10 +3740,10 @@ function claudeSessions(home) {
3487
3740
  const projects = claudeProjectsDirectory(home);
3488
3741
  for (const project of listDirectory(projects)) {
3489
3742
  if (!project.isDirectory()) continue;
3490
- const directory = path11.join(projects, project.name);
3743
+ const directory = path12.join(projects, project.name);
3491
3744
  for (const entry of listDirectory(directory)) {
3492
3745
  if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
3493
- const file = path11.join(directory, entry.name);
3746
+ const file = path12.join(directory, entry.name);
3494
3747
  const ref = claudeSessionRefForFile(file);
3495
3748
  if (!ref) continue;
3496
3749
  const size = fileSize(file);
@@ -3545,13 +3798,13 @@ function claudeSessions(home) {
3545
3798
  }
3546
3799
  function codexThreadNames(home) {
3547
3800
  const names = /* @__PURE__ */ new Map();
3548
- const index = path11.join(
3549
- path11.dirname(codexSessionsDirectory(home)),
3801
+ const index = path12.join(
3802
+ path12.dirname(codexSessionsDirectory(home)),
3550
3803
  "session_index.jsonl"
3551
3804
  );
3552
3805
  let text = "";
3553
3806
  try {
3554
- text = fs8.readFileSync(index, "utf8");
3807
+ text = fs9.readFileSync(index, "utf8");
3555
3808
  } catch {
3556
3809
  return names;
3557
3810
  }
@@ -3647,7 +3900,7 @@ function opencodeSessions(home) {
3647
3900
  function jsonlFiles(directory, depth) {
3648
3901
  const files = [];
3649
3902
  for (const entry of listDirectory(directory)) {
3650
- const full = path11.join(directory, entry.name);
3903
+ const full = path12.join(directory, entry.name);
3651
3904
  if (entry.isFile() && entry.name.endsWith(".jsonl")) files.push(full);
3652
3905
  else if (entry.isDirectory() && depth > 0)
3653
3906
  files.push(...jsonlFiles(full, depth - 1));
@@ -3693,15 +3946,15 @@ function grokSessions(home) {
3693
3946
  const root = grokSessionsDirectory(home);
3694
3947
  for (const cwdEntry of listDirectory(root)) {
3695
3948
  if (!cwdEntry.isDirectory()) continue;
3696
- for (const sessionEntry of listDirectory(path11.join(root, cwdEntry.name))) {
3949
+ for (const sessionEntry of listDirectory(path12.join(root, cwdEntry.name))) {
3697
3950
  if (!sessionEntry.isDirectory()) continue;
3698
- const directory = path11.join(root, cwdEntry.name, sessionEntry.name);
3951
+ const directory = path12.join(root, cwdEntry.name, sessionEntry.name);
3699
3952
  const ref = grokSessionRefForDirectory(directory);
3700
3953
  if (!ref) continue;
3701
- const history = path11.join(directory, "chat_history.jsonl");
3702
- const updates = path11.join(directory, "updates.jsonl");
3954
+ const history = path12.join(directory, "chat_history.jsonl");
3955
+ const updates = path12.join(directory, "updates.jsonl");
3703
3956
  const size = fileSize(history) + fileSize(updates);
3704
- const source = fs8.existsSync(history) ? history : updates;
3957
+ const source = fs9.existsSync(history) ? history : updates;
3705
3958
  const sample = headSample(source, fileSize(source));
3706
3959
  let messages = 0;
3707
3960
  let previousKind;
@@ -3735,7 +3988,7 @@ function grokSessions(home) {
3735
3988
  function geminiSessions(home, candidates) {
3736
3989
  return listGeminiSessionRefs(home, candidates).map((ref) => {
3737
3990
  const size = fileSize(ref.location);
3738
- if (path11.basename(ref.location) === "logs.json")
3991
+ if (path12.basename(ref.location) === "logs.json")
3739
3992
  return {
3740
3993
  tool: "gemini",
3741
3994
  id: ref.id,
@@ -3794,7 +4047,7 @@ function cursorAgentSessions(home, candidates) {
3794
4047
  let title;
3795
4048
  try {
3796
4049
  const meta = parseJsonObject(
3797
- fs8.readFileSync(path11.join(ref.location, "meta.json"), "utf8")
4050
+ fs9.readFileSync(path12.join(ref.location, "meta.json"), "utf8")
3798
4051
  );
3799
4052
  title = asString(meta?.title)?.trim() || void 0;
3800
4053
  } catch {
@@ -3809,7 +4062,7 @@ function cursorAgentSessions(home, candidates) {
3809
4062
  updatedAt: ref.updatedAt,
3810
4063
  messageCount: count ?? 0,
3811
4064
  messageCountExact: count !== void 0,
3812
- sizeBytes: fileSize(path11.join(ref.location, "store.db")),
4065
+ sizeBytes: fileSize(path12.join(ref.location, "store.db")),
3813
4066
  sizeExact: true,
3814
4067
  ref
3815
4068
  };
@@ -3819,7 +4072,7 @@ var CURSOR_AVERAGE_BUBBLE_BYTES = 6800;
3819
4072
  function cursorAppSessions(home) {
3820
4073
  const sessions = [];
3821
4074
  for (const userDirectory of cursorUserDirectories(home)) {
3822
- const stateFile = path11.join(userDirectory, "globalStorage", "state.vscdb");
4075
+ const stateFile = path12.join(userDirectory, "globalStorage", "state.vscdb");
3823
4076
  for (const composer of listCursorComposers(userDirectory).composers) {
3824
4077
  if (!isListedComposer(composer)) continue;
3825
4078
  const ref = {
@@ -3900,259 +4153,6 @@ function discoverAllSessions(options = {}) {
3900
4153
  };
3901
4154
  }
3902
4155
 
3903
- // src/api.ts
3904
- var ApiError = class extends Error {
3905
- constructor(message, status, path21) {
3906
- super(message);
3907
- this.status = status;
3908
- this.path = path21;
3909
- }
3910
- status;
3911
- path;
3912
- };
3913
- var TIMEOUT_MS = 12e4;
3914
- async function errorMessage(response) {
3915
- const text = (await response.text().catch(() => "")).trim();
3916
- try {
3917
- const json = JSON.parse(text);
3918
- if (typeof json.error === "string") return json.error;
3919
- } catch {
3920
- }
3921
- return text.slice(0, 500) || `HTTP ${response.status}`;
3922
- }
3923
- var ImportApi = class {
3924
- constructor(base, token = null, userAgent = "ytimesy-cli") {
3925
- this.base = base;
3926
- this.token = token;
3927
- this.userAgent = userAgent;
3928
- }
3929
- base;
3930
- token;
3931
- userAgent;
3932
- setToken(token) {
3933
- this.token = token;
3934
- }
3935
- async request(path21, init) {
3936
- const url = new URL(path21, this.base).toString();
3937
- let response;
3938
- try {
3939
- response = await fetch(url, {
3940
- method: init.method,
3941
- body: init.body,
3942
- headers: {
3943
- "user-agent": this.userAgent,
3944
- ...init.contentType ? { "content-type": init.contentType } : {},
3945
- ...this.token ? { authorization: `Bearer ${this.token}` } : {}
3946
- },
3947
- signal: AbortSignal.timeout(TIMEOUT_MS)
3948
- });
3949
- } catch (error) {
3950
- throw new ApiError(
3951
- `Could not reach ${new URL(this.base).host}: ${error.message}`,
3952
- 0,
3953
- path21
3954
- );
3955
- }
3956
- if (!response.ok)
3957
- throw new ApiError(await errorMessage(response), response.status, path21);
3958
- return await response.json();
3959
- }
3960
- json(path21, body) {
3961
- return this.request(path21, {
3962
- method: "POST",
3963
- body: JSON.stringify(body),
3964
- contentType: "application/json"
3965
- });
3966
- }
3967
- start(body) {
3968
- return this.json("/api/local-import/start", body);
3969
- }
3970
- plan(groups) {
3971
- return this.json("/api/local-import/plan", {
3972
- groups
3973
- });
3974
- }
3975
- /** A project for a repository the ytimesy app reaches (409: it cannot see it yet). */
3976
- createProject(body) {
3977
- return this.json(
3978
- "/api/local-import/create-project",
3979
- body
3980
- );
3981
- }
3982
- secrets(body) {
3983
- return this.json("/api/local-import/secrets", body);
3984
- }
3985
- session(body) {
3986
- return this.json("/api/local-import/sessions", body);
3987
- }
3988
- transcript(uploadPath, archive) {
3989
- return this.request(uploadPath, {
3990
- method: "PUT",
3991
- body: new Blob([new Uint8Array(archive)]),
3992
- contentType: "application/gzip"
3993
- });
3994
- }
3995
- finish(body) {
3996
- return this.json("/api/local-import/finish", body);
3997
- }
3998
- cancel() {
3999
- return this.json("/api/local-import/cancel", {});
4000
- }
4001
- };
4002
-
4003
- // src/env-file.ts
4004
- import fs9 from "node:fs";
4005
- import path12 from "node:path";
4006
- var ENV_FILES = [".env", ".env.local"];
4007
- var NAME = /^[A-Za-z_][A-Za-z0-9_.-]*$/;
4008
- function unescapeDouble(text) {
4009
- return text.replace(
4010
- /\\([nrt"\\$])/g,
4011
- (_, char) => char === "n" ? "\n" : char === "r" ? "\r" : char === "t" ? " " : char
4012
- );
4013
- }
4014
- function parseEnvText(text) {
4015
- const variables = /* @__PURE__ */ new Map();
4016
- const source = text.replace(/^\uFEFF/, "").replace(/\r\n?/g, "\n");
4017
- let index = 0;
4018
- while (index < source.length) {
4019
- const lineEnd = source.indexOf("\n", index);
4020
- const end = lineEnd === -1 ? source.length : lineEnd;
4021
- const line = source.slice(index, end);
4022
- const match = /^\s*(?:export\s+)?([^=\s]+)\s*=\s*/.exec(line);
4023
- if (!match || line.trimStart().startsWith("#")) {
4024
- index = end + 1;
4025
- continue;
4026
- }
4027
- const name = match[1];
4028
- const valueStart = index + match[0].length;
4029
- const quote = source[valueStart];
4030
- let value;
4031
- if (quote === '"' || quote === "'" || quote === "`") {
4032
- const close = source.indexOf(quote, valueStart + 1);
4033
- let at = close;
4034
- while (quote === '"' && at !== -1) {
4035
- let slashes = 0;
4036
- for (let back = at - 1; source[back] === "\\"; back--) slashes++;
4037
- if (slashes % 2 === 0) break;
4038
- at = source.indexOf(quote, at + 1);
4039
- }
4040
- if (at === -1) {
4041
- value = line.slice(match[0].length).trim();
4042
- index = end + 1;
4043
- } else {
4044
- const raw = source.slice(valueStart + 1, at);
4045
- value = quote === '"' ? unescapeDouble(raw) : raw;
4046
- const after = source.indexOf("\n", at);
4047
- index = after === -1 ? source.length : after + 1;
4048
- }
4049
- } else {
4050
- value = line.slice(match[0].length).replace(/(^|\s)#.*$/, "").trim();
4051
- index = end + 1;
4052
- }
4053
- if (NAME.test(name)) variables.set(name, value);
4054
- }
4055
- return [...variables].map(([name, value]) => ({ name, value }));
4056
- }
4057
- function readEnvFiles(folder) {
4058
- const variables = [];
4059
- for (const source of ENV_FILES) {
4060
- let text;
4061
- try {
4062
- const file = path12.join(folder, source);
4063
- if (!fs9.statSync(file).isFile()) continue;
4064
- text = fs9.readFileSync(file, "utf8");
4065
- } catch {
4066
- continue;
4067
- }
4068
- for (const variable of parseEnvText(text))
4069
- variables.push({ ...variable, source });
4070
- }
4071
- return variables;
4072
- }
4073
- var TOO_COMMON = /^(?:true|false|yes|no|null|none|on|off|development|production|staging|test|localhost|127\.0\.0\.1|0\.0\.0\.0|\d+(?:\.\d+)?)$/i;
4074
- function redactionValues(variables) {
4075
- const values = /* @__PURE__ */ new Set();
4076
- for (const { value } of variables) {
4077
- const trimmed = value.trim();
4078
- if (trimmed.length >= 8 && !TOO_COMMON.test(trimmed)) values.add(trimmed);
4079
- if (value.length >= 8 && value !== trimmed && !TOO_COMMON.test(value))
4080
- values.add(value);
4081
- }
4082
- return [...values];
4083
- }
4084
-
4085
- // src/github-cli.ts
4086
- import { execFileSync } from "node:child_process";
4087
- var GithubCliError = class extends Error {
4088
- };
4089
- function gh(args, env) {
4090
- return execFileSync("gh", args, {
4091
- env: {
4092
- ...env,
4093
- GH_PROMPT_DISABLED: "1",
4094
- NO_COLOR: "1"
4095
- },
4096
- encoding: "utf8",
4097
- timeout: 6e4,
4098
- stdio: ["ignore", "pipe", "pipe"]
4099
- });
4100
- }
4101
- function githubCliStatus(env) {
4102
- try {
4103
- gh(["--version"], env);
4104
- } catch {
4105
- return { ready: false, reason: "missing" };
4106
- }
4107
- try {
4108
- gh(["auth", "status", "--hostname", "github.com"], env);
4109
- return { ready: true };
4110
- } catch {
4111
- return { ready: false, reason: "signed-out" };
4112
- }
4113
- }
4114
- function githubCliNextStep(status) {
4115
- const otherwise = "or create the repository at https://github.com/new, make it this folder's origin remote (git init first if needed) and re-run without --create-repo";
4116
- return status.ready ? "" : status.reason === "missing" ? `Install the GitHub CLI (https://cli.github.com) and run \`gh auth login\`, then re-run the same command; ${otherwise}.` : `Run \`gh auth login\` to sign in to GitHub, then re-run the same command; ${otherwise}.`;
4117
- }
4118
- function createPrivateRepository(name, env) {
4119
- let output;
4120
- try {
4121
- output = gh(
4122
- [
4123
- "api",
4124
- "--method",
4125
- "POST",
4126
- "user/repos",
4127
- "-f",
4128
- `name=${name}`,
4129
- "-F",
4130
- "private=true"
4131
- ],
4132
- env
4133
- );
4134
- } catch (error) {
4135
- const failure = error;
4136
- const text = `${String(failure.stdout ?? "")} ${String(failure.stderr ?? "")}`;
4137
- if (/name already exists/i.test(text))
4138
- throw new GithubCliError(
4139
- `A repository named ${name} already exists on your GitHub account.`
4140
- );
4141
- throw new GithubCliError(
4142
- `gh could not create ${name}: ${text.trim().split("\n").slice(-2).join(" ") || error.message}`
4143
- );
4144
- }
4145
- const created = JSON.parse(output);
4146
- if (!created.full_name)
4147
- throw new GithubCliError(`gh did not return the new repository ${name}.`);
4148
- return {
4149
- fullName: created.full_name,
4150
- defaultBranch: created.default_branch || "main",
4151
- cloneUrl: created.clone_url || `https://github.com/${created.full_name}.git`,
4152
- sshUrl: created.ssh_url || `git@github.com:${created.full_name}.git`
4153
- };
4154
- }
4155
-
4156
4156
  // src/repo-snapshot.ts
4157
4157
  import { execFileSync as execFileSync2 } from "node:child_process";
4158
4158
  import fs11 from "node:fs";
@@ -4700,10 +4700,10 @@ import fs14 from "node:fs";
4700
4700
  import os14 from "node:os";
4701
4701
  import path18 from "node:path";
4702
4702
 
4703
- // ../../src/local-sessions/index.ts
4703
+ // src/local-sessions/index.ts
4704
4704
  import os13 from "node:os";
4705
4705
 
4706
- // ../../src/local-sessions/caller.ts
4706
+ // src/local-sessions/caller.ts
4707
4707
  import { execFileSync as execFileSync3 } from "node:child_process";
4708
4708
  import fs12 from "node:fs";
4709
4709
  import os11 from "node:os";
@@ -4955,7 +4955,7 @@ function trimImportTail(turns, options) {
4955
4955
  return result;
4956
4956
  }
4957
4957
 
4958
- // ../../src/local-sessions/handoff-helpers.ts
4958
+ // src/local-sessions/handoff-helpers.ts
4959
4959
  import path16 from "node:path";
4960
4960
  var DIGEST_HEADER = "[Summary of earlier context]";
4961
4961
  var DIGEST_MAX_TASK_CHARS = 240;
@@ -5120,7 +5120,7 @@ function trimToBudget(turns, budgetChars) {
5120
5120
  return result;
5121
5121
  }
5122
5122
 
5123
- // ../../src/local-sessions/full-transcript.ts
5123
+ // src/local-sessions/full-transcript.ts
5124
5124
  import fs13 from "node:fs";
5125
5125
  import os12 from "node:os";
5126
5126
  import path17 from "node:path";
@@ -5904,7 +5904,7 @@ function exportFullTranscript(ref, options) {
5904
5904
  };
5905
5905
  }
5906
5906
 
5907
- // ../../src/local-sessions/index.ts
5907
+ // src/local-sessions/index.ts
5908
5908
  var discoverers = {
5909
5909
  claude: discoverClaudeSessions,
5910
5910
  codex: discoverCodexSessions,
@@ -7526,7 +7526,7 @@ async function execute(input) {
7526
7526
  }
7527
7527
 
7528
7528
  // src/cli.ts
7529
- var VERSION = true ? "0.1.1" : "0.0.0-dev";
7529
+ var VERSION = true ? "0.1.2" : "0.0.0-dev";
7530
7530
  var HELP = `ytimesy \u2014 move your local coding-agent sessions to ytimesy
7531
7531
 
7532
7532
  Usage: