failproofai 1.0.4-beta.7 → 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 (132) 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/auth/login-request/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +1 -1
  29. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +5 -5
  31. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  33. package/.next/standalone/.next/server/app/index.html +1 -1
  34. package/.next/standalone/.next/server/app/index.rsc +14 -14
  35. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
  36. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
  37. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  38. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  39. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  42. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  44. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  45. package/.next/standalone/.next/server/app/project/[name]/page.js +2 -2
  46. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  48. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  49. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  50. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +2 -2
  51. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  54. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  55. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  56. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +5 -5
  57. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  58. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  59. package/.next/standalone/.next/server/chunks/{[externals]__0v1hz15._.js → [externals]__0hmcwgg._.js} +1 -1
  60. package/.next/standalone/.next/server/chunks/{[externals]__1nb206a._.js → [externals]__14b7cc6._.js} +1 -1
  61. package/.next/standalone/.next/server/chunks/[root-of-the-server]__08dchfu._.js +1 -1
  62. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0faqz9x._.js +22 -0
  63. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  64. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zyc_nm._.js +3 -0
  65. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p-qi2t._.js → [root-of-the-server]__112b4go._.js} +22 -3
  66. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1l71g3y._.js +22 -0
  67. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  68. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  69. package/.next/standalone/.next/server/chunks/{_0otft92._.js → _1_eakl4._.js} +2 -2
  70. package/.next/standalone/.next/server/chunks/lib_openclaw-projects_ts_0gc-p24._.js +3 -0
  71. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  72. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-4ja6q._.js +2 -2
  73. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00cr3xu._.js +2 -2
  74. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1sc84bb._.js → [root-of-the-server]__00y9ww2._.js} +21 -2
  75. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04px77e._.js +2 -2
  76. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0egr5s1._.js +2 -2
  77. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0i0l1di._.js +2 -2
  78. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n2txhk._.js +1 -1
  79. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
  80. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0r3c1_0._.js +2 -2
  81. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17xnxlx._.js +2 -2
  82. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1fvfw59._.js → [root-of-the-server]__187jks6._.js} +1 -1
  83. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ckpmkk._.js +2 -2
  84. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__12hbpha._.js → [root-of-the-server]__1fa1jd9._.js} +2 -2
  85. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1kaotix._.js +22 -0
  86. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0dxf928._.js → [root-of-the-server]__1kpd1za._.js} +1 -1
  87. package/.next/standalone/.next/server/chunks/ssr/{_0a0zlpr._.js → _00bqkhj._.js} +2 -2
  88. package/.next/standalone/.next/server/chunks/ssr/_04ng_6x._.js +1 -1
  89. package/.next/standalone/.next/server/chunks/ssr/_07t3jol._.js +1 -1
  90. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  91. package/.next/standalone/.next/server/chunks/ssr/{_1if9ixi._.js → _14c6q09._.js} +21 -2
  92. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
  93. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  94. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  95. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  96. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
  97. package/.next/standalone/.next/server/chunks/ssr/lib_openclaw-projects_ts_0qxq3bp._.js +1 -1
  98. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  99. package/.next/standalone/.next/server/pages/404.html +1 -1
  100. package/.next/standalone/.next/server/pages/500.html +1 -1
  101. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  102. package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
  103. package/.next/standalone/.next/static/chunks/{2h_pcb1y8_jde.js → 0igq884ziuv-8.js} +1 -1
  104. package/.next/standalone/.next/static/chunks/{083fk73jtv9a0.js → 0vm4wdx3w-2_w.js} +1 -1
  105. package/.next/standalone/.next/static/chunks/{0f1pznnc7zlub.js → 1302duobnz07l.js} +1 -1
  106. package/.next/standalone/.next/static/chunks/{15uon66hpwbgg.js → 1_x7pqemw5n_w.js} +1 -1
  107. package/.next/standalone/.next/static/chunks/{0t6ea7d3bkmdv.js → 1chm9piluggc-.js} +1 -1
  108. package/.next/standalone/.next/static/chunks/{2pwfrn6_mw-1u.js → 2mizt96igig1y.js} +1 -1
  109. package/.next/standalone/.next/static/chunks/{1csubx9gwhsf6.js → 2n85g-crgcx5j.js} +1 -1
  110. package/.next/standalone/.next/static/chunks/{0ntdfr2552x-h.js → 2ukucf6g-kbs5.js} +1 -1
  111. package/.next/standalone/.next/static/chunks/{27du9n7ssja7l.js → 349jkb79v5g6z.js} +1 -1
  112. package/.next/standalone/.next/static/chunks/{0divvxng208xo.js → 3a4gth64hwtwf.js} +1 -1
  113. package/.next/standalone/lib/download-session.ts +58 -13
  114. package/.next/standalone/lib/openclaw-db.ts +271 -0
  115. package/.next/standalone/lib/openclaw-projects.ts +54 -18
  116. package/.next/standalone/lib/openclaw-sessions.ts +75 -17
  117. package/.next/standalone/package.json +9 -9
  118. package/.next/standalone/server.js +1 -1
  119. package/dist/cli.mjs +456 -261
  120. package/dist/worker.mjs +285 -90
  121. package/lib/download-session.ts +58 -13
  122. package/lib/openclaw-db.ts +271 -0
  123. package/lib/openclaw-projects.ts +54 -18
  124. package/lib/openclaw-sessions.ts +75 -17
  125. package/package.json +9 -9
  126. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-219ec._.js +0 -3
  127. package/.next/standalone/.next/server/chunks/[root-of-the-server]__04_h-a5._.js +0 -3
  128. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1le9jqc._.js +0 -3
  129. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1nq7ivq._.js +0 -3
  130. /package/.next/standalone/.next/static/{YiPsVpjrc-pEQoN7XvhZ0 → DNhaAH8iPGH0tIuxee5_2}/_buildManifest.js +0 -0
  131. /package/.next/standalone/.next/static/{YiPsVpjrc-pEQoN7XvhZ0 → DNhaAH8iPGH0tIuxee5_2}/_clientMiddlewareManifest.js +0 -0
  132. /package/.next/standalone/.next/static/{YiPsVpjrc-pEQoN7XvhZ0 → DNhaAH8iPGH0tIuxee5_2}/_ssgManifest.js +0 -0
