failproofai 1.0.4-beta.2 → 1.0.4-beta.6
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 +3 -3
- 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/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js +2 -2
- 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 +6 -6
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- 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 +2 -2
- 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 +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +5 -5
- package/.next/standalone/.next/server/app/audit/page.js +3 -3
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +2 -2
- 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/server-reference-manifest.json +14 -14
- package/.next/standalone/.next/server/app/policies/page.js +4 -4
- 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/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js +3 -3
- 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/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 -4
- 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/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +3 -3
- 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/app/settings/page/server-reference-manifest.json +4 -4
- package/.next/standalone/.next/server/app/settings/page.js +2 -2
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__1lh7m5d._.js → [externals]__0v1hz15._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__1rqkg_y._.js → [externals]__1nb206a._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rv7m0k._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1legmza._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1p-qi2t._.js +1 -1
- package/.next/standalone/.next/server/chunks/{_08w6xzm._.js → _0otft92._.js} +2 -2
- package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1ek68ln._.js +4 -4
- package/.next/standalone/.next/server/chunks/_1vslkoe._.js +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0p-5p8u._.js → [root-of-the-server]__0-4ja6q._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1p2otjt._.js → [root-of-the-server]__00cr3xu._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__013jr2b._.js → [root-of-the-server]__04px77e._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__190won8._.js → [root-of-the-server]__0dxf928._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0s740oi._.js → [root-of-the-server]__0egr5s1._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__01wy8d-._.js → [root-of-the-server]__0i0l1di._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0n_lxhg._.js → [root-of-the-server]__0kokc8z._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1ctpynv._.js → [root-of-the-server]__0n2txhk._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__02npjtd._.js → [root-of-the-server]__0r3c1_0._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ftmoxc._.js → [root-of-the-server]__17xnxlx._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0da85px._.js → [root-of-the-server]__1ckpmkk._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__00-s7h8._.js → [root-of-the-server]__1fvfw59._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ui5ur8._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_02b3i98._.js +23 -0
- package/.next/standalone/.next/server/chunks/ssr/{_0oq1dh6._.js → _04ng_6x._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_1u8-lu2._.js → _07t3jol._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0h_douw._.js → _0s-77v5._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1_ozgif._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1ddpc5g._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1es2j7i._.js +4 -1
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/pages/404.html +1 -1
- 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 +22 -22
- package/.next/standalone/.next/static/chunks/{1pb1oztsbwcss.js → 07c6l1lq5_69b.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0o-hh5_turzlz.css → 0jpd8dv2vk930.css} +1 -1
- package/.next/standalone/.next/static/chunks/{32spub4wqjem-.js → 12bsgz8czvcnn.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3m4upvybtrexd.js → 1gn08w2pgqh09.js} +1 -1
- package/.next/standalone/.next/static/chunks/{010bv1w6j171t.js → 1xgq22tri86an.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2aquitk72k2op.js → 20xkiqzvfkuvm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2bi_1y0a_smt7.js → 2a84ug32tzik2.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2ej3b8gk5ittu.js → 32m2ryfankf_2.js} +1 -1
- package/.next/standalone/.next/static/chunks/3ioub_lpen-sq.js +1 -0
- package/.next/standalone/.next/static/chunks/{0wz8yftk18ts2.js → 3jxd133cw2vm3.js} +1 -1
- package/.next/standalone/.next/static/chunks/44ncu88eq6z71.js +1 -0
- package/.next/standalone/app/actions/get-leaks.ts +5 -1
- package/.next/standalone/app/actions/update-scheduled-audit.ts +4 -56
- package/.next/standalone/app/api/auth/status/route.ts +3 -2
- package/.next/standalone/app/audit/_components/audit-dashboard.tsx +29 -2
- package/.next/standalone/app/audit/_components/leak-section.tsx +15 -2
- package/.next/standalone/app/audit/audit-styles.css +18 -0
- package/.next/standalone/app/settings/page.tsx +1 -1
- package/.next/standalone/app/settings/settings-client.tsx +13 -39
- package/.next/standalone/lib/auth/api-server-client.ts +6 -6
- package/.next/standalone/lib/codex-sessions.ts +20 -4
- package/.next/standalone/lib/copilot-sessions.ts +32 -1
- package/.next/standalone/lib/cursor-sessions.ts +62 -5
- package/.next/standalone/lib/sqlite-reader.ts +78 -1
- package/.next/standalone/package.json +10 -10
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +1 -1
- package/dist/cli.mjs +1191 -1130
- package/dist/worker.mjs +198 -359
- package/lib/auth/api-server-client.ts +6 -6
- package/lib/codex-sessions.ts +20 -4
- package/lib/copilot-sessions.ts +32 -1
- package/lib/cursor-sessions.ts +62 -5
- package/lib/sqlite-reader.ts +78 -1
- package/package.json +10 -10
- package/pi-extension/index.ts +11 -4
- package/src/audit/cache.ts +6 -0
- package/src/audit/cli-adapters/claude.ts +13 -0
- package/src/audit/cli-login.ts +4 -1
- package/src/audit/cli.ts +67 -51
- package/src/audit/harm-report.ts +12 -6
- package/src/audit/index.ts +151 -8
- package/src/audit/leak-fingerprint.ts +2 -4
- package/src/audit/leak-record.ts +13 -9
- package/src/audit/leak-scan.ts +20 -44
- package/src/audit/leak-store.ts +5 -2
- package/src/audit/machine-store.ts +8 -9
- package/src/audit/macos-notifier.ts +2 -2
- package/src/audit/redact-example.ts +62 -5
- package/src/audit/report-harm.ts +31 -46
- package/src/audit/schedule-cli.ts +17 -33
- package/src/audit/types.ts +11 -0
- package/src/hooks/configure-wizard.ts +28 -0
- package/src/hooks/fp-config.ts +29 -54
- package/src/hooks/handler.ts +1 -59
- package/src/hooks/integrations.ts +4 -1
- package/src/hooks/notice.ts +23 -154
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rgu2r3._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_0-oij9d._.js +0 -23
- package/.next/standalone/.next/static/chunks/04r6ch8uf_n8m.js +0 -1
- package/.next/standalone/.next/static/chunks/0zebh1n9jkfbt.js +0 -1
- package/src/audit/leak-notice.ts +0 -161
- /package/.next/standalone/.next/static/{aKNv4Kmv98Xpwns0Xa-C- → aeM365dNTtUZOZvNkX8ba}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{aKNv4Kmv98Xpwns0Xa-C- → aeM365dNTtUZOZvNkX8ba}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{aKNv4Kmv98Xpwns0Xa-C- → aeM365dNTtUZOZvNkX8ba}/_ssgManifest.js +0 -0
package/dist/cli.mjs
CHANGED
|
@@ -29,7 +29,7 @@ var __esm = (fn, res, err) => () => {
|
|
|
29
29
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
30
30
|
|
|
31
31
|
// package.json
|
|
32
|
-
var version2 = "1.0.4-beta.
|
|
32
|
+
var version2 = "1.0.4-beta.6", package_default;
|
|
33
33
|
var init_package = __esm(() => {
|
|
34
34
|
package_default = {
|
|
35
35
|
name: "failproofai",
|
|
@@ -150,20 +150,20 @@ var init_package = __esm(() => {
|
|
|
150
150
|
vite: "8.0.16",
|
|
151
151
|
undici: "7.29.0",
|
|
152
152
|
"brace-expansion": "5.0.9",
|
|
153
|
-
sharp: "0.35.
|
|
153
|
+
sharp: "0.35.4",
|
|
154
154
|
browserslist: "4.28.8"
|
|
155
155
|
},
|
|
156
156
|
optionalDependencies: {
|
|
157
|
-
"@failproofai/failproofaid-linux-x64": "1.0.4-beta.
|
|
158
|
-
"@failproofai/failproofaid-linux-arm64": "1.0.4-beta.
|
|
159
|
-
"@failproofai/failproofaid-darwin-x64": "1.0.4-beta.
|
|
160
|
-
"@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.
|
|
157
|
+
"@failproofai/failproofaid-linux-x64": "1.0.4-beta.6",
|
|
158
|
+
"@failproofai/failproofaid-linux-arm64": "1.0.4-beta.6",
|
|
159
|
+
"@failproofai/failproofaid-darwin-x64": "1.0.4-beta.6",
|
|
160
|
+
"@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.6"
|
|
161
161
|
},
|
|
162
162
|
failproofaidBinaries: {
|
|
163
|
-
"linux-x64": "
|
|
164
|
-
"linux-arm64": "
|
|
165
|
-
"darwin-x64": "
|
|
166
|
-
"darwin-arm64": "
|
|
163
|
+
"linux-x64": "24118b8bd058cc5d8711053c4c77cdca9361c12dbf0f421a757d33f07596d428",
|
|
164
|
+
"linux-arm64": "b4278c34a288de2c747bcebcc623d8fd5bda3a1f1e55800926eb1a4b89f0a5e9",
|
|
165
|
+
"darwin-x64": "ecb66699f45f605b0d54ac9e4bac360ac11e4e136442dcccdd083514d77c7d42",
|
|
166
|
+
"darwin-arm64": "b3dbad58bda960ef9481f90bc5085ba8624b2472519cc0bf212a0e8451dd2db4"
|
|
167
167
|
}
|
|
168
168
|
};
|
|
169
169
|
});
|
|
@@ -11865,7 +11865,10 @@ export default async function failproofaiPlugin({ client, directory }) {
|
|
|
11865
11865
|
const claudeEvent = BUS_EVENT_MAP[event.type];
|
|
11866
11866
|
if (!claudeEvent) return;
|
|
11867
11867
|
const props = event.properties || {};
|
|
11868
|
-
const
|
|
11868
|
+
const info = props.info || props.session || {};
|
|
11869
|
+
|
|
11870
|
+
const sessionID = info.id || info.sessionID || info.sessionId || info.session_id ||
|
|
11871
|
+
props.sessionID || props.sessionId || props.session_id || props.id;
|
|
11869
11872
|
const r = await runFailproofai(claudeEvent, {
|
|
11870
11873
|
session_id: sessionID, cwd: directory, hook_event_name: claudeEvent,
|
|
11871
11874
|
}, directory);
|
|
@@ -16480,374 +16483,6 @@ var init_delivery_health = __esm(() => {
|
|
|
16480
16483
|
};
|
|
16481
16484
|
});
|
|
16482
16485
|
|
|
16483
|
-
// src/hooks/notice.ts
|
|
16484
|
-
function shapeNotice(cli, notice, existingStdout = "") {
|
|
16485
|
-
const empty = { stdout: existingStdout, stderr: "" };
|
|
16486
|
-
if (!notice.trim() || !cli)
|
|
16487
|
-
return empty;
|
|
16488
|
-
const channel = NOTICE_CHANNEL[cli] ?? "none";
|
|
16489
|
-
const text = notice.length > MAX_NOTICE_CHARS ? notice.slice(0, MAX_NOTICE_CHARS - 1) + "…" : notice;
|
|
16490
|
-
switch (channel) {
|
|
16491
|
-
case "systemMessage": {
|
|
16492
|
-
if (existingStdout.trim().startsWith("{")) {
|
|
16493
|
-
try {
|
|
16494
|
-
const parsed = JSON.parse(existingStdout);
|
|
16495
|
-
parsed.systemMessage = text;
|
|
16496
|
-
return { stdout: JSON.stringify(parsed), stderr: "" };
|
|
16497
|
-
} catch {
|
|
16498
|
-
return empty;
|
|
16499
|
-
}
|
|
16500
|
-
}
|
|
16501
|
-
if (existingStdout.trim())
|
|
16502
|
-
return empty;
|
|
16503
|
-
return { stdout: JSON.stringify({ systemMessage: text }), stderr: "" };
|
|
16504
|
-
}
|
|
16505
|
-
case "stderr":
|
|
16506
|
-
return { stdout: existingStdout, stderr: text + `
|
|
16507
|
-
` };
|
|
16508
|
-
case "stdout":
|
|
16509
|
-
if (existingStdout.trim())
|
|
16510
|
-
return empty;
|
|
16511
|
-
return { stdout: text + `
|
|
16512
|
-
`, stderr: "" };
|
|
16513
|
-
default:
|
|
16514
|
-
return empty;
|
|
16515
|
-
}
|
|
16516
|
-
}
|
|
16517
|
-
function canDeliverNotice(cli) {
|
|
16518
|
-
return !!cli && (NOTICE_CHANNEL[cli] ?? "none") !== "none";
|
|
16519
|
-
}
|
|
16520
|
-
function leakNoticeText(newFindings) {
|
|
16521
|
-
const n = newFindings === 1 ? "a credential" : `${newFindings} credentials`;
|
|
16522
|
-
return `failproofai found ${n} in this project's agent transcripts.
|
|
16523
|
-
` + "Run `failproofai audit` to see the details, " + "or `failproofai audit --schedule` to get these by email.";
|
|
16524
|
-
}
|
|
16525
|
-
var NOTICE_CHANNEL, MAX_NOTICE_CHARS = 900;
|
|
16526
|
-
var init_notice = __esm(() => {
|
|
16527
|
-
NOTICE_CHANNEL = {
|
|
16528
|
-
claude: "systemMessage",
|
|
16529
|
-
codex: "systemMessage",
|
|
16530
|
-
copilot: "stderr",
|
|
16531
|
-
factory: "stdout"
|
|
16532
|
-
};
|
|
16533
|
-
});
|
|
16534
|
-
|
|
16535
|
-
// lib/atomic-write.ts
|
|
16536
|
-
import {
|
|
16537
|
-
chmodSync as chmodSync2,
|
|
16538
|
-
existsSync as existsSync11,
|
|
16539
|
-
mkdirSync as mkdirSync7,
|
|
16540
|
-
renameSync as renameSync4,
|
|
16541
|
-
rmSync as rmSync3,
|
|
16542
|
-
statSync as statSync7,
|
|
16543
|
-
writeFileSync as writeFileSync6
|
|
16544
|
-
} from "node:fs";
|
|
16545
|
-
import { dirname as dirname7 } from "node:path";
|
|
16546
|
-
import { randomBytes } from "node:crypto";
|
|
16547
|
-
function writeJsonAtomically(filePath, value, opts = {}) {
|
|
16548
|
-
const mode = opts.mode ?? 384;
|
|
16549
|
-
const dirMode = opts.dirMode ?? 448;
|
|
16550
|
-
const dir = dirname7(filePath);
|
|
16551
|
-
if (!existsSync11(dir))
|
|
16552
|
-
mkdirSync7(dir, { recursive: true, mode: dirMode });
|
|
16553
|
-
const tmp = `${filePath}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
|
|
16554
|
-
try {
|
|
16555
|
-
writeFileSync6(tmp, JSON.stringify(value, null, 2), { mode });
|
|
16556
|
-
try {
|
|
16557
|
-
if ((statSync7(tmp).mode & 63) !== 0)
|
|
16558
|
-
chmodSync2(tmp, mode);
|
|
16559
|
-
} catch {}
|
|
16560
|
-
renameSync4(tmp, filePath);
|
|
16561
|
-
try {
|
|
16562
|
-
if ((statSync7(filePath).mode & 63) !== 0)
|
|
16563
|
-
chmodSync2(filePath, mode);
|
|
16564
|
-
} catch {}
|
|
16565
|
-
} catch (err) {
|
|
16566
|
-
try {
|
|
16567
|
-
rmSync3(tmp, { force: true });
|
|
16568
|
-
} catch {}
|
|
16569
|
-
throw err;
|
|
16570
|
-
}
|
|
16571
|
-
}
|
|
16572
|
-
var init_atomic_write = () => {};
|
|
16573
|
-
|
|
16574
|
-
// src/audit/leak-record.ts
|
|
16575
|
-
function upsertFinding(record, incoming) {
|
|
16576
|
-
const { sighting, ...rest } = incoming;
|
|
16577
|
-
const existing = record.findings.find((f) => f.id === rest.id);
|
|
16578
|
-
if (!existing) {
|
|
16579
|
-
record.findings.push({
|
|
16580
|
-
...rest,
|
|
16581
|
-
firstSeen: sighting.at,
|
|
16582
|
-
lastSeen: sighting.at,
|
|
16583
|
-
occurrences: 1,
|
|
16584
|
-
sightings: [sighting]
|
|
16585
|
-
});
|
|
16586
|
-
return { record, isNew: true };
|
|
16587
|
-
}
|
|
16588
|
-
existing.occurrences += 1;
|
|
16589
|
-
if (sighting.at > existing.lastSeen)
|
|
16590
|
-
existing.lastSeen = sighting.at;
|
|
16591
|
-
if (sighting.at < existing.firstSeen)
|
|
16592
|
-
existing.firstSeen = sighting.at;
|
|
16593
|
-
if (existing.sightings.length < MAX_SIGHTINGS) {
|
|
16594
|
-
const seen = existing.sightings.some((s) => s.sessionId === sighting.sessionId && s.at === sighting.at);
|
|
16595
|
-
if (!seen)
|
|
16596
|
-
existing.sightings.push(sighting);
|
|
16597
|
-
}
|
|
16598
|
-
return { record, isNew: false };
|
|
16599
|
-
}
|
|
16600
|
-
function pruneRecord(record, nowMs) {
|
|
16601
|
-
const cutoff = new Date(nowMs - FINDING_TTL_DAYS * 86400000).toISOString();
|
|
16602
|
-
const live = record.findings.filter((f) => f.lastSeen >= cutoff);
|
|
16603
|
-
live.sort((a, b) => a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0);
|
|
16604
|
-
record.findings = live.slice(0, MAX_FINDINGS);
|
|
16605
|
-
return record;
|
|
16606
|
-
}
|
|
16607
|
-
function emptyRecord(salt, nowIso) {
|
|
16608
|
-
return {
|
|
16609
|
-
schemaVersion: LEAK_RECORD_SCHEMA_VERSION,
|
|
16610
|
-
salt,
|
|
16611
|
-
updatedAt: nowIso,
|
|
16612
|
-
findings: []
|
|
16613
|
-
};
|
|
16614
|
-
}
|
|
16615
|
-
function describeMechanism(toolName, direction, shortPath) {
|
|
16616
|
-
const where = shortPath ? ` ${shortPath}` : "";
|
|
16617
|
-
let summary;
|
|
16618
|
-
if (direction === "result") {
|
|
16619
|
-
summary = shortPath ? `appeared in the output of reading${where}` : "appeared in tool output";
|
|
16620
|
-
} else {
|
|
16621
|
-
switch (toolName) {
|
|
16622
|
-
case "Read":
|
|
16623
|
-
summary = `read from${where || " a file"}`;
|
|
16624
|
-
break;
|
|
16625
|
-
case "Write":
|
|
16626
|
-
summary = `written to${where || " a file"}`;
|
|
16627
|
-
break;
|
|
16628
|
-
case "Edit":
|
|
16629
|
-
case "NotebookEdit":
|
|
16630
|
-
summary = `edited into${where || " a file"}`;
|
|
16631
|
-
break;
|
|
16632
|
-
case "Bash":
|
|
16633
|
-
summary = "passed in a shell command";
|
|
16634
|
-
break;
|
|
16635
|
-
default:
|
|
16636
|
-
summary = `sent to the ${toolName} tool`;
|
|
16637
|
-
}
|
|
16638
|
-
}
|
|
16639
|
-
return { summary, toolName, direction };
|
|
16640
|
-
}
|
|
16641
|
-
var MAX_SIGHTINGS = 5, FINDING_TTL_DAYS = 90, MAX_FINDINGS = 500, LEAK_RECORD_SCHEMA_VERSION = 1;
|
|
16642
|
-
|
|
16643
|
-
// src/audit/leak-fingerprint.ts
|
|
16644
|
-
function matchPublicPrefix(value) {
|
|
16645
|
-
for (const entry of PUBLIC_PREFIXES) {
|
|
16646
|
-
if (value.startsWith(entry[0]))
|
|
16647
|
-
return entry;
|
|
16648
|
-
}
|
|
16649
|
-
return null;
|
|
16650
|
-
}
|
|
16651
|
-
function fingerprintSecret(value, fallbackLabel = "secret") {
|
|
16652
|
-
const length = value.length;
|
|
16653
|
-
const matched = matchPublicPrefix(value);
|
|
16654
|
-
if (!matched) {
|
|
16655
|
-
return {
|
|
16656
|
-
display: `[${length}-char ${fallbackLabel}]`,
|
|
16657
|
-
label: fallbackLabel,
|
|
16658
|
-
length,
|
|
16659
|
-
attributed: false
|
|
16660
|
-
};
|
|
16661
|
-
}
|
|
16662
|
-
const [prefix, label] = matched;
|
|
16663
|
-
const bodyLength = length - prefix.length;
|
|
16664
|
-
const run = MASK_CHAR.repeat(Math.max(1, Math.min(MAX_MASK_RUN, bodyLength)));
|
|
16665
|
-
if (length >= MIN_LEN_FOR_TAIL && bodyLength > TAIL_CHARS * 2) {
|
|
16666
|
-
return {
|
|
16667
|
-
display: `${prefix}${run}${value.slice(-TAIL_CHARS)}`,
|
|
16668
|
-
label,
|
|
16669
|
-
length,
|
|
16670
|
-
attributed: true
|
|
16671
|
-
};
|
|
16672
|
-
}
|
|
16673
|
-
return { display: `${prefix}${run}`, label, length, attributed: true };
|
|
16674
|
-
}
|
|
16675
|
-
function isFindingId(id) {
|
|
16676
|
-
return /^[0-9a-f]{16}$/.test(id);
|
|
16677
|
-
}
|
|
16678
|
-
function fingerprintId(value, machineSalt) {
|
|
16679
|
-
const { createHmac } = __require("node:crypto");
|
|
16680
|
-
return createHmac("sha256", machineSalt).update(value).digest("hex").slice(0, 16);
|
|
16681
|
-
}
|
|
16682
|
-
var MASK_CHAR = "•", MAX_MASK_RUN = 8, MIN_LEN_FOR_TAIL = 24, TAIL_CHARS = 4, PUBLIC_PREFIXES;
|
|
16683
|
-
var init_leak_fingerprint = __esm(() => {
|
|
16684
|
-
PUBLIC_PREFIXES = [
|
|
16685
|
-
["sk-ant-api03-", "Anthropic API key"],
|
|
16686
|
-
["sk-ant-oat01-", "Anthropic OAuth token"],
|
|
16687
|
-
["sk-ant-", "Anthropic key"],
|
|
16688
|
-
["sk-proj-", "OpenAI project key"],
|
|
16689
|
-
["sk-svcacct-", "OpenAI service-account key"],
|
|
16690
|
-
["sk-admin-", "OpenAI admin key"],
|
|
16691
|
-
["sk-or-v1-", "OpenRouter key"],
|
|
16692
|
-
["github_pat_", "GitHub fine-grained token"],
|
|
16693
|
-
["ghp_", "GitHub personal access token"],
|
|
16694
|
-
["gho_", "GitHub OAuth token"],
|
|
16695
|
-
["ghu_", "GitHub user-to-server token"],
|
|
16696
|
-
["ghs_", "GitHub server-to-server token"],
|
|
16697
|
-
["ghr_", "GitHub refresh token"],
|
|
16698
|
-
["glpat-", "GitLab personal access token"],
|
|
16699
|
-
["xoxb-", "Slack bot token"],
|
|
16700
|
-
["xoxp-", "Slack user token"],
|
|
16701
|
-
["xapp-", "Slack app-level token"],
|
|
16702
|
-
["sk_live_", "Stripe live secret key"],
|
|
16703
|
-
["sk_test_", "Stripe test secret key"],
|
|
16704
|
-
["rk_live_", "Stripe restricted key"],
|
|
16705
|
-
["AKIA", "AWS access key ID"],
|
|
16706
|
-
["ASIA", "AWS temporary access key ID"],
|
|
16707
|
-
["AIza", "Google API key"],
|
|
16708
|
-
["hf_", "Hugging Face token"],
|
|
16709
|
-
["gsk_", "Groq API key"],
|
|
16710
|
-
["r8_", "Replicate token"],
|
|
16711
|
-
["xai-", "xAI key"],
|
|
16712
|
-
["npm_", "npm access token"],
|
|
16713
|
-
["dop_v1_", "DigitalOcean token"],
|
|
16714
|
-
["shpat_", "Shopify access token"],
|
|
16715
|
-
["sbp_", "Supabase token"]
|
|
16716
|
-
];
|
|
16717
|
-
});
|
|
16718
|
-
|
|
16719
|
-
// src/audit/leak-store.ts
|
|
16720
|
-
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
16721
|
-
import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync8 } from "node:fs";
|
|
16722
|
-
import { dirname as dirname8 } from "node:path";
|
|
16723
|
-
function readJson(path) {
|
|
16724
|
-
try {
|
|
16725
|
-
if (!existsSync12(path))
|
|
16726
|
-
return null;
|
|
16727
|
-
return JSON.parse(readFileSync8(path, "utf8"));
|
|
16728
|
-
} catch {
|
|
16729
|
-
return null;
|
|
16730
|
-
}
|
|
16731
|
-
}
|
|
16732
|
-
function readLeakIdentity(home) {
|
|
16733
|
-
const existing = readJson(auditLeakIdentityFile(home));
|
|
16734
|
-
if (existing && typeof existing.salt === "string" && existing.salt.length >= 32) {
|
|
16735
|
-
return { salt: existing.salt, dismissed: existing.dismissed ?? [] };
|
|
16736
|
-
}
|
|
16737
|
-
const minted = { salt: randomBytes2(32).toString("hex"), dismissed: [] };
|
|
16738
|
-
writeLeakIdentity(minted, home);
|
|
16739
|
-
return minted;
|
|
16740
|
-
}
|
|
16741
|
-
function writeLeakIdentity(identity, home) {
|
|
16742
|
-
const path = auditLeakIdentityFile(home);
|
|
16743
|
-
try {
|
|
16744
|
-
mkdirSync8(dirname8(path), { recursive: true });
|
|
16745
|
-
writeJsonAtomically(path, identity, { mode: FILE_MODE });
|
|
16746
|
-
return true;
|
|
16747
|
-
} catch {
|
|
16748
|
-
return false;
|
|
16749
|
-
}
|
|
16750
|
-
}
|
|
16751
|
-
function sanitizeFinding(raw) {
|
|
16752
|
-
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
16753
|
-
return null;
|
|
16754
|
-
const f = raw;
|
|
16755
|
-
if (typeof f.id !== "string" || !isFindingId(f.id))
|
|
16756
|
-
return null;
|
|
16757
|
-
const fp = f.fingerprint;
|
|
16758
|
-
if (!fp || typeof fp !== "object" || typeof fp.display !== "string" || typeof fp.label !== "string") {
|
|
16759
|
-
return null;
|
|
16760
|
-
}
|
|
16761
|
-
const sightings = Array.isArray(f.sightings) ? f.sightings.filter((s) => {
|
|
16762
|
-
if (!s || typeof s !== "object")
|
|
16763
|
-
return false;
|
|
16764
|
-
const m = s.mechanism;
|
|
16765
|
-
return !!m && typeof m === "object" && typeof m.summary === "string";
|
|
16766
|
-
}) : [];
|
|
16767
|
-
return {
|
|
16768
|
-
...f,
|
|
16769
|
-
fingerprint: {
|
|
16770
|
-
display: fp.display,
|
|
16771
|
-
label: fp.label,
|
|
16772
|
-
length: typeof fp.length === "number" && Number.isFinite(fp.length) ? fp.length : 0,
|
|
16773
|
-
attributed: fp.attributed === true
|
|
16774
|
-
},
|
|
16775
|
-
name: typeof f.name === "string" ? f.name : null,
|
|
16776
|
-
firstSeen: typeof f.firstSeen === "string" ? f.firstSeen : "",
|
|
16777
|
-
lastSeen: typeof f.lastSeen === "string" ? f.lastSeen : "",
|
|
16778
|
-
occurrences: typeof f.occurrences === "number" && Number.isFinite(f.occurrences) ? f.occurrences : sightings.length,
|
|
16779
|
-
sightings
|
|
16780
|
-
};
|
|
16781
|
-
}
|
|
16782
|
-
function readLeakRecord(home) {
|
|
16783
|
-
const identity = readLeakIdentity(home);
|
|
16784
|
-
const raw = readJson(auditLeaksFile(home));
|
|
16785
|
-
if (!raw || raw.schemaVersion !== LEAK_RECORD_SCHEMA_VERSION || !Array.isArray(raw.findings)) {
|
|
16786
|
-
return emptyRecord(identity.salt, new Date().toISOString());
|
|
16787
|
-
}
|
|
16788
|
-
const findings = raw.findings.map(sanitizeFinding).filter((f) => f !== null);
|
|
16789
|
-
return { ...raw, findings, salt: identity.salt };
|
|
16790
|
-
}
|
|
16791
|
-
function writeLeakRecord(record, home, nowMs = Date.now()) {
|
|
16792
|
-
const path = auditLeaksFile(home);
|
|
16793
|
-
try {
|
|
16794
|
-
mkdirSync8(dirname8(path), { recursive: true });
|
|
16795
|
-
const pruned = pruneRecord(record, nowMs);
|
|
16796
|
-
pruned.updatedAt = new Date(nowMs).toISOString();
|
|
16797
|
-
writeJsonAtomically(path, pruned, { mode: FILE_MODE });
|
|
16798
|
-
return true;
|
|
16799
|
-
} catch {
|
|
16800
|
-
return false;
|
|
16801
|
-
}
|
|
16802
|
-
}
|
|
16803
|
-
function activeFindings(record, home) {
|
|
16804
|
-
const dismissed = new Set(readLeakIdentity(home).dismissed);
|
|
16805
|
-
return record.findings.filter((f) => !dismissed.has(f.id)).sort((a, b) => a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0);
|
|
16806
|
-
}
|
|
16807
|
-
var FILE_MODE = 384;
|
|
16808
|
-
var init_leak_store = __esm(() => {
|
|
16809
|
-
init_fp_home();
|
|
16810
|
-
init_atomic_write();
|
|
16811
|
-
init_leak_fingerprint();
|
|
16812
|
-
});
|
|
16813
|
-
|
|
16814
|
-
// src/audit/leak-notice.ts
|
|
16815
|
-
import { existsSync as existsSync13, mkdirSync as mkdirSync9, readdirSync as readdirSync5, statSync as statSync8, writeFileSync as writeFileSync7, rmSync as rmSync4 } from "node:fs";
|
|
16816
|
-
import { resolve as resolve11 } from "node:path";
|
|
16817
|
-
function pendingLeakNotice(home, channel = "cli") {
|
|
16818
|
-
try {
|
|
16819
|
-
const dir = NOTICE_DIR(home, channel);
|
|
16820
|
-
const claimed = new Set(existsSync13(dir) ? readdirSync5(dir) : []);
|
|
16821
|
-
const ids = activeFindings(readLeakRecord(home), home).map((f) => f.id).filter((id) => !claimed.has(id));
|
|
16822
|
-
return { ids, count: ids.length };
|
|
16823
|
-
} catch {
|
|
16824
|
-
return { ids: [], count: 0 };
|
|
16825
|
-
}
|
|
16826
|
-
}
|
|
16827
|
-
function markLeakNoticeDelivered(ids, home, channel = "cli") {
|
|
16828
|
-
const won = [];
|
|
16829
|
-
try {
|
|
16830
|
-
const dir = NOTICE_DIR(home, channel);
|
|
16831
|
-
mkdirSync9(dir, { recursive: true });
|
|
16832
|
-
for (const id of ids) {
|
|
16833
|
-
if (!isFindingId(id))
|
|
16834
|
-
continue;
|
|
16835
|
-
try {
|
|
16836
|
-
writeFileSync7(resolve11(dir, id), "", { flag: "wx", mode: 384 });
|
|
16837
|
-
won.push(id);
|
|
16838
|
-
} catch {}
|
|
16839
|
-
}
|
|
16840
|
-
} catch {}
|
|
16841
|
-
return won;
|
|
16842
|
-
}
|
|
16843
|
-
var NOTICE_DIR = (home, channel = "cli") => resolve11(auditDir(home), channel === "cli" ? "notified" : `notified-${channel}`), MARKER_TTL_MS;
|
|
16844
|
-
var init_leak_notice = __esm(() => {
|
|
16845
|
-
init_fp_home();
|
|
16846
|
-
init_leak_store();
|
|
16847
|
-
init_leak_fingerprint();
|
|
16848
|
-
MARKER_TTL_MS = 120 * 86400000;
|
|
16849
|
-
});
|
|
16850
|
-
|
|
16851
16486
|
// src/hooks/resolve-cwd.ts
|
|
16852
16487
|
function resolveCwd(integration, parsed) {
|
|
16853
16488
|
const direct = typeof parsed.cwd === "string" && parsed.cwd.length > 0 ? parsed.cwd : undefined;
|
|
@@ -17540,10 +17175,23 @@ var init_cursor_projects = __esm(() => {
|
|
|
17540
17175
|
});
|
|
17541
17176
|
|
|
17542
17177
|
// lib/sqlite-reader.ts
|
|
17543
|
-
import { existsSync as
|
|
17178
|
+
import { existsSync as existsSync11, readFileSync as readFileSync8 } from "node:fs";
|
|
17544
17179
|
import initSqlJs from "sql.js/dist/sql-asm.js";
|
|
17180
|
+
function silenceSqliteExperimentalWarning() {
|
|
17181
|
+
if (warningPatched)
|
|
17182
|
+
return;
|
|
17183
|
+
warningPatched = true;
|
|
17184
|
+
const original = process.emitWarning.bind(process);
|
|
17185
|
+
process.emitWarning = (warning, ...rest) => {
|
|
17186
|
+
const text = typeof warning === "string" ? warning : String(warning?.message ?? "");
|
|
17187
|
+
if (text.includes("SQLite is an experimental feature"))
|
|
17188
|
+
return;
|
|
17189
|
+
return original(warning, ...rest);
|
|
17190
|
+
};
|
|
17191
|
+
}
|
|
17545
17192
|
async function tryNodeSqlite(dbPath) {
|
|
17546
17193
|
try {
|
|
17194
|
+
silenceSqliteExperimentalWarning();
|
|
17547
17195
|
const mod = await import("node:sqlite");
|
|
17548
17196
|
const db = new mod.DatabaseSync(dbPath, { readOnly: true });
|
|
17549
17197
|
return {
|
|
@@ -17564,10 +17212,21 @@ function loadSqlJs() {
|
|
|
17564
17212
|
sqlPromise = initSqlJs();
|
|
17565
17213
|
return sqlPromise;
|
|
17566
17214
|
}
|
|
17215
|
+
function clearWalFlag(bytes) {
|
|
17216
|
+
if (bytes.length < 20)
|
|
17217
|
+
return bytes;
|
|
17218
|
+
if (bytes.toString("latin1", 0, 16) !== SQLITE_MAGIC)
|
|
17219
|
+
return bytes;
|
|
17220
|
+
if (bytes[18] === 1 && bytes[19] === 1)
|
|
17221
|
+
return bytes;
|
|
17222
|
+
bytes[18] = 1;
|
|
17223
|
+
bytes[19] = 1;
|
|
17224
|
+
return bytes;
|
|
17225
|
+
}
|
|
17567
17226
|
async function trySqlJs(dbPath) {
|
|
17568
17227
|
try {
|
|
17569
17228
|
const SQL = await loadSqlJs();
|
|
17570
|
-
const db = new SQL.Database(
|
|
17229
|
+
const db = new SQL.Database(clearWalFlag(readFileSync8(dbPath)));
|
|
17571
17230
|
return {
|
|
17572
17231
|
query(sql, params) {
|
|
17573
17232
|
const stmt = db.prepare(sql);
|
|
@@ -17591,11 +17250,11 @@ async function trySqlJs(dbPath) {
|
|
|
17591
17250
|
}
|
|
17592
17251
|
}
|
|
17593
17252
|
async function openSqliteReadonly(dbPath) {
|
|
17594
|
-
if (!
|
|
17253
|
+
if (!existsSync11(dbPath))
|
|
17595
17254
|
return null;
|
|
17596
17255
|
return await tryNodeSqlite(dbPath) ?? await trySqlJs(dbPath);
|
|
17597
17256
|
}
|
|
17598
|
-
var sqlPromise = null;
|
|
17257
|
+
var warningPatched = false, sqlPromise = null, SQLITE_MAGIC = "SQLite format 3\x00";
|
|
17599
17258
|
var init_sqlite_reader = () => {};
|
|
17600
17259
|
|
|
17601
17260
|
// lib/opencode-db.ts
|
|
@@ -18248,7 +17907,7 @@ var init_hermes_projects = __esm(() => {
|
|
|
18248
17907
|
|
|
18249
17908
|
// lib/openclaw-sessions.ts
|
|
18250
17909
|
import { readFile as readFile7 } from "node:fs/promises";
|
|
18251
|
-
import { readdirSync as
|
|
17910
|
+
import { readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
|
|
18252
17911
|
import { homedir as homedir12 } from "node:os";
|
|
18253
17912
|
import { join as join14 } from "node:path";
|
|
18254
17913
|
function openclawHome() {
|
|
@@ -18367,7 +18026,7 @@ function openclawLinesToLogEntries(lines, source = "session") {
|
|
|
18367
18026
|
}
|
|
18368
18027
|
function listOpenClawAgents() {
|
|
18369
18028
|
try {
|
|
18370
|
-
return
|
|
18029
|
+
return readdirSync5(join14(openclawHome(), "agents"), { withFileTypes: true }).filter((d) => d.isDirectory() && !d.name.startsWith(".")).map((d) => d.name).sort();
|
|
18371
18030
|
} catch {
|
|
18372
18031
|
return [];
|
|
18373
18032
|
}
|
|
@@ -18377,7 +18036,7 @@ function listOpenClawTranscripts() {
|
|
|
18377
18036
|
const out = [];
|
|
18378
18037
|
let agentIds;
|
|
18379
18038
|
try {
|
|
18380
|
-
agentIds =
|
|
18039
|
+
agentIds = readdirSync5(agentsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
18381
18040
|
} catch {
|
|
18382
18041
|
return out;
|
|
18383
18042
|
}
|
|
@@ -18385,7 +18044,7 @@ function listOpenClawTranscripts() {
|
|
|
18385
18044
|
const sessionsDir = join14(agentsDir, agentId, "sessions");
|
|
18386
18045
|
let files;
|
|
18387
18046
|
try {
|
|
18388
|
-
files =
|
|
18047
|
+
files = readdirSync5(sessionsDir);
|
|
18389
18048
|
} catch {
|
|
18390
18049
|
continue;
|
|
18391
18050
|
}
|
|
@@ -18397,7 +18056,7 @@ function listOpenClawTranscripts() {
|
|
|
18397
18056
|
continue;
|
|
18398
18057
|
const transcriptPath = join14(sessionsDir, file);
|
|
18399
18058
|
try {
|
|
18400
|
-
const st =
|
|
18059
|
+
const st = statSync7(transcriptPath);
|
|
18401
18060
|
out.push({ agentId, sessionId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
|
|
18402
18061
|
} catch {}
|
|
18403
18062
|
}
|
|
@@ -18448,7 +18107,7 @@ __export(exports_openclaw_projects, {
|
|
|
18448
18107
|
getOpenClawSessions: () => getOpenClawSessions,
|
|
18449
18108
|
openClawProjectPath: () => openClawProjectPath
|
|
18450
18109
|
});
|
|
18451
|
-
import { readFileSync as
|
|
18110
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
18452
18111
|
import { join as join15 } from "node:path";
|
|
18453
18112
|
function str(v) {
|
|
18454
18113
|
return typeof v === "string" && v.length > 0 ? v : undefined;
|
|
@@ -18458,7 +18117,7 @@ function readSessionsIndex(agentId) {
|
|
|
18458
18117
|
const indexPath = join15(openclawHome(), "agents", agentId, "sessions", "sessions.json");
|
|
18459
18118
|
let raw;
|
|
18460
18119
|
try {
|
|
18461
|
-
raw = JSON.parse(
|
|
18120
|
+
raw = JSON.parse(readFileSync9(indexPath, "utf-8"));
|
|
18462
18121
|
} catch {
|
|
18463
18122
|
return out;
|
|
18464
18123
|
}
|
|
@@ -18607,7 +18266,7 @@ var init_openclaw_projects = __esm(() => {
|
|
|
18607
18266
|
|
|
18608
18267
|
// lib/factory-sessions.ts
|
|
18609
18268
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
18610
|
-
import { readdirSync as
|
|
18269
|
+
import { readdirSync as readdirSync6, statSync as statSync8 } from "node:fs";
|
|
18611
18270
|
import { homedir as homedir13 } from "node:os";
|
|
18612
18271
|
import { join as join16 } from "node:path";
|
|
18613
18272
|
function factoryHome() {
|
|
@@ -18753,7 +18412,7 @@ function listFactoryTranscripts() {
|
|
|
18753
18412
|
const out = [];
|
|
18754
18413
|
let projectDirs;
|
|
18755
18414
|
try {
|
|
18756
|
-
projectDirs =
|
|
18415
|
+
projectDirs = readdirSync6(root, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
18757
18416
|
} catch {
|
|
18758
18417
|
return out;
|
|
18759
18418
|
}
|
|
@@ -18763,7 +18422,7 @@ function listFactoryTranscripts() {
|
|
|
18763
18422
|
const projectPath = join16(root, projectName);
|
|
18764
18423
|
let files;
|
|
18765
18424
|
try {
|
|
18766
|
-
files =
|
|
18425
|
+
files = readdirSync6(projectPath);
|
|
18767
18426
|
} catch {
|
|
18768
18427
|
continue;
|
|
18769
18428
|
}
|
|
@@ -18775,7 +18434,7 @@ function listFactoryTranscripts() {
|
|
|
18775
18434
|
continue;
|
|
18776
18435
|
const transcriptPath = join16(projectPath, file);
|
|
18777
18436
|
try {
|
|
18778
|
-
const st =
|
|
18437
|
+
const st = statSync8(transcriptPath);
|
|
18779
18438
|
out.push({ projectName, cwd, sessionId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
|
|
18780
18439
|
} catch {}
|
|
18781
18440
|
}
|
|
@@ -19195,7 +18854,7 @@ var init_devin_projects = __esm(() => {
|
|
|
19195
18854
|
|
|
19196
18855
|
// lib/antigravity-sessions.ts
|
|
19197
18856
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
19198
|
-
import { readdirSync as
|
|
18857
|
+
import { readdirSync as readdirSync7, statSync as statSync9 } from "node:fs";
|
|
19199
18858
|
import { homedir as homedir15 } from "node:os";
|
|
19200
18859
|
import { join as join18 } from "node:path";
|
|
19201
18860
|
function antigravityHome() {
|
|
@@ -19320,7 +18979,7 @@ function listAntigravityTranscripts() {
|
|
|
19320
18979
|
const out = [];
|
|
19321
18980
|
let convoDirs;
|
|
19322
18981
|
try {
|
|
19323
|
-
convoDirs =
|
|
18982
|
+
convoDirs = readdirSync7(root, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
19324
18983
|
} catch {
|
|
19325
18984
|
return out;
|
|
19326
18985
|
}
|
|
@@ -19330,7 +18989,7 @@ function listAntigravityTranscripts() {
|
|
|
19330
18989
|
continue;
|
|
19331
18990
|
const transcriptPath = join18(root, conversationId, rel);
|
|
19332
18991
|
try {
|
|
19333
|
-
const st =
|
|
18992
|
+
const st = statSync9(transcriptPath);
|
|
19334
18993
|
if (!st.isFile())
|
|
19335
18994
|
continue;
|
|
19336
18995
|
out.push({ conversationId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
|
|
@@ -19343,7 +19002,7 @@ function findAntigravityTranscript(conversationId) {
|
|
|
19343
19002
|
return null;
|
|
19344
19003
|
const transcriptPath = join18(antigravityBrainRoot(), conversationId, antigravityTranscriptRelPath());
|
|
19345
19004
|
try {
|
|
19346
|
-
if (
|
|
19005
|
+
if (statSync9(transcriptPath).isFile())
|
|
19347
19006
|
return transcriptPath;
|
|
19348
19007
|
} catch {}
|
|
19349
19008
|
return null;
|
|
@@ -19795,7 +19454,7 @@ var init_goose_projects = __esm(() => {
|
|
|
19795
19454
|
|
|
19796
19455
|
// lib/projects.ts
|
|
19797
19456
|
import { readdir as readdir5, stat as stat4 } from "node:fs/promises";
|
|
19798
|
-
import { join as join21, resolve as
|
|
19457
|
+
import { join as join21, resolve as resolve11, sep } from "node:path";
|
|
19799
19458
|
async function getMtime(path, label) {
|
|
19800
19459
|
try {
|
|
19801
19460
|
return (await stat4(path)).mtime;
|
|
@@ -19947,8 +19606,8 @@ function resolveProjectPath(projectName) {
|
|
|
19947
19606
|
throw new RangeError("Empty project name");
|
|
19948
19607
|
if (/^[/\\]/.test(projectName))
|
|
19949
19608
|
throw new RangeError("Absolute project name");
|
|
19950
|
-
const projectsPath =
|
|
19951
|
-
const candidate =
|
|
19609
|
+
const projectsPath = resolve11(getClaudeProjectsPath());
|
|
19610
|
+
const candidate = resolve11(join21(projectsPath, projectName));
|
|
19952
19611
|
if (!candidate.startsWith(projectsPath + sep)) {
|
|
19953
19612
|
throw new RangeError("Project path escapes root");
|
|
19954
19613
|
}
|
|
@@ -20258,30 +19917,30 @@ var init_log_entries = __esm(() => {
|
|
|
20258
19917
|
});
|
|
20259
19918
|
|
|
20260
19919
|
// lib/codex-sessions.ts
|
|
20261
|
-
import { readFileSync as
|
|
19920
|
+
import { readFileSync as readFileSync10, readdirSync as readdirSync8, existsSync as existsSync12, writeFileSync as writeFileSync6, mkdirSync as mkdirSync7, statSync as statSync10 } from "node:fs";
|
|
20262
19921
|
import { readFile as readFile11 } from "node:fs/promises";
|
|
20263
|
-
import { dirname as
|
|
19922
|
+
import { dirname as dirname7, join as join24 } from "node:path";
|
|
20264
19923
|
import { homedir as homedir17 } from "node:os";
|
|
20265
19924
|
function readCache() {
|
|
20266
19925
|
try {
|
|
20267
|
-
if (!
|
|
19926
|
+
if (!existsSync12(CACHE_PATH))
|
|
20268
19927
|
return {};
|
|
20269
|
-
return JSON.parse(
|
|
19928
|
+
return JSON.parse(readFileSync10(CACHE_PATH, "utf-8"));
|
|
20270
19929
|
} catch {
|
|
20271
19930
|
return {};
|
|
20272
19931
|
}
|
|
20273
19932
|
}
|
|
20274
19933
|
function writeCacheEntry(sessionId, path) {
|
|
20275
19934
|
try {
|
|
20276
|
-
|
|
19935
|
+
mkdirSync7(dirname7(CACHE_PATH), { recursive: true });
|
|
20277
19936
|
const cache = readCache();
|
|
20278
19937
|
cache[sessionId] = path;
|
|
20279
|
-
|
|
19938
|
+
writeFileSync6(CACHE_PATH, JSON.stringify(cache), "utf-8");
|
|
20280
19939
|
} catch {}
|
|
20281
19940
|
}
|
|
20282
19941
|
function dirSearch(dir, sessionId) {
|
|
20283
19942
|
try {
|
|
20284
|
-
for (const f of
|
|
19943
|
+
for (const f of readdirSync8(dir, { withFileTypes: true })) {
|
|
20285
19944
|
if (f.isFile() && f.name.includes(sessionId) && f.name.endsWith(".jsonl")) {
|
|
20286
19945
|
return join24(dir, f.name);
|
|
20287
19946
|
}
|
|
@@ -20292,7 +19951,7 @@ function dirSearch(dir, sessionId) {
|
|
|
20292
19951
|
function findCodexTranscript(sessionId) {
|
|
20293
19952
|
const cache = readCache();
|
|
20294
19953
|
const cached = cache[sessionId];
|
|
20295
|
-
if (cached &&
|
|
19954
|
+
if (cached && existsSync12(cached))
|
|
20296
19955
|
return cached;
|
|
20297
19956
|
const root = join24(homedir17(), ".codex", "sessions");
|
|
20298
19957
|
const today = new Date;
|
|
@@ -20311,13 +19970,13 @@ function findCodexTranscript(sessionId) {
|
|
|
20311
19970
|
}
|
|
20312
19971
|
}
|
|
20313
19972
|
try {
|
|
20314
|
-
for (const y of
|
|
19973
|
+
for (const y of readdirSync8(root, { withFileTypes: true })) {
|
|
20315
19974
|
if (!y.isDirectory())
|
|
20316
19975
|
continue;
|
|
20317
|
-
for (const m of
|
|
19976
|
+
for (const m of readdirSync8(join24(root, y.name), { withFileTypes: true })) {
|
|
20318
19977
|
if (!m.isDirectory())
|
|
20319
19978
|
continue;
|
|
20320
|
-
for (const d of
|
|
19979
|
+
for (const d of readdirSync8(join24(root, y.name, m.name), { withFileTypes: true })) {
|
|
20321
19980
|
if (!d.isDirectory())
|
|
20322
19981
|
continue;
|
|
20323
19982
|
const hit = dirSearch(join24(root, y.name, m.name, d.name), sessionId);
|
|
@@ -20346,6 +20005,15 @@ function joinTexts(blocks, wantedType) {
|
|
|
20346
20005
|
return blocks.filter((b) => b?.type === wantedType && typeof b.text === "string").map((b) => b.text).join(`
|
|
20347
20006
|
`);
|
|
20348
20007
|
}
|
|
20008
|
+
function toolOutputText(output) {
|
|
20009
|
+
if (typeof output === "string")
|
|
20010
|
+
return output;
|
|
20011
|
+
if (Array.isArray(output)) {
|
|
20012
|
+
return output.filter((block) => !!block && typeof block === "object").map((block) => typeof block.text === "string" ? block.text : "").filter(Boolean).join(`
|
|
20013
|
+
`);
|
|
20014
|
+
}
|
|
20015
|
+
return output === undefined ? "" : JSON.stringify(output);
|
|
20016
|
+
}
|
|
20349
20017
|
async function parseCodexLog(fileContent, source = "session") {
|
|
20350
20018
|
const lines = fileContent.split(`
|
|
20351
20019
|
`).filter((line) => line.trim() !== "");
|
|
@@ -20422,10 +20090,11 @@ async function parseCodexLog(fileContent, source = "session") {
|
|
|
20422
20090
|
});
|
|
20423
20091
|
continue;
|
|
20424
20092
|
}
|
|
20425
|
-
if (subType === "function_call") {
|
|
20093
|
+
if (subType === "function_call" || subType === "custom_tool_call") {
|
|
20426
20094
|
const callId = payload.call_id;
|
|
20427
20095
|
const name = payload.name ?? "function_call";
|
|
20428
|
-
const
|
|
20096
|
+
const encodedInput = payload.arguments ?? payload.input;
|
|
20097
|
+
const input = safeJsonParse4(encodedInput);
|
|
20429
20098
|
const toolUse = {
|
|
20430
20099
|
type: "tool_use",
|
|
20431
20100
|
id: callId ?? `${timestamp}-${name}`,
|
|
@@ -20444,7 +20113,7 @@ async function parseCodexLog(fileContent, source = "session") {
|
|
|
20444
20113
|
}
|
|
20445
20114
|
continue;
|
|
20446
20115
|
}
|
|
20447
|
-
if (subType === "function_call_output") {
|
|
20116
|
+
if (subType === "function_call_output" || subType === "custom_tool_call_output") {
|
|
20448
20117
|
const callId = payload.call_id;
|
|
20449
20118
|
const block = callId ? toolUseById.get(callId) : undefined;
|
|
20450
20119
|
if (block) {
|
|
@@ -20453,7 +20122,7 @@ async function parseCodexLog(fileContent, source = "session") {
|
|
|
20453
20122
|
block.result = {
|
|
20454
20123
|
timestamp,
|
|
20455
20124
|
timestampFormatted: formatTimestamp(date),
|
|
20456
|
-
content:
|
|
20125
|
+
content: toolOutputText(payload.output),
|
|
20457
20126
|
durationMs: duration,
|
|
20458
20127
|
durationFormatted: formatDuration(duration)
|
|
20459
20128
|
};
|
|
@@ -20546,7 +20215,7 @@ var init_codex_sessions = __esm(() => {
|
|
|
20546
20215
|
});
|
|
20547
20216
|
|
|
20548
20217
|
// src/hooks/resolve-permission-mode.ts
|
|
20549
|
-
import { readFileSync as
|
|
20218
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
20550
20219
|
function resolvePermissionMode(integration, parsed, sessionId) {
|
|
20551
20220
|
if (integration === "claude") {
|
|
20552
20221
|
return parsed.permission_mode ?? "default";
|
|
@@ -20561,7 +20230,7 @@ function resolveCodexMode(sessionId) {
|
|
|
20561
20230
|
const path = findCodexTranscript(sessionId);
|
|
20562
20231
|
if (!path)
|
|
20563
20232
|
return;
|
|
20564
|
-
for (const line of
|
|
20233
|
+
for (const line of readFileSync11(path, "utf-8").split(`
|
|
20565
20234
|
`)) {
|
|
20566
20235
|
if (!line.includes("turn_context"))
|
|
20567
20236
|
continue;
|
|
@@ -20586,9 +20255,9 @@ var init_resolve_permission_mode = __esm(() => {
|
|
|
20586
20255
|
});
|
|
20587
20256
|
|
|
20588
20257
|
// lib/copilot-sessions.ts
|
|
20589
|
-
import { readFileSync as
|
|
20258
|
+
import { readFileSync as readFileSync12, readdirSync as readdirSync9, existsSync as existsSync13, statSync as statSync11 } from "node:fs";
|
|
20590
20259
|
import { readFile as readFile12 } from "node:fs/promises";
|
|
20591
|
-
import { join as join25, resolve as
|
|
20260
|
+
import { join as join25, resolve as resolve12, sep as sep2 } from "node:path";
|
|
20592
20261
|
import { homedir as homedir18 } from "node:os";
|
|
20593
20262
|
function getCopilotHome() {
|
|
20594
20263
|
return process.env.COPILOT_HOME || join25(homedir18(), ".copilot");
|
|
@@ -20599,8 +20268,8 @@ function getCopilotSessionStateRoot2() {
|
|
|
20599
20268
|
function getCopilotSessionDir(sessionId) {
|
|
20600
20269
|
if (!sessionId)
|
|
20601
20270
|
return null;
|
|
20602
|
-
const root =
|
|
20603
|
-
const candidate =
|
|
20271
|
+
const root = resolve12(getCopilotSessionStateRoot2());
|
|
20272
|
+
const candidate = resolve12(root, sessionId);
|
|
20604
20273
|
if (candidate === root || !candidate.startsWith(`${root}${sep2}`))
|
|
20605
20274
|
return null;
|
|
20606
20275
|
return candidate;
|
|
@@ -20615,17 +20284,17 @@ function findCopilotTranscript(sessionId) {
|
|
|
20615
20284
|
const candidate = resolveSessionFile(sessionId, "events.jsonl");
|
|
20616
20285
|
if (!candidate)
|
|
20617
20286
|
return null;
|
|
20618
|
-
return
|
|
20287
|
+
return existsSync13(candidate) ? candidate : null;
|
|
20619
20288
|
}
|
|
20620
20289
|
function findCopilotWorkspace(sessionId) {
|
|
20621
20290
|
const candidate = resolveSessionFile(sessionId, "workspace.yaml");
|
|
20622
20291
|
if (!candidate)
|
|
20623
20292
|
return null;
|
|
20624
|
-
return
|
|
20293
|
+
return existsSync13(candidate) ? candidate : null;
|
|
20625
20294
|
}
|
|
20626
20295
|
function readYamlScalar(path, key) {
|
|
20627
20296
|
try {
|
|
20628
|
-
const text =
|
|
20297
|
+
const text = readFileSync12(path, "utf-8");
|
|
20629
20298
|
const re = new RegExp(`^${key}\\s*:\\s*(.+?)\\s*$`, "m");
|
|
20630
20299
|
const m = text.match(re);
|
|
20631
20300
|
if (!m)
|
|
@@ -20648,6 +20317,8 @@ async function parseCopilotLog(fileContent, source = "session") {
|
|
|
20648
20317
|
const rawLines = [];
|
|
20649
20318
|
const toolUseById = new Map;
|
|
20650
20319
|
const toolUseStartMs = new Map;
|
|
20320
|
+
let mostRecentToolUse;
|
|
20321
|
+
let mostRecentToolUseStartMs = 0;
|
|
20651
20322
|
let cwd;
|
|
20652
20323
|
let seenSessionStart = false;
|
|
20653
20324
|
for (let i = 0;i < lines.length; i++) {
|
|
@@ -20743,8 +20414,24 @@ async function parseCopilotLog(fileContent, source = "session") {
|
|
|
20743
20414
|
toolUseById.set(callId, toolUse);
|
|
20744
20415
|
toolUseStartMs.set(callId, date.getTime());
|
|
20745
20416
|
}
|
|
20417
|
+
mostRecentToolUse = toolUse;
|
|
20418
|
+
mostRecentToolUseStartMs = date.getTime();
|
|
20746
20419
|
continue;
|
|
20747
20420
|
}
|
|
20421
|
+
if (recType === "hook.start" && data.hookType === "postToolUse" && mostRecentToolUse) {
|
|
20422
|
+
const input = data.input ?? {};
|
|
20423
|
+
const hookResult = input.toolResult ?? {};
|
|
20424
|
+
const hookContent = hookResult.textResultForLlm ?? hookResult.sessionLog;
|
|
20425
|
+
if (typeof hookContent === "string" && hookContent.length > 0) {
|
|
20426
|
+
mostRecentToolUse.result = {
|
|
20427
|
+
timestamp,
|
|
20428
|
+
timestampFormatted: formatTimestamp(date),
|
|
20429
|
+
content: hookContent,
|
|
20430
|
+
durationMs: Math.max(0, date.getTime() - mostRecentToolUseStartMs),
|
|
20431
|
+
durationFormatted: formatDuration(Math.max(0, date.getTime() - mostRecentToolUseStartMs))
|
|
20432
|
+
};
|
|
20433
|
+
}
|
|
20434
|
+
}
|
|
20748
20435
|
if (recType === "tool.execution_complete") {
|
|
20749
20436
|
const callId = data.toolCallId;
|
|
20750
20437
|
const block = callId ? toolUseById.get(callId) : undefined;
|
|
@@ -20754,7 +20441,8 @@ async function parseCopilotLog(fileContent, source = "session") {
|
|
|
20754
20441
|
const telemetry = data.toolTelemetry ?? {};
|
|
20755
20442
|
const reportedMs = telemetry.metrics?.commandTimeMs ?? telemetry.metrics?.durationMs ?? null;
|
|
20756
20443
|
const durationMs = typeof reportedMs === "number" && reportedMs >= 0 ? reportedMs : Math.max(0, date.getTime() - startMs);
|
|
20757
|
-
const
|
|
20444
|
+
const completionContent = result.detailedContent ?? result.content ?? "";
|
|
20445
|
+
const content = block.result?.content || completionContent;
|
|
20758
20446
|
block.result = {
|
|
20759
20447
|
timestamp,
|
|
20760
20448
|
timestampFormatted: formatTimestamp(date),
|
|
@@ -20803,9 +20491,9 @@ var init_copilot_sessions = __esm(() => {
|
|
|
20803
20491
|
});
|
|
20804
20492
|
|
|
20805
20493
|
// lib/cursor-sessions.ts
|
|
20806
|
-
import { readFileSync as
|
|
20494
|
+
import { readFileSync as readFileSync13, readdirSync as readdirSync10, existsSync as existsSync14, statSync as statSync12 } from "node:fs";
|
|
20807
20495
|
import { readFile as readFile13 } from "node:fs/promises";
|
|
20808
|
-
import { basename as basename3, join as join26, resolve as
|
|
20496
|
+
import { basename as basename3, join as join26, resolve as resolve13, sep as sep3 } from "node:path";
|
|
20809
20497
|
import { homedir as homedir19 } from "node:os";
|
|
20810
20498
|
function getCursorHome2() {
|
|
20811
20499
|
return process.env.CURSOR_HOME || join26(homedir19(), ".cursor");
|
|
@@ -20813,28 +20501,28 @@ function getCursorHome2() {
|
|
|
20813
20501
|
function getCursorSessionDir(sessionId) {
|
|
20814
20502
|
if (!sessionId)
|
|
20815
20503
|
return null;
|
|
20816
|
-
const home =
|
|
20817
|
-
const projectsRoot =
|
|
20504
|
+
const home = resolve13(getCursorHome2());
|
|
20505
|
+
const projectsRoot = resolve13(home, NEW_PROJECTS_DIR2);
|
|
20818
20506
|
let projectEntries = [];
|
|
20819
20507
|
try {
|
|
20820
|
-
projectEntries =
|
|
20508
|
+
projectEntries = readdirSync10(projectsRoot, { withFileTypes: true });
|
|
20821
20509
|
} catch {}
|
|
20822
20510
|
for (const entry of projectEntries) {
|
|
20823
20511
|
if (!entry.isDirectory())
|
|
20824
20512
|
continue;
|
|
20825
|
-
const candidate =
|
|
20826
|
-
const transcriptRoot =
|
|
20513
|
+
const candidate = resolve13(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2, sessionId);
|
|
20514
|
+
const transcriptRoot = resolve13(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2);
|
|
20827
20515
|
if (candidate === transcriptRoot || !candidate.startsWith(`${transcriptRoot}${sep3}`))
|
|
20828
20516
|
continue;
|
|
20829
|
-
if (
|
|
20517
|
+
if (existsSync14(candidate))
|
|
20830
20518
|
return candidate;
|
|
20831
20519
|
}
|
|
20832
20520
|
for (const sub of LEGACY_SESSION_ROOT_CANDIDATES2) {
|
|
20833
|
-
const root =
|
|
20834
|
-
const candidate =
|
|
20521
|
+
const root = resolve13(home, sub);
|
|
20522
|
+
const candidate = resolve13(root, sessionId);
|
|
20835
20523
|
if (candidate === root || !candidate.startsWith(`${root}${sep3}`))
|
|
20836
20524
|
continue;
|
|
20837
|
-
if (
|
|
20525
|
+
if (existsSync14(candidate))
|
|
20838
20526
|
return candidate;
|
|
20839
20527
|
}
|
|
20840
20528
|
return null;
|
|
@@ -20844,11 +20532,11 @@ function findCursorTranscript(sessionId) {
|
|
|
20844
20532
|
if (!dir)
|
|
20845
20533
|
return null;
|
|
20846
20534
|
const newCandidate = join26(dir, `${basename3(dir)}.jsonl`);
|
|
20847
|
-
if (
|
|
20535
|
+
if (existsSync14(newCandidate))
|
|
20848
20536
|
return newCandidate;
|
|
20849
20537
|
for (const name of LEGACY_TRANSCRIPT_FILE_CANDIDATES2) {
|
|
20850
20538
|
const candidate = join26(dir, name);
|
|
20851
|
-
if (
|
|
20539
|
+
if (existsSync14(candidate))
|
|
20852
20540
|
return candidate;
|
|
20853
20541
|
}
|
|
20854
20542
|
return null;
|
|
@@ -20878,8 +20566,27 @@ async function parseCursorLog(fileContent, source = "session") {
|
|
|
20878
20566
|
if (!raw.type && raw.role && raw.message?.content) {
|
|
20879
20567
|
const synthDate = new Date(SYNTH_T0 + i);
|
|
20880
20568
|
const synthTs = synthDate.toISOString();
|
|
20881
|
-
const
|
|
20569
|
+
const messageContent = raw.message.content;
|
|
20570
|
+
const textParts = messageContent.filter((c) => c?.type === "text" && typeof c.text === "string").map((c) => c.text).join("");
|
|
20882
20571
|
if (raw.role === "user") {
|
|
20572
|
+
let attachedResult = false;
|
|
20573
|
+
for (const block of messageContent) {
|
|
20574
|
+
if (block?.type !== "tool_result")
|
|
20575
|
+
continue;
|
|
20576
|
+
const callId = typeof block.tool_use_id === "string" ? block.tool_use_id : undefined;
|
|
20577
|
+
const toolUse = callId ? toolUseById.get(callId) : undefined;
|
|
20578
|
+
if (!toolUse)
|
|
20579
|
+
continue;
|
|
20580
|
+
const durationMs = Math.max(0, synthDate.getTime() - (toolUseStartMs.get(callId) ?? synthDate.getTime()));
|
|
20581
|
+
toolUse.result = {
|
|
20582
|
+
timestamp: synthTs,
|
|
20583
|
+
timestampFormatted: formatTimestamp(synthDate),
|
|
20584
|
+
content: typeof block.content === "string" ? block.content : block.content == null ? "" : JSON.stringify(block.content),
|
|
20585
|
+
durationMs,
|
|
20586
|
+
durationFormatted: formatDuration(durationMs)
|
|
20587
|
+
};
|
|
20588
|
+
attachedResult = true;
|
|
20589
|
+
}
|
|
20883
20590
|
const queryMatch = /<user_query>\s*([\s\S]*?)\s*<\/user_query>/.exec(textParts);
|
|
20884
20591
|
const text = queryMatch ? queryMatch[1] : textParts;
|
|
20885
20592
|
if (text) {
|
|
@@ -20888,11 +20595,35 @@ async function parseCursorLog(fileContent, source = "session") {
|
|
|
20888
20595
|
...baseEntry(rawCopy, synthTs, synthDate, source),
|
|
20889
20596
|
message: { role: "user", content: text }
|
|
20890
20597
|
});
|
|
20598
|
+
} else if (!attachedResult) {
|
|
20599
|
+
entries.push({
|
|
20600
|
+
type: "system",
|
|
20601
|
+
...baseEntry(rawCopy, synthTs, synthDate, source),
|
|
20602
|
+
raw: rawCopy
|
|
20603
|
+
});
|
|
20891
20604
|
}
|
|
20892
20605
|
continue;
|
|
20893
20606
|
}
|
|
20894
20607
|
if (raw.role === "assistant") {
|
|
20895
|
-
const blocks =
|
|
20608
|
+
const blocks = [];
|
|
20609
|
+
if (textParts)
|
|
20610
|
+
blocks.push({ type: "text", text: textParts });
|
|
20611
|
+
for (let j = 0;j < messageContent.length; j++) {
|
|
20612
|
+
const contentBlock = messageContent[j];
|
|
20613
|
+
if (contentBlock?.type !== "tool_use")
|
|
20614
|
+
continue;
|
|
20615
|
+
const name = typeof contentBlock.name === "string" ? contentBlock.name : "tool";
|
|
20616
|
+
const id = typeof contentBlock.id === "string" && contentBlock.id ? contentBlock.id : `cursor-${i}-${name}-${j}`;
|
|
20617
|
+
const toolUse = {
|
|
20618
|
+
type: "tool_use",
|
|
20619
|
+
id,
|
|
20620
|
+
name,
|
|
20621
|
+
input: contentBlock.input && typeof contentBlock.input === "object" ? contentBlock.input : {}
|
|
20622
|
+
};
|
|
20623
|
+
blocks.push(toolUse);
|
|
20624
|
+
toolUseById.set(id, toolUse);
|
|
20625
|
+
toolUseStartMs.set(id, synthDate.getTime());
|
|
20626
|
+
}
|
|
20896
20627
|
if (blocks.length === 0) {
|
|
20897
20628
|
entries.push({
|
|
20898
20629
|
type: "system",
|
|
@@ -21059,9 +20790,9 @@ var init_cursor_sessions = __esm(() => {
|
|
|
21059
20790
|
});
|
|
21060
20791
|
|
|
21061
20792
|
// lib/pi-sessions.ts
|
|
21062
|
-
import { readFileSync as
|
|
20793
|
+
import { readFileSync as readFileSync14, readdirSync as readdirSync11, existsSync as existsSync15, statSync as statSync13 } from "node:fs";
|
|
21063
20794
|
import { readFile as readFile14 } from "node:fs/promises";
|
|
21064
|
-
import { join as join27, resolve as
|
|
20795
|
+
import { join as join27, resolve as resolve14, sep as sep4 } from "node:path";
|
|
21065
20796
|
import { homedir as homedir20 } from "node:os";
|
|
21066
20797
|
function getPiSessionStateRoot() {
|
|
21067
20798
|
return process.env.PI_SESSIONS_DIR || join27(homedir20(), ".pi", "agent", "sessions");
|
|
@@ -21072,20 +20803,20 @@ function isSafeSessionId(sessionId) {
|
|
|
21072
20803
|
function findPiTranscript(sessionId) {
|
|
21073
20804
|
if (!isSafeSessionId(sessionId))
|
|
21074
20805
|
return null;
|
|
21075
|
-
const root =
|
|
20806
|
+
const root = resolve14(getPiSessionStateRoot());
|
|
21076
20807
|
let cwdDirs;
|
|
21077
20808
|
try {
|
|
21078
|
-
cwdDirs =
|
|
20809
|
+
cwdDirs = readdirSync11(root);
|
|
21079
20810
|
} catch {
|
|
21080
20811
|
return null;
|
|
21081
20812
|
}
|
|
21082
20813
|
for (const cwdDir of cwdDirs) {
|
|
21083
|
-
const cwdPath =
|
|
20814
|
+
const cwdPath = resolve14(root, cwdDir);
|
|
21084
20815
|
if (!cwdPath.startsWith(`${root}${sep4}`))
|
|
21085
20816
|
continue;
|
|
21086
20817
|
let files;
|
|
21087
20818
|
try {
|
|
21088
|
-
files =
|
|
20819
|
+
files = readdirSync11(cwdPath);
|
|
21089
20820
|
} catch {
|
|
21090
20821
|
continue;
|
|
21091
20822
|
}
|
|
@@ -21093,10 +20824,10 @@ function findPiTranscript(sessionId) {
|
|
|
21093
20824
|
const m = SESSION_FILE_RE2.exec(f);
|
|
21094
20825
|
if (!m || m[1].toLowerCase() !== sessionId.toLowerCase())
|
|
21095
20826
|
continue;
|
|
21096
|
-
const candidate =
|
|
20827
|
+
const candidate = resolve14(cwdPath, f);
|
|
21097
20828
|
if (!candidate.startsWith(`${cwdPath}${sep4}`))
|
|
21098
20829
|
continue;
|
|
21099
|
-
if (
|
|
20830
|
+
if (existsSync15(candidate))
|
|
21100
20831
|
return candidate;
|
|
21101
20832
|
}
|
|
21102
20833
|
}
|
|
@@ -21499,14 +21230,53 @@ var init_pack_failclosed = __esm(() => {
|
|
|
21499
21230
|
]);
|
|
21500
21231
|
});
|
|
21501
21232
|
|
|
21233
|
+
// lib/atomic-write.ts
|
|
21234
|
+
import {
|
|
21235
|
+
chmodSync as chmodSync2,
|
|
21236
|
+
existsSync as existsSync16,
|
|
21237
|
+
mkdirSync as mkdirSync8,
|
|
21238
|
+
renameSync as renameSync4,
|
|
21239
|
+
rmSync as rmSync3,
|
|
21240
|
+
statSync as statSync14,
|
|
21241
|
+
writeFileSync as writeFileSync7
|
|
21242
|
+
} from "node:fs";
|
|
21243
|
+
import { dirname as dirname8 } from "node:path";
|
|
21244
|
+
import { randomBytes } from "node:crypto";
|
|
21245
|
+
function writeJsonAtomically(filePath, value, opts = {}) {
|
|
21246
|
+
const mode = opts.mode ?? 384;
|
|
21247
|
+
const dirMode = opts.dirMode ?? 448;
|
|
21248
|
+
const dir = dirname8(filePath);
|
|
21249
|
+
if (!existsSync16(dir))
|
|
21250
|
+
mkdirSync8(dir, { recursive: true, mode: dirMode });
|
|
21251
|
+
const tmp = `${filePath}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
|
|
21252
|
+
try {
|
|
21253
|
+
writeFileSync7(tmp, JSON.stringify(value, null, 2), { mode });
|
|
21254
|
+
try {
|
|
21255
|
+
if ((statSync14(tmp).mode & 63) !== 0)
|
|
21256
|
+
chmodSync2(tmp, mode);
|
|
21257
|
+
} catch {}
|
|
21258
|
+
renameSync4(tmp, filePath);
|
|
21259
|
+
try {
|
|
21260
|
+
if ((statSync14(filePath).mode & 63) !== 0)
|
|
21261
|
+
chmodSync2(filePath, mode);
|
|
21262
|
+
} catch {}
|
|
21263
|
+
} catch (err) {
|
|
21264
|
+
try {
|
|
21265
|
+
rmSync3(tmp, { force: true });
|
|
21266
|
+
} catch {}
|
|
21267
|
+
throw err;
|
|
21268
|
+
}
|
|
21269
|
+
}
|
|
21270
|
+
var init_atomic_write = () => {};
|
|
21271
|
+
|
|
21502
21272
|
// src/hooks/session-pause.ts
|
|
21503
|
-
import { existsSync as
|
|
21273
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync9, readdirSync as readdirSync12, readFileSync as readFileSync15, rmSync as rmSync4 } from "node:fs";
|
|
21504
21274
|
import { createHash as createHash6 } from "node:crypto";
|
|
21505
|
-
import { join as join28, resolve as
|
|
21275
|
+
import { join as join28, resolve as resolve15 } from "node:path";
|
|
21506
21276
|
function pauseStateDir() {
|
|
21507
21277
|
const override = process.env.FAILPROOFAI_STATE_DIR;
|
|
21508
21278
|
if (override)
|
|
21509
|
-
return
|
|
21279
|
+
return resolve15(override, "sessions");
|
|
21510
21280
|
return sessionPauseDir();
|
|
21511
21281
|
}
|
|
21512
21282
|
function pauseFilePath(sessionId) {
|
|
@@ -21567,9 +21337,9 @@ function readActivePause(sessionId, now = Date.now()) {
|
|
|
21567
21337
|
return null;
|
|
21568
21338
|
try {
|
|
21569
21339
|
const path = pauseFilePath(sessionId);
|
|
21570
|
-
if (!
|
|
21340
|
+
if (!existsSync17(path))
|
|
21571
21341
|
return null;
|
|
21572
|
-
const stored = parseStored(JSON.parse(
|
|
21342
|
+
const stored = parseStored(JSON.parse(readFileSync15(path, "utf8")));
|
|
21573
21343
|
if (!stored)
|
|
21574
21344
|
return null;
|
|
21575
21345
|
if (stored.expiresAt <= now)
|
|
@@ -21592,16 +21362,16 @@ function writePause(opts) {
|
|
|
21592
21362
|
setBy: opts.setBy ?? "cli",
|
|
21593
21363
|
...opts.cwd ? { cwd: opts.cwd } : {}
|
|
21594
21364
|
};
|
|
21595
|
-
|
|
21365
|
+
mkdirSync9(pauseStateDir(), { recursive: true, mode: 448 });
|
|
21596
21366
|
writeJsonAtomically(pauseFilePath(opts.sessionId), { schemaVersion: SCHEMA_VERSION, ...pause });
|
|
21597
21367
|
return pause;
|
|
21598
21368
|
}
|
|
21599
21369
|
function clearPause(sessionId) {
|
|
21600
21370
|
const path = pauseFilePath(sessionId);
|
|
21601
|
-
if (!
|
|
21371
|
+
if (!existsSync17(path))
|
|
21602
21372
|
return false;
|
|
21603
21373
|
try {
|
|
21604
|
-
|
|
21374
|
+
rmSync4(path);
|
|
21605
21375
|
return true;
|
|
21606
21376
|
} catch {
|
|
21607
21377
|
return false;
|
|
@@ -21609,12 +21379,12 @@ function clearPause(sessionId) {
|
|
|
21609
21379
|
}
|
|
21610
21380
|
function listActivePauses(now = Date.now()) {
|
|
21611
21381
|
const dir = pauseStateDir();
|
|
21612
|
-
if (!
|
|
21382
|
+
if (!existsSync17(dir))
|
|
21613
21383
|
return [];
|
|
21614
21384
|
const out = [];
|
|
21615
21385
|
let names;
|
|
21616
21386
|
try {
|
|
21617
|
-
names =
|
|
21387
|
+
names = readdirSync12(dir);
|
|
21618
21388
|
} catch {
|
|
21619
21389
|
return [];
|
|
21620
21390
|
}
|
|
@@ -21622,7 +21392,7 @@ function listActivePauses(now = Date.now()) {
|
|
|
21622
21392
|
if (!name.endsWith(".json"))
|
|
21623
21393
|
continue;
|
|
21624
21394
|
try {
|
|
21625
|
-
const stored = parseStored(JSON.parse(
|
|
21395
|
+
const stored = parseStored(JSON.parse(readFileSync15(join28(dir, name), "utf8")));
|
|
21626
21396
|
if (!stored || stored.expiresAt <= now)
|
|
21627
21397
|
continue;
|
|
21628
21398
|
const { schemaVersion: _ignored, ...pause } = stored;
|
|
@@ -21663,17 +21433,17 @@ var init_session_pause = __esm(() => {
|
|
|
21663
21433
|
import { createHash as createHash7 } from "node:crypto";
|
|
21664
21434
|
import {
|
|
21665
21435
|
chmodSync as chmodSync3,
|
|
21666
|
-
existsSync as
|
|
21667
|
-
mkdirSync as
|
|
21668
|
-
readdirSync as
|
|
21669
|
-
readFileSync as
|
|
21436
|
+
existsSync as existsSync18,
|
|
21437
|
+
mkdirSync as mkdirSync10,
|
|
21438
|
+
readdirSync as readdirSync13,
|
|
21439
|
+
readFileSync as readFileSync16,
|
|
21670
21440
|
renameSync as renameSync5,
|
|
21671
|
-
rmSync as
|
|
21672
|
-
statSync as
|
|
21673
|
-
writeFileSync as
|
|
21441
|
+
rmSync as rmSync5,
|
|
21442
|
+
statSync as statSync15,
|
|
21443
|
+
writeFileSync as writeFileSync8
|
|
21674
21444
|
} from "node:fs";
|
|
21675
21445
|
import { createRequire as createRequire2 } from "node:module";
|
|
21676
|
-
import { dirname as
|
|
21446
|
+
import { dirname as dirname9, resolve as resolve16 } from "node:path";
|
|
21677
21447
|
import { gunzipSync } from "node:zlib";
|
|
21678
21448
|
function baseUrl2() {
|
|
21679
21449
|
return (process.env.FAILPROOFAI_DAEMON_BASE_URL || DEFAULT_BASE_URL2).replace(/\/+$/, "");
|
|
@@ -21682,7 +21452,7 @@ function daemonBinaryDir() {
|
|
|
21682
21452
|
return binDir();
|
|
21683
21453
|
}
|
|
21684
21454
|
function installedBinaryPath(ver = version2) {
|
|
21685
|
-
return
|
|
21455
|
+
return resolve16(daemonBinaryDir(), `failproofaid-${ver}`);
|
|
21686
21456
|
}
|
|
21687
21457
|
function daemonAssetUrl(key, ver = version2) {
|
|
21688
21458
|
return `${baseUrl2()}/v${ver}/failproofaid-${key}.gz`;
|
|
@@ -21699,35 +21469,35 @@ function npmPlatformBinaryPath(key) {
|
|
|
21699
21469
|
return null;
|
|
21700
21470
|
const name = platformPackageName(key);
|
|
21701
21471
|
try {
|
|
21702
|
-
const requireFromRoot = createRequire2(
|
|
21703
|
-
const found = platformPackageBinary(
|
|
21472
|
+
const requireFromRoot = createRequire2(resolve16(packageRoot, "package.json"));
|
|
21473
|
+
const found = platformPackageBinary(dirname9(requireFromRoot.resolve(`${name}/package.json`)));
|
|
21704
21474
|
if (found)
|
|
21705
21475
|
return found;
|
|
21706
21476
|
} catch {}
|
|
21707
|
-
return platformPackageBinary(
|
|
21477
|
+
return platformPackageBinary(resolve16(packageRoot, "node_modules", name));
|
|
21708
21478
|
}
|
|
21709
21479
|
function platformPackageBinary(dir) {
|
|
21710
21480
|
try {
|
|
21711
|
-
const manifest = JSON.parse(
|
|
21481
|
+
const manifest = JSON.parse(readFileSync16(resolve16(dir, "package.json"), "utf8"));
|
|
21712
21482
|
if (manifest.version !== version2)
|
|
21713
21483
|
return null;
|
|
21714
21484
|
} catch {
|
|
21715
21485
|
return null;
|
|
21716
21486
|
}
|
|
21717
|
-
const candidate =
|
|
21718
|
-
return
|
|
21487
|
+
const candidate = resolve16(dir, "bin", "failproofaid");
|
|
21488
|
+
return existsSync18(candidate) ? candidate : null;
|
|
21719
21489
|
}
|
|
21720
21490
|
function pruneOldDaemonBinaries(keep = 2) {
|
|
21721
21491
|
const removed = [];
|
|
21722
21492
|
try {
|
|
21723
21493
|
const dir = daemonBinaryDir();
|
|
21724
|
-
const entries =
|
|
21725
|
-
const full =
|
|
21726
|
-
return { full, mtime:
|
|
21494
|
+
const entries = readdirSync13(dir).filter((f) => f.startsWith("failproofaid-") && !f.endsWith(".tmp")).map((f) => {
|
|
21495
|
+
const full = resolve16(dir, f);
|
|
21496
|
+
return { full, mtime: statSync15(full).mtimeMs };
|
|
21727
21497
|
}).sort((a, b) => b.mtime - a.mtime);
|
|
21728
21498
|
for (const stale of entries.slice(keep)) {
|
|
21729
21499
|
try {
|
|
21730
|
-
|
|
21500
|
+
rmSync5(stale.full, { force: true });
|
|
21731
21501
|
removed.push(stale.full);
|
|
21732
21502
|
} catch {}
|
|
21733
21503
|
}
|
|
@@ -21738,13 +21508,13 @@ function installBinaryBytes(binary) {
|
|
|
21738
21508
|
const target = installedBinaryPath();
|
|
21739
21509
|
const tempPath = `${target}.${process.pid}.tmp`;
|
|
21740
21510
|
try {
|
|
21741
|
-
|
|
21742
|
-
|
|
21511
|
+
mkdirSync10(daemonBinaryDir(), { recursive: true });
|
|
21512
|
+
writeFileSync8(tempPath, binary);
|
|
21743
21513
|
chmodSync3(tempPath, 493);
|
|
21744
21514
|
renameSync5(tempPath, target);
|
|
21745
21515
|
return target;
|
|
21746
21516
|
} catch (err) {
|
|
21747
|
-
|
|
21517
|
+
rmSync5(tempPath, { force: true });
|
|
21748
21518
|
throw err;
|
|
21749
21519
|
}
|
|
21750
21520
|
}
|
|
@@ -21758,7 +21528,7 @@ function installFromNpmPackage(key) {
|
|
|
21758
21528
|
if (!source)
|
|
21759
21529
|
return { error: `${platformPackageName(key)} is not installed` };
|
|
21760
21530
|
try {
|
|
21761
|
-
const bytes =
|
|
21531
|
+
const bytes = readFileSync16(source);
|
|
21762
21532
|
const mismatch = binaryDigestMismatch(expectedNpmBinaryDigest(key), bytes, source);
|
|
21763
21533
|
if (mismatch)
|
|
21764
21534
|
return { error: mismatch };
|
|
@@ -21793,7 +21563,7 @@ function digestFor2(manifest, assetName) {
|
|
|
21793
21563
|
}
|
|
21794
21564
|
async function downloadFailproofaidBinary(key) {
|
|
21795
21565
|
const target = installedBinaryPath();
|
|
21796
|
-
if (
|
|
21566
|
+
if (existsSync18(target))
|
|
21797
21567
|
return { path: target };
|
|
21798
21568
|
if (process.env.FAILPROOFAI_NO_DOWNLOAD) {
|
|
21799
21569
|
return { error: "daemon downloads are disabled (FAILPROOFAI_NO_DOWNLOAD)" };
|
|
@@ -21827,10 +21597,10 @@ var init_daemon_download = __esm(() => {
|
|
|
21827
21597
|
|
|
21828
21598
|
// src/hooks/daemon-client.ts
|
|
21829
21599
|
import { createConnection as createConnection2 } from "node:net";
|
|
21830
|
-
import { existsSync as
|
|
21600
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
21831
21601
|
function daemonSocketPresent() {
|
|
21832
21602
|
try {
|
|
21833
|
-
return
|
|
21603
|
+
return existsSync19(socketPath2());
|
|
21834
21604
|
} catch {
|
|
21835
21605
|
return false;
|
|
21836
21606
|
}
|
|
@@ -21956,16 +21726,16 @@ var init_daemon_client2 = __esm(() => {
|
|
|
21956
21726
|
|
|
21957
21727
|
// src/hooks/daemon-service.ts
|
|
21958
21728
|
import {
|
|
21959
|
-
existsSync as
|
|
21960
|
-
mkdirSync as
|
|
21729
|
+
existsSync as existsSync20,
|
|
21730
|
+
mkdirSync as mkdirSync11,
|
|
21961
21731
|
mkdtempSync,
|
|
21962
|
-
readFileSync as
|
|
21963
|
-
writeFileSync as
|
|
21732
|
+
readFileSync as readFileSync17,
|
|
21733
|
+
writeFileSync as writeFileSync9,
|
|
21964
21734
|
unlinkSync as unlinkSync3,
|
|
21965
|
-
rmSync as
|
|
21735
|
+
rmSync as rmSync6
|
|
21966
21736
|
} from "node:fs";
|
|
21967
21737
|
import { homedir as homedir21, tmpdir as tmpdir2, userInfo } from "node:os";
|
|
21968
|
-
import { resolve as
|
|
21738
|
+
import { resolve as resolve17 } from "node:path";
|
|
21969
21739
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
21970
21740
|
function setDaemonConfigured(value, installedVersion) {
|
|
21971
21741
|
try {
|
|
@@ -21987,13 +21757,13 @@ function resolveFailproofaidBinaryPath() {
|
|
|
21987
21757
|
if (process.env.FAILPROOFAI_DAEMON_BINARY)
|
|
21988
21758
|
return process.env.FAILPROOFAI_DAEMON_BINARY;
|
|
21989
21759
|
const downloaded = installedBinaryPath();
|
|
21990
|
-
if (
|
|
21760
|
+
if (existsSync20(downloaded))
|
|
21991
21761
|
return downloaded;
|
|
21992
21762
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
21993
21763
|
if (packageRoot) {
|
|
21994
21764
|
for (const profile of ["release", "debug"]) {
|
|
21995
|
-
const candidate =
|
|
21996
|
-
if (
|
|
21765
|
+
const candidate = resolve17(packageRoot, "target", profile, "failproofaid");
|
|
21766
|
+
if (existsSync20(candidate))
|
|
21997
21767
|
return candidate;
|
|
21998
21768
|
}
|
|
21999
21769
|
}
|
|
@@ -22023,8 +21793,8 @@ function resolveWorkerCommand() {
|
|
|
22023
21793
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
22024
21794
|
if (!packageRoot)
|
|
22025
21795
|
return null;
|
|
22026
|
-
const workerScript =
|
|
22027
|
-
if (!
|
|
21796
|
+
const workerScript = resolve17(packageRoot, "dist", "worker.mjs");
|
|
21797
|
+
if (!existsSync20(workerScript))
|
|
22028
21798
|
return null;
|
|
22029
21799
|
return `${shellQuote(process.execPath)} ${shellQuote(workerScript)}`;
|
|
22030
21800
|
}
|
|
@@ -22034,8 +21804,8 @@ function resolveCliCommand() {
|
|
|
22034
21804
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
22035
21805
|
if (!packageRoot)
|
|
22036
21806
|
return null;
|
|
22037
|
-
const cliScript =
|
|
22038
|
-
if (!
|
|
21807
|
+
const cliScript = resolve17(packageRoot, "dist", "cli.mjs");
|
|
21808
|
+
if (!existsSync20(cliScript))
|
|
22039
21809
|
return null;
|
|
22040
21810
|
return `${shellQuote(process.execPath)} ${shellQuote(cliScript)}`;
|
|
22041
21811
|
}
|
|
@@ -22048,8 +21818,8 @@ function workerScriptPath() {
|
|
|
22048
21818
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
22049
21819
|
if (!packageRoot)
|
|
22050
21820
|
return null;
|
|
22051
|
-
const workerScript =
|
|
22052
|
-
return
|
|
21821
|
+
const workerScript = resolve17(packageRoot, "dist", "worker.mjs");
|
|
21822
|
+
return existsSync20(workerScript) ? workerScript : null;
|
|
22053
21823
|
}
|
|
22054
21824
|
function assertUnitSafe(value, field) {
|
|
22055
21825
|
if (UNIT_UNSAFE_RE.test(value)) {
|
|
@@ -22075,10 +21845,10 @@ function systemdUnitDir() {
|
|
|
22075
21845
|
return process.env.FAILPROOFAI_SYSTEMD_DIR || "/etc/systemd/system";
|
|
22076
21846
|
}
|
|
22077
21847
|
function systemdUnitPath(user = serviceUser()) {
|
|
22078
|
-
return
|
|
21848
|
+
return resolve17(systemdUnitDir(), systemdUnitName(user));
|
|
22079
21849
|
}
|
|
22080
21850
|
function legacySystemdUserUnitPath() {
|
|
22081
|
-
return
|
|
21851
|
+
return resolve17(homedir21(), ".config", "systemd", "user", "failproofaid.service");
|
|
22082
21852
|
}
|
|
22083
21853
|
function launchdLabel(user = serviceUser()) {
|
|
22084
21854
|
return `ai.failproof.failproofaid.${user}`;
|
|
@@ -22087,7 +21857,7 @@ function launchdPlistPath(user = serviceUser()) {
|
|
|
22087
21857
|
return `/Library/LaunchDaemons/${launchdLabel(user)}.plist`;
|
|
22088
21858
|
}
|
|
22089
21859
|
function legacyLaunchAgentPlistPath() {
|
|
22090
|
-
return
|
|
21860
|
+
return resolve17(homedir21(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
|
|
22091
21861
|
}
|
|
22092
21862
|
function legacySharedLaunchDaemonPath() {
|
|
22093
21863
|
return "/Library/LaunchDaemons/ai.failproof.failproofaid.plist";
|
|
@@ -22135,20 +21905,20 @@ function runPrivileged(command, args) {
|
|
|
22135
21905
|
execFileSync2(cmd, argv, { stdio: "ignore", timeout: SERVICE_CMD_TIMEOUT_MS });
|
|
22136
21906
|
}
|
|
22137
21907
|
function writePrivilegedFile(destination, contents, mode = "0644") {
|
|
22138
|
-
const stagingDir = mkdtempSync(
|
|
22139
|
-
const staging =
|
|
21908
|
+
const stagingDir = mkdtempSync(resolve17(tmpdir2(), "failproofaid-stage-"));
|
|
21909
|
+
const staging = resolve17(stagingDir, "service-definition");
|
|
22140
21910
|
try {
|
|
22141
|
-
|
|
21911
|
+
writeFileSync9(staging, contents, "utf8");
|
|
22142
21912
|
runPrivileged("install", ["-m", mode, staging, destination]);
|
|
22143
21913
|
} finally {
|
|
22144
|
-
|
|
21914
|
+
rmSync6(stagingDir, { recursive: true, force: true });
|
|
22145
21915
|
}
|
|
22146
21916
|
}
|
|
22147
21917
|
function removeLegacyUserService() {
|
|
22148
21918
|
try {
|
|
22149
21919
|
if (process.platform === "linux") {
|
|
22150
21920
|
const legacy = legacySystemdUserUnitPath();
|
|
22151
|
-
if (!
|
|
21921
|
+
if (!existsSync20(legacy))
|
|
22152
21922
|
return;
|
|
22153
21923
|
try {
|
|
22154
21924
|
execFileSync2("systemctl", ["--user", "disable", "--now", "failproofaid.service"], {
|
|
@@ -22165,7 +21935,7 @@ function removeLegacyUserService() {
|
|
|
22165
21935
|
} catch {}
|
|
22166
21936
|
} else {
|
|
22167
21937
|
const legacyAgent = legacyLaunchAgentPlistPath();
|
|
22168
|
-
if (
|
|
21938
|
+
if (existsSync20(legacyAgent)) {
|
|
22169
21939
|
try {
|
|
22170
21940
|
execFileSync2("launchctl", ["unload", "-w", legacyAgent], {
|
|
22171
21941
|
stdio: "ignore",
|
|
@@ -22175,7 +21945,7 @@ function removeLegacyUserService() {
|
|
|
22175
21945
|
unlinkSync3(legacyAgent);
|
|
22176
21946
|
}
|
|
22177
21947
|
const legacyDaemon = legacySharedLaunchDaemonPath();
|
|
22178
|
-
if (
|
|
21948
|
+
if (existsSync20(legacyDaemon)) {
|
|
22179
21949
|
try {
|
|
22180
21950
|
runPrivileged("launchctl", ["unload", "-w", legacyDaemon]);
|
|
22181
21951
|
} catch {}
|
|
@@ -22192,7 +21962,7 @@ function systemdUnitContents(binaryPath, workerCmd, cliCmd = null) {
|
|
|
22192
21962
|
const user = assertUnitSafe(serviceUser(), "User");
|
|
22193
21963
|
assertUnitSafe(binaryPath, "ExecStart");
|
|
22194
21964
|
assertUnitSafe(homedir21(), "HOME");
|
|
22195
|
-
const conditionPaths = [binaryPath, workerScriptPath()].filter((p) => typeof p === "string" &&
|
|
21965
|
+
const conditionPaths = [binaryPath, workerScriptPath()].filter((p) => typeof p === "string" && existsSync20(p));
|
|
22196
21966
|
const conditionLines = conditionPaths.map((p) => `ConditionPathExists=${assertUnitSafe(p, "ConditionPathExists")}
|
|
22197
21967
|
`).join("");
|
|
22198
21968
|
return `[Unit]
|
|
@@ -22253,9 +22023,9 @@ ${env.map(([key, value]) => ` <key>${key}</key>
|
|
|
22253
22023
|
<key>UserName</key>
|
|
22254
22024
|
<string>${escapeXml(serviceUser())}</string>
|
|
22255
22025
|
${envBlock} <key>StandardOutPath</key>
|
|
22256
|
-
<string>${escapeXml(
|
|
22026
|
+
<string>${escapeXml(resolve17(logDir, "failproofaid.log"))}</string>
|
|
22257
22027
|
<key>StandardErrorPath</key>
|
|
22258
|
-
<string>${escapeXml(
|
|
22028
|
+
<string>${escapeXml(resolve17(logDir, "failproofaid.err.log"))}</string>
|
|
22259
22029
|
</dict>
|
|
22260
22030
|
</plist>
|
|
22261
22031
|
`;
|
|
@@ -22301,7 +22071,7 @@ async function installDaemonService() {
|
|
|
22301
22071
|
} else {
|
|
22302
22072
|
const plistPath = launchdPlistPath();
|
|
22303
22073
|
const logDir = logsDir();
|
|
22304
|
-
|
|
22074
|
+
mkdirSync11(logDir, { recursive: true });
|
|
22305
22075
|
try {
|
|
22306
22076
|
runPrivileged("launchctl", ["unload", plistPath]);
|
|
22307
22077
|
} catch {}
|
|
@@ -22387,10 +22157,10 @@ function readInstalledServiceDefinition() {
|
|
|
22387
22157
|
if (!isDaemonSupportedPlatform())
|
|
22388
22158
|
return null;
|
|
22389
22159
|
const path = daemonServiceFilePath();
|
|
22390
|
-
if (!path || !
|
|
22160
|
+
if (!path || !existsSync20(path))
|
|
22391
22161
|
return null;
|
|
22392
22162
|
try {
|
|
22393
|
-
return
|
|
22163
|
+
return readFileSync17(path, "utf8");
|
|
22394
22164
|
} catch {
|
|
22395
22165
|
return null;
|
|
22396
22166
|
}
|
|
@@ -22499,7 +22269,7 @@ async function ensureDaemonServiceCurrent() {
|
|
|
22499
22269
|
restartSystemdUnit();
|
|
22500
22270
|
} else {
|
|
22501
22271
|
const plistPath = launchdPlistPath();
|
|
22502
|
-
|
|
22272
|
+
mkdirSync11(logDir, { recursive: true });
|
|
22503
22273
|
previous = definition;
|
|
22504
22274
|
try {
|
|
22505
22275
|
runPrivileged("launchctl", ["unload", plistPath]);
|
|
@@ -22523,7 +22293,7 @@ async function uninstallDaemonService() {
|
|
|
22523
22293
|
try {
|
|
22524
22294
|
if (process.platform === "linux") {
|
|
22525
22295
|
const unitPath = systemdUnitPath();
|
|
22526
|
-
if (!
|
|
22296
|
+
if (!existsSync20(unitPath))
|
|
22527
22297
|
return;
|
|
22528
22298
|
try {
|
|
22529
22299
|
runPrivileged("systemctl", ["disable", "--now", systemdUnitName()]);
|
|
@@ -22534,7 +22304,7 @@ async function uninstallDaemonService() {
|
|
|
22534
22304
|
} catch {}
|
|
22535
22305
|
} else {
|
|
22536
22306
|
const plistPath = launchdPlistPath();
|
|
22537
|
-
if (!
|
|
22307
|
+
if (!existsSync20(plistPath))
|
|
22538
22308
|
return;
|
|
22539
22309
|
try {
|
|
22540
22310
|
runPrivileged("launchctl", ["unload", "-w", plistPath]);
|
|
@@ -22551,7 +22321,7 @@ function daemonVersionSkew() {
|
|
|
22551
22321
|
const recorded = readVersionFile()?.daemon;
|
|
22552
22322
|
if (!recorded)
|
|
22553
22323
|
return null;
|
|
22554
|
-
if (!
|
|
22324
|
+
if (!existsSync20(installedBinaryPath(recorded)))
|
|
22555
22325
|
return null;
|
|
22556
22326
|
return recorded === version2 ? null : { installed: recorded, expected: version2 };
|
|
22557
22327
|
}
|
|
@@ -22569,7 +22339,7 @@ function daemonServiceStatus() {
|
|
|
22569
22339
|
if (!isDaemonSupportedPlatform())
|
|
22570
22340
|
return "unsupported-platform";
|
|
22571
22341
|
if (process.platform === "linux") {
|
|
22572
|
-
if (!
|
|
22342
|
+
if (!existsSync20(systemdUnitPath()))
|
|
22573
22343
|
return "not-installed";
|
|
22574
22344
|
try {
|
|
22575
22345
|
const out = execFileSync2("systemctl", ["is-active", systemdUnitName()], {
|
|
@@ -22582,7 +22352,7 @@ function daemonServiceStatus() {
|
|
|
22582
22352
|
}
|
|
22583
22353
|
}
|
|
22584
22354
|
const plistPath = launchdPlistPath();
|
|
22585
|
-
if (!
|
|
22355
|
+
if (!existsSync20(plistPath))
|
|
22586
22356
|
return "not-installed";
|
|
22587
22357
|
try {
|
|
22588
22358
|
const root = typeof process.getuid === "function" && process.getuid() === 0;
|
|
@@ -22614,48 +22384,48 @@ var init_daemon_service = __esm(() => {
|
|
|
22614
22384
|
// src/hooks/fp-reset.ts
|
|
22615
22385
|
import {
|
|
22616
22386
|
copyFileSync,
|
|
22617
|
-
existsSync as
|
|
22618
|
-
mkdirSync as
|
|
22619
|
-
readFileSync as
|
|
22620
|
-
readdirSync as
|
|
22387
|
+
existsSync as existsSync21,
|
|
22388
|
+
mkdirSync as mkdirSync12,
|
|
22389
|
+
readFileSync as readFileSync18,
|
|
22390
|
+
readdirSync as readdirSync14,
|
|
22621
22391
|
renameSync as renameSync6,
|
|
22622
|
-
rmSync as
|
|
22392
|
+
rmSync as rmSync7,
|
|
22623
22393
|
rmdirSync,
|
|
22624
|
-
statSync as
|
|
22625
|
-
writeFileSync as
|
|
22394
|
+
statSync as statSync16,
|
|
22395
|
+
writeFileSync as writeFileSync10
|
|
22626
22396
|
} from "node:fs";
|
|
22627
|
-
import { dirname as
|
|
22397
|
+
import { dirname as dirname10, isAbsolute as isAbsolute3, relative as relative4, resolve as resolve18 } from "node:path";
|
|
22628
22398
|
function migrateConventionPolicies() {
|
|
22629
22399
|
const from = legacy.customPoliciesDir();
|
|
22630
|
-
if (!
|
|
22400
|
+
if (!existsSync21(from))
|
|
22631
22401
|
return [];
|
|
22632
22402
|
const moved = [];
|
|
22633
22403
|
const mergeInto = (dir, dest, prefix) => {
|
|
22634
22404
|
let entries;
|
|
22635
22405
|
try {
|
|
22636
|
-
entries =
|
|
22406
|
+
entries = readdirSync14(dir, { withFileTypes: true });
|
|
22637
22407
|
} catch {
|
|
22638
22408
|
return;
|
|
22639
22409
|
}
|
|
22640
22410
|
if (entries.length === 0)
|
|
22641
22411
|
return;
|
|
22642
22412
|
try {
|
|
22643
|
-
|
|
22413
|
+
mkdirSync12(dest, { recursive: true });
|
|
22644
22414
|
} catch {
|
|
22645
22415
|
return;
|
|
22646
22416
|
}
|
|
22647
22417
|
for (const entry of entries) {
|
|
22648
|
-
const source =
|
|
22649
|
-
const target =
|
|
22418
|
+
const source = resolve18(dir, entry.name);
|
|
22419
|
+
const target = resolve18(dest, entry.name);
|
|
22650
22420
|
const name = `${prefix}${entry.name}`;
|
|
22651
|
-
if (!
|
|
22421
|
+
if (!existsSync21(target)) {
|
|
22652
22422
|
try {
|
|
22653
22423
|
renameSync6(source, target);
|
|
22654
22424
|
moved.push(name);
|
|
22655
22425
|
} catch {}
|
|
22656
22426
|
continue;
|
|
22657
22427
|
}
|
|
22658
|
-
if (entry.isDirectory() &&
|
|
22428
|
+
if (entry.isDirectory() && statSync16(target).isDirectory()) {
|
|
22659
22429
|
mergeInto(source, target, `${name}/`);
|
|
22660
22430
|
try {
|
|
22661
22431
|
rmdirSync(source);
|
|
@@ -22675,23 +22445,23 @@ function migrateLegacySpool() {
|
|
|
22675
22445
|
[legacy.spoolDir(), spoolDir()],
|
|
22676
22446
|
[legacy.failedDir(), failedDir()]
|
|
22677
22447
|
]) {
|
|
22678
|
-
if (!
|
|
22448
|
+
if (!existsSync21(from))
|
|
22679
22449
|
continue;
|
|
22680
22450
|
try {
|
|
22681
|
-
|
|
22682
|
-
for (const entry of
|
|
22451
|
+
mkdirSync12(to, { recursive: true });
|
|
22452
|
+
for (const entry of readdirSync14(from, { withFileTypes: true })) {
|
|
22683
22453
|
if (!entry.isFile())
|
|
22684
22454
|
continue;
|
|
22685
22455
|
let name = entry.name;
|
|
22686
22456
|
let n = 0;
|
|
22687
|
-
while (
|
|
22457
|
+
while (existsSync21(resolve18(to, name)))
|
|
22688
22458
|
name = `legacy-${n++}-${entry.name}`;
|
|
22689
22459
|
try {
|
|
22690
|
-
renameSync6(
|
|
22460
|
+
renameSync6(resolve18(from, entry.name), resolve18(to, name));
|
|
22691
22461
|
moved.push(name);
|
|
22692
22462
|
} catch {
|
|
22693
22463
|
try {
|
|
22694
|
-
copyFileSync(
|
|
22464
|
+
copyFileSync(resolve18(from, entry.name), resolve18(to, name));
|
|
22695
22465
|
moved.push(name);
|
|
22696
22466
|
} catch {}
|
|
22697
22467
|
}
|
|
@@ -22702,24 +22472,24 @@ function migrateLegacySpool() {
|
|
|
22702
22472
|
}
|
|
22703
22473
|
function migrateHookActivity() {
|
|
22704
22474
|
const from = legacy.hookActivityDir();
|
|
22705
|
-
if (!
|
|
22475
|
+
if (!existsSync21(from))
|
|
22706
22476
|
return [];
|
|
22707
22477
|
const moved = [];
|
|
22708
22478
|
try {
|
|
22709
|
-
const entries =
|
|
22479
|
+
const entries = readdirSync14(from, { withFileTypes: true }).filter((e) => e.isFile() && e.name.endsWith(".jsonl"));
|
|
22710
22480
|
if (entries.length === 0)
|
|
22711
22481
|
return [];
|
|
22712
22482
|
const to = hookActivityDir();
|
|
22713
|
-
|
|
22483
|
+
mkdirSync12(to, { recursive: true });
|
|
22714
22484
|
const stamp = Date.now();
|
|
22715
22485
|
let seq = 0;
|
|
22716
22486
|
for (const entry of entries) {
|
|
22717
|
-
const source =
|
|
22487
|
+
const source = resolve18(from, entry.name);
|
|
22718
22488
|
let name = entry.name === "current.jsonl" ? `page-${stamp}-${seq++}.jsonl` : entry.name;
|
|
22719
|
-
let target =
|
|
22720
|
-
while (
|
|
22489
|
+
let target = resolve18(to, name);
|
|
22490
|
+
while (existsSync21(target)) {
|
|
22721
22491
|
name = `page-${stamp}-${seq++}.jsonl`;
|
|
22722
|
-
target =
|
|
22492
|
+
target = resolve18(to, name);
|
|
22723
22493
|
}
|
|
22724
22494
|
try {
|
|
22725
22495
|
renameSync6(source, target);
|
|
@@ -22743,7 +22513,7 @@ function retirePolicyConfigKeys() {
|
|
|
22743
22513
|
const at = globalPolicyConfigFile();
|
|
22744
22514
|
let parsed;
|
|
22745
22515
|
try {
|
|
22746
|
-
const raw = JSON.parse(
|
|
22516
|
+
const raw = JSON.parse(readFileSync18(at, "utf8"));
|
|
22747
22517
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
22748
22518
|
return [];
|
|
22749
22519
|
parsed = raw;
|
|
@@ -22757,9 +22527,9 @@ function retirePolicyConfigKeys() {
|
|
|
22757
22527
|
delete parsed[key];
|
|
22758
22528
|
try {
|
|
22759
22529
|
if (Object.keys(parsed).length === 0)
|
|
22760
|
-
|
|
22530
|
+
rmSync7(at, { force: true });
|
|
22761
22531
|
else
|
|
22762
|
-
|
|
22532
|
+
writeFileSync10(at, JSON.stringify(parsed, null, 2) + `
|
|
22763
22533
|
`, "utf8");
|
|
22764
22534
|
} catch {
|
|
22765
22535
|
return [];
|
|
@@ -22767,12 +22537,12 @@ function retirePolicyConfigKeys() {
|
|
|
22767
22537
|
return [...removed];
|
|
22768
22538
|
}
|
|
22769
22539
|
function readCarriedPolicyConfig() {
|
|
22770
|
-
const from =
|
|
22771
|
-
if (!
|
|
22540
|
+
const from = resolve18(legacy.localPoliciesDir(), "policies-config.json");
|
|
22541
|
+
if (!existsSync21(from))
|
|
22772
22542
|
return null;
|
|
22773
22543
|
let parsed;
|
|
22774
22544
|
try {
|
|
22775
|
-
parsed = JSON.parse(
|
|
22545
|
+
parsed = JSON.parse(readFileSync18(from, "utf8"));
|
|
22776
22546
|
} catch {
|
|
22777
22547
|
return null;
|
|
22778
22548
|
}
|
|
@@ -22797,11 +22567,11 @@ function rewriteCarriedCustomPaths(carried) {
|
|
|
22797
22567
|
const repoint = (value) => {
|
|
22798
22568
|
if (typeof value !== "string" || value === "")
|
|
22799
22569
|
return value;
|
|
22800
|
-
const abs =
|
|
22570
|
+
const abs = resolve18(value);
|
|
22801
22571
|
const rel = relative4(fromDir, abs);
|
|
22802
22572
|
if (rel === "" || rel.startsWith("..") || isAbsolute3(rel))
|
|
22803
22573
|
return value;
|
|
22804
|
-
return
|
|
22574
|
+
return resolve18(toDir, rel);
|
|
22805
22575
|
};
|
|
22806
22576
|
if (Array.isArray(carried.customPoliciesPaths)) {
|
|
22807
22577
|
carried.customPoliciesPaths = carried.customPoliciesPaths.map(repoint);
|
|
@@ -22816,14 +22586,14 @@ function writeCarriedPolicyConfig(carried) {
|
|
|
22816
22586
|
const to = globalPolicyConfigFile();
|
|
22817
22587
|
let existing = {};
|
|
22818
22588
|
try {
|
|
22819
|
-
const parsed = JSON.parse(
|
|
22589
|
+
const parsed = JSON.parse(readFileSync18(to, "utf8"));
|
|
22820
22590
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
22821
22591
|
existing = parsed;
|
|
22822
22592
|
}
|
|
22823
22593
|
} catch {}
|
|
22824
22594
|
try {
|
|
22825
|
-
|
|
22826
|
-
|
|
22595
|
+
mkdirSync12(dirname10(to), { recursive: true });
|
|
22596
|
+
writeFileSync10(to, JSON.stringify({ ...existing, ...carried }, null, 2) + `
|
|
22827
22597
|
`, "utf8");
|
|
22828
22598
|
} catch {
|
|
22829
22599
|
return [];
|
|
@@ -22832,10 +22602,10 @@ function writeCarriedPolicyConfig(carried) {
|
|
|
22832
22602
|
}
|
|
22833
22603
|
function readCarriedTelemetryOptOut() {
|
|
22834
22604
|
const from = legacy.configToml();
|
|
22835
|
-
if (!
|
|
22605
|
+
if (!existsSync21(from))
|
|
22836
22606
|
return false;
|
|
22837
22607
|
try {
|
|
22838
|
-
const text =
|
|
22608
|
+
const text = readFileSync18(from, "utf8");
|
|
22839
22609
|
const start = text.search(/^\s*\[telemetry\]\s*$/m);
|
|
22840
22610
|
if (start === -1)
|
|
22841
22611
|
return false;
|
|
@@ -22887,26 +22657,26 @@ function parseLegacyToml(text) {
|
|
|
22887
22657
|
}
|
|
22888
22658
|
function readCarriedLegacyConfig() {
|
|
22889
22659
|
const from = legacy.configToml();
|
|
22890
|
-
if (!
|
|
22660
|
+
if (!existsSync21(from))
|
|
22891
22661
|
return null;
|
|
22892
22662
|
try {
|
|
22893
|
-
return projectConfig(parseLegacyToml(
|
|
22663
|
+
return projectConfig(parseLegacyToml(readFileSync18(from, "utf8")));
|
|
22894
22664
|
} catch {
|
|
22895
22665
|
return null;
|
|
22896
22666
|
}
|
|
22897
22667
|
}
|
|
22898
22668
|
function readCarriedLegacyCredentials() {
|
|
22899
22669
|
const toml = legacy.credentialsToml();
|
|
22900
|
-
if (
|
|
22670
|
+
if (existsSync21(toml)) {
|
|
22901
22671
|
try {
|
|
22902
|
-
const creds = projectCredentials(parseLegacyToml(
|
|
22672
|
+
const creds = projectCredentials(parseLegacyToml(readFileSync18(toml, "utf8")));
|
|
22903
22673
|
if (Object.keys(creds).length > 0)
|
|
22904
22674
|
return creds;
|
|
22905
22675
|
} catch {}
|
|
22906
22676
|
}
|
|
22907
22677
|
const readJson = (path) => {
|
|
22908
22678
|
try {
|
|
22909
|
-
const parsed = JSON.parse(
|
|
22679
|
+
const parsed = JSON.parse(readFileSync18(path, "utf8"));
|
|
22910
22680
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
22911
22681
|
} catch {
|
|
22912
22682
|
return null;
|
|
@@ -22940,10 +22710,10 @@ function resetHome(from, to = LAYOUT_VERSION) {
|
|
|
22940
22710
|
const spooled = migrateLegacySpool();
|
|
22941
22711
|
const removed = [];
|
|
22942
22712
|
for (const path of resettablePaths()) {
|
|
22943
|
-
if (!
|
|
22713
|
+
if (!existsSync21(path))
|
|
22944
22714
|
continue;
|
|
22945
22715
|
try {
|
|
22946
|
-
|
|
22716
|
+
rmSync7(path, { recursive: true, force: true });
|
|
22947
22717
|
removed.push(path);
|
|
22948
22718
|
} catch {}
|
|
22949
22719
|
}
|
|
@@ -22965,7 +22735,7 @@ function layoutWarningForHook() {
|
|
|
22965
22735
|
if (state.kind === "future") {
|
|
22966
22736
|
return `[failproofai] this directory was written by a newer version (layout ${state.found} vs ${LAYOUT_VERSION}) — policies are NOT being enforced. ` + `Upgrade failproofai.`;
|
|
22967
22737
|
}
|
|
22968
|
-
if (
|
|
22738
|
+
if (existsSync21(globalPolicyConfigFile()))
|
|
22969
22739
|
return null;
|
|
22970
22740
|
return `[failproofai] setup predates this version — global policies are NOT being enforced. ` + `Run \`failproofai config\` to re-create it.`;
|
|
22971
22741
|
}
|
|
@@ -23012,31 +22782,6 @@ function canonicalizeEventType(raw, cli) {
|
|
|
23012
22782
|
}
|
|
23013
22783
|
return raw;
|
|
23014
22784
|
}
|
|
23015
|
-
function attachLeakNotice(eventType, cli, outcome) {
|
|
23016
|
-
try {
|
|
23017
|
-
if (!canDeliverNotice(cli))
|
|
23018
|
-
return outcome;
|
|
23019
|
-
if (!cli)
|
|
23020
|
-
return outcome;
|
|
23021
|
-
const canonical = canonicalizeEventType(eventType, cli);
|
|
23022
|
-
if (canonical !== "Stop" && canonical !== "SessionStart")
|
|
23023
|
-
return outcome;
|
|
23024
|
-
const pending = pendingLeakNotice();
|
|
23025
|
-
if (pending.count === 0)
|
|
23026
|
-
return outcome;
|
|
23027
|
-
const shaped = shapeNotice(cli, leakNoticeText(pending.count), outcome.stdout);
|
|
23028
|
-
if (shaped.stdout === outcome.stdout && !shaped.stderr)
|
|
23029
|
-
return outcome;
|
|
23030
|
-
markLeakNoticeDelivered(pending.ids);
|
|
23031
|
-
return {
|
|
23032
|
-
exitCode: outcome.exitCode,
|
|
23033
|
-
stdout: shaped.stdout,
|
|
23034
|
-
stderr: outcome.stderr + shaped.stderr
|
|
23035
|
-
};
|
|
23036
|
-
} catch {
|
|
23037
|
-
return outcome;
|
|
23038
|
-
}
|
|
23039
|
-
}
|
|
23040
22785
|
async function runObserved(hook, ctx, hookName, eventType, cli) {
|
|
23041
22786
|
try {
|
|
23042
22787
|
return await Promise.race([
|
|
@@ -23339,12 +23084,7 @@ async function evaluateHookEvent(eventType, cli = "claude", stdinPayload, opts)
|
|
|
23339
23084
|
}
|
|
23340
23085
|
} catch {}
|
|
23341
23086
|
}
|
|
23342
|
-
|
|
23343
|
-
exitCode: result.exitCode,
|
|
23344
|
-
stdout: result.stdout,
|
|
23345
|
-
stderr: result.stderr
|
|
23346
|
-
});
|
|
23347
|
-
return withNotice;
|
|
23087
|
+
return { exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr };
|
|
23348
23088
|
} finally {
|
|
23349
23089
|
if (opts?.awaitTelemetryFlush ?? true) {
|
|
23350
23090
|
await flushHookTelemetry2();
|
|
@@ -23403,8 +23143,6 @@ var init_handler = __esm(() => {
|
|
|
23403
23143
|
init_custom_hooks_loader();
|
|
23404
23144
|
init_hook_activity_store();
|
|
23405
23145
|
init_delivery_health();
|
|
23406
|
-
init_notice();
|
|
23407
|
-
init_leak_notice();
|
|
23408
23146
|
init_hook_telemetry2();
|
|
23409
23147
|
init_resolve_permission_mode();
|
|
23410
23148
|
init_resolve_transcript_path();
|
|
@@ -24045,17 +23783,17 @@ var init_collector_config = __esm(() => {
|
|
|
24045
23783
|
});
|
|
24046
23784
|
|
|
24047
23785
|
// src/hooks/flush-cli.ts
|
|
24048
|
-
import { existsSync as
|
|
24049
|
-
import { dirname as
|
|
23786
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync13, writeFileSync as writeFileSync11, readdirSync as readdirSync15 } from "node:fs";
|
|
23787
|
+
import { dirname as dirname11, join as join29 } from "node:path";
|
|
24050
23788
|
function flushRequestPath(home) {
|
|
24051
23789
|
return join29(failproofaiHome(home), "state", "flush-request.json");
|
|
24052
23790
|
}
|
|
24053
23791
|
function spoolDirs(home) {
|
|
24054
23792
|
const root = spoolDir(home);
|
|
24055
|
-
if (!
|
|
23793
|
+
if (!existsSync22(root))
|
|
24056
23794
|
return [];
|
|
24057
23795
|
try {
|
|
24058
|
-
return
|
|
23796
|
+
return readdirSync15(root, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name !== "failed").map((e) => join29(root, e.name));
|
|
24059
23797
|
} catch {
|
|
24060
23798
|
return [];
|
|
24061
23799
|
}
|
|
@@ -24064,7 +23802,7 @@ function pendingBatches(home) {
|
|
|
24064
23802
|
let n = 0;
|
|
24065
23803
|
for (const dir of spoolDirs(home)) {
|
|
24066
23804
|
try {
|
|
24067
|
-
n +=
|
|
23805
|
+
n += readdirSync15(dir).filter((f) => f.endsWith(".jsonl")).length;
|
|
24068
23806
|
} catch {}
|
|
24069
23807
|
}
|
|
24070
23808
|
return n;
|
|
@@ -24121,8 +23859,8 @@ async function runFlushCommand(opts = {}) {
|
|
|
24121
23859
|
return { exitCode: 0, pending: 0, lines: ["Nothing spooled — everything already delivered."] };
|
|
24122
23860
|
}
|
|
24123
23861
|
const path = flushRequestPath(home);
|
|
24124
|
-
|
|
24125
|
-
|
|
23862
|
+
mkdirSync13(dirname11(path), { recursive: true });
|
|
23863
|
+
writeFileSync11(path, `${JSON.stringify({ requestedAtMs: Date.now() }, null, 2)}
|
|
24126
23864
|
`, {
|
|
24127
23865
|
mode: 384
|
|
24128
23866
|
});
|
|
@@ -24156,14 +23894,14 @@ var init_flush_cli = __esm(() => {
|
|
|
24156
23894
|
import {
|
|
24157
23895
|
chmodSync as chmodSync4,
|
|
24158
23896
|
copyFileSync as copyFileSync2,
|
|
24159
|
-
existsSync as
|
|
24160
|
-
mkdirSync as
|
|
24161
|
-
readFileSync as
|
|
23897
|
+
existsSync as existsSync23,
|
|
23898
|
+
mkdirSync as mkdirSync14,
|
|
23899
|
+
readFileSync as readFileSync19,
|
|
24162
23900
|
renameSync as renameSync7,
|
|
24163
|
-
rmSync as
|
|
24164
|
-
writeFileSync as
|
|
23901
|
+
rmSync as rmSync8,
|
|
23902
|
+
writeFileSync as writeFileSync12
|
|
24165
23903
|
} from "node:fs";
|
|
24166
|
-
import { basename as basename4, dirname as
|
|
23904
|
+
import { basename as basename4, dirname as dirname12, join as join30, resolve as resolve19 } from "node:path";
|
|
24167
23905
|
function migrateToLayout4() {
|
|
24168
23906
|
const moves = [
|
|
24169
23907
|
{ from: legacy.authJson(), to: auditSessionFile() },
|
|
@@ -24179,13 +23917,13 @@ function migrateToLayout4() {
|
|
|
24179
23917
|
}
|
|
24180
23918
|
const migrated = [];
|
|
24181
23919
|
for (const { from, to } of moves) {
|
|
24182
|
-
if (!
|
|
23920
|
+
if (!existsSync23(from))
|
|
24183
23921
|
continue;
|
|
24184
|
-
if (
|
|
24185
|
-
|
|
23922
|
+
if (existsSync23(to)) {
|
|
23923
|
+
rmSync8(from, { force: true });
|
|
24186
23924
|
continue;
|
|
24187
23925
|
}
|
|
24188
|
-
|
|
23926
|
+
mkdirSync14(dirname12(to), { recursive: true });
|
|
24189
23927
|
try {
|
|
24190
23928
|
renameSync7(from, to);
|
|
24191
23929
|
} catch {
|
|
@@ -24193,16 +23931,16 @@ function migrateToLayout4() {
|
|
|
24193
23931
|
copyFileSync2(from, to);
|
|
24194
23932
|
} catch (err) {
|
|
24195
23933
|
try {
|
|
24196
|
-
|
|
23934
|
+
rmSync8(to, { force: true });
|
|
24197
23935
|
} catch {}
|
|
24198
23936
|
throw err;
|
|
24199
23937
|
}
|
|
24200
|
-
|
|
23938
|
+
rmSync8(from, { force: true });
|
|
24201
23939
|
}
|
|
24202
23940
|
migrated.push(`${basename4(from)} → audit/${basename4(to)}`);
|
|
24203
23941
|
}
|
|
24204
23942
|
for (const secret of [auditSessionFile()]) {
|
|
24205
|
-
if (!
|
|
23943
|
+
if (!existsSync23(secret))
|
|
24206
23944
|
continue;
|
|
24207
23945
|
try {
|
|
24208
23946
|
chmodSync4(secret, 384);
|
|
@@ -24228,7 +23966,7 @@ function planMigration(from, registry = MIGRATIONS) {
|
|
|
24228
23966
|
}
|
|
24229
23967
|
function readLedger() {
|
|
24230
23968
|
try {
|
|
24231
|
-
const parsed = JSON.parse(
|
|
23969
|
+
const parsed = JSON.parse(readFileSync19(migrationLedgerFile(), "utf8"));
|
|
24232
23970
|
return Array.isArray(parsed) ? parsed : [];
|
|
24233
23971
|
} catch {
|
|
24234
23972
|
return [];
|
|
@@ -24236,9 +23974,9 @@ function readLedger() {
|
|
|
24236
23974
|
}
|
|
24237
23975
|
function appendLedger(entry) {
|
|
24238
23976
|
try {
|
|
24239
|
-
|
|
23977
|
+
mkdirSync14(migrationsDir(), { recursive: true });
|
|
24240
23978
|
const all = [...readLedger(), entry];
|
|
24241
|
-
|
|
23979
|
+
writeFileSync12(migrationLedgerFile(), `${JSON.stringify(all, null, 2)}
|
|
24242
23980
|
`, "utf8");
|
|
24243
23981
|
} catch {}
|
|
24244
23982
|
}
|
|
@@ -24250,12 +23988,12 @@ function pruneMigratedCredentials(from) {
|
|
|
24250
23988
|
for (let layout = from;layout < LAYOUT_VERSION; layout++) {
|
|
24251
23989
|
for (const { as, landsAt } of PRUNED_AFTER_SUCCESS) {
|
|
24252
23990
|
try {
|
|
24253
|
-
if (!
|
|
23991
|
+
if (!existsSync23(landsAt()))
|
|
24254
23992
|
continue;
|
|
24255
|
-
const copy =
|
|
24256
|
-
if (!
|
|
23993
|
+
const copy = resolve19(migrationBackupDir(layout), as);
|
|
23994
|
+
if (!existsSync23(copy))
|
|
24257
23995
|
continue;
|
|
24258
|
-
|
|
23996
|
+
rmSync8(copy, { force: true });
|
|
24259
23997
|
pruned.push(as);
|
|
24260
23998
|
} catch {}
|
|
24261
23999
|
}
|
|
@@ -24266,7 +24004,7 @@ function filesToBackUp() {
|
|
|
24266
24004
|
const seen = new Map;
|
|
24267
24005
|
for (const f of [...BACKED_UP, ...BACKED_UP_LEGACY]) {
|
|
24268
24006
|
const path = f.at();
|
|
24269
|
-
if (
|
|
24007
|
+
if (existsSync23(path))
|
|
24270
24008
|
seen.set(path, backupNameOf(f));
|
|
24271
24009
|
}
|
|
24272
24010
|
return [...seen].map(([path, as]) => ({ path, as }));
|
|
@@ -24275,14 +24013,14 @@ function backupBeforeMigrating(from) {
|
|
|
24275
24013
|
const dir = migrationBackupDir(from);
|
|
24276
24014
|
const saved = [];
|
|
24277
24015
|
try {
|
|
24278
|
-
|
|
24279
|
-
|
|
24016
|
+
rmSync8(dir, { recursive: true, force: true });
|
|
24017
|
+
mkdirSync14(dir, { recursive: true });
|
|
24280
24018
|
} catch {
|
|
24281
24019
|
return [];
|
|
24282
24020
|
}
|
|
24283
24021
|
for (const { path: source, as } of filesToBackUp()) {
|
|
24284
24022
|
try {
|
|
24285
|
-
copyFileSync2(source,
|
|
24023
|
+
copyFileSync2(source, resolve19(dir, as));
|
|
24286
24024
|
saved.push(as);
|
|
24287
24025
|
} catch {}
|
|
24288
24026
|
}
|
|
@@ -24572,7 +24310,7 @@ var init_fp_reset2 = __esm(() => {
|
|
|
24572
24310
|
// scripts/install-telemetry.mjs
|
|
24573
24311
|
import { createHmac, randomUUID as randomUUID2 } from "node:crypto";
|
|
24574
24312
|
import { execSync as execSync5 } from "node:child_process";
|
|
24575
|
-
import { readFileSync as
|
|
24313
|
+
import { readFileSync as readFileSync20, writeFileSync as writeFileSync13, mkdirSync as mkdirSync15 } from "node:fs";
|
|
24576
24314
|
import { homedir as homedir22, platform, arch, hostname, cpus } from "node:os";
|
|
24577
24315
|
import { join as join31 } from "node:path";
|
|
24578
24316
|
function hashToId3(raw) {
|
|
@@ -24582,7 +24320,7 @@ function getInstanceId3() {
|
|
|
24582
24320
|
const idDir = join31(homedir22(), ".failproofai");
|
|
24583
24321
|
const idFile = join31(idDir, "instance-id");
|
|
24584
24322
|
try {
|
|
24585
|
-
const existing =
|
|
24323
|
+
const existing = readFileSync20(idFile, "utf-8").trim();
|
|
24586
24324
|
if (existing)
|
|
24587
24325
|
return existing;
|
|
24588
24326
|
} catch {}
|
|
@@ -24591,7 +24329,7 @@ function getInstanceId3() {
|
|
|
24591
24329
|
if (p === "linux") {
|
|
24592
24330
|
for (const machineIdPath of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
|
|
24593
24331
|
try {
|
|
24594
|
-
const id =
|
|
24332
|
+
const id = readFileSync20(machineIdPath, "utf-8").trim();
|
|
24595
24333
|
if (id)
|
|
24596
24334
|
return hashToId3(id);
|
|
24597
24335
|
} catch {}
|
|
@@ -24623,8 +24361,8 @@ function getInstanceId3() {
|
|
|
24623
24361
|
} catch {}
|
|
24624
24362
|
const id = randomUUID2();
|
|
24625
24363
|
try {
|
|
24626
|
-
|
|
24627
|
-
|
|
24364
|
+
mkdirSync15(idDir, { recursive: true });
|
|
24365
|
+
writeFileSync13(idFile, id, "utf-8");
|
|
24628
24366
|
} catch {}
|
|
24629
24367
|
return id;
|
|
24630
24368
|
}
|
|
@@ -24656,8 +24394,8 @@ var NAMESPACE3 = "failproofai-telemetry-v1", API_KEY3 = "phc_Ac1Ww1GqKc0z1SyrRWb
|
|
|
24656
24394
|
var init_install_telemetry = () => {};
|
|
24657
24395
|
|
|
24658
24396
|
// lib/install-check.ts
|
|
24659
|
-
import { existsSync as
|
|
24660
|
-
import { dirname as
|
|
24397
|
+
import { existsSync as existsSync24, readFileSync as readFileSync21, writeFileSync as writeFileSync14, mkdirSync as mkdirSync16 } from "node:fs";
|
|
24398
|
+
import { dirname as dirname13, resolve as resolve20 } from "node:path";
|
|
24661
24399
|
import { platform as platform2, arch as arch2, release, homedir as homedir23, hostname as hostname2 } from "node:os";
|
|
24662
24400
|
import { createHmac as createHmac2 } from "node:crypto";
|
|
24663
24401
|
function hashToId4(raw) {
|
|
@@ -24712,12 +24450,12 @@ function compareSemver(a, b) {
|
|
|
24712
24450
|
}
|
|
24713
24451
|
function checkHooks() {
|
|
24714
24452
|
const hooksConfigPath = globalPolicyConfigFile();
|
|
24715
|
-
if (!
|
|
24453
|
+
if (!existsSync24(hooksConfigPath)) {
|
|
24716
24454
|
return { configured: false, registered: false, policyCount: 0 };
|
|
24717
24455
|
}
|
|
24718
24456
|
let config;
|
|
24719
24457
|
try {
|
|
24720
|
-
config = JSON.parse(
|
|
24458
|
+
config = JSON.parse(readFileSync21(hooksConfigPath, "utf8"));
|
|
24721
24459
|
} catch {
|
|
24722
24460
|
return { configured: false, registered: false, policyCount: 0 };
|
|
24723
24461
|
}
|
|
@@ -24725,12 +24463,12 @@ function checkHooks() {
|
|
|
24725
24463
|
return { configured: false, registered: false, policyCount: 0 };
|
|
24726
24464
|
}
|
|
24727
24465
|
const policyCount = config.enabledPolicies.length;
|
|
24728
|
-
const settingsPath =
|
|
24729
|
-
if (!
|
|
24466
|
+
const settingsPath = resolve20(homedir23(), ".claude", "settings.json");
|
|
24467
|
+
if (!existsSync24(settingsPath))
|
|
24730
24468
|
return { configured: true, registered: false, policyCount };
|
|
24731
24469
|
let settings;
|
|
24732
24470
|
try {
|
|
24733
|
-
settings = JSON.parse(
|
|
24471
|
+
settings = JSON.parse(readFileSync21(settingsPath, "utf8"));
|
|
24734
24472
|
} catch {
|
|
24735
24473
|
return { configured: true, registered: false, policyCount };
|
|
24736
24474
|
}
|
|
@@ -24754,8 +24492,8 @@ async function maybeReportInstall(version) {
|
|
|
24754
24492
|
const versionFile = lastVersionPath();
|
|
24755
24493
|
let previousVersion = null;
|
|
24756
24494
|
try {
|
|
24757
|
-
if (
|
|
24758
|
-
previousVersion =
|
|
24495
|
+
if (existsSync24(versionFile)) {
|
|
24496
|
+
previousVersion = readFileSync21(versionFile, "utf8").trim() || null;
|
|
24759
24497
|
}
|
|
24760
24498
|
} catch {}
|
|
24761
24499
|
if (previousVersion === version)
|
|
@@ -24791,8 +24529,8 @@ async function maybeReportInstall(version) {
|
|
|
24791
24529
|
enabled_policy_count: hooks.policyCount
|
|
24792
24530
|
}, { version, timeoutMs: REPORT_TIMEOUT_MS, enabled: telemetryEnabled }));
|
|
24793
24531
|
try {
|
|
24794
|
-
|
|
24795
|
-
|
|
24532
|
+
mkdirSync16(dirname13(versionFile), { recursive: true });
|
|
24533
|
+
writeFileSync14(versionFile, version, "utf8");
|
|
24796
24534
|
} catch {}
|
|
24797
24535
|
await Promise.all(events.map((p) => p.catch(() => {})));
|
|
24798
24536
|
} catch {}
|
|
@@ -24842,8 +24580,8 @@ var init_cli_error = __esm(() => {
|
|
|
24842
24580
|
|
|
24843
24581
|
// src/hooks/manager.ts
|
|
24844
24582
|
import { execSync as execSync6 } from "node:child_process";
|
|
24845
|
-
import { existsSync as
|
|
24846
|
-
import { resolve as
|
|
24583
|
+
import { existsSync as existsSync25 } from "node:fs";
|
|
24584
|
+
import { resolve as resolve21, basename as basename5 } from "node:path";
|
|
24847
24585
|
import { platform as platform3, arch as arch3, release as release2, hostname as hostname3 } from "node:os";
|
|
24848
24586
|
function getSettingsPath(scope, cwd) {
|
|
24849
24587
|
return claudeCode.getSettingsPath(scope, cwd);
|
|
@@ -25062,9 +24800,9 @@ async function installHooksImpl(policyNames, scope = "user", cwd, includeBeta =
|
|
|
25062
24800
|
delete configToWrite.customPoliciesPath;
|
|
25063
24801
|
delete configToWrite.customPoliciesPaths;
|
|
25064
24802
|
} else if (customPoliciesPath && (typeof customPoliciesPath === "string" || customPoliciesPath.length > 0)) {
|
|
25065
|
-
const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path) =>
|
|
25066
|
-
const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path) =>
|
|
25067
|
-
if (
|
|
24803
|
+
const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path) => resolve21(path));
|
|
24804
|
+
const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path) => resolve21(path)).filter((path) => {
|
|
24805
|
+
if (existsSync25(path))
|
|
25068
24806
|
return true;
|
|
25069
24807
|
console.log(`Dropping custom policies path (file no longer exists): ${path}`);
|
|
25070
24808
|
return false;
|
|
@@ -25287,7 +25025,7 @@ async function removeHooks(policyNames, scope = "user", cwd, opts) {
|
|
|
25287
25025
|
const scopesToRemove = scope === "all" ? [...integration.scopes] : integration.scopes.includes(scope) ? [scope] : [];
|
|
25288
25026
|
for (const s of scopesToRemove) {
|
|
25289
25027
|
const settingsPaths = settingsPathsFor(integration, s, cwd);
|
|
25290
|
-
const existing = settingsPaths.filter((p) =>
|
|
25028
|
+
const existing = settingsPaths.filter((p) => existsSync25(p));
|
|
25291
25029
|
if (existing.length === 0) {
|
|
25292
25030
|
if (scope !== "all" && selectedClis.length === 1) {
|
|
25293
25031
|
console.log("No settings file found. Nothing to remove.");
|
|
@@ -25374,16 +25112,92 @@ var init_manager = __esm(() => {
|
|
|
25374
25112
|
VALID_POLICY_NAMES = new Set(BUILTIN_POLICIES.map((p) => p.name));
|
|
25375
25113
|
});
|
|
25376
25114
|
|
|
25115
|
+
// src/audit/leak-fingerprint.ts
|
|
25116
|
+
function matchPublicPrefix(value) {
|
|
25117
|
+
for (const entry of PUBLIC_PREFIXES) {
|
|
25118
|
+
if (value.startsWith(entry[0]))
|
|
25119
|
+
return entry;
|
|
25120
|
+
}
|
|
25121
|
+
return null;
|
|
25122
|
+
}
|
|
25123
|
+
function fingerprintSecret(value, fallbackLabel = "secret") {
|
|
25124
|
+
const length = value.length;
|
|
25125
|
+
const matched = matchPublicPrefix(value);
|
|
25126
|
+
if (!matched) {
|
|
25127
|
+
return {
|
|
25128
|
+
display: `[${length}-char ${fallbackLabel}]`,
|
|
25129
|
+
label: fallbackLabel,
|
|
25130
|
+
length,
|
|
25131
|
+
attributed: false
|
|
25132
|
+
};
|
|
25133
|
+
}
|
|
25134
|
+
const [prefix, label] = matched;
|
|
25135
|
+
const bodyLength = length - prefix.length;
|
|
25136
|
+
const run = MASK_CHAR.repeat(Math.max(1, Math.min(MAX_MASK_RUN, bodyLength)));
|
|
25137
|
+
if (length >= MIN_LEN_FOR_TAIL && bodyLength > TAIL_CHARS * 2) {
|
|
25138
|
+
return {
|
|
25139
|
+
display: `${prefix}${run}${value.slice(-TAIL_CHARS)}`,
|
|
25140
|
+
label,
|
|
25141
|
+
length,
|
|
25142
|
+
attributed: true
|
|
25143
|
+
};
|
|
25144
|
+
}
|
|
25145
|
+
return { display: `${prefix}${run}`, label, length, attributed: true };
|
|
25146
|
+
}
|
|
25147
|
+
function isFindingId(id) {
|
|
25148
|
+
return /^[0-9a-f]{16}$/.test(id);
|
|
25149
|
+
}
|
|
25150
|
+
function fingerprintId(value, machineSalt) {
|
|
25151
|
+
const { createHmac } = __require("node:crypto");
|
|
25152
|
+
return createHmac("sha256", machineSalt).update(value).digest("hex").slice(0, 16);
|
|
25153
|
+
}
|
|
25154
|
+
var MASK_CHAR = "•", MAX_MASK_RUN = 8, MIN_LEN_FOR_TAIL = 24, TAIL_CHARS = 4, PUBLIC_PREFIXES;
|
|
25155
|
+
var init_leak_fingerprint = __esm(() => {
|
|
25156
|
+
PUBLIC_PREFIXES = [
|
|
25157
|
+
["sk-ant-api03-", "Anthropic API key"],
|
|
25158
|
+
["sk-ant-oat01-", "Anthropic OAuth token"],
|
|
25159
|
+
["sk-ant-", "Anthropic key"],
|
|
25160
|
+
["sk-proj-", "OpenAI project key"],
|
|
25161
|
+
["sk-svcacct-", "OpenAI service-account key"],
|
|
25162
|
+
["sk-admin-", "OpenAI admin key"],
|
|
25163
|
+
["sk-or-v1-", "OpenRouter key"],
|
|
25164
|
+
["github_pat_", "GitHub fine-grained token"],
|
|
25165
|
+
["ghp_", "GitHub personal access token"],
|
|
25166
|
+
["gho_", "GitHub OAuth token"],
|
|
25167
|
+
["ghu_", "GitHub user-to-server token"],
|
|
25168
|
+
["ghs_", "GitHub server-to-server token"],
|
|
25169
|
+
["ghr_", "GitHub refresh token"],
|
|
25170
|
+
["glpat-", "GitLab personal access token"],
|
|
25171
|
+
["xoxb-", "Slack bot token"],
|
|
25172
|
+
["xoxp-", "Slack user token"],
|
|
25173
|
+
["xapp-", "Slack app-level token"],
|
|
25174
|
+
["sk_live_", "Stripe live secret key"],
|
|
25175
|
+
["sk_test_", "Stripe test secret key"],
|
|
25176
|
+
["rk_live_", "Stripe restricted key"],
|
|
25177
|
+
["AKIA", "AWS access key ID"],
|
|
25178
|
+
["ASIA", "AWS temporary access key ID"],
|
|
25179
|
+
["AIza", "Google API key"],
|
|
25180
|
+
["hf_", "Hugging Face token"],
|
|
25181
|
+
["gsk_", "Groq API key"],
|
|
25182
|
+
["r8_", "Replicate token"],
|
|
25183
|
+
["xai-", "xAI key"],
|
|
25184
|
+
["npm_", "npm access token"],
|
|
25185
|
+
["dop_v1_", "DigitalOcean token"],
|
|
25186
|
+
["shpat_", "Shopify access token"],
|
|
25187
|
+
["sbp_", "Supabase token"]
|
|
25188
|
+
];
|
|
25189
|
+
});
|
|
25190
|
+
|
|
25377
25191
|
// src/audit/macos-notifier.ts
|
|
25378
25192
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
25379
|
-
import { existsSync as
|
|
25193
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync17, readdirSync as readdirSync16, renameSync as renameSync8, rmSync as rmSync9, writeFileSync as writeFileSync15 } from "node:fs";
|
|
25380
25194
|
import { homedir as homedir24 } from "node:os";
|
|
25381
|
-
import { resolve as
|
|
25195
|
+
import { resolve as resolve22 } from "node:path";
|
|
25382
25196
|
function macNotifierAppPath(home) {
|
|
25383
|
-
return
|
|
25197
|
+
return resolve22(runDir(home), "..", "bin", "FailproofAI Notifier.app");
|
|
25384
25198
|
}
|
|
25385
25199
|
function macNotifierPlistPath() {
|
|
25386
|
-
return
|
|
25200
|
+
return resolve22(homedir24(), "Library", "LaunchAgents", `${MAC_NOTIFIER_LABEL}.plist`);
|
|
25387
25201
|
}
|
|
25388
25202
|
function escapeXml2(s) {
|
|
25389
25203
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
@@ -25427,7 +25241,7 @@ function notifierPlistContents(appPath, watchDir) {
|
|
|
25427
25241
|
<string>${escapeXml2(MAC_NOTIFIER_LABEL)}</string>
|
|
25428
25242
|
<key>ProgramArguments</key>
|
|
25429
25243
|
<array>
|
|
25430
|
-
<string>${escapeXml2(
|
|
25244
|
+
<string>${escapeXml2(resolve22(appPath, "Contents", "MacOS", "applet"))}</string>
|
|
25431
25245
|
</array>
|
|
25432
25246
|
<!-- Started only when something is queued, and it exits when the queue is
|
|
25433
25247
|
empty. RunAtLoad would fire it once at login with nothing to say. -->
|
|
@@ -25456,18 +25270,18 @@ function installMacNotifier(home) {
|
|
|
25456
25270
|
try {
|
|
25457
25271
|
const app = macNotifierAppPath(home);
|
|
25458
25272
|
const watch = macNotifyDir(home);
|
|
25459
|
-
|
|
25460
|
-
|
|
25461
|
-
const scriptPath =
|
|
25462
|
-
|
|
25463
|
-
|
|
25273
|
+
mkdirSync17(watch, { recursive: true, mode: 448 });
|
|
25274
|
+
mkdirSync17(resolve22(app, ".."), { recursive: true });
|
|
25275
|
+
const scriptPath = resolve22(watch, "..", "notifier.applescript");
|
|
25276
|
+
writeFileSync15(scriptPath, notifierScript(home), { mode: 384 });
|
|
25277
|
+
rmSync9(app, { recursive: true, force: true });
|
|
25464
25278
|
run("osacompile", ["-o", app, scriptPath]);
|
|
25465
|
-
|
|
25466
|
-
const plist =
|
|
25279
|
+
rmSync9(scriptPath, { force: true });
|
|
25280
|
+
const plist = resolve22(app, "Contents", "Info.plist");
|
|
25467
25281
|
run("defaults", ["write", plist, "CFBundleIdentifier", MAC_NOTIFIER_LABEL]);
|
|
25468
25282
|
run("defaults", ["write", plist, "CFBundleName", "failproofai"]);
|
|
25469
|
-
|
|
25470
|
-
|
|
25283
|
+
mkdirSync17(resolve22(macNotifierPlistPath(), ".."), { recursive: true });
|
|
25284
|
+
writeFileSync15(macNotifierPlistPath(), notifierPlistContents(app, watch), { mode: 420 });
|
|
25471
25285
|
const target = `gui/${process.getuid?.() ?? 0}`;
|
|
25472
25286
|
try {
|
|
25473
25287
|
run("launchctl", ["bootout", `${target}/${MAC_NOTIFIER_LABEL}`]);
|
|
@@ -25484,49 +25298,49 @@ function uninstallMacNotifier(home) {
|
|
|
25484
25298
|
try {
|
|
25485
25299
|
run("launchctl", ["bootout", `gui/${process.getuid?.() ?? 0}/${MAC_NOTIFIER_LABEL}`]);
|
|
25486
25300
|
} catch {}
|
|
25487
|
-
|
|
25488
|
-
|
|
25489
|
-
|
|
25301
|
+
rmSync9(macNotifierPlistPath(), { force: true });
|
|
25302
|
+
rmSync9(macNotifierAppPath(home), { recursive: true, force: true });
|
|
25303
|
+
rmSync9(macNotifyDir(home), { recursive: true, force: true });
|
|
25490
25304
|
}
|
|
25491
25305
|
function queueMacNotification(id, title, body, home) {
|
|
25492
25306
|
if (!isFindingId(id))
|
|
25493
25307
|
return false;
|
|
25494
25308
|
const dir = macNotifyDir(home);
|
|
25495
|
-
const tmp =
|
|
25309
|
+
const tmp = resolve22(dir, "..", `notify-${id}.tmp`);
|
|
25496
25310
|
try {
|
|
25497
|
-
|
|
25311
|
+
mkdirSync17(dir, { recursive: true, mode: 448 });
|
|
25498
25312
|
const payload = `${title.replace(/\s+/g, " ")}
|
|
25499
25313
|
${body.replace(/\s+/g, " ")}
|
|
25500
25314
|
`;
|
|
25501
|
-
|
|
25502
|
-
renameSync8(tmp,
|
|
25315
|
+
writeFileSync15(tmp, payload, { mode: 384 });
|
|
25316
|
+
renameSync8(tmp, resolve22(dir, id));
|
|
25503
25317
|
return true;
|
|
25504
25318
|
} catch {
|
|
25505
25319
|
try {
|
|
25506
|
-
|
|
25320
|
+
rmSync9(tmp, { force: true });
|
|
25507
25321
|
} catch {}
|
|
25508
25322
|
return false;
|
|
25509
25323
|
}
|
|
25510
25324
|
}
|
|
25511
25325
|
function macNotifierInstalled(home) {
|
|
25512
|
-
return
|
|
25326
|
+
return existsSync26(macNotifierPlistPath()) && existsSync26(macNotifierAppPath(home));
|
|
25513
25327
|
}
|
|
25514
25328
|
function pruneMacNotifyQueue(home, maxAgeMs = 7 * 86400000) {
|
|
25515
25329
|
try {
|
|
25516
25330
|
const dir = macNotifyDir(home);
|
|
25517
|
-
if (!
|
|
25331
|
+
if (!existsSync26(dir))
|
|
25518
25332
|
return;
|
|
25519
25333
|
const { statSync } = __require("node:fs");
|
|
25520
|
-
for (const name of
|
|
25521
|
-
const path =
|
|
25334
|
+
for (const name of readdirSync16(dir)) {
|
|
25335
|
+
const path = resolve22(dir, name);
|
|
25522
25336
|
try {
|
|
25523
25337
|
if (Date.now() - statSync(path).mtimeMs > maxAgeMs)
|
|
25524
|
-
|
|
25338
|
+
rmSync9(path, { force: true });
|
|
25525
25339
|
} catch {}
|
|
25526
25340
|
}
|
|
25527
25341
|
} catch {}
|
|
25528
25342
|
}
|
|
25529
|
-
var MAC_NOTIFIER_LABEL = "ai.failproof.notifier", macNotifyDir = (home) =>
|
|
25343
|
+
var MAC_NOTIFIER_LABEL = "ai.failproof.notifier", macNotifyDir = (home) => resolve22(runDir(home), "notify");
|
|
25530
25344
|
var init_macos_notifier = __esm(() => {
|
|
25531
25345
|
init_fp_home();
|
|
25532
25346
|
init_leak_fingerprint();
|
|
@@ -25548,7 +25362,7 @@ var DEFAULT_FETCH_TIMEOUT_MS = 15000;
|
|
|
25548
25362
|
|
|
25549
25363
|
// src/hooks/cloud-enrollment.ts
|
|
25550
25364
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
25551
|
-
import { existsSync as
|
|
25365
|
+
import { existsSync as existsSync27, readFileSync as readFileSync22, rmSync as rmSync10 } from "node:fs";
|
|
25552
25366
|
import { hostname as hostname4 } from "node:os";
|
|
25553
25367
|
function cloudCredentialPath() {
|
|
25554
25368
|
return process.env.FAILPROOFAI_CLOUD_CREDENTIALS ?? credentialsFile();
|
|
@@ -25587,10 +25401,10 @@ function readCloudCredentials() {
|
|
|
25587
25401
|
if (!usingJsonOverride())
|
|
25588
25402
|
return readCredentials().cloud ?? null;
|
|
25589
25403
|
const path = cloudCredentialPath();
|
|
25590
|
-
if (!
|
|
25404
|
+
if (!existsSync27(path))
|
|
25591
25405
|
return null;
|
|
25592
25406
|
try {
|
|
25593
|
-
const raw = JSON.parse(
|
|
25407
|
+
const raw = JSON.parse(readFileSync22(path, "utf8"));
|
|
25594
25408
|
if (raw.schemaVersion !== SCHEMA_VERSION2)
|
|
25595
25409
|
return null;
|
|
25596
25410
|
if (typeof raw.url !== "string" || typeof raw.machineId !== "string" || typeof raw.token !== "string") {
|
|
@@ -25629,10 +25443,10 @@ function resolveMachineLabel(explicit) {
|
|
|
25629
25443
|
function clearCloudCredentials() {
|
|
25630
25444
|
if (usingJsonOverride()) {
|
|
25631
25445
|
const path = cloudCredentialPath();
|
|
25632
|
-
if (!
|
|
25446
|
+
if (!existsSync27(path))
|
|
25633
25447
|
return false;
|
|
25634
25448
|
try {
|
|
25635
|
-
|
|
25449
|
+
rmSync10(path);
|
|
25636
25450
|
return true;
|
|
25637
25451
|
} catch {
|
|
25638
25452
|
return false;
|
|
@@ -25880,21 +25694,21 @@ var init_cloud_connection = __esm(() => {
|
|
|
25880
25694
|
});
|
|
25881
25695
|
|
|
25882
25696
|
// src/hooks/setup-state.ts
|
|
25883
|
-
import { existsSync as
|
|
25884
|
-
import { dirname as
|
|
25697
|
+
import { existsSync as existsSync28, realpathSync as realpathSync2, statSync as statSync17 } from "node:fs";
|
|
25698
|
+
import { dirname as dirname14, resolve as resolve23 } from "node:path";
|
|
25885
25699
|
import { homedir as homedir25 } from "node:os";
|
|
25886
25700
|
function globalConfigPath(home = homedir25()) {
|
|
25887
25701
|
return globalPolicyConfigFile(home);
|
|
25888
25702
|
}
|
|
25889
25703
|
function projectConfigPath(projectRoot) {
|
|
25890
|
-
return
|
|
25704
|
+
return resolve23(projectRoot, ".failproofai", "policies-config.json");
|
|
25891
25705
|
}
|
|
25892
25706
|
function legacyMarkerPath(home) {
|
|
25893
25707
|
return launcherMarker(home);
|
|
25894
25708
|
}
|
|
25895
25709
|
function isDir(path) {
|
|
25896
25710
|
try {
|
|
25897
|
-
return
|
|
25711
|
+
return statSync17(path).isDirectory();
|
|
25898
25712
|
} catch {
|
|
25899
25713
|
return false;
|
|
25900
25714
|
}
|
|
@@ -25903,14 +25717,14 @@ function findProjectRoot(start, home = homedir25()) {
|
|
|
25903
25717
|
const resolvedHome = realResolve(home);
|
|
25904
25718
|
let dir = realResolve(start);
|
|
25905
25719
|
while (dir !== resolvedHome) {
|
|
25906
|
-
if (isDir(
|
|
25720
|
+
if (isDir(resolve23(dir, ".failproofai")))
|
|
25907
25721
|
return dir;
|
|
25908
|
-
const parent =
|
|
25722
|
+
const parent = dirname14(dir);
|
|
25909
25723
|
if (parent === dir)
|
|
25910
25724
|
break;
|
|
25911
25725
|
dir = parent;
|
|
25912
25726
|
}
|
|
25913
|
-
return
|
|
25727
|
+
return resolve23(start);
|
|
25914
25728
|
}
|
|
25915
25729
|
function hasGlobalHooksInstalled() {
|
|
25916
25730
|
for (const id of INTEGRATION_TYPES) {
|
|
@@ -25922,7 +25736,7 @@ function hasGlobalHooksInstalled() {
|
|
|
25922
25736
|
return false;
|
|
25923
25737
|
}
|
|
25924
25738
|
function realResolve(path) {
|
|
25925
|
-
const lexical =
|
|
25739
|
+
const lexical = resolve23(path);
|
|
25926
25740
|
try {
|
|
25927
25741
|
return realpathSync2(lexical);
|
|
25928
25742
|
} catch {
|
|
@@ -25937,10 +25751,10 @@ function detectSetupState(cwd = process.cwd(), home = homedir25()) {
|
|
|
25937
25751
|
cwd: resolvedCwd,
|
|
25938
25752
|
home: resolvedHome,
|
|
25939
25753
|
projectRoot,
|
|
25940
|
-
hasGlobalConfig:
|
|
25941
|
-
hasProjectConfig: projectRoot !== resolvedHome &&
|
|
25754
|
+
hasGlobalConfig: existsSync28(globalConfigPath(resolvedHome)),
|
|
25755
|
+
hasProjectConfig: projectRoot !== resolvedHome && existsSync28(projectConfigPath(projectRoot)),
|
|
25942
25756
|
hasGlobalHooks: hasGlobalHooksInstalled(),
|
|
25943
|
-
hasLegacyMarker:
|
|
25757
|
+
hasLegacyMarker: existsSync28(legacyMarkerPath(resolvedHome)),
|
|
25944
25758
|
inHomeDir: resolvedCwd === resolvedHome
|
|
25945
25759
|
};
|
|
25946
25760
|
}
|
|
@@ -25957,14 +25771,14 @@ var init_setup_state = __esm(() => {
|
|
|
25957
25771
|
});
|
|
25958
25772
|
|
|
25959
25773
|
// src/hooks/onboarding-attempt.ts
|
|
25960
|
-
import { existsSync as
|
|
25961
|
-
import { dirname as
|
|
25774
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync18, readFileSync as readFileSync23, rmSync as rmSync11, writeFileSync as writeFileSync16 } from "node:fs";
|
|
25775
|
+
import { dirname as dirname15 } from "node:path";
|
|
25962
25776
|
function readOnboardingAttempt() {
|
|
25963
25777
|
const path = onboardingAttemptFile();
|
|
25964
|
-
if (!
|
|
25778
|
+
if (!existsSync29(path))
|
|
25965
25779
|
return null;
|
|
25966
25780
|
try {
|
|
25967
|
-
const raw = JSON.parse(
|
|
25781
|
+
const raw = JSON.parse(readFileSync23(path, "utf8"));
|
|
25968
25782
|
if (raw.schemaVersion !== SCHEMA_VERSION3)
|
|
25969
25783
|
return null;
|
|
25970
25784
|
if (typeof raw.reason !== "string" || typeof raw.cliVersion !== "string")
|
|
@@ -25983,7 +25797,7 @@ function readOnboardingAttempt() {
|
|
|
25983
25797
|
function recordOnboardingAttempt(reason, cliVersion, daemonStatus, now = Date.now()) {
|
|
25984
25798
|
try {
|
|
25985
25799
|
const path = onboardingAttemptFile();
|
|
25986
|
-
|
|
25800
|
+
mkdirSync18(dirname15(path), { recursive: true });
|
|
25987
25801
|
const record = {
|
|
25988
25802
|
schemaVersion: SCHEMA_VERSION3,
|
|
25989
25803
|
reason,
|
|
@@ -25991,12 +25805,12 @@ function recordOnboardingAttempt(reason, cliVersion, daemonStatus, now = Date.no
|
|
|
25991
25805
|
daemonStatus,
|
|
25992
25806
|
at: now
|
|
25993
25807
|
};
|
|
25994
|
-
|
|
25808
|
+
writeFileSync16(path, JSON.stringify(record, null, 2), "utf8");
|
|
25995
25809
|
} catch {}
|
|
25996
25810
|
}
|
|
25997
25811
|
function clearOnboardingAttempt() {
|
|
25998
25812
|
try {
|
|
25999
|
-
|
|
25813
|
+
rmSync11(onboardingAttemptFile(), { force: true });
|
|
26000
25814
|
} catch {}
|
|
26001
25815
|
}
|
|
26002
25816
|
function blockerCleared(attempt, probe) {
|
|
@@ -26038,7 +25852,7 @@ var init_onboarding_attempt = __esm(() => {
|
|
|
26038
25852
|
});
|
|
26039
25853
|
|
|
26040
25854
|
// src/hooks/onboarding-lock.ts
|
|
26041
|
-
import { mkdirSync as
|
|
25855
|
+
import { mkdirSync as mkdirSync19, readFileSync as readFileSync24, rmSync as rmSync12, writeFileSync as writeFileSync17 } from "node:fs";
|
|
26042
25856
|
import { homedir as homedir26 } from "node:os";
|
|
26043
25857
|
function onboardingLockPath(home = homedir26()) {
|
|
26044
25858
|
return onboardingLockFile(home);
|
|
@@ -26055,7 +25869,7 @@ function processAlive(pid) {
|
|
|
26055
25869
|
}
|
|
26056
25870
|
function readLock(path) {
|
|
26057
25871
|
try {
|
|
26058
|
-
const parsed = JSON.parse(
|
|
25872
|
+
const parsed = JSON.parse(readFileSync24(path, "utf8"));
|
|
26059
25873
|
if (typeof parsed.pid !== "number")
|
|
26060
25874
|
return null;
|
|
26061
25875
|
return { pid: parsed.pid, startedAt: Number(parsed.startedAt) || 0 };
|
|
@@ -26069,9 +25883,9 @@ function acquireOnboardingLock(home = homedir26()) {
|
|
|
26069
25883
|
const held = readLock(path);
|
|
26070
25884
|
if (held && held.pid !== process.pid && processAlive(held.pid))
|
|
26071
25885
|
return null;
|
|
26072
|
-
|
|
25886
|
+
mkdirSync19(stateDir(home), { recursive: true });
|
|
26073
25887
|
const body = { pid: process.pid, startedAt: Date.now() };
|
|
26074
|
-
|
|
25888
|
+
writeFileSync17(path, JSON.stringify(body), "utf8");
|
|
26075
25889
|
let released = false;
|
|
26076
25890
|
return {
|
|
26077
25891
|
release() {
|
|
@@ -26081,7 +25895,7 @@ function acquireOnboardingLock(home = homedir26()) {
|
|
|
26081
25895
|
try {
|
|
26082
25896
|
const current = readLock(path);
|
|
26083
25897
|
if (!current || current.pid === process.pid)
|
|
26084
|
-
|
|
25898
|
+
rmSync12(path, { force: true });
|
|
26085
25899
|
} catch {}
|
|
26086
25900
|
}
|
|
26087
25901
|
};
|
|
@@ -26094,7 +25908,7 @@ var init_onboarding_lock = __esm(() => {
|
|
|
26094
25908
|
});
|
|
26095
25909
|
|
|
26096
25910
|
// lib/claude-sessions.ts
|
|
26097
|
-
import { readdirSync as
|
|
25911
|
+
import { readdirSync as readdirSync17, statSync as statSync18, existsSync as existsSync30 } from "node:fs";
|
|
26098
25912
|
import { join as join32, basename as basename6 } from "node:path";
|
|
26099
25913
|
function getClaudeProjectsRoot() {
|
|
26100
25914
|
return getClaudeProjectsPath();
|
|
@@ -26103,7 +25917,7 @@ function listClaudeProjects() {
|
|
|
26103
25917
|
const root = getClaudeProjectsRoot();
|
|
26104
25918
|
let entries;
|
|
26105
25919
|
try {
|
|
26106
|
-
entries =
|
|
25920
|
+
entries = readdirSync17(root, { withFileTypes: true });
|
|
26107
25921
|
} catch {
|
|
26108
25922
|
return [];
|
|
26109
25923
|
}
|
|
@@ -26118,7 +25932,7 @@ function collectSubagentTranscripts(dir, relPrefix, project, out, depth) {
|
|
|
26118
25932
|
return;
|
|
26119
25933
|
let entries;
|
|
26120
25934
|
try {
|
|
26121
|
-
entries =
|
|
25935
|
+
entries = readdirSync17(dir, { withFileTypes: true });
|
|
26122
25936
|
} catch {
|
|
26123
25937
|
return;
|
|
26124
25938
|
}
|
|
@@ -26134,7 +25948,7 @@ function collectSubagentTranscripts(dir, relPrefix, project, out, depth) {
|
|
|
26134
25948
|
const stem = entry.name.slice(0, -".jsonl".length);
|
|
26135
25949
|
const transcriptPath = join32(dir, entry.name);
|
|
26136
25950
|
try {
|
|
26137
|
-
const s =
|
|
25951
|
+
const s = statSync18(transcriptPath);
|
|
26138
25952
|
out.push({
|
|
26139
25953
|
projectName: project.name,
|
|
26140
25954
|
cwd: project.cwd,
|
|
@@ -26151,7 +25965,7 @@ function listClaudeTranscripts(project) {
|
|
|
26151
25965
|
const out = [];
|
|
26152
25966
|
let entries;
|
|
26153
25967
|
try {
|
|
26154
|
-
entries =
|
|
25968
|
+
entries = readdirSync17(project.path, { withFileTypes: true });
|
|
26155
25969
|
} catch {
|
|
26156
25970
|
return out;
|
|
26157
25971
|
}
|
|
@@ -26162,7 +25976,7 @@ function listClaudeTranscripts(project) {
|
|
|
26162
25976
|
continue;
|
|
26163
25977
|
const transcriptPath = join32(project.path, entry.name);
|
|
26164
25978
|
try {
|
|
26165
|
-
const s =
|
|
25979
|
+
const s = statSync18(transcriptPath);
|
|
26166
25980
|
out.push({
|
|
26167
25981
|
projectName: project.name,
|
|
26168
25982
|
cwd: project.cwd,
|
|
@@ -26175,7 +25989,7 @@ function listClaudeTranscripts(project) {
|
|
|
26175
25989
|
} catch {}
|
|
26176
25990
|
} else if (entry.isDirectory() && UUID_RE2.test(entry.name)) {
|
|
26177
25991
|
const subDir = join32(project.path, entry.name, "subagents");
|
|
26178
|
-
if (!
|
|
25992
|
+
if (!existsSync30(subDir))
|
|
26179
25993
|
continue;
|
|
26180
25994
|
collectSubagentTranscripts(subDir, entry.name, project, out, 0);
|
|
26181
25995
|
}
|
|
@@ -26241,6 +26055,7 @@ var init_shared = __esm(() => {
|
|
|
26241
26055
|
|
|
26242
26056
|
// src/audit/cli-adapters/claude.ts
|
|
26243
26057
|
import { readFile as readFile15, open as open2 } from "node:fs/promises";
|
|
26058
|
+
import { readFileSync as readFileSync25 } from "node:fs";
|
|
26244
26059
|
async function listClaudeTranscriptMetadata(opts = {}) {
|
|
26245
26060
|
const projectFilter = opts.projects ? new Set(opts.projects) : null;
|
|
26246
26061
|
const sinceMs = opts.sinceMs ?? 0;
|
|
@@ -26257,13 +26072,22 @@ async function listClaudeTranscriptMetadata(opts = {}) {
|
|
|
26257
26072
|
for (const t of transcripts) {
|
|
26258
26073
|
if (t.mtimeMs < sinceMs)
|
|
26259
26074
|
continue;
|
|
26075
|
+
let sessionDescription;
|
|
26076
|
+
if (t.isSubagent) {
|
|
26077
|
+
try {
|
|
26078
|
+
const meta = JSON.parse(readFileSync25(t.transcriptPath.replace(/\.jsonl$/, ".meta.json"), "utf8"));
|
|
26079
|
+
if (typeof meta.description === "string")
|
|
26080
|
+
sessionDescription = meta.description;
|
|
26081
|
+
} catch {}
|
|
26082
|
+
}
|
|
26260
26083
|
out.push({
|
|
26261
26084
|
cli: "claude",
|
|
26262
26085
|
projectName: project.name,
|
|
26263
26086
|
sessionId: t.sessionId,
|
|
26264
26087
|
transcriptPath: t.transcriptPath,
|
|
26265
26088
|
mtimeMs: t.mtimeMs,
|
|
26266
|
-
sizeBytes: t.sizeBytes
|
|
26089
|
+
sizeBytes: t.sizeBytes,
|
|
26090
|
+
sessionDescription
|
|
26267
26091
|
});
|
|
26268
26092
|
}
|
|
26269
26093
|
}
|
|
@@ -26382,7 +26206,7 @@ var init_claude = __esm(() => {
|
|
|
26382
26206
|
});
|
|
26383
26207
|
|
|
26384
26208
|
// src/audit/cli-adapters/codex.ts
|
|
26385
|
-
import { statSync as
|
|
26209
|
+
import { statSync as statSync19 } from "node:fs";
|
|
26386
26210
|
async function listCodexTranscriptMetadata(opts = {}) {
|
|
26387
26211
|
const projectFilter = opts.projects ? new Set(opts.projects) : null;
|
|
26388
26212
|
const sinceMs = opts.sinceMs ?? 0;
|
|
@@ -26399,7 +26223,7 @@ async function listCodexTranscriptMetadata(opts = {}) {
|
|
|
26399
26223
|
continue;
|
|
26400
26224
|
let sizeBytes = 0;
|
|
26401
26225
|
try {
|
|
26402
|
-
sizeBytes =
|
|
26226
|
+
sizeBytes = statSync19(s.path).size;
|
|
26403
26227
|
} catch {}
|
|
26404
26228
|
if (!s.sessionId)
|
|
26405
26229
|
continue;
|
|
@@ -26433,7 +26257,7 @@ var init_codex = __esm(() => {
|
|
|
26433
26257
|
});
|
|
26434
26258
|
|
|
26435
26259
|
// src/audit/cli-adapters/copilot.ts
|
|
26436
|
-
import { statSync as
|
|
26260
|
+
import { statSync as statSync20 } from "node:fs";
|
|
26437
26261
|
async function listCopilotTranscriptMetadata(opts = {}) {
|
|
26438
26262
|
const projectFilter = opts.projects ? new Set(opts.projects) : null;
|
|
26439
26263
|
const sinceMs = opts.sinceMs ?? 0;
|
|
@@ -26450,7 +26274,7 @@ async function listCopilotTranscriptMetadata(opts = {}) {
|
|
|
26450
26274
|
continue;
|
|
26451
26275
|
let sizeBytes = 0;
|
|
26452
26276
|
try {
|
|
26453
|
-
sizeBytes =
|
|
26277
|
+
sizeBytes = statSync20(s.path).size;
|
|
26454
26278
|
} catch {}
|
|
26455
26279
|
if (!s.sessionId)
|
|
26456
26280
|
continue;
|
|
@@ -26484,7 +26308,7 @@ var init_copilot = __esm(() => {
|
|
|
26484
26308
|
});
|
|
26485
26309
|
|
|
26486
26310
|
// src/audit/cli-adapters/cursor.ts
|
|
26487
|
-
import { statSync as
|
|
26311
|
+
import { statSync as statSync21 } from "node:fs";
|
|
26488
26312
|
async function listCursorTranscriptMetadata(opts = {}) {
|
|
26489
26313
|
const projectFilter = opts.projects ? new Set(opts.projects) : null;
|
|
26490
26314
|
const sinceMs = opts.sinceMs ?? 0;
|
|
@@ -26501,7 +26325,7 @@ async function listCursorTranscriptMetadata(opts = {}) {
|
|
|
26501
26325
|
continue;
|
|
26502
26326
|
let sizeBytes = 0;
|
|
26503
26327
|
try {
|
|
26504
|
-
sizeBytes =
|
|
26328
|
+
sizeBytes = statSync21(s.path).size;
|
|
26505
26329
|
} catch {}
|
|
26506
26330
|
if (!s.sessionId)
|
|
26507
26331
|
continue;
|
|
@@ -26742,7 +26566,7 @@ var init_opencode = __esm(() => {
|
|
|
26742
26566
|
});
|
|
26743
26567
|
|
|
26744
26568
|
// src/audit/cli-adapters/pi.ts
|
|
26745
|
-
import { statSync as
|
|
26569
|
+
import { statSync as statSync22 } from "node:fs";
|
|
26746
26570
|
async function listPiTranscriptMetadata(opts = {}) {
|
|
26747
26571
|
const projectFilter = opts.projects ? new Set(opts.projects) : null;
|
|
26748
26572
|
const sinceMs = opts.sinceMs ?? 0;
|
|
@@ -26759,7 +26583,7 @@ async function listPiTranscriptMetadata(opts = {}) {
|
|
|
26759
26583
|
continue;
|
|
26760
26584
|
let sizeBytes = 0;
|
|
26761
26585
|
try {
|
|
26762
|
-
sizeBytes =
|
|
26586
|
+
sizeBytes = statSync22(s.path).size;
|
|
26763
26587
|
} catch {}
|
|
26764
26588
|
if (!s.sessionId)
|
|
26765
26589
|
continue;
|
|
@@ -27493,6 +27317,276 @@ var init_features = __esm(() => {
|
|
|
27493
27317
|
})();
|
|
27494
27318
|
});
|
|
27495
27319
|
|
|
27320
|
+
// src/audit/leak-scan.ts
|
|
27321
|
+
function unquote(v) {
|
|
27322
|
+
return v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'") ? v.slice(1, -1) : v;
|
|
27323
|
+
}
|
|
27324
|
+
function isDocsLiteral(value) {
|
|
27325
|
+
const { createHash } = __require("node:crypto");
|
|
27326
|
+
return DOCS_LITERALS.has(createHash("sha256").update(value).digest("hex"));
|
|
27327
|
+
}
|
|
27328
|
+
function isSelfOutput(text) {
|
|
27329
|
+
return SELF_OUTPUT_MARKERS.some((m) => text.includes(m));
|
|
27330
|
+
}
|
|
27331
|
+
function literalPrefixOf(source) {
|
|
27332
|
+
let out = "";
|
|
27333
|
+
for (let i = 0;i < source.length; i++) {
|
|
27334
|
+
const c = source[i];
|
|
27335
|
+
if (c === "\\") {
|
|
27336
|
+
const next = source[i + 1];
|
|
27337
|
+
if (next === undefined)
|
|
27338
|
+
break;
|
|
27339
|
+
if (/[dwsSDWbB]/.test(next))
|
|
27340
|
+
break;
|
|
27341
|
+
out += next;
|
|
27342
|
+
i++;
|
|
27343
|
+
continue;
|
|
27344
|
+
}
|
|
27345
|
+
if ("[](){}|?*+^$.".includes(c))
|
|
27346
|
+
break;
|
|
27347
|
+
out += c;
|
|
27348
|
+
}
|
|
27349
|
+
return out.length >= 2 ? out : null;
|
|
27350
|
+
}
|
|
27351
|
+
function applicablePatterns(text) {
|
|
27352
|
+
return GATED_PATTERNS.filter(([, , gate]) => gate === null || text.includes(gate));
|
|
27353
|
+
}
|
|
27354
|
+
function findSecrets(text) {
|
|
27355
|
+
if (!text)
|
|
27356
|
+
return [];
|
|
27357
|
+
if (isSelfOutput(text))
|
|
27358
|
+
return [];
|
|
27359
|
+
const byValue = new Map;
|
|
27360
|
+
for (const [pattern, label] of applicablePatterns(text)) {
|
|
27361
|
+
const re = new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g");
|
|
27362
|
+
for (const m of text.matchAll(re)) {
|
|
27363
|
+
const value = m[0];
|
|
27364
|
+
if (isDocsLiteral(value))
|
|
27365
|
+
continue;
|
|
27366
|
+
if (!byValue.has(value))
|
|
27367
|
+
byValue.set(value, { value, name: null, rule: label, shaped: true });
|
|
27368
|
+
}
|
|
27369
|
+
}
|
|
27370
|
+
for (const m of text.matchAll(ASSIGNMENT_RE)) {
|
|
27371
|
+
const name = m[2];
|
|
27372
|
+
const value = unquote(m[4]);
|
|
27373
|
+
const existing = byValue.get(value);
|
|
27374
|
+
if (existing)
|
|
27375
|
+
existing.name ??= name;
|
|
27376
|
+
}
|
|
27377
|
+
return [...byValue.values()];
|
|
27378
|
+
}
|
|
27379
|
+
function flattenToolInput(input, depth = 0) {
|
|
27380
|
+
if (depth > 6 || input == null)
|
|
27381
|
+
return "";
|
|
27382
|
+
if (typeof input === "string")
|
|
27383
|
+
return input;
|
|
27384
|
+
if (typeof input === "number" || typeof input === "boolean")
|
|
27385
|
+
return String(input);
|
|
27386
|
+
if (Array.isArray(input))
|
|
27387
|
+
return input.map((v) => flattenToolInput(v, depth + 1)).join(`
|
|
27388
|
+
`);
|
|
27389
|
+
if (typeof input === "object") {
|
|
27390
|
+
return Object.entries(input).map(([k, v]) => `${k}=${flattenToolInput(v, depth + 1)}`).join(`
|
|
27391
|
+
`);
|
|
27392
|
+
}
|
|
27393
|
+
return "";
|
|
27394
|
+
}
|
|
27395
|
+
var LEAK_SCAN_VERSION = 6, ASSIGNMENT_RE, DOCS_LITERALS, SELF_OUTPUT_MARKERS, GATED_PATTERNS;
|
|
27396
|
+
var init_leak_scan = __esm(() => {
|
|
27397
|
+
init_builtin_policies();
|
|
27398
|
+
ASSIGNMENT_RE = /(["']?)\b([A-Za-z_][A-Za-z0-9_]{0,127})\1([ \t]*(?::(?!\/\/)|=)[ \t]*)("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
|
|
27399
|
+
DOCS_LITERALS = new Set([
|
|
27400
|
+
"1a5d44a2dca19669d72edf4c4f1c27c4c1ca4b4408fbb17f6ce4ad452d78ddb3",
|
|
27401
|
+
"78314b11be2e581549ac1c4f616563fad3fdf0c3b71678f6e2299182080e0598",
|
|
27402
|
+
"cb20d34a7adda2f5d2043836051e242fd4c2b233e02c80c91fe9d5af9b100574",
|
|
27403
|
+
"3543c50b0cb9cea8e55eb1f529b79f043cb250d485fde7b66cabbb5183add7da",
|
|
27404
|
+
"1fae28c1b317300acfd90078c973567c8159015822b0c8b81508a5ec40517d20",
|
|
27405
|
+
"23219833092a3136d7ad178ccb62ebd6ac8cba54ff24c2cfcd37b84aba9e95cf",
|
|
27406
|
+
"872db7f4419592e397ef45230f910e06b48c36ed9970cf1f9e4fb896e69f129c",
|
|
27407
|
+
"78a08441f4314f0a2833cfe58c62e555a162264206982cda39f6804f5048f570",
|
|
27408
|
+
"2cafc0970149a84f3b9e62eaf169f36f59907a3b3e31f7b82e68c69cd27f7326",
|
|
27409
|
+
"b363ade84d56c43bebbc9339b4971e340e3f13f7f8d45580b53373d2763e9e33"
|
|
27410
|
+
]);
|
|
27411
|
+
SELF_OUTPUT_MARKERS = [
|
|
27412
|
+
"[REDACTED:",
|
|
27413
|
+
"[redacted:",
|
|
27414
|
+
"failproofai audit",
|
|
27415
|
+
"assigned secret]"
|
|
27416
|
+
];
|
|
27417
|
+
GATED_PATTERNS = SECRET_PATTERNS.map(([re, label]) => [re, label, literalPrefixOf(re.source)]);
|
|
27418
|
+
});
|
|
27419
|
+
|
|
27420
|
+
// src/audit/leak-record.ts
|
|
27421
|
+
function upsertFinding(record, incoming) {
|
|
27422
|
+
const { sighting, ...rest } = incoming;
|
|
27423
|
+
const existing = record.findings.find((f) => f.id === rest.id);
|
|
27424
|
+
if (!existing) {
|
|
27425
|
+
record.findings.push({
|
|
27426
|
+
...rest,
|
|
27427
|
+
firstSeen: sighting.at,
|
|
27428
|
+
lastSeen: sighting.at,
|
|
27429
|
+
occurrences: 1,
|
|
27430
|
+
sightings: [sighting]
|
|
27431
|
+
});
|
|
27432
|
+
return { record, isNew: true };
|
|
27433
|
+
}
|
|
27434
|
+
existing.occurrences += 1;
|
|
27435
|
+
if (sighting.at > existing.lastSeen)
|
|
27436
|
+
existing.lastSeen = sighting.at;
|
|
27437
|
+
if (sighting.at < existing.firstSeen)
|
|
27438
|
+
existing.firstSeen = sighting.at;
|
|
27439
|
+
const seen = existing.sightings.some((s) => s.sessionId === sighting.sessionId && s.at === sighting.at);
|
|
27440
|
+
if (!seen) {
|
|
27441
|
+
existing.sightings.push(sighting);
|
|
27442
|
+
existing.sightings.sort((a, b) => a.at.localeCompare(b.at));
|
|
27443
|
+
if (existing.sightings.length > MAX_SIGHTINGS) {
|
|
27444
|
+
existing.sightings.splice(1, existing.sightings.length - MAX_SIGHTINGS);
|
|
27445
|
+
}
|
|
27446
|
+
}
|
|
27447
|
+
return { record, isNew: false };
|
|
27448
|
+
}
|
|
27449
|
+
function pruneRecord(record, nowMs) {
|
|
27450
|
+
const cutoff = new Date(nowMs - FINDING_TTL_DAYS * 86400000).toISOString();
|
|
27451
|
+
const live = record.findings.filter((f) => f.lastSeen >= cutoff);
|
|
27452
|
+
live.sort((a, b) => a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0);
|
|
27453
|
+
record.findings = live.slice(0, MAX_FINDINGS);
|
|
27454
|
+
return record;
|
|
27455
|
+
}
|
|
27456
|
+
function emptyRecord(salt, nowIso) {
|
|
27457
|
+
return {
|
|
27458
|
+
schemaVersion: LEAK_RECORD_SCHEMA_VERSION,
|
|
27459
|
+
salt,
|
|
27460
|
+
updatedAt: nowIso,
|
|
27461
|
+
findings: []
|
|
27462
|
+
};
|
|
27463
|
+
}
|
|
27464
|
+
function describeMechanism(toolName, direction, shortPath) {
|
|
27465
|
+
const where = shortPath ? ` ${shortPath}` : "";
|
|
27466
|
+
let summary;
|
|
27467
|
+
if (direction === "result") {
|
|
27468
|
+
summary = shortPath ? `appeared in the output of reading${where}` : "appeared in tool output";
|
|
27469
|
+
} else {
|
|
27470
|
+
switch (toolName) {
|
|
27471
|
+
case "Read":
|
|
27472
|
+
summary = `read from${where || " a file"}`;
|
|
27473
|
+
break;
|
|
27474
|
+
case "Write":
|
|
27475
|
+
summary = `written to${where || " a file"}`;
|
|
27476
|
+
break;
|
|
27477
|
+
case "Edit":
|
|
27478
|
+
case "NotebookEdit":
|
|
27479
|
+
summary = `edited into${where || " a file"}`;
|
|
27480
|
+
break;
|
|
27481
|
+
case "Bash":
|
|
27482
|
+
summary = "passed in a shell command";
|
|
27483
|
+
break;
|
|
27484
|
+
default:
|
|
27485
|
+
summary = `sent to the ${toolName} tool`;
|
|
27486
|
+
}
|
|
27487
|
+
}
|
|
27488
|
+
return { summary, toolName, direction };
|
|
27489
|
+
}
|
|
27490
|
+
var MAX_SIGHTINGS = 5, FINDING_TTL_DAYS = 90, MAX_FINDINGS = 500, LEAK_RECORD_SCHEMA_VERSION = 1;
|
|
27491
|
+
|
|
27492
|
+
// src/audit/leak-store.ts
|
|
27493
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
27494
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync20, readFileSync as readFileSync26 } from "node:fs";
|
|
27495
|
+
import { dirname as dirname16 } from "node:path";
|
|
27496
|
+
function readJson(path) {
|
|
27497
|
+
try {
|
|
27498
|
+
if (!existsSync31(path))
|
|
27499
|
+
return null;
|
|
27500
|
+
return JSON.parse(readFileSync26(path, "utf8"));
|
|
27501
|
+
} catch {
|
|
27502
|
+
return null;
|
|
27503
|
+
}
|
|
27504
|
+
}
|
|
27505
|
+
function readLeakIdentity(home) {
|
|
27506
|
+
const existing = readJson(auditLeakIdentityFile(home));
|
|
27507
|
+
if (existing && typeof existing.salt === "string" && existing.salt.length >= 32) {
|
|
27508
|
+
return {
|
|
27509
|
+
salt: existing.salt,
|
|
27510
|
+
dismissed: existing.dismissed ?? []
|
|
27511
|
+
};
|
|
27512
|
+
}
|
|
27513
|
+
const minted = { salt: randomBytes2(32).toString("hex"), dismissed: [] };
|
|
27514
|
+
writeLeakIdentity(minted, home);
|
|
27515
|
+
return minted;
|
|
27516
|
+
}
|
|
27517
|
+
function writeLeakIdentity(identity, home) {
|
|
27518
|
+
const path = auditLeakIdentityFile(home);
|
|
27519
|
+
try {
|
|
27520
|
+
mkdirSync20(dirname16(path), { recursive: true });
|
|
27521
|
+
writeJsonAtomically(path, identity, { mode: FILE_MODE });
|
|
27522
|
+
return true;
|
|
27523
|
+
} catch {
|
|
27524
|
+
return false;
|
|
27525
|
+
}
|
|
27526
|
+
}
|
|
27527
|
+
function sanitizeFinding(raw) {
|
|
27528
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
27529
|
+
return null;
|
|
27530
|
+
const f = raw;
|
|
27531
|
+
if (typeof f.id !== "string" || !isFindingId(f.id))
|
|
27532
|
+
return null;
|
|
27533
|
+
const fp = f.fingerprint;
|
|
27534
|
+
if (!fp || typeof fp !== "object" || typeof fp.display !== "string" || typeof fp.label !== "string") {
|
|
27535
|
+
return null;
|
|
27536
|
+
}
|
|
27537
|
+
const sightings = Array.isArray(f.sightings) ? f.sightings.filter((s) => {
|
|
27538
|
+
if (!s || typeof s !== "object")
|
|
27539
|
+
return false;
|
|
27540
|
+
const m = s.mechanism;
|
|
27541
|
+
return !!m && typeof m === "object" && typeof m.summary === "string";
|
|
27542
|
+
}) : [];
|
|
27543
|
+
return {
|
|
27544
|
+
...f,
|
|
27545
|
+
fingerprint: {
|
|
27546
|
+
display: fp.display,
|
|
27547
|
+
label: fp.label,
|
|
27548
|
+
length: typeof fp.length === "number" && Number.isFinite(fp.length) ? fp.length : 0,
|
|
27549
|
+
attributed: fp.attributed === true
|
|
27550
|
+
},
|
|
27551
|
+
name: typeof f.name === "string" ? f.name : null,
|
|
27552
|
+
firstSeen: typeof f.firstSeen === "string" ? f.firstSeen : "",
|
|
27553
|
+
lastSeen: typeof f.lastSeen === "string" ? f.lastSeen : "",
|
|
27554
|
+
occurrences: typeof f.occurrences === "number" && Number.isFinite(f.occurrences) ? f.occurrences : sightings.length,
|
|
27555
|
+
sightings
|
|
27556
|
+
};
|
|
27557
|
+
}
|
|
27558
|
+
function readLeakRecord(home) {
|
|
27559
|
+
const identity = readLeakIdentity(home);
|
|
27560
|
+
const raw = readJson(auditLeaksFile(home));
|
|
27561
|
+
if (!raw || raw.schemaVersion !== LEAK_RECORD_SCHEMA_VERSION || !Array.isArray(raw.findings)) {
|
|
27562
|
+
return emptyRecord(identity.salt, new Date().toISOString());
|
|
27563
|
+
}
|
|
27564
|
+
const findings = raw.findings.map(sanitizeFinding).filter((f) => f !== null);
|
|
27565
|
+
return { ...raw, findings, salt: identity.salt };
|
|
27566
|
+
}
|
|
27567
|
+
function writeLeakRecord(record, home, nowMs = Date.now()) {
|
|
27568
|
+
const path = auditLeaksFile(home);
|
|
27569
|
+
try {
|
|
27570
|
+
mkdirSync20(dirname16(path), { recursive: true });
|
|
27571
|
+
const pruned = pruneRecord(record, nowMs);
|
|
27572
|
+
pruned.updatedAt = new Date(nowMs).toISOString();
|
|
27573
|
+
writeJsonAtomically(path, pruned, { mode: FILE_MODE });
|
|
27574
|
+
return true;
|
|
27575
|
+
} catch {
|
|
27576
|
+
return false;
|
|
27577
|
+
}
|
|
27578
|
+
}
|
|
27579
|
+
function activeFindings(record, home) {
|
|
27580
|
+
const dismissed = new Set(readLeakIdentity(home).dismissed);
|
|
27581
|
+
return record.findings.filter((f) => !dismissed.has(f.id)).sort((a, b) => a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0);
|
|
27582
|
+
}
|
|
27583
|
+
var FILE_MODE = 384;
|
|
27584
|
+
var init_leak_store = __esm(() => {
|
|
27585
|
+
init_fp_home();
|
|
27586
|
+
init_atomic_write();
|
|
27587
|
+
init_leak_fingerprint();
|
|
27588
|
+
});
|
|
27589
|
+
|
|
27496
27590
|
// src/audit/redact-example.ts
|
|
27497
27591
|
import { homedir as homedir27 } from "node:os";
|
|
27498
27592
|
function maskTruncatedSecret(input) {
|
|
@@ -27529,7 +27623,7 @@ function isSecretName(name) {
|
|
|
27529
27623
|
return components.length > 1 && components.some((part) => COMPOUND_ONLY_COMPONENTS.includes(part));
|
|
27530
27624
|
}
|
|
27531
27625
|
function maskAssignedSecrets(input) {
|
|
27532
|
-
let out = input.replace(
|
|
27626
|
+
let out = input.replace(ASSIGNMENT_RE2, (match, quote, name, separator, value) => {
|
|
27533
27627
|
if (!isSecretName(name))
|
|
27534
27628
|
return match;
|
|
27535
27629
|
if (value.startsWith("[REDACTED"))
|
|
@@ -27588,7 +27682,7 @@ function redactExample(input, home = homedir27()) {
|
|
|
27588
27682
|
const collapsed = shortened.replace(/\s+/g, " ").trim();
|
|
27589
27683
|
return collapsed.length > REDACTED_EXAMPLE_MAX_CHARS ? `${collapsed.slice(0, REDACTED_EXAMPLE_MAX_CHARS - 1)}…` : collapsed;
|
|
27590
27684
|
}
|
|
27591
|
-
var REDACTED_EXAMPLE_MAX_CHARS = 160, KEPT_PARENT_SEGMENTS = 0, ABSOLUTE_PATH_RE, PUBLIC_PATH_ROOTS, SECRET_PREFIXES, SECRET_NAME_SUBSTRINGS, SECRET_NAME_COMPONENTS, COMPOUND_ONLY_COMPONENTS,
|
|
27685
|
+
var REDACTED_EXAMPLE_MAX_CHARS = 160, KEPT_PARENT_SEGMENTS = 0, ABSOLUTE_PATH_RE, PUBLIC_PATH_ROOTS, SECRET_PREFIXES, SECRET_NAME_SUBSTRINGS, SECRET_NAME_COMPONENTS, COMPOUND_ONLY_COMPONENTS, ASSIGNMENT_RE2, URL_CREDENTIALS_RE, BASIC_AUTH_FLAG_RE, CLIENT_BUNDLE_PREFIXES, PUBLISHED_MARKERS;
|
|
27592
27686
|
var init_redact_example = __esm(() => {
|
|
27593
27687
|
init_builtin_policies();
|
|
27594
27688
|
ABSOLUTE_PATH_RE = /(?:\/[\w.\-@+]+){2,}\/?/g;
|
|
@@ -27616,9 +27710,9 @@ var init_redact_example = __esm(() => {
|
|
|
27616
27710
|
"APIKEY",
|
|
27617
27711
|
"PRIVATEKEY"
|
|
27618
27712
|
];
|
|
27619
|
-
SECRET_NAME_COMPONENTS = ["
|
|
27620
|
-
COMPOUND_ONLY_COMPONENTS = ["PWD"];
|
|
27621
|
-
|
|
27713
|
+
SECRET_NAME_COMPONENTS = ["PASS", "AUTH", "PAT", "SIG", "SIGNATURE", "COOKIE"];
|
|
27714
|
+
COMPOUND_ONLY_COMPONENTS = ["PWD", "KEY"];
|
|
27715
|
+
ASSIGNMENT_RE2 = /(["']?)\b([A-Za-z_][A-Za-z0-9_]{0,127})\1([ \t]*(?::(?!\/\/)|=)[ \t]*)("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
|
|
27622
27716
|
URL_CREDENTIALS_RE = /([a-z][a-z0-9+.\-]{0,31}:\/\/)[^\s/:@]{1,256}:[^\s/@]{1,256}@/gi;
|
|
27623
27717
|
BASIC_AUTH_FLAG_RE = /((?:^|\s)(?:-u|--user)[\s=])\S+:\S+/g;
|
|
27624
27718
|
CLIENT_BUNDLE_PREFIXES = [
|
|
@@ -27634,136 +27728,9 @@ var init_redact_example = __esm(() => {
|
|
|
27634
27728
|
PUBLISHED_MARKERS = /PUBLISHABLE|(^|_)PUBLIC_KEY$|(^|_)ANON_KEY$/;
|
|
27635
27729
|
});
|
|
27636
27730
|
|
|
27637
|
-
// src/audit/leak-scan.ts
|
|
27638
|
-
function isNotACredential(value) {
|
|
27639
|
-
if (value.length < MIN_VALUE_LEN)
|
|
27640
|
-
return true;
|
|
27641
|
-
if (/^[$<{(`%]/.test(value))
|
|
27642
|
-
return true;
|
|
27643
|
-
if (value.includes("${") || value.includes("{{") || value.includes("%("))
|
|
27644
|
-
return true;
|
|
27645
|
-
if (/^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*)+$/.test(value))
|
|
27646
|
-
return true;
|
|
27647
|
-
if (value.includes("[REDACTED") || /^[•*#.]+$/.test(value))
|
|
27648
|
-
return true;
|
|
27649
|
-
if (/(.)\1{5,}/.test(value))
|
|
27650
|
-
return true;
|
|
27651
|
-
if (/^(true|false|null|undefined|none)$/i.test(value))
|
|
27652
|
-
return true;
|
|
27653
|
-
if (/^-?\d+(\.\d+)?$/.test(value))
|
|
27654
|
-
return true;
|
|
27655
|
-
if (/^\/|^~\/|^\.\.?\//.test(value))
|
|
27656
|
-
return true;
|
|
27657
|
-
return false;
|
|
27658
|
-
}
|
|
27659
|
-
function unquote(v) {
|
|
27660
|
-
return v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'") ? v.slice(1, -1) : v;
|
|
27661
|
-
}
|
|
27662
|
-
function isDocsLiteral(value) {
|
|
27663
|
-
const { createHash } = __require("node:crypto");
|
|
27664
|
-
return DOCS_LITERALS.has(createHash("sha256").update(value).digest("hex"));
|
|
27665
|
-
}
|
|
27666
|
-
function isSelfOutput(text) {
|
|
27667
|
-
return SELF_OUTPUT_MARKERS.some((m) => text.includes(m));
|
|
27668
|
-
}
|
|
27669
|
-
function literalPrefixOf(source) {
|
|
27670
|
-
let out = "";
|
|
27671
|
-
for (let i = 0;i < source.length; i++) {
|
|
27672
|
-
const c = source[i];
|
|
27673
|
-
if (c === "\\") {
|
|
27674
|
-
const next = source[i + 1];
|
|
27675
|
-
if (next === undefined)
|
|
27676
|
-
break;
|
|
27677
|
-
if (/[dwsSDWbB]/.test(next))
|
|
27678
|
-
break;
|
|
27679
|
-
out += next;
|
|
27680
|
-
i++;
|
|
27681
|
-
continue;
|
|
27682
|
-
}
|
|
27683
|
-
if ("[](){}|?*+^$.".includes(c))
|
|
27684
|
-
break;
|
|
27685
|
-
out += c;
|
|
27686
|
-
}
|
|
27687
|
-
return out.length >= 2 ? out : null;
|
|
27688
|
-
}
|
|
27689
|
-
function applicablePatterns(text) {
|
|
27690
|
-
return GATED_PATTERNS.filter(([, , gate]) => gate === null || text.includes(gate));
|
|
27691
|
-
}
|
|
27692
|
-
function findSecrets(text) {
|
|
27693
|
-
if (!text)
|
|
27694
|
-
return [];
|
|
27695
|
-
if (isSelfOutput(text))
|
|
27696
|
-
return [];
|
|
27697
|
-
const byValue = new Map;
|
|
27698
|
-
for (const [pattern, label] of applicablePatterns(text)) {
|
|
27699
|
-
const re = new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g");
|
|
27700
|
-
for (const m of text.matchAll(re)) {
|
|
27701
|
-
const value = m[0];
|
|
27702
|
-
if (isDocsLiteral(value))
|
|
27703
|
-
continue;
|
|
27704
|
-
if (!byValue.has(value))
|
|
27705
|
-
byValue.set(value, { value, name: null, rule: label, shaped: true });
|
|
27706
|
-
}
|
|
27707
|
-
}
|
|
27708
|
-
for (const m of text.matchAll(ASSIGNMENT_RE2)) {
|
|
27709
|
-
const name = m[2];
|
|
27710
|
-
const value = unquote(m[4]);
|
|
27711
|
-
if (!isSecretName(name) || isNotACredential(value) || isDocsLiteral(value))
|
|
27712
|
-
continue;
|
|
27713
|
-
const existing = byValue.get(value);
|
|
27714
|
-
if (existing) {
|
|
27715
|
-
existing.name ??= name;
|
|
27716
|
-
continue;
|
|
27717
|
-
}
|
|
27718
|
-
byValue.set(value, { value, name, rule: "assigned secret", shaped: false });
|
|
27719
|
-
}
|
|
27720
|
-
return [...byValue.values()];
|
|
27721
|
-
}
|
|
27722
|
-
function flattenToolInput(input, depth = 0) {
|
|
27723
|
-
if (depth > 6 || input == null)
|
|
27724
|
-
return "";
|
|
27725
|
-
if (typeof input === "string")
|
|
27726
|
-
return input;
|
|
27727
|
-
if (typeof input === "number" || typeof input === "boolean")
|
|
27728
|
-
return String(input);
|
|
27729
|
-
if (Array.isArray(input))
|
|
27730
|
-
return input.map((v) => flattenToolInput(v, depth + 1)).join(`
|
|
27731
|
-
`);
|
|
27732
|
-
if (typeof input === "object") {
|
|
27733
|
-
return Object.entries(input).map(([k, v]) => `${k}=${flattenToolInput(v, depth + 1)}`).join(`
|
|
27734
|
-
`);
|
|
27735
|
-
}
|
|
27736
|
-
return "";
|
|
27737
|
-
}
|
|
27738
|
-
var ASSIGNMENT_RE2, MIN_VALUE_LEN = 8, DOCS_LITERALS, SELF_OUTPUT_MARKERS, GATED_PATTERNS;
|
|
27739
|
-
var init_leak_scan = __esm(() => {
|
|
27740
|
-
init_builtin_policies();
|
|
27741
|
-
init_redact_example();
|
|
27742
|
-
ASSIGNMENT_RE2 = /(["']?)\b([A-Za-z_][A-Za-z0-9_]{0,127})\1([ \t]*(?::(?!\/\/)|=)[ \t]*)("[^"]*"|'[^']*'|[^\s;|&"']+)/g;
|
|
27743
|
-
DOCS_LITERALS = new Set([
|
|
27744
|
-
"1a5d44a2dca19669d72edf4c4f1c27c4c1ca4b4408fbb17f6ce4ad452d78ddb3",
|
|
27745
|
-
"78314b11be2e581549ac1c4f616563fad3fdf0c3b71678f6e2299182080e0598",
|
|
27746
|
-
"cb20d34a7adda2f5d2043836051e242fd4c2b233e02c80c91fe9d5af9b100574",
|
|
27747
|
-
"3543c50b0cb9cea8e55eb1f529b79f043cb250d485fde7b66cabbb5183add7da",
|
|
27748
|
-
"1fae28c1b317300acfd90078c973567c8159015822b0c8b81508a5ec40517d20",
|
|
27749
|
-
"23219833092a3136d7ad178ccb62ebd6ac8cba54ff24c2cfcd37b84aba9e95cf",
|
|
27750
|
-
"872db7f4419592e397ef45230f910e06b48c36ed9970cf1f9e4fb896e69f129c",
|
|
27751
|
-
"78a08441f4314f0a2833cfe58c62e555a162264206982cda39f6804f5048f570",
|
|
27752
|
-
"2cafc0970149a84f3b9e62eaf169f36f59907a3b3e31f7b82e68c69cd27f7326",
|
|
27753
|
-
"b363ade84d56c43bebbc9339b4971e340e3f13f7f8d45580b53373d2763e9e33"
|
|
27754
|
-
]);
|
|
27755
|
-
SELF_OUTPUT_MARKERS = [
|
|
27756
|
-
"[REDACTED:",
|
|
27757
|
-
"[redacted:",
|
|
27758
|
-
"failproofai audit",
|
|
27759
|
-
"assigned secret]"
|
|
27760
|
-
];
|
|
27761
|
-
GATED_PATTERNS = SECRET_PATTERNS.map(([re, label]) => [re, label, literalPrefixOf(re.source)]);
|
|
27762
|
-
});
|
|
27763
|
-
|
|
27764
27731
|
// src/audit/cache.ts
|
|
27765
27732
|
import { createHash as createHash8 } from "node:crypto";
|
|
27766
|
-
import { existsSync as
|
|
27733
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync21, readFileSync as readFileSync27, writeFileSync as writeFileSync18, chmodSync as chmodSync5, openSync, readSync, closeSync } from "node:fs";
|
|
27767
27734
|
import { join as join33 } from "node:path";
|
|
27768
27735
|
function getEngineVersion() {
|
|
27769
27736
|
if (cachedEngineVersion)
|
|
@@ -27824,10 +27791,10 @@ function readCachedTranscript(transcriptPath, mtimeMs, sizeBytes) {
|
|
|
27824
27791
|
if (sizeBytes === 0)
|
|
27825
27792
|
return null;
|
|
27826
27793
|
const cachePath = getCachePathFor(transcriptPath);
|
|
27827
|
-
if (!
|
|
27794
|
+
if (!existsSync32(cachePath))
|
|
27828
27795
|
return null;
|
|
27829
27796
|
try {
|
|
27830
|
-
const raw =
|
|
27797
|
+
const raw = readFileSync27(cachePath, "utf-8");
|
|
27831
27798
|
const entry = JSON.parse(raw);
|
|
27832
27799
|
if (entry.schemaVersion !== CACHE_SCHEMA_VERSION)
|
|
27833
27800
|
return null;
|
|
@@ -27835,6 +27802,8 @@ function readCachedTranscript(transcriptPath, mtimeMs, sizeBytes) {
|
|
|
27835
27802
|
return null;
|
|
27836
27803
|
if (entry.detectorVersion !== getDetectorVersion())
|
|
27837
27804
|
return null;
|
|
27805
|
+
if (entry.leakScanVersion !== LEAK_SCAN_VERSION)
|
|
27806
|
+
return null;
|
|
27838
27807
|
if (!Number.isFinite(entry.cachedAt) || Date.now() - entry.cachedAt > CACHE_TTL_MS)
|
|
27839
27808
|
return null;
|
|
27840
27809
|
if (!entry.result)
|
|
@@ -27866,7 +27835,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
|
|
|
27866
27835
|
return;
|
|
27867
27836
|
const cachePath = getCachePathFor(transcriptPath);
|
|
27868
27837
|
try {
|
|
27869
|
-
|
|
27838
|
+
mkdirSync21(auditCacheDir(), { recursive: true });
|
|
27870
27839
|
const entry = {
|
|
27871
27840
|
schemaVersion: CACHE_SCHEMA_VERSION,
|
|
27872
27841
|
cachedAt: Date.now(),
|
|
@@ -27874,6 +27843,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
|
|
|
27874
27843
|
sizeBytes,
|
|
27875
27844
|
engineVersion: getEngineVersion(),
|
|
27876
27845
|
detectorVersion: getDetectorVersion(),
|
|
27846
|
+
leakScanVersion: LEAK_SCAN_VERSION,
|
|
27877
27847
|
result
|
|
27878
27848
|
};
|
|
27879
27849
|
if (resume && resume.bytesScanned > 0) {
|
|
@@ -27884,7 +27854,7 @@ function writeCachedTranscriptResult(transcriptPath, mtimeMs, sizeBytes, result,
|
|
|
27884
27854
|
entry.detectorState = encodeDetectorState(resume.detectorState);
|
|
27885
27855
|
}
|
|
27886
27856
|
}
|
|
27887
|
-
|
|
27857
|
+
writeFileSync18(cachePath, JSON.stringify(entry), { encoding: "utf-8", mode: 384 });
|
|
27888
27858
|
try {
|
|
27889
27859
|
chmodSync5(cachePath, 384);
|
|
27890
27860
|
} catch {}
|
|
@@ -27894,6 +27864,7 @@ var cachedEngineVersion = null, cachedDetectorVersion = null, CACHE_SCHEMA_VERSI
|
|
|
27894
27864
|
var init_cache = __esm(() => {
|
|
27895
27865
|
init_builtin_policies();
|
|
27896
27866
|
init_detectors();
|
|
27867
|
+
init_leak_scan();
|
|
27897
27868
|
init_fp_home();
|
|
27898
27869
|
CACHE_TTL_MS = 30 * 24 * 60 * 60000;
|
|
27899
27870
|
});
|
|
@@ -27962,6 +27933,30 @@ var init_replay = __esm(() => {
|
|
|
27962
27933
|
});
|
|
27963
27934
|
|
|
27964
27935
|
// src/audit/index.ts
|
|
27936
|
+
class ByteGate {
|
|
27937
|
+
budget;
|
|
27938
|
+
inFlight = 0;
|
|
27939
|
+
waiting = [];
|
|
27940
|
+
constructor(budget) {
|
|
27941
|
+
this.budget = budget;
|
|
27942
|
+
}
|
|
27943
|
+
async acquire(bytes) {
|
|
27944
|
+
const want = Math.max(0, bytes);
|
|
27945
|
+
while (this.inFlight > 0 && this.inFlight + want > this.budget) {
|
|
27946
|
+
await new Promise((resolve) => this.waiting.push(resolve));
|
|
27947
|
+
}
|
|
27948
|
+
this.inFlight += want;
|
|
27949
|
+
}
|
|
27950
|
+
release(bytes) {
|
|
27951
|
+
this.inFlight -= Math.max(0, bytes);
|
|
27952
|
+
if (this.inFlight < 0)
|
|
27953
|
+
this.inFlight = 0;
|
|
27954
|
+
const waiters = this.waiting;
|
|
27955
|
+
this.waiting = [];
|
|
27956
|
+
for (const wake of waiters)
|
|
27957
|
+
wake();
|
|
27958
|
+
}
|
|
27959
|
+
}
|
|
27965
27960
|
function shortPolicyName(name) {
|
|
27966
27961
|
const slash = name.indexOf("/");
|
|
27967
27962
|
return slash >= 0 ? name.slice(slash + 1) : name;
|
|
@@ -28003,6 +27998,27 @@ function parseSinceOpt(since) {
|
|
|
28003
27998
|
return t;
|
|
28004
27999
|
throw new Error(`Invalid --since value: "${since}" (expected e.g. "7d", "30d", or "2026-04-01")`);
|
|
28005
28000
|
}
|
|
28001
|
+
function isCredentialResearchSession(events, sessionDescription) {
|
|
28002
|
+
if (sessionDescription && CREDENTIAL_RESEARCH_PURPOSE.test(sessionDescription))
|
|
28003
|
+
return true;
|
|
28004
|
+
const matched = new Set;
|
|
28005
|
+
let evidenceEvents = 0;
|
|
28006
|
+
for (const event of events) {
|
|
28007
|
+
const intent = flattenToolInput(event.toolInput);
|
|
28008
|
+
let eventMatched = false;
|
|
28009
|
+
for (let i = 0;i < CREDENTIAL_RESEARCH_MARKERS.length; i++) {
|
|
28010
|
+
if (CREDENTIAL_RESEARCH_MARKERS[i].test(intent)) {
|
|
28011
|
+
matched.add(i);
|
|
28012
|
+
eventMatched = true;
|
|
28013
|
+
}
|
|
28014
|
+
}
|
|
28015
|
+
if (eventMatched)
|
|
28016
|
+
evidenceEvents++;
|
|
28017
|
+
if (matched.size >= 2 || evidenceEvents >= 3)
|
|
28018
|
+
return true;
|
|
28019
|
+
}
|
|
28020
|
+
return false;
|
|
28021
|
+
}
|
|
28006
28022
|
async function scanOneTranscript(meta, resume) {
|
|
28007
28023
|
const empty = {
|
|
28008
28024
|
transcriptPath: meta.transcriptPath,
|
|
@@ -28043,6 +28059,9 @@ async function scanOneTranscript(meta, resume) {
|
|
|
28043
28059
|
const result = empty;
|
|
28044
28060
|
result.eventsScanned = events.length;
|
|
28045
28061
|
result.cwd = result.cwd || events[0].cwd || "";
|
|
28062
|
+
const suppressLeakScan = isCredentialResearchSession(events, meta.sessionDescription);
|
|
28063
|
+
if (suppressLeakScan)
|
|
28064
|
+
result.leakScanSuppressed = "credential-research";
|
|
28046
28065
|
for (const event of events) {
|
|
28047
28066
|
let replayHits;
|
|
28048
28067
|
try {
|
|
@@ -28054,7 +28073,8 @@ async function scanOneTranscript(meta, resume) {
|
|
|
28054
28073
|
const example = formatPolicyExample(hit.policyName, event);
|
|
28055
28074
|
recordHit(result, hit.policyName, event.timestamp, event.cwd, truncateExample(example));
|
|
28056
28075
|
}
|
|
28057
|
-
|
|
28076
|
+
if (!suppressLeakScan)
|
|
28077
|
+
recordLeaks(result, event);
|
|
28058
28078
|
}
|
|
28059
28079
|
return { result, bytesScanned, detectorState: sessionState, resumed };
|
|
28060
28080
|
}
|
|
@@ -28094,10 +28114,12 @@ function leakSalt() {
|
|
|
28094
28114
|
}
|
|
28095
28115
|
return cachedSalt;
|
|
28096
28116
|
}
|
|
28097
|
-
function persistLeaks(perTranscript) {
|
|
28117
|
+
function persistLeaks(perTranscript, replaceExisting) {
|
|
28098
28118
|
const fresh = [];
|
|
28099
28119
|
try {
|
|
28100
|
-
const
|
|
28120
|
+
const previous = readLeakRecord();
|
|
28121
|
+
const previousIds = new Set(previous.findings.map((f) => f.id));
|
|
28122
|
+
const record = replaceExisting ? emptyRecord(previous.salt, new Date().toISOString()) : previous;
|
|
28101
28123
|
for (const t of perTranscript) {
|
|
28102
28124
|
for (const leak of t.leaks ?? []) {
|
|
28103
28125
|
const { isNew } = upsertFinding(record, {
|
|
@@ -28114,7 +28136,7 @@ function persistLeaks(perTranscript) {
|
|
|
28114
28136
|
mechanism: describeMechanism(leak.toolName, leak.direction, leak.path)
|
|
28115
28137
|
}
|
|
28116
28138
|
});
|
|
28117
|
-
if (isNew)
|
|
28139
|
+
if (isNew && !previousIds.has(leak.id))
|
|
28118
28140
|
fresh.push(leak.id);
|
|
28119
28141
|
}
|
|
28120
28142
|
}
|
|
@@ -28144,6 +28166,12 @@ function mergeIncremental(cached, tail) {
|
|
|
28144
28166
|
examplesByName: {},
|
|
28145
28167
|
rangeByName: { ...cached.rangeByName }
|
|
28146
28168
|
};
|
|
28169
|
+
if (cached.leakScanSuppressed || tail.leakScanSuppressed) {
|
|
28170
|
+
out.leakScanSuppressed = "credential-research";
|
|
28171
|
+
out.leaks = [];
|
|
28172
|
+
} else {
|
|
28173
|
+
out.leaks = [...cached.leaks ?? [], ...tail.leaks ?? []];
|
|
28174
|
+
}
|
|
28147
28175
|
for (const [name, list] of Object.entries(cached.examplesByName)) {
|
|
28148
28176
|
out.examplesByName[name] = [...list];
|
|
28149
28177
|
}
|
|
@@ -28267,16 +28295,19 @@ async function runAuditInner(opts, startedAt) {
|
|
|
28267
28295
|
}
|
|
28268
28296
|
} catch {}
|
|
28269
28297
|
const allTranscripts = [];
|
|
28298
|
+
let discoveryErrors = 0;
|
|
28270
28299
|
for (const cli of clis) {
|
|
28271
28300
|
const adapter = ADAPTERS[cli];
|
|
28272
28301
|
let list;
|
|
28273
28302
|
try {
|
|
28274
28303
|
list = await adapter.listTranscripts({ projects: opts.projects, sinceMs });
|
|
28275
28304
|
} catch {
|
|
28305
|
+
discoveryErrors++;
|
|
28276
28306
|
continue;
|
|
28277
28307
|
}
|
|
28278
28308
|
allTranscripts.push(...list);
|
|
28279
28309
|
}
|
|
28310
|
+
const gate = new ByteGate(TRANSCRIPT_BYTE_BUDGET);
|
|
28280
28311
|
let skipped = 0;
|
|
28281
28312
|
let errors = 0;
|
|
28282
28313
|
const tasks = allTranscripts.map((meta) => async () => {
|
|
@@ -28289,6 +28320,7 @@ async function runAuditInner(opts, startedAt) {
|
|
|
28289
28320
|
resume = found?.kind === "resume" ? { fromByte: found.fromByte, detectorState: found.detectorState } : undefined;
|
|
28290
28321
|
cachedPrefix = found?.kind === "resume" ? found.result : null;
|
|
28291
28322
|
}
|
|
28323
|
+
await gate.acquire(meta.sizeBytes);
|
|
28292
28324
|
try {
|
|
28293
28325
|
const scan = await scanOneTranscript(meta, resume);
|
|
28294
28326
|
const fresh = cachedPrefix && scan.resumed ? mergeIncremental(cachedPrefix, scan.result) : scan.result;
|
|
@@ -28311,6 +28343,8 @@ async function runAuditInner(opts, startedAt) {
|
|
|
28311
28343
|
examplesByName: {},
|
|
28312
28344
|
rangeByName: {}
|
|
28313
28345
|
};
|
|
28346
|
+
} finally {
|
|
28347
|
+
gate.release(meta.sizeBytes);
|
|
28314
28348
|
}
|
|
28315
28349
|
});
|
|
28316
28350
|
const settled = await batchAll(tasks, TRANSCRIPT_CONCURRENCY);
|
|
@@ -28337,9 +28371,12 @@ async function runAuditInner(opts, startedAt) {
|
|
|
28337
28371
|
projectsScannedSet.add(t.cwd);
|
|
28338
28372
|
eventsScanned += t.eventsScanned ?? 0;
|
|
28339
28373
|
}
|
|
28340
|
-
const
|
|
28374
|
+
const coversAllHistory = opts.clis === undefined && opts.projects === undefined && opts.since === undefined && discoveryErrors === 0 && errors === 0 && skipped === 0;
|
|
28375
|
+
const newFindingIds = persistLeaks(perTranscript, coversAllHistory);
|
|
28376
|
+
const leakIds = [...new Set(perTranscript.flatMap((t) => (t.leaks ?? []).map((leak) => leak.id)))];
|
|
28341
28377
|
const auditResult = {
|
|
28342
28378
|
version: 2,
|
|
28379
|
+
leakIds,
|
|
28343
28380
|
newLeakIds: newFindingIds,
|
|
28344
28381
|
scannedAt: new Date(startedAt).toISOString(),
|
|
28345
28382
|
scope: {
|
|
@@ -28364,7 +28401,7 @@ async function runAuditInner(opts, startedAt) {
|
|
|
28364
28401
|
};
|
|
28365
28402
|
return auditResult;
|
|
28366
28403
|
}
|
|
28367
|
-
var TRANSCRIPT_CONCURRENCY = 8, cachedSalt;
|
|
28404
|
+
var TRANSCRIPT_CONCURRENCY = 8, TRANSCRIPT_BYTE_BUDGET, CREDENTIAL_RESEARCH_MARKERS, CREDENTIAL_RESEARCH_PURPOSE, cachedSalt;
|
|
28368
28405
|
var init_audit = __esm(() => {
|
|
28369
28406
|
init_builtin_policies();
|
|
28370
28407
|
init_hooks_config();
|
|
@@ -28380,17 +28417,26 @@ var init_audit = __esm(() => {
|
|
|
28380
28417
|
init_cache();
|
|
28381
28418
|
init_replay();
|
|
28382
28419
|
init_types2();
|
|
28420
|
+
TRANSCRIPT_BYTE_BUDGET = 48 * 1024 * 1024;
|
|
28421
|
+
CREDENTIAL_RESEARCH_MARKERS = [
|
|
28422
|
+
/\b(?:secret|credential)[-_ ](?:scanner|detection|detector|pattern|regex|corpus)\b/i,
|
|
28423
|
+
/\b(?:trufflehog|trufflesecurity|gitleaks|detect-secrets|secret-detection-rules)\b/i,
|
|
28424
|
+
/\b(?:SECRET_PATTERNS|findSecrets|isDocsLiteral|leak-scan)\b/,
|
|
28425
|
+
/\b(?:fixture|placeholder|synthetic|sample) (?:api )?(?:key|token|secret|credential)s?\b/i,
|
|
28426
|
+
/\b(?:grep|rg|ripgrep|scan|hunt|search)\b[^\n]{0,240}\b(?:secret|credential|token)s?\b/i
|
|
28427
|
+
];
|
|
28428
|
+
CREDENTIAL_RESEARCH_PURPOSE = /\b(?:hunt|scan|search|research|test)(?:ing)?\b[^\n]{0,80}\b(?:secret|credential|token)s?\b|\b(?:secret|credential|token)s?\b[^\n]{0,80}\b(?:scanner|detector|detection|research|fixtures?|corpus)\b/i;
|
|
28383
28429
|
});
|
|
28384
28430
|
|
|
28385
28431
|
// src/audit/audit-lock.ts
|
|
28386
28432
|
import {
|
|
28387
28433
|
closeSync as closeSync2,
|
|
28388
28434
|
linkSync,
|
|
28389
|
-
mkdirSync as
|
|
28435
|
+
mkdirSync as mkdirSync22,
|
|
28390
28436
|
openSync as openSync2,
|
|
28391
|
-
readFileSync as
|
|
28437
|
+
readFileSync as readFileSync28,
|
|
28392
28438
|
unlinkSync as unlinkSync4,
|
|
28393
|
-
writeFileSync as
|
|
28439
|
+
writeFileSync as writeFileSync19,
|
|
28394
28440
|
writeSync
|
|
28395
28441
|
} from "node:fs";
|
|
28396
28442
|
function acquireAuditLock(source, now = Date.now()) {
|
|
@@ -28449,7 +28495,7 @@ function handleFor(path, info) {
|
|
|
28449
28495
|
}
|
|
28450
28496
|
function readLock2(path) {
|
|
28451
28497
|
try {
|
|
28452
|
-
const parsed = JSON.parse(
|
|
28498
|
+
const parsed = JSON.parse(readFileSync28(path, "utf8"));
|
|
28453
28499
|
if (typeof parsed?.pid !== "number" || typeof parsed?.startedAt !== "number")
|
|
28454
28500
|
return null;
|
|
28455
28501
|
return {
|
|
@@ -28465,7 +28511,7 @@ function writeLockExclusive(path, info) {
|
|
|
28465
28511
|
const body = JSON.stringify(info);
|
|
28466
28512
|
const staging = `${path}.${process.pid}.tmp`;
|
|
28467
28513
|
try {
|
|
28468
|
-
|
|
28514
|
+
writeFileSync19(staging, body, { mode: 384 });
|
|
28469
28515
|
} catch {
|
|
28470
28516
|
return false;
|
|
28471
28517
|
}
|
|
@@ -28499,8 +28545,8 @@ function createThenWrite(path, body) {
|
|
|
28499
28545
|
}
|
|
28500
28546
|
}
|
|
28501
28547
|
function ensureRunDir() {
|
|
28502
|
-
|
|
28503
|
-
|
|
28548
|
+
mkdirSync22(failproofaiHome(), { recursive: true });
|
|
28549
|
+
mkdirSync22(runDir(), { recursive: true, mode: 448 });
|
|
28504
28550
|
}
|
|
28505
28551
|
var AUDIT_LOCK_MAX_AGE_MS;
|
|
28506
28552
|
var init_audit_lock = __esm(() => {
|
|
@@ -28509,7 +28555,7 @@ var init_audit_lock = __esm(() => {
|
|
|
28509
28555
|
});
|
|
28510
28556
|
|
|
28511
28557
|
// src/audit/dashboard-cache.ts
|
|
28512
|
-
import { existsSync as
|
|
28558
|
+
import { existsSync as existsSync33, readFileSync as readFileSync29 } from "node:fs";
|
|
28513
28559
|
function getCachePath() {
|
|
28514
28560
|
return auditDashboardFile();
|
|
28515
28561
|
}
|
|
@@ -28529,10 +28575,10 @@ function writeDashboardCache(params, result) {
|
|
|
28529
28575
|
}
|
|
28530
28576
|
function readDashboardCacheMeta() {
|
|
28531
28577
|
const cachePath = getCachePath();
|
|
28532
|
-
if (!
|
|
28578
|
+
if (!existsSync33(cachePath))
|
|
28533
28579
|
return null;
|
|
28534
28580
|
try {
|
|
28535
|
-
const raw =
|
|
28581
|
+
const raw = readFileSync29(cachePath, "utf-8");
|
|
28536
28582
|
const entry = JSON.parse(raw);
|
|
28537
28583
|
if (!entry || entry.schemaVersion !== DASHBOARD_CACHE_SCHEMA_VERSION || typeof entry.cachedAt !== "string" || Number.isNaN(new Date(entry.cachedAt).getTime()))
|
|
28538
28584
|
return null;
|
|
@@ -28756,18 +28802,18 @@ var init_api_server_client = __esm(() => {
|
|
|
28756
28802
|
});
|
|
28757
28803
|
|
|
28758
28804
|
// lib/auth/auth-store.ts
|
|
28759
|
-
import { existsSync as
|
|
28760
|
-
import { join as join34, resolve as
|
|
28805
|
+
import { existsSync as existsSync34, readFileSync as readFileSync30, readdirSync as readdirSync18, rmSync as rmSync13 } from "node:fs";
|
|
28806
|
+
import { join as join34, resolve as resolve24 } from "node:path";
|
|
28761
28807
|
function getAuthFilePath() {
|
|
28762
28808
|
const override = process.env.FAILPROOFAI_AUTH_DIR;
|
|
28763
28809
|
return override ? join34(override, "session.json") : auditSessionFile();
|
|
28764
28810
|
}
|
|
28765
28811
|
function readAuth() {
|
|
28766
28812
|
const p = getAuthFilePath();
|
|
28767
|
-
if (!
|
|
28813
|
+
if (!existsSync34(p))
|
|
28768
28814
|
return null;
|
|
28769
28815
|
try {
|
|
28770
|
-
const raw =
|
|
28816
|
+
const raw = readFileSync30(p, "utf-8");
|
|
28771
28817
|
const parsed = JSON.parse(raw);
|
|
28772
28818
|
if (typeof parsed.access_token !== "string" || typeof parsed.refresh_token !== "string" || typeof parsed.access_expires_at !== "number" || typeof parsed.user !== "object" || !parsed.user || typeof parsed.user.id !== "string" || typeof parsed.user.email !== "string") {
|
|
28773
28819
|
return null;
|
|
@@ -28791,18 +28837,18 @@ function writeAuth(auth) {
|
|
|
28791
28837
|
}
|
|
28792
28838
|
function deleteAuth() {
|
|
28793
28839
|
const p = getAuthFilePath();
|
|
28794
|
-
if (
|
|
28795
|
-
|
|
28840
|
+
if (existsSync34(p))
|
|
28841
|
+
rmSync13(p, { force: true });
|
|
28796
28842
|
try {
|
|
28797
28843
|
const root = migrationsDir();
|
|
28798
|
-
if (!
|
|
28844
|
+
if (!existsSync34(root))
|
|
28799
28845
|
return;
|
|
28800
|
-
for (const entry of
|
|
28846
|
+
for (const entry of readdirSync18(root)) {
|
|
28801
28847
|
if (!entry.startsWith("backup-layout"))
|
|
28802
28848
|
continue;
|
|
28803
|
-
const copy =
|
|
28804
|
-
if (
|
|
28805
|
-
|
|
28849
|
+
const copy = resolve24(root, entry, "auth.json");
|
|
28850
|
+
if (existsSync34(copy))
|
|
28851
|
+
rmSync13(copy, { force: true });
|
|
28806
28852
|
}
|
|
28807
28853
|
} catch {}
|
|
28808
28854
|
}
|
|
@@ -28934,7 +28980,11 @@ function selectLeaks(findings, from, to) {
|
|
|
28934
28980
|
const last = ts(f.lastSeen);
|
|
28935
28981
|
if (last !== null && (last < lo || last > hi))
|
|
28936
28982
|
continue;
|
|
28937
|
-
const seen = f.sightings?.
|
|
28983
|
+
const seen = f.sightings?.reduce((latest, candidate) => {
|
|
28984
|
+
if (!latest)
|
|
28985
|
+
return candidate;
|
|
28986
|
+
return (ts(candidate.at) ?? 0) >= (ts(latest.at) ?? 0) ? candidate : latest;
|
|
28987
|
+
}, undefined);
|
|
28938
28988
|
out.push({
|
|
28939
28989
|
id: f.id,
|
|
28940
28990
|
display: f.fingerprint?.display ?? "[credential]",
|
|
@@ -28966,7 +29016,7 @@ function buildHarmReport(result, lastReportedAt, intervalDays, leakFindings = []
|
|
|
28966
29016
|
window_from: from.toISOString(),
|
|
28967
29017
|
window_to: windowTo.toISOString(),
|
|
28968
29018
|
harmful: selectHarmful(result, from, windowTo, { includeUnplaceable: isFirstReport }),
|
|
28969
|
-
leaks: selectLeaks(leakFindings, from, windowTo)
|
|
29019
|
+
leaks: selectLeaks(leakFindings, from, windowTo).slice(0, 1)
|
|
28970
29020
|
};
|
|
28971
29021
|
}
|
|
28972
29022
|
var HARMFUL_SEVERITIES, ALSO_HARMFUL;
|
|
@@ -28977,15 +29027,15 @@ var init_harm_report = __esm(() => {
|
|
|
28977
29027
|
});
|
|
28978
29028
|
|
|
28979
29029
|
// src/audit/machine-store.ts
|
|
28980
|
-
import { existsSync as
|
|
29030
|
+
import { existsSync as existsSync35, readFileSync as readFileSync31, rmSync as rmSync14 } from "node:fs";
|
|
28981
29031
|
import { hostname as hostname5 } from "node:os";
|
|
28982
29032
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
28983
29033
|
function readMachineIdentity(home) {
|
|
28984
29034
|
const path = auditMachineFile(home);
|
|
28985
|
-
if (!
|
|
29035
|
+
if (!existsSync35(path))
|
|
28986
29036
|
return null;
|
|
28987
29037
|
try {
|
|
28988
|
-
const parsed = JSON.parse(
|
|
29038
|
+
const parsed = JSON.parse(readFileSync31(path, "utf8"));
|
|
28989
29039
|
if (typeof parsed.machine_id !== "string" || !parsed.machine_id)
|
|
28990
29040
|
return null;
|
|
28991
29041
|
return {
|
|
@@ -29031,20 +29081,20 @@ var init_machine_store = __esm(() => {
|
|
|
29031
29081
|
// src/audit/report-harm.ts
|
|
29032
29082
|
async function reportHarm(result) {
|
|
29033
29083
|
let auto = false;
|
|
29034
|
-
let consentedAt;
|
|
29035
29084
|
let intervalDays = 7;
|
|
29036
29085
|
try {
|
|
29037
29086
|
const config = readConfig();
|
|
29038
29087
|
auto = config.audit.auto;
|
|
29039
|
-
consentedAt = config.audit.reportsConsentedAt;
|
|
29040
29088
|
intervalDays = config.audit.intervalDays;
|
|
29041
29089
|
} catch {
|
|
29042
29090
|
return { kind: "disabled" };
|
|
29043
29091
|
}
|
|
29044
29092
|
if (!auto)
|
|
29045
29093
|
return { kind: "disabled" };
|
|
29046
|
-
|
|
29047
|
-
|
|
29094
|
+
const prior = readMachineIdentity();
|
|
29095
|
+
const report = buildHarmReport(result, prior?.last_reported_at, intervalDays, activeFindings(readLeakRecord()));
|
|
29096
|
+
if (report.leaks.length === 0)
|
|
29097
|
+
return { kind: "no-leak" };
|
|
29048
29098
|
const auth = await getValidAccessToken();
|
|
29049
29099
|
if (!auth) {
|
|
29050
29100
|
return { kind: "signed-out" };
|
|
@@ -29055,8 +29105,6 @@ async function reportHarm(result) {
|
|
|
29055
29105
|
} catch (err) {
|
|
29056
29106
|
return { kind: "failed", error: err instanceof Error ? err.message : String(err) };
|
|
29057
29107
|
}
|
|
29058
|
-
const report = buildHarmReport(result, identity.last_reported_at, intervalDays, activeFindings(readLeakRecord()));
|
|
29059
|
-
const hits = report.harmful.reduce((n, p) => n + p.hits, 0);
|
|
29060
29108
|
try {
|
|
29061
29109
|
const res = await submitAuditReport(auth.access_token, {
|
|
29062
29110
|
machine_id: identity.machine_id,
|
|
@@ -29070,7 +29118,7 @@ async function reportHarm(result) {
|
|
|
29070
29118
|
try {
|
|
29071
29119
|
recordReportWatermark(res.next_window_from);
|
|
29072
29120
|
} catch {}
|
|
29073
|
-
return res.emailed ? { kind: "sent",
|
|
29121
|
+
return res.emailed ? { kind: "sent", leaks: report.leaks.length } : { kind: "held", leaks: report.leaks.length, reason: res.reason ?? "not_sent" };
|
|
29074
29122
|
} catch (err) {
|
|
29075
29123
|
const error = err instanceof AuthApiError ? `${err.code}: ${err.message}` : err instanceof Error ? err.message : String(err);
|
|
29076
29124
|
return { kind: "failed", error };
|
|
@@ -29079,17 +29127,16 @@ async function reportHarm(result) {
|
|
|
29079
29127
|
function describeOutcome2(outcome) {
|
|
29080
29128
|
switch (outcome.kind) {
|
|
29081
29129
|
case "disabled":
|
|
29130
|
+
case "no-leak":
|
|
29082
29131
|
return null;
|
|
29083
|
-
case "consent-required":
|
|
29084
|
-
return "failproofai: scheduled scans are on, but emailing what they find needs a fresh opt-in — run `failproofai audit --schedule` (or visit /settings) to turn digests on";
|
|
29085
29132
|
case "signed-out":
|
|
29086
|
-
return "failproofai:
|
|
29133
|
+
return "failproofai: a credential exposure was found, but no email is configured — run `failproofai audit --schedule --email you@example.com`";
|
|
29087
29134
|
case "sent":
|
|
29088
|
-
return
|
|
29135
|
+
return "failproofai: emailed the most recent credential exposure";
|
|
29089
29136
|
case "held":
|
|
29090
|
-
return `failproofai:
|
|
29137
|
+
return `failproofai: credential exposure reported, no email (${outcome.reason})`;
|
|
29091
29138
|
case "failed":
|
|
29092
|
-
return `failproofai: could not send the
|
|
29139
|
+
return `failproofai: could not send the credential alert: ${outcome.error}`;
|
|
29093
29140
|
}
|
|
29094
29141
|
}
|
|
29095
29142
|
var init_report_harm = __esm(() => {
|
|
@@ -29363,6 +29410,15 @@ var init_desktop_notify = __esm(() => {
|
|
|
29363
29410
|
];
|
|
29364
29411
|
});
|
|
29365
29412
|
|
|
29413
|
+
// src/hooks/notice.ts
|
|
29414
|
+
function desktopLeakNotice(email = "held") {
|
|
29415
|
+
const followUp = email === "sent" ? "A masked alert was also sent to your email." : email === "missing" ? "Add email alerts with: failproofai audit --schedule --email you@example.com" : email === "failed" ? "Email delivery failed this time; the local result is still available." : "Email was not sent for this run.";
|
|
29416
|
+
return {
|
|
29417
|
+
title: "failproofai audit needs review",
|
|
29418
|
+
body: "Possible credential exposure was found in your agent transcripts. " + `Run failproofai audit to verify the matches and rotate anything real. ${followUp}`
|
|
29419
|
+
};
|
|
29420
|
+
}
|
|
29421
|
+
|
|
29366
29422
|
// src/audit/cli.ts
|
|
29367
29423
|
function colorOn() {
|
|
29368
29424
|
if (process.env.NO_COLOR && process.env.NO_COLOR !== "")
|
|
@@ -29555,8 +29611,8 @@ var init_cli = __esm(() => {
|
|
|
29555
29611
|
init_report_harm();
|
|
29556
29612
|
init_desktop_notify();
|
|
29557
29613
|
init_macos_notifier();
|
|
29558
|
-
init_leak_notice();
|
|
29559
29614
|
init_fp_config();
|
|
29615
|
+
init_auth_store();
|
|
29560
29616
|
init_tui();
|
|
29561
29617
|
init_package();
|
|
29562
29618
|
AUDIT_STAGES = [
|
|
@@ -29575,9 +29631,9 @@ var init_cli = __esm(() => {
|
|
|
29575
29631
|
});
|
|
29576
29632
|
|
|
29577
29633
|
// src/hooks/configure-wizard.ts
|
|
29578
|
-
import { existsSync as
|
|
29634
|
+
import { existsSync as existsSync36, mkdirSync as mkdirSync23, writeFileSync as writeFileSync20, readFileSync as readFileSync32 } from "node:fs";
|
|
29579
29635
|
import { homedir as homedir28 } from "node:os";
|
|
29580
|
-
import { dirname as dirname17, resolve as
|
|
29636
|
+
import { dirname as dirname17, resolve as resolve25, sep as sep5 } from "node:path";
|
|
29581
29637
|
async function emit(event, props) {
|
|
29582
29638
|
try {
|
|
29583
29639
|
await trackHookEvent2(getInstanceId2(), event, props);
|
|
@@ -29600,8 +29656,8 @@ function setCustomPoliciesEnabled(scope, cwd, enabled) {
|
|
|
29600
29656
|
const path = getConfigPathForScope(scope, cwd);
|
|
29601
29657
|
let config = {};
|
|
29602
29658
|
try {
|
|
29603
|
-
if (
|
|
29604
|
-
config = JSON.parse(
|
|
29659
|
+
if (existsSync36(path))
|
|
29660
|
+
config = JSON.parse(readFileSync32(path, "utf8"));
|
|
29605
29661
|
} catch {
|
|
29606
29662
|
return;
|
|
29607
29663
|
}
|
|
@@ -29610,7 +29666,7 @@ function setCustomPoliciesEnabled(scope, cwd, enabled) {
|
|
|
29610
29666
|
else
|
|
29611
29667
|
config.customPoliciesEnabled = false;
|
|
29612
29668
|
try {
|
|
29613
|
-
|
|
29669
|
+
writeFileSync20(path, JSON.stringify(config, null, 2) + `
|
|
29614
29670
|
`, "utf8");
|
|
29615
29671
|
} catch {}
|
|
29616
29672
|
}
|
|
@@ -29641,7 +29697,7 @@ function describeCustomPolicies(cwd) {
|
|
|
29641
29697
|
const scopes = [];
|
|
29642
29698
|
let fileCount = 0;
|
|
29643
29699
|
const dirs = [
|
|
29644
|
-
{ dir:
|
|
29700
|
+
{ dir: resolve25(cwd, ".failproofai", "policies"), label: "project" },
|
|
29645
29701
|
{ dir: customPoliciesDir(), label: "global" }
|
|
29646
29702
|
];
|
|
29647
29703
|
for (const { dir, label } of dirs) {
|
|
@@ -29652,7 +29708,7 @@ function describeCustomPolicies(cwd) {
|
|
|
29652
29708
|
fileCount += found.length;
|
|
29653
29709
|
}
|
|
29654
29710
|
for (const name of findSkippedPolicyFiles(dir)) {
|
|
29655
|
-
warnings.push(`! ${homeify(
|
|
29711
|
+
warnings.push(`! ${homeify(resolve25(dir, name))} is NOT loaded — rename to ` + `${name.replace(/\.(js|mjs|ts)$/, "-policies.$1")}`);
|
|
29656
29712
|
}
|
|
29657
29713
|
}
|
|
29658
29714
|
return { active, warnings, fileCount, scopes };
|
|
@@ -29745,8 +29801,8 @@ function firstRunMarkerPath() {
|
|
|
29745
29801
|
}
|
|
29746
29802
|
function markLauncherSeen() {
|
|
29747
29803
|
try {
|
|
29748
|
-
|
|
29749
|
-
|
|
29804
|
+
mkdirSync23(dirname17(firstRunMarkerPath()), { recursive: true });
|
|
29805
|
+
writeFileSync20(firstRunMarkerPath(), "1", "utf8");
|
|
29750
29806
|
} catch {}
|
|
29751
29807
|
}
|
|
29752
29808
|
function retryProbe() {
|
|
@@ -29824,6 +29880,8 @@ async function runConfigureWizard(io = {}, answers = {}) {
|
|
|
29824
29880
|
const cwd = process.cwd();
|
|
29825
29881
|
const unattended = !stdin.isTTY || !stdout.isTTY;
|
|
29826
29882
|
const preAnswered = Boolean(answers.token);
|
|
29883
|
+
const initialAudit = readConfigRaw().raw.audit;
|
|
29884
|
+
const hadExplicitAuditAuto = !!initialAudit && typeof initialAudit === "object" && !Array.isArray(initialAudit) && typeof initialAudit.auto === "boolean";
|
|
29827
29885
|
if (typeof process.getuid === "function" && process.getuid() === 0 && process.env.SUDO_USER) {
|
|
29828
29886
|
stdout.write(`Run failproofai config as ${process.env.SUDO_USER}, not under sudo.
|
|
29829
29887
|
` + `Everything it configures is per-user — hooks, policies and the daemon's own
|
|
@@ -30146,6 +30204,11 @@ Hooks keep enforcing; scheduled audits stay off until it is.
|
|
|
30146
30204
|
}
|
|
30147
30205
|
if (daemonInstalled) {
|
|
30148
30206
|
setDaemonConfigured(true, version2);
|
|
30207
|
+
if (!hadExplicitAuditAuto) {
|
|
30208
|
+
try {
|
|
30209
|
+
updateConfig({ audit: { auto: true } });
|
|
30210
|
+
} catch {}
|
|
30211
|
+
}
|
|
30149
30212
|
pruneOldDaemonBinaries();
|
|
30150
30213
|
installMacNotifier();
|
|
30151
30214
|
}
|
|
@@ -30235,21 +30298,22 @@ var init_configure_wizard = __esm(() => {
|
|
|
30235
30298
|
init_package();
|
|
30236
30299
|
init_onboarding_attempt();
|
|
30237
30300
|
init_onboarding_lock();
|
|
30301
|
+
init_fp_config();
|
|
30238
30302
|
POLICY_LIST_INDENT = " ".repeat(15);
|
|
30239
30303
|
});
|
|
30240
30304
|
|
|
30241
30305
|
// src/hooks/flush-cli.ts
|
|
30242
|
-
import { existsSync as
|
|
30306
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync24, writeFileSync as writeFileSync21, readdirSync as readdirSync19 } from "node:fs";
|
|
30243
30307
|
import { dirname as dirname18, join as join35 } from "node:path";
|
|
30244
30308
|
function flushRequestPath2(home) {
|
|
30245
30309
|
return join35(failproofaiHome(home), "state", "flush-request.json");
|
|
30246
30310
|
}
|
|
30247
30311
|
function spoolDirs2(home) {
|
|
30248
30312
|
const root = spoolDir(home);
|
|
30249
|
-
if (!
|
|
30313
|
+
if (!existsSync37(root))
|
|
30250
30314
|
return [];
|
|
30251
30315
|
try {
|
|
30252
|
-
return
|
|
30316
|
+
return readdirSync19(root, { withFileTypes: true }).filter((e) => e.isDirectory() && e.name !== "failed").map((e) => join35(root, e.name));
|
|
30253
30317
|
} catch {
|
|
30254
30318
|
return [];
|
|
30255
30319
|
}
|
|
@@ -30258,7 +30322,7 @@ function pendingBatches2(home) {
|
|
|
30258
30322
|
let n = 0;
|
|
30259
30323
|
for (const dir of spoolDirs2(home)) {
|
|
30260
30324
|
try {
|
|
30261
|
-
n +=
|
|
30325
|
+
n += readdirSync19(dir).filter((f) => f.endsWith(".jsonl")).length;
|
|
30262
30326
|
} catch {}
|
|
30263
30327
|
}
|
|
30264
30328
|
return n;
|
|
@@ -30315,8 +30379,8 @@ async function runFlushCommand2(opts = {}) {
|
|
|
30315
30379
|
return { exitCode: 0, pending: 0, lines: ["Nothing spooled — everything already delivered."] };
|
|
30316
30380
|
}
|
|
30317
30381
|
const path = flushRequestPath2(home);
|
|
30318
|
-
|
|
30319
|
-
|
|
30382
|
+
mkdirSync24(dirname18(path), { recursive: true });
|
|
30383
|
+
writeFileSync21(path, `${JSON.stringify({ requestedAtMs: Date.now() }, null, 2)}
|
|
30320
30384
|
`, {
|
|
30321
30385
|
mode: 384
|
|
30322
30386
|
});
|
|
@@ -30347,7 +30411,7 @@ var init_flush_cli2 = __esm(() => {
|
|
|
30347
30411
|
});
|
|
30348
30412
|
|
|
30349
30413
|
// src/hooks/backfill-cli.ts
|
|
30350
|
-
import { existsSync as
|
|
30414
|
+
import { existsSync as existsSync38, mkdirSync as mkdirSync25, writeFileSync as writeFileSync22, readdirSync as readdirSync20, statSync as statSync23 } from "node:fs";
|
|
30351
30415
|
import { dirname as dirname19, join as join36 } from "node:path";
|
|
30352
30416
|
function backfillRequestPath(home) {
|
|
30353
30417
|
return join36(failproofaiHome(home), "state", "backfill-request.json");
|
|
@@ -30356,7 +30420,7 @@ function surveySessions(sinceMs, homeDir) {
|
|
|
30356
30420
|
const out = [];
|
|
30357
30421
|
for (const { cli, dir } of SESSION_DIRS) {
|
|
30358
30422
|
const root = join36(homeDir, dir);
|
|
30359
|
-
if (!
|
|
30423
|
+
if (!existsSync38(root))
|
|
30360
30424
|
continue;
|
|
30361
30425
|
let files = 0;
|
|
30362
30426
|
let newest = 0;
|
|
@@ -30365,7 +30429,7 @@ function surveySessions(sinceMs, homeDir) {
|
|
|
30365
30429
|
return;
|
|
30366
30430
|
let entries;
|
|
30367
30431
|
try {
|
|
30368
|
-
entries =
|
|
30432
|
+
entries = readdirSync20(d, { withFileTypes: true });
|
|
30369
30433
|
} catch {
|
|
30370
30434
|
return;
|
|
30371
30435
|
}
|
|
@@ -30376,7 +30440,7 @@ function surveySessions(sinceMs, homeDir) {
|
|
|
30376
30440
|
continue;
|
|
30377
30441
|
}
|
|
30378
30442
|
try {
|
|
30379
|
-
const st =
|
|
30443
|
+
const st = statSync23(p);
|
|
30380
30444
|
if (st.mtimeMs >= sinceMs) {
|
|
30381
30445
|
files += 1;
|
|
30382
30446
|
newest = Math.max(newest, st.mtimeMs);
|
|
@@ -30394,7 +30458,7 @@ function runBackfillCommand(opts = {}) {
|
|
|
30394
30458
|
const now = opts.now ?? Date.now();
|
|
30395
30459
|
const sinceMs = opts.sinceMs ?? now - DEFAULT_BACKFILL_DAYS * 24 * 60 * 60 * 1000;
|
|
30396
30460
|
const home = failproofaiHome();
|
|
30397
|
-
if (!
|
|
30461
|
+
if (!existsSync38(home)) {
|
|
30398
30462
|
return {
|
|
30399
30463
|
exitCode: 1,
|
|
30400
30464
|
lines: [`No failproofai home at ${home}. Run \`failproofai config\` first.`]
|
|
@@ -30449,8 +30513,8 @@ function runBackfillCommand(opts = {}) {
|
|
|
30449
30513
|
}
|
|
30450
30514
|
try {
|
|
30451
30515
|
const path = backfillRequestPath();
|
|
30452
|
-
|
|
30453
|
-
|
|
30516
|
+
mkdirSync25(dirname19(path), { recursive: true });
|
|
30517
|
+
writeFileSync22(path, `${JSON.stringify({ sinceMs, requestedAtMs: now }, null, 2)}
|
|
30454
30518
|
`, {
|
|
30455
30519
|
mode: 384
|
|
30456
30520
|
});
|
|
@@ -30493,7 +30557,7 @@ var init_backfill_cli = __esm(() => {
|
|
|
30493
30557
|
|
|
30494
30558
|
// src/hooks/harness-cli.ts
|
|
30495
30559
|
import { homedir as homedir29 } from "node:os";
|
|
30496
|
-
import { resolve as
|
|
30560
|
+
import { resolve as resolve26 } from "node:path";
|
|
30497
30561
|
function unknownHarness(name) {
|
|
30498
30562
|
return fail([
|
|
30499
30563
|
`Unknown harness: ${name}`,
|
|
@@ -30537,7 +30601,7 @@ function comparableLabel(raw) {
|
|
|
30537
30601
|
}
|
|
30538
30602
|
function comparablePath(raw) {
|
|
30539
30603
|
const home = homedir29();
|
|
30540
|
-
const expanded = raw === "~" ? home : raw.startsWith("~/") ?
|
|
30604
|
+
const expanded = raw === "~" ? home : raw.startsWith("~/") ? resolve26(home, raw.slice(2)) : raw;
|
|
30541
30605
|
return expanded.replace(/\/+$/, "");
|
|
30542
30606
|
}
|
|
30543
30607
|
function effectiveLabel(entry) {
|
|
@@ -30725,7 +30789,7 @@ var init_harness_cli = __esm(() => {
|
|
|
30725
30789
|
});
|
|
30726
30790
|
|
|
30727
30791
|
// src/hooks/fp-config.ts
|
|
30728
|
-
import { chmodSync as chmodSync6, existsSync as
|
|
30792
|
+
import { chmodSync as chmodSync6, existsSync as existsSync39, mkdirSync as mkdirSync26, readFileSync as readFileSync33, statSync as statSync24, writeFileSync as writeFileSync23 } from "node:fs";
|
|
30729
30793
|
function detectLayout2() {
|
|
30730
30794
|
const raw = readVersionFile2();
|
|
30731
30795
|
if (raw) {
|
|
@@ -30733,17 +30797,17 @@ function detectLayout2() {
|
|
|
30733
30797
|
return { kind: "current", version: raw };
|
|
30734
30798
|
return raw.layout > LAYOUT_VERSION ? { kind: "future", found: raw.layout } : { kind: "stale", found: raw.layout };
|
|
30735
30799
|
}
|
|
30736
|
-
if (
|
|
30800
|
+
if (existsSync39(configFile())) {
|
|
30737
30801
|
const layoutThreePositions = [
|
|
30738
30802
|
legacy.authJson(),
|
|
30739
30803
|
legacy.nextAudit(),
|
|
30740
30804
|
legacy.auditSchedule()
|
|
30741
30805
|
];
|
|
30742
|
-
if (layoutThreePositions.some((p) =>
|
|
30806
|
+
if (layoutThreePositions.some((p) => existsSync39(p)))
|
|
30743
30807
|
return { kind: "stale", found: 3 };
|
|
30744
30808
|
return { kind: "current", version: { layout: LAYOUT_VERSION, cli: "" }, inferred: true };
|
|
30745
30809
|
}
|
|
30746
|
-
if (
|
|
30810
|
+
if (existsSync39(legacy.configToml()))
|
|
30747
30811
|
return { kind: "stale", found: 2 };
|
|
30748
30812
|
const layoutOneMarkers = [
|
|
30749
30813
|
legacy.policyConfig(),
|
|
@@ -30754,7 +30818,7 @@ function detectLayout2() {
|
|
|
30754
30818
|
legacy.ingestCredentials(),
|
|
30755
30819
|
legacy.auditDashboard()
|
|
30756
30820
|
];
|
|
30757
|
-
return layoutOneMarkers.some((p) =>
|
|
30821
|
+
return layoutOneMarkers.some((p) => existsSync39(p)) ? { kind: "stale", found: 1 } : { kind: "absent" };
|
|
30758
30822
|
}
|
|
30759
30823
|
function readLegacyTomlVersion2(text) {
|
|
30760
30824
|
const layout = Number(/^\s*layout\s*=\s*(\d+)\s*$/m.exec(text)?.[1]);
|
|
@@ -30766,7 +30830,7 @@ function readLegacyTomlVersion2(text) {
|
|
|
30766
30830
|
function readVersionFile2() {
|
|
30767
30831
|
let text;
|
|
30768
30832
|
try {
|
|
30769
|
-
text =
|
|
30833
|
+
text = readFileSync33(versionFile(), "utf8");
|
|
30770
30834
|
} catch {
|
|
30771
30835
|
return null;
|
|
30772
30836
|
}
|
|
@@ -30797,14 +30861,14 @@ var init_fp_home2 = () => {};
|
|
|
30797
30861
|
import {
|
|
30798
30862
|
chmodSync as chmodSync7,
|
|
30799
30863
|
copyFileSync as copyFileSync3,
|
|
30800
|
-
existsSync as
|
|
30801
|
-
mkdirSync as
|
|
30802
|
-
readFileSync as
|
|
30864
|
+
existsSync as existsSync40,
|
|
30865
|
+
mkdirSync as mkdirSync27,
|
|
30866
|
+
readFileSync as readFileSync34,
|
|
30803
30867
|
renameSync as renameSync9,
|
|
30804
|
-
rmSync as
|
|
30805
|
-
writeFileSync as
|
|
30868
|
+
rmSync as rmSync15,
|
|
30869
|
+
writeFileSync as writeFileSync24
|
|
30806
30870
|
} from "node:fs";
|
|
30807
|
-
import { basename as basename7, dirname as dirname20, join as join37, resolve as
|
|
30871
|
+
import { basename as basename7, dirname as dirname20, join as join37, resolve as resolve27 } from "node:path";
|
|
30808
30872
|
function migrateToLayout42() {
|
|
30809
30873
|
const moves = [
|
|
30810
30874
|
{ from: legacy.authJson(), to: auditSessionFile() },
|
|
@@ -30820,13 +30884,13 @@ function migrateToLayout42() {
|
|
|
30820
30884
|
}
|
|
30821
30885
|
const migrated = [];
|
|
30822
30886
|
for (const { from, to } of moves) {
|
|
30823
|
-
if (!
|
|
30887
|
+
if (!existsSync40(from))
|
|
30824
30888
|
continue;
|
|
30825
|
-
if (
|
|
30826
|
-
|
|
30889
|
+
if (existsSync40(to)) {
|
|
30890
|
+
rmSync15(from, { force: true });
|
|
30827
30891
|
continue;
|
|
30828
30892
|
}
|
|
30829
|
-
|
|
30893
|
+
mkdirSync27(dirname20(to), { recursive: true });
|
|
30830
30894
|
try {
|
|
30831
30895
|
renameSync9(from, to);
|
|
30832
30896
|
} catch {
|
|
@@ -30834,16 +30898,16 @@ function migrateToLayout42() {
|
|
|
30834
30898
|
copyFileSync3(from, to);
|
|
30835
30899
|
} catch (err) {
|
|
30836
30900
|
try {
|
|
30837
|
-
|
|
30901
|
+
rmSync15(to, { force: true });
|
|
30838
30902
|
} catch {}
|
|
30839
30903
|
throw err;
|
|
30840
30904
|
}
|
|
30841
|
-
|
|
30905
|
+
rmSync15(from, { force: true });
|
|
30842
30906
|
}
|
|
30843
30907
|
migrated.push(`${basename7(from)} → audit/${basename7(to)}`);
|
|
30844
30908
|
}
|
|
30845
30909
|
for (const secret of [auditSessionFile()]) {
|
|
30846
|
-
if (!
|
|
30910
|
+
if (!existsSync40(secret))
|
|
30847
30911
|
continue;
|
|
30848
30912
|
try {
|
|
30849
30913
|
chmodSync7(secret, 384);
|
|
@@ -30869,7 +30933,7 @@ function planMigration2(from, registry = MIGRATIONS2) {
|
|
|
30869
30933
|
}
|
|
30870
30934
|
function readLedger2() {
|
|
30871
30935
|
try {
|
|
30872
|
-
const parsed = JSON.parse(
|
|
30936
|
+
const parsed = JSON.parse(readFileSync34(migrationLedgerFile(), "utf8"));
|
|
30873
30937
|
return Array.isArray(parsed) ? parsed : [];
|
|
30874
30938
|
} catch {
|
|
30875
30939
|
return [];
|
|
@@ -30877,9 +30941,9 @@ function readLedger2() {
|
|
|
30877
30941
|
}
|
|
30878
30942
|
function appendLedger2(entry) {
|
|
30879
30943
|
try {
|
|
30880
|
-
|
|
30944
|
+
mkdirSync27(migrationsDir(), { recursive: true });
|
|
30881
30945
|
const all = [...readLedger2(), entry];
|
|
30882
|
-
|
|
30946
|
+
writeFileSync24(migrationLedgerFile(), `${JSON.stringify(all, null, 2)}
|
|
30883
30947
|
`, "utf8");
|
|
30884
30948
|
} catch {}
|
|
30885
30949
|
}
|
|
@@ -30891,12 +30955,12 @@ function pruneMigratedCredentials2(from) {
|
|
|
30891
30955
|
for (let layout = from;layout < LAYOUT_VERSION; layout++) {
|
|
30892
30956
|
for (const { as, landsAt } of PRUNED_AFTER_SUCCESS2) {
|
|
30893
30957
|
try {
|
|
30894
|
-
if (!
|
|
30958
|
+
if (!existsSync40(landsAt()))
|
|
30895
30959
|
continue;
|
|
30896
|
-
const copy =
|
|
30897
|
-
if (!
|
|
30960
|
+
const copy = resolve27(migrationBackupDir(layout), as);
|
|
30961
|
+
if (!existsSync40(copy))
|
|
30898
30962
|
continue;
|
|
30899
|
-
|
|
30963
|
+
rmSync15(copy, { force: true });
|
|
30900
30964
|
pruned.push(as);
|
|
30901
30965
|
} catch {}
|
|
30902
30966
|
}
|
|
@@ -30907,7 +30971,7 @@ function filesToBackUp2() {
|
|
|
30907
30971
|
const seen = new Map;
|
|
30908
30972
|
for (const f of [...BACKED_UP2, ...BACKED_UP_LEGACY2]) {
|
|
30909
30973
|
const path = f.at();
|
|
30910
|
-
if (
|
|
30974
|
+
if (existsSync40(path))
|
|
30911
30975
|
seen.set(path, backupNameOf2(f));
|
|
30912
30976
|
}
|
|
30913
30977
|
return [...seen].map(([path, as]) => ({ path, as }));
|
|
@@ -30916,14 +30980,14 @@ function backupBeforeMigrating2(from) {
|
|
|
30916
30980
|
const dir = migrationBackupDir(from);
|
|
30917
30981
|
const saved = [];
|
|
30918
30982
|
try {
|
|
30919
|
-
|
|
30920
|
-
|
|
30983
|
+
rmSync15(dir, { recursive: true, force: true });
|
|
30984
|
+
mkdirSync27(dir, { recursive: true });
|
|
30921
30985
|
} catch {
|
|
30922
30986
|
return [];
|
|
30923
30987
|
}
|
|
30924
30988
|
for (const { path: source, as } of filesToBackUp2()) {
|
|
30925
30989
|
try {
|
|
30926
|
-
copyFileSync3(source,
|
|
30990
|
+
copyFileSync3(source, resolve27(dir, as));
|
|
30927
30991
|
saved.push(as);
|
|
30928
30992
|
} catch {}
|
|
30929
30993
|
}
|
|
@@ -31061,16 +31125,16 @@ var init_migrations2 = __esm(() => {
|
|
|
31061
31125
|
|
|
31062
31126
|
// src/hooks/daemon-service.ts
|
|
31063
31127
|
import {
|
|
31064
|
-
existsSync as
|
|
31065
|
-
mkdirSync as
|
|
31128
|
+
existsSync as existsSync41,
|
|
31129
|
+
mkdirSync as mkdirSync28,
|
|
31066
31130
|
mkdtempSync as mkdtempSync2,
|
|
31067
|
-
readFileSync as
|
|
31068
|
-
writeFileSync as
|
|
31131
|
+
readFileSync as readFileSync35,
|
|
31132
|
+
writeFileSync as writeFileSync25,
|
|
31069
31133
|
unlinkSync as unlinkSync5,
|
|
31070
|
-
rmSync as
|
|
31134
|
+
rmSync as rmSync16
|
|
31071
31135
|
} from "node:fs";
|
|
31072
31136
|
import { homedir as homedir30, tmpdir as tmpdir3, userInfo as userInfo2 } from "node:os";
|
|
31073
|
-
import { resolve as
|
|
31137
|
+
import { resolve as resolve28 } from "node:path";
|
|
31074
31138
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
31075
31139
|
function isDaemonSupportedPlatform2() {
|
|
31076
31140
|
return process.platform === "linux" || process.platform === "darwin";
|
|
@@ -31086,13 +31150,13 @@ function resolveFailproofaidBinaryPath2() {
|
|
|
31086
31150
|
if (process.env.FAILPROOFAI_DAEMON_BINARY)
|
|
31087
31151
|
return process.env.FAILPROOFAI_DAEMON_BINARY;
|
|
31088
31152
|
const downloaded = installedBinaryPath();
|
|
31089
|
-
if (
|
|
31153
|
+
if (existsSync41(downloaded))
|
|
31090
31154
|
return downloaded;
|
|
31091
31155
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
31092
31156
|
if (packageRoot) {
|
|
31093
31157
|
for (const profile of ["release", "debug"]) {
|
|
31094
|
-
const candidate =
|
|
31095
|
-
if (
|
|
31158
|
+
const candidate = resolve28(packageRoot, "target", profile, "failproofaid");
|
|
31159
|
+
if (existsSync41(candidate))
|
|
31096
31160
|
return candidate;
|
|
31097
31161
|
}
|
|
31098
31162
|
}
|
|
@@ -31122,8 +31186,8 @@ function resolveWorkerCommand2() {
|
|
|
31122
31186
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
31123
31187
|
if (!packageRoot)
|
|
31124
31188
|
return null;
|
|
31125
|
-
const workerScript =
|
|
31126
|
-
if (!
|
|
31189
|
+
const workerScript = resolve28(packageRoot, "dist", "worker.mjs");
|
|
31190
|
+
if (!existsSync41(workerScript))
|
|
31127
31191
|
return null;
|
|
31128
31192
|
return `${shellQuote2(process.execPath)} ${shellQuote2(workerScript)}`;
|
|
31129
31193
|
}
|
|
@@ -31133,8 +31197,8 @@ function resolveCliCommand2() {
|
|
|
31133
31197
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
31134
31198
|
if (!packageRoot)
|
|
31135
31199
|
return null;
|
|
31136
|
-
const cliScript =
|
|
31137
|
-
if (!
|
|
31200
|
+
const cliScript = resolve28(packageRoot, "dist", "cli.mjs");
|
|
31201
|
+
if (!existsSync41(cliScript))
|
|
31138
31202
|
return null;
|
|
31139
31203
|
return `${shellQuote2(process.execPath)} ${shellQuote2(cliScript)}`;
|
|
31140
31204
|
}
|
|
@@ -31147,8 +31211,8 @@ function workerScriptPath2() {
|
|
|
31147
31211
|
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
|
|
31148
31212
|
if (!packageRoot)
|
|
31149
31213
|
return null;
|
|
31150
|
-
const workerScript =
|
|
31151
|
-
return
|
|
31214
|
+
const workerScript = resolve28(packageRoot, "dist", "worker.mjs");
|
|
31215
|
+
return existsSync41(workerScript) ? workerScript : null;
|
|
31152
31216
|
}
|
|
31153
31217
|
function assertUnitSafe2(value, field) {
|
|
31154
31218
|
if (UNIT_UNSAFE_RE2.test(value)) {
|
|
@@ -31174,10 +31238,10 @@ function systemdUnitDir2() {
|
|
|
31174
31238
|
return process.env.FAILPROOFAI_SYSTEMD_DIR || "/etc/systemd/system";
|
|
31175
31239
|
}
|
|
31176
31240
|
function systemdUnitPath2(user = serviceUser2()) {
|
|
31177
|
-
return
|
|
31241
|
+
return resolve28(systemdUnitDir2(), systemdUnitName2(user));
|
|
31178
31242
|
}
|
|
31179
31243
|
function legacySystemdUserUnitPath2() {
|
|
31180
|
-
return
|
|
31244
|
+
return resolve28(homedir30(), ".config", "systemd", "user", "failproofaid.service");
|
|
31181
31245
|
}
|
|
31182
31246
|
function launchdLabel2(user = serviceUser2()) {
|
|
31183
31247
|
return `ai.failproof.failproofaid.${user}`;
|
|
@@ -31186,7 +31250,7 @@ function launchdPlistPath2(user = serviceUser2()) {
|
|
|
31186
31250
|
return `/Library/LaunchDaemons/${launchdLabel2(user)}.plist`;
|
|
31187
31251
|
}
|
|
31188
31252
|
function legacyLaunchAgentPlistPath2() {
|
|
31189
|
-
return
|
|
31253
|
+
return resolve28(homedir30(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
|
|
31190
31254
|
}
|
|
31191
31255
|
function legacySharedLaunchDaemonPath2() {
|
|
31192
31256
|
return "/Library/LaunchDaemons/ai.failproof.failproofaid.plist";
|
|
@@ -31224,20 +31288,20 @@ function runPrivileged2(command, args) {
|
|
|
31224
31288
|
execFileSync4(cmd, argv, { stdio: "ignore", timeout: SERVICE_CMD_TIMEOUT_MS2 });
|
|
31225
31289
|
}
|
|
31226
31290
|
function writePrivilegedFile2(destination, contents, mode = "0644") {
|
|
31227
|
-
const stagingDir = mkdtempSync2(
|
|
31228
|
-
const staging =
|
|
31291
|
+
const stagingDir = mkdtempSync2(resolve28(tmpdir3(), "failproofaid-stage-"));
|
|
31292
|
+
const staging = resolve28(stagingDir, "service-definition");
|
|
31229
31293
|
try {
|
|
31230
|
-
|
|
31294
|
+
writeFileSync25(staging, contents, "utf8");
|
|
31231
31295
|
runPrivileged2("install", ["-m", mode, staging, destination]);
|
|
31232
31296
|
} finally {
|
|
31233
|
-
|
|
31297
|
+
rmSync16(stagingDir, { recursive: true, force: true });
|
|
31234
31298
|
}
|
|
31235
31299
|
}
|
|
31236
31300
|
function removeLegacyUserService2() {
|
|
31237
31301
|
try {
|
|
31238
31302
|
if (process.platform === "linux") {
|
|
31239
31303
|
const legacy = legacySystemdUserUnitPath2();
|
|
31240
|
-
if (!
|
|
31304
|
+
if (!existsSync41(legacy))
|
|
31241
31305
|
return;
|
|
31242
31306
|
try {
|
|
31243
31307
|
execFileSync4("systemctl", ["--user", "disable", "--now", "failproofaid.service"], {
|
|
@@ -31254,7 +31318,7 @@ function removeLegacyUserService2() {
|
|
|
31254
31318
|
} catch {}
|
|
31255
31319
|
} else {
|
|
31256
31320
|
const legacyAgent = legacyLaunchAgentPlistPath2();
|
|
31257
|
-
if (
|
|
31321
|
+
if (existsSync41(legacyAgent)) {
|
|
31258
31322
|
try {
|
|
31259
31323
|
execFileSync4("launchctl", ["unload", "-w", legacyAgent], {
|
|
31260
31324
|
stdio: "ignore",
|
|
@@ -31264,7 +31328,7 @@ function removeLegacyUserService2() {
|
|
|
31264
31328
|
unlinkSync5(legacyAgent);
|
|
31265
31329
|
}
|
|
31266
31330
|
const legacyDaemon = legacySharedLaunchDaemonPath2();
|
|
31267
|
-
if (
|
|
31331
|
+
if (existsSync41(legacyDaemon)) {
|
|
31268
31332
|
try {
|
|
31269
31333
|
runPrivileged2("launchctl", ["unload", "-w", legacyDaemon]);
|
|
31270
31334
|
} catch {}
|
|
@@ -31281,7 +31345,7 @@ function systemdUnitContents2(binaryPath, workerCmd, cliCmd = null) {
|
|
|
31281
31345
|
const user = assertUnitSafe2(serviceUser2(), "User");
|
|
31282
31346
|
assertUnitSafe2(binaryPath, "ExecStart");
|
|
31283
31347
|
assertUnitSafe2(homedir30(), "HOME");
|
|
31284
|
-
const conditionPaths = [binaryPath, workerScriptPath2()].filter((p) => typeof p === "string" &&
|
|
31348
|
+
const conditionPaths = [binaryPath, workerScriptPath2()].filter((p) => typeof p === "string" && existsSync41(p));
|
|
31285
31349
|
const conditionLines = conditionPaths.map((p) => `ConditionPathExists=${assertUnitSafe2(p, "ConditionPathExists")}
|
|
31286
31350
|
`).join("");
|
|
31287
31351
|
return `[Unit]
|
|
@@ -31339,9 +31403,9 @@ ${env.map(([key, value]) => ` <key>${key}</key>
|
|
|
31339
31403
|
<key>UserName</key>
|
|
31340
31404
|
<string>${escapeXml3(serviceUser2())}</string>
|
|
31341
31405
|
${envBlock} <key>StandardOutPath</key>
|
|
31342
|
-
<string>${escapeXml3(
|
|
31406
|
+
<string>${escapeXml3(resolve28(logDir, "failproofaid.log"))}</string>
|
|
31343
31407
|
<key>StandardErrorPath</key>
|
|
31344
|
-
<string>${escapeXml3(
|
|
31408
|
+
<string>${escapeXml3(resolve28(logDir, "failproofaid.err.log"))}</string>
|
|
31345
31409
|
</dict>
|
|
31346
31410
|
</plist>
|
|
31347
31411
|
`;
|
|
@@ -31387,7 +31451,7 @@ async function installDaemonService2() {
|
|
|
31387
31451
|
} else {
|
|
31388
31452
|
const plistPath = launchdPlistPath2();
|
|
31389
31453
|
const logDir = logsDir();
|
|
31390
|
-
|
|
31454
|
+
mkdirSync28(logDir, { recursive: true });
|
|
31391
31455
|
try {
|
|
31392
31456
|
runPrivileged2("launchctl", ["unload", plistPath]);
|
|
31393
31457
|
} catch {}
|
|
@@ -31486,7 +31550,7 @@ function daemonServiceStatus2() {
|
|
|
31486
31550
|
if (!isDaemonSupportedPlatform2())
|
|
31487
31551
|
return "unsupported-platform";
|
|
31488
31552
|
if (process.platform === "linux") {
|
|
31489
|
-
if (!
|
|
31553
|
+
if (!existsSync41(systemdUnitPath2()))
|
|
31490
31554
|
return "not-installed";
|
|
31491
31555
|
try {
|
|
31492
31556
|
const out = execFileSync4("systemctl", ["is-active", systemdUnitName2()], {
|
|
@@ -31499,7 +31563,7 @@ function daemonServiceStatus2() {
|
|
|
31499
31563
|
}
|
|
31500
31564
|
}
|
|
31501
31565
|
const plistPath = launchdPlistPath2();
|
|
31502
|
-
if (!
|
|
31566
|
+
if (!existsSync41(plistPath))
|
|
31503
31567
|
return "not-installed";
|
|
31504
31568
|
try {
|
|
31505
31569
|
const root = typeof process.getuid === "function" && process.getuid() === 0;
|
|
@@ -31529,7 +31593,7 @@ var init_daemon_service2 = __esm(() => {
|
|
|
31529
31593
|
});
|
|
31530
31594
|
|
|
31531
31595
|
// src/hooks/uninstall-cli.ts
|
|
31532
|
-
import { existsSync as
|
|
31596
|
+
import { existsSync as existsSync42, rmSync as rmSync17 } from "node:fs";
|
|
31533
31597
|
function survey(cwd) {
|
|
31534
31598
|
const clis = [];
|
|
31535
31599
|
for (const id of listInstallableIds()) {
|
|
@@ -31550,9 +31614,9 @@ function survey(cwd) {
|
|
|
31550
31614
|
return {
|
|
31551
31615
|
clis,
|
|
31552
31616
|
servicePath,
|
|
31553
|
-
serviceInstalled: !!servicePath &&
|
|
31617
|
+
serviceInstalled: !!servicePath && existsSync42(servicePath),
|
|
31554
31618
|
daemonConfigured,
|
|
31555
|
-
homeExists:
|
|
31619
|
+
homeExists: existsSync42(failproofaiHome())
|
|
31556
31620
|
};
|
|
31557
31621
|
}
|
|
31558
31622
|
async function runUninstallCommand(opts = {}) {
|
|
@@ -31650,7 +31714,7 @@ async function runUninstallCommand(opts = {}) {
|
|
|
31650
31714
|
} catch {}
|
|
31651
31715
|
try {
|
|
31652
31716
|
await uninstallDaemonService();
|
|
31653
|
-
if (found.servicePath &&
|
|
31717
|
+
if (found.servicePath && existsSync42(found.servicePath)) {
|
|
31654
31718
|
failures.push(`the service at ${found.servicePath} is still there (most often: no sudo). ` + `Remove it with the commands below.`);
|
|
31655
31719
|
} else {
|
|
31656
31720
|
lines.push(`✓ stopped and removed the daemon service`);
|
|
@@ -31665,7 +31729,7 @@ async function runUninstallCommand(opts = {}) {
|
|
|
31665
31729
|
}
|
|
31666
31730
|
if (opts.purge && found.homeExists) {
|
|
31667
31731
|
try {
|
|
31668
|
-
|
|
31732
|
+
rmSync17(failproofaiHome(), { recursive: true, force: true });
|
|
31669
31733
|
purged = true;
|
|
31670
31734
|
lines.push(`✓ deleted ${failproofaiHome()}`);
|
|
31671
31735
|
} catch (err) {
|
|
@@ -31676,7 +31740,7 @@ async function runUninstallCommand(opts = {}) {
|
|
|
31676
31740
|
lines.push(``, `Not everything could be removed:`);
|
|
31677
31741
|
for (const f of failures)
|
|
31678
31742
|
lines.push(` ✗ ${f}`);
|
|
31679
|
-
if (found.servicePath &&
|
|
31743
|
+
if (found.servicePath && existsSync42(found.servicePath)) {
|
|
31680
31744
|
lines.push(``, `To remove the service by hand:`, ...manualServiceRemoval(found.servicePath), ``, `(\`${daemonStatusCommand()}\` shows its current state.)`);
|
|
31681
31745
|
}
|
|
31682
31746
|
return { exitCode: 1, lines, planLines, purged };
|
|
@@ -31711,8 +31775,8 @@ var init_uninstall_cli = __esm(() => {
|
|
|
31711
31775
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
31712
31776
|
import { homedir as homedir31, tmpdir as tmpdir4 } from "node:os";
|
|
31713
31777
|
import { createHash as createHash9 } from "node:crypto";
|
|
31714
|
-
import { copyFileSync as copyFileSync4, existsSync as
|
|
31715
|
-
import { basename as basename8, dirname as dirname21, isAbsolute as isAbsolute4, join as join38, relative as relative5, resolve as
|
|
31778
|
+
import { copyFileSync as copyFileSync4, existsSync as existsSync43, mkdirSync as mkdirSync29, mkdtempSync as mkdtempSync3, readFileSync as readFileSync36, readdirSync as readdirSync21, realpathSync as realpathSync3, rmSync as rmSync18, statSync as statSync25, writeFileSync as writeFileSync26 } from "node:fs";
|
|
31779
|
+
import { basename as basename8, dirname as dirname21, isAbsolute as isAbsolute4, join as join38, relative as relative5, resolve as resolve29, sep as sep6 } from "node:path";
|
|
31716
31780
|
function parseList(rest, flag) {
|
|
31717
31781
|
const idx = rest.findIndex((a) => a === flag || a.startsWith(`${flag}=`));
|
|
31718
31782
|
if (idx === -1)
|
|
@@ -31812,7 +31876,7 @@ async function build(rest) {
|
|
|
31812
31876
|
const version = flag("version");
|
|
31813
31877
|
const commit = flag("commit");
|
|
31814
31878
|
const effect = flag("effect") ?? "enforce";
|
|
31815
|
-
const outDir =
|
|
31879
|
+
const outDir = resolve29(flag("out") ?? "dist-pack");
|
|
31816
31880
|
if (!entry || !id || !version) {
|
|
31817
31881
|
return fail2([
|
|
31818
31882
|
"Usage: failproofai publish <entry.mjs> --repo <owner>/<repo> --version <version>",
|
|
@@ -31825,10 +31889,10 @@ async function build(rest) {
|
|
|
31825
31889
|
} catch (err) {
|
|
31826
31890
|
return fail2([err instanceof Error ? err.message : String(err)]);
|
|
31827
31891
|
}
|
|
31828
|
-
const entryPath =
|
|
31829
|
-
if (!
|
|
31892
|
+
const entryPath = resolve29(entry);
|
|
31893
|
+
if (!existsSync43(entryPath))
|
|
31830
31894
|
return fail2([`No such file: ${entryPath}`]);
|
|
31831
|
-
const source =
|
|
31895
|
+
const source = readFileSync36(entryPath, "utf8");
|
|
31832
31896
|
const localImport = /(?:^|\n)\s*(?:import|export)[^;\n]*from\s+["'](\.[^"']*)["']/.exec(source);
|
|
31833
31897
|
if (localImport) {
|
|
31834
31898
|
return fail2([
|
|
@@ -31884,14 +31948,14 @@ async function build(rest) {
|
|
|
31884
31948
|
policies
|
|
31885
31949
|
}, null, 2) + `
|
|
31886
31950
|
`;
|
|
31887
|
-
|
|
31888
|
-
const manifestPath =
|
|
31889
|
-
const entryOut =
|
|
31890
|
-
|
|
31951
|
+
mkdirSync29(outDir, { recursive: true });
|
|
31952
|
+
const manifestPath = resolve29(outDir, PACK_MANIFEST_ASSET);
|
|
31953
|
+
const entryOut = resolve29(outDir, PACK_ENTRY_ASSET);
|
|
31954
|
+
writeFileSync26(manifestPath, manifest, "utf8");
|
|
31891
31955
|
copyFileSync4(entryPath, entryOut);
|
|
31892
31956
|
const sha = (bytes) => createHash9("sha256").update(bytes).digest("hex");
|
|
31893
|
-
|
|
31894
|
-
${sha(
|
|
31957
|
+
writeFileSync26(resolve29(outDir, PACK_CHECKSUMS_ASSET), `${sha(manifest)} ${PACK_MANIFEST_ASSET}
|
|
31958
|
+
${sha(readFileSync36(entryOut))} ${PACK_ENTRY_ASSET}
|
|
31895
31959
|
`, "utf8");
|
|
31896
31960
|
const on = policies.filter((p) => p.defaultEnabled).length;
|
|
31897
31961
|
return ok2([
|
|
@@ -32020,12 +32084,12 @@ async function scaffold(target) {
|
|
|
32020
32084
|
return ok2(["Nothing written."]);
|
|
32021
32085
|
chosen = answer.trim();
|
|
32022
32086
|
}
|
|
32023
|
-
const path =
|
|
32024
|
-
if (
|
|
32087
|
+
const path = resolve29(withPolicyExtension(chosen ?? "my-policies"));
|
|
32088
|
+
if (existsSync43(path)) {
|
|
32025
32089
|
return fail2([`${path} already exists — name a different file, or edit that one.`]);
|
|
32026
32090
|
}
|
|
32027
|
-
|
|
32028
|
-
|
|
32091
|
+
mkdirSync29(resolve29(path, ".."), { recursive: true });
|
|
32092
|
+
writeFileSync26(path, `import { customPolicies, allow, deny } from "failproofai";
|
|
32029
32093
|
|
|
32030
32094
|
// One file, no relative imports: only this entry is digest-pinned, so a pack
|
|
32031
32095
|
// that imported siblings could not honestly claim to be verified.
|
|
@@ -32062,7 +32126,7 @@ customPolicies.add({
|
|
|
32062
32126
|
function inferRepo(entryPath) {
|
|
32063
32127
|
try {
|
|
32064
32128
|
const url = execFileSync5("git", ["remote", "get-url", "origin"], {
|
|
32065
|
-
cwd:
|
|
32129
|
+
cwd: resolve29(entryPath, ".."),
|
|
32066
32130
|
encoding: "utf8",
|
|
32067
32131
|
stdio: ["ignore", "pipe", "ignore"],
|
|
32068
32132
|
timeout: 5000
|
|
@@ -32074,7 +32138,7 @@ function inferRepo(entryPath) {
|
|
|
32074
32138
|
}
|
|
32075
32139
|
}
|
|
32076
32140
|
function inferCommit(entryPath, outDir, sources) {
|
|
32077
|
-
const cwd =
|
|
32141
|
+
const cwd = resolve29(entryPath, "..");
|
|
32078
32142
|
const raw = (args) => {
|
|
32079
32143
|
try {
|
|
32080
32144
|
return execFileSync5("git", args, {
|
|
@@ -32129,9 +32193,9 @@ function realOrSelf(path) {
|
|
|
32129
32193
|
}
|
|
32130
32194
|
}
|
|
32131
32195
|
function sourcesInHead(git, raw, sources) {
|
|
32132
|
-
const paths = sources.map((f) => realOrSelf(
|
|
32196
|
+
const paths = sources.map((f) => realOrSelf(resolve29(f)));
|
|
32133
32197
|
const shown = git(["rev-parse", "--show-toplevel"]);
|
|
32134
|
-
const top = shown === null ? null : realOrSelf(
|
|
32198
|
+
const top = shown === null ? null : realOrSelf(resolve29(shown));
|
|
32135
32199
|
const missing = [];
|
|
32136
32200
|
for (const path of paths) {
|
|
32137
32201
|
const rel = top ? relative5(top, path) : null;
|
|
@@ -32155,7 +32219,7 @@ function sourcesInHead(git, raw, sources) {
|
|
|
32155
32219
|
]);
|
|
32156
32220
|
if (status === null)
|
|
32157
32221
|
return { ok: false, offending: paths, why: "modified" };
|
|
32158
|
-
const dirty = porcelainEntries(status).flatMap((entry) => [entry.path, entry.from].filter(Boolean).map((path) =>
|
|
32222
|
+
const dirty = porcelainEntries(status).flatMap((entry) => [entry.path, entry.from].filter(Boolean).map((path) => resolve29(top ?? ".", path)));
|
|
32159
32223
|
if (dirty.length > 0)
|
|
32160
32224
|
return { ok: false, offending: dirty, why: "modified" };
|
|
32161
32225
|
return { ok: true };
|
|
@@ -32163,19 +32227,19 @@ function sourcesInHead(git, raw, sources) {
|
|
|
32163
32227
|
function skipOutDir(git, entryPath, outDir) {
|
|
32164
32228
|
if (!outDir)
|
|
32165
32229
|
return [];
|
|
32166
|
-
const out =
|
|
32167
|
-
if (
|
|
32230
|
+
const out = resolve29(outDir);
|
|
32231
|
+
if (resolve29(entryPath).startsWith(out + sep6))
|
|
32168
32232
|
return [];
|
|
32169
32233
|
const top = git(["rev-parse", "--show-toplevel"]);
|
|
32170
32234
|
if (!top)
|
|
32171
32235
|
return [];
|
|
32172
|
-
const rel = relative5(
|
|
32236
|
+
const rel = relative5(resolve29(top), out);
|
|
32173
32237
|
if (!rel || rel.startsWith("..") || isAbsolute4(rel))
|
|
32174
32238
|
return [];
|
|
32175
32239
|
return ["--", ":(top)", `:(exclude,literal,top)${rel.split(sep6).join("/")}`];
|
|
32176
32240
|
}
|
|
32177
32241
|
function inferTaggedVersion(entryPath, sources) {
|
|
32178
|
-
const cwd =
|
|
32242
|
+
const cwd = resolve29(entryPath, "..");
|
|
32179
32243
|
const raw = (args) => {
|
|
32180
32244
|
try {
|
|
32181
32245
|
return execFileSync5("git", args, {
|
|
@@ -32205,7 +32269,7 @@ function inferTaggedVersion(entryPath, sources) {
|
|
|
32205
32269
|
function findEntry(dir) {
|
|
32206
32270
|
let names;
|
|
32207
32271
|
try {
|
|
32208
|
-
names =
|
|
32272
|
+
names = readdirSync21(dir);
|
|
32209
32273
|
} catch {
|
|
32210
32274
|
return [];
|
|
32211
32275
|
}
|
|
@@ -32213,11 +32277,11 @@ function findEntry(dir) {
|
|
|
32213
32277
|
for (const name of names) {
|
|
32214
32278
|
if (!/\.(mjs|js|ts)$/.test(name))
|
|
32215
32279
|
continue;
|
|
32216
|
-
const full =
|
|
32280
|
+
const full = resolve29(dir, name);
|
|
32217
32281
|
try {
|
|
32218
|
-
if (
|
|
32282
|
+
if (statSync25(full).size > 512 * 1024)
|
|
32219
32283
|
continue;
|
|
32220
|
-
const text =
|
|
32284
|
+
const text = readFileSync36(full, "utf8");
|
|
32221
32285
|
if (/from\s+["']failproofai["']/.test(text) && /customPolicies\s*\.\s*add\s*\(/.test(text)) {
|
|
32222
32286
|
found.push(full);
|
|
32223
32287
|
}
|
|
@@ -32228,27 +32292,27 @@ function findEntry(dir) {
|
|
|
32228
32292
|
return found.sort();
|
|
32229
32293
|
}
|
|
32230
32294
|
function withLocalImports(sources) {
|
|
32231
|
-
const seen = new Set(sources.map((f) =>
|
|
32295
|
+
const seen = new Set(sources.map((f) => resolve29(f)));
|
|
32232
32296
|
const queue = [...seen];
|
|
32233
32297
|
while (queue.length > 0 && seen.size < 500) {
|
|
32234
32298
|
const file = queue.shift();
|
|
32235
32299
|
let text;
|
|
32236
32300
|
try {
|
|
32237
|
-
if (
|
|
32301
|
+
if (statSync25(file).size > 512 * 1024)
|
|
32238
32302
|
continue;
|
|
32239
|
-
text =
|
|
32303
|
+
text = readFileSync36(file, "utf8");
|
|
32240
32304
|
} catch {
|
|
32241
32305
|
continue;
|
|
32242
32306
|
}
|
|
32243
32307
|
for (const re of LOCAL_IMPORT_RES) {
|
|
32244
32308
|
for (const match of text.matchAll(re)) {
|
|
32245
|
-
const base =
|
|
32309
|
+
const base = resolve29(dirname21(file), match[1]);
|
|
32246
32310
|
for (const ext of LOCAL_IMPORT_EXTENSIONS) {
|
|
32247
32311
|
const candidate = base + ext;
|
|
32248
32312
|
if (seen.has(candidate))
|
|
32249
32313
|
break;
|
|
32250
32314
|
try {
|
|
32251
|
-
if (!
|
|
32315
|
+
if (!statSync25(candidate).isFile())
|
|
32252
32316
|
continue;
|
|
32253
32317
|
} catch {
|
|
32254
32318
|
continue;
|
|
@@ -32263,7 +32327,7 @@ function withLocalImports(sources) {
|
|
|
32263
32327
|
return [...seen];
|
|
32264
32328
|
}
|
|
32265
32329
|
function settleGitState(entryPath, provenance, packFiles, id, outDir) {
|
|
32266
|
-
const cwd =
|
|
32330
|
+
const cwd = resolve29(entryPath, "..");
|
|
32267
32331
|
const raw = (args) => {
|
|
32268
32332
|
try {
|
|
32269
32333
|
return execFileSync5("git", args, {
|
|
@@ -32338,11 +32402,11 @@ function settleGitState(entryPath, provenance, packFiles, id, outDir) {
|
|
|
32338
32402
|
if (root === null || status === null)
|
|
32339
32403
|
return null;
|
|
32340
32404
|
const entries = porcelainEntries(status);
|
|
32341
|
-
const dirty = entries.map((entry) =>
|
|
32342
|
-
const renamedFrom = entries.filter((entry) => entry.from).map((entry) =>
|
|
32405
|
+
const dirty = entries.map((entry) => resolve29(root, entry.path));
|
|
32406
|
+
const renamedFrom = entries.filter((entry) => entry.from).map((entry) => resolve29(root, entry.from));
|
|
32343
32407
|
if (dirty.length === 0)
|
|
32344
32408
|
return null;
|
|
32345
|
-
const mine = new Set(packFiles.map((f) =>
|
|
32409
|
+
const mine = new Set(packFiles.map((f) => resolve29(f)));
|
|
32346
32410
|
const foreign = dirty.filter((path) => !mine.has(path));
|
|
32347
32411
|
const toStage = [...dirty, ...renamedFrom];
|
|
32348
32412
|
if (foreign.length > 0) {
|
|
@@ -32475,7 +32539,7 @@ function pushExistingHistory(dir, owner, name, token) {
|
|
|
32475
32539
|
return false;
|
|
32476
32540
|
const askpass = join38(mkdtempSync3(join38(tmpdir4(), "fpai-askpass-")), "askpass.sh");
|
|
32477
32541
|
try {
|
|
32478
|
-
|
|
32542
|
+
writeFileSync26(askpass, `#!/bin/sh
|
|
32479
32543
|
case "$1" in
|
|
32480
32544
|
*Username*) echo x-access-token ;;
|
|
32481
32545
|
*) echo "$FPAI_GH_TOKEN" ;;
|
|
@@ -32495,7 +32559,7 @@ esac
|
|
|
32495
32559
|
return true;
|
|
32496
32560
|
} finally {
|
|
32497
32561
|
try {
|
|
32498
|
-
|
|
32562
|
+
rmSync18(dirname21(askpass), { recursive: true, force: true });
|
|
32499
32563
|
} catch {}
|
|
32500
32564
|
}
|
|
32501
32565
|
}
|
|
@@ -32519,8 +32583,8 @@ failproofai policies add ${owner}/${name}
|
|
|
32519
32583
|
function findBun() {
|
|
32520
32584
|
const candidates = [
|
|
32521
32585
|
"bun",
|
|
32522
|
-
process.env.BUN_INSTALL ?
|
|
32523
|
-
|
|
32586
|
+
process.env.BUN_INSTALL ? resolve29(process.env.BUN_INSTALL, "bin", "bun") : null,
|
|
32587
|
+
resolve29(homedir31(), ".bun", "bin", "bun"),
|
|
32524
32588
|
"/opt/homebrew/bin/bun",
|
|
32525
32589
|
"/usr/local/bin/bun"
|
|
32526
32590
|
].filter((c) => c !== null);
|
|
@@ -32546,12 +32610,12 @@ function bundleEntry(sources, outDir) {
|
|
|
32546
32610
|
]
|
|
32547
32611
|
};
|
|
32548
32612
|
}
|
|
32549
|
-
|
|
32550
|
-
const entry =
|
|
32551
|
-
|
|
32613
|
+
mkdirSync29(outDir, { recursive: true });
|
|
32614
|
+
const entry = resolve29(outDir, ".entry.generated.mjs");
|
|
32615
|
+
writeFileSync26(entry, sources.map((f) => `import ${JSON.stringify(f.startsWith("/") ? f : resolve29(f))};`).join(`
|
|
32552
32616
|
`) + `
|
|
32553
32617
|
`, "utf8");
|
|
32554
|
-
const bundled =
|
|
32618
|
+
const bundled = resolve29(outDir, ".bundled.mjs");
|
|
32555
32619
|
try {
|
|
32556
32620
|
execFileSync5(bun, [
|
|
32557
32621
|
"build",
|
|
@@ -32669,7 +32733,7 @@ async function publish(rest) {
|
|
|
32669
32733
|
`);
|
|
32670
32734
|
const token = githubToken();
|
|
32671
32735
|
const login = token ? await credentialLogin(token) : null;
|
|
32672
|
-
const folder = basename8(
|
|
32736
|
+
const folder = basename8(resolve29(entry, ".."));
|
|
32673
32737
|
const answered = await askWhereToPublish(`${login ?? "your-account"}/${folder}`, { stdin: process.stdin, stdout: process.stdout });
|
|
32674
32738
|
if (answered === null)
|
|
32675
32739
|
return ok2(["Nothing was published."]);
|
|
@@ -32680,7 +32744,7 @@ async function publish(rest) {
|
|
|
32680
32744
|
let versionFromSha = false;
|
|
32681
32745
|
const dryRun = rest.includes("--dry-run") || !repo;
|
|
32682
32746
|
const allowPrivate = rest.includes("--allow-private");
|
|
32683
|
-
const id = flag("id") ?? repo ?? (dryRun && entry ? `local/${basename8(
|
|
32747
|
+
const id = flag("id") ?? repo ?? (dryRun && entry ? `local/${basename8(resolve29(entry, ".."))}` : undefined);
|
|
32684
32748
|
const [owner, name] = (repo ?? "/").split("/");
|
|
32685
32749
|
if (repo && (!owner || !name || repo.split("/").length !== 2)) {
|
|
32686
32750
|
return fail2([`--repo must be <owner>/<repo>, got ${JSON.stringify(repo)}`]);
|
|
@@ -32699,7 +32763,7 @@ async function publish(rest) {
|
|
|
32699
32763
|
"With no --repo it writes the three release assets and stops."
|
|
32700
32764
|
]);
|
|
32701
32765
|
}
|
|
32702
|
-
const outDirEarly =
|
|
32766
|
+
const outDirEarly = resolve29(flag("out") ?? "dist-pack");
|
|
32703
32767
|
let provenance = entry ? inferCommit(entry, outDirEarly, bundledSources) : null;
|
|
32704
32768
|
const gitLines = [];
|
|
32705
32769
|
if (!version && entry && interactive) {
|
|
@@ -32739,7 +32803,7 @@ async function publish(rest) {
|
|
|
32739
32803
|
"It needs write access to releases on that repository, and nothing else."
|
|
32740
32804
|
]);
|
|
32741
32805
|
}
|
|
32742
|
-
const ensured = await ensureRepo(owner, name, id, token,
|
|
32806
|
+
const ensured = await ensureRepo(owner, name, id, token, resolve29(entry, ".."));
|
|
32743
32807
|
if ("error" in ensured)
|
|
32744
32808
|
return fail2(ensured.error);
|
|
32745
32809
|
created = ensured.created;
|
|
@@ -32759,7 +32823,7 @@ async function publish(rest) {
|
|
|
32759
32823
|
}
|
|
32760
32824
|
const tag = flag("tag") ?? version;
|
|
32761
32825
|
let entryToBuild = entry;
|
|
32762
|
-
const needsBundle = discovered.length > 1 || /(?:^|\n)\s*(?:import|export)[^;\n]*from\s+["']\.[^"']*["']/.test(
|
|
32826
|
+
const needsBundle = discovered.length > 1 || /(?:^|\n)\s*(?:import|export)[^;\n]*from\s+["']\.[^"']*["']/.test(readFileSync36(entry, "utf8"));
|
|
32763
32827
|
if (needsBundle) {
|
|
32764
32828
|
const sources = discovered.length > 1 ? discovered : [entry];
|
|
32765
32829
|
const bundled = bundleEntry(sources, outDirEarly);
|
|
@@ -32838,7 +32902,7 @@ async function publish(rest) {
|
|
|
32838
32902
|
if (prior) {
|
|
32839
32903
|
await gh(`${GITHUB_API2}/repos/${owner}/${name}/releases/assets/${prior.id}`, auth, { method: "DELETE" });
|
|
32840
32904
|
}
|
|
32841
|
-
const bytes =
|
|
32905
|
+
const bytes = readFileSync36(resolve29(outDir, asset));
|
|
32842
32906
|
const upload = await gh(`${GITHUB_UPLOADS2}/repos/${owner}/${name}/releases/${releaseId}/assets?name=${encodeURIComponent(asset)}`, auth, {
|
|
32843
32907
|
method: "POST",
|
|
32844
32908
|
contentType: asset.endsWith(".json") ? "application/json" : "application/octet-stream",
|
|
@@ -33519,8 +33583,8 @@ var init_install_prompt = __esm(() => {
|
|
|
33519
33583
|
|
|
33520
33584
|
// src/hooks/manager.ts
|
|
33521
33585
|
import { execSync as execSync7 } from "node:child_process";
|
|
33522
|
-
import { existsSync as
|
|
33523
|
-
import { resolve as
|
|
33586
|
+
import { existsSync as existsSync44 } from "node:fs";
|
|
33587
|
+
import { resolve as resolve30, basename as basename9 } from "node:path";
|
|
33524
33588
|
import { platform as platform4, arch as arch4, release as release3, hostname as hostname6 } from "node:os";
|
|
33525
33589
|
function getSettingsPath2(scope, cwd) {
|
|
33526
33590
|
return claudeCode.getSettingsPath(scope, cwd);
|
|
@@ -33739,9 +33803,9 @@ async function installHooksImpl2(policyNames, scope = "user", cwd, includeBeta =
|
|
|
33739
33803
|
delete configToWrite.customPoliciesPath;
|
|
33740
33804
|
delete configToWrite.customPoliciesPaths;
|
|
33741
33805
|
} else if (customPoliciesPath && (typeof customPoliciesPath === "string" || customPoliciesPath.length > 0)) {
|
|
33742
|
-
const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path) =>
|
|
33743
|
-
const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path) =>
|
|
33744
|
-
if (
|
|
33806
|
+
const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path) => resolve30(path));
|
|
33807
|
+
const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path) => resolve30(path)).filter((path) => {
|
|
33808
|
+
if (existsSync44(path))
|
|
33745
33809
|
return true;
|
|
33746
33810
|
console.log(`Dropping custom policies path (file no longer exists): ${path}`);
|
|
33747
33811
|
return false;
|
|
@@ -33964,7 +34028,7 @@ async function removeHooks2(policyNames, scope = "user", cwd, opts) {
|
|
|
33964
34028
|
const scopesToRemove = scope === "all" ? [...integration.scopes] : integration.scopes.includes(scope) ? [scope] : [];
|
|
33965
34029
|
for (const s of scopesToRemove) {
|
|
33966
34030
|
const settingsPaths = settingsPathsFor(integration, s, cwd);
|
|
33967
|
-
const existing = settingsPaths.filter((p) =>
|
|
34031
|
+
const existing = settingsPaths.filter((p) => existsSync44(p));
|
|
33968
34032
|
if (existing.length === 0) {
|
|
33969
34033
|
if (scope !== "all" && selectedClis.length === 1) {
|
|
33970
34034
|
console.log("No settings file found. Nothing to remove.");
|
|
@@ -34108,9 +34172,9 @@ async function listHooks(cwd) {
|
|
|
34108
34172
|
if (explicitPaths.length > 0) {
|
|
34109
34173
|
groups.push(rule("Custom Policies", opts));
|
|
34110
34174
|
for (const path of explicitPaths) {
|
|
34111
|
-
const absPath =
|
|
34175
|
+
const absPath = resolve30(findProjectConfigDir(cwd ?? process.cwd()), path);
|
|
34112
34176
|
groups.push(note(absPath, opts));
|
|
34113
|
-
if (!
|
|
34177
|
+
if (!existsSync44(absPath)) {
|
|
34114
34178
|
groups.push(warning([`file not found: ${absPath}`], opts));
|
|
34115
34179
|
continue;
|
|
34116
34180
|
}
|
|
@@ -34130,7 +34194,7 @@ async function listHooks(cwd) {
|
|
|
34130
34194
|
}
|
|
34131
34195
|
}
|
|
34132
34196
|
const base = findProjectConfigDir(cwd ?? process.cwd());
|
|
34133
|
-
const projectDir =
|
|
34197
|
+
const projectDir = resolve30(base, ".failproofai", "policies");
|
|
34134
34198
|
const userDir = customPoliciesDir();
|
|
34135
34199
|
const sameDir = userDir === projectDir;
|
|
34136
34200
|
const conventionDirs = [
|
|
@@ -34242,11 +34306,11 @@ var init_manager2 = __esm(() => {
|
|
|
34242
34306
|
});
|
|
34243
34307
|
|
|
34244
34308
|
// src/audit/audit-schedule.ts
|
|
34245
|
-
import { readFileSync as
|
|
34309
|
+
import { readFileSync as readFileSync37 } from "node:fs";
|
|
34246
34310
|
function readAuditSchedule(home) {
|
|
34247
34311
|
let raw;
|
|
34248
34312
|
try {
|
|
34249
|
-
raw =
|
|
34313
|
+
raw = readFileSync37(auditScheduleFile(home), "utf8");
|
|
34250
34314
|
} catch {
|
|
34251
34315
|
return null;
|
|
34252
34316
|
}
|
|
@@ -34310,7 +34374,9 @@ async function ensureSignedIn(preset) {
|
|
|
34310
34374
|
}
|
|
34311
34375
|
if (!canPrompt()) {
|
|
34312
34376
|
throw new LoginError(`Signing in needs an interactive terminal, and this one is not.
|
|
34313
|
-
` + "Run `failproofai audit --schedule` from a shell you are sitting at,\n" +
|
|
34377
|
+
` + "Run `failproofai audit --schedule` from a shell you are sitting at,\n" + `or sign in from the dashboard — both write the same session file.
|
|
34378
|
+
` + `
|
|
34379
|
+
` + "`--email` does not avoid this: it fills in the address so you are not\n" + "asked for it, but a one-time code is still sent there for you to paste.");
|
|
34314
34380
|
}
|
|
34315
34381
|
return { user: await runLogin(preset), prompted: true };
|
|
34316
34382
|
}
|
|
@@ -34434,21 +34500,20 @@ async function runScheduleOn(daysArg, emailArg) {
|
|
|
34434
34500
|
if (bad)
|
|
34435
34501
|
throw new ScheduleCliError(bad);
|
|
34436
34502
|
}
|
|
34437
|
-
const { user, prompted }
|
|
34503
|
+
const signedIn = emailArg === undefined ? { user: readAuth()?.user ?? null, prompted: false } : await ensureSignedIn(emailArg);
|
|
34438
34504
|
const next = updateConfig({
|
|
34439
34505
|
audit: {
|
|
34440
34506
|
auto: true,
|
|
34441
|
-
reportsConsentedAt: Date.now(),
|
|
34442
34507
|
...days !== undefined ? { intervalDays: days } : {}
|
|
34443
34508
|
}
|
|
34444
34509
|
});
|
|
34445
34510
|
const interval = next.audit.intervalDays;
|
|
34446
34511
|
const summary = [
|
|
34447
|
-
`every ${interval} day${interval === 1 ? "" : "s"} ·
|
|
34448
|
-
|
|
34449
|
-
"
|
|
34512
|
+
`every ${interval} day${interval === 1 ? "" : "s"} · desktop notification on leaks`,
|
|
34513
|
+
signedIn.user ? `masked leak alerts also go to ${signedIn.user.email}` : "email is optional · add it with --email you@example.com",
|
|
34514
|
+
"email contains only the most recent masked credential exposure"
|
|
34450
34515
|
];
|
|
34451
|
-
if (prompted) {
|
|
34516
|
+
if (signedIn.prompted) {
|
|
34452
34517
|
step("scheduled audits are on", summary);
|
|
34453
34518
|
} else {
|
|
34454
34519
|
process.stdout.write(`
|
|
@@ -34457,7 +34522,7 @@ ${green("✓")} ${bold("scheduled audits are on")}
|
|
|
34457
34522
|
`).join(""));
|
|
34458
34523
|
}
|
|
34459
34524
|
warnIfDaemonWontRun();
|
|
34460
|
-
if (prompted) {
|
|
34525
|
+
if (signedIn.prompted) {
|
|
34461
34526
|
outro("failproofai audit --status · when the next scan is due");
|
|
34462
34527
|
} else {
|
|
34463
34528
|
process.stdout.write(dim(`
|
|
@@ -34509,12 +34574,7 @@ function runScheduleStatus() {
|
|
|
34509
34574
|
]);
|
|
34510
34575
|
detail.push(["reports to", live ? live.user.email : dim("— signed out")]);
|
|
34511
34576
|
if (on && !live) {
|
|
34512
|
-
detail.push(["", pink("scans continue;
|
|
34513
|
-
} else if (on && config.audit.reportsConsentedAt === undefined) {
|
|
34514
|
-
detail.push([
|
|
34515
|
-
"",
|
|
34516
|
-
pink("scans continue; digests need a fresh opt-in — run `--schedule` to turn them on")
|
|
34517
|
-
]);
|
|
34577
|
+
detail.push(["", pink("scans and desktop alerts continue; email alerts are paused")]);
|
|
34518
34578
|
}
|
|
34519
34579
|
detail.push(["daemon", describeDaemon(daemon)]);
|
|
34520
34580
|
if (sched?.nextDueAtMs != null && on) {
|
|
@@ -34629,14 +34689,14 @@ var init_schedule_cli = __esm(() => {
|
|
|
34629
34689
|
});
|
|
34630
34690
|
|
|
34631
34691
|
// scripts/parse-script-args.ts
|
|
34632
|
-
import { resolve as
|
|
34692
|
+
import { resolve as resolve31 } from "path";
|
|
34633
34693
|
function parseStringFlag(flagName, errorLabel, inlineValue, args, index, options) {
|
|
34634
34694
|
const raw = inlineValue ?? args[index + 1];
|
|
34635
34695
|
if (raw === undefined || inlineValue === null && raw.startsWith("-")) {
|
|
34636
34696
|
console.error(`Error: ${flagName} requires ${errorLabel}`);
|
|
34637
34697
|
process.exit(1);
|
|
34638
34698
|
}
|
|
34639
|
-
const value = options?.resolve ?
|
|
34699
|
+
const value = options?.resolve ? resolve31(raw) : raw;
|
|
34640
34700
|
return { value, spliceCount: inlineValue !== null ? 1 : 2 };
|
|
34641
34701
|
}
|
|
34642
34702
|
function parseScriptArgs(argv) {
|
|
@@ -34692,21 +34752,21 @@ function parseScriptArgs(argv) {
|
|
|
34692
34752
|
var init_parse_script_args = () => {};
|
|
34693
34753
|
|
|
34694
34754
|
// scripts/install-diagnosis.mjs
|
|
34695
|
-
import { existsSync as
|
|
34696
|
-
import { dirname as dirname22, resolve as
|
|
34755
|
+
import { existsSync as existsSync45, readFileSync as readFileSync38, realpathSync as realpathSync4 } from "node:fs";
|
|
34756
|
+
import { dirname as dirname22, resolve as resolve32 } from "node:path";
|
|
34697
34757
|
import { homedir as homedir32, platform as platform5 } from "node:os";
|
|
34698
34758
|
import { spawnSync } from "node:child_process";
|
|
34699
34759
|
function findPackageRoot(start) {
|
|
34700
34760
|
try {
|
|
34701
34761
|
let dir = realpathSync4(start);
|
|
34702
|
-
if (
|
|
34762
|
+
if (existsSync45(dir) && !existsSync45(resolve32(dir, "package.json"))) {
|
|
34703
34763
|
dir = dirname22(dir);
|
|
34704
34764
|
}
|
|
34705
34765
|
while (true) {
|
|
34706
|
-
const pkgPath =
|
|
34707
|
-
if (
|
|
34766
|
+
const pkgPath = resolve32(dir, "package.json");
|
|
34767
|
+
if (existsSync45(pkgPath)) {
|
|
34708
34768
|
try {
|
|
34709
|
-
const pkg = JSON.parse(
|
|
34769
|
+
const pkg = JSON.parse(readFileSync38(pkgPath, "utf8"));
|
|
34710
34770
|
if (pkg.name === PKG_NAME)
|
|
34711
34771
|
return dir;
|
|
34712
34772
|
} catch {}
|
|
@@ -34724,7 +34784,7 @@ function readPackageVersion(packageRoot) {
|
|
|
34724
34784
|
if (!packageRoot)
|
|
34725
34785
|
return null;
|
|
34726
34786
|
try {
|
|
34727
|
-
const pkg = JSON.parse(
|
|
34787
|
+
const pkg = JSON.parse(readFileSync38(resolve32(packageRoot, "package.json"), "utf8"));
|
|
34728
34788
|
return typeof pkg.version === "string" ? pkg.version : null;
|
|
34729
34789
|
} catch {
|
|
34730
34790
|
return null;
|
|
@@ -34750,16 +34810,16 @@ function locateNpmGlobal() {
|
|
|
34750
34810
|
const root = (res.stdout || "").trim();
|
|
34751
34811
|
if (!root)
|
|
34752
34812
|
return null;
|
|
34753
|
-
const candidate =
|
|
34754
|
-
return
|
|
34813
|
+
const candidate = resolve32(root, PKG_NAME);
|
|
34814
|
+
return existsSync45(resolve32(candidate, "package.json")) ? candidate : null;
|
|
34755
34815
|
} catch {
|
|
34756
34816
|
return null;
|
|
34757
34817
|
}
|
|
34758
34818
|
}
|
|
34759
34819
|
function locateBunGlobal() {
|
|
34760
34820
|
try {
|
|
34761
|
-
const candidate =
|
|
34762
|
-
return
|
|
34821
|
+
const candidate = resolve32(homedir32(), ".bun", "install", "global", "node_modules", PKG_NAME);
|
|
34822
|
+
return existsSync45(resolve32(candidate, "package.json")) ? candidate : null;
|
|
34763
34823
|
} catch {
|
|
34764
34824
|
return null;
|
|
34765
34825
|
}
|
|
@@ -34767,8 +34827,8 @@ function locateBunGlobal() {
|
|
|
34767
34827
|
function buildRecommendation(pathFirstBin) {
|
|
34768
34828
|
if (!pathFirstBin)
|
|
34769
34829
|
return null;
|
|
34770
|
-
const bunBinPrefix =
|
|
34771
|
-
const bunGlobalPrefix =
|
|
34830
|
+
const bunBinPrefix = resolve32(homedir32(), ".bun", "bin") + "/";
|
|
34831
|
+
const bunGlobalPrefix = resolve32(homedir32(), ".bun", "install", "global") + "/";
|
|
34772
34832
|
const isBun = pathFirstBin.startsWith(bunBinPrefix) || pathFirstBin.startsWith(bunGlobalPrefix);
|
|
34773
34833
|
if (isBun) {
|
|
34774
34834
|
return `rm -f ~/.bun/bin/${PKG_NAME} && rm -rf ~/.bun/install/global/node_modules/${PKG_NAME}`;
|
|
@@ -34862,8 +34922,8 @@ var init_dashboard_host = __esm(() => {
|
|
|
34862
34922
|
|
|
34863
34923
|
// scripts/launch.ts
|
|
34864
34924
|
import { spawn as spawn2 } from "child_process";
|
|
34865
|
-
import { realpathSync as realpathSync5, existsSync as
|
|
34866
|
-
import { resolve as
|
|
34925
|
+
import { realpathSync as realpathSync5, existsSync as existsSync46 } from "node:fs";
|
|
34926
|
+
import { resolve as resolve33, dirname as dirname23 } from "node:path";
|
|
34867
34927
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
34868
34928
|
import { createInterface } from "node:readline";
|
|
34869
34929
|
function launch(mode) {
|
|
@@ -34887,9 +34947,9 @@ function launch(mode) {
|
|
|
34887
34947
|
process.env.PORT = port;
|
|
34888
34948
|
process.env.HOSTNAME = bindHost;
|
|
34889
34949
|
cmd = "node";
|
|
34890
|
-
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ??
|
|
34891
|
-
const serverJsPath =
|
|
34892
|
-
if (!
|
|
34950
|
+
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve33(dirname23(realpathSync5(fileURLToPath2(import.meta.url))), "..");
|
|
34951
|
+
const serverJsPath = resolve33(packageRoot, ".next/standalone/server.js");
|
|
34952
|
+
if (!existsSync46(serverJsPath)) {
|
|
34893
34953
|
let shadowMessage = null;
|
|
34894
34954
|
try {
|
|
34895
34955
|
const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
|
|
@@ -34972,23 +35032,27 @@ function helpText() {
|
|
|
34972
35032
|
const lines = helpScreen({
|
|
34973
35033
|
command: "audit",
|
|
34974
35034
|
version: version2,
|
|
34975
|
-
tagline: "
|
|
35035
|
+
tagline: "find credentials your agents leaked into their own transcripts",
|
|
34976
35036
|
sections: [
|
|
34977
35037
|
{
|
|
34978
35038
|
label: "usage",
|
|
34979
35039
|
entries: [
|
|
34980
|
-
["(bare)", `Scan your session history, then open http://localhost:${DASHBOARD_PORT}/audit`],
|
|
34981
|
-
["--schedule [days]", "Scan on a timer and
|
|
34982
|
-
["--email <address>", "With --schedule,
|
|
35040
|
+
["(bare)", `Scan your session history for leaked keys, then open http://localhost:${DASHBOARD_PORT}/audit`],
|
|
35041
|
+
["--schedule [days]", "Scan on a timer and notify you on this machine. Default 7 days, range 1-90. No account required."],
|
|
35042
|
+
["--email <address>", "With --schedule, add email alerts for the most recent masked credential leak. A sign-in code is emailed to you."],
|
|
34983
35043
|
["--no-schedule", "Stop the timer. Leaves you signed in."],
|
|
34984
35044
|
["--notify", "Show a desktop notification when a scan finds a credential. On by default."],
|
|
34985
|
-
["--no-notify", "Stop
|
|
35045
|
+
["--no-notify", "Stop desktop notifications. Scheduled scans and optional email alerts are unaffected."],
|
|
34986
35046
|
["--status", "Whether scheduling is on, where reports go, the daemon's state, and when the next scan is due."],
|
|
34987
35047
|
["-h, --help", "Show this help."]
|
|
34988
35048
|
]
|
|
34989
35049
|
}
|
|
34990
35050
|
],
|
|
34991
|
-
footer: [
|
|
35051
|
+
footer: [
|
|
35052
|
+
"Every scan runs on this machine. Leak alerts appear as desktop system",
|
|
35053
|
+
"notifications, never inside agent sessions. If you add email, only the",
|
|
35054
|
+
"newest masked credential exposure and its metadata leave the machine."
|
|
35055
|
+
]
|
|
34992
35056
|
}, helpOptsFor(process.stdout));
|
|
34993
35057
|
return ["", ...lines, ""].join(`
|
|
34994
35058
|
`) + `
|
|
@@ -35137,29 +35201,26 @@ function heldByLine(held) {
|
|
|
35137
35201
|
const ageS = Math.max(0, Math.round((Date.now() - held.startedAt) / 1000));
|
|
35138
35202
|
return `another audit is already running (pid ${held.pid}, started by ${held.source} ${ageS}s ago)`;
|
|
35139
35203
|
}
|
|
35140
|
-
async function announceLeaksOnDesktop(result) {
|
|
35204
|
+
async function announceLeaksOnDesktop(result, report) {
|
|
35141
35205
|
try {
|
|
35142
|
-
await announceLeaksOrThrow(result);
|
|
35206
|
+
await announceLeaksOrThrow(result, report);
|
|
35143
35207
|
} catch (err) {
|
|
35144
35208
|
process.stderr.write(`failproofai: could not announce a leak on the desktop: ` + `${err instanceof Error ? err.message : String(err)}
|
|
35145
35209
|
`);
|
|
35146
35210
|
}
|
|
35147
35211
|
}
|
|
35148
|
-
async function announceLeaksOrThrow(result) {
|
|
35149
|
-
const ids = result.newLeakIds ?? [];
|
|
35212
|
+
async function announceLeaksOrThrow(result, report) {
|
|
35213
|
+
const ids = result.leakIds ?? result.newLeakIds ?? [];
|
|
35150
35214
|
if (ids.length === 0)
|
|
35151
35215
|
return;
|
|
35152
35216
|
if (!readConfig().audit.notify)
|
|
35153
35217
|
return;
|
|
35154
|
-
const
|
|
35155
|
-
|
|
35156
|
-
|
|
35157
|
-
const n = claimed.length === 1 ? "a credential" : `${claimed.length} credentials`;
|
|
35158
|
-
const title = "failproofai found a leaked credential";
|
|
35159
|
-
const body = `${n} in your agent transcripts. Run failproofai audit to see them — ` + "or failproofai audit --schedule to get them by email.";
|
|
35218
|
+
const n = ids.length === 1 ? "a possible credential exposure" : `${ids.length} possible credential exposures`;
|
|
35219
|
+
const emailState = report.kind === "sent" ? "sent" : report.kind === "signed-out" || !readAuth() ? "missing" : report.kind === "failed" ? "failed" : "held";
|
|
35220
|
+
const { title, body } = desktopLeakNotice(emailState);
|
|
35160
35221
|
if (process.platform === "darwin") {
|
|
35161
35222
|
pruneMacNotifyQueue();
|
|
35162
|
-
if (!queueMacNotification(
|
|
35223
|
+
if (!queueMacNotification(ids[0], title, body)) {
|
|
35163
35224
|
process.stderr.write(`failproofai: found ${n} but could not queue a notification
|
|
35164
35225
|
`);
|
|
35165
35226
|
} else if (!macNotifierInstalled()) {
|
|
@@ -35205,8 +35266,8 @@ async function runScheduledAudit() {
|
|
|
35205
35266
|
}
|
|
35206
35267
|
process.stdout.write(`failproofai: audit complete — ${num2(result.eventsScanned)} tool calls across ` + `${num2(result.transcripts.scanned)} sessions, ${num2(result.totals.hits)} hits
|
|
35207
35268
|
`);
|
|
35208
|
-
await announceLeaksOnDesktop(result);
|
|
35209
35269
|
const outcome = await reportHarm(result);
|
|
35270
|
+
await announceLeaksOnDesktop(result, outcome);
|
|
35210
35271
|
const line = describeOutcome2(outcome);
|
|
35211
35272
|
if (line) {
|
|
35212
35273
|
const stream = outcome.kind === "sent" ? process.stdout : process.stderr;
|
|
@@ -35364,8 +35425,8 @@ var init_cli2 = __esm(() => {
|
|
|
35364
35425
|
init_report_harm();
|
|
35365
35426
|
init_desktop_notify();
|
|
35366
35427
|
init_macos_notifier();
|
|
35367
|
-
init_leak_notice();
|
|
35368
35428
|
init_fp_config();
|
|
35429
|
+
init_auth_store();
|
|
35369
35430
|
init_tui();
|
|
35370
35431
|
init_package();
|
|
35371
35432
|
AUDIT_STAGES2 = [
|
|
@@ -35698,8 +35759,8 @@ var init_session_pause_cli = __esm(() => {
|
|
|
35698
35759
|
|
|
35699
35760
|
// scripts/launch.ts
|
|
35700
35761
|
import { spawn as spawn3 } from "child_process";
|
|
35701
|
-
import { realpathSync as realpathSync6, existsSync as
|
|
35702
|
-
import { resolve as
|
|
35762
|
+
import { realpathSync as realpathSync6, existsSync as existsSync47 } from "node:fs";
|
|
35763
|
+
import { resolve as resolve34, dirname as dirname24 } from "node:path";
|
|
35703
35764
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
35704
35765
|
import { createInterface as createInterface2 } from "node:readline";
|
|
35705
35766
|
function launch2(mode) {
|
|
@@ -35723,9 +35784,9 @@ function launch2(mode) {
|
|
|
35723
35784
|
process.env.PORT = port;
|
|
35724
35785
|
process.env.HOSTNAME = bindHost;
|
|
35725
35786
|
cmd = "node";
|
|
35726
|
-
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ??
|
|
35727
|
-
const serverJsPath =
|
|
35728
|
-
if (!
|
|
35787
|
+
const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve34(dirname24(realpathSync6(fileURLToPath3(import.meta.url))), "..");
|
|
35788
|
+
const serverJsPath = resolve34(packageRoot, ".next/standalone/server.js");
|
|
35789
|
+
if (!existsSync47(serverJsPath)) {
|
|
35729
35790
|
let shadowMessage = null;
|
|
35730
35791
|
try {
|
|
35731
35792
|
const diag = diagnoseShadow({ selfPackageRoot: packageRoot, selfVersion: version2 });
|
|
@@ -35822,17 +35883,17 @@ var init_cli_error2 = __esm(() => {
|
|
|
35822
35883
|
|
|
35823
35884
|
// bin/failproofai.mjs
|
|
35824
35885
|
import { realpathSync as realpathSync7 } from "fs";
|
|
35825
|
-
import { dirname as dirname25, resolve as
|
|
35886
|
+
import { dirname as dirname25, resolve as resolve35 } from "path";
|
|
35826
35887
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
35827
35888
|
// package.json
|
|
35828
|
-
var version = "1.0.4-beta.
|
|
35889
|
+
var version = "1.0.4-beta.6";
|
|
35829
35890
|
|
|
35830
35891
|
// bin/failproofai.mjs
|
|
35831
35892
|
if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
|
|
35832
|
-
process.env.FAILPROOFAI_PACKAGE_ROOT =
|
|
35893
|
+
process.env.FAILPROOFAI_PACKAGE_ROOT = resolve35(dirname25(realpathSync7(fileURLToPath4(import.meta.url))), "..");
|
|
35833
35894
|
}
|
|
35834
35895
|
if (!process.env.FAILPROOFAI_DIST_PATH) {
|
|
35835
|
-
process.env.FAILPROOFAI_DIST_PATH =
|
|
35896
|
+
process.env.FAILPROOFAI_DIST_PATH = resolve35(dirname25(realpathSync7(fileURLToPath4(import.meta.url))), "..", "dist");
|
|
35836
35897
|
}
|
|
35837
35898
|
var args = process.argv.slice(2);
|
|
35838
35899
|
if (args[0] === "p" || args[0] === "policy")
|
|
@@ -36070,7 +36131,7 @@ Run \`failproofai help\` for usage.`);
|
|
|
36070
36131
|
label: "see what it caught",
|
|
36071
36132
|
entries: [
|
|
36072
36133
|
["(no args)", "Open the policy dashboard on localhost:8020"],
|
|
36073
|
-
["audit", "
|
|
36134
|
+
["audit", "Find credentials your agents leaked, and get told about it"],
|
|
36074
36135
|
["config --status", "Cloud connection, daemon version, pause state"]
|
|
36075
36136
|
]
|
|
36076
36137
|
},
|