failproofai 1.0.4-beta.6 → 1.0.4-beta.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  10. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  11. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  12. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  16. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  17. package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
  18. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  19. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +13 -13
  20. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  21. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  22. package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -4
  23. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
  30. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +5 -5
  32. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  34. package/.next/standalone/.next/server/app/index.html +1 -1
  35. package/.next/standalone/.next/server/app/index.rsc +14 -14
  36. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
  37. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
  38. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  39. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  40. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  42. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  43. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  45. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  46. package/.next/standalone/.next/server/app/project/[name]/page.js +2 -2
  47. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  49. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  50. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  51. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +2 -2
  52. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  53. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  54. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  55. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  56. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  57. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +15 -4
  58. package/.next/standalone/.next/server/app/settings/page.js +2 -2
  59. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  60. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  61. package/.next/standalone/.next/server/chunks/{[externals]__0v1hz15._.js → [externals]__0hmcwgg._.js} +1 -1
  62. package/.next/standalone/.next/server/chunks/{[externals]__1nb206a._.js → [externals]__14b7cc6._.js} +1 -1
  63. package/.next/standalone/.next/server/chunks/[root-of-the-server]__08dchfu._.js +1 -1
  64. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0faqz9x._.js +22 -0
  65. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  66. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zyc_nm._.js +3 -0
  67. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p-qi2t._.js → [root-of-the-server]__112b4go._.js} +22 -3
  68. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1l71g3y._.js +22 -0
  69. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  70. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  71. package/.next/standalone/.next/server/chunks/{_0otft92._.js → _1_eakl4._.js} +2 -2
  72. package/.next/standalone/.next/server/chunks/_1ek68ln._.js +10 -10
  73. package/.next/standalone/.next/server/chunks/lib_openclaw-projects_ts_0gc-p24._.js +3 -0
  74. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  75. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-4ja6q._.js +2 -2
  76. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00cr3xu._.js +2 -2
  77. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1sc84bb._.js → [root-of-the-server]__00y9ww2._.js} +21 -2
  78. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04px77e._.js +2 -2
  79. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0egr5s1._.js +2 -2
  80. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0i0l1di._.js +2 -2
  81. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n2txhk._.js +1 -1
  82. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
  83. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0r3c1_0._.js +2 -2
  84. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17xnxlx._.js +2 -2
  85. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1fvfw59._.js → [root-of-the-server]__187jks6._.js} +1 -1
  86. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ckpmkk._.js +2 -2
  87. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1ui5ur8._.js → [root-of-the-server]__1fa1jd9._.js} +2 -2
  88. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1kaotix._.js +22 -0
  89. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0dxf928._.js → [root-of-the-server]__1kpd1za._.js} +1 -1
  90. package/.next/standalone/.next/server/chunks/ssr/{_02b3i98._.js → _00bqkhj._.js} +2 -2
  91. package/.next/standalone/.next/server/chunks/ssr/_04ng_6x._.js +1 -1
  92. package/.next/standalone/.next/server/chunks/ssr/_07t3jol._.js +1 -1
  93. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  94. package/.next/standalone/.next/server/chunks/ssr/{_1if9ixi._.js → _14c6q09._.js} +21 -2
  95. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
  96. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  97. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  98. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  99. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
  100. package/.next/standalone/.next/server/chunks/ssr/lib_openclaw-projects_ts_0qxq3bp._.js +1 -1
  101. package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
  102. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  103. package/.next/standalone/.next/server/pages/404.html +1 -1
  104. package/.next/standalone/.next/server/pages/500.html +1 -1
  105. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  106. package/.next/standalone/.next/server/server-reference-manifest.json +33 -22
  107. package/.next/standalone/.next/static/chunks/0igq884ziuv-8.js +1 -0
  108. package/.next/standalone/.next/static/chunks/{20xkiqzvfkuvm.js → 0vm4wdx3w-2_w.js} +1 -1
  109. package/.next/standalone/.next/static/chunks/{1gn08w2pgqh09.js → 1302duobnz07l.js} +1 -1
  110. package/.next/standalone/.next/static/chunks/{07c6l1lq5_69b.js → 1_x7pqemw5n_w.js} +1 -1
  111. package/.next/standalone/.next/static/chunks/{32m2ryfankf_2.js → 1chm9piluggc-.js} +1 -1
  112. package/.next/standalone/.next/static/chunks/{12bsgz8czvcnn.js → 2mizt96igig1y.js} +1 -1
  113. package/.next/standalone/.next/static/chunks/{2a84ug32tzik2.js → 2n85g-crgcx5j.js} +1 -1
  114. package/.next/standalone/.next/static/chunks/{3jxd133cw2vm3.js → 2ukucf6g-kbs5.js} +1 -1
  115. package/.next/standalone/.next/static/chunks/349jkb79v5g6z.js +1 -0
  116. package/.next/standalone/.next/static/chunks/{1xgq22tri86an.js → 3a4gth64hwtwf.js} +1 -1
  117. package/.next/standalone/app/actions/get-scheduled-audit.ts +5 -0
  118. package/.next/standalone/app/actions/update-scheduled-audit.ts +14 -1
  119. package/.next/standalone/app/audit/_components/audit-dashboard.tsx +1 -1
  120. package/.next/standalone/app/audit/_components/empty-state.tsx +1 -1
  121. package/.next/standalone/app/audit/_components/leak-section.tsx +1 -1
  122. package/.next/standalone/app/settings/settings-client.tsx +42 -11
  123. package/.next/standalone/lib/download-session.ts +58 -13
  124. package/.next/standalone/lib/openclaw-db.ts +271 -0
  125. package/.next/standalone/lib/openclaw-projects.ts +54 -18
  126. package/.next/standalone/lib/openclaw-sessions.ts +75 -17
  127. package/.next/standalone/package.json +9 -9
  128. package/.next/standalone/server.js +1 -1
  129. package/dist/cli.mjs +511 -315
  130. package/dist/worker.mjs +287 -92
  131. package/lib/download-session.ts +58 -13
  132. package/lib/openclaw-db.ts +271 -0
  133. package/lib/openclaw-projects.ts +54 -18
  134. package/lib/openclaw-sessions.ts +75 -17
  135. package/package.json +9 -9
  136. package/src/audit/index.ts +1 -1
  137. package/src/audit/leak-record.ts +24 -12
  138. package/src/audit/macos-notifier.ts +54 -66
  139. package/src/hooks/builtin-policies.ts +2 -2
  140. package/src/hooks/configure-wizard.ts +8 -1
  141. package/src/hooks/uninstall-cli.ts +3 -3
  142. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-219ec._.js +0 -3
  143. package/.next/standalone/.next/server/chunks/[root-of-the-server]__04_h-a5._.js +0 -3
  144. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1le9jqc._.js +0 -3
  145. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1nq7ivq._.js +0 -3
  146. package/.next/standalone/.next/static/chunks/3ioub_lpen-sq.js +0 -1
  147. package/.next/standalone/.next/static/chunks/44ncu88eq6z71.js +0 -1
  148. /package/.next/standalone/.next/static/{aeM365dNTtUZOZvNkX8ba → DNhaAH8iPGH0tIuxee5_2}/_buildManifest.js +0 -0
  149. /package/.next/standalone/.next/static/{aeM365dNTtUZOZvNkX8ba → DNhaAH8iPGH0tIuxee5_2}/_clientMiddlewareManifest.js +0 -0
  150. /package/.next/standalone/.next/static/{aeM365dNTtUZOZvNkX8ba → DNhaAH8iPGH0tIuxee5_2}/_ssgManifest.js +0 -0