@@ -1,18 +1,21 @@
1
1
  /**
2
2
  * OpenClaw (openclaw gateway) session enumeration — AUDIT-ONLY.
3
3
  *
4
- * Surfaces the on-disk transcripts (agents/<agentId>/sessions/<uuid>.jsonl) as
5
- * synthetic dashboard "projects" grouped by (agentId, channel). The per-agent
6
- * `sessions.json` index maps sessionKey → {sessionId, timestamps}; we read it to
7
- * recover the sessionKey (which encodes the channel for gateway sessions) and a
8
- * reliable last-activity time. Verified live against openclaw v2026.7.1.
4
+ * Surfaces both legacy JSONL transcripts and OpenClaw 2026.9.2+ per-agent
5
+ * SQLite transcripts as synthetic dashboard "projects" grouped by
6
+ * (agentId, channel).
9
7
  */
10
8
  import { readFileSync } from "node:fs";
11
9
  import { join } from "node:path";
12
10
  import { runtimeCache } from "./runtime-cache";
13
- import { listOpenClawAgents, listOpenClawTranscripts, openclawHome } from "./openclaw-sessions";
11
+ import {
12
+ listOpenClawAgents,
13
+ listOpenClawTranscripts,
14
+ openclawHome,
15
+ } from "./openclaw-sessions";
14
16
  import type { ProjectFolder, SessionFile } from "./projects";
15
17
  import { formatDate } from "./format-date";
18
+ import { listOpenClawSqliteSessions } from "./openclaw-db";
16
19
 
