failproofai 1.0.5-beta.1 → 1.0.5-beta.2

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 (135) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +7 -7
  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/build-manifest.json +4 -4
  6. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +6 -6
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +4 -4
  15. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  16. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
  20. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  21. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +13 -13
  22. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  23. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  24. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  25. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  26. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  28. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +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/build-manifest.json +4 -4
  32. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  33. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  35. package/.next/standalone/.next/server/app/index.html +1 -1
  36. package/.next/standalone/.next/server/app/index.rsc +14 -14
  37. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +13 -13
  38. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
  39. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  40. package/.next/standalone/.next/server/app/page/build-manifest.json +4 -4
  41. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  42. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  44. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +4 -4
  45. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
  46. package/.next/standalone/.next/server/app/policies/page.js +1 -1
  47. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  48. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  49. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +4 -4
  50. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  51. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  52. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  53. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +4 -4
  54. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  55. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  56. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  57. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  58. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +4 -4
  59. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  60. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  61. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  62. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +4 -4
  63. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
  64. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  66. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
  67. package/.next/standalone/.next/server/chunks/_09dz7xv._.js +1 -1
  68. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  69. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  70. package/.next/standalone/.next/server/chunks/_1vslkoe._.js +1 -1
  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]__00y9ww2._.js +1 -1
  73. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +2 -2
  74. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +2 -2
  75. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +2 -2
  76. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0n_lxhg._.js → [root-of-the-server]__0bym1os._.js} +1 -1
  77. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +2 -2
  78. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +2 -2
  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]__0p-5p8u._.js +2 -2
  81. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +2 -2
  82. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0sz_5na._.js +1 -1
  83. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ctpynv._.js +1 -1
  84. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +2 -2
  85. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u6sn69._.js +1 -1
  86. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__05g1k7_._.js → [root-of-the-server]__1xu5t8b._.js} +2 -2
  87. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/ssr/_1_ozgif._.js +1 -1
  89. package/.next/standalone/.next/server/chunks/ssr/_1es2j7i._.js +2 -2
  90. package/.next/standalone/.next/server/chunks/ssr/{_0iv28v5._.js → _1mo4bp9._.js} +1 -1
  91. package/.next/standalone/.next/server/chunks/ssr/{_17noq1a._.js → _1olen4g._.js} +2 -2
  92. package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
  93. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  94. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
  95. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  96. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  97. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  98. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
  99. package/.next/standalone/.next/server/chunks/ssr/lib_codex-projects_ts_0pqlw37._.js +1 -1
  100. package/.next/standalone/.next/server/middleware-build-manifest.js +7 -7
  101. package/.next/standalone/.next/server/pages/404.html +1 -1
  102. package/.next/standalone/.next/server/pages/500.html +1 -1
  103. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  104. package/.next/standalone/.next/server/server-reference-manifest.json +19 -19
  105. package/.next/standalone/.next/static/chunks/{2b014kj28p0vz.js → 04cawl3i7gqi5.js} +1 -1
  106. package/.next/standalone/.next/static/chunks/{3pmi7qhtmniku.js → 0671mdu5plc8o.js} +1 -1
  107. package/.next/standalone/.next/static/chunks/{26tf_lpco5n-v.js → 0cn62s92buqr1.js} +1 -1
  108. package/.next/standalone/.next/static/chunks/{41ejnuj2d9g7_.js → 0h95tsad4_-gr.js} +1 -1
  109. package/.next/standalone/.next/static/chunks/{3qxl_gibq3bas.js → 0pdmk3xha1zih.js} +1 -1
  110. package/.next/standalone/.next/static/chunks/{3kltzmx9k_t6x.js → 1c6aptmytnu6q.js} +1 -1
  111. package/.next/standalone/.next/static/chunks/{25cn9xpv4r1ow.js → 1oey07bwm1ayr.js} +1 -1
  112. package/.next/standalone/.next/static/chunks/{3q1rji38vuvr4.js → 1qwk_vp6dsat_.js} +1 -1
  113. package/.next/standalone/.next/static/chunks/{0qytob94jbzs6.js → 2pnvnpg-kdbyt.js} +1 -1
  114. package/.next/standalone/.next/static/chunks/{3i8rg2fv9nd6e.js → 315zh293r-n7v.js} +1 -1
  115. package/.next/standalone/.next/static/chunks/{3_fnbc-v5r-9e.js → 3aoj_ov89ym_h.js} +1 -1
  116. package/.next/standalone/.next/static/chunks/{074xcclgow3yh.js → 3gfi5ixrc6v1z.js} +1 -1
  117. package/.next/standalone/.next/static/chunks/{3vjaz4hld9oo8.js → 3k3g_4k13t9za.js} +1 -1
  118. package/.next/standalone/.next/static/chunks/{turbopack-1xgsp63yhrdu5.js → turbopack-44avr18ueo9ob.js} +1 -1
  119. package/.next/standalone/lib/openclaw-profiles.ts +78 -0
  120. package/.next/standalone/lib/openclaw-projects.ts +3 -3
  121. package/.next/standalone/lib/sqlite-reader.ts +165 -9
  122. package/.next/standalone/package.json +9 -9
  123. package/.next/standalone/server.js +1 -1
  124. package/dist/cli.mjs +845 -684
  125. package/dist/worker.mjs +129 -17
  126. package/lib/openclaw-profiles.ts +78 -0
  127. package/lib/openclaw-projects.ts +3 -3
  128. package/lib/sqlite-reader.ts +165 -9
  129. package/openclaw-plugin/index.js +13 -7
  130. package/openclaw-plugin/workspace-context.js +93 -0
  131. package/package.json +9 -9
  132. package/src/hooks/integrations.ts +22 -14
  133. /package/.next/standalone/.next/static/{Qexks15mjEoPt6cN3D2jb → GDwSJ81wNHeh1pQdxpvk_}/_buildManifest.js +0 -0
  134. /package/.next/standalone/.next/static/{Qexks15mjEoPt6cN3D2jb → GDwSJ81wNHeh1pQdxpvk_}/_clientMiddlewareManifest.js +0 -0
  135. /package/.next/standalone/.next/static/{Qexks15mjEoPt6cN3D2jb → GDwSJ81wNHeh1pQdxpvk_}/_ssgManifest.js +0 -0
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Resolve the workspace for OpenClaw tool hooks.
3
+ *
4
+ * OpenClaw's agent hooks expose `ctx.workspaceDir`, but its tool hooks expose
5
+ * only agent/session identity. Policies still need the real workspace at tool
6
+ * time, so derive it from the profile config and retain agent-hook observations
7
+ * as a compatibility fallback.
8
+ */
9
+
10
+ function nonEmptyString(value) {
11
+ return typeof value === "string" && value.length > 0 ? value : undefined;
12
+ }
13
+
14
+ function agentIdFromContext(payload, ctx) {
15
+ const direct = nonEmptyString(ctx?.agentId) ?? nonEmptyString(payload?.agentId);
16
+ if (direct) return direct;
17
+
18
+ const sessionKey = nonEmptyString(ctx?.sessionKey) ?? nonEmptyString(payload?.sessionKey);
19
+ const match = sessionKey?.match(/^agent:([^:]+):/);
20
+ return match?.[1];
21
+ }
22
+
23
+ /** Resolve both current (`agents.entries`) and legacy (`agents.list`) shapes. */
24
+ export function workspaceFromConfig(config, agentId) {
25
+ if (!config || typeof config !== "object" || !agentId) return undefined;
26
+ const agents = config.agents;
27
+ if (!agents || typeof agents !== "object") return undefined;
28
+
29
+ const entries = agents.entries;
30
+ if (entries && typeof entries === "object" && !Array.isArray(entries)) {
31
+ const exact = entries[agentId];
32
+ if (exact && typeof exact === "object") {
33
+ const workspace = nonEmptyString(exact.workspace);
34
+ if (workspace) return workspace;
35
+ }
36
+ }
37
+
38
+ if (Array.isArray(agents.list)) {
39
+ const entry = agents.list.find((candidate) =>
40
+ candidate && typeof candidate === "object" &&
41
+ (candidate.id === agentId || candidate.name === agentId),
42
+ );
43
+ const workspace = nonEmptyString(entry?.workspace);
44
+ if (workspace) return workspace;
45
+ }
46
+
47
+ const defaults = agents.defaults;
48
+ if (defaults && typeof defaults === "object") {
49
+ return nonEmptyString(defaults.workspace);
50
+ }
51
+ return undefined;
52
+ }
53
+
54
+ function cacheKeys(payload, ctx) {
55
+ const values = [
56
+ ["run", ctx?.runId ?? payload?.runId],
57
+ ["session-id", ctx?.sessionId ?? payload?.sessionId],
58
+ ["session-key", ctx?.sessionKey ?? payload?.sessionKey],
59
+ ["agent", agentIdFromContext(payload, ctx)],
60
+ ];
61
+ return values
62
+ .filter(([, value]) => nonEmptyString(value))
63
+ .map(([kind, value]) => `${kind}:${value}`);
64
+ }
65
+
66
+ export function createWorkspaceContext() {
67
+ const cache = new Map();
68
+
69
+ function remember(payload, ctx) {
70
+ const workspace = nonEmptyString(payload?.cwd) ?? nonEmptyString(ctx?.workspaceDir);
71
+ if (!workspace) return undefined;
72
+ for (const key of cacheKeys(payload, ctx)) cache.set(key, workspace);
73
+ return workspace;
74
+ }
75
+
76
+ function resolveWorkspace(payload, ctx, config) {
77
+ const direct = remember(payload, ctx);
78
+ if (direct) return direct;
79
+
80
+ for (const key of cacheKeys(payload, ctx)) {
81
+ const cached = cache.get(key);
82
+ if (cached) return cached;
83
+ }
84
+
85
+ return workspaceFromConfig(config, agentIdFromContext(payload, ctx));
86
+ }
87
+
88
+ function clear(payload, ctx) {
89
+ for (const key of cacheKeys(payload, ctx)) cache.delete(key);
90
+ }
91
+
92
+ return { remember, resolveWorkspace, clear };
93
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "failproofai",
3
- "version": "1.0.5-beta.1",
3
+ "version": "1.0.5-beta.2",
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.5-beta.1",
125
- "@failproofai/failproofaid-linux-arm64": "1.0.5-beta.1",
126
- "@failproofai/failproofaid-darwin-x64": "1.0.5-beta.1",
127
- "@failproofai/failproofaid-darwin-arm64": "1.0.5-beta.1"
124
+ "@failproofai/failproofaid-linux-x64": "1.0.5-beta.2",
125
+ "@failproofai/failproofaid-linux-arm64": "1.0.5-beta.2",
126
+ "@failproofai/failproofaid-darwin-x64": "1.0.5-beta.2",
127
+ "@failproofai/failproofaid-darwin-arm64": "1.0.5-beta.2"
128
128
  },
