failproofai 1.0.0-beta.12 → 1.0.0-beta.13

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 (173) 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 +2 -3
  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 +2 -2
  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/_head.segment.rsc +3 -3
  14. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  15. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page.js +2 -3
  18. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  20. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  21. package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
  22. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
  23. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  24. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
  25. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  26. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  27. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  28. package/.next/standalone/.next/server/app/api/audit/invite/route.js +2 -2
  29. package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/audit/run/route.js +2 -2
  31. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/auth/login-request/route.js +3 -2
  34. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +2 -2
  36. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  37. package/.next/standalone/.next/server/app/api/auth/logout/route.js +2 -2
  38. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/api/auth/reminder/route.js +2 -2
  40. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
  41. package/.next/standalone/.next/server/app/api/auth/status/route.js +2 -2
  42. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  44. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  45. package/.next/standalone/.next/server/app/audit/page.js +2 -3
  46. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  48. package/.next/standalone/.next/server/app/index.html +1 -1
  49. package/.next/standalone/.next/server/app/index.rsc +15 -15
  50. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  51. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  52. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  53. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  54. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  55. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  56. package/.next/standalone/.next/server/app/page.js +2 -3
  57. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  58. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  59. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +10 -10
  60. package/.next/standalone/.next/server/app/policies/page.js +2 -3
  61. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  62. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  63. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  64. package/.next/standalone/.next/server/app/project/[name]/page.js +3 -4
  65. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  66. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  67. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  68. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  69. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +3 -4
  70. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  71. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  72. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  73. package/.next/standalone/.next/server/app/projects/page.js +3 -4
  74. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  75. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  76. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
  77. package/.next/standalone/.next/server/app/settings/page.js +2 -3
  78. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  79. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  80. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1a7i2q4._.js → [root-of-the-server]__00ni9za._.js} +1 -1
  81. package/.next/standalone/.next/server/chunks/[root-of-the-server]__08y94xv._.js +3 -0
  82. package/.next/standalone/.next/server/chunks/[root-of-the-server]__094p1f1._.js +1 -1
  83. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
  84. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ed01_d._.js +1 -1
  85. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1_ps0jw._.js → [root-of-the-server]__0effm9m._.js} +1 -1
  86. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0lk_935._.js → [root-of-the-server]__0ix8gm7._.js} +1 -1
  87. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0ky_n0r._.js → [root-of-the-server]__0ji11a-._.js} +1 -1
  88. package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0v2fpxe._.js → [root-of-the-server]__0ojwjxl._.js} +1 -1
  89. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0vb5fl2._.js +3 -0
  90. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ibjy5x._.js +1 -1
  91. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tvn4wf._.js +1 -1
  92. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1uyc-z4._.js +3 -0
  93. package/.next/standalone/.next/server/chunks/[root-of-the-server]__20d06rh._.js +3 -0
  94. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +1 -3
  95. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +1 -3
  96. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  97. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1rdruw4._.js → [root-of-the-server]__0_1tiya._.js} +1 -1
  98. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ha3gul._.js → [root-of-the-server]__0eeipso._.js} +2 -2
  99. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0spkm68._.js +3 -3
  100. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1tyf0tc._.js → [root-of-the-server]__17itmx-._.js} +2 -2
  101. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1io8n-9._.js → [root-of-the-server]__1dx-a-c._.js} +2 -2
  102. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1mmefsr._.js +5 -0
  103. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1yw368c._.js → [root-of-the-server]__1n2vcv4._.js} +1 -1
  104. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1rv-sc9._.js +1 -1
  105. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1a2hcb_._.js → [root-of-the-server]__1tlvv9a._.js} +1 -1
  106. package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +1 -1
  107. package/.next/standalone/.next/server/chunks/ssr/{_1fahg9e._.js → _0vo2qyt._.js} +2 -2
  108. package/.next/standalone/.next/server/chunks/ssr/{_0uz7o9y._.js → _0xej-0e._.js} +2 -2
  109. package/.next/standalone/.next/server/chunks/ssr/{_04mekdy._.js → _10399ge._.js} +2 -2
  110. package/.next/standalone/.next/server/chunks/ssr/{_0se484m._.js → _149k9oy._.js} +2 -2
  111. package/.next/standalone/.next/server/chunks/ssr/{_1vsgpqt._.js → _166jvu8._.js} +1 -1
  112. package/.next/standalone/.next/server/chunks/ssr/{_0r-dsre._.js → _1_hwp06._.js} +2 -2
  113. package/.next/standalone/.next/server/chunks/ssr/{_1w8sola._.js → _1mnhi_r._.js} +2 -2
  114. package/.next/standalone/.next/server/chunks/ssr/{_1w_6p9g._.js → _1ror7k9._.js} +2 -2
  115. package/.next/standalone/.next/server/chunks/ssr/{_1gmzkwj._.js → _1sdgprl._.js} +1 -1
  116. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  117. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  118. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  119. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  120. package/.next/standalone/.next/server/pages/404.html +1 -1
  121. package/.next/standalone/.next/server/pages/500.html +1 -1
  122. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  123. package/.next/standalone/.next/server/server-reference-manifest.json +15 -15
  124. package/.next/standalone/.next/static/chunks/{2_h--2ame3r83.js → 01s3vpzky_qew.js} +1 -1
  125. package/.next/standalone/.next/static/chunks/0km-jn9o5xyqs.css +2 -0
  126. package/.next/standalone/.next/static/chunks/{23hp7hekegpe5.js → 0zbcd_n8ku2ov.js} +1 -1
  127. package/.next/standalone/.next/static/chunks/{0cakk77ppmlo7.js → 1erji0ratofla.js} +1 -1
  128. package/.next/standalone/.next/static/chunks/{40-zk44qsg5y-.js → 23hnlzqx44vbe.js} +1 -1
  129. package/.next/standalone/.next/static/chunks/{1wb8cnmzx69rz.js → 2cwsiyhc7d2cw.js} +1 -1
  130. package/.next/standalone/.next/static/chunks/{0_rdbv_k5j51p.js → 2y42ebzynyxdv.js} +1 -1
  131. package/.next/standalone/.next/static/chunks/{1spk1bub0vd-h.js → 315lncj7dsp9c.js} +1 -1
  132. package/.next/standalone/.next/static/chunks/{0-zh1umoq6ppc.js → 31_px0dfgdg9j.js} +2 -2
  133. package/.next/standalone/.next/static/chunks/{2bie7ajv70p9b.js → 3l4-fu3xt75j8.js} +1 -1
  134. package/.next/standalone/.next/static/chunks/{298v78ypf8edl.js → 3poscoxn69x9g.js} +1 -1
  135. package/.next/standalone/app/policies/hooks-client.tsx +4 -4
  136. package/.next/standalone/ino.ujh3/.failproofai/VERSION +4 -0
  137. package/.next/standalone/ino.ujh3/.failproofai/state/last-version +1 -0
  138. package/.next/standalone/ino.ujh3/.failproofai/state/telemetry-id +1 -0
  139. package/.next/standalone/package.json +10 -10
  140. package/.next/standalone/server.js +1 -1
  141. package/bin/failproofai.mjs +186 -5
  142. package/dist/cli.mjs +1130 -1352
  143. package/dist/worker.mjs +107 -1000
  144. package/package.json +10 -10
  145. package/src/hooks/backfill-cli.ts +1 -1
  146. package/src/hooks/cloud-connection.ts +4 -4
  147. package/src/hooks/cloud-enrollment-cli.ts +1 -1
  148. package/src/hooks/cloud-enrollment.ts +3 -3
  149. package/src/hooks/cloud-managed-policies.ts +60 -22
  150. package/src/hooks/configure-wizard.ts +124 -53
  151. package/src/hooks/custom-hooks-loader.ts +57 -8
  152. package/src/hooks/daemon-service.ts +66 -11
  153. package/src/hooks/flush-cli.ts +180 -0
  154. package/src/hooks/fp-config.ts +242 -118
  155. package/src/hooks/fp-home.ts +138 -22
  156. package/src/hooks/fp-reset.ts +357 -43
  157. package/src/hooks/handler.ts +11 -11
  158. package/src/hooks/harness-cli.ts +309 -0
  159. package/src/hooks/hook-activity-store.ts +5 -5
  160. package/src/hooks/manager.ts +35 -0
  161. package/src/hooks/onboarding-attempt.ts +22 -6
  162. package/src/hooks/tui.ts +64 -7
  163. package/src/hooks/uninstall-cli.ts +1 -1
  164. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06hexd0._.js +0 -3
  165. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1iny24d._.js +0 -3
  166. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tyedjt._.js +0 -3
  167. package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +0 -5
  168. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u-wx42._.js +0 -4
  169. package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +0 -5
  170. package/.next/standalone/.next/static/chunks/13vrxdsdihqd_.css +0 -2
  171. /package/.next/standalone/.next/static/{-3gDrXYxNRTVwrFnqXAWd → ziAsXfNE0cH_S7LHK-Py3}/_buildManifest.js +0 -0
  172. /package/.next/standalone/.next/static/{-3gDrXYxNRTVwrFnqXAWd → ziAsXfNE0cH_S7LHK-Py3}/_clientMiddlewareManifest.js +0 -0
  173. /package/.next/standalone/.next/static/{-3gDrXYxNRTVwrFnqXAWd → ziAsXfNE0cH_S7LHK-Py3}/_ssgManifest.js +0 -0
