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.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +6 -6
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +2 -2
- package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -2
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/policies/page.js +2 -2
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +4 -3
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +2 -2
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g72weg._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0su~k6f._.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_codex-projects_ts_07qqk1g._.js +3 -0
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01743wx._.js +3 -0
- 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
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__092s1ta._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09icjsf._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0dub28-._.js → [root-of-the-server]__0_b7pgn._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g.lg8b._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0gs6wz4._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h..k-e._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0it81ys._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u4a9jq._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ymlddl._.js +18 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11pa2ra._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12.h2mg._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12t-wym._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_04w00cm._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_10lm7or._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_0cdqd9w._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/lib_codex-projects_ts_0eosib~._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/lib_utils_ts_068jk73._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{_0zaq1hm._.js → node_modules_0ttbz1~._.js} +2 -2
- package/.next/standalone/.next/server/middleware-build-manifest.js +6 -6
- package/.next/standalone/.next/server/pages/404.html +2 -2
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +9 -9
- package/.next/standalone/.next/static/chunks/{0_c_yox08g_44.js → 01q52wg_amm60.js} +2 -2
- package/.next/standalone/.next/static/chunks/06x4-d1~o-opr.js +1 -0
- package/.next/standalone/.next/static/chunks/{0bghqwo4iloy0.js → 0756i.7omnnl6.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0p5zh2diw90a1.js → 095l4hc7-h.~~.js} +1 -1
- package/.next/standalone/.next/static/chunks/09ose_165ra4d.js +1 -0
- package/.next/standalone/.next/static/chunks/0n-_j_6fo6jex.js +6 -0
- package/.next/standalone/.next/static/chunks/0n~s0gafwnp2y.js +1 -0
- package/.next/standalone/.next/static/chunks/{0ufq8smh~i7wc.js → 0pr7k36o_.du1.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0z-jh701rc~j8.js → 0t~iusm_fxoao.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0jryicwtm9z2g.js → 0u-ys71jc4y68.js} +3 -3
- package/.next/standalone/.next/static/chunks/0zig0fh30t6ou.js +1 -0
- package/.next/standalone/.next/static/chunks/{0w1f.k~gi-y6..js → 11kt_9zaooda3.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0kzk5-mh1_x53.js → 12simlrcfk3g2.js} +1 -1
- package/.next/standalone/.next/static/chunks/{turbopack-0s36is87fc9r2.js → turbopack-0o7k.hakttp4k.js} +1 -1
- package/.next/standalone/app/components/cli-badge.tsx +24 -0
- package/.next/standalone/app/components/project-list.tsx +13 -7
- package/.next/standalone/app/components/sessions-list.tsx +4 -2
- package/.next/standalone/app/policies/hooks-client.tsx +66 -10
- package/.next/standalone/app/project/[name]/page.tsx +49 -22
- package/.next/standalone/app/project/[name]/session/[sessionId]/page.tsx +51 -19
- package/.next/standalone/components/reach-developers.tsx +6 -1
- package/.next/standalone/lib/codex-projects.ts +250 -0
- package/.next/standalone/lib/codex-sessions.ts +414 -0
- package/.next/standalone/lib/format-date.ts +21 -0
- package/.next/standalone/lib/log-entries.ts +3 -3
- package/.next/standalone/lib/paths.ts +13 -0
- package/.next/standalone/lib/projects.ts +57 -3
- package/.next/standalone/lib/utils.ts +6 -22
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +1 -0
- package/dist/cli.mjs +1042 -122
- package/lib/codex-projects.ts +250 -0
- package/lib/codex-sessions.ts +414 -0
- package/lib/format-date.ts +21 -0
- package/lib/log-entries.ts +3 -3
- package/lib/paths.ts +13 -0
- package/lib/projects.ts +57 -3
- package/lib/utils.ts +6 -22
- package/package.json +1 -1
- package/scripts/launch.ts +2 -1
- package/src/hooks/builtin-policies.ts +7 -1
- package/src/hooks/hook-activity-store.ts +3 -0
- package/src/hooks/manager.ts +1 -1
- package/src/hooks/resolve-permission-mode.ts +6 -91
- package/.next/standalone/.next/server/chunks/[externals]__080wern._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0b57.gk._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__03rd.z8._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e74wa-._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0vu.o-3._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0w6l33k._.js +0 -17
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0zqcovi._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__105.l_7._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0uy6m~m._.js +0 -3
- package/.next/standalone/.next/static/chunks/00b5h4r1el.6f.js +0 -1
- package/.next/standalone/.next/static/chunks/0fw2h.g66c0h3.js +0 -1
- package/.next/standalone/.next/static/chunks/0gu87mlr5ssnt.js +0 -6
- package/.next/standalone/.next/static/chunks/0igf3xbisp1lx.js +0 -1
- package/.next/standalone/.next/static/chunks/0vwqucikost_q.js +0 -1
- /package/.next/standalone/.next/static/{CiVeb_yiVt-O2JYrzGzB7 → A_Ax17P33facL0OmIwFXj}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{CiVeb_yiVt-O2JYrzGzB7 → A_Ax17P33facL0OmIwFXj}/_clientMiddlewareManifest.js +0 -0
- /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_
|
|
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
|
|
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
|
-
//
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
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
|
-
|
|
2440
|
-
|
|
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
|
|
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
|
|
3167
|
+
return join9(dir, f.name);
|
|
2466
3168
|
}
|
|
2467
3169
|
}
|
|
2468
3170
|
} catch {}
|
|
2469
3171
|
return null;
|
|
2470
3172
|
}
|
|
2471
|
-
function
|
|
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 =
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
3441
|
+
const path = findCodexTranscript(sessionId);
|
|
2516
3442
|
if (!path)
|
|
2517
3443
|
return;
|
|
2518
|
-
for (const line of
|
|
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
|
-
|
|
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
|
|
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
|
|
2636
|
-
import { homedir as
|
|
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 =
|
|
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 =
|
|
2672
|
-
AUTH_FILE =
|
|
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
|
|
2690
|
-
statSync as
|
|
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
|
|
2697
|
-
import { homedir as
|
|
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) &&
|
|
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
|
|
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 =
|
|
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 =
|
|
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) =>
|
|
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 =
|
|
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 =
|
|
2812
|
-
PENDING_FILE =
|
|
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
|
|
2818
|
-
import { join as
|
|
2819
|
-
import { homedir as
|
|
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 =
|
|
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 =
|
|
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
|
|
2886
|
-
import { homedir as
|
|
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
|
|
3891
|
+
const resolve6 = this.pendingAcks.get(msg.ack);
|
|
2967
3892
|
this.pendingAcks.delete(msg.ack);
|
|
2968
|
-
|
|
3893
|
+
resolve6(true);
|
|
2969
3894
|
}
|
|
2970
3895
|
} catch {}
|
|
2971
3896
|
}
|
|
2972
3897
|
handleClose() {
|
|
2973
3898
|
this.closed = true;
|
|
2974
|
-
for (const [,
|
|
2975
|
-
|
|
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((
|
|
2992
|
-
this.pendingAcks.set(batchId,
|
|
3916
|
+
const ackPromise = new Promise((resolve6) => {
|
|
3917
|
+
this.pendingAcks.set(batchId, resolve6);
|
|
2993
3918
|
setTimeout(() => {
|
|
2994
3919
|
if (this.pendingAcks.delete(batchId))
|
|
2995
|
-
|
|
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((
|
|
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
|
-
|
|
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 =
|
|
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((
|
|
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
|
-
|
|
4108
|
+
resolve6("");
|
|
3184
4109
|
return;
|
|
3185
4110
|
}
|
|
3186
4111
|
chunks.push(chunk);
|
|
3187
4112
|
});
|
|
3188
|
-
process.stdin.on("end", () =>
|
|
4113
|
+
process.stdin.on("end", () => resolve6(chunks.join("")));
|
|
3189
4114
|
process.stdin.on("error", reject);
|
|
3190
4115
|
if (process.stdin.readableEnded)
|
|
3191
|
-
|
|
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
|
|
3354
|
-
import { homedir as
|
|
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
|
|
4359
|
+
const resolve6 = this.pendingAcks.get(msg.ack);
|
|
3435
4360
|
this.pendingAcks.delete(msg.ack);
|
|
3436
|
-
|
|
4361
|
+
resolve6(true);
|
|
3437
4362
|
}
|
|
3438
4363
|
} catch {}
|
|
3439
4364
|
}
|
|
3440
4365
|
handleClose() {
|
|
3441
4366
|
this.closed = true;
|
|
3442
|
-
for (const [,
|
|
3443
|
-
|
|
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((
|
|
3460
|
-
this.pendingAcks.set(batchId,
|
|
4384
|
+
const ackPromise = new Promise((resolve6) => {
|
|
4385
|
+
this.pendingAcks.set(batchId, resolve6);
|
|
3461
4386
|
setTimeout(() => {
|
|
3462
4387
|
if (this.pendingAcks.delete(batchId))
|
|
3463
|
-
|
|
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((
|
|
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
|
-
|
|
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 =
|
|
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
|
|
3627
|
-
import { resolve as
|
|
3628
|
-
import { homedir as
|
|
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 =
|
|
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 ?
|
|
4599
|
+
const base = cwd ? resolve6(cwd) : process.cwd();
|
|
3675
4600
|
switch (scope) {
|
|
3676
4601
|
case "user":
|
|
3677
|
-
return
|
|
4602
|
+
return resolve6(homedir14(), ".claude", "settings.json");
|
|
3678
4603
|
case "project":
|
|
3679
|
-
return
|
|
4604
|
+
return resolve6(base, ".claude", "settings.json");
|
|
3680
4605
|
case "local":
|
|
3681
|
-
return
|
|
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 ?
|
|
4707
|
+
const base = cwd ? resolve6(cwd) : process.cwd();
|
|
3783
4708
|
switch (scope) {
|
|
3784
4709
|
case "user":
|
|
3785
|
-
return
|
|
4710
|
+
return resolve6(homedir14(), ".codex", "hooks.json");
|
|
3786
4711
|
case "project":
|
|
3787
|
-
return
|
|
4712
|
+
return resolve6(base, ".codex", "hooks.json");
|
|
3788
4713
|
case "local":
|
|
3789
|
-
return
|
|
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((
|
|
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
|
-
|
|
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
|
|
4178
|
-
import { homedir as
|
|
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 =
|
|
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 ?
|
|
5518
|
+
const base = cwd ? resolve7(cwd) : process.cwd();
|
|
4593
5519
|
const conventionDirs = [
|
|
4594
|
-
{ label: "Project", dir:
|
|
4595
|
-
{ label: "User", dir:
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
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
|
|
5166
|
-
import { join as
|
|
5167
|
-
import { homedir as
|
|
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 =
|
|
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 =
|
|
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
|
|
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 ?
|
|
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
|
|
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 ??
|
|
5339
|
-
const serverJsPath =
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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
|
}
|