129
129
  "failproofaidBinaries": {
130
- "linux-x64": "c782c8d7c8522bf8af6f776640cae80fa671affa5b92d8c09e646c8f381d7fd4",
131
- "linux-arm64": "6e9717ef40872a530501ad17cc6bc9743546968e11acf45f87f35488d1563e28",
132
- "darwin-x64": "b47adb286e2cf08370ec2e1293ea3ed42891c7d2a8a1bece3da8e3e2b0d72f7a",
133
- "darwin-arm64": "a5095522dc3f2518fc8177e9e2a3048062540958e3b623b198b401a7d6a2ddd5"
130
+ "linux-x64": "cce0b612f53a28591a0eb6f3e1abe7cadfc490afedff85c8f55772e76c7be566",
131
+ "linux-arm64": "20ead289387082e38e456cef27271ff74df368ec90389ce4f818af73af24cfa1",
132
+ "darwin-x64": "9a6fc5c2aa250224aea7fa7b945230636d34e7aea454177c131d40a5f56e17a1",
133
+ "darwin-arm64": "fb26aa5ffbbc971b9923593dc6f5a05f1d20b7d5e9953172b81318038252a240"
134
134
  }
135
135
  }
@@ -13,6 +13,7 @@ import { fileURLToPath } from "node:url";
13
13
  import { homedir } from "node:os";