17
20
  export interface OpenClawSessionRef {
18
21
  sessionId: string;
@@ -51,7 +54,13 @@ function str(v: unknown): string | undefined {
51
54
  * than in the key — verified live against v2026.7.1. */
52
55
  function readSessionsIndex(agentId: string): Map<string, SessionIndexMeta> {
53
56
  const out = new Map<string, SessionIndexMeta>();
54
- const indexPath = join(openclawHome(), "agents", agentId, "sessions", "sessions.json");
57
+ const indexPath = join(
58
+ openclawHome(),
59
+ "agents",
60
+ agentId,
61
+ "sessions",
62
+ "sessions.json",
63
+ );
55
64
  let raw: unknown;
56
65
  try {
57
66
  raw = JSON.parse(readFileSync(indexPath, "utf-8"));
@@ -64,7 +73,9 @@ function readSessionsIndex(agentId: string): Map<string, SessionIndexMeta> {
64
73
  const e = v as Record<string, unknown>;
65
74
  const sessionId = str(e.sessionId);
66
75
  if (!sessionId) continue;
67
- const origin = (e.origin && typeof e.origin === "object" ? e.origin : {}) as Record<string, unknown>;
76
+ const origin = (
77
+ e.origin && typeof e.origin === "object" ? e.origin : {}
78
+ ) as Record<string, unknown>;
68
79
  const lastMs =
69
80
  typeof e.lastInteractionAt === "number"
70
81
  ? e.lastInteractionAt
@@ -73,7 +84,8 @@ function readSessionsIndex(agentId: string): Map<string, SessionIndexMeta> {
73
84
  : undefined;
74
85
  out.set(sessionId, {
75
86
  lastMs,
76
- channel: str(e.lastChannel) ?? str(origin.provider) ?? str(origin.surface),
87
+ channel:
88
+ str(e.lastChannel) ?? str(origin.provider) ?? str(origin.surface),
77
89
  chatType: str(e.chatType) ?? str(origin.chatType),
78
90
  label: str(origin.label),
79
91
  chatId: str(e.lastTo) ?? str(origin.from),
@@ -86,7 +98,7 @@ function readSessionsIndex(agentId: string): Map<string, SessionIndexMeta> {
86
98
  export async function getOpenClawSessions(): Promise<OpenClawSessionRef[]> {
87
99
  const transcripts = listOpenClawTranscripts();
88
100
  const indexByAgent = new Map<string, Map<string, SessionIndexMeta>>();
89
- const refs: OpenClawSessionRef[] = [];
101
+ const refs = new Map<string, OpenClawSessionRef>();
90
102
  for (const t of transcripts) {
91
103
  let idx = indexByAgent.get(t.agentId);
92
104
  if (!idx) {
@@ -94,7 +106,7 @@ export async function getOpenClawSessions(): Promise<OpenClawSessionRef[]> {
94
106
  indexByAgent.set(t.agentId, idx);
95
107
  }
96
108
  const meta = idx.get(t.sessionId);
97
- refs.push({
109
+ refs.set(`${t.agentId}\0${t.sessionId}`, {
98
110
  sessionId: t.sessionId,
99
111
  agentId: t.agentId,
100
112
  // Gateway sessions group by channel; CLI/local runs have none.
@@ -107,8 +119,18 @@ export async function getOpenClawSessions(): Promise<OpenClawSessionRef[]> {
107
119
  sizeBytes: t.sizeBytes,
108
120
  });
109
121
  }
110
- refs.sort((a, b) => b.mtimeMs - a.mtimeMs);
111
- return refs;
122
+
123
+ // SQLite is the live source on OpenClaw 2026.9.2+. Insert it second so it
124
+ // replaces an archived JSONL copy of the same agent/session.
125
+ const sqliteSessions = await listOpenClawSqliteSessions(
126
+ openclawHome(),
127
+ listOpenClawAgents(),
128
+ );
129
+ for (const s of sqliteSessions) {
130
+ refs.set(`${s.agentId}\0${s.sessionId}`, s);
131
+ }
132
+
133
+ return [...refs.values()].sort((a, b) => b.mtimeMs - a.mtimeMs);
112
134
  }
113
135
 
114
136
  export const getCachedOpenClawSessions = runtimeCache(getOpenClawSessions, 2);
@@ -145,7 +167,9 @@ export interface OpenClawNameSplit {
145
167
  * form (`agentId: null`), so links shared before agents became part of the name
146
168
  * keep resolving — to every agent on that channel, which is what they meant.
147
169
  */
148
- export function openClawProjectNameCandidates(name: string): OpenClawNameSplit[] {
170
+ export function openClawProjectNameCandidates(
171
+ name: string,
172
+ ): OpenClawNameSplit[] {
149
173
  if (!name.startsWith("openclaw-")) return [];
150
174
  const rest = name.slice("openclaw-".length);
151
175
  if (!rest) return [];
@@ -163,7 +187,9 @@ export function openClawProjectNameCandidates(name: string): OpenClawNameSplit[]
163
187
  }
164
188
 
165
189
  /** The best-guess split for a project name — `null` if it isn't an OpenClaw one. */
166
- export function parseOpenClawProjectName(name: string): OpenClawNameSplit | null {
190
+ export function parseOpenClawProjectName(
191
+ name: string,
192
+ ): OpenClawNameSplit | null {
167
193
  return openClawProjectNameCandidates(name)[0] ?? null;
168
194
  }
169
195
 
@@ -190,7 +216,12 @@ export async function getOpenClawProjects(): Promise<ProjectFolder[]> {
190
216
  prev.latest = Math.max(prev.latest, s.mtimeMs);
191
217
  prev.count += 1;
192
218
  } else {
193
- groups.set(key, { agentId: s.agentId, channel: s.channel, latest: s.mtimeMs, count: 1 });
219
+ groups.set(key, {
220
+ agentId: s.agentId,
221
+ channel: s.channel,
222
+ latest: s.mtimeMs,
223
+ count: 1,
224
+ });
194
225
  }
195
226
  }
196
227
  const out: ProjectFolder[] = [];
@@ -228,7 +259,9 @@ export async function getOpenClawSessionsByEncodedName(
228
259
  const sessions = await getOpenClawSessions();
229
260
  const matching = (split: OpenClawNameSplit) =>
230
261
  sessions.filter(
231
- (s) => s.channel === split.channel && (split.agentId === null || s.agentId === split.agentId),
262
+ (s) =>
263
+ s.channel === split.channel &&
264
+ (split.agentId === null || s.agentId === split.agentId),
232
265
  );
233
266
 
234
267
  // Take the first split that actually owns sessions — length alone picks the
@@ -250,7 +283,10 @@ export async function getOpenClawSessionsByEncodedName(
250
283
  return {
251
284
  // Legacy channel-only names keep their old cwd label, since they really do
252
285
  // span every agent on that channel.
253
- cwd: agentId === null ? `openclaw:${channel}` : openClawProjectPath(agentId, channel),
286
+ cwd:
287
+ agentId === null
288
+ ? `openclaw:${channel}`
289
+ : openClawProjectPath(agentId, channel),
254
290
  sessions: matched.map((s) => {
255
291
  const lastModified = new Date(s.mtimeMs);
256
292
  return {
@@ -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
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "failproofai",
3
- "version": "1.0.4-beta.7",
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.7",
125
- "@failproofai/failproofaid-linux-arm64": "1.0.4-beta.7",
126
- "@failproofai/failproofaid-darwin-x64": "1.0.4-beta.7",
127
- "@failproofai/failproofaid-darwin-arm64": "1.0.4-beta.7"
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": "e59735a8f94cd8ac697b2bd67aafdd8d76a8394d53db229876980cc13a18f07e",
131
- "linux-arm64": "b9ce50dd2f79b55f4f7112add265a776a4a6d002c2a56f971e666fbb796f3906",
132
- "darwin-x64": "b46efc8ec33945a5cc26b7bb288fb87cea65b5983bd83094b5e607d53b8eda4c",
133
- "darwin-arm64": "a8cc6112cee5ca8a7d517900e9ce32118855135980f22979fa0ff7aa6f68d954"
130
+ "linux-x64": "17274c1da30675b49de74953a4ce2777e09ba07b9da79250ab155e5fdb316a0a",
131
+ "linux-arm64": "a07b228d899914baca1c75024be19c0319eb4fc40c6d5a303ba733bf6721924a",
132
+ "darwin-x64": "d170fd5604cb419bc83f4a5ab1a6cb5be2f9aec957aed99ce237990aa5d3966f",
133
+ "darwin-arm64": "0e2bde5bd0762641fa072a6640e485c637b2102f2fb6c1afeca679f005e89679"
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.7"},"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"}
12
+ const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"1.0.4-beta.8"},"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