@@ -1,11 +1,9 @@
1
1
  /**
2
2
  * OpenClaw (openclaw gateway) session transcript loader + parser.
3
3
  *
4
- * AUDIT-ONLY (Pillar 2). OpenClaw writes one JSONL transcript per session at
5
- * `~/.openclaw/agents/<agentId>/sessions/<sessionId>.jsonl` (sessionId is a
6
- * UUID), alongside a much larger `<sessionId>.trajectory.jsonl` OTel trace we
7
- * IGNORE, and a `sessions.json` index keyed by sessionKey. Verified live
8
- * against openclaw v2026.7.1.
4
+ * Legacy OpenClaw writes one JSONL transcript per session under `sessions/`;
5
+ * 2026.9.2+ stores the same logical records as `event_json` rows in each
6
+ * agent's `agent/openclaw-agent.sqlite`. SQLite is preferred when both exist.
9
7
  *
10
8
  * The transcript is type-discriminated JSONL:
11
9
  * {type:"session", cwd, …} — header (carries cwd)
@@ -18,8 +16,8 @@
18
16
  * `toolResult` by `toolCallId` (mirrors lib/hermes-sessions.ts) and is PURE, so
19
17
  * it is unit-testable with plain line objects.
20
18
  *
21
- * Home override: set `OPENCLAW_HOME` (used by tests / to point at a copied
22
- * gateway config dir).
19
+ * Home override: `OPENCLAW_STATE_DIR`, then `OPENCLAW_HOME` (used by tests /
20
+ * to point at a copied gateway config dir).
23
21
  */
24
22
  import { readFile } from "node:fs/promises";
25
23
  import { readdirSync, statSync } from "node:fs";
@@ -39,13 +37,18 @@ import {
39
37
  type LogSource,
40
38
  } from "./log-entries";
41
39
  import { formatDuration } from "./format-duration";
40
+ import { readOpenClawSqliteTranscript } from "./openclaw-db";
42
41
 
43
42
  /** OpenClaw sessions are stored under UUID filenames. */
44
43
  export const OPENCLAW_SESSION_ID_RE = /^[0-9a-fA-F-]{36}$/;
45
44
 
46
- /** Absolute path to OpenClaw's config home (override with OPENCLAW_HOME). */
45
+ /** Absolute path to OpenClaw's state home. */
47
46
  export function openclawHome(): string {
48
- return process.env.OPENCLAW_HOME || join(homedir(), ".openclaw");
47
+ return (
48
+ process.env.OPENCLAW_STATE_DIR ||
49
+ process.env.OPENCLAW_HOME ||
50
+ join(homedir(), ".openclaw")
51
+ );
49
52
  }
50
53
 
51
54
  // ── Parsing helpers ──
