failproofai 0.0.9-beta.1 → 0.0.9

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 (154) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +6 -6
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +3 -3
  6. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  14. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  15. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +3 -3
  17. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  18. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  20. package/.next/standalone/.next/server/app/_not-found.html +2 -2
  21. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  22. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  23. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  24. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  25. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  26. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  27. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  28. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -2
  29. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/index.html +1 -1
  31. package/.next/standalone/.next/server/app/index.rsc +15 -15
  32. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  33. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  34. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  35. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  36. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  37. package/.next/standalone/.next/server/app/page/build-manifest.json +3 -3
  38. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  39. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +3 -3
  42. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
  43. package/.next/standalone/.next/server/app/policies/page.js +2 -2
  44. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  45. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  46. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +3 -3
  47. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  48. package/.next/standalone/.next/server/app/project/[name]/page.js +1 -1
  49. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  51. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +3 -3
  52. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  53. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  54. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +4 -3
  55. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  56. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  57. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +3 -3
  58. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  59. package/.next/standalone/.next/server/app/projects/page.js +2 -2
  60. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  62. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g72weg._.js +1 -1
  63. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0su~k6f._.js +3 -0
  64. package/.next/standalone/.next/server/chunks/lib_codex-projects_ts_07qqk1g._.js +3 -0
  65. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
  66. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01743wx._.js +3 -0
  67. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0.f_cyx._.js → [root-of-the-server]__01g_w_e._.js} +2 -2
  68. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__092s1ta._.js +2 -2
  69. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09icjsf._.js +2 -2
  70. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0dub28-._.js → [root-of-the-server]__0_b7pgn._.js} +2 -2
  71. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g.lg8b._.js +2 -2
  72. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0gs6wz4._.js +3 -0
  73. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h..k-e._.js +2 -2
  74. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0it81ys._.js +3 -0
  75. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u4a9jq._.js +4 -0
  76. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ymlddl._.js +18 -0
  77. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11pa2ra._.js +2 -2
  78. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12.h2mg._.js +3 -0
  79. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12t-wym._.js +2 -2
  80. package/.next/standalone/.next/server/chunks/ssr/_04w00cm._.js +3 -0
  81. package/.next/standalone/.next/server/chunks/ssr/_10lm7or._.js +2 -2
  82. package/.next/standalone/.next/server/chunks/ssr/app_0cdqd9w._.js +3 -0
  83. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
  84. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +1 -1
  85. package/.next/standalone/.next/server/chunks/ssr/lib_codex-projects_ts_0eosib~._.js +3 -0
  86. package/.next/standalone/.next/server/chunks/ssr/lib_utils_ts_068jk73._.js +3 -0
  87. package/.next/standalone/.next/server/chunks/ssr/{_0zaq1hm._.js → node_modules_0ttbz1~._.js} +2 -2
  88. package/.next/standalone/.next/server/middleware-build-manifest.js +6 -6
  89. package/.next/standalone/.next/server/pages/404.html +2 -2
  90. package/.next/standalone/.next/server/pages/500.html +1 -1
  91. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  92. package/.next/standalone/.next/server/server-reference-manifest.json +9 -9
  93. package/.next/standalone/.next/static/chunks/{0_c_yox08g_44.js → 01q52wg_amm60.js} +2 -2
  94. package/.next/standalone/.next/static/chunks/06x4-d1~o-opr.js +1 -0
  95. package/.next/standalone/.next/static/chunks/{0bghqwo4iloy0.js → 0756i.7omnnl6.js} +1 -1
  96. package/.next/standalone/.next/static/chunks/{0p5zh2diw90a1.js → 095l4hc7-h.~~.js} +1 -1
  97. package/.next/standalone/.next/static/chunks/09ose_165ra4d.js +1 -0
  98. package/.next/standalone/.next/static/chunks/0n-_j_6fo6jex.js +6 -0
  99. package/.next/standalone/.next/static/chunks/0n~s0gafwnp2y.js +1 -0
  100. package/.next/standalone/.next/static/chunks/{0ufq8smh~i7wc.js → 0pr7k36o_.du1.js} +1 -1
  101. package/.next/standalone/.next/static/chunks/{0z-jh701rc~j8.js → 0t~iusm_fxoao.js} +1 -1
  102. package/.next/standalone/.next/static/chunks/{0jryicwtm9z2g.js → 0u-ys71jc4y68.js} +3 -3
  103. package/.next/standalone/.next/static/chunks/0zig0fh30t6ou.js +1 -0
  104. package/.next/standalone/.next/static/chunks/{0w1f.k~gi-y6..js → 11kt_9zaooda3.js} +1 -1
  105. package/.next/standalone/.next/static/chunks/{0kzk5-mh1_x53.js → 12simlrcfk3g2.js} +1 -1
  106. package/.next/standalone/.next/static/chunks/{turbopack-0s36is87fc9r2.js → turbopack-0o7k.hakttp4k.js} +1 -1
  107. package/.next/standalone/app/components/cli-badge.tsx +24 -0
  108. package/.next/standalone/app/components/project-list.tsx +13 -7
  109. package/.next/standalone/app/components/sessions-list.tsx +4 -2
  110. package/.next/standalone/app/policies/hooks-client.tsx +66 -10
  111. package/.next/standalone/app/project/[name]/page.tsx +49 -22
  112. package/.next/standalone/app/project/[name]/session/[sessionId]/page.tsx +51 -19
  113. package/.next/standalone/components/reach-developers.tsx +6 -1
  114. package/.next/standalone/lib/codex-projects.ts +250 -0
  115. package/.next/standalone/lib/codex-sessions.ts +414 -0
  116. package/.next/standalone/lib/format-date.ts +21 -0
  117. package/.next/standalone/lib/log-entries.ts +3 -3
  118. package/.next/standalone/lib/paths.ts +13 -0
  119. package/.next/standalone/lib/projects.ts +57 -3
  120. package/.next/standalone/lib/utils.ts +6 -22
  121. package/.next/standalone/package.json +1 -1
  122. package/.next/standalone/server.js +1 -1
  123. package/bin/failproofai.mjs +1 -0
  124. package/dist/cli.mjs +1042 -122
  125. package/lib/codex-projects.ts +250 -0
  126. package/lib/codex-sessions.ts +414 -0
  127. package/lib/format-date.ts +21 -0
  128. package/lib/log-entries.ts +3 -3
  129. package/lib/paths.ts +13 -0
  130. package/lib/projects.ts +57 -3
  131. package/lib/utils.ts +6 -22
  132. package/package.json +1 -1
  133. package/scripts/launch.ts +2 -1
  134. package/src/hooks/builtin-policies.ts +7 -1
  135. package/src/hooks/hook-activity-store.ts +3 -0
  136. package/src/hooks/manager.ts +1 -1
  137. package/src/hooks/resolve-permission-mode.ts +6 -91
  138. package/.next/standalone/.next/server/chunks/[externals]__080wern._.js +0 -3
  139. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0b57.gk._.js +0 -3
  140. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__03rd.z8._.js +0 -3
  141. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e74wa-._.js +0 -3
  142. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0vu.o-3._.js +0 -4
  143. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w6l33k._.js +0 -17
  144. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0zqcovi._.js +0 -3
  145. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__105.l_7._.js +0 -3
  146. package/.next/standalone/.next/server/chunks/ssr/_0uy6m~m._.js +0 -3
  147. package/.next/standalone/.next/static/chunks/00b5h4r1el.6f.js +0 -1
  148. package/.next/standalone/.next/static/chunks/0fw2h.g66c0h3.js +0 -1
  149. package/.next/standalone/.next/static/chunks/0gu87mlr5ssnt.js +0 -6
  150. package/.next/standalone/.next/static/chunks/0igf3xbisp1lx.js +0 -1
  151. package/.next/standalone/.next/static/chunks/0vwqucikost_q.js +0 -1
  152. /package/.next/standalone/.next/static/{CiVeb_yiVt-O2JYrzGzB7 → A_Ax17P33facL0OmIwFXj}/_buildManifest.js +0 -0
  153. /package/.next/standalone/.next/static/{CiVeb_yiVt-O2JYrzGzB7 → A_Ax17P33facL0OmIwFXj}/_clientMiddlewareManifest.js +0 -0
  154. /package/.next/standalone/.next/static/{CiVeb_yiVt-O2JYrzGzB7 → A_Ax17P33facL0OmIwFXj}/_ssgManifest.js +0 -0
package/dist/cli.mjs CHANGED
@@ -727,7 +727,7 @@ function blockSecretsWrite(ctx) {
727
727
  }
