failproofai 1.0.6-beta.0 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) 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 +4 -4
  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.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  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 +6 -5
  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 +1 -1
  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 +1 -1
  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 +4 -4
  58. package/.next/standalone/.next/server/app/settings/page.js +3 -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/[root-of-the-server]__0o07qi9._.js +1 -1
  62. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zlqo2t._.js +1 -1
  63. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__112b4go._.js → [root-of-the-server]__1_r2rbg._.js} +4 -4
  64. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1anxb5k._.js +1 -1
  65. package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
  66. package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
  67. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  68. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-_ki57._.js +4 -0
  69. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +2 -2
  70. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +2 -2
  71. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +2 -2
  72. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0576iuy._.js +3 -0
  73. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0bym1os._.js → [root-of-the-server]__0cg-bgc._.js} +2 -2
  74. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +2 -2
  75. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +2 -2
  76. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +2 -2
  77. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__00y9ww2._.js → [root-of-the-server]__0u3w0ll._.js} +2 -2
  78. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1b2dbet._.js +1 -1
  79. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +2 -2
  80. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1py795m._.js +1 -1
  81. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1i26dsw._.js → [root-of-the-server]__1svlq8e._.js} +2 -2
  82. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1v185mo._.js +1 -1
  83. package/.next/standalone/.next/server/chunks/ssr/_06imw3p._.js +5 -0
  84. package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
  85. package/.next/standalone/.next/server/chunks/ssr/{_09hs6ms._.js → _0do6d26._.js} +1 -1
  86. package/.next/standalone/.next/server/chunks/ssr/{_0lbwa8m._.js → _17o744m._.js} +2 -2
  87. package/.next/standalone/.next/server/chunks/ssr/{_14c6q09._.js → _1_qswah._.js} +2 -2
  88. package/.next/standalone/.next/server/chunks/ssr/_1es2j7i._.js +1 -1
  89. package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
  90. package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
  91. package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +12 -11
  92. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  93. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  94. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  95. package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
  96. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  97. package/.next/standalone/.next/server/pages/404.html +1 -1
  98. package/.next/standalone/.next/server/pages/500.html +1 -1
  99. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  100. package/.next/standalone/.next/server/server-reference-manifest.json +19 -19
  101. package/.next/standalone/.next/static/chunks/0bepqeawy72n6.js +1 -0
  102. package/.next/standalone/.next/static/chunks/{17pjz_h45j10c.js → 0h-gz8e00478q.js} +1 -1
  103. package/.next/standalone/.next/static/chunks/{3d3hzhcnns6ww.js → 25m8mg7bosgip.js} +1 -1
  104. package/.next/standalone/.next/static/chunks/{44_cj1_i_aa2z.js → 2y4ycwcwfjv4k.js} +1 -1
  105. package/.next/standalone/.next/static/chunks/3-6zhytp6adkk.js +1 -0
  106. package/.next/standalone/.next/static/chunks/{0vanab2g65op_.js → 319c_91le7-h_.js} +1 -1
  107. package/.next/standalone/.next/static/chunks/35m53kix7uaii.js +6 -0
  108. package/.next/standalone/.next/static/chunks/{1so_3s0q4c4j1.js → 35pw7zxhh76n7.js} +1 -1
  109. package/.next/standalone/.next/static/chunks/3xacd7qmuqlvs.js +1 -0
  110. package/.next/standalone/.next/static/chunks/{03n_qjih7-w6q.js → 40-wncjnguy4e.js} +1 -1
  111. package/.next/standalone/hermes-plugin/README.md +6 -1
  112. package/.next/standalone/hermes-plugin/client.py +22 -6
  113. package/.next/standalone/lib/hermes-profiles.ts +67 -19
  114. package/.next/standalone/lib/hermes-sessions.ts +3 -2
  115. package/.next/standalone/package.json +9 -9
  116. package/.next/standalone/server.js +1 -1
  117. package/dist/cli.mjs +380 -266
  118. package/dist/worker.mjs +62 -32
  119. package/hermes-plugin/README.md +6 -1
  120. package/hermes-plugin/client.py +22 -6
  121. package/lib/hermes-profiles.ts +67 -19
  122. package/lib/hermes-sessions.ts +3 -2
  123. package/package.json +9 -9
  124. package/src/hooks/daemon-client.ts +128 -50
  125. package/src/hooks/daemon-service.ts +30 -0
  126. package/src/hooks/integrations.ts +8 -0
  127. package/src/hooks/manager.ts +24 -2
  128. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +0 -3
  129. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +0 -6
  130. package/.next/standalone/.next/static/chunks/1ekh-hj_iom84.js +0 -1
  131. package/.next/standalone/.next/static/chunks/2u0kol_boahtv.js +0 -1
  132. package/.next/standalone/.next/static/chunks/3_vesf83-0903.js +0 -1
  133. package/.next/standalone/.next/static/chunks/3iasus89n8mg1.js +0 -6
  134. /package/.next/standalone/.next/static/{-7OT2NwGPxAu-skEL_Xee → LzR_etPlaZV9JZH09lEp3}/_buildManifest.js +0 -0
  135. /package/.next/standalone/.next/static/{-7OT2NwGPxAu-skEL_Xee → LzR_etPlaZV9JZH09lEp3}/_clientMiddlewareManifest.js +0 -0
  136. /package/.next/standalone/.next/static/{-7OT2NwGPxAu-skEL_Xee → LzR_etPlaZV9JZH09lEp3}/_ssgManifest.js +0 -0