@@ -271,7 +271,7 @@ if (hookIdx >= 0) {
271
271
  */
272
272
  async function runCli() {
273
273
  // --help / -h (only when not inside a subcommand that handles its own --help)
274
- const SUBCOMMANDS = ["policies", "policy", "audit", "config", "uninstall", "backfill"];
274
+ const SUBCOMMANDS = ["policies", "policy", "audit", "config", "uninstall", "backfill", "flush", "harness"];
275
275
  if ((args.includes("--help") || args.includes("-h")) && !SUBCOMMANDS.includes(args[0])) {
276
276
  const extraArgs = args.filter((a) => a !== "--help" && a !== "-h");
277
277
  if (extraArgs.length > 0) {
@@ -286,6 +286,13 @@ USAGE
286
286
  COMMANDS
287
287
  (no args) Launch the policy dashboard
288
288
  config Interactive setup — pick scope, agents & policies
289
+ --connect <url> --token <key> Connect to Failproof Cloud non-interactively
290
+ --machine-id <id> Stable id for this machine
291
+ --machine-label <name> Human-readable name in the dashboard
292
+ --no-transcripts Report decisions only, never transcripts
293
+ --disconnect Stop pulling policy and sending activity
294
+ --status Show connection, daemon and pause state
295
+ --pause / --resume Pause or resume enforcement
289
296
 
290
297
  policy add <name> Enable a single policy (see \`policy --help\`)
291
298
  policy remove <name> Disable a single policy
@@ -312,10 +319,30 @@ COMMANDS
312
319
 
313
320
  policies --help, -h Show this help for the policies command
314
321
 
322
+ harness list Show extra capture paths per agent CLI
323
+ harness add-path <h> <path> Also capture sessions from <path> for harness
324
+ <h>. Accepts \`<label>=<path>\`; the label
325
+ namespaces agent ids so two copies of one
326
+ project stay distinct.
327
+ harness remove-path <h> <p> Stop capturing that path
328
+ harness --help, -h Show this help for the harness command
329
+
315
330
  audit Audit your agent's behavior, then open the
316
331
  dashboard at http://localhost:8020/audit
317
332
  audit --help, -h Show this help for the audit command
318
333
 
334
+ backfill Re-send history the collector already read past
335
+ — after clearing the dashboard, re-enrolling a
336
+ machine, or connecting later than the work
337
+ --since <when> How far back: 30d, 6m, or YYYY-MM-DD
338
+ (default: 30 days)
339
+ --dry-run Report what would be re-read, change nothing
340
+
341
+ flush Deliver everything already spooled, now,
342
+ instead of waiting for the next sweep
343
+ --wait Block until the spool drains (or --timeout)
344
+ --timeout <secs> How long to wait with --wait (default: 60)
345
+
319
346
  uninstall Remove failproofai from this machine: hook
320
347
  entries from every agent CLI, and the daemon
321
348
  service. Run this BEFORE \`npm rm -g failproofai\`
@@ -355,6 +382,10 @@ EXAMPLES
355
382
  failproofai policies --uninstall --cli opencode
356
383
  failproofai policies --uninstall --cli pi
357
384
  failproofai policies --uninstall --custom
385
+ failproofai backfill --since 6m
386
+ failproofai backfill --dry-run
387
+ failproofai flush --wait
388
+ failproofai config --status
358
389
 
359
390
  LINKS
360
391
  ⭐ Star us: https://github.com/failproofai/failproofai
@@ -419,8 +450,12 @@ LINKS
419
450
  const isHelpOrVersion =
420
451
  args.includes("--help") || args.includes("-h") || args.includes("--version") || args.includes("-v");
421
452
  if (args[0] === "audit" && args.includes("--scheduled")) {
422
- const { layoutWarningForHook } = await import("../src/hooks/fp-reset");
423
- const warning = layoutWarningForHook();
453
+ // NOT `layoutWarningForHook` — that one answers the hook's question
454
+ // ("are policies unenforced?") and deliberately stays quiet when the
455
+ // global config is readable. This gate is about the LAYOUT, and must
456
+ // fire whenever completing the run would reset the home.
457
+ const { layoutBlockerForScheduledRun } = await import("../src/hooks/fp-reset");
458
+ const warning = layoutBlockerForScheduledRun();
424
459
  if (warning) {
425
460
  // Exit 1, not 75: 75 means "another audit holds the lock" and is retried
426
461
  // in fifteen minutes, which here would just re-warn four times an hour
@@ -487,6 +522,72 @@ LINKS
487
522
  // over. Every precondition a person can get wrong is still checked HERE,
488
523
  // synchronously, because reporting success and leaving the real failure in the
489
524
  // journal is what already cost twenty minutes on a live machine.
525
+ if (args[0] === "flush") {
526
+ const subArgs = args.slice(1);
527
+ if (subArgs.includes("--help") || subArgs.includes("-h")) {
528
+ console.log(`
529
+ failproofai flush — deliver what is already spooled, now
530
+
531
+ USAGE
532
+ failproofai flush [--wait] [--timeout <secs>]
533
+
534
+ WHY
535
+ The collector is unhurried on purpose: a batch is swept once it is older than
536
+ two minutes, at most 64 per pass, on a 60-second cadence. That pacing keeps a
537
+ backlog from stampeding the server, and it is exactly wrong when you are
538
+ standing at a dashboard waiting to see your own events — "not delivered yet"
539
+ and "not working" look identical from there.
540
+
541
+ This asks the daemon to make a pass right now, with no minimum age and no
542
+ per-pass cap. It re-sends nothing: only batches already spooled and not yet
543
+ delivered. For history the collector has already read past, use \`backfill\`.
544
+
545
+ OPTIONS
546
+ --wait Block until the spool drains, or --timeout elapses.
547
+ --timeout <secs> How long --wait waits. Default: 60.
548
+ `);
549
+ process.exit(0);
550
+ }
551
+
552
+ const KNOWN = new Set(["--wait", "--timeout"]);
553
+ const unknown = subArgs.find(
554
+ (a, i) => a.startsWith("-") && !KNOWN.has(a) && subArgs[i - 1] !== "--timeout",
555
+ );
556
+ if (unknown) {
557
+ throw new CliError(`Unexpected argument: ${unknown}\nRun \`failproofai flush --help\` for usage.`);
558
+ }
559
+
560
+ let timeoutSecs;
561
+ const tIdx = subArgs.indexOf("--timeout");
562
+ if (tIdx >= 0) {
563
+ const raw = subArgs[tIdx + 1];
564
+ if (!raw || raw.startsWith("-")) throw new CliError("Missing value after --timeout.");
565
+ const n = Number(raw);
566
+ // Rejected rather than coerced: NaN would silently become "wait forever
567
+ // or not at all" depending on the comparison, and neither is what was asked.
568
+ if (!Number.isFinite(n) || n <= 0) {
569
+ throw new CliError(`Could not read --timeout ${raw}. Give a number of seconds.`);
570
+ }
571
+ timeoutSecs = n;
572
+ }
573
+
574
+ lastSubcommand = "flush";
575
+ const { runFlushCommand } = await import("../src/hooks/flush-cli");
576
+ const result = await runFlushCommand({ wait: subArgs.includes("--wait"), timeoutSecs });
577
+ for (const line of result.lines) {
578
+ if (result.exitCode === 0) console.log(line);
579
+ else console.error(line);
580
+ }
581
+ await track("cli_flush", {
582
+ ok: result.exitCode === 0,
583
+ waited: subArgs.includes("--wait"),
584
+ pending: result.pending,
585
+ });
586
+ lastSubcommand = null;
587
+ await exitAfterFlush(result.exitCode);
588
+ return;
589
+ }
590
+
490
591
  if (args[0] === "backfill") {
491
592
  const subArgs = args.slice(1);
492
593
  if (subArgs.includes("--help") || subArgs.includes("-h")) {
@@ -557,6 +658,80 @@ OPTIONS
557
658
  return;
558
659
  }
559
660
 
661
+ // harness list | add-path | remove-path
662
+ //
663
+ // Extra capture paths per harness. Writes ~/.failproofai/config.toml and
664
+ // nothing else — no root, no daemon call — so it works on a machine whose
665
+ // daemon is stopped, which is when someone is most likely to be fixing what
666
+ // it captures.
667
+ if (args[0] === "harness") {
668
+ const subArgs = args.slice(1);
669
+ if (subArgs.length === 0 || subArgs.includes("--help") || subArgs.includes("-h")) {
670
+ console.log(`
671
+ failproofai harness — capture sessions from more than one location per agent CLI
672
+
673
+ USAGE
674
+ failproofai harness list [<harness>]
675
+ failproofai harness add-path <harness> [<label>=]<path>
676
+ failproofai harness remove-path <harness> <path|label>
677
+
678
+ WHY
679
+ Each agent CLI is watched wherever its own installer put it — ~/.claude/projects,
680
+ ~/.hermes/state.db, and so on. That misses every other arrangement: a second
681
+ profile, a mounted team share, a container's home beside the host's, an agent
682
+ an operator moved. Those hold real sessions and nothing collects them.
683
+
684
+ THE LABEL
685
+ An entry is \`<path>\` or \`<label>=<path>\`. The label namespaces agent ids as
686
+ <label>-<agentId>, and it matters: two locations holding the same project
687
+ derive the SAME id (it comes from the cwd inside the transcript, identical in
688
+ both copies), so without a label they merge into one agent whose sessions
689
+ interleave from two machines' worth of history. Omit it and one is derived
690
+ from the folder name.
691
+
692
+ HARNESSES
693
+ claude, codex, copilot, openclaw, pi, factory, antigravity, cursor,
694
+ goose, opencode, devin, hermes
695
+
696
+ \`claude\` covers subagent transcripts too — they live under the same root.
697
+
698
+ NOTES
699
+ • Session collection must be on for any of this to be read; extra paths follow
700
+ [collector] in ~/.failproofai/config.toml like the default ones do.
701
+ • A path overlapping one already captured is REFUSED by the daemon at startup
702
+ rather than collected twice under two ids. It says so in the journal.
703
+ • Takes effect within seconds — the daemon re-reads config.toml on an interval
704
+ and cycles its collector. No restart, no sudo.
705
+
706
+ EXAMPLES
707
+ failproofai harness add-path claude work=/srv/team/.claude/projects
708
+ failproofai harness add-path hermes prod=/srv/hermes-prod/state.db
709
+ failproofai harness add-path codex /mnt/other-home/.codex/sessions
710
+ failproofai harness list
711
+ failproofai harness remove-path claude work
712
+ `.trimStart());
713
+ process.exit(0);
714
+ }
715
+
716
+ lastSubcommand = "harness";
717
+ const { runHarnessCommand } = await import("../src/hooks/harness-cli");
718
+ const result = runHarnessCommand(subArgs);
719
+ for (const line of result.lines) {
720
+ if (result.exitCode === 0) console.log(line);
721
+ else console.error(line);
722
+ }
723
+ await track("cli_harness", {
724
+ ok: result.exitCode === 0,
725
+ // The subcommand only — never the harness name, the label or the path.
726
+ // A path is a value the user typed, and `enterprise-docs/product-analytics.md`
727
+ // promises we send shape, never value.
728
+ sub: ["list", "add-path", "remove-path"].includes(subArgs[0]) ? subArgs[0] : "unknown",
729
+ });
730
+ lastSubcommand = null;
731
+ await exitAfterFlush(result.exitCode);
732
+ return;
733
+ }
734
+
560
735
  // uninstall [--purge] [--dry-run] [--yes|-y]
561
736
  //
562
737
  // Top-level, and deliberately NOT a flag on `policies`. `policies --uninstall`
@@ -1115,7 +1290,7 @@ USAGE
1115
1290
  WHAT IT DOES
1116
1291
  Walks you through 4 quick steps and writes everything for you:
1117
1292
  1. Where — global (all projects) or just this project
1118
- 2. Assistants — which agent CLIs to protect (Claude, Codex, ...)
1293
+ 2. Harnesses — which agent CLIs to protect (Claude, Codex, ...)
1119
1294
  3. Policies — presets (combine any), Everything, or a custom pick
1120
1295
  4. Review — confirms the exact files it will change, then applies
1121
1296
 
@@ -1124,7 +1299,13 @@ FAILPROOF CLOUD
1124
1299
  Connect this machine to Failproof Cloud
1125
1300
  [--no-transcripts] decisions only, no transcripts
1126
1301
  failproofai config --disconnect Stop pulling policy and sending activity
1127
- failproofai config --status Show connection and pause state
1302
+ failproofai config --status Show connection, daemon and pause state
1303
+ failproofai config --pause [--session <id>]
1304
+ Pause enforcement, time-boxed
1305
+ failproofai config --resume [--all]
1306
+ Resume enforcement
1307
+
1308
+ --machine-label <name> Human-readable name in the dashboard
1128
1309
 
1129
1310
  One connection, two capabilities: this machine PULLS centrally-managed
1130
1311
  policies and SENDS what its hooks decided, so the dashboard shows the fleet