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
|
@@ -127,7 +127,15 @@ interface CursorRecord {
|
|
|
127
127
|
/** Cursor 2026-04+ transcript shape: `{role, message: {content: [...]}}`. */
|
|
128
128
|
role?: "user" | "assistant" | "system" | string;
|
|
129
129
|
message?: {
|
|
130
|
-
content?: Array<{
|
|
130
|
+
content?: Array<{
|
|
131
|
+
type?: string;
|
|
132
|
+
text?: string;
|
|
133
|
+
id?: string;
|
|
134
|
+
name?: string;
|
|
135
|
+
input?: Record<string, unknown>;
|
|
136
|
+
tool_use_id?: string;
|
|
137
|
+
content?: unknown;
|
|
138
|
+
}>;
|
|
131
139
|
};
|
|
132
140
|
}
|
|
133
141
|
|
|
@@ -183,11 +191,36 @@ export async function parseCursorLog(
|
|
|
183
191
|
if (!raw.type && raw.role && raw.message?.content) {
|
|
184
192
|
const synthDate = new Date(SYNTH_T0 + i);
|
|
185
193
|
const synthTs = synthDate.toISOString();
|
|
186
|
-
const
|
|
194
|
+
const messageContent = raw.message.content;
|
|
195
|
+
const textParts = messageContent
|
|
187
196
|
.filter((c) => c?.type === "text" && typeof c.text === "string")
|
|
188
197
|
.map((c) => c.text!)
|
|
189
198
|
.join("");
|
|
190
199
|
if (raw.role === "user") {
|
|
200
|
+
// Some Cursor builds emit Claude-style tool_result blocks in the next
|
|
201
|
+
// user record. Pair them before treating any remaining text as a user
|
|
202
|
+
// turn so command output is available to the credential scanner.
|
|
203
|
+
let attachedResult = false;
|
|
204
|
+
for (const block of messageContent) {
|
|
205
|
+
if (block?.type !== "tool_result") continue;
|
|
206
|
+
const callId = typeof block.tool_use_id === "string" ? block.tool_use_id : undefined;
|
|
207
|
+
const toolUse = callId ? toolUseById.get(callId) : undefined;
|
|
208
|
+
if (!toolUse) continue;
|
|
209
|
+
const durationMs = Math.max(
|
|
210
|
+
0,
|
|
211
|
+
synthDate.getTime() - (toolUseStartMs.get(callId!) ?? synthDate.getTime()),
|
|
212
|
+
);
|
|
213
|
+
toolUse.result = {
|
|
214
|
+
timestamp: synthTs,
|
|
215
|
+
timestampFormatted: formatTimestamp(synthDate),
|
|
216
|
+
content: typeof block.content === "string"
|
|
217
|
+
? block.content
|
|
218
|
+
: block.content == null ? "" : JSON.stringify(block.content),
|
|
219
|
+
durationMs,
|
|
220
|
+
durationFormatted: formatDuration(durationMs),
|
|
221
|
+
};
|
|
222
|
+
attachedResult = true;
|
|
223
|
+
}
|
|
191
224
|
// Strip the synthesized `<timestamp>...</timestamp>\n<user_query>...\n</user_query>`
|
|
192
225
|
// wrapper Cursor adds for context — keep just the user_query body.
|
|
193
226
|
const queryMatch = /<user_query>\s*([\s\S]*?)\s*<\/user_query>/.exec(textParts);
|
|
@@ -198,13 +231,37 @@ export async function parseCursorLog(
|
|
|
198
231
|
...baseEntry(rawCopy, synthTs, synthDate, source),
|
|
199
232
|
message: { role: "user", content: text },
|
|
200
233
|
} satisfies UserEntry);
|
|
234
|
+
} else if (!attachedResult) {
|
|
235
|
+
entries.push({
|
|
236
|
+
type: "system",
|
|
237
|
+
...baseEntry(rawCopy, synthTs, synthDate, source),
|
|
238
|
+
raw: rawCopy,
|
|
239
|
+
} satisfies GenericEntry);
|
|
201
240
|
}
|
|
202
241
|
continue;
|
|
203
242
|
}
|
|
204
243
|
if (raw.role === "assistant") {
|
|
205
|
-
const blocks: ContentBlock[] =
|
|
206
|
-
|
|
207
|
-
|
|
244
|
+
const blocks: ContentBlock[] = [];
|
|
245
|
+
if (textParts) blocks.push({ type: "text", text: textParts });
|
|
246
|
+
for (let j = 0; j < messageContent.length; j++) {
|
|
247
|
+
const contentBlock = messageContent[j];
|
|
248
|
+
if (contentBlock?.type !== "tool_use") continue;
|
|
249
|
+
const name = typeof contentBlock.name === "string" ? contentBlock.name : "tool";
|
|
250
|
+
const id = typeof contentBlock.id === "string" && contentBlock.id
|
|
251
|
+
? contentBlock.id
|
|
252
|
+
: `cursor-${i}-${name}-${j}`;
|
|
253
|
+
const toolUse: ToolUseBlock = {
|
|
254
|
+
type: "tool_use",
|
|
255
|
+
id,
|
|
256
|
+
name,
|
|
257
|
+
input: contentBlock.input && typeof contentBlock.input === "object"
|
|
258
|
+
? contentBlock.input
|
|
259
|
+
: {},
|
|
260
|
+
};
|
|
261
|
+
blocks.push(toolUse);
|
|
262
|
+
toolUseById.set(id, toolUse);
|
|
263
|
+
toolUseStartMs.set(id, synthDate.getTime());
|
|
264
|
+
}
|
|
208
265
|
if (blocks.length === 0) {
|
|
209
266
|
entries.push({
|
|
210
267
|
type: "system",
|
|
@@ -39,8 +39,42 @@ interface NodeSqliteModule {
|
|
|
39
39
|
DatabaseSync: new (path: string, options?: { readOnly?: boolean }) => NodeSqliteDb;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Swallow Node's "SQLite is an experimental feature" warning, once.
|
|
44
|
+
*
|
|
45
|
+
* It is not information the user can act on — we chose `node:sqlite`
|
|
46
|
+
* deliberately, and the alternative tier is a WASM build that leaks. But it is
|
|
47
|
+
* emitted on first use, which lands it in the MIDDLE of whatever is on screen,
|
|
48
|
+
* and the audit's progress display redraws itself by moving the cursor up a
|
|
49
|
+
* fixed number of lines. Two unexpected lines of stderr push the cursor down
|
|
50
|
+
* two rows, so the next redraw repaints the block two rows lower and strands
|
|
51
|
+
* the top of the previous frame above it. The user sees every stage twice and
|
|
52
|
+
* reasonably concludes the audit ran twice.
|
|
53
|
+
*
|
|
54
|
+
* Filtered by message rather than silenced wholesale: `process.emitWarning` is
|
|
55
|
+
* how deprecations and real problems surface too, and a blanket
|
|
56
|
+
* `NODE_NO_WARNINGS` in a tool that installs into other people's machines would
|
|
57
|
+
* hide those as well.
|
|
58
|
+
*/
|
|
59
|
+
let warningPatched = false;
|
|
60
|
+
function silenceSqliteExperimentalWarning(): void {
|
|
61
|
+
if (warningPatched) return;
|
|
62
|
+
warningPatched = true;
|
|
63
|
+
const original = process.emitWarning.bind(process);
|
|
64
|
+
// The overloads differ across Node versions; the shape we care about is the
|
|
65
|
+
// first argument, and everything else is passed straight through.
|
|
66
|
+
process.emitWarning = ((warning: unknown, ...rest: unknown[]) => {
|
|
67
|
+
const text = typeof warning === "string" ? warning : String((warning as Error)?.message ?? "");
|
|
68
|
+
if (text.includes("SQLite is an experimental feature")) return;
|
|
69
|
+
return (original as (...a: unknown[]) => void)(warning, ...rest);
|
|
70
|
+
}) as typeof process.emitWarning;
|
|
71
|
+
}
|
|
72
|
+
|
|
42
73
|
async function tryNodeSqlite(dbPath: string): Promise<SqliteReader | null> {
|
|
43
74
|
try {
|
|
75
|
+
// Before the import, not after: the warning fires on first use of the
|
|
76
|
+
// module, which is this line.
|
|
77
|
+
silenceSqliteExperimentalWarning();
|
|
44
78
|
// Dynamic import: on Node < 22.5 this rejects and we fall through to sql.js.
|
|
45
79
|
const mod = (await import("node:sqlite")) as unknown as NodeSqliteModule;
|
|
46
80
|
const db = new mod.DatabaseSync(dbPath, { readOnly: true });
|
|
@@ -66,10 +100,53 @@ function loadSqlJs(): Promise<SqlJsStatic> {
|
|
|
66
100
|
return sqlPromise;
|
|
67
101
|
}
|
|
68
102
|
|
|
103
|
+
const SQLITE_MAGIC = "SQLite format 3\0";
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Clear the WAL flag on OUR OWN in-memory copy of the database image.
|
|
107
|
+
*
|
|
108
|
+
* Header bytes 18 and 19 are the file-format write and read versions; `2`
|
|
109
|
+
* means WAL. sql.js never sees the `-wal` sidecar — it is handed the main
|
|
110
|
+
* file's bytes and nothing else, which is exactly the snapshot caveat this
|
|
111
|
+
* module already documents — so the flag buys us nothing, and it costs a great
|
|
112
|
+
* deal: opening a WAL-flagged image makes SQLite build a wal-index
|
|
113
|
+
* shared-memory region that sql.js's MEMFS-backed VFS never reclaims on
|
|
114
|
+
* `close()` (close unlinks only the db file it created).
|
|
115
|
+
*
|
|
116
|
+
* The asm.js build's heap is a FIXED 22,151,168-byte ArrayBuffer with
|
|
117
|
+
* ALLOW_MEMORY_GROWTH off, so `emscripten_resize_heap` is compiled to
|
|
118
|
+
* `abort("OOM")`. Measured: the 128th WAL-mode open exhausts it — the same
|
|
119
|
+
* threshold for a 319 KB database and a 10 MB one, because the leaked region
|
|
120
|
+
* is a fixed per-connection allocation rather than data.
|
|
121
|
+
*
|
|
122
|
+
* And the abort is not confined to that open. `initSqlJs` memoizes one
|
|
123
|
+
* process-wide module, so once it aborts every later `openSqliteReadonly`
|
|
124
|
+
* silently returns null. A full audit opens ~150 databases — devin, goose and
|
|
125
|
+
* opencode each open theirs once per SESSION — so it crossed 128 and then
|
|
126
|
+
* dropped whatever it had not yet read, with no error anywhere. The
|
|
127
|
+
* `Aborted(OOM)` lines on stderr were the only symptom, and they read as
|
|
128
|
+
* harmless because the run still completed.
|
|
129
|
+
*
|
|
130
|
+
* Only under bun and Node < 22.5: tier 1 is `node:sqlite`, which bun does not
|
|
131
|
+
* provide, and `engines.node` allows 20.9. Both fall through to here.
|
|
132
|
+
*/
|
|
133
|
+
function clearWalFlag(bytes: Buffer): Buffer {
|
|
134
|
+
// Too short to carry a header, or not a SQLite image at all — hand it back
|
|
135
|
+
// untouched and let sql.js produce its own error.
|
|
136
|
+
if (bytes.length < 20) return bytes;
|
|
137
|
+
if (bytes.toString("latin1", 0, 16) !== SQLITE_MAGIC) return bytes;
|
|
138
|
+
if (bytes[18] === 1 && bytes[19] === 1) return bytes; // already rollback-journal
|
|
139
|
+
bytes[18] = 1;
|
|
140
|
+
bytes[19] = 1;
|
|
141
|
+
return bytes;
|
|
142
|
+
}
|
|
143
|
+
|
|
69
144
|
async function trySqlJs(dbPath: string): Promise<SqliteReader | null> {
|
|
70
145
|
try {
|
|
71
146
|
const SQL = await loadSqlJs();
|
|
72
|
-
|
|
147
|
+
// `readFileSync` already returns a private copy, so mutating the two header
|
|
148
|
+
// bytes cannot touch the file on disk.
|
|
149
|
+
const db = new SQL.Database(clearWalFlag(readFileSync(dbPath)));
|
|
73
150
|
return {
|
|
74
151
|
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): T[] {
|
|
75
152
|
const stmt = db.prepare(sql);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "failproofai",
|
|
3
|
-
"version": "1.0.4-beta.
|
|
3
|
+
"version": "1.0.4-beta.6",
|
|
4
4
|
"description": "Observability and enforcement for AI agent harnesses. 39 built-in policies hooked into 12 of them — Claude Code, Codex, Cursor, Hermes, OpenClaw and more — blocking the tool call before it runs. Local dashboard included, no account needed.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"failproofai": "./dist/cli.mjs",
|
|
@@ -117,19 +117,19 @@
|
|
|
117
117
|
"vite": "8.0.16",
|
|
118
118
|
"undici": "7.29.0",
|
|
119
119
|
"brace-expansion": "5.0.9",
|
|
120
|
-
"sharp": "0.35.
|
|
120
|
+
"sharp": "0.35.4",
|
|
121
121
|
"browserslist": "4.28.8"
|
|
122
122
|
},
|
|
123
123
|
"optionalDependencies": {
|
|
124
|
-
"@failproofai/failproofaid-linux-x64": "1.0.4-beta.
|
|
125
|
-
"@failproofai/failproofaid-linux-arm64": "1.0.4-beta.
|
|
126
|
-
"@failproofai/failproofaid-darwin-x64": "1.0.4-beta.
|
|
127
|
-
"@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.
|
|
124
|
+
"@failproofai/failproofaid-linux-x64": "1.0.4-beta.6",
|
|
125
|
+
"@failproofai/failproofaid-linux-arm64": "1.0.4-beta.6",
|
|
126
|
+
"@failproofai/failproofaid-darwin-x64": "1.0.4-beta.6",
|
|
127
|
+
"@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.6"
|
|
128
128
|
},
|
|
129
129
|
"failproofaidBinaries": {
|
|
130
|
-
"linux-x64": "
|
|
131
|
-
"linux-arm64": "
|
|
132
|
-
"darwin-x64": "
|
|
133
|
-
"darwin-arm64": "
|
|
130
|
+
"linux-x64": "24118b8bd058cc5d8711053c4c77cdca9361c12dbf0f421a757d33f07596d428",
|
|
131
|
+
"linux-arm64": "b4278c34a288de2c747bcebcc623d8fd5bda3a1f1e55800926eb1a4b89f0a5e9",
|
|
132
|
+
"darwin-x64": "ecb66699f45f605b0d54ac9e4bac360ac11e4e136442dcccdd083514d77c7d42",
|
|
133
|
+
"darwin-arm64": "b3dbad58bda960ef9481f90bc5085ba8624b2472519cc0bf212a0e8451dd2db4"
|
|
134
134
|
}
|
|
135
135
|
}
|
|
@@ -9,7 +9,7 @@ const currentPort = parseInt(process.env.PORT, 10) || 3000
|
|
|
9
9
|
const hostname = process.env.HOSTNAME || '0.0.0.0'
|
|
10
10
|
|
|
11
11
|
let keepAliveTimeout = parseInt(process.env.KEEP_ALIVE_TIMEOUT, 10)
|
|
12
|
-
const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"1.0.4-beta.
|
|
12
|
+
const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"1.0.4-beta.6"},"typescript":{"ignoreBuildErrors":false},"typedRoutes":false,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.ts","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"instrumentationClientInject":[],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"maximumResponseBody":50000000,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":true,"customCacheHandler":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":null,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{"serverFunctions":true,"browserToTerminal":"warn"},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/failproofai/failproofai","enablePrerenderSourceMaps":true,"cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"appNewScrollHandler":true,"coldCacheBadge":false,"devValidationWorker":true,"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"cachedNavigations":false,"dynamicOnHover":false,"useOffline":false,"varyParams":true,"optimisticRouting":true,"instrumentationClientRouterTransitionEvents":false,"prefetchInlining":{"maxSize":2048,"maxBundleSize":10240},"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":3,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptOperationCache":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"devMemoryThresholdRestart":true,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"requestInsights":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"strictRouteTypes":false,"useTypeScriptCli":true,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":true,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":true,"serverComponentsHmrCache":true,"serverComponentsHmrCancellation":false,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"gestureTransition":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":"warn","lockDistDir":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":true,"turbopackInferModuleSideEffects":true,"turbopackPluginRuntimeStrategy":"childProcesses","turbopackMemoryEvictionMode":"auto","optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"useCacheTimeout":54,"instantInsights":{"validationLevel":"warning"},"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.ts","outputFileTracingExcludes":{"*":["node_modules/@img/**","node_modules/sharp/**"]},"turbopack":{"root":"/home/runner/work/failproofai/failproofai"},"repoRoot":"/home/runner/work/failproofai/failproofai","distDirRoot":".next"}
|
|
13
13
|
|
|
14
14
|
process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)
|
|
15
15
|
|
package/bin/failproofai.mjs
CHANGED
|
@@ -481,7 +481,7 @@ async function runCli() {
|
|
|
481
481
|
label: "see what it caught",
|
|
482
482
|
entries: [
|
|
483
483
|
["(no args)", "Open the policy dashboard on localhost:8020"],
|
|
484
|
-
["audit", "
|
|
484
|
+
["audit", "Find credentials your agents leaked, and get told about it"],
|
|
485
485
|
["config --status", "Cloud connection, daemon version, pause state"],
|
|
486
486
|
],
|
|
487
487
|
},
|