package/dist/worker.mjs CHANGED
@@ -3483,7 +3483,7 @@ function parsePackPolicyName(canonicalName) {
3483
3483
  }
3484
3484
 
3485
3485
  // package.json
3486
- var version = "1.0.6-beta.0";
3486
+ var version = "1.0.6";
3487
3487
  var init_package = () => {};
3488
3488
 
3489
3489
  // src/posthog-key.ts
@@ -6388,36 +6388,66 @@ var init_pi_projects = __esm(() => {
6388
6388
  });
6389
6389
 
6390
6390
  // lib/hermes-profiles.ts
6391
- import { readdirSync as readdirSync3 } from "node:fs";
6391
+ import { existsSync as existsSync9, readdirSync as readdirSync3 } from "node:fs";
6392
6392
  import { homedir as homedir10 } from "node:os";
6393
6393
  import { basename as basename2, dirname as dirname3, join as join11, resolve as resolve8 } from "node:path";
6394
6394
  function hermesRoot() {
6395
6395
  const env = (process.env.HERMES_HOME || "").trim();
6396
6396
  if (env) {
6397
- const home = resolve8(env);
6397
+ let home = resolve8(env);
6398
6398
  const parent = dirname3(home);
6399
6399
  if (basename2(parent) === PROFILES_DIR)
6400
- return dirname3(parent);
6400
+ home = dirname3(parent);
6401
+ const base = basename2(home);
6402
+ if (base === STANDARD_HOME || base.startsWith(SIBLING_HOME_PREFIX)) {
6403
+ return join11(dirname3(home), STANDARD_HOME);
6404
+ }
6401
6405
  return home;
6402
6406
  }
6403
- return join11(homedir10(), ".hermes");
6407
+ return join11(homedir10(), STANDARD_HOME);
6408
+ }
6409
+ function uniqueProfileName(preferred, seen) {
6410
+ if (!seen.has(preferred))
6411
+ return preferred;
6412
+ const base = `${preferred}-home`;
6413
+ if (!seen.has(base))
6414
+ return base;
6415
+ let suffix = 2;
6416
+ while (seen.has(`${base}-${suffix}`))
6417
+ suffix += 1;
6418
+ return `${base}-${suffix}`;
6404
6419
  }
6405
6420
  function listHermesProfiles() {
6406
6421
  const root = hermesRoot();
6407
6422
  const out = [{ name: HERMES_DEFAULT_PROFILE, home: root }];
6408
6423
  const seen = new Set([HERMES_DEFAULT_PROFILE]);
6409
- let names;
6424
+ let names = [];
6410
6425
  try {
6411
6426
  names = readdirSync3(join11(root, PROFILES_DIR), { withFileTypes: true }).filter((e) => (e.isDirectory() || e.isSymbolicLink()) && !e.name.startsWith(".")).map((e) => e.name).sort();
6412
- } catch {
6413
- return out;
6414
- }
6427
+ } catch {}
6415
6428
  for (const name of names) {
6416
6429
  if (seen.has(name))
6417
6430
  continue;
6418
6431
  seen.add(name);
6419
6432
  out.push({ name, home: join11(root, PROFILES_DIR, name) });
6420
6433
  }