@@ -60,7 +63,11 @@ function extractText(content: unknown): string {
60
63
  if (typeof content === "string") return content;
61
64
  if (Array.isArray(content)) {
62
65
  return content
63
- .map((c) => (isPlainObject(c) && typeof c.text === "string" ? (c.text as string) : ""))
66
+ .map((c) =>
67
+ isPlainObject(c) && typeof c.text === "string"
68
+ ? (c.text as string)
69
+ : "",
70
+ )
64
71
  .filter(Boolean)
65
72
  .join("\n");
66
73
  }
@@ -134,7 +141,10 @@ export function openclawLinesToLogEntries(
134
141
  if (b.type === "text" && typeof b.text === "string") {
135
142
  blocks.push({ type: "text", text: b.text });
136
143
  } else if (b.type === "toolCall") {
137
- const id = typeof b.id === "string" ? b.id : `${String(b.name ?? "tool")}-${blocks.length}`;
144
+ const id =
145
+ typeof b.id === "string"
146
+ ? b.id
147
+ : `${String(b.name ?? "tool")}-${blocks.length}`;
138
148
  const name = typeof b.name === "string" ? b.name : "tool";
139
149
  const input = isPlainObject(b.arguments) ? b.arguments : {};
140
150
  const block: ToolUseBlock = { type: "tool_use", id, name, input };
@@ -151,17 +161,23 @@ export function openclawLinesToLogEntries(
151
161
  entries.push({
152
162
  type: "assistant",
153
163
  ...base,
154
- message: { role: "assistant", content: blocks, model: typeof m.model === "string" ? m.model : undefined },
164
+ message: {
165
+ role: "assistant",
166
+ content: blocks,
167
+ model: typeof m.model === "string" ? m.model : undefined,
168
+ },
155
169
  } satisfies AssistantEntry);
156
170
  continue;
157
171
  }
158
172
 
159
173
  if (role === "toolResult") {
160
- const callId = typeof m.toolCallId === "string" ? m.toolCallId : undefined;
174
+ const callId =
175
+ typeof m.toolCallId === "string" ? m.toolCallId : undefined;
161
176
  const block = callId ? toolUseById.get(callId) : undefined;
162
177
  if (block) {
163
178
  const details = isPlainObject(m.details) ? m.details : undefined;
164
- const startMs = (callId && toolUseStartMs.get(callId)) || date.getTime();
179
+ const startMs =
180
+ (callId && toolUseStartMs.get(callId)) || date.getTime();
165
181
  const durationMs =
166
182
  details && typeof details.durationMs === "number"
167
183
  ? details.durationMs
@@ -238,13 +254,20 @@ export function listOpenClawTranscripts(): OpenClawTranscriptFile[] {
238
254
  }
239
255
  for (const file of files) {
240
256
  // Only `<uuid>.jsonl` — not `<uuid>.trajectory.jsonl` / `.trajectory-path.json`.
241
- if (!file.endsWith(".jsonl") || file.endsWith(".trajectory.jsonl")) continue;
257
+ if (!file.endsWith(".jsonl") || file.endsWith(".trajectory.jsonl"))
258
+ continue;
242
259
  const sessionId = file.slice(0, -".jsonl".length);
243
260
  if (!OPENCLAW_SESSION_ID_RE.test(sessionId)) continue;
244
261
  const transcriptPath = join(sessionsDir, file);
245
262
  try {
246
263
  const st = statSync(transcriptPath);
247
- out.push({ agentId, sessionId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
264
+ out.push({
265
+ agentId,
266
+ sessionId,
267
+ transcriptPath,
268
+ mtimeMs: st.mtimeMs,
269
+ sizeBytes: st.size,
270
+ });
248
271
  } catch {
249
272
  // skip unreadable
250
273
  }
@@ -276,6 +299,36 @@ export interface OpenClawSessionLogData {
276
299
  export async function getOpenClawSessionLog(
277
300
  sessionId: string,
278
301
  ): Promise<OpenClawSessionLogData | null> {
302
+ if (!OPENCLAW_SESSION_ID_RE.test(sessionId)) return null;
303
+
304
+ // New OpenClaw versions keep live transcripts in SQLite. Prefer that copy
305
+ // when an archived JSONL with the same UUID also exists.
306
+ const sqlite = await readOpenClawSqliteTranscript(
307
+ openclawHome(),
308
+ listOpenClawAgents(),
309
+ sessionId,
310
+ );
311
+ if (sqlite) {
312
+ const entries = openclawLinesToLogEntries(sqlite.rawLines, "session");
313
+ let cwd: string | undefined;
314
+ for (const line of sqlite.rawLines) {
315
+ if (
316
+ line.type === "session" &&
317
+ typeof line.cwd === "string" &&
318
+ line.cwd.length > 0
319
+ ) {
320
+ cwd = line.cwd;
321
+ break;
322
+ }
323
+ }
324
+ return {
325
+ entries,
326
+ rawLines: sqlite.rawLines,
327
+ cwd,
328
+ filePath: sqlite.filePath,
329
+ };
330
+ }
331
+
279
332
  const filePath = findOpenClawTranscript(sessionId);
280
333
  if (!filePath) return null;
281
334
  let content: string;
@@ -289,7 +342,12 @@ export async function getOpenClawSessionLog(
289
342
  // cwd lives on the `type:"session"` header line.
290
343
  let cwd: string | undefined;
291
344
  for (const line of rawLines) {
292
- if (isPlainObject(line) && line.type === "session" && typeof line.cwd === "string" && line.cwd.length > 0) {
345
+ if (
346
+ isPlainObject(line) &&
347
+ line.type === "session" &&
348
+ typeof line.cwd === "string" &&
349
+ line.cwd.length > 0
350
+ ) {
293
351
  cwd = line.cwd;
294
352
  break;
295
353
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "failproofai",
3
- "version": "1.0.4-beta.6",
3
+ "version": "1.0.4-beta.8",
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",
@@ -121,15 +121,15 @@
121
121
  "browserslist": "4.28.8"
122
122
  },
123
123
  "optionalDependencies": {
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"
124
+ "@failproofai/failproofaid-linux-x64": "1.0.4-beta.8",
125
+ "@failproofai/failproofaid-linux-arm64": "1.0.4-beta.8",
126
+ "@failproofai/failproofaid-darwin-x64": "1.0.4-beta.8",
127
+ "@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.8"
128
128
  },
129
129
  "failproofaidBinaries": {
130
- "linux-x64": "24118b8bd058cc5d8711053c4c77cdca9361c12dbf0f421a757d33f07596d428",
131
- "linux-arm64": "b4278c34a288de2c747bcebcc623d8fd5bda3a1f1e55800926eb1a4b89f0a5e9",
132
- "darwin-x64": "ecb66699f45f605b0d54ac9e4bac360ac11e4e136442dcccdd083514d77c7d42",
133
- "darwin-arm64": "b3dbad58bda960ef9481f90bc5085ba8624b2472519cc0bf212a0e8451dd2db4"
130
+ "linux-x64": "17274c1da30675b49de74953a4ce2777e09ba07b9da79250ab155e5fdb316a0a",
131
+ "linux-arm64": "a07b228d899914baca1c75024be19c0319eb4fc40c6d5a303ba733bf6721924a",
132
+ "darwin-x64": "d170fd5604cb419bc83f4a5ab1a6cb5be2f9aec957aed99ce237990aa5d3966f",
133
+ "darwin-arm64": "0e2bde5bd0762641fa072a6640e485c637b2102f2fb6c1afeca679f005e89679"
134
134
  }
135
135
  }
@@ -70,7 +70,7 @@ const TRANSCRIPT_BYTE_BUDGET = 48 * 1024 * 1024;
70
70
  * otherwise the largest transcript on the machine could never be scanned, which
71
71
  * is precisely the one most likely to hold something.
72
72
  */
73
- class ByteGate {
73
+ export class ByteGate {
74
74
  private inFlight = 0;
75
75
  private waiting: Array<() => void> = [];
76
76
 
@@ -152,23 +152,30 @@ export function upsertFinding(
152
152
  return { record, isNew: true };
153
153
  }
154
154
 
155
- existing.occurrences += 1;
156
- if (sighting.at > existing.lastSeen) existing.lastSeen = sighting.at;
157
- if (sighting.at < existing.firstSeen) existing.firstSeen = sighting.at;
158
-
159
155
  // Keep the earliest sighting AND the most recent evidence. The report/email
160
156
  // promises the CLI and timestamp of the latest exposure; keeping only the
161
157
  // first five made those fields stale forever after a busy credential crossed
162
158
  // the cap. Middle sightings are the expendable ones.
163
159
  const seen = existing.sightings.some(
164
- (s) => s.sessionId === sighting.sessionId && s.at === sighting.at,
160
+ (s) =>
161
+ s.sessionId === sighting.sessionId &&
162
+ s.at === sighting.at &&
163
+ s.mechanism.direction === sighting.mechanism.direction &&
164
+ s.mechanism.summary === sighting.mechanism.summary,
165
165
  );
166
- if (!seen) {
167
- existing.sightings.push(sighting);
168
- existing.sightings.sort((a, b) => a.at.localeCompare(b.at));
169
- if (existing.sightings.length > MAX_SIGHTINGS) {
170
- existing.sightings.splice(1, existing.sightings.length - MAX_SIGHTINGS);
171
- }
166
+ // Cached transcript results are folded through this function again. An
167
+ // identical sighting is therefore not a new exposure and must not inflate
168
+ // the count each time the same cache entry is reused.
169
+ if (seen) return { record, isNew: false };
170
+
171
+ existing.occurrences += 1;
172
+ if (sighting.at > existing.lastSeen) existing.lastSeen = sighting.at;
173
+ if (sighting.at < existing.firstSeen) existing.firstSeen = sighting.at;
174
+
175
+ existing.sightings.push(sighting);
176
+ existing.sightings.sort((a, b) => a.at.localeCompare(b.at));
177
+ if (existing.sightings.length > MAX_SIGHTINGS) {
178
+ existing.sightings.splice(1, existing.sightings.length - MAX_SIGHTINGS);
172
179
  }
173
180
  return { record, isNew: false };
174
181
  }
@@ -181,7 +188,12 @@ export function upsertFinding(
181
188
  */
182
189
  export function pruneRecord(record: LeakRecord, nowMs: number): LeakRecord {
183
190
  const cutoff = new Date(nowMs - FINDING_TTL_DAYS * 86_400_000).toISOString();
184
- const live = record.findings.filter((f) => f.lastSeen >= cutoff);
191
+ // A missing or malformed timestamp cannot be aged out safely. Keep it until
192
+ // the bounded-cap pass below rather than silently deleting a finding that the
193
+ // reporting path deliberately surfaces as having an unknown date.
194
+ const live = record.findings.filter(
195
+ (f) => !f.lastSeen || !Number.isFinite(Date.parse(f.lastSeen)) || f.lastSeen >= cutoff,
196
+ );
185
197
  live.sort((a, b) => (a.lastSeen < b.lastSeen ? 1 : a.lastSeen > b.lastSeen ? -1 : 0));
186
198
  record.findings = live.slice(0, MAX_FINDINGS);
187
199
  return record;
@@ -24,13 +24,13 @@
24
24
  * would install for every account on the box, which is not what a per-user
25
25
  * notification is.
26
26
  *
27
- * **An app bundle, not a bare `osascript -e 'display notification'`.** A raw
28
- * osascript notification is attributed to whatever host ran it — in practice
29
- * "Script Editor" — so it inherits Script Editor's notification permission,
30
- * appears under Script Editor in System Settings, and is indistinguishable from
31
- * any other script on the machine. Compiling a tiny applet with `osacompile`
32
- * gives it its own bundle identifier, so the banner says failproofai, and the
33
- * user gets a real entry they can allow, silence or deny like any other app.
27
+ * **A user-session `osascript`, not an applet binary launched directly.** The
28
+ * compiled applet path looked attractive because it could carry a FailproofAI
29
+ * bundle identifier, but launching `Contents/MacOS/applet` directly from
30
+ * launchd is not a dependable Notification Center client on current macOS.
31
+ * `osascript` from a user LaunchAgent is the same mechanism ordinary scheduled
32
+ * jobs use successfully. Delivery matters more than owning the label shown by
33
+ * Notification Center, so the runner uses that proven path.
34
34
  *
35
35
  * **A watched drop directory, not a resident process.** The agent is not a
36
36
  * daemon: `WatchPaths` makes launchd start it only when a file appears, and it
@@ -45,25 +45,29 @@
45
45
  * the thing that lasts.
46
46
  */
47
47
  import { execFileSync } from "node:child_process";
48
- import { existsSync, mkdirSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
48
+ import { chmodSync, existsSync, mkdirSync, readdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
49
49
  import { homedir } from "node:os";
50
50
  import { resolve } from "node:path";
51
51
 
52
52
  import { runDir } from "../hooks/fp-home";
53
53
  import { isFindingId } from "./leak-fingerprint";
54
54
 
55
- /** The bundle identifier the banner is attributed to, and the agent's label. */
55
+ /** Stable label used to load, inspect, and remove the per-user LaunchAgent. */
56
56
  export const MAC_NOTIFIER_LABEL = "ai.failproof.notifier";
57
57
 
58
58
  /** Where a queued notification waits for the agent to pick it up. */
59
59
  export const macNotifyDir = (home?: string) => resolve(runDir(home), "notify");
60
60
 
61
- /** The compiled applet. Under `~/.failproofai` rather than `/Applications`,
62
- * because it is a delivery mechanism, not something to launch. */
61
+ /** Legacy compiled applet path, retained so upgrades and uninstall remove it. */
63
62
  export function macNotifierAppPath(home?: string): string {
64
63
  return resolve(runDir(home), "..", "bin", "FailproofAI Notifier.app");
65
64
  }
66
65
 
66
+ /** User-session runner invoked by launchd when a notification is queued. */
67
+ export function macNotifierRunnerPath(home?: string): string {
68
+ return resolve(runDir(home), "..", "bin", "failproofai-notifier.zsh");
69
+ }
70
+
67
71
  export function macNotifierPlistPath(): string {
68
72
  return resolve(homedir(), "Library", "LaunchAgents", `${MAC_NOTIFIER_LABEL}.plist`);
69
73
  }
@@ -73,11 +77,11 @@ function escapeXml(s: string): string {
73
77
  }
74
78
 
75
79
  /**
76
- * The AppleScript the applet runs: drain the directory, say each line, exit.
80
+ * The user-session runner: drain the directory, say each notification, exit.
77
81
  *
78
- * Payload format is two lines — title, then body — chosen over JSON because
79
- * AppleScript has no JSON parser and shelling out to one would put a second
80
- * interpreter in the path of a two-field message.
82
+ * Payload format is two lines — title, then body. Values are passed to
83
+ * AppleScript as argv, never interpolated into source, so notification text
84
+ * cannot become AppleScript code.
81
85
  *
82
86
  * The file is REMOVED BEFORE the notification is posted, and that order is
83
87
  * deliberate: `WatchPaths` fires on every change to the directory, so a file
@@ -88,32 +92,25 @@ function escapeXml(s: string): string {
88
92
  */
89
93
  export function notifierScript(home?: string): string {
90
94
  const dir = macNotifyDir(home);
91
- return `on run
92
- set dropDir to ${JSON.stringify(dir + "/")}
93
- set listing to ""
94
- try
95
- set listing to do shell script "ls -1 " & quoted form of dropDir & " 2>/dev/null"
96
- end try
97
- repeat with entryName in paragraphs of listing
98
- set entryPath to dropDir & (entryName as string)
99
- if (entryName as string) is not "" then
100
- try
101
- set payload to do shell script "cat " & quoted form of entryPath & " 2>/dev/null"
102
- do shell script "rm -f " & quoted form of entryPath
103
- set lines_ to paragraphs of payload
104
- if (count of lines_) is greater than 1 then
105
- set noteTitle to item 1 of lines_
106
- set noteBody to ""
107
- repeat with i from 2 to (count of lines_)
108
- if noteBody is not "" then set noteBody to noteBody & " "
109
- set noteBody to noteBody & (item i of lines_)
110
- end repeat
111
- display notification noteBody with title noteTitle
112
- end if
113
- end try
114
- end if
115
- end repeat
95
+ const quotedDir = `'${dir.replace(/'/g, `'\\''`)}'`;
96
+ return `#!/bin/zsh
97
+ set -u
98
+ setopt NULL_GLOB
99
+
100
+ drop_dir=${quotedDir}
101
+
102
+ for entry_path in "$drop_dir"/*; do
103
+ [ -f "$entry_path" ] || continue
104
+ note_title=$(/usr/bin/sed -n '1p' "$entry_path")
105
+ note_body=$(/usr/bin/sed -n '2,$p' "$entry_path" | /usr/bin/tr '\\n' ' ')
106
+ /bin/rm -f "$entry_path"
107
+ [ -n "$note_title" ] || continue
108
+ /usr/bin/osascript - "$note_title" "$note_body" <<'APPLESCRIPT'
109
+ on run argv
110
+ display notification (item 2 of argv) with title (item 1 of argv)
116
111
  end run
112
+ APPLESCRIPT
113
+ done
117
114
  `;
118
115
  }
119
116
 
@@ -122,7 +119,7 @@ end run
122
119
  * assert this file's shape from a Linux CI runner, which is every CI runner we
123
120
  * have.
124
121
  */
125
- export function notifierPlistContents(appPath: string, watchDir: string): string {
122
+ export function notifierPlistContents(runnerPath: string, watchDir: string): string {
126
123
  return `<?xml version="1.0" encoding="UTF-8"?>
127
124
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
128
125
  <plist version="1.0">
@@ -131,7 +128,7 @@ export function notifierPlistContents(appPath: string, watchDir: string): string
131
128
  <string>${escapeXml(MAC_NOTIFIER_LABEL)}</string>
132
129
  <key>ProgramArguments</key>
133
130
  <array>
134
- <string>${escapeXml(resolve(appPath, "Contents", "MacOS", "applet"))}</string>
131
+ <string>${escapeXml(runnerPath)}</string>
135
132
  </array>
136
133
  <!-- Started only when something is queued, and it exits when the queue is
137
134
  empty. RunAtLoad would fire it once at login with nothing to say. -->
@@ -173,36 +170,26 @@ function run(cmd: string, args: string[]): void {
173
170
  * machine scan, and may it interrupt), and both of those are real settings.
174
171
  *
175
172
  * Returns rather than throws. Notifications are one channel of several, and a
176
- * Mac that cannot compile an applet must still finish setting up its daemon,
177
- * its hooks and its policies — the parts that actually enforce anything.
173
+ * Mac that cannot load the user LaunchAgent must still finish setting up its
174
+ * daemon, hooks and policies — the parts that actually enforce anything.
178
175
  */
179
176
  export function installMacNotifier(home?: string): MacNotifierResult {
180
177
  if (process.platform !== "darwin") return { installed: false, reason: "not macOS" };
181
178
  try {
182
- const app = macNotifierAppPath(home);
179
+ const runner = macNotifierRunnerPath(home);
183
180
  const watch = macNotifyDir(home);
184
181
  mkdirSync(watch, { recursive: true, mode: 0o700 });
185
- mkdirSync(resolve(app, ".."), { recursive: true });
186
-
187
- const scriptPath = resolve(watch, "..", "notifier.applescript");
188
- writeFileSync(scriptPath, notifierScript(home), { mode: 0o600 });
189
- // osacompile refuses to overwrite an existing bundle, so a reinstall (a
190
- // second `failproofai config`, or an upgrade) has to clear it first.
191
- rmSync(app, { recursive: true, force: true });
192
- run("osacompile", ["-o", app, scriptPath]);
193
- rmSync(scriptPath, { force: true });
194
-
195
- // Give the bundle its own identity, so the banner is attributed to
196
- // failproofai instead of to whatever compiled it, and so the user gets one
197
- // entry in System Settings > Notifications they can turn off themselves.
198
- const plist = resolve(app, "Contents", "Info.plist");
199
- run("defaults", ["write", plist, "CFBundleIdentifier", MAC_NOTIFIER_LABEL]);
200
- run("defaults", ["write", plist, "CFBundleName", "failproofai"]);
201
- // `defaults write` leaves the file 0600 and owned by us but in binary
202
- // format; launchd and LaunchServices both read either, so no conversion.
182
+ mkdirSync(resolve(runner, ".."), { recursive: true });
183
+ writeFileSync(runner, notifierScript(home), { mode: 0o700 });
184
+ // writeFileSync preserves an existing file's mode. Repair it explicitly on
185
+ // upgrades from a partially-created or hand-edited runner.
186
+ chmodSync(runner, 0o700);
187
+ // Remove the applet used by older builds. The LaunchAgent below no longer
188
+ // references it, and leaving it behind makes diagnosis ambiguous.
189
+ rmSync(macNotifierAppPath(home), { recursive: true, force: true });
203
190
 
204
191
  mkdirSync(resolve(macNotifierPlistPath(), ".."), { recursive: true });
205
- writeFileSync(macNotifierPlistPath(), notifierPlistContents(app, watch), { mode: 0o644 });
192
+ writeFileSync(macNotifierPlistPath(), notifierPlistContents(runner, watch), { mode: 0o644 });
206
193
 
207
194
  const target = `gui/${process.getuid?.() ?? 0}`;
208
195
  // bootout first: bootstrap fails outright on an already-loaded label, and
@@ -220,7 +207,7 @@ export function installMacNotifier(home?: string): MacNotifierResult {
220
207
  }
221
208
 
222
209
  /**
223
- * Remove the agent and the bundle.
210
+ * Remove the agent and its runner, including the applet used by older builds.
224
211
  *
225
212
  * Called from `failproofai uninstall --purge`. Unconditional and quiet: an
226
213
  * agent left behind after an uninstall is a plist launchd keeps trying to start
@@ -236,6 +223,7 @@ export function uninstallMacNotifier(home?: string): void {
236
223
  }
237
224
  rmSync(macNotifierPlistPath(), { force: true });
238
225
  rmSync(macNotifierAppPath(home), { recursive: true, force: true });
226
+ rmSync(macNotifierRunnerPath(home), { force: true });
239
227
  rmSync(macNotifyDir(home), { recursive: true, force: true });
240
228
  }
241
229
 
@@ -281,7 +269,7 @@ export function queueMacNotification(
281
269
 
282
270
  /** True when an agent is installed and could pick a queued file up. */
283
271
  export function macNotifierInstalled(home?: string): boolean {
284
- return existsSync(macNotifierPlistPath()) && existsSync(macNotifierAppPath(home));
272
+ return existsSync(macNotifierPlistPath()) && existsSync(macNotifierRunnerPath(home));
285
273
  }
286
274
 
287
275
  /**
@@ -138,10 +138,10 @@ const API_KEY_PATTERNS: Array<[RegExp, string]> = [
138
138
  // this rule's run would bridge the hyphen in `sk-proj-` and report every
139
139
  // project key a second time under the wrong label.
140
140
  [/sk-proj-[A-Za-z0-9\-_]{20,}/, "OpenAI project API key"],
141
- [/sk-svcacct-[A-Za-z0-9\-_]{20,}/, "OpenAI service-account key"],
141
+ [/(?<!\w)sk-svcacct-[A-Za-z0-9\-_]{20,}/, "OpenAI service-account key"],
142
142
  // Highest blast radius in the family: it authenticates the organisation
143
143
  // admin surface, and lives at a DIFFERENT console from the other keys.
144
- [/sk-admin-[A-Za-z0-9\-_]{20,}/, "OpenAI admin key"],
144
+ [/(?<!\w)sk-admin-[A-Za-z0-9\-_]{20,}/, "OpenAI admin key"],
145
145
 
146
146
  // ── OpenAI-compatible gateways ──
147
147
  [/sk-or-v1-[A-Za-z0-9\-_]{20,}/, "OpenRouter API key"],
@@ -1489,7 +1489,14 @@ export async function runConfigureWizard(
1489
1489
  // missing or launchd refuses the job must still finish installing its
1490
1490
  // daemon, its hooks and its policies, which are the parts that enforce
1491
1491
  // anything; the notice in-CLI still reaches them either way.
1492
- installMacNotifier();
1492
+ const notifier = installMacNotifier();
1493
+ if (process.platform === "darwin" && !notifier.installed) {
1494
+ hookLogWarn(`macOS notification helper was not installed: ${notifier.reason ?? "unknown error"}`);
1495
+ stdout.write(
1496
+ "\nSystem notifications could not be installed. Scheduled scans and email alerts\n" +
1497
+ "still work; re-run `failproofai config` after checking the local LaunchAgent.\n\n",
1498
+ );
1499
+ }
1493
1500
  }
1494
1501
 
1495
1502
  // Telemetry runs concurrently with the install (never rejects, 5s-bounded) so
@@ -193,6 +193,7 @@ export async function runUninstallCommand(opts: UninstallOptions = {}): Promise<
193
193
  if (found.daemonConfigured) {
194
194
  plan.push(` • stop requiring the daemon (policies go back to evaluating in-process)`);
195
195
  }
196
+ let removeDaemon = opts.purge === true;
196
197
  if (found.serviceInstalled) {
197
198
  plan.push(
198
199
  opts.purge || opts.yes
@@ -305,8 +306,7 @@ export async function runUninstallCommand(opts: UninstallOptions = {}): Promise<
305
306
  //
306
307
  // So the only case that keeps it is an INTERACTIVE run where the person said no
307
308
  // (or could not be asked).
308
- const removeDaemon =
309
- opts.purge || opts.yes ? true : ((await opts.confirmDaemon?.()) ?? false);
309
+ removeDaemon = opts.purge || opts.yes ? true : ((await opts.confirmDaemon?.()) ?? false);
310
310
 
311
311
  if (!removeDaemon) {
312
312
  lines.push(
@@ -357,7 +357,7 @@ export async function runUninstallCommand(opts: UninstallOptions = {}): Promise<
357
357
  // No-ops on every other platform, and needs no elevation on macOS: a per-user
358
358
  // agent is the user's own to load and unload. Tied to the daemon's removal
359
359
  // because it exists only to deliver what the daemon's scheduled audit finds.
360
- if (opts.purge || (found.serviceInstalled && (opts.purge || opts.yes))) {
360
+ if (opts.purge || removeDaemon) {
361
361
  uninstallMacNotifier();
362
362
  }
363
363
 
@@ -1,3 +0,0 @@
1
- module.exports=[2157,(t,e,n)=>{e.exports=t.x("node:fs",()=>require("node:fs"))},60526,(t,e,n)=>{e.exports=t.x("node:os",()=>require("node:os"))},54214,67405,t=>{"use strict";var e=t.i(24868),n=t.i(14747),i=t.i(81580),s=t.i(56936);async function r(t,i,s,r){let a=`agent-${r}.jsonl`;for(let r of[(0,n.join)(t,i,a),(0,n.join)(t,i,s,a),(0,n.join)(t,i,s,"subagents",a)])if(!(0,n.relative)(t,r).startsWith(".."))try{return await (0,e.access)(r),r}catch(t){if("ENOENT"===t.code)continue;break}return null}var a=t.i(83534),o=t.i(71809),u=t.i(28557);function l(t){if(t<1e3)return`${t}ms`;let e=Math.round(t/100);if(e<600)return`${(e/10).toFixed(1)}s`;let n=Math.round(t/1e3);if(n<3600){let t=Math.floor(n/60);return`${t}m ${n%60}s`}let i=Math.round(t/6e4),s=Math.floor(i/60);return`${s}h ${i%60}m`}function m(t){let e=(0,u.formatDate)(t),n=t.getMilliseconds().toString().padStart(3,"0");return`${e}.${n}`}function p(t,e,n,i){return{_source:i,uuid:t.uuid||"",parentUuid:t.parentUuid??null,timestamp:e,timestampMs:n.getTime(),timestampFormatted:m(n)}}async function f(t,e){let n=t.split("\n").filter(t=>""!==t.trim()),i=new Map,s=[],r=[],a=new Set,o=!1;for(let t=0;t<n.length;t++){let u;t>0&&t%200==0&&await new Promise(t=>setImmediate(t));let l=n[t];try{u=JSON.parse(l)}catch{continue}let m={...u,_source:e};r.push(m);let f=u.type,c=u.timestamp;if(!c)continue;let d=new Date(c),y=d.getTime();if("user"===f){let t=u.message;if(Array.isArray(t?.content)){let e=t.content;if(e.some(t=>"tool_result"===t.type)){let t=u.toolUseResult,n="string"==typeof t?.agentId?t.agentId:void 0;for(let t of(n&&/^[a-f0-9]+$/.test(n)&&a.add(n),e)){if("tool_result"!==t.type)continue;let e=t.tool_use_id;if(!e)continue;let{text:s,images:r}=function(t){let e=t.content;if("string"==typeof e)return{text:e};if(Array.isArray(e)){let t=e.filter(t=>"text"===t.type).map(t=>t.text),n=e.filter(t=>"image"===t.type).map(t=>{let e=t.source;return{base64:e.data,mediaType:e.media_type}}).filter(t=>t.base64&&t.mediaType);return{text:t.length>0?t.join("\n"):void 0,images:n.length>0?n:void 0}}return{}}(t);i.set(e,{timestamp:c,timestampMs:y,content:s,images:r,agentId:n})}continue}}let n="string"==typeof t?.content?t.content:"";s.push({type:"user",...p(u,c,d,e),message:{role:"user",content:n}});continue}if("assistant"===f){let t=u.message,n=[];if(Array.isArray(t?.content)&&(n=t.content.filter(t=>["text","tool_use","thinking"].includes(t.type)).map(t=>{if("text"===t.type)return{type:"text",text:t.text};if("tool_use"===t.type){let e=t.input;return{type:"tool_use",id:t.id,name:t.name,input:t.input??{},..."Task"===t.name&&e?{subagentType:e.subagent_type,subagentDescription:e.description}:{}}}return{type:"thinking",thinking:t.thinking,signature:t.signature}})),0===n.length)continue;s.push({type:"assistant",...p(u,c,d,e),message:{role:"assistant",content:n,model:t?.model}});continue}if("file-history-snapshot"===f||"progress"===f||"system"===f){s.push({type:f,...p(u,c,d,e),raw:{...u}});continue}if("queue-operation"===f){let t=o?"Session Resumed":"Session Started";o=!0,s.push({type:"queue-operation",...p(u,c,d,e),label:t});continue}}let u=0;for(let t of s)if("assistant"===t.type)for(let e of(++u%200==0&&await new Promise(t=>setImmediate(t)),t.message.content)){if("tool_use"!==e.type)continue;let n=i.get(e.id);if(!n)continue;let s=new Date(n.timestamp),r=Math.max(0,n.timestampMs-t.timestampMs);e.result={timestamp:n.timestamp,timestampFormatted:m(s),content:n.content,images:n.images,durationMs:r,durationFormatted:l(r)},n.agentId&&(e.subagentId=n.agentId)}return s.length>500&&await new Promise(t=>setImmediate(t)),s.sort((t,e)=>t.timestampMs-e.timestampMs),{entries:s,rawLines:r,subagentIds:Array.from(a)}}async function c(t,e="session"){return(await f(t,e)).entries}async function d(t,a){let u=(0,s.resolveProjectPath)(t),l=(0,i.getClaudeProjectsPath)(),m=(0,n.join)(u,`${a}.jsonl`),p=await (0,e.readFile)(m,"utf-8"),{entries:c,rawLines:d,subagentIds:y}=await f(p,"session");if(0===y.length)return{entries:c,rawLines:d,subagentIds:[]};let g=await (0,o.batchAll)(y.map(n=>async()=>{let i=`agent-${n}`,s=await r(l,t,a,n);if(!s)return null;let o=await (0,e.readFile)(s,"utf-8"),{entries:u,rawLines:m}=await f(o,i);return{entries:u,rawLines:m}}),4),h=[...c],w=[...d];for(let t of g)"fulfilled"===t.status&&t.value&&(h.push(...t.value.entries),w.push(...t.value.rawLines));return h.length>500&&await new Promise(t=>setImmediate(t)),h.sort((t,e)=>t.timestampMs-e.timestampMs),{entries:h,rawLines:w,subagentIds:y}}t.s(["formatDuration",0,l],67405),(0,a.runtimeCache)((t,e)=>d(t,e),60,{maxSize:50}),t.s(["baseEntry",0,p,"formatTimestamp",0,m,"parseLogContent",0,c,"parseRawLines",0,function(t,e){return t.split("\n").filter(t=>""!==t.trim()).flatMap(t=>{try{let n=JSON.parse(t);return void 0!==e&&(n._source=e),[n]}catch{return[]}})}],54214)},64199,t=>{"use strict";var e=t.i(12714),n=t.i(2157),i=t.i(60526),s=t.i(50227),r=t.i(83534),a=t.i(54214),o=t.i(67405);let u=/^[0-9a-fA-F-]{36}$/;function l(){return process.env.OPENCLAW_HOME||(0,s.join)((0,i.homedir)(),".openclaw")}function m(t){return!!t&&"object"==typeof t&&!Array.isArray(t)}function p(t){return"string"==typeof t?t:Array.isArray(t)?t.map(t=>m(t)&&"string"==typeof t.text?t.text:"").filter(Boolean).join("\n"):""}function f(){let t,e=(0,s.join)(l(),"agents"),i=[];try{t=(0,n.readdirSync)(e,{withFileTypes:!0}).filter(t=>t.isDirectory()).map(t=>t.name)}catch{return i}for(let r of t){let t,a=(0,s.join)(e,r,"sessions");try{t=(0,n.readdirSync)(a)}catch{continue}for(let e of t){if(!e.endsWith(".jsonl")||e.endsWith(".trajectory.jsonl"))continue;let t=e.slice(0,-6);if(!u.test(t))continue;let o=(0,s.join)(a,e);try{let e=(0,n.statSync)(o);i.push({agentId:r,sessionId:t,transcriptPath:o,mtimeMs:e.mtimeMs,sizeBytes:e.size})}catch{}}}return i}function c(t){if(!u.test(t))return null;for(let e of f())if(e.sessionId===t)return e.transcriptPath;return null}async function d(t){let n,i,s=c(t);if(!s)return null;try{n=await (0,e.readFile)(s,"utf-8")}catch{return null}let r=(0,a.parseRawLines)(n,"session"),u=function(t,e="session"){let n=[],i=new Map,s=new Map,r=Date.now();for(let u=0;u<t.length;u++){let l=t[u];if(!m(l)||"message"!==l.type)continue;let f=m(l.message)?l.message:void 0;if(!f)continue;let c="string"==typeof f.role?f.role:"system",d=function(t,e){if("number"==typeof t&&Number.isFinite(t)){if(t>1e12)return new Date(t);if(t>1e9)return new Date(1e3*t)}if("string"==typeof t){let e=Date.parse(t);if(!Number.isNaN(e))return new Date(e)}return new Date(e)}(l.timestamp??f.timestamp,r+u),y=d.toISOString(),g={uuid:null!=l.id?String(l.id):`openclaw-${u}`,parentUuid:null!=l.parentId?String(l.parentId):null},h=(0,a.baseEntry)(g,y,d,e);if("user"===c){n.push({type:"user",...h,message:{role:"user",content:p(f.content)}});continue}if("assistant"===c){let t=[],e=f.content;if(Array.isArray(e)){for(let n of e)if(m(n)){if("text"===n.type&&"string"==typeof n.text)t.push({type:"text",text:n.text});else if("toolCall"===n.type){let e="string"==typeof n.id?n.id:`${String(n.name??"tool")}-${t.length}`,r={type:"tool_use",id:e,name:"string"==typeof n.name?n.name:"tool",input:m(n.arguments)?n.arguments:{}};t.push(r),i.set(e,r),s.set(e,d.getTime())}}}else{let n=p(e);n&&t.push({type:"text",text:n})}if(0===t.length)continue;n.push({type:"assistant",...h,message:{role:"assistant",content:t,model:"string"==typeof f.model?f.model:void 0}});continue}if("toolResult"===c){let t="string"==typeof f.toolCallId?f.toolCallId:void 0,e=t?i.get(t):void 0;if(e){let n=m(f.details)?f.details:void 0,i=t&&s.get(t)||d.getTime(),r=n&&"number"==typeof n.durationMs?n.durationMs:Math.max(0,d.getTime()-i);e.result={timestamp:y,timestampFormatted:(0,a.formatTimestamp)(d),content:p(f.content),durationMs:r,durationFormatted:(0,o.formatDuration)(r)};continue}}n.push({type:"system",...h,raw:g})}return n.sort((t,e)=>t.timestampMs-e.timestampMs),n}(r,"session");for(let t of r)if(m(t)&&"session"===t.type&&"string"==typeof t.cwd&&t.cwd.length>0){i=t.cwd;break}return{entries:u,rawLines:r,cwd:i,filePath:s}}(0,r.runtimeCache)(t=>d(t),2,{maxSize:50}),t.s(["findOpenClawTranscript",0,c,"getOpenClawSessionLog",0,d,"listOpenClawAgents",0,function(){try{return(0,n.readdirSync)((0,s.join)(l(),"agents"),{withFileTypes:!0}).filter(t=>t.isDirectory()&&!t.name.startsWith(".")).map(t=>t.name).sort()}catch{return[]}},"listOpenClawTranscripts",0,f,"openclawHome",0,l])}];
2
-
3
- //# sourceMappingURL=%5Broot-of-the-server%5D__0-219ec._.js.map
@@ -1,3 +0,0 @@
1
- module.exports=[2157,(e,t,n)=>{t.exports=e.x("node:fs",()=>require("node:fs"))},60526,(e,t,n)=>{t.exports=e.x("node:os",()=>require("node:os"))},54214,67405,e=>{"use strict";var t=e.i(24868),n=e.i(14747),i=e.i(81580),s=e.i(56936);async function a(e,i,s,a){let r=`agent-${a}.jsonl`;for(let a of[(0,n.join)(e,i,r),(0,n.join)(e,i,s,r),(0,n.join)(e,i,s,"subagents",r)])if(!(0,n.relative)(e,a).startsWith(".."))try{return await (0,t.access)(a),a}catch(e){if("ENOENT"===e.code)continue;break}return null}var r=e.i(83534),o=e.i(71809),l=e.i(28557);function u(e){if(e<1e3)return`${e}ms`;let t=Math.round(e/100);if(t<600)return`${(t/10).toFixed(1)}s`;let n=Math.round(e/1e3);if(n<3600){let e=Math.floor(n/60);return`${e}m ${n%60}s`}let i=Math.round(e/6e4),s=Math.floor(i/60);return`${s}h ${i%60}m`}function c(e){let t=(0,l.formatDate)(e),n=e.getMilliseconds().toString().padStart(3,"0");return`${t}.${n}`}function p(e,t,n,i){return{_source:i,uuid:e.uuid||"",parentUuid:e.parentUuid??null,timestamp:t,timestampMs:n.getTime(),timestampFormatted:c(n)}}async function f(e,t){let n=e.split("\n").filter(e=>""!==e.trim()),i=new Map,s=[],a=[],r=new Set,o=!1;for(let e=0;e<n.length;e++){let l;e>0&&e%200==0&&await new Promise(e=>setImmediate(e));let u=n[e];try{l=JSON.parse(u)}catch{continue}let c={...l,_source:t};a.push(c);let f=l.type,m=l.timestamp;if(!m)continue;let d=new Date(m),g=d.getTime();if("user"===f){let e=l.message;if(Array.isArray(e?.content)){let t=e.content;if(t.some(e=>"tool_result"===e.type)){let e=l.toolUseResult,n="string"==typeof e?.agentId?e.agentId:void 0;for(let e of(n&&/^[a-f0-9]+$/.test(n)&&r.add(n),t)){if("tool_result"!==e.type)continue;let t=e.tool_use_id;if(!t)continue;let{text:s,images:a}=function(e){let t=e.content;if("string"==typeof t)return{text:t};if(Array.isArray(t)){let e=t.filter(e=>"text"===e.type).map(e=>e.text),n=t.filter(e=>"image"===e.type).map(e=>{let t=e.source;return{base64:t.data,mediaType:t.media_type}}).filter(e=>e.base64&&e.mediaType);return{text:e.length>0?e.join("\n"):void 0,images:n.length>0?n:void 0}}return{}}(e);i.set(t,{timestamp:m,timestampMs:g,content:s,images:a,agentId:n})}continue}}let n="string"==typeof e?.content?e.content:"";s.push({type:"user",...p(l,m,d,t),message:{role:"user",content:n}});continue}if("assistant"===f){let e=l.message,n=[];if(Array.isArray(e?.content)&&(n=e.content.filter(e=>["text","tool_use","thinking"].includes(e.type)).map(e=>{if("text"===e.type)return{type:"text",text:e.text};if("tool_use"===e.type){let t=e.input;return{type:"tool_use",id:e.id,name:e.name,input:e.input??{},..."Task"===e.name&&t?{subagentType:t.subagent_type,subagentDescription:t.description}:{}}}return{type:"thinking",thinking:e.thinking,signature:e.signature}})),0===n.length)continue;s.push({type:"assistant",...p(l,m,d,t),message:{role:"assistant",content:n,model:e?.model}});continue}if("file-history-snapshot"===f||"progress"===f||"system"===f){s.push({type:f,...p(l,m,d,t),raw:{...l}});continue}if("queue-operation"===f){let e=o?"Session Resumed":"Session Started";o=!0,s.push({type:"queue-operation",...p(l,m,d,t),label:e});continue}}let l=0;for(let e of s)if("assistant"===e.type)for(let t of(++l%200==0&&await new Promise(e=>setImmediate(e)),e.message.content)){if("tool_use"!==t.type)continue;let n=i.get(t.id);if(!n)continue;let s=new Date(n.timestamp),a=Math.max(0,n.timestampMs-e.timestampMs);t.result={timestamp:n.timestamp,timestampFormatted:c(s),content:n.content,images:n.images,durationMs:a,durationFormatted:u(a)},n.agentId&&(t.subagentId=n.agentId)}return s.length>500&&await new Promise(e=>setImmediate(e)),s.sort((e,t)=>e.timestampMs-t.timestampMs),{entries:s,rawLines:a,subagentIds:Array.from(r)}}async function m(e,t="session"){return(await f(e,t)).entries}async function d(e,r){let l=(0,s.resolveProjectPath)(e),u=(0,i.getClaudeProjectsPath)(),c=(0,n.join)(l,`${r}.jsonl`),p=await (0,t.readFile)(c,"utf-8"),{entries:m,rawLines:d,subagentIds:g}=await f(p,"session");if(0===g.length)return{entries:m,rawLines:d,subagentIds:[]};let y=await (0,o.batchAll)(g.map(n=>async()=>{let i=`agent-${n}`,s=await a(u,e,r,n);if(!s)return null;let o=await (0,t.readFile)(s,"utf-8"),{entries:l,rawLines:c}=await f(o,i);return{entries:l,rawLines:c}}),4),h=[...m],w=[...d];for(let e of y)"fulfilled"===e.status&&e.value&&(h.push(...e.value.entries),w.push(...e.value.rawLines));return h.length>500&&await new Promise(e=>setImmediate(e)),h.sort((e,t)=>e.timestampMs-t.timestampMs),{entries:h,rawLines:w,subagentIds:g}}e.s(["formatDuration",0,u],67405),(0,r.runtimeCache)((e,t)=>d(e,t),60,{maxSize:50}),e.s(["baseEntry",0,p,"formatTimestamp",0,c,"parseLogContent",0,m,"parseRawLines",0,function(e,t){return e.split("\n").filter(e=>""!==e.trim()).flatMap(e=>{try{let n=JSON.parse(e);return void 0!==t&&(n._source=t),[n]}catch{return[]}})}],54214)},90624,e=>{"use strict";var t=e.i(2157),n=e.i(50227),i=e.i(83534),s=e.i(64199),a=e.i(28557);function r(e){return"string"==typeof e&&e.length>0?e:void 0}async function o(){let e=(0,s.listOpenClawTranscripts)(),i=new Map,a=[];for(let o of e){let e=i.get(o.agentId);e||(e=function(e){let i,a=new Map,o=(0,n.join)((0,s.openclawHome)(),"agents",e,"sessions","sessions.json");try{i=JSON.parse((0,t.readFileSync)(o,"utf-8"))}catch{return a}if(!i||"object"!=typeof i)return a;for(let e of Object.values(i)){if(!e||"object"!=typeof e)continue;let t=r(e.sessionId);if(!t)continue;let n=e.origin&&"object"==typeof e.origin?e.origin:{},i="number"==typeof e.lastInteractionAt?e.lastInteractionAt:"number"==typeof e.updatedAt?e.updatedAt:void 0;a.set(t,{lastMs:i,channel:r(e.lastChannel)??r(n.provider)??r(n.surface),chatType:r(e.chatType)??r(n.chatType),label:r(n.label),chatId:r(e.lastTo)??r(n.from)})}return a}(o.agentId),i.set(o.agentId,e));let l=e.get(o.sessionId);a.push({sessionId:o.sessionId,agentId:o.agentId,channel:l?.channel??"local",label:l?.label,chatType:l?.chatType,chatId:l?.chatId,transcriptPath:o.transcriptPath,mtimeMs:l?.lastMs??o.mtimeMs,sizeBytes:o.sizeBytes})}return a.sort((e,t)=>t.mtimeMs-e.mtimeMs),a}let l=(0,i.runtimeCache)(o,2);function u(e,t){return`openclaw-${e}-${t}`}function c(e,t){return`openclaw:${e}:${t}`}function p(e){if(!e.startsWith("openclaw-"))return[];let t=e.slice(9);if(!t)return[];let n=[];for(let e of(0,s.listOpenClawAgents)().sort((e,t)=>t.length-e.length)){let i=`${e}-`;t.startsWith(i)&&t.length>i.length&&n.push({agentId:e,channel:t.slice(i.length)})}return n.push({agentId:null,channel:t}),n}async function f(){let e=await o(),t=new Map;for(let n of e){let e=JSON.stringify([n.agentId,n.channel]),i=t.get(e);i?(i.latest=Math.max(i.latest,n.mtimeMs),i.count+=1):t.set(e,{agentId:n.agentId,channel:n.channel,latest:n.mtimeMs,count:1})}let n=[];for(let{agentId:e,channel:i,latest:s,count:r}of t.values()){let t=new Date(s);n.push({name:u(e,i),path:c(e,i),isDirectory:!0,lastModified:t,lastModifiedFormatted:(0,a.formatDate)(t),cli:["openclaw"],sessionCount:r})}return n.sort((e,t)=>t.lastModified.getTime()-e.lastModified.getTime()),n}async function m(e){let t=p(e);if(0===t.length)return{cwd:null,sessions:[]};let n=await o(),i=e=>n.filter(t=>t.channel===e.channel&&(null===e.agentId||t.agentId===e.agentId)),s=t[0],r=i(s);if(0===r.length)for(let e of t.slice(1)){let t=i(e);if(t.length>0){s=e,r=t;break}}let{agentId:l,channel:u}=s;return{cwd:null===l?`openclaw:${u}`:c(l,u),sessions:r.map(e=>{let t=new Date(e.mtimeMs);return{name:e.label??e.chatId??e.sessionId,path:e.sessionId,lastModified:t,lastModifiedFormatted:(0,a.formatDate)(t),sessionId:e.sessionId,cli:"openclaw",channelId:e.chatId,channelType:e.chatType}})}}let d=(0,i.runtimeCache)(f,2),g=(0,i.runtimeCache)(e=>m(e),2,{maxSize:50});e.s(["getCachedOpenClawProjects",0,d,"getCachedOpenClawSessions",0,l,"getCachedOpenClawSessionsByEncodedName",0,g,"getOpenClawProjects",0,f,"getOpenClawSessions",0,o,"getOpenClawSessionsByEncodedName",0,m,"openClawProjectName",0,u,"openClawProjectNameCandidates",0,p,"openClawProjectPath",0,c,"parseOpenClawProjectName",0,function(e){return p(e)[0]??null}])},64199,e=>{"use strict";var t=e.i(12714),n=e.i(2157),i=e.i(60526),s=e.i(50227),a=e.i(83534),r=e.i(54214),o=e.i(67405);let l=/^[0-9a-fA-F-]{36}$/;function u(){return process.env.OPENCLAW_HOME||(0,s.join)((0,i.homedir)(),".openclaw")}function c(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function p(e){return"string"==typeof e?e:Array.isArray(e)?e.map(e=>c(e)&&"string"==typeof e.text?e.text:"").filter(Boolean).join("\n"):""}function f(){let e,t=(0,s.join)(u(),"agents"),i=[];try{e=(0,n.readdirSync)(t,{withFileTypes:!0}).filter(e=>e.isDirectory()).map(e=>e.name)}catch{return i}for(let a of e){let e,r=(0,s.join)(t,a,"sessions");try{e=(0,n.readdirSync)(r)}catch{continue}for(let t of e){if(!t.endsWith(".jsonl")||t.endsWith(".trajectory.jsonl"))continue;let e=t.slice(0,-6);if(!l.test(e))continue;let o=(0,s.join)(r,t);try{let t=(0,n.statSync)(o);i.push({agentId:a,sessionId:e,transcriptPath:o,mtimeMs:t.mtimeMs,sizeBytes:t.size})}catch{}}}return i}function m(e){if(!l.test(e))return null;for(let t of f())if(t.sessionId===e)return t.transcriptPath;return null}async function d(e){let n,i,s=m(e);if(!s)return null;try{n=await (0,t.readFile)(s,"utf-8")}catch{return null}let a=(0,r.parseRawLines)(n,"session"),l=function(e,t="session"){let n=[],i=new Map,s=new Map,a=Date.now();for(let l=0;l<e.length;l++){let u=e[l];if(!c(u)||"message"!==u.type)continue;let f=c(u.message)?u.message:void 0;if(!f)continue;let m="string"==typeof f.role?f.role:"system",d=function(e,t){if("number"==typeof e&&Number.isFinite(e)){if(e>1e12)return new Date(e);if(e>1e9)return new Date(1e3*e)}if("string"==typeof e){let t=Date.parse(e);if(!Number.isNaN(t))return new Date(t)}return new Date(t)}(u.timestamp??f.timestamp,a+l),g=d.toISOString(),y={uuid:null!=u.id?String(u.id):`openclaw-${l}`,parentUuid:null!=u.parentId?String(u.parentId):null},h=(0,r.baseEntry)(y,g,d,t);if("user"===m){n.push({type:"user",...h,message:{role:"user",content:p(f.content)}});continue}if("assistant"===m){let e=[],t=f.content;if(Array.isArray(t)){for(let n of t)if(c(n)){if("text"===n.type&&"string"==typeof n.text)e.push({type:"text",text:n.text});else if("toolCall"===n.type){let t="string"==typeof n.id?n.id:`${String(n.name??"tool")}-${e.length}`,a={type:"tool_use",id:t,name:"string"==typeof n.name?n.name:"tool",input:c(n.arguments)?n.arguments:{}};e.push(a),i.set(t,a),s.set(t,d.getTime())}}}else{let n=p(t);n&&e.push({type:"text",text:n})}if(0===e.length)continue;n.push({type:"assistant",...h,message:{role:"assistant",content:e,model:"string"==typeof f.model?f.model:void 0}});continue}if("toolResult"===m){let e="string"==typeof f.toolCallId?f.toolCallId:void 0,t=e?i.get(e):void 0;if(t){let n=c(f.details)?f.details:void 0,i=e&&s.get(e)||d.getTime(),a=n&&"number"==typeof n.durationMs?n.durationMs:Math.max(0,d.getTime()-i);t.result={timestamp:g,timestampFormatted:(0,r.formatTimestamp)(d),content:p(f.content),durationMs:a,durationFormatted:(0,o.formatDuration)(a)};continue}}n.push({type:"system",...h,raw:y})}return n.sort((e,t)=>e.timestampMs-t.timestampMs),n}(a,"session");for(let e of a)if(c(e)&&"session"===e.type&&"string"==typeof e.cwd&&e.cwd.length>0){i=e.cwd;break}return{entries:l,rawLines:a,cwd:i,filePath:s}}(0,a.runtimeCache)(e=>d(e),2,{maxSize:50}),e.s(["findOpenClawTranscript",0,m,"getOpenClawSessionLog",0,d,"listOpenClawAgents",0,function(){try{return(0,n.readdirSync)((0,s.join)(u(),"agents"),{withFileTypes:!0}).filter(e=>e.isDirectory()&&!e.name.startsWith(".")).map(e=>e.name).sort()}catch{return[]}},"listOpenClawTranscripts",0,f,"openclawHome",0,u])}];
2
-
3
- //# sourceMappingURL=%5Broot-of-the-server%5D__04_h-a5._.js.map