728
728
  function extractAbsolutePaths(command) {
729
729
  const paths = [];
730
- const pathRe = /(?<![a-zA-Z0-9_.\-~\\])(?:~\/[^\s;|&"'()\[\]{}]*|~(?=\s|$|[;|&"'()\[\]{}])|\/[^\s;|&"'()\[\]{}]*)/g;
730
+ const pathRe = /(?<![a-zA-Z0-9_.\-~\\*?:=])(?:~\/[^\s;|&"'()\[\]{}]*|~(?=\s|$|[;|&"'()\[\]{}])|\/[^\s;|&"'()\[\]{}]*)/g;
731
731
  function addPaths(s) {
732
732
  pathRe.lastIndex = 0;
733
733
  let m;
@@ -2397,7 +2397,7 @@ var init_hook_activity_store = __esm(() => {
2397
2397
  });
2398
2398
 
2399
2399
  // package.json
2400
- var version2 = "0.0.9-beta.1";
2400
+ var version2 = "0.0.9";
2401
2401
  var init_package = () => {};
2402
2402
 
2403
2403
  // src/posthog-key.ts
@@ -2428,19 +2428,721 @@ var init_hook_telemetry = __esm(() => {
2428
2428
  API_KEY = POSTHOG_API_KEY;
2429
2429
  });
2430
2430
 
2431
- // src/hooks/resolve-permission-mode.ts
2432
- import { readFileSync as readFileSync3, readdirSync as readdirSync3, existsSync as existsSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4 } from "node:fs";
2433
- import { dirname as dirname3, join as join4 } from "node:path";
2434
- import { homedir as homedir6 } from "node:os";
2435
- function resolvePermissionMode(integration, parsed, sessionId) {
2436
- if (integration === "claude") {
2437
- return parsed.permission_mode ?? "default";
2431
+ // lib/runtime-cache.ts
2432
+ function runtimeCache(fn, revalidateSeconds, options) {
2433
+ const cache = new Map;
2434
+ const inflight = new Map;
2435
+ const maxSize = options?.maxSize;
2436
+ return async (...args) => {
2437
+ const key = JSON.stringify(args);
2438
+ const entry = cache.get(key);
2439
+ if (entry && Date.now() < entry.expiry) {
2440
+ return entry.data;
2441
+ }
2442
+ const existing = inflight.get(key);
2443
+ if (existing)
2444
+ return existing;
2445
+ const promise = fn(...args).then((data) => {
2446
+ inflight.delete(key);
2447
+ if (maxSize && cache.size >= maxSize) {
2448
+ const oldestKey = cache.keys().next().value;
2449
+ cache.delete(oldestKey);
2450
+ }
2451
+ cache.set(key, { data, expiry: Date.now() + revalidateSeconds * 1000 });
2452
+ return data;
2453
+ }, (err) => {
2454
+ inflight.delete(key);
2455
+ throw err;
2456
+ });
2457
+ inflight.set(key, promise);
2458
+ return promise;
2459
+ };
2460
+ }
2461
+
2462
+ // lib/paths.ts
2463
+ import { homedir as homedir6 } from "os";
2464
+ import { join as join4 } from "path";
2465
+ function getDefaultClaudeProjectsPath() {
2466
+ return join4(homedir6(), ".claude", "projects");
2467
+ }
2468
+ function encodeFolderName(path) {
2469
+ const driveMatch = /^([A-Za-z]):[\\/](.*)$/.exec(path);
2470
+ if (driveMatch) {
2471
+ return driveMatch[1] + "--" + driveMatch[2].replace(/[\\/]/g, "-");
2438
2472
  }
2439
- if (integration === "codex" && sessionId) {
2440
- return resolveCodexMode(sessionId) ?? "default";
2473
+ return path.replace(/[\\/]/g, "-");
2474
+ }
2475
+ function getClaudeProjectsPath() {
2476
+ const envPath = process.env.CLAUDE_PROJECTS_PATH;
2477
+ if (envPath) {
2478
+ return envPath;
2441
2479
  }
2442
- return "default";
2480
+ return getDefaultClaudeProjectsPath();
2443
2481
  }
2482
+ var init_paths = () => {};
2483
+
2484
+ // lib/concurrency.ts
2485
+ async function batchAll(tasks, concurrency) {
2486
+ const results = new Array(tasks.length);
2487
+ let next = 0;
2488
+ async function worker() {
2489
+ while (next < tasks.length) {
2490
+ const idx = next++;
2491
+ try {
2492
+ results[idx] = { status: "fulfilled", value: await tasks[idx]() };
2493
+ } catch (reason) {
2494
+ results[idx] = { status: "rejected", reason };
2495
+ }
2496
+ }
2497
+ }
2498
+ const workers = Array.from({ length: Math.min(concurrency, tasks.length) }, () => worker());
2499
+ await Promise.all(workers);
2500
+ return results;
2501
+ }
2502
+
2503
+ // lib/logger.ts
2504
+ function shouldEmit2(level) {
2505
+ return LEVEL_ORDER2[level] >= LEVEL_ORDER2[currentLevel2];
2506
+ }
2507
+ function stamp(label) {
2508
+ return `[failproofai${new Date().toISOString()}] ${label}`;
2509
+ }
2510
+ function logWarn(msg, detail) {
2511
+ if (!shouldEmit2("warn"))
2512
+ return;
2513
+ if (detail !== undefined) {
2514
+ console.warn(stamp("WARN"), msg, detail);
2515
+ } else {
2516
+ console.warn(stamp("WARN"), msg);
2517
+ }
2518
+ }
2519
+ function logError(msg, detail) {
2520
+ if (detail !== undefined) {
2521
+ console.error(stamp("ERROR"), msg, detail);
2522
+ } else {
2523
+ console.error(stamp("ERROR"), msg);
2524
+ }
2525
+ }
2526
+ var LEVEL_ORDER2, currentLevel2 = "warn";
2527
+ var init_logger = __esm(() => {
2528
+ LEVEL_ORDER2 = { info: 0, warn: 1, error: 2 };
2529
+ });
2530
+
2531
+ // lib/format-date.ts
2532
+ function formatDate(date) {
2533
+ return new Intl.DateTimeFormat("en-US", {
2534
+ month: "short",
2535
+ day: "numeric",
2536
+ year: "numeric",
2537
+ hour: "numeric",
2538
+ minute: "2-digit",
2539
+ hour12: true
2540
+ }).format(date);
2541
+ }
2542
+
2543
+ // lib/codex-projects.ts
2544
+ var exports_codex_projects = {};
2545
+ __export(exports_codex_projects, {
2546
+ getCodexSessionsForCwd: () => getCodexSessionsForCwd,
2547
+ getCodexSessionsByEncodedName: () => getCodexSessionsByEncodedName,
2548
+ getCodexProjects: () => getCodexProjects,
2549
+ getCachedCodexSessionsForCwd: () => getCachedCodexSessionsForCwd,
2550
+ getCachedCodexSessionsByEncodedName: () => getCachedCodexSessionsByEncodedName,
2551
+ getCachedCodexProjects: () => getCachedCodexProjects
2552
+ });
2553
+ import { open as open2, readdir } from "fs/promises";
2554
+ import { homedir as homedir7 } from "os";
2555
+ import { join as join5 } from "path";
2556
+ async function safeReaddir(dir) {
2557
+ try {
2558
+ return await readdir(dir, { withFileTypes: true });
2559
+ } catch {
2560
+ return null;
2561
+ }
2562
+ }
2563
+ async function readFirstLine(filePath) {
2564
+ let fh = null;
2565
+ try {
2566
+ fh = await open2(filePath, "r");
2567
+ const buf = Buffer.alloc(FIRST_LINE_CHUNK_BYTES);
2568
+ const { bytesRead } = await fh.read(buf, 0, FIRST_LINE_CHUNK_BYTES, 0);
2569
+ if (bytesRead === 0)
2570
+ return null;
2571
+ const slice = buf.subarray(0, bytesRead);
2572
+ const nl = slice.indexOf(10);
2573
+ const end = nl === -1 ? bytesRead : nl;
2574
+ return slice.subarray(0, end).toString("utf-8");
2575
+ } catch {
2576
+ return null;
2577
+ } finally {
2578
+ if (fh)
2579
+ await fh.close().catch(() => {});
2580
+ }
2581
+ }
2582
+ function extractSessionMeta(line) {
2583
+ try {
2584
+ const obj = JSON.parse(line);
2585
+ if (obj.type !== "session_meta")
2586
+ return {};
2587
+ const cwd = obj.payload?.cwd;
2588
+ if (typeof cwd !== "string" || cwd.length === 0)
2589
+ return {};
2590
+ return { cwd };
2591
+ } catch {
2592
+ return {};
2593
+ }
2594
+ }
2595
+ function extractSessionId(filename) {
2596
+ const m = filename.match(SESSION_ID_RE);
2597
+ return m ? m[0] : null;
2598
+ }
2599
+ async function listJsonlFiles(dir) {
2600
+ const entries = await safeReaddir(dir);
2601
+ if (!entries)
2602
+ return [];
2603
+ return entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => join5(dir, e.name));
2604
+ }
2605
+ async function scanCodexSessions() {
2606
+ const yearDirs = await safeReaddir(CODEX_SESSIONS_ROOT);
2607
+ if (!yearDirs)
2608
+ return [];
2609
+ const filePaths = [];
2610
+ for (const y of yearDirs) {
2611
+ if (!y.isDirectory())
2612
+ continue;
2613
+ const monthDirs = await safeReaddir(join5(CODEX_SESSIONS_ROOT, y.name));
2614
+ if (!monthDirs)
2615
+ continue;
2616
+ for (const m of monthDirs) {
2617
+ if (!m.isDirectory())
2618
+ continue;
2619
+ const dayDirs = await safeReaddir(join5(CODEX_SESSIONS_ROOT, y.name, m.name));
2620
+ if (!dayDirs)
2621
+ continue;
2622
+ for (const d of dayDirs) {
2623
+ if (!d.isDirectory())
2624
+ continue;
2625
+ const dayPath = join5(CODEX_SESSIONS_ROOT, y.name, m.name, d.name);
2626
+ filePaths.push(...await listJsonlFiles(dayPath));
2627
+ }
2628
+ }
2629
+ }
2630
+ if (filePaths.length === 0)
2631
+ return [];
2632
+ const settled = await batchAll(filePaths.map((filePath) => async () => {
2633
+ const sessionId = extractSessionId(filePath.split("/").pop() ?? "");
2634
+ if (!sessionId)
2635
+ return null;
2636
+ const line = await readFirstLine(filePath);
2637
+ if (!line)
2638
+ return null;
2639
+ const { cwd } = extractSessionMeta(line);
2640
+ if (!cwd)
2641
+ return null;
2642
+ let fileMtime;
2643
+ try {
2644
+ const fh = await open2(filePath, "r");
2645
+ try {
2646
+ const stat2 = await fh.stat();
2647
+ fileMtime = stat2.mtime;
2648
+ } finally {
2649
+ await fh.close().catch(() => {});
2650
+ }
2651
+ } catch {
2652
+ fileMtime = new Date(0);
2653
+ }
2654
+ return {
2655
+ filePath,
2656
+ fileName: filePath.split("/").pop() ?? "",
2657
+ cwd,
2658
+ sessionId,
2659
+ fileMtime
2660
+ };
2661
+ }), 16);
2662
+ return settled.filter((r) => r.status === "fulfilled").map((r) => r.value).filter((v) => v !== null);
2663
+ }
2664
+ async function getCodexProjects() {
2665
+ let metas;
2666
+ try {
2667
+ metas = await cachedScan();
2668
+ } catch (error) {
2669
+ logWarn("Failed to scan Codex sessions:", error);
2670
+ return [];
2671
+ }
2672
+ const byCwd = new Map;
2673
+ for (const m of metas) {
2674
+ const existing = byCwd.get(m.cwd);
2675
+ if (!existing || m.fileMtime.getTime() > existing.latest.getTime()) {
2676
+ byCwd.set(m.cwd, { latest: m.fileMtime, cwd: m.cwd });
2677
+ }
2678
+ }
2679
+ const folders = [];
2680
+ for (const { cwd, latest } of byCwd.values()) {
2681
+ folders.push({
2682
+ name: encodeFolderName(cwd),
2683
+ path: cwd,
2684
+ isDirectory: true,
2685
+ lastModified: latest,
2686
+ lastModifiedFormatted: formatDate(latest),
2687
+ cli: ["codex"]
2688
+ });
2689
+ }
2690
+ folders.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());
2691
+ return folders;
2692
+ }
2693
+ function metasToSessionFiles(metas) {
2694
+ const files = metas.map((m) => ({
2695
+ name: m.fileName.replace(/\.jsonl$/, ""),
2696
+ path: m.filePath,
2697
+ lastModified: m.fileMtime,
2698
+ lastModifiedFormatted: formatDate(m.fileMtime),
2699
+ sessionId: m.sessionId,
2700
+ cli: "codex"
2701
+ }));
2702
+ files.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());
2703
+ return files;
2704
+ }
2705
+ async function getCodexSessionsForCwd(cwd) {
2706
+ let metas;
2707
+ try {
2708
+ metas = await cachedScan();
2709
+ } catch (error) {
2710
+ logWarn("Failed to scan Codex sessions:", error);
2711
+ return [];
2712
+ }
2713
+ return metasToSessionFiles(metas.filter((m) => m.cwd === cwd));
2714
+ }
2715
+ async function getCodexSessionsByEncodedName(name) {
2716
+ let metas;
2717
+ try {
2718
+ metas = await cachedScan();
2719
+ } catch (error) {
2720
+ logWarn("Failed to scan Codex sessions:", error);
2721
+ return { cwd: null, sessions: [] };
2722
+ }
2723
+ const matches = metas.filter((m) => encodeFolderName(m.cwd) === name);
2724
+ return {
2725
+ cwd: matches[0]?.cwd ?? null,
2726
+ sessions: metasToSessionFiles(matches)
2727
+ };
2728
+ }
2729
+ var CODEX_SESSIONS_ROOT, SESSION_ID_RE, FIRST_LINE_CHUNK_BYTES, cachedScan, getCachedCodexProjects, getCachedCodexSessionsForCwd, getCachedCodexSessionsByEncodedName;
2730
+ var init_codex_projects = __esm(() => {
2731
+ init_paths();
2732
+ init_logger();
2733
+ CODEX_SESSIONS_ROOT = join5(homedir7(), ".codex", "sessions");
2734
+ SESSION_ID_RE = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
2735
+ FIRST_LINE_CHUNK_BYTES = 256 * 1024;
2736
+ cachedScan = runtimeCache(scanCodexSessions, 30);
2737
+ getCachedCodexProjects = runtimeCache(getCodexProjects, 30);
2738
+ getCachedCodexSessionsForCwd = runtimeCache((cwd) => getCodexSessionsForCwd(cwd), 30, { maxSize: 50 });
2739
+ getCachedCodexSessionsByEncodedName = runtimeCache((name) => getCodexSessionsByEncodedName(name), 30, { maxSize: 50 });
2740
+ });
2741
+
2742
+ // lib/projects.ts
2743
+ import { readdir as readdir2, stat as stat2 } from "fs/promises";
2744
+ import { join as join6, resolve as resolve5, sep } from "path";
2745
+ async function getMtime(path, label) {
2746
+ try {
2747
+ return (await stat2(path)).mtime;
2748
+ } catch (error) {
2749
+ logWarn(`Failed to stat ${label}:`, error);
2750
+ return new Date(0);
2751
+ }
2752
+ }
2753
+ async function safeReaddir2(dirPath) {
2754
+ try {
2755
+ const s = await stat2(dirPath);
2756
+ if (!s.isDirectory())
2757
+ return null;
2758
+ return await readdir2(dirPath, { withFileTypes: true });
2759
+ } catch {
2760
+ return null;
2761
+ }
2762
+ }
2763
+ async function getClaudeProjectFolders() {
2764
+ try {
2765
+ const projectsPath = getClaudeProjectsPath();
2766
+ const entries = await safeReaddir2(projectsPath);
2767
+ if (!entries)
2768
+ return [];
2769
+ const settled = await batchAll(entries.filter((entry) => entry.isDirectory()).map((entry) => async () => {
2770
+ const folderPath = join6(projectsPath, entry.name);
2771
+ const mtime = await getMtime(folderPath, entry.name);
2772
+ return {
2773
+ name: entry.name,
2774
+ path: folderPath,
2775
+ isDirectory: true,
2776
+ lastModified: mtime,
2777
+ lastModifiedFormatted: formatDate(mtime),
2778
+ cli: ["claude"]
2779
+ };
2780
+ }), 16);
2781
+ const folders = settled.filter((r) => r.status === "fulfilled").map((r) => r.value);
2782
+ folders.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());
2783
+ return folders;
2784
+ } catch (error) {
2785
+ logError("Error reading Claude project folders:", error);
2786
+ return [];
2787
+ }
2788
+ }
2789
+ function mergeProjectFolders(claude, codex) {
2790
+ const byName = new Map;
2791
+ for (const f of claude)
2792
+ byName.set(f.name, { ...f, cli: [...f.cli] });
2793
+ for (const f of codex) {
2794
+ const existing = byName.get(f.name);
2795
+ if (!existing) {
2796
+ byName.set(f.name, { ...f, cli: [...f.cli] });
2797
+ continue;
2798
+ }
2799
+ const mergedCli = [...existing.cli];
2800
+ for (const c of f.cli)
2801
+ if (!mergedCli.includes(c))
2802
+ mergedCli.push(c);
2803
+ const newer = f.lastModified.getTime() > existing.lastModified.getTime() ? f : existing;
2804
+ byName.set(f.name, {
2805
+ ...existing,
2806
+ cli: mergedCli,
2807
+ lastModified: newer.lastModified,
2808
+ lastModifiedFormatted: newer.lastModifiedFormatted
2809
+ });
2810
+ }
2811
+ const merged = Array.from(byName.values());
2812
+ merged.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());
2813
+ return merged;
2814
+ }
2815
+ async function getProjectFolders() {
2816
+ const { getCodexProjects: getCodexProjects2 } = await Promise.resolve().then(() => (init_codex_projects(), exports_codex_projects));
2817
+ const [claude, codex] = await Promise.all([
2818
+ getClaudeProjectFolders(),
2819
+ getCodexProjects2().catch((error) => {
2820
+ logError("Error reading Codex projects:", error);
2821
+ return [];
2822
+ })
2823
+ ]);
2824
+ return mergeProjectFolders(claude, codex);
2825
+ }
2826
+ function resolveProjectPath(projectName) {
2827
+ if (!projectName)
2828
+ throw new RangeError("Empty project name");
2829
+ if (/^[/\\]/.test(projectName))
2830
+ throw new RangeError("Absolute project name");
2831
+ const projectsPath = resolve5(getClaudeProjectsPath());
2832
+ const candidate = resolve5(join6(projectsPath, projectName));
2833
+ if (!candidate.startsWith(projectsPath + sep)) {
2834
+ throw new RangeError("Project path escapes root");
2835
+ }
2836
+ return candidate;
2837
+ }
2838
+ function extractSessionId2(filename) {
2839
+ const uuidPattern = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i;
2840
+ const match = filename.match(uuidPattern);
2841
+ return match ? match[0] : undefined;
2842
+ }
2843
+ async function getSessionFiles(projectPath) {
2844
+ try {
2845
+ const entries = await safeReaddir2(projectPath);
2846
+ if (!entries)
2847
+ return [];
2848
+ const jsonlEntries = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl") && extractSessionId2(entry.name));
2849
+ const settled = await batchAll(jsonlEntries.map((entry) => async () => {
2850
+ const filePath = join6(projectPath, entry.name);
2851
+ const mtime = await getMtime(filePath, entry.name);
2852
+ return {
2853
+ name: entry.name,
2854
+ path: filePath,
2855
+ lastModified: mtime,
2856
+ lastModifiedFormatted: formatDate(mtime),
2857
+ sessionId: extractSessionId2(entry.name),
2858
+ cli: "claude"
2859
+ };
2860
+ }), 16);
2861
+ const files = settled.filter((r) => r.status === "fulfilled").map((r) => r.value);
2862
+ files.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());
2863
+ return files;
2864
+ } catch (error) {
2865
+ logError("Error reading session files:", error);
2866
+ return [];
2867
+ }
2868
+ }
2869
+ var getCachedProjectFolders, getCachedSessionFiles;
2870
+ var init_projects = __esm(() => {
2871
+ init_paths();
2872
+ init_logger();
2873
+ getCachedProjectFolders = runtimeCache(getProjectFolders, 30);
2874
+ getCachedSessionFiles = runtimeCache((projectPath) => getSessionFiles(projectPath), 30);
2875
+ });
2876
+
2877
+ // lib/resolve-subagent-path.ts
2878
+ import { access as access2 } from "fs/promises";
2879
+ import { join as join7, relative as relative2 } from "path";
2880
+ async function resolveSubagentPath(projectsPath, projectName, sessionId, agentId) {
2881
+ const fileName = `agent-${agentId}.jsonl`;
2882
+ const candidatePaths = [
2883
+ join7(projectsPath, projectName, fileName),
2884
+ join7(projectsPath, projectName, sessionId, fileName),
2885
+ join7(projectsPath, projectName, sessionId, "subagents", fileName)
2886
+ ];
2887
+ for (const candidatePath of candidatePaths) {
2888
+ if (relative2(projectsPath, candidatePath).startsWith("..")) {
2889
+ continue;
2890
+ }
2891
+ try {
2892
+ await access2(candidatePath);
2893
+ return candidatePath;
2894
+ } catch (e) {
2895
+ const code = e.code;
2896
+ if (code === "ENOENT")
2897
+ continue;
2898
+ break;
2899
+ }
2900
+ }
2901
+ return null;
2902
+ }
2903
+ var init_resolve_subagent_path = () => {};
2904
+
2905
+ // lib/format-duration.ts
2906
+ function formatDuration(ms) {
2907
+ if (ms < 1000)
2908
+ return `${ms}ms`;
2909
+ const seconds = ms / 1000;
2910
+ if (seconds < 60)
2911
+ return `${seconds.toFixed(1)}s`;
2912
+ const totalMinutes = Math.floor(seconds / 60);
2913
+ if (totalMinutes >= 60) {
2914
+ const hours = Math.floor(totalMinutes / 60);
2915
+ const remainingMinutes = totalMinutes % 60;
2916
+ return `${hours}h ${remainingMinutes}m`;
2917
+ }
2918
+ const remainingSeconds = (seconds % 60).toFixed(0);
2919
+ return `${totalMinutes}m ${remainingSeconds}s`;
2920
+ }
2921
+
2922
+ // lib/log-entries.ts
2923
+ import { readFile as readFile3 } from "fs/promises";
2924
+ import { join as join8 } from "path";
2925
+ function formatTimestamp(date) {
2926
+ const base = formatDate(date);
2927
+ const ms = date.getMilliseconds().toString().padStart(3, "0");
2928
+ return `${base}.${ms}`;
2929
+ }
2930
+ function baseEntry(raw, timestamp, date, source) {
2931
+ return {
2932
+ _source: source,
2933
+ uuid: raw.uuid || "",
2934
+ parentUuid: raw.parentUuid ?? null,
2935
+ timestamp,
2936
+ timestampMs: date.getTime(),
2937
+ timestampFormatted: formatTimestamp(date)
2938
+ };
2939
+ }
2940
+ function extractToolResultContent(block) {
2941
+ const resultContent = block.content;
2942
+ if (typeof resultContent === "string")
2943
+ return { text: resultContent };
2944
+ if (Array.isArray(resultContent)) {
2945
+ const arr = resultContent;
2946
+ const textParts = arr.filter((r) => r.type === "text").map((r) => r.text);
2947
+ const images = arr.filter((r) => r.type === "image").map((r) => {
2948
+ const source = r.source;
2949
+ return {
2950
+ base64: source.data,
2951
+ mediaType: source.media_type
2952
+ };
2953
+ }).filter((img) => img.base64 && img.mediaType);
2954
+ return {
2955
+ text: textParts.length > 0 ? textParts.join(`
2956
+ `) : undefined,
2957
+ images: images.length > 0 ? images : undefined
2958
+ };
2959
+ }
2960
+ return {};
2961
+ }
2962
+ async function parseFileContent(fileContent, source) {
2963
+ const lines = fileContent.split(`
2964
+ `).filter((line) => line.trim() !== "");
2965
+ const toolResultMap = new Map;
2966
+ const entries = [];
2967
+ const rawLines = [];
2968
+ const subagentIdSet = new Set;
2969
+ let seenQueue = false;
2970
+ for (let i = 0;i < lines.length; i++) {
2971
+ if (i > 0 && i % 200 === 0)
2972
+ await new Promise((r) => setImmediate(r));
2973
+ const line = lines[i];
2974
+ let raw;
2975
+ try {
2976
+ raw = JSON.parse(line);
2977
+ } catch {
2978
+ continue;
2979
+ }
2980
+ const rawCopy = { ...raw, _source: source };
2981
+ rawLines.push(rawCopy);
2982
+ const type = raw.type;
2983
+ const timestamp = raw.timestamp;
2984
+ if (!timestamp)
2985
+ continue;
2986
+ const date = new Date(timestamp);
2987
+ const timestampMs = date.getTime();
2988
+ if (type === "user") {
2989
+ const message = raw.message;
2990
+ if (Array.isArray(message?.content)) {
2991
+ const blocks = message.content;
2992
+ const hasToolResult = blocks.some((b) => b.type === "tool_result");
2993
+ if (hasToolResult) {
2994
+ const toolUseResult = raw.toolUseResult;
2995
+ const agentId = typeof toolUseResult?.agentId === "string" ? toolUseResult.agentId : undefined;
2996
+ if (agentId && /^[a-f0-9]+$/.test(agentId)) {
2997
+ subagentIdSet.add(agentId);
2998
+ }
2999
+ for (const block of blocks) {
3000
+ if (block.type !== "tool_result")
3001
+ continue;
3002
+ const toolUseId = block.tool_use_id;
3003
+ if (!toolUseId)
3004
+ continue;
3005
+ const { text, images } = extractToolResultContent(block);
3006
+ toolResultMap.set(toolUseId, {
3007
+ timestamp,
3008
+ timestampMs,
3009
+ content: text,
3010
+ images,
3011
+ agentId
3012
+ });
3013
+ }
3014
+ continue;
3015
+ }
3016
+ }
3017
+ const content = typeof message?.content === "string" ? message.content : "";
3018
+ entries.push({ type: "user", ...baseEntry(raw, timestamp, date, source), message: { role: "user", content } });
3019
+ continue;
3020
+ }
3021
+ if (type === "assistant") {
3022
+ const message = raw.message;
3023
+ let content = [];
3024
+ if (Array.isArray(message?.content)) {
3025
+ content = message.content.filter((block) => ["text", "tool_use", "thinking"].includes(block.type)).map((block) => {
3026
+ if (block.type === "text") {
3027
+ return { type: "text", text: block.text };
3028
+ }
3029
+ if (block.type === "tool_use") {
3030
+ const input = block.input;
3031
+ return {
3032
+ type: "tool_use",
3033
+ id: block.id,
3034
+ name: block.name,
3035
+ input: block.input ?? {},
3036
+ ...block.name === "Task" && input ? {
3037
+ subagentType: input.subagent_type,
3038
+ subagentDescription: input.description
3039
+ } : {}
3040
+ };
3041
+ }
3042
+ return {
3043
+ type: "thinking",
3044
+ thinking: block.thinking,
3045
+ signature: block.signature
3046
+ };
3047
+ });
3048
+ }
3049
+ if (content.length === 0)
3050
+ continue;
3051
+ entries.push({
3052
+ type: "assistant",
3053
+ ...baseEntry(raw, timestamp, date, source),
3054
+ message: { role: "assistant", content, model: message?.model }
3055
+ });
3056
+ continue;
3057
+ }
3058
+ if (type === "file-history-snapshot" || type === "progress" || type === "system") {
3059
+ entries.push({ type, ...baseEntry(raw, timestamp, date, source), raw: { ...raw } });
3060
+ continue;
3061
+ }
3062
+ if (type === "queue-operation") {
3063
+ const label = seenQueue ? "Session Resumed" : "Session Started";
3064
+ seenQueue = true;
3065
+ entries.push({ type: "queue-operation", ...baseEntry(raw, timestamp, date, source), label });
3066
+ continue;
3067
+ }
3068
+ }
3069
+ let enrichCount = 0;
3070
+ for (const entry of entries) {
3071
+ if (entry.type !== "assistant")
3072
+ continue;
3073
+ enrichCount++;
3074
+ if (enrichCount % 200 === 0)
3075
+ await new Promise((r) => setImmediate(r));
3076
+ for (const block of entry.message.content) {
3077
+ if (block.type !== "tool_use")
3078
+ continue;
3079
+ const resultInfo = toolResultMap.get(block.id);
3080
+ if (!resultInfo)
3081
+ continue;
3082
+ const returnDate = new Date(resultInfo.timestamp);
3083
+ const durationMs = Math.max(0, resultInfo.timestampMs - entry.timestampMs);
3084
+ block.result = {
3085
+ timestamp: resultInfo.timestamp,
3086
+ timestampFormatted: formatTimestamp(returnDate),
3087
+ content: resultInfo.content,
3088
+ images: resultInfo.images,
3089
+ durationMs,
3090
+ durationFormatted: formatDuration(durationMs)
3091
+ };
3092
+ if (resultInfo.agentId) {
3093
+ block.subagentId = resultInfo.agentId;
3094
+ }
3095
+ }
3096
+ }
3097
+ if (entries.length > 500)
3098
+ await new Promise((r) => setImmediate(r));
3099
+ entries.sort((a, b) => a.timestampMs - b.timestampMs);
3100
+ return { entries, rawLines, subagentIds: Array.from(subagentIdSet) };
3101
+ }
3102
+ async function parseSessionLog(projectName, sessionId) {
3103
+ const projectDir = resolveProjectPath(projectName);
3104
+ const projectsPath = getClaudeProjectsPath();
3105
+ const filePath = join8(projectDir, `${sessionId}.jsonl`);
3106
+ const fileContent = await readFile3(filePath, "utf-8");
3107
+ const { entries: sessionEntries, rawLines: sessionRawLines, subagentIds } = await parseFileContent(fileContent, "session");
3108
+ if (subagentIds.length === 0) {
3109
+ return { entries: sessionEntries, rawLines: sessionRawLines, subagentIds: [] };
3110
+ }
3111
+ const results = await batchAll(subagentIds.map((agentId) => async () => {
3112
+ const agentSource = `agent-${agentId}`;
3113
+ const agentPath = await resolveSubagentPath(projectsPath, projectName, sessionId, agentId);
3114
+ if (!agentPath)
3115
+ return null;
3116
+ const agentContent = await readFile3(agentPath, "utf-8");
3117
+ const { entries, rawLines } = await parseFileContent(agentContent, agentSource);
3118
+ return { entries, rawLines };
3119
+ }), SUBAGENT_CONCURRENCY);
3120
+ const allEntries = [...sessionEntries];
3121
+ const allRawLines = [...sessionRawLines];
3122
+ for (const result of results) {
3123
+ if (result.status === "fulfilled" && result.value) {
3124
+ allEntries.push(...result.value.entries);
3125
+ allRawLines.push(...result.value.rawLines);
3126
+ }
3127
+ }
3128
+ if (allEntries.length > 500)
3129
+ await new Promise((r) => setImmediate(r));
3130
+ allEntries.sort((a, b) => a.timestampMs - b.timestampMs);
3131
+ return { entries: allEntries, rawLines: allRawLines, subagentIds };
3132
+ }
3133
+ var SUBAGENT_CONCURRENCY = 4, getCachedSessionLog;
3134
+ var init_log_entries = __esm(() => {
3135
+ init_paths();
3136
+ init_projects();
3137
+ init_resolve_subagent_path();
3138
+ getCachedSessionLog = runtimeCache((projectName, sessionId) => parseSessionLog(projectName, sessionId), 60, { maxSize: 50 });
3139
+ });
3140
+
3141
+ // lib/codex-sessions.ts
3142
+ import { readFileSync as readFileSync3, readdirSync as readdirSync3, existsSync as existsSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, statSync as statSync4 } from "node:fs";
3143
+ import { readFile as readFile4 } from "node:fs/promises";
3144
+ import { dirname as dirname3, join as join9 } from "node:path";
3145
+ import { homedir as homedir8 } from "node:os";
2444
3146
  function readCache() {
2445
3147
  try {
2446
3148
  if (!existsSync5(CACHE_PATH))
@@ -2462,25 +3164,25 @@ function dirSearch(dir, sessionId) {
2462
3164
  try {
2463
3165
  for (const f of readdirSync3(dir, { withFileTypes: true })) {
2464
3166
  if (f.isFile() && f.name.includes(sessionId) && f.name.endsWith(".jsonl")) {
2465
- return join4(dir, f.name);
3167
+ return join9(dir, f.name);
2466
3168
  }
2467
3169
  }
2468
3170
  } catch {}
2469
3171
  return null;
2470
3172
  }
2471
- function findCodexTranscriptSync(sessionId) {
3173
+ function findCodexTranscript(sessionId) {
2472
3174
  const cache = readCache();
2473
3175
  const cached = cache[sessionId];
2474
3176
  if (cached && existsSync5(cached))
2475
3177
  return cached;
2476
- const root = join4(homedir6(), ".codex", "sessions");
3178
+ const root = join9(homedir8(), ".codex", "sessions");
2477
3179
  const today = new Date;
2478
3180
  const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);
2479
3181
  const datedDirs = [today, yesterday].map((d) => {
2480
3182
  const y = String(d.getUTCFullYear());
2481
3183
  const m = String(d.getUTCMonth() + 1).padStart(2, "0");
2482
3184
  const day = String(d.getUTCDate()).padStart(2, "0");
2483
- return join4(root, y, m, day);
3185
+ return join9(root, y, m, day);
2484
3186
  });
2485
3187
  for (const dir of datedDirs) {
2486
3188
  const hit = dirSearch(dir, sessionId);
@@ -2493,13 +3195,13 @@ function findCodexTranscriptSync(sessionId) {
2493
3195
  for (const y of readdirSync3(root, { withFileTypes: true })) {
2494
3196
  if (!y.isDirectory())
2495
3197
  continue;
2496
- for (const m of readdirSync3(join4(root, y.name), { withFileTypes: true })) {
3198
+ for (const m of readdirSync3(join9(root, y.name), { withFileTypes: true })) {
2497
3199
  if (!m.isDirectory())
2498
3200
  continue;
2499
- for (const d of readdirSync3(join4(root, y.name, m.name), { withFileTypes: true })) {
3201
+ for (const d of readdirSync3(join9(root, y.name, m.name), { withFileTypes: true })) {
2500
3202
  if (!d.isDirectory())
2501
3203
  continue;
2502
- const hit = dirSearch(join4(root, y.name, m.name, d.name), sessionId);
3204
+ const hit = dirSearch(join9(root, y.name, m.name, d.name), sessionId);
2503
3205
  if (hit) {
2504
3206
  writeCacheEntry(sessionId, hit);
2505
3207
  return hit;
@@ -2510,12 +3212,236 @@ function findCodexTranscriptSync(sessionId) {
2510
3212
  } catch {}
2511
3213
  return null;
2512
3214
  }
3215
+ function safeJsonParse(s) {
3216
+ if (!s)
3217
+ return {};
3218
+ try {
3219
+ return JSON.parse(s);
3220
+ } catch {
3221
+ return {};
3222
+ }
3223
+ }
3224
+ function joinTexts(blocks, wantedType) {
3225
+ if (!Array.isArray(blocks))
3226
+ return "";
3227
+ return blocks.filter((b) => b?.type === wantedType && typeof b.text === "string").map((b) => b.text).join(`
3228
+ `);
3229
+ }
3230
+ async function parseCodexLog(fileContent, source = "session") {
3231
+ const lines = fileContent.split(`
3232
+ `).filter((line) => line.trim() !== "");
3233
+ const entries = [];
3234
+ const rawLines = [];
3235
+ const toolUseById = new Map;
3236
+ const toolUseStartMs = new Map;
3237
+ let cwd;
3238
+ let seenTaskStart = false;
3239
+ for (let i = 0;i < lines.length; i++) {
3240
+ if (i > 0 && i % 200 === 0)
3241
+ await new Promise((r) => setImmediate(r));
3242
+ const line = lines[i];
3243
+ let raw;
3244
+ try {
3245
+ raw = JSON.parse(line);
3246
+ } catch {
3247
+ continue;
3248
+ }
3249
+ const rawCopy = { ...raw, _source: source };
3250
+ rawLines.push(rawCopy);
3251
+ const timestamp = raw.timestamp;
3252
+ if (!timestamp)
3253
+ continue;
3254
+ const date = new Date(timestamp);
3255
+ if (Number.isNaN(date.getTime()))
3256
+ continue;
3257
+ const recType = raw.type;
3258
+ const payload = raw.payload ?? {};
3259
+ if (recType === "session_meta") {
3260
+ const c = payload.cwd;
3261
+ if (typeof c === "string" && !cwd)
3262
+ cwd = c;
3263
+ entries.push({
3264
+ type: "system",
3265
+ ...baseEntry(rawCopy, timestamp, date, source),
3266
+ raw: rawCopy
3267
+ });
3268
+ continue;
3269
+ }
3270
+ if (recType === "response_item") {
3271
+ const subType = payload.type;
3272
+ if (subType === "message") {
3273
+ const role = payload.role;
3274
+ const content = payload.content;
3275
+ if (role === "user" || role === "developer") {
3276
+ const text = joinTexts(content, "input_text");
3277
+ if (!text)
3278
+ continue;
3279
+ const message = role === "developer" ? `[developer] ${text}` : text;
3280
+ entries.push({
3281
+ type: "user",
3282
+ ...baseEntry(rawCopy, timestamp, date, source),
3283
+ message: { role: "user", content: message }
3284
+ });
3285
+ continue;
3286
+ }
3287
+ if (role === "assistant") {
3288
+ const text = joinTexts(content, "output_text");
3289
+ if (!text)
3290
+ continue;
3291
+ const blocks = [{ type: "text", text }];
3292
+ entries.push({
3293
+ type: "assistant",
3294
+ ...baseEntry(rawCopy, timestamp, date, source),
3295
+ message: { role: "assistant", content: blocks }
3296
+ });
3297
+ continue;
3298
+ }
3299
+ entries.push({
3300
+ type: "system",
3301
+ ...baseEntry(rawCopy, timestamp, date, source),
3302
+ raw: rawCopy
3303
+ });
3304
+ continue;
3305
+ }
3306
+ if (subType === "function_call") {
3307
+ const callId = payload.call_id;
3308
+ const name = payload.name ?? "function_call";
3309
+ const input = safeJsonParse(payload.arguments);
3310
+ const toolUse = {
3311
+ type: "tool_use",
3312
+ id: callId ?? `${timestamp}-${name}`,
3313
+ name,
3314
+ input
3315
+ };
3316
+ const entry = {
3317
+ type: "assistant",
3318
+ ...baseEntry(rawCopy, timestamp, date, source),
3319
+ message: { role: "assistant", content: [toolUse] }
3320
+ };
3321
+ entries.push(entry);
3322
+ if (callId) {
3323
+ toolUseById.set(callId, toolUse);
3324
+ toolUseStartMs.set(callId, date.getTime());
3325
+ }
3326
+ continue;
3327
+ }
3328
+ if (subType === "function_call_output") {
3329
+ const callId = payload.call_id;
3330
+ const block = callId ? toolUseById.get(callId) : undefined;
3331
+ if (block) {
3332
+ const startMs = toolUseStartMs.get(callId) ?? date.getTime();
3333
+ const duration = Math.max(0, date.getTime() - startMs);
3334
+ block.result = {
3335
+ timestamp,
3336
+ timestampFormatted: formatTimestamp(date),
3337
+ content: typeof payload.output === "string" ? payload.output : JSON.stringify(payload.output),
3338
+ durationMs: duration,
3339
+ durationFormatted: formatDuration(duration)
3340
+ };
3341
+ continue;
3342
+ }
3343
+ entries.push({
3344
+ type: "system",
3345
+ ...baseEntry(rawCopy, timestamp, date, source),
3346
+ raw: rawCopy
3347
+ });
3348
+ continue;
3349
+ }
3350
+ entries.push({
3351
+ type: "system",
3352
+ ...baseEntry(rawCopy, timestamp, date, source),
3353
+ raw: rawCopy
3354
+ });
3355
+ continue;
3356
+ }
3357
+ if (recType === "event_msg") {
3358
+ const subType = payload.type;
3359
+ if (subType === "task_started") {
3360
+ const label = seenTaskStart ? "Session Resumed" : "Session Started";
3361
+ seenTaskStart = true;
3362
+ entries.push({
3363
+ type: "queue-operation",
3364
+ ...baseEntry(rawCopy, timestamp, date, source),
3365
+ label
3366
+ });
3367
+ continue;
3368
+ }
3369
+ if (subType === "exec_command_end") {
3370
+ const callId = payload.call_id;
3371
+ const block = callId ? toolUseById.get(callId) : undefined;
3372
+ if (block) {
3373
+ const duration = payload.duration;
3374
+ const durationMs = duration ? (duration.secs ?? 0) * 1000 + Math.round((duration.nanos ?? 0) / 1e6) : Math.max(0, date.getTime() - (toolUseStartMs.get(callId) ?? date.getTime()));
3375
+ const aggregated = payload.aggregated_output;
3376
+ block.result = {
3377
+ timestamp,
3378
+ timestampFormatted: formatTimestamp(date),
3379
+ content: typeof aggregated === "string" ? aggregated : JSON.stringify(aggregated),
3380
+ durationMs,
3381
+ durationFormatted: formatDuration(durationMs)
3382
+ };
3383
+ continue;
3384
+ }
3385
+ entries.push({
3386
+ type: "system",
3387
+ ...baseEntry(rawCopy, timestamp, date, source),
3388
+ raw: rawCopy
3389
+ });
3390
+ continue;
3391
+ }
3392
+ if (subType === "user_message" || subType === "agent_message") {
3393
+ continue;
3394
+ }
3395
+ entries.push({
3396
+ type: "system",
3397
+ ...baseEntry(rawCopy, timestamp, date, source),
3398
+ raw: rawCopy
3399
+ });
3400
+ continue;
3401
+ }
3402
+ entries.push({
3403
+ type: "system",
3404
+ ...baseEntry(rawCopy, timestamp, date, source),
3405
+ raw: rawCopy
3406
+ });
3407
+ }
3408
+ if (entries.length > 500)
3409
+ await new Promise((r) => setImmediate(r));
3410
+ entries.sort((a, b) => a.timestampMs - b.timestampMs);
3411
+ return { entries, rawLines, cwd };
3412
+ }
3413
+ async function getCodexSessionLog(sessionId) {
3414
+ const filePath = findCodexTranscript(sessionId);
3415
+ if (!filePath)
3416
+ return null;
3417
+ const fileContent = await readFile4(filePath, "utf-8");
3418
+ const { entries, rawLines, cwd } = await parseCodexLog(fileContent, "session");
3419
+ return { entries, rawLines, cwd, filePath };
3420
+ }
3421
+ var CACHE_PATH, getCachedCodexSessionLog;
3422
+ var init_codex_sessions = __esm(() => {
3423
+ init_log_entries();
3424
+ CACHE_PATH = join9(homedir8(), ".failproofai", "cache", "codex-session-paths.json");
3425
+ getCachedCodexSessionLog = runtimeCache((sessionId) => getCodexSessionLog(sessionId), 60, { maxSize: 50 });
3426
+ });
3427
+
3428
+ // src/hooks/resolve-permission-mode.ts
3429
+ import { readFileSync as readFileSync4 } from "node:fs";
3430
+ function resolvePermissionMode(integration, parsed, sessionId) {
3431
+ if (integration === "claude") {
3432
+ return parsed.permission_mode ?? "default";
3433
+ }
3434
+ if (integration === "codex" && sessionId) {
3435
+ return resolveCodexMode(sessionId) ?? "default";
3436
+ }
3437
+ return "default";
3438
+ }
2513
3439
  function resolveCodexMode(sessionId) {
2514
3440
  try {
2515
- const path = findCodexTranscriptSync(sessionId);
3441
+ const path = findCodexTranscript(sessionId);
2516
3442
  if (!path)
2517
3443
  return;
2518
- for (const line of readFileSync3(path, "utf-8").split(`
3444
+ for (const line of readFileSync4(path, "utf-8").split(`
2519
3445
  `)) {
2520
3446
  if (!line.includes("turn_context"))
2521
3447
  continue;
@@ -2535,9 +3461,8 @@ function resolveCodexMode(sessionId) {
2535
3461
  } catch {}
2536
3462
  return;
2537
3463
  }
2538
- var CACHE_PATH;
2539
3464
  var init_resolve_permission_mode = __esm(() => {
2540
- CACHE_PATH = join4(homedir6(), ".failproofai", "cache", "codex-session-paths.json");
3465
+ init_codex_sessions();
2541
3466
  });
2542
3467
 
2543
3468
  // lib/telemetry-id.ts
@@ -2623,7 +3548,7 @@ var init_telemetry_id = __esm(() => {
2623
3548
 
2624
3549
  // src/auth/token-store.ts
2625
3550
  import {
2626
- readFileSync as readFileSync4,
3551
+ readFileSync as readFileSync5,
2627
3552
  writeFileSync as writeFileSync4,
2628
3553
  existsSync as existsSync6,
2629
3554
  mkdirSync as mkdirSync5,
@@ -2632,8 +3557,8 @@ import {
2632
3557
  openSync,
2633
3558
  closeSync
2634
3559
  } from "node:fs";
2635
- import { join as join5 } from "node:path";
2636
- import { homedir as homedir7 } from "node:os";
3560
+ import { join as join10 } from "node:path";
3561
+ import { homedir as homedir9 } from "node:os";
2637
3562
  function ensureAuthDir() {
2638
3563
  if (!existsSync6(AUTH_DIR))
2639
3564
  mkdirSync5(AUTH_DIR, { recursive: true, mode: 448 });
@@ -2642,7 +3567,7 @@ function readTokens() {
2642
3567
  if (!existsSync6(AUTH_FILE))
2643
3568
  return null;
2644
3569
  try {
2645
- const raw = readFileSync4(AUTH_FILE, "utf8");
3570
+ const raw = readFileSync5(AUTH_FILE, "utf8");
2646
3571
  return JSON.parse(raw);
2647
3572
  } catch {
2648
3573
  return null;
@@ -2668,8 +3593,8 @@ function isLoggedIn() {
2668
3593
  }
2669
3594
  var AUTH_DIR, AUTH_FILE;
2670
3595
  var init_token_store = __esm(() => {
2671
- AUTH_DIR = join5(homedir7(), ".failproofai");
2672
- AUTH_FILE = join5(AUTH_DIR, "auth.json");
3596
+ AUTH_DIR = join10(homedir9(), ".failproofai");
3597
+ AUTH_FILE = join10(AUTH_DIR, "auth.json");
2673
3598
  });
2674
3599
 
2675
3600
  // src/relay/queue.ts
@@ -2686,15 +3611,15 @@ import {
2686
3611
  appendFileSync as appendFileSync3,
2687
3612
  mkdirSync as mkdirSync6,
2688
3613
  existsSync as existsSync7,
2689
- readFileSync as readFileSync5,
2690
- statSync as statSync4,
3614
+ readFileSync as readFileSync6,
3615
+ statSync as statSync5,
2691
3616
  renameSync as renameSync4,
2692
3617
  unlinkSync as unlinkSync3,
2693
3618
  readdirSync as readdirSync4,
2694
3619
  chmodSync
2695
3620
  } from "node:fs";
2696
- import { join as join6 } from "node:path";
2697
- import { homedir as homedir8 } from "node:os";
3621
+ import { join as join11 } from "node:path";
3622
+ import { homedir as homedir10 } from "node:os";
2698
3623
  import { createHash, randomUUID } from "node:crypto";
2699
3624
  function hashCwd(cwd) {
2700
3625
  if (!cwd)
@@ -2733,7 +3658,7 @@ function appendToServerQueue(entry) {
2733
3658
  return;
2734
3659
  ensureDir2();
2735
3660
  try {
2736
- if (existsSync7(PENDING_FILE) && statSync4(PENDING_FILE).size > MAX_QUEUE_BYTES) {
3661
+ if (existsSync7(PENDING_FILE) && statSync5(PENDING_FILE).size > MAX_QUEUE_BYTES) {
2737
3662
  return;
2738
3663
  }
2739
3664
  } catch {}
@@ -2746,7 +3671,7 @@ function appendToServerQueue(entry) {
2746
3671
  }
2747
3672
  function queueSizeBytes() {
2748
3673
  try {
2749
- return statSync4(PENDING_FILE).size;
3674
+ return statSync5(PENDING_FILE).size;
2750
3675
  } catch {
2751
3676
  return 0;
2752
3677
  }
@@ -2755,14 +3680,14 @@ function claimPendingBatch() {
2755
3680
  if (!existsSync7(PENDING_FILE))
2756
3681
  return null;
2757
3682
  try {
2758
- const size = statSync4(PENDING_FILE).size;
3683
+ const size = statSync5(PENDING_FILE).size;
2759
3684
  if (size === 0)
2760
3685
  return null;
2761
3686
  } catch {
2762
3687
  return null;
2763
3688
  }
2764
3689
  const seq = `${Date.now()}-${process.pid}`;
2765
- const processingFile = join6(QUEUE_DIR, `${PROCESSING_PREFIX}${seq}.jsonl`);
3690
+ const processingFile = join11(QUEUE_DIR, `${PROCESSING_PREFIX}${seq}.jsonl`);
2766
3691
  try {
2767
3692
  renameSync4(PENDING_FILE, processingFile);
2768
3693
  try {
@@ -2779,7 +3704,7 @@ function claimPendingBatch() {
2779
3704
  function findOrphanProcessingFiles() {
2780
3705
  ensureDir2();
2781
3706
  try {
2782
- return readdirSync4(QUEUE_DIR).filter((n) => n.startsWith(PROCESSING_PREFIX) && n.endsWith(".jsonl")).map((n) => join6(QUEUE_DIR, n)).sort();
3707
+ return readdirSync4(QUEUE_DIR).filter((n) => n.startsWith(PROCESSING_PREFIX) && n.endsWith(".jsonl")).map((n) => join11(QUEUE_DIR, n)).sort();
2783
3708
  } catch {
2784
3709
  return [];
2785
3710
  }
@@ -2787,7 +3712,7 @@ function findOrphanProcessingFiles() {
2787
3712
  function readProcessingFile(path2) {
2788
3713
  if (!existsSync7(path2))
2789
3714
  return [];
2790
- const content = readFileSync5(path2, "utf8");
3715
+ const content = readFileSync6(path2, "utf8");
2791
3716
  const out = [];
2792
3717
  for (const line of content.split(`
2793
3718
  `)) {
@@ -2808,20 +3733,20 @@ function deleteProcessingFile(path2) {
2808
3733
  var QUEUE_DIR, PENDING_FILE, PROCESSING_PREFIX = "processing-", MAX_QUEUE_BYTES;
2809
3734
  var init_queue = __esm(() => {
2810
3735
  init_token_store();
2811
- QUEUE_DIR = join6(homedir8(), ".failproofai", "cache", "server-queue");
2812
- PENDING_FILE = join6(QUEUE_DIR, "pending.jsonl");
3736
+ QUEUE_DIR = join11(homedir10(), ".failproofai", "cache", "server-queue");
3737
+ PENDING_FILE = join11(QUEUE_DIR, "pending.jsonl");
2813
3738
  MAX_QUEUE_BYTES = 50 * 1024 * 1024;
2814
3739
  });
2815
3740
 
2816
3741
  // src/relay/pid.ts
2817
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync8, unlinkSync as unlinkSync4, mkdirSync as mkdirSync7 } from "node:fs";
2818
- import { join as join7, dirname as dirname4 } from "node:path";
2819
- import { homedir as homedir9 } from "node:os";
3742
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync8, unlinkSync as unlinkSync4, mkdirSync as mkdirSync7 } from "node:fs";
3743
+ import { join as join12, dirname as dirname4 } from "node:path";
3744
+ import { homedir as homedir11 } from "node:os";
2820
3745
  function readPid() {
2821
3746
  if (!existsSync8(PID_FILE))
2822
3747
  return null;
2823
3748
  try {
2824
- const raw = readFileSync6(PID_FILE, "utf8").trim();
3749
+ const raw = readFileSync7(PID_FILE, "utf8").trim();
2825
3750
  const pid = parseInt(raw, 10);
2826
3751
  if (Number.isNaN(pid) || pid <= 0)
2827
3752
  return null;
@@ -2869,7 +3794,7 @@ function stopRelay() {
2869
3794
  }
2870
3795
  var PID_FILE;
2871
3796
  var init_pid = __esm(() => {
2872
- PID_FILE = join7(homedir9(), ".failproofai", "relay.pid");
3797
+ PID_FILE = join12(homedir11(), ".failproofai", "relay.pid");
2873
3798
  });
2874
3799
 
2875
3800
  // src/relay/daemon.ts
@@ -2882,8 +3807,8 @@ __export(exports_daemon, {
2882
3807
  });
2883
3808
  import { spawn } from "node:child_process";
2884
3809
  import { existsSync as existsSync9 } from "node:fs";
2885
- import { join as join8 } from "node:path";
2886
- import { homedir as homedir10 } from "node:os";
3810
+ import { join as join13 } from "node:path";
3811
+ import { homedir as homedir12 } from "node:os";
2887
3812
  import { randomUUID as randomUUID2 } from "node:crypto";
2888
3813
  function ensureRelayRunning() {
2889
3814
  if (!isLoggedIn())
@@ -2963,16 +3888,16 @@ class Relay {
2963
3888
  try {
2964
3889
  const msg = JSON.parse(data);
2965
3890
  if (msg.ack && this.pendingAcks.has(msg.ack)) {
2966
- const resolve5 = this.pendingAcks.get(msg.ack);
3891
+ const resolve6 = this.pendingAcks.get(msg.ack);
2967
3892
  this.pendingAcks.delete(msg.ack);
2968
- resolve5(true);
3893
+ resolve6(true);
2969
3894
  }
2970
3895
  } catch {}
2971
3896
  }
2972
3897
  handleClose() {
2973
3898
  this.closed = true;
2974
- for (const [, resolve5] of this.pendingAcks) {
2975
- resolve5(false);
3899
+ for (const [, resolve6] of this.pendingAcks) {
3900
+ resolve6(false);
2976
3901
  }
2977
3902
  this.pendingAcks.clear();
2978
3903
  }
@@ -2988,11 +3913,11 @@ class Relay {
2988
3913
  if (this.closed)
2989
3914
  return false;
2990
3915
  const batchId = randomUUID2();
2991
- const ackPromise = new Promise((resolve5) => {
2992
- this.pendingAcks.set(batchId, resolve5);
3916
+ const ackPromise = new Promise((resolve6) => {
3917
+ this.pendingAcks.set(batchId, resolve6);
2993
3918
  setTimeout(() => {
2994
3919
  if (this.pendingAcks.delete(batchId))
2995
- resolve5(false);
3920
+ resolve6(false);
2996
3921
  }, ACK_TIMEOUT_MS);
2997
3922
  });
2998
3923
  try {
@@ -3010,7 +3935,7 @@ async function connect(wsUrl, token) {
3010
3935
  throw new Error("WebSocket not available in this Node version. Requires Node 22+.");
3011
3936
  }
3012
3937
  const ws = new WSCtor(wsUrl);
3013
- await new Promise((resolve5, reject) => {
3938
+ await new Promise((resolve6, reject) => {
3014
3939
  let settled = false;
3015
3940
  const timeout = setTimeout(() => {
3016
3941
  if (settled)
@@ -3028,7 +3953,7 @@ async function connect(wsUrl, token) {
3028
3953
  clearTimeout(timeout);
3029
3954
  try {
3030
3955
  ws.send(token);
3031
- resolve5();
3956
+ resolve6();
3032
3957
  } catch (e) {
3033
3958
  reject(e);
3034
3959
  }
@@ -3150,7 +4075,7 @@ var init_daemon = __esm(() => {
3150
4075
  init_token_store();
3151
4076
  init_pid();
3152
4077
  init_queue();
3153
- QUEUE_DIR2 = join8(homedir10(), ".failproofai", "cache", "server-queue");
4078
+ QUEUE_DIR2 = join13(homedir12(), ".failproofai", "cache", "server-queue");
3154
4079
  });
3155
4080
 
3156
4081
  // src/hooks/handler.ts
@@ -3171,7 +4096,7 @@ async function handleHookEvent(eventType, cli = "claude") {
3171
4096
  const MAX_STDIN_BYTES = 1048576;
3172
4097
  let payload = "";
3173
4098
  try {
3174
- payload = await new Promise((resolve5, reject) => {
4099
+ payload = await new Promise((resolve6, reject) => {
3175
4100
  const chunks = [];
3176
4101
  let totalBytes = 0;
3177
4102
  process.stdin.setEncoding("utf8");
@@ -3180,15 +4105,15 @@ async function handleHookEvent(eventType, cli = "claude") {
3180
4105
  if (totalBytes > MAX_STDIN_BYTES) {
3181
4106
  hookLogWarn(`stdin payload exceeds 1 MB for ${eventType}, discarding`);
3182
4107
  process.stdin.destroy();
3183
- resolve5("");
4108
+ resolve6("");
3184
4109
  return;
3185
4110
  }
3186
4111
  chunks.push(chunk);
3187
4112
  });
3188
- process.stdin.on("end", () => resolve5(chunks.join("")));
4113
+ process.stdin.on("end", () => resolve6(chunks.join("")));
3189
4114
  process.stdin.on("error", reject);
3190
4115
  if (process.stdin.readableEnded)
3191
- resolve5("");
4116
+ resolve6("");
3192
4117
  });
3193
4118
  } catch {
3194
4119
  hookLogWarn(`stdin read failed for ${eventType}`);
@@ -3350,8 +4275,8 @@ __export(exports_daemon2, {
3350
4275
  });
3351
4276
  import { spawn as spawn2 } from "node:child_process";
3352
4277
  import { existsSync as existsSync10 } from "node:fs";
3353
- import { join as join9 } from "node:path";
3354
- import { homedir as homedir11 } from "node:os";
4278
+ import { join as join14 } from "node:path";
4279
+ import { homedir as homedir13 } from "node:os";
3355
4280
  import { randomUUID as randomUUID3 } from "node:crypto";
3356
4281
  function ensureRelayRunning2() {
3357
4282
  if (!isLoggedIn())
@@ -3431,16 +4356,16 @@ class Relay2 {
3431
4356
  try {
3432
4357
  const msg = JSON.parse(data);
3433
4358
  if (msg.ack && this.pendingAcks.has(msg.ack)) {
3434
- const resolve5 = this.pendingAcks.get(msg.ack);
4359
+ const resolve6 = this.pendingAcks.get(msg.ack);
3435
4360
  this.pendingAcks.delete(msg.ack);
3436
- resolve5(true);
4361
+ resolve6(true);
3437
4362
  }
3438
4363
  } catch {}
3439
4364
  }
3440
4365
  handleClose() {
3441
4366
  this.closed = true;
3442
- for (const [, resolve5] of this.pendingAcks) {
3443
- resolve5(false);
4367
+ for (const [, resolve6] of this.pendingAcks) {
4368
+ resolve6(false);
3444
4369
  }
3445
4370
  this.pendingAcks.clear();
3446
4371
  }
@@ -3456,11 +4381,11 @@ class Relay2 {
3456
4381
  if (this.closed)
3457
4382
  return false;
3458
4383
  const batchId = randomUUID3();
3459
- const ackPromise = new Promise((resolve5) => {
3460
- this.pendingAcks.set(batchId, resolve5);
4384
+ const ackPromise = new Promise((resolve6) => {
4385
+ this.pendingAcks.set(batchId, resolve6);
3461
4386
  setTimeout(() => {
3462
4387
  if (this.pendingAcks.delete(batchId))
3463
- resolve5(false);
4388
+ resolve6(false);
3464
4389
  }, ACK_TIMEOUT_MS2);
3465
4390
  });
3466
4391
  try {
@@ -3478,7 +4403,7 @@ async function connect2(wsUrl, token) {
3478
4403
  throw new Error("WebSocket not available in this Node version. Requires Node 22+.");
3479
4404
  }
3480
4405
  const ws = new WSCtor(wsUrl);
3481
- await new Promise((resolve5, reject) => {
4406
+ await new Promise((resolve6, reject) => {
3482
4407
  let settled = false;
3483
4408
  const timeout = setTimeout(() => {
3484
4409
  if (settled)
@@ -3496,7 +4421,7 @@ async function connect2(wsUrl, token) {
3496
4421
  clearTimeout(timeout);
3497
4422
  try {
3498
4423
  ws.send(token);
3499
- resolve5();
4424
+ resolve6();
3500
4425
  } catch (e) {
3501
4426
  reject(e);
3502
4427
  }
@@ -3618,18 +4543,18 @@ var init_daemon2 = __esm(() => {
3618
4543
  init_token_store();
3619
4544
  init_pid();
3620
4545
  init_queue();
3621
- QUEUE_DIR3 = join9(homedir11(), ".failproofai", "cache", "server-queue");
4546
+ QUEUE_DIR3 = join14(homedir13(), ".failproofai", "cache", "server-queue");
3622
4547
  });
3623
4548
 
3624
4549
  // src/hooks/integrations.ts
3625
4550
  import { execSync as execSync3 } from "node:child_process";
3626
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync6, existsSync as existsSync11, mkdirSync as mkdirSync8 } from "node:fs";
3627
- import { resolve as resolve5, dirname as dirname5 } from "node:path";
3628
- import { homedir as homedir12 } from "node:os";
4551
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync11, mkdirSync as mkdirSync8 } from "node:fs";
4552
+ import { resolve as resolve6, dirname as dirname5 } from "node:path";
4553
+ import { homedir as homedir14 } from "node:os";
3629
4554
  function readJsonFile(path2) {
3630
4555
  if (!existsSync11(path2))
3631
4556
  return {};
3632
- const raw = readFileSync7(path2, "utf8");
4557
+ const raw = readFileSync8(path2, "utf8");
3633
4558
  return JSON.parse(raw);
3634
4559
  }
3635
4560
  function writeJsonFile(path2, data) {
@@ -3671,14 +4596,14 @@ var init_integrations = __esm(() => {
3671
4596
  scopes: HOOK_SCOPES,
3672
4597
  eventTypes: HOOK_EVENT_TYPES,
3673
4598
  getSettingsPath(scope, cwd) {
3674
- const base = cwd ? resolve5(cwd) : process.cwd();
4599
+ const base = cwd ? resolve6(cwd) : process.cwd();
3675
4600
  switch (scope) {
3676
4601
  case "user":
3677
- return resolve5(homedir12(), ".claude", "settings.json");
4602
+ return resolve6(homedir14(), ".claude", "settings.json");
3678
4603
  case "project":
3679
- return resolve5(base, ".claude", "settings.json");
4604
+ return resolve6(base, ".claude", "settings.json");
3680
4605
  case "local":
3681
- return resolve5(base, ".claude", "settings.local.json");
4606
+ return resolve6(base, ".claude", "settings.local.json");
3682
4607
  }
3683
4608
  },
3684
4609
  readSettings(settingsPath) {
@@ -3779,14 +4704,14 @@ var init_integrations = __esm(() => {
3779
4704
  scopes: CODEX_HOOK_SCOPES,
3780
4705
  eventTypes: CODEX_HOOK_EVENT_TYPES,
3781
4706
  getSettingsPath(scope, cwd) {
3782
- const base = cwd ? resolve5(cwd) : process.cwd();
4707
+ const base = cwd ? resolve6(cwd) : process.cwd();
3783
4708
  switch (scope) {
3784
4709
  case "user":
3785
- return resolve5(homedir12(), ".codex", "hooks.json");
4710
+ return resolve6(homedir14(), ".codex", "hooks.json");
3786
4711
  case "project":
3787
- return resolve5(base, ".codex", "hooks.json");
4712
+ return resolve6(base, ".codex", "hooks.json");
3788
4713
  case "local":
3789
- return resolve5(base, ".codex", "hooks.json");
4714
+ return resolve6(base, ".codex", "hooks.json");
3790
4715
  }
3791
4716
  },
3792
4717
  readSettings(settingsPath) {
@@ -4081,7 +5006,7 @@ async function promptPolicySelection(preSelected, options = {}) {
4081
5006
  process.stdout.write(output);
4082
5007
  lastLineCount = lines.length;
4083
5008
  }
4084
- return new Promise((resolve6) => {
5009
+ return new Promise((resolve7) => {
4085
5010
  render();
4086
5011
  process.stdin.setRawMode(true);
4087
5012
  process.stdin.resume();
@@ -4123,7 +5048,7 @@ async function promptPolicySelection(preSelected, options = {}) {
4123
5048
  const selected = items.filter((i) => i.selected).map((i) => i.name);
4124
5049
  process.stdout.write(`
4125
5050
  `);
4126
- resolve6(selected);
5051
+ resolve7(selected);
4127
5052
  } else if (key.name === "backspace" || key.name === "delete") {
4128
5053
  if (search.length > 0) {
4129
5054
  search = search.slice(0, -1);
@@ -4174,8 +5099,8 @@ __export(exports_manager, {
4174
5099
  });
4175
5100
  import { execSync as execSync4 } from "node:child_process";
4176
5101
  import { existsSync as existsSync12 } from "node:fs";
4177
- import { resolve as resolve6, basename as basename2 } from "node:path";
4178
- import { homedir as homedir13, platform, arch, release, hostname } from "node:os";
5102
+ import { resolve as resolve7, basename as basename2 } from "node:path";
5103
+ import { homedir as homedir15, platform, arch, release, hostname } from "node:os";
4179
5104
  function getSettingsPath(scope, cwd) {
4180
5105
  return claudeCode.getSettingsPath(scope, cwd);
4181
5106
  }
@@ -4261,7 +5186,7 @@ async function installHooks(policyNames, scope = "user", cwd, includeBeta = fals
4261
5186
  if (removeCustomHooks) {
4262
5187
  delete configToWrite.customPoliciesPath;
4263
5188
  } else if (customPoliciesPath) {
4264
- configToWrite.customPoliciesPath = resolve6(customPoliciesPath);
5189
+ configToWrite.customPoliciesPath = resolve7(customPoliciesPath);
4265
5190
  let validatedHooks = [];
4266
5191
  try {
4267
5192
  validatedHooks = await loadCustomHooks(configToWrite.customPoliciesPath, { strict: true });
@@ -4278,7 +5203,8 @@ Validated ${validatedHooks.length} custom hook(s): ${validatedHooks.map((h) => h
4278
5203
  }
4279
5204
  writeScopedHooksConfig(configToWrite, scope, cwd);
4280
5205
  console.log(`
4281
- Enabled ${selectedPolicies.length} policy(ies): ${selectedPolicies.join(", ")}`);
5206
+ Enabled ${selectedPolicies.length} policy(ies): ${selectedPolicies.join(", ")}
5207
+ `);
4282
5208
  if (removeCustomHooks) {
4283
5209
  console.log("Custom hooks path cleared.");
4284
5210
  } else if (configToWrite.customPoliciesPath) {
@@ -4589,10 +5515,10 @@ Failproof AI Hook Policies
4589
5515
  }
4590
5516
  console.log();
4591
5517
  }
4592
- const base = cwd ? resolve6(cwd) : process.cwd();
5518
+ const base = cwd ? resolve7(cwd) : process.cwd();
4593
5519
  const conventionDirs = [
4594
- { label: "Project", dir: resolve6(base, ".failproofai", "policies") },
4595
- { label: "User", dir: resolve6(homedir13(), ".failproofai", "policies") }
5520
+ { label: "Project", dir: resolve7(base, ".failproofai", "policies") },
5521
+ { label: "User", dir: resolve7(homedir15(), ".failproofai", "policies") }
4596
5522
  ];
4597
5523
  for (const { label, dir } of conventionDirs) {
4598
5524
  const files = discoverPolicyFiles(dir);
@@ -4733,7 +5659,7 @@ async function promptCliTargetSelection(detected) {
4733
5659
  process.stdout.write(output);
4734
5660
  lastLineCount = lines.length;
4735
5661
  }
4736
- return new Promise((resolve7) => {
5662
+ return new Promise((resolve8) => {
4737
5663
  render();
4738
5664
  readline2.emitKeypressEvents(process.stdin);
4739
5665
  const wasRaw = process.stdin.isRaw;
@@ -4766,7 +5692,7 @@ async function promptCliTargetSelection(detected) {
4766
5692
  cleanup();
4767
5693
  process.stdout.write(`
4768
5694
  `);
4769
- resolve7(options[cursor].value);
5695
+ resolve8(options[cursor].value);
4770
5696
  }
4771
5697
  }
4772
5698
  process.stdin.on("keypress", onKey);
@@ -4958,7 +5884,7 @@ async function promptPolicySelection2(preSelected, options = {}) {
4958
5884
  process.stdout.write(output);
4959
5885
  lastLineCount = lines.length;
4960
5886
  }
4961
- return new Promise((resolve7) => {
5887
+ return new Promise((resolve8) => {
4962
5888
  render();
4963
5889
  process.stdin.setRawMode(true);
4964
5890
  process.stdin.resume();
@@ -5000,7 +5926,7 @@ async function promptPolicySelection2(preSelected, options = {}) {
5000
5926
  const selected = items.filter((i) => i.selected).map((i) => i.name);
5001
5927
  process.stdout.write(`
5002
5928
  `);
5003
- resolve7(selected);
5929
+ resolve8(selected);
5004
5930
  } else if (key.name === "backspace" || key.name === "delete") {
5005
5931
  if (search.length > 0) {
5006
5932
  search = search.slice(0, -1);
@@ -5162,14 +6088,14 @@ __export(exports_pid, {
5162
6088
  isProcessAlive: () => isProcessAlive2,
5163
6089
  clearPid: () => clearPid2
5164
6090
  });
5165
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync7, existsSync as existsSync13, unlinkSync as unlinkSync5, mkdirSync as mkdirSync9 } from "node:fs";
5166
- import { join as join10, dirname as dirname6 } from "node:path";
5167
- import { homedir as homedir14 } from "node:os";
6091
+ import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, existsSync as existsSync13, unlinkSync as unlinkSync5, mkdirSync as mkdirSync9 } from "node:fs";
6092
+ import { join as join15, dirname as dirname6 } from "node:path";
6093
+ import { homedir as homedir16 } from "node:os";
5168
6094
  function readPid2() {
5169
6095
  if (!existsSync13(PID_FILE2))
5170
6096
  return null;
5171
6097
  try {
5172
- const raw = readFileSync8(PID_FILE2, "utf8").trim();
6098
+ const raw = readFileSync9(PID_FILE2, "utf8").trim();
5173
6099
  const pid = parseInt(raw, 10);
5174
6100
  if (Number.isNaN(pid) || pid <= 0)
5175
6101
  return null;
@@ -5223,26 +6149,18 @@ function relayStatus() {
5223
6149
  }
5224
6150
  var PID_FILE2;
5225
6151
  var init_pid2 = __esm(() => {
5226
- PID_FILE2 = join10(homedir14(), ".failproofai", "relay.pid");
6152
+ PID_FILE2 = join15(homedir16(), ".failproofai", "relay.pid");
5227
6153
  });
5228
6154
 
5229
- // lib/paths.ts
5230
- import { homedir as homedir15 } from "os";
5231
- import { join as join11 } from "path";
5232
- function getDefaultClaudeProjectsPath() {
5233
- return join11(homedir15(), ".claude", "projects");
5234
- }
5235
- var init_paths = () => {};
5236
-
5237
6155
  // scripts/parse-script-args.ts
5238
- import { resolve as resolve7 } from "path";
6156
+ import { resolve as resolve8 } from "path";
5239
6157
  function parseStringFlag(flagName, errorLabel, inlineValue, args, index, options) {
5240
6158
  const raw = inlineValue ?? args[index + 1];
5241
6159
  if (raw === undefined || inlineValue === null && raw.startsWith("-")) {
5242
6160
  console.error(`Error: ${flagName} requires ${errorLabel}`);
5243
6161
  process.exit(1);
5244
6162
  }
5245
- const value = options?.resolve ? resolve7(raw) : raw;
6163
+ const value = options?.resolve ? resolve8(raw) : raw;
5246
6164
  return { value, spliceCount: inlineValue !== null ? 1 : 2 };
5247
6165
  }
5248
6166
  function parseScriptArgs(argv) {
@@ -5304,7 +6222,7 @@ __export(exports_launch, {
5304
6222
  });
5305
6223
  import { spawn as spawn4 } from "child_process";
5306
6224
  import { realpathSync, existsSync as existsSync14 } from "node:fs";
5307
- import { resolve as resolve8, dirname as dirname7 } from "node:path";
6225
+ import { resolve as resolve9, dirname as dirname7 } from "node:path";
5308
6226
  import { fileURLToPath } from "node:url";
5309
6227
  function launch(mode) {
5310
6228
  const { claudeProjectsPath: parsedPath, loggingLevel, disableTelemetry, allowedDevOrigins, remainingArgs } = parseScriptArgs(process.argv.slice(2));
@@ -5317,7 +6235,8 @@ function launch(mode) {
5317
6235
  /_/ v${version2}
5318
6236
  `);
5319
6237
  console.log(` ⭐ Star us: https://github.com/exospherehost/failproofai`);
5320
- console.log(` \uD83D\uDCD6 Docs: https://befailproof.ai
6238
+ console.log(` \uD83D\uDCD6 Docs: https://befailproof.ai`);
6239
+ console.log(` \uD83D\uDCAC Slack: https://join.slack.com/t/failproofai/shared_invite/zt-3v63b7k5e-O3NBHmj8X6n9gZSGDx6ggQ
5321
6240
  `);
5322
6241
  let claudeProjectsPath = parsedPath;
5323
6242
  if (!claudeProjectsPath) {
@@ -5335,8 +6254,8 @@ function launch(mode) {
5335
6254
  process.env.PORT = port;
5336
6255
  process.env.HOSTNAME = "0.0.0.0";
5337
6256
  cmd = "node";
5338
- const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve8(dirname7(realpathSync(fileURLToPath(import.meta.url))), "..");
5339
- const serverJsPath = resolve8(packageRoot, ".next/standalone/server.js");
6257
+ const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve9(dirname7(realpathSync(fileURLToPath(import.meta.url))), "..");
6258
+ const serverJsPath = resolve9(packageRoot, ".next/standalone/server.js");
5340
6259
  if (!existsSync14(serverJsPath)) {
5341
6260
  console.error(`
5342
6261
  Error: Cannot find server.js at:
@@ -5396,17 +6315,17 @@ var init_cli_error2 = __esm(() => {
5396
6315
 
5397
6316
  // bin/failproofai.mjs
5398
6317
  import { realpathSync as realpathSync2 } from "fs";
5399
- import { dirname as dirname8, resolve as resolve9 } from "path";
6318
+ import { dirname as dirname8, resolve as resolve10 } from "path";
5400
6319
  import { fileURLToPath as fileURLToPath2 } from "url";
5401
6320
  // package.json
5402
- var version = "0.0.9-beta.1";
6321
+ var version = "0.0.9";
5403
6322
 
5404
6323
  // bin/failproofai.mjs
5405
6324
  if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
5406
- process.env.FAILPROOFAI_PACKAGE_ROOT = resolve9(dirname8(realpathSync2(fileURLToPath2(import.meta.url))), "..");
6325
+ process.env.FAILPROOFAI_PACKAGE_ROOT = resolve10(dirname8(realpathSync2(fileURLToPath2(import.meta.url))), "..");
5407
6326
  }
5408
6327
  if (!process.env.FAILPROOFAI_DIST_PATH) {
5409
- process.env.FAILPROOFAI_DIST_PATH = resolve9(dirname8(realpathSync2(fileURLToPath2(import.meta.url))), "..", "dist");
6328
+ process.env.FAILPROOFAI_DIST_PATH = resolve10(dirname8(realpathSync2(fileURLToPath2(import.meta.url))), "..", "dist");
5410
6329
  }
5411
6330
  var args = process.argv.slice(2);
5412
6331
  if (args[0] === "p")
@@ -5509,6 +6428,7 @@ EXAMPLES
5509
6428
  LINKS
5510
6429
  \u2B50 Star us: https://github.com/exospherehost/failproofai
5511
6430
  \uD83D\uDCD6 Docs: https://befailproof.ai
6431
+ \uD83D\uDCAC Slack: https://join.slack.com/t/failproofai/shared_invite/zt-3v63b7k5e-O3NBHmj8X6n9gZSGDx6ggQ
5512
6432
  `.trimStart());
5513
6433
  process.exit(0);
5514
6434
  }