14
14
  import { parseDocument, type Document } from "yaml";
15
15
  import { listHermesProfiles, hermesRoot } from "../../lib/hermes-profiles";
16
+ import { listOpenClawProfiles } from "../../lib/openclaw-profiles";
16
17
  import {
17
18
  CLAUDE_INSTALL_EVENT_TYPES,
18
19
  HOOK_SCOPES,
@@ -1534,7 +1535,7 @@ export function unhookedHermesProfiles(): string[] {
1534
1535
  // PLUGIN hooks (file-based "internal hooks" are observation-only), so failproofai
1535
1536
  // ships a static plugin package (`openclaw-plugin/`, like Pi's pi-extension) that
1536
1537
  // async-spawns the binary and maps verdicts back. Install registers the plugin in
1537
- // `~/.openclaw/openclaw.json` (JSON):
1538
+ // every profile's `openclaw.json` (JSON):
1538
1539
  // • plugins.load.paths[] → the shipped openclaw-plugin dir (absolute path)
1539
1540
  // • plugins.entries.failproofai = { enabled: true, hooks: { allowConversationAccess: true } }
1540
1541
  // (allowConversationAccess is required for the raw-conversation hooks
@@ -1577,9 +1578,14 @@ export const openclaw: Integration = {
1577
1578
  scopes: OPENCLAW_HOOK_SCOPES,
1578
1579
  eventTypes: OPENCLAW_HOOK_EVENT_TYPES,
1579
1580
 
1580
- // USER scope only (~/.openclaw/openclaw.json); OpenClaw has no project config.
1581
+ // USER scope only; this is the default profile. Named profiles are returned
1582
+ // by getSettingsPaths so one config pass cannot leave gateways unenforced.
1581
1583
  getSettingsPath() {
1582
- return resolve(homedir(), ".openclaw", "openclaw.json");
1584
+ return resolve(listOpenClawProfiles()[0].home, "openclaw.json");
1585
+ },
1586
+
1587
+ getSettingsPaths() {
1588
+ return listOpenClawProfiles().map((profile) => resolve(profile.home, "openclaw.json"));
1583
1589
  },
1584
1590
 
1585
1591
  readSettings(settingsPath) {
@@ -1657,17 +1663,19 @@ export const openclaw: Integration = {
1657
1663
  },
1658
1664
 
1659
1665
  hooksInstalledInSettings(scope, cwd) {
1660
- const settingsPath = this.getSettingsPath(scope, cwd);
1661
- if (!existsSync(settingsPath)) return false;
1662
- try {
1663
- const settings = this.readSettings(settingsPath) as OpenClawSettingsFile;
1664
- const paths = settings.plugins?.load?.paths;
1665
- const pathPresent = Array.isArray(paths) && paths.some((p) => isFailproofaiOpenClawPath(p));
1666
- const entryEnabled = settings.plugins?.entries?.[OPENCLAW_PLUGIN_ID]?.enabled === true;
1667
- return pathPresent && entryEnabled;
1668
- } catch {
1669
- return false;
1670
- }
1666
+ const settingsPaths = settingsPathsFor(this, scope, cwd);
1667
+ return settingsPaths.length > 0 && settingsPaths.every((settingsPath) => {
1668
+ if (!existsSync(settingsPath)) return false;
1669
+ try {
1670
+ const settings = this.readSettings(settingsPath) as OpenClawSettingsFile;
1671
+ const paths = settings.plugins?.load?.paths;
1672
+ const pathPresent = Array.isArray(paths) && paths.some((p) => isFailproofaiOpenClawPath(p));
1673
+ const entryEnabled = settings.plugins?.entries?.[OPENCLAW_PLUGIN_ID]?.enabled === true;
1674
+ return pathPresent && entryEnabled;
1675
+ } catch {
1676
+ return false;
1677
+ }
1678
+ });
1671
1679
  },
1672
1680
 
1673
1681
  detectInstalled() {