6434
+ if (basename2(root) !== STANDARD_HOME)
6435
+ return out;
6436
+ let siblings = [];
6437
+ const parent = dirname3(root);
6438
+ try {
6439
+ siblings = readdirSync3(parent, { withFileTypes: true }).filter((entry) => (entry.isDirectory() || entry.isSymbolicLink()) && entry.name.startsWith(SIBLING_HOME_PREFIX) && entry.name.length > SIBLING_HOME_PREFIX.length && existsSync9(join11(parent, entry.name, "config.yaml"))).map((entry) => ({
6440
+ name: entry.name.slice(SIBLING_HOME_PREFIX.length),
6441
+ home: join11(parent, entry.name)
6442
+ })).sort((a, b) => a.name.localeCompare(b.name));
6443
+ } catch {
6444
+ return out;
6445
+ }
6446
+ for (const sibling of siblings) {
6447
+ const name = uniqueProfileName(sibling.name, seen);
6448
+ seen.add(name);
6449
+ out.push({ name, home: sibling.home });
6450
+ }
6421
6451
  return out;
6422
6452
  }
6423
6453
  function hermesProjectName(profile, source) {
@@ -6443,7 +6473,7 @@ function hermesProjectNameCandidates(name) {
6443
6473
  out.push({ profile: HERMES_DEFAULT_PROFILE, source: rest });
6444
6474
  return out;
6445
6475
  }
6446
- var PROFILES_DIR = "profiles", HERMES_DEFAULT_PROFILE = "default";
6476
+ var PROFILES_DIR = "profiles", STANDARD_HOME = ".hermes", SIBLING_HOME_PREFIX = ".hermes-", HERMES_DEFAULT_PROFILE = "default";
6447
6477
  var init_hermes_profiles = () => {};
6448
6478
 
6449
6479
  // lib/format-duration.ts
@@ -6765,7 +6795,7 @@ var init_hermes_projects = __esm(() => {
6765
6795
  });
6766
6796
 
6767
6797
  // lib/openclaw-db.ts
6768
- import { existsSync as existsSync9 } from "node:fs";
6798
+ import { existsSync as existsSync10 } from "node:fs";
6769
6799
  import { join as join13 } from "node:path";
6770
6800
  function str(value) {
6771
6801
  return typeof value === "string" && value.length > 0 ? value : undefined;
@@ -6785,7 +6815,7 @@ function listOpenClawDatabases(home, agentIds) {
6785
6815
  const out = [];
6786
6816
  for (const agentId of agentIds) {
6787
6817
  const dbPath = join13(home, "agents", agentId, "agent", DB_NAME);
6788
- if (existsSync9(dbPath))
6818
+ if (existsSync10(dbPath))
6789
6819
  out.push({ agentId, dbPath });
6790
6820
  }
6791
6821
  return out;
@@ -8962,13 +8992,13 @@ var init_log_entries = __esm(() => {
8962
8992
  });
8963
8993
 
8964
8994
  // lib/codex-sessions.ts
8965
- import { readFileSync as readFileSync8, readdirSync as readdirSync7, existsSync as existsSync10, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, statSync as statSync10 } from "node:fs";
8995
+ import { readFileSync as readFileSync8, readdirSync as readdirSync7, existsSync as existsSync11, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, statSync as statSync10 } from "node:fs";
8966
8996
  import { readFile as readFile11 } from "node:fs/promises";
8967
8997
  import { dirname as dirname4, join as join24 } from "node:path";
8968
8998
  import { homedir as homedir16 } from "node:os";
8969
8999
  function readCache() {
8970
9000
  try {
8971
- if (!existsSync10(CACHE_PATH))
9001
+ if (!existsSync11(CACHE_PATH))
8972
9002
  return {};
8973
9003
  return JSON.parse(readFileSync8(CACHE_PATH, "utf-8"));
8974
9004
  } catch {
@@ -8996,7 +9026,7 @@ function dirSearch(dir, sessionId) {
8996
9026
  function findCodexTranscript(sessionId) {
8997
9027
  const cache = readCache();
8998
9028
  const cached = cache[sessionId];
8999
- if (cached && existsSync10(cached))
9029
+ if (cached && existsSync11(cached))
9000
9030
  return cached;
9001
9031
  const root = join24(homedir16(), ".codex", "sessions");
9002
9032
  const today = new Date;
@@ -9290,7 +9320,7 @@ var init_resolve_permission_mode = __esm(() => {
9290
9320
  });
9291
9321
 
9292
9322
  // lib/copilot-sessions.ts
9293
- import { readFileSync as readFileSync10, readdirSync as readdirSync8, existsSync as existsSync11, statSync as statSync11 } from "node:fs";
9323
+ import { readFileSync as readFileSync10, readdirSync as readdirSync8, existsSync as existsSync12, statSync as statSync11 } from "node:fs";
9294
9324
  import { readFile as readFile12 } from "node:fs/promises";
9295
9325
  import { join as join25, resolve as resolve10, sep as sep2 } from "node:path";
9296
9326
  import { homedir as homedir17 } from "node:os";
@@ -9319,13 +9349,13 @@ function findCopilotTranscript(sessionId) {
9319
9349
  const candidate = resolveSessionFile(sessionId, "events.jsonl");
9320
9350
  if (!candidate)
9321
9351
  return null;
9322
- return existsSync11(candidate) ? candidate : null;
9352
+ return existsSync12(candidate) ? candidate : null;
9323
9353
  }
9324
9354
  function findCopilotWorkspace(sessionId) {
9325
9355
  const candidate = resolveSessionFile(sessionId, "workspace.yaml");
9326
9356
  if (!candidate)
9327
9357
  return null;
9328
- return existsSync11(candidate) ? candidate : null;
9358
+ return existsSync12(candidate) ? candidate : null;
9329
9359
  }
9330
9360
  function readYamlScalar(path, key) {
9331
9361
  try {
@@ -9507,7 +9537,7 @@ var init_copilot_sessions = __esm(() => {
9507
9537
  });
9508
9538
 
9509
9539
  // lib/cursor-sessions.ts
9510
- import { readFileSync as readFileSync11, readdirSync as readdirSync9, existsSync as existsSync12, statSync as statSync12 } from "node:fs";
9540
+ import { readFileSync as readFileSync11, readdirSync as readdirSync9, existsSync as existsSync13, statSync as statSync12 } from "node:fs";
9511
9541
  import { readFile as readFile13 } from "node:fs/promises";
9512
9542
  import { basename as basename3, join as join26, resolve as resolve11, sep as sep3 } from "node:path";
9513
9543
  import { homedir as homedir18 } from "node:os";
@@ -9530,7 +9560,7 @@ function getCursorSessionDir(sessionId) {
9530
9560
  const transcriptRoot = resolve11(projectsRoot, entry.name, NEW_AGENT_TRANSCRIPTS_DIR2);
9531
9561
  if (candidate === transcriptRoot || !candidate.startsWith(`${transcriptRoot}${sep3}`))
9532
9562
  continue;
9533
- if (existsSync12(candidate))
9563
+ if (existsSync13(candidate))
9534
9564
  return candidate;
9535
9565
  }
9536
9566
  for (const sub of LEGACY_SESSION_ROOT_CANDIDATES2) {
@@ -9538,7 +9568,7 @@ function getCursorSessionDir(sessionId) {
9538
9568
  const candidate = resolve11(root, sessionId);
9539
9569
  if (candidate === root || !candidate.startsWith(`${root}${sep3}`))
9540
9570
  continue;
9541
- if (existsSync12(candidate))
9571
+ if (existsSync13(candidate))
9542
9572
  return candidate;
9543
9573
  }
9544
9574
  return null;
@@ -9548,11 +9578,11 @@ function findCursorTranscript(sessionId) {
9548
9578
  if (!dir)
9549
9579
  return null;
9550
9580
  const newCandidate = join26(dir, `${basename3(dir)}.jsonl`);
9551
- if (existsSync12(newCandidate))
9581
+ if (existsSync13(newCandidate))
9552
9582
  return newCandidate;
9553
9583
  for (const name of LEGACY_TRANSCRIPT_FILE_CANDIDATES2) {
9554
9584
  const candidate = join26(dir, name);
9555
- if (existsSync12(candidate))
9585
+ if (existsSync13(candidate))
9556
9586
  return candidate;
9557
9587
  }
9558
9588
  return null;
@@ -9763,7 +9793,7 @@ var init_cursor_sessions = __esm(() => {
9763
9793
  });
9764
9794
 
9765
9795
  // lib/pi-sessions.ts
9766
- import { readFileSync as readFileSync12, readdirSync as readdirSync10, existsSync as existsSync13, statSync as statSync13 } from "node:fs";
9796
+ import { readFileSync as readFileSync12, readdirSync as readdirSync10, existsSync as existsSync14, statSync as statSync13 } from "node:fs";
9767
9797
  import { readFile as readFile14 } from "node:fs/promises";
9768
9798
  import { join as join27, resolve as resolve12, sep as sep4 } from "node:path";
9769
9799
  import { homedir as homedir19 } from "node:os";
@@ -9800,7 +9830,7 @@ function findPiTranscript(sessionId) {
9800
9830
  const candidate = resolve12(cwdPath, f);
9801
9831
  if (!candidate.startsWith(`${cwdPath}${sep4}`))
9802
9832
  continue;
9803
- if (existsSync13(candidate))
9833
+ if (existsSync14(candidate))
9804
9834
  return candidate;
9805
9835
  }
9806
9836
  }
@@ -10160,7 +10190,7 @@ var init_pack_failclosed = __esm(() => {
10160
10190
  var init_atomic_write = () => {};
10161
10191
 
10162
10192
  // src/hooks/session-pause.ts
10163
- import { existsSync as existsSync14, mkdirSync as mkdirSync6, readdirSync as readdirSync11, readFileSync as readFileSync13, rmSync as rmSync2 } from "node:fs";
10193
+ import { existsSync as existsSync15, mkdirSync as mkdirSync6, readdirSync as readdirSync11, readFileSync as readFileSync13, rmSync as rmSync2 } from "node:fs";
10164
10194
  import { createHash as createHash5 } from "node:crypto";
10165
10195
  import { join as join28, resolve as resolve13 } from "node:path";
10166
10196
  function pauseStateDir() {
@@ -10200,7 +10230,7 @@ function readActivePause(sessionId, now = Date.now()) {
10200
10230
  return null;
10201
10231
  try {
10202
10232
  const path = pauseFilePath(sessionId);
10203
- if (!existsSync14(path))
10233
+ if (!existsSync15(path))
10204
10234
  return null;
10205
10235
  const stored = parseStored(JSON.parse(readFileSync13(path, "utf8")));
10206
10236
  if (!stored)
@@ -10241,7 +10271,7 @@ var init_daemon_service = __esm(() => {
10241
10271
  // src/hooks/fp-reset.ts
10242
10272
  import {
10243
10273
  copyFileSync,
10244
- existsSync as existsSync15,
10274
+ existsSync as existsSync16,
10245
10275
  mkdirSync as mkdirSync7,
10246
10276
  readFileSync as readFileSync14,
10247
10277
  readdirSync as readdirSync12,
@@ -10258,7 +10288,7 @@ function layoutWarningForHook() {
10258
10288
  if (state.kind === "future") {
10259
10289
  return `[failproofai] this directory was written by a newer version (layout ${state.found} vs ${LAYOUT_VERSION}) — policies are NOT being enforced. ` + `Upgrade failproofai.`;
10260
10290
  }
10261
- if (existsSync15(globalPolicyConfigFile()))
10291
+ if (existsSync16(globalPolicyConfigFile()))
10262
10292
  return null;
10263
10293
  return `[failproofai] setup predates this version — global policies are NOT being enforced. ` + `Run \`failproofai config\` to re-create it.`;
10264
10294
  }
@@ -10648,7 +10678,7 @@ var init_handler = __esm(() => {
10648
10678
 
10649
10679
  // src/hooks/worker-server.ts
10650
10680
  import { createConnection, createServer } from "node:net";
10651
- import { existsSync as existsSync16, unlinkSync as unlinkSync2 } from "node:fs";
10681
+ import { existsSync as existsSync17, unlinkSync as unlinkSync2 } from "node:fs";
10652
10682
  function isWorkerHookRequest(msg) {
10653
10683
  if (!msg || typeof msg !== "object")
10654
10684
  return false;
@@ -10782,14 +10812,14 @@ function requestExistingWorkerShutdown(socketPath) {
10782
10812
  function startWorkerServer(socketPath, shutdown) {
10783
10813
  const server = createServer((socket) => handleConnection(socket, shutdown ?? (() => server.close())));
10784
10814
  const listen = () => {
10785
- if (existsSync16(socketPath)) {
10815
+ if (existsSync17(socketPath)) {
10786
10816
  try {
10787
10817
  unlinkSync2(socketPath);
10788
10818
  } catch {}
10789
10819
  }
10790
10820
  server.listen(socketPath);
10791
10821
  };
10792
- if (!existsSync16(socketPath))
10822
+ if (!existsSync17(socketPath))
10793
10823
  listen();
10794
10824
  else
10795
10825
  requestExistingWorkerShutdown(socketPath).then(listen, (err) => server.emit("error", err));
@@ -10,7 +10,12 @@ manifest v2 fields, `PluginContext` methods/state, and keyword hook payloads.
10
10
 
11
11
  ## Installation
12
12
 
13
- Run:
13
+ Hermes policy evaluation requires a configured, healthy local `failproofaid`
14
+ daemon. If this machine has not been configured yet, run `failproofai config`
15
+ first. The standalone installer refuses to enable the fail-closed plugin until
16
+ the daemon answers an end-to-end health probe.
17
+
18
+ Then run:
14
19
 
15
20
  ```bash
16
21
  failproofai policies --install --cli hermes --scope user
@@ -6,6 +6,7 @@ import json
6
6
  import os
7
7
  import socket
8
8
  import struct
9
+ import time
9
10
  from dataclasses import dataclass
10
11
  from pathlib import Path
11
12
  from typing import Any, Mapping, Sequence
@@ -38,11 +39,22 @@ def daemon_socket_path() -> Path:
38
39
  return home / "run" / "failproofaid.sock"
39
40
 
40
41
 
41
- def _read_exact(sock: socket.socket, length: int) -> bytes:
42
+ def _remaining_timeout(deadline: float) -> float:
43
+ remaining = deadline - time.monotonic()
44
+ if remaining <= 0:
45
+ raise EvaluationError("failproofaid evaluation timed out")
46
+ return remaining
47
+
48
+
49
+ def _read_exact(sock: socket.socket, length: int, deadline: float) -> bytes:
42
50
  chunks: list[bytes] = []
43
51
  remaining = length
44
52
  while remaining:
45
- chunk = sock.recv(remaining)
53
+ sock.settimeout(_remaining_timeout(deadline))
54
+ try:
55
+ chunk = sock.recv(remaining)
56
+ except TimeoutError as exc:
57
+ raise EvaluationError("failproofaid evaluation timed out") from exc
46
58
  if not chunk:
47
59
  raise EvaluationError("failproofaid closed the connection before returning a verdict")
48
60
  chunks.append(chunk)
@@ -90,12 +102,16 @@ def evaluate_policy(
90
102
  with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock:
91
103
  sock.settimeout(max(connect_timeout_ms, 1) / 1000)
92
104
  sock.connect(str(daemon_socket_path()))
93
- sock.settimeout(max(evaluation_timeout_ms, 1) / 1000)
94
- sock.sendall(struct.pack(">I", len(body)) + body)
95
- declared_length = struct.unpack(">I", _read_exact(sock, 4))[0]
105
+ deadline = time.monotonic() + max(evaluation_timeout_ms, 1) / 1000
106
+ sock.settimeout(_remaining_timeout(deadline))
107
+ try:
108
+ sock.sendall(struct.pack(">I", len(body)) + body)
109
+ except TimeoutError as exc:
110
+ raise EvaluationError("failproofaid evaluation timed out") from exc
111
+ declared_length = struct.unpack(">I", _read_exact(sock, 4, deadline))[0]
96
112
  if declared_length > MAX_FRAME_BYTES:
97
113
  raise EvaluationError("failproofaid response exceeds the 16 MiB limit")
98
- response = json.loads(_read_exact(sock, declared_length).decode("utf-8"))
114
+ response = json.loads(_read_exact(sock, declared_length, deadline).decode("utf-8"))
99
115
  except EvaluationError:
100
116
  raise
101
117
  except (OSError, UnicodeError, ValueError, struct.error) as exc:
@@ -3,10 +3,11 @@
3
3
  *
4
4
  * A Hermes "profile" is not a column or a flag: it is a whole separate Hermes
5
5
  * home directory, each with its own `config.yaml`, `.env`, `SOUL.md`, and
6
- * `state.db`. The default profile lives at `~/.hermes`; every other profile at
7
- * `~/.hermes/profiles/<name>/`. Selection is `hermes -p <name>`, a generated
8
- * `~/.local/bin/<name>` alias that exports `HERMES_HOME`, or a sticky default
9
- * recorded in `<root>/active_profile`.
6
+ * `state.db`. The default profile lives at `~/.hermes`; upstream named profiles
7
+ * live at `~/.hermes/profiles/<name>/`, while older/custom multi-install setups
8
+ * may use sibling homes such as `~/.hermes-work`. Selection is `hermes -p
9
+ * <name>`, a generated `~/.local/bin/<name>` alias that exports `HERMES_HOME`,
10
+ * or a sticky default recorded in `<root>/active_profile`.
10
11
  *
11
12
  * Upstream's own contributor guide warns that hardcoding `~/.hermes` breaks
12
13
  * profiles — which is exactly what both pillars used to do:
@@ -21,12 +22,14 @@
21
22
  * Home override: set `HERMES_HOME` (Hermes's own env var — respected here so a
22
23
  * profile-scoped shell and failproofai agree on what "all profiles" means).
23
24
  */
24
- import { readdirSync } from "node:fs";
25
+ import { existsSync, readdirSync } from "node:fs";
25
26
  import { homedir } from "node:os";
26
27
  import { basename, dirname, join, resolve } from "node:path";
27
28
 
28
29
  /** Directory under the Hermes root that holds non-default profiles. */
29
30
  const PROFILES_DIR = "profiles";
31
+ const STANDARD_HOME = ".hermes";
32
+ const SIBLING_HOME_PREFIX = ".hermes-";
30
33
 
31
34
  /** Name we give the root home (`~/.hermes`), which Hermes itself leaves unnamed. */
32
35
  export const HERMES_DEFAULT_PROFILE = "default";
@@ -41,28 +44,45 @@ export interface HermesProfile {
41
44
  /**
42
45
  * The Hermes ROOT home — the directory that owns `profiles/`.
43
46
  *
44
- * `HERMES_HOME` may point AT a profile (`<root>/profiles/<name>`), because
45
- * that's what the per-profile alias wrapper exports. We climb back to `<root>`
46
- * in that case so discovery still sees every sibling profile — mirroring what
47
- * upstream does so `profile list` can see them all.
47
+ * `HERMES_HOME` may point AT an upstream profile (`<root>/profiles/<name>`) or
48
+ * at a sibling installation (`~/.hermes-<name>`). We normalize either standard
49
+ * layout back to `~/.hermes` so discovery covers every installation. A custom
50
+ * non-standard path remains authoritative; scanning arbitrary sibling paths
51
+ * would risk treating backups and unrelated directories as live agents.
48
52
  */
49
53
  export function hermesRoot(): string {
50
54
  const env = (process.env.HERMES_HOME || "").trim();
51
55
  if (env) {
52
- const home = resolve(env);
56
+ let home = resolve(env);
53
57
  const parent = dirname(home);
54
- if (basename(parent) === PROFILES_DIR) return dirname(parent);
58
+ if (basename(parent) === PROFILES_DIR) home = dirname(parent);
59
+ const base = basename(home);
60
+ if (base === STANDARD_HOME || base.startsWith(SIBLING_HOME_PREFIX)) {
61
+ return join(dirname(home), STANDARD_HOME);
62
+ }
55
63
  return home;
56
64
  }
57
- return join(homedir(), ".hermes");
65
+ return join(homedir(), STANDARD_HOME);
66
+ }
67
+
68
+ function uniqueProfileName(preferred: string, seen: Set<string>): string {
69
+ if (!seen.has(preferred)) return preferred;
70
+ const base = `${preferred}-home`;
71
+ if (!seen.has(base)) return base;
72
+ let suffix = 2;
73
+ while (seen.has(`${base}-${suffix}`)) suffix += 1;
74
+ return `${base}-${suffix}`;
58
75
  }
59
76
 
60
77
  /**
61
78
  * Every Hermes profile on disk: the root home first (as `"default"`), then each
62
- * `<root>/profiles/<name>/` in name order.
79
+ * `<root>/profiles/<name>/`, then valid `~/.hermes-<name>` sibling homes, in
80
+ * name order within each layout.
63
81
  *
64
- * Fail-open a missing or unreadable `profiles/` dir just means "default only",
65
- * which is the single-profile install everyone starts with.
82
+ * A sibling home counts only when it contains `config.yaml`, matching OpenClaw
83
+ * discovery and avoiding arbitrary `.hermes-*` backup directories. Upstream
84
+ * `profiles/` directories are authoritative and remain discoverable before
85
+ * their config is first written.
66
86
  *
67
87
  * A profile directory literally named `default` would collide with the root's
68
88
  * reserved name; the root wins and the directory is skipped (dedup by name keeps
@@ -73,22 +93,50 @@ export function listHermesProfiles(): HermesProfile[] {
73
93
  const out: HermesProfile[] = [{ name: HERMES_DEFAULT_PROFILE, home: root }];
74
94
  const seen = new Set<string>([HERMES_DEFAULT_PROFILE]);
75
95
 
76
- let names: string[];
96
+ let names: string[] = [];
77
97
  try {
78
98
  names = readdirSync(join(root, PROFILES_DIR), { withFileTypes: true })
79
99
  // Symlinked profile dirs are legitimate, and `isDirectory()` is false for them.
80
100
  .filter((e) => (e.isDirectory() || e.isSymbolicLink()) && !e.name.startsWith("."))
81
101
  .map((e) => e.name)
82
102
  .sort();
83
- } catch {
84
- return out;
85
- }
103
+ } catch {}
86
104
 
87
105
  for (const name of names) {
88
106
  if (seen.has(name)) continue;
89
107
  seen.add(name);
90
108
  out.push({ name, home: join(root, PROFILES_DIR, name) });
91
109
  }
110
+
111
+ // Only the standard ~/.hermes layout defines `.hermes-*` sibling homes.
112
+ // A custom HERMES_HOME is intentionally not used as a prefix convention.
113
+ if (basename(root) !== STANDARD_HOME) return out;
114
+
115
+ let siblings: HermesProfile[] = [];
116
+ const parent = dirname(root);
117
+ try {
118
+ siblings = readdirSync(parent, { withFileTypes: true })
119
+ .filter(
120
+ (entry) =>
121
+ (entry.isDirectory() || entry.isSymbolicLink()) &&
122
+ entry.name.startsWith(SIBLING_HOME_PREFIX) &&
123
+ entry.name.length > SIBLING_HOME_PREFIX.length &&
124
+ existsSync(join(parent, entry.name, "config.yaml")),
125
+ )
126
+ .map((entry) => ({
127
+ name: entry.name.slice(SIBLING_HOME_PREFIX.length),
128
+ home: join(parent, entry.name),
129
+ }))
130
+ .sort((a, b) => a.name.localeCompare(b.name));
131
+ } catch {
132
+ return out;
133
+ }
134
+
135
+ for (const sibling of siblings) {
136
+ const name = uniqueProfileName(sibling.name, seen);
137
+ seen.add(name);
138
+ out.push({ name, home: sibling.home });
139
+ }
92
140
  return out;
93
141
  }
94
142
 
@@ -14,8 +14,9 @@
14
14
  *
15
15
  * PROFILES: Hermes profiles are separate home dirs, each with its OWN state.db
16
16
  * (`~/.hermes/state.db` for the default, `~/.hermes/profiles/<name>/state.db`
17
- * otherwise) see lib/hermes-profiles.ts. So every read here fans out across
18
- * profiles instead of assuming one DB.
17
+ * for upstream profiles, and `~/.hermes-<name>/state.db` for sibling homes)
18
+ * see lib/hermes-profiles.ts. So every read here fans out across profiles
19
+ * instead of assuming one DB.
19
20
  *
20
21
  * DB path override: set `HERMES_DB_PATH` (used by tests and to point at a copied
21
22
  * or remote state.db) — it collapses discovery to that single file. Set
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "failproofai",
3
- "version": "1.0.6-beta.0",
3
+ "version": "1.0.6",
4
4
  "description": "Observability and enforcement for AI agent harnesses. 39 built-in policies hooked into 12 of them — Claude Code, Codex, Cursor, Hermes, OpenClaw and more — blocking the tool call before it runs. Local dashboard included, no account needed.",
5
5
  "bin": {
6
6
  "failproofai": "./dist/cli.mjs",
@@ -122,15 +122,15 @@
122
122
  "browserslist": "4.28.8"
123
123
  },
124
124
  "optionalDependencies": {
125
- "@failproofai/failproofaid-linux-x64": "1.0.6-beta.0",
126
- "@failproofai/failproofaid-linux-arm64": "1.0.6-beta.0",
127
- "@failproofai/failproofaid-darwin-x64": "1.0.6-beta.0",
128
- "@failproofai/failproofaid-darwin-arm64": "1.0.6-beta.0"
125
+ "@failproofai/failproofaid-linux-x64": "1.0.6",
126
+ "@failproofai/failproofaid-linux-arm64": "1.0.6",
127
+ "@failproofai/failproofaid-darwin-x64": "1.0.6",
128
+ "@failproofai/failproofaid-darwin-arm64": "1.0.6"
129
129
  },
130
130
  "failproofaidBinaries": {
131
- "linux-x64": "38637a91db9a0e5683bbfbfffbba3d65e421960c3135510f23541df5f9d60478",
132
- "linux-arm64": "b9a2d9126fb9816b7743ec5b068d36d6515fa3a93fc2e3801fbe3a7a1b2143bf",
133
- "darwin-x64": "a06675cd28b3d2f54d45a28f527643841a69006dd68f989dad654806b190948b",
134
- "darwin-arm64": "6ef65b956ebff944c38cf2d65b6dc1066384aba7952d7d19c4805c1f1ba593ba"
131
+ "linux-x64": "e075f24a3a0950b631979d9370b665da2c3e2920decfb917ff0831d1f17c9740",
132
+ "linux-arm64": "b90ce8c642f2685719f4915695615219860daf3155a9c07344cf1e10395028c3",
133
+ "darwin-x64": "51dd95e9b85226e4f1888c7edaa56ec4464e91eb645d39c5cb7cede16d2da2f1",
134
+ "darwin-arm64": "f6a1b9d63363e8805e0d72b4fa168fde661bdbbd4125b54047f7de8948ea0f39"
135
135
  }
136
136
  }