failproofai 1.0.0-beta.1 → 1.0.0-beta.3

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 (197) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +6 -6
  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 +3 -3
  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 +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/build-manifest.json +3 -3
  17. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  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.nft.json +1 -1
  29. package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
  30. package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
  32. package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
  33. package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
  34. package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
  35. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/audit/page/build-manifest.json +3 -3
  37. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  38. package/.next/standalone/.next/server/app/audit/page.js +1 -1
  39. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/.next/server/app/index.html +1 -1
  42. package/.next/standalone/.next/server/app/index.rsc +15 -15
  43. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  44. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
  45. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  46. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
  47. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  48. package/.next/standalone/.next/server/app/page/build-manifest.json +3 -3
  49. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  50. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  51. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  52. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +3 -3
  53. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +30 -18
  54. package/.next/standalone/.next/server/app/policies/page.js +2 -2
  55. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  56. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  57. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +3 -3
  58. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  59. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  60. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  61. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +3 -3
  62. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  63. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  64. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  65. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  66. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +3 -3
  67. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  68. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  69. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  70. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0id_xf7._.js +1 -1
  71. package/.next/standalone/.next/server/chunks/[root-of-the-server]__19120tr._.js +1 -1
  72. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +1 -1
  73. package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +1 -1
  74. package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +4 -4
  75. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  76. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02r5bgf._.js +2 -2
  77. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e8sjqm._.js +2 -2
  78. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0lkzqax._.js +2 -2
  79. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1ath6v_._.js → [root-of-the-server]__0ls0gsr._.js} +3 -3
  80. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qucxyj._.js +2 -2
  81. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__170799-._.js → [root-of-the-server]__0spkm68._.js} +11 -11
  82. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0u02miy._.js +2 -2
  83. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1ig795d._.js → [root-of-the-server]__10s_z4l._.js} +2 -2
  84. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0114ewg._.js → [root-of-the-server]__1j4u3yd._.js} +3 -3
  85. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1yo1gyz._.js → [root-of-the-server]__1ky3im9._.js} +2 -2
  86. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zqz4v8._.js +2 -2
  87. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  88. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  89. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
  90. package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_14q3-7b.js → node_modules_html-to-image_es_index_0jfts82.js} +1 -1
  91. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +1 -1
  92. package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.js +1 -1
  93. package/.next/standalone/.next/server/middleware-build-manifest.js +6 -6
  94. package/.next/standalone/.next/server/pages/404.html +1 -1
  95. package/.next/standalone/.next/server/pages/500.html +1 -1
  96. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  97. package/.next/standalone/.next/server/server-reference-manifest.json +32 -20
  98. package/.next/standalone/.next/static/chunks/{1d71o1_tav721.js → 01h6lfjz1_oie.js} +1 -1
  99. package/.next/standalone/.next/static/chunks/{03fmihek9n986.js → 06zgzyh3wv1ig.js} +1 -1
  100. package/.next/standalone/.next/static/chunks/{07ix3lb4gib0x.js → 0a7k_x4rp_97z.js} +1 -1
  101. package/.next/standalone/.next/static/chunks/{35584kn409ad1.js → 0cvd6bcdwchc_.js} +1 -1
  102. package/.next/standalone/.next/static/chunks/{191njgoik03fm.js → 13-obgukzg_ke.js} +1 -1
  103. package/.next/standalone/.next/static/chunks/16p68cybetr31.js +1 -0
  104. package/.next/standalone/.next/static/chunks/{2ovmv4esqalpb.js → 1h0_yaoq5f3yx.js} +1 -1
  105. package/.next/standalone/.next/static/chunks/{30is-6r00sbd7.js → 29g8ykjk6sx_8.js} +1 -1
  106. package/.next/standalone/.next/static/chunks/{1b3a1scouf40o.js → 2rqm-klet_gbl.js} +1 -1
  107. package/.next/standalone/.next/static/chunks/{24gs8ip6_spcb.js → 2uvyh8y0naofj.js} +1 -1
  108. package/.next/standalone/.next/static/chunks/31coz11ia5vc4.js +1 -0
  109. package/.next/standalone/.next/static/chunks/3p-n_j80zlzi3.js +6 -0
  110. package/.next/standalone/.next/static/chunks/3zdwnnthucs_1.css +2 -0
  111. package/.next/standalone/.next/static/chunks/{turbopack-1lsv92x7klwrn.js → turbopack-3diub4ctvn1n0.js} +1 -1
  112. package/.next/standalone/Cargo.lock +1992 -198
  113. package/.next/standalone/Cargo.toml +1 -1
  114. package/.next/standalone/app/actions/get-active-pauses.ts +16 -0
  115. package/.next/standalone/app/components/pause-notices.tsx +111 -0
  116. package/.next/standalone/app/policies/hooks-client.tsx +81 -6
  117. package/.next/standalone/crates/CLOUD_POLICIES.md +136 -0
  118. package/.next/standalone/crates/failproofaid/Cargo.toml +7 -0
  119. package/.next/standalone/crates/failproofaid/src/cloud_client.rs +484 -0
  120. package/.next/standalone/crates/failproofaid/src/cloud_policies.rs +921 -0
  121. package/.next/standalone/crates/failproofaid/src/main.rs +452 -3
  122. package/.next/standalone/crates/failproofaid/src/paths.rs +29 -0
  123. package/.next/standalone/crates/fpai-collect/Cargo.toml +43 -0
  124. package/.next/standalone/crates/fpai-collect/src/config.rs +412 -0
  125. package/.next/standalone/crates/fpai-collect/src/cursor.rs +520 -0
  126. package/.next/standalone/crates/fpai-collect/src/delivery.rs +472 -0
  127. package/.next/standalone/crates/fpai-collect/src/filetail.rs +484 -0
  128. package/.next/standalone/crates/fpai-collect/src/health.rs +369 -0
  129. package/.next/standalone/crates/fpai-collect/src/lib.rs +34 -0
  130. package/.next/standalone/crates/fpai-collect/src/redact.rs +516 -0
  131. package/.next/standalone/crates/fpai-collect/src/sources/claude/mod.rs +279 -0
  132. package/.next/standalone/crates/fpai-collect/src/sources/claude/transform.rs +619 -0
  133. package/.next/standalone/crates/fpai-collect/src/sources/codex/mod.rs +156 -0
  134. package/.next/standalone/crates/fpai-collect/src/sources/codex/transform.rs +715 -0
  135. package/.next/standalone/crates/fpai-collect/src/sources/copilot/mod.rs +158 -0
  136. package/.next/standalone/crates/fpai-collect/src/sources/copilot/transform.rs +512 -0
  137. package/.next/standalone/crates/fpai-collect/src/sources/goose/mod.rs +511 -0
  138. package/.next/standalone/crates/fpai-collect/src/sources/goose/transform.rs +586 -0
  139. package/.next/standalone/crates/fpai-collect/src/sources/hermes/mod.rs +318 -0
  140. package/.next/standalone/crates/fpai-collect/src/sources/hermes/transform.rs +579 -0
  141. package/.next/standalone/crates/fpai-collect/src/sources/hooks/mod.rs +310 -0
  142. package/.next/standalone/crates/fpai-collect/src/sources/hooks/transform.rs +448 -0
  143. package/.next/standalone/crates/fpai-collect/src/sources/mod.rs +23 -0
  144. package/.next/standalone/crates/fpai-collect/src/sources/openclaw/mod.rs +176 -0
  145. package/.next/standalone/crates/fpai-collect/src/sources/openclaw/transform.rs +500 -0
  146. package/.next/standalone/crates/fpai-collect/src/sources/opencode/mod.rs +315 -0
  147. package/.next/standalone/crates/fpai-collect/src/sources/opencode/transform.rs +493 -0
  148. package/.next/standalone/crates/fpai-collect/src/sources/pi/mod.rs +201 -0
  149. package/.next/standalone/crates/fpai-collect/src/sources/pi/transform.rs +533 -0
  150. package/.next/standalone/crates/fpai-collect/src/spool.rs +458 -0
  151. package/.next/standalone/crates/fpai-collect/src/sqlitepoll.rs +387 -0
  152. package/.next/standalone/crates/fpai-collect/src/supervisor.rs +423 -0
  153. package/.next/standalone/crates/fpai-collect/src/uploader.rs +600 -0
  154. package/.next/standalone/crates/fpai-collect/tests/claude_source.rs +738 -0
  155. package/.next/standalone/crates/fpai-collect/tests/claude_subagents.rs +393 -0
  156. package/.next/standalone/crates/fpai-collect/tests/codex_source.rs +975 -0
  157. package/.next/standalone/crates/fpai-collect/tests/config.rs +286 -0
  158. package/.next/standalone/crates/fpai-collect/tests/copilot_source.rs +1019 -0
  159. package/.next/standalone/crates/fpai-collect/tests/delivery.rs +281 -0
  160. package/.next/standalone/crates/fpai-collect/tests/goose_source.rs +1008 -0
  161. package/.next/standalone/crates/fpai-collect/tests/hermes_source.rs +1129 -0
  162. package/.next/standalone/crates/fpai-collect/tests/hooks_source.rs +621 -0
  163. package/.next/standalone/crates/fpai-collect/tests/openclaw_source.rs +854 -0
  164. package/.next/standalone/crates/fpai-collect/tests/opencode_source.rs +1478 -0
  165. package/.next/standalone/crates/fpai-collect/tests/pi_source.rs +1191 -0
  166. package/.next/standalone/crates/fpai-collect/tests/supervisor.rs +290 -0
  167. package/.next/standalone/crates/fpai-collect/tests/uploader.rs +506 -0
  168. package/.next/standalone/package.json +2 -2
  169. package/.next/standalone/server.js +1 -1
  170. package/bin/failproofai.mjs +129 -0
  171. package/dist/cli.mjs +2294 -786
  172. package/dist/worker.mjs +365 -52
  173. package/package.json +2 -2
  174. package/src/hooks/builtin-policies.ts +139 -0
  175. package/src/hooks/cloud-connection.ts +205 -0
  176. package/src/hooks/cloud-enrollment-cli.ts +227 -0
  177. package/src/hooks/cloud-enrollment.ts +173 -0
  178. package/src/hooks/cloud-managed-policies.ts +138 -0
  179. package/src/hooks/collector-config.ts +226 -0
  180. package/src/hooks/configure-wizard.ts +308 -18
  181. package/src/hooks/custom-hooks-loader.ts +69 -25
  182. package/src/hooks/daemon-client.ts +18 -0
  183. package/src/hooks/daemon-service.ts +125 -24
  184. package/src/hooks/handler.ts +144 -6
  185. package/src/hooks/hook-activity-store.ts +50 -0
  186. package/src/hooks/loader-utils.ts +6 -4
  187. package/src/hooks/policy-types.ts +35 -0
  188. package/src/hooks/session-pause-cli.ts +157 -0
  189. package/src/hooks/session-pause.ts +236 -0
  190. package/src/hooks/tui.ts +115 -0
  191. package/.next/standalone/.next/static/chunks/0fdx7ikab08-g.js +0 -6
  192. package/.next/standalone/.next/static/chunks/0zbxssxh53n-3.js +0 -1
  193. package/.next/standalone/.next/static/chunks/2pujpnfx4pws6.css +0 -2
  194. package/.next/standalone/.next/static/chunks/33u59vf_8xpd-.js +0 -1
  195. /package/.next/standalone/.next/static/{avJMC2AXvrg13Pbm4QH8F → pM1veX5Llx4YKEaiFc8Sf}/_buildManifest.js +0 -0
  196. /package/.next/standalone/.next/static/{avJMC2AXvrg13Pbm4QH8F → pM1veX5Llx4YKEaiFc8Sf}/_clientMiddlewareManifest.js +0 -0
  197. /package/.next/standalone/.next/static/{avJMC2AXvrg13Pbm4QH8F → pM1veX5Llx4YKEaiFc8Sf}/_ssgManifest.js +0 -0
@@ -0,0 +1,157 @@
1
+ /**
2
+ * `failproofai config --pause | --resume | --status`.
3
+ *
4
+ * Lives on `config` rather than as its own verb because `config` is the single
5
+ * place this product configures anything. The state it writes is NOT config
6
+ * though — see session-pause.ts for why a pause must never reach a file that
7
+ * gets committed.
8
+ */
9
+ import {
10
+ PAUSE_CEILING_MS,
11
+ clearPause,
12
+ formatDuration,
13
+ listActivePauses,
14
+ parsePauseDuration,
15
+ readActivePause,
16
+ resolveSessionForCwd,
17
+ writePause,
18
+ type ActivePause,
19
+ } from "./session-pause";
20
+ import { readMergedHooksConfig } from "./hooks-config";
21
+
22
+ export interface PauseCommandOptions {
23
+ action: "pause" | "resume" | "status";
24
+ /** Raw `--pause <duration>` argument, if any. */
25
+ duration?: string;
26
+ /** Explicit `--session <id>`. */
27
+ sessionId?: string;
28
+ /** `--all`. */
29
+ all?: boolean;
30
+ cwd?: string;
31
+ now?: number;
32
+ }
33
+
34
+ export interface PauseCommandResult {
35
+ exitCode: number;
36
+ lines: string[];
37
+ /** For telemetry; never the session id itself. */
38
+ affected: number;
39
+ }
40
+
41
+ /**
42
+ * The ceiling, after any config lowering. A project may tighten this; nothing
43
+ * may loosen it, so a config asking for 24h still gets 8h.
44
+ */
45
+ export function effectiveCeilingMs(cwd?: string): number {
46
+ try {
47
+ const configured = readMergedHooksConfig(cwd).maxPauseMs;
48
+ if (typeof configured === "number" && Number.isFinite(configured) && configured > 0) {
49
+ return Math.min(configured, PAUSE_CEILING_MS);
50
+ }
51
+ } catch {
52
+ // An unreadable config must not remove the ceiling.
53
+ }
54
+ return PAUSE_CEILING_MS;
55
+ }
56
+
57
+ function describe(pause: ActivePause, now: number): string {
58
+ const remaining = formatDuration(Math.max(0, pause.expiresAt - now));
59
+ const at = new Date(pause.expiresAt).toLocaleTimeString();
60
+ const where = pause.cwd ? ` · ${pause.cwd}` : "";
61
+ return ` ${pause.sessionId} ${remaining} left (until ${at})${where}`;
62
+ }
63
+
64
+ export function runPauseCommand(opts: PauseCommandOptions): PauseCommandResult {
65
+ const now = opts.now ?? Date.now();
66
+ const cwd = opts.cwd ?? process.cwd();
67
+
68
+ if (opts.action === "status") {
69
+ const active = listActivePauses(now);
70
+ if (active.length === 0) {
71
+ return { exitCode: 0, lines: ["Enforcement is active — nothing is paused."], affected: 0 };
72
+ }
73
+ return {
74
+ exitCode: 0,
75
+ lines: [
76
+ `Enforcement paused for ${active.length} session${active.length === 1 ? "" : "s"}:`,
77
+ ...active.map((p) => describe(p, now)),
78
+ "",
79
+ "Cloud-managed policies keep enforcing regardless.",
80
+ "Resume early with: failproofai config --resume",
81
+ ],
82
+ affected: active.length,
83
+ };
84
+ }
85
+
86
+ if (opts.action === "resume") {
87
+ if (opts.all) {
88
+ const active = listActivePauses(now);
89
+ let cleared = 0;
90
+ for (const pause of active) if (clearPause(pause.sessionId)) cleared++;
91
+ return {
92
+ exitCode: 0,
93
+ lines: [cleared === 0 ? "Nothing was paused." : `Resumed enforcement for ${cleared} session(s).`],
94
+ affected: cleared,
95
+ };
96
+ }
97
+ const sessionId = opts.sessionId ?? resolveSessionForCwd(cwd, undefined, now);
98
+ if (!sessionId) {
99
+ return { exitCode: 0, lines: ["Nothing was paused for this directory."], affected: 0 };
100
+ }
101
+ const cleared = clearPause(sessionId);
102
+ return {
103
+ exitCode: 0,
104
+ lines: [cleared ? "Enforcement resumed." : "Nothing was paused for that session."],
105
+ affected: cleared ? 1 : 0,
106
+ };
107
+ }
108
+
109
+ // pause
110
+ let durationMs: number;
111
+ try {
112
+ durationMs = parsePauseDuration(opts.duration, effectiveCeilingMs(cwd));
113
+ } catch (err) {
114
+ return { exitCode: 1, lines: [err instanceof Error ? err.message : String(err)], affected: 0 };
115
+ }
116
+
117
+ const sessionId = opts.sessionId ?? resolveSessionForCwd(cwd, undefined, now);
118
+ if (!sessionId) {
119
+ // Deliberately an error, not a guess. Pausing the wrong session would leave
120
+ // the user believing enforcement is off while it is on, or vice versa.
121
+ return {
122
+ exitCode: 1,
123
+ lines: [
124
+ "No recent agent session found for this directory.",
125
+ "",
126
+ "A pause applies to one agent session, and the session id only appears once",
127
+ "an agent has run at least one tool call here. Either run your agent first,",
128
+ "or name the session explicitly:",
129
+ "",
130
+ " failproofai config --pause --session <id>",
131
+ "",
132
+ "Session ids are listed in the dashboard's activity view.",
133
+ ],
134
+ affected: 0,
135
+ };
136
+ }
137
+
138
+ const existing = readActivePause(sessionId, now);
139
+ const pause = writePause({ sessionId, durationMs, cwd, setBy: "cli", now });
140
+ const until = new Date(pause.expiresAt).toLocaleTimeString();
141
+
142
+ return {
143
+ exitCode: 0,
144
+ lines: [
145
+ existing
146
+ ? `Enforcement pause extended · ${formatDuration(durationMs)} · resumes at ${until}`
147
+ : `Enforcement paused · ${formatDuration(durationMs)} · resumes at ${until}`,
148
+ "",
149
+ " Builtin, custom and convention policies are suspended for this session.",
150
+ " Cloud-managed policies keep enforcing.",
151
+ "",
152
+ "It lifts on its own — no action needed. To end it early:",
153
+ " failproofai config --resume",
154
+ ],
155
+ affected: 1,
156
+ };
157
+ }
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Per-session enforcement pause — the state behind `failproofai config --pause`.
3
+ *
4
+ * A pause suspends LOCAL policy (builtins, explicit custom, convention) for one
5
+ * agent session, for a bounded time. It is deliberately NOT configuration:
6
+ *
7
+ * - Config is persistent, merged across project/local/global, and routinely
8
+ * committed to git. A paused enforcement state written there would outlive
9
+ * the session that asked for it and travel to everyone who checks out the
10
+ * branch — enforcement silently off for a whole team.
11
+ * - So pause state lives here, under `~/.failproofai/state/sessions/`, owner-
12
+ * only, keyed by session, and carrying an absolute expiry.
13
+ *
14
+ * Disk is the source of truth rather than the daemon: most machines have no
15
+ * daemon at all, and even where one exists the CLI that writes a pause is a
16
+ * different process from the hook that reads it. A daemon may cache this; it
17
+ * must not own it.
18
+ *
19
+ * Expiry is evaluated at READ time against the clock, never by a sweeper. A
20
+ * stale file is therefore inert rather than dangerous — the failure mode worth
21
+ * engineering against is not "the pause didn't work", it is "the pause silently
22
+ * never ended".
23
+ */
24
+ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync } from "node:fs";
25
+ import { homedir } from "node:os";
26
+ import { createHash } from "node:crypto";
27
+ import { join, resolve } from "node:path";
28
+ import { writeJsonAtomically } from "../../lib/atomic-write";
29
+ import { getAllHookActivityEntries } from "./hook-activity-store";
30
+
31
+ const SCHEMA_VERSION = 1;
32
+
33
+ /** Default when `--pause` is given no duration. */
34
+ export const PAUSE_DEFAULT_MS = 30 * 60_000;
35
+
36
+ /**
37
+ * Hard ceiling. Config may lower this, never raise it — a ceiling a project
38
+ * could raise is not a ceiling, and the whole point is that a forgotten pause
39
+ * costs little.
40
+ */
41
+ export const PAUSE_CEILING_MS = 8 * 60 * 60_000;
42
+
43
+ export interface ActivePause {
44
+ sessionId: string;
45
+ /** Epoch ms. */
46
+ pausedAt: number;
47
+ /** Epoch ms. Always finite — there is no unbounded pause. */
48
+ expiresAt: number;
49
+ /** Free-form provenance, e.g. "cli". Recorded so the activity log can say who. */
50
+ setBy: string;
51
+ /** Where it was issued from, for `--status` and for cwd-based resolution. */
52
+ cwd?: string;
53
+ }
54
+
55
+ interface StoredPause extends ActivePause {
56
+ schemaVersion: number;
57
+ }
58
+
59
+ export function pauseStateDir(): string {
60
+ const override = process.env.FAILPROOFAI_STATE_DIR;
61
+ if (override) return resolve(override, "sessions");
62
+ return join(homedir(), ".failproofai", "state", "sessions");
63
+ }
64
+
65
+ /**
66
+ * Filename is a digest of the session id, not the id itself.
67
+ *
68
+ * Session ids come from twelve different agent CLIs and are not a format we
69
+ * control — Hermes and OpenClaw mint their own, and nothing stops one
70
+ * containing a path separator or `..`. Hashing sidesteps the entire class
71
+ * rather than trying to enumerate what is safe; the real id is stored inside
72
+ * the file, so `--status` and `--all` still report it.
73
+ */
74
+ function pauseFilePath(sessionId: string): string {
75
+ const digest = createHash("sha256").update(sessionId).digest("hex").slice(0, 32);
76
+ return join(pauseStateDir(), `${digest}.json`);
77
+ }
78
+
79
+ /**
80
+ * Parse `10m` / `2h` / `90s`, or a bare integer read as minutes.
81
+ *
82
+ * Refuses anything over the ceiling rather than silently clamping: someone
83
+ * typing `--pause 12h` has a expectation about how long enforcement is off,
84
+ * and quietly giving them 8h is worse than telling them no.
85
+ */
86
+ export function parsePauseDuration(input: string | undefined, ceilingMs = PAUSE_CEILING_MS): number {
87
+ if (input === undefined || input === "") return Math.min(PAUSE_DEFAULT_MS, ceilingMs);
88
+
89
+ const match = /^(\d+)\s*(s|m|h)?$/i.exec(input.trim());
90
+ if (!match) {
91
+ throw new Error(
92
+ `Invalid duration ${JSON.stringify(input)}. Use e.g. 30m, 2h, 90s (a bare number means minutes).`,
93
+ );
94
+ }
95
+ const value = Number(match[1]);
96
+ const unit = (match[2] ?? "m").toLowerCase();
97
+ const ms = unit === "s" ? value * 1000 : unit === "h" ? value * 3_600_000 : value * 60_000;
98
+
99
+ if (ms <= 0) throw new Error("Duration must be greater than zero.");
100
+ if (ms > ceilingMs) {
101
+ throw new Error(`Duration ${input} exceeds the maximum pause of ${formatDuration(ceilingMs)}.`);
102
+ }
103
+ return ms;
104
+ }
105
+
106
+ /** Human-readable, for CLI output and log reasons. */
107
+ export function formatDuration(ms: number): string {
108
+ if (ms < 60_000) return `${Math.round(ms / 1000)}s`;
109
+ const minutes = Math.round(ms / 60_000);
110
+ if (minutes < 60) return `${minutes}m`;
111
+ const hours = Math.floor(minutes / 60);
112
+ const rest = minutes % 60;
113
+ return rest === 0 ? `${hours}h` : `${hours}h${rest}m`;
114
+ }
115
+
116
+ function parseStored(raw: unknown): StoredPause | null {
117
+ if (!raw || typeof raw !== "object") return null;
118
+ const p = raw as Partial<StoredPause>;
119
+ if (p.schemaVersion !== SCHEMA_VERSION) return null;
120
+ if (typeof p.sessionId !== "string" || p.sessionId.length === 0) return null;
121
+ if (!Number.isFinite(p.pausedAt) || !Number.isFinite(p.expiresAt)) return null;
122
+ return {
123
+ schemaVersion: SCHEMA_VERSION,
124
+ sessionId: p.sessionId,
125
+ pausedAt: p.pausedAt as number,
126
+ expiresAt: p.expiresAt as number,
127
+ setBy: typeof p.setBy === "string" ? p.setBy : "unknown",
128
+ ...(typeof p.cwd === "string" ? { cwd: p.cwd } : {}),
129
+ };
130
+ }
131
+
132
+ /**
133
+ * The active pause for a session, or null.
134
+ *
135
+ * Never throws: this is called on the hook path, and a malformed or unreadable
136
+ * state file must mean "enforcement is ON" rather than crashing the evaluation.
137
+ * Failing toward enforcement is the only safe direction here.
138
+ */
139
+ export function readActivePause(sessionId: string | undefined, now = Date.now()): ActivePause | null {
140
+ if (!sessionId) return null;
141
+ try {
142
+ const path = pauseFilePath(sessionId);
143
+ if (!existsSync(path)) return null;
144
+ const stored = parseStored(JSON.parse(readFileSync(path, "utf8")));
145
+ if (!stored) return null;
146
+ if (stored.expiresAt <= now) return null; // expired — inert, not dangerous
147
+ const { schemaVersion: _ignored, ...pause } = stored;
148
+ return pause;
149
+ } catch {
150
+ return null;
151
+ }
152
+ }
153
+
154
+ export function writePause(opts: {
155
+ sessionId: string;
156
+ durationMs: number;
157
+ cwd?: string;
158
+ setBy?: string;
159
+ now?: number;
160
+ }): ActivePause {
161
+ const now = opts.now ?? Date.now();
162
+ const pause: ActivePause = {
163
+ sessionId: opts.sessionId,
164
+ pausedAt: now,
165
+ expiresAt: now + opts.durationMs,
166
+ setBy: opts.setBy ?? "cli",
167
+ ...(opts.cwd ? { cwd: opts.cwd } : {}),
168
+ };
169
+ mkdirSync(pauseStateDir(), { recursive: true, mode: 0o700 });
170
+ writeJsonAtomically(pauseFilePath(opts.sessionId), { schemaVersion: SCHEMA_VERSION, ...pause });
171
+ return pause;
172
+ }
173
+
174
+ /** Returns true if a pause file was removed. */
175
+ export function clearPause(sessionId: string): boolean {
176
+ const path = pauseFilePath(sessionId);
177
+ if (!existsSync(path)) return false;
178
+ try {
179
+ rmSync(path);
180
+ return true;
181
+ } catch {
182
+ return false;
183
+ }
184
+ }
185
+
186
+ /** Every pause that has not yet expired, newest first. Expired files are ignored. */
187
+ export function listActivePauses(now = Date.now()): ActivePause[] {
188
+ const dir = pauseStateDir();
189
+ if (!existsSync(dir)) return [];
190
+ const out: ActivePause[] = [];
191
+ let names: string[];
192
+ try {
193
+ names = readdirSync(dir);
194
+ } catch {
195
+ return [];
196
+ }
197
+ for (const name of names) {
198
+ if (!name.endsWith(".json")) continue;
199
+ try {
200
+ const stored = parseStored(JSON.parse(readFileSync(join(dir, name), "utf8")));
201
+ if (!stored || stored.expiresAt <= now) continue;
202
+ const { schemaVersion: _ignored, ...pause } = stored;
203
+ out.push(pause);
204
+ } catch {
205
+ // A single unreadable file must not hide every other pause from --status.
206
+ }
207
+ }
208
+ return out.sort((a, b) => b.pausedAt - a.pausedAt);
209
+ }
210
+
211
+ /**
212
+ * The session to act on when the user names none.
213
+ *
214
+ * Whoever types the command has no session id — it exists only inside the hook
215
+ * payload. But every hook event already records `sessionId` alongside `cwd` and
216
+ * a timestamp, so the most recent session seen in this directory is derivable
217
+ * from data we already write. Returns null when nothing recent matches, so the
218
+ * caller can say so instead of guessing at a stranger's session.
219
+ */
220
+ export function resolveSessionForCwd(cwd: string, maxAgeMs = 12 * 3_600_000, now = Date.now()): string | null {
221
+ let best: { sessionId: string; timestamp: number } | null = null;
222
+ let entries;
223
+ try {
224
+ entries = getAllHookActivityEntries();
225
+ } catch {
226
+ return null;
227
+ }
228
+ for (const entry of entries) {
229
+ if (!entry.sessionId || entry.cwd !== cwd) continue;
230
+ if (now - entry.timestamp > maxAgeMs) continue;
231
+ if (!best || entry.timestamp > best.timestamp) {
232
+ best = { sessionId: entry.sessionId, timestamp: entry.timestamp };
233
+ }
234
+ }
235
+ return best?.sessionId ?? null;
236
+ }
package/src/hooks/tui.ts CHANGED
@@ -643,3 +643,118 @@ export function multiSelect<T>(opts: MultiSelectOptions<T>): Promise<T[] | null>
643
643
  ),
644
644
  });
645
645
  }
646
+
647
+ // ── promptText (single line, optionally masked) ───────────────────────────────
648
+
649
+ export interface PromptTextOptions {
650
+ message: string;
651
+ /** Shown dimmed under the prompt. */
652
+ hint?: string;
653
+ /** Used when the user submits an empty line. */
654
+ defaultValue?: string;
655
+ /**
656
+ * Render `•` instead of the typed characters. For credentials: the wizard is
657
+ * routinely run while screen-sharing, and a pasted key would otherwise sit in
658
+ * the scrollback of every recording of that session.
659
+ */
660
+ mask?: boolean;
661
+ /** Return an error string to reject and re-ask, or null to accept. */
662
+ validate?: (value: string) => string | null;
663
+ stdin?: TTYIn;
664
+ stdout?: TTYOut;
665
+ }
666
+
667
+ /**
668
+ * Read one line. Resolves `null` on Ctrl-C / Escape, which every caller in the
669
+ * wizard treats as "cancel the whole run" — consistent with selectOne.
670
+ *
671
+ * Falls back to a plain non-TTY read so `failproofai config` still works when
672
+ * driven from a pipe or a test, the same way the other prompts do.
673
+ */
674
+ export function promptText(opts: PromptTextOptions): Promise<string | null> {
675
+ const stdin: TTYIn = opts.stdin ?? process.stdin;
676
+ const stdout: TTYOut = opts.stdout ?? process.stdout;
677
+ const c = paint(colorsEnabled(stdout));
678
+
679
+ const accept = (raw: string): { ok: true; value: string } | { ok: false; error: string } => {
680
+ const value = raw.trim() || opts.defaultValue || "";
681
+ const error = opts.validate?.(value) ?? null;
682
+ return error ? { ok: false, error } : { ok: true, value };
683
+ };
684
+
685
+ if (!stdin.isTTY) {
686
+ // Non-TTY: read whatever is piped, validate once, no re-ask loop (there is
687
+ // no one to re-ask).
688
+ return new Promise((resolve) => {
689
+ let buf = "";
690
+ const onData = (chunk: Buffer | string) => {
691
+ buf += String(chunk);
692
+ if (buf.includes("\n")) done();
693
+ };
694
+ const done = () => {
695
+ stdin.removeListener("data", onData);
696
+ stdin.removeListener("end", done);
697
+ const r = accept(buf.split("\n")[0] ?? "");
698
+ resolve(r.ok ? r.value : null);
699
+ };
700
+ stdin.on("data", onData);
701
+ stdin.on("end", done);
702
+ });
703
+ }
704
+
705
+ return new Promise((resolve) => {
706
+ let value = "";
707
+ const draw = (error?: string) => {
708
+ const shown = opts.mask ? "•".repeat(value.length) : value;
709
+ const hint = opts.hint ? ` ${c.dim(opts.hint)}` : "";
710
+ const err = error ? `\n ${c.warn(error)}` : "";
711
+ stdout.write(`\r\x1b[2K${c.bold(opts.message)} ${shown}${hint}${err}`);
712
+ if (err) stdout.write("\x1b[1A");
713
+ };
714
+ draw();
715
+
716
+ readline.emitKeypressEvents(stdin);
717
+ const wasRaw = stdin.isRaw;
718
+ stdin.setRawMode?.(true);
719
+ stdin.resume();
720
+
721
+ const cleanup = () => {
722
+ stdin.removeListener("keypress", onKey);
723
+ stdin.setRawMode?.(wasRaw ?? false);
724
+ stdin.pause();
725
+ stdout.write("\n");
726
+ };
727
+
728
+ function onKey(str: string | undefined, key: readline.Key): void {
729
+ if (!key) return;
730
+ if ((key.ctrl && (key.name === "c" || key.name === "d")) || key.name === "escape") {
731
+ cleanup();
732
+ resolve(null);
733
+ return;
734
+ }
735
+ if (key.name === "return" || key.name === "enter") {
736
+ const r = accept(value);
737
+ if (r.ok) {
738
+ cleanup();
739
+ resolve(r.value);
740
+ } else {
741
+ draw(r.error);
742
+ }
743
+ return;
744
+ }
745
+ if (key.name === "backspace") {
746
+ value = value.slice(0, -1);
747
+ draw();
748
+ return;
749
+ }
750
+ // Ignore control keys; accept any printable character, including a
751
+ // bracketed paste arriving as one chunk.
752
+ if (str && !key.ctrl && !key.meta) {
753
+ value += str;
754
+ draw();
755
+ }
756
+ }
757
+
758
+ stdin.on("keypress", onKey);
759
+ });
760
+ }
@@ -1,6 +0,0 @@
1
- (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,64245,e=>{"use strict";var t=e.i(43476),s=e.i(71645),r=e.i(74080),o=e.i(22016),n=e.i(89664),l=e.i(16327),a=e.i(56420);let i=(0,a.default)("code",[["path",{d:"m16 18 6-6-6-6",key:"eg8j8"}],["path",{d:"m8 6-6 6 6 6",key:"ppft3o"}]]);var c=e.i(8734),d=e.i(66794),m=e.i(82954),u=e.i(16306),x=e.i(84026),p=e.i(54959);let h=(0,a.default)("triangle-alert",[["path",{d:"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",key:"wmoenq"}],["path",{d:"M12 9v4",key:"juzpu7"}],["path",{d:"M12 17h.01",key:"p32p05"}]]);var b=e.i(63676),g=e.i(73520),f=e.i(95187);let v=(0,f.createServerReference)("40fe4dbd1e48d7e90f7174d0484585bdb4ac7adfdb",f.callServer,void 0,f.findSourceMapURL,"getHookActivityAction");var j=e.i(22811);let y=(0,f.createServerReference)("00963ab4af32979e5b7b14700afa86e5c4b2c2ac78",f.callServer,void 0,f.findSourceMapURL,"getHooksConfigAction"),N=(0,f.createServerReference)("6004a1348b7037c0aca88511000190157d11f4a45f",f.callServer,void 0,f.findSourceMapURL,"toggleCustomPolicyAction"),k=(0,f.createServerReference)("60199cd9ba96fc80beaf48e48e6d67cea79e76c8d3",f.callServer,void 0,f.findSourceMapURL,"togglePolicyAction"),S=(0,f.createServerReference)("6081d238126830abe2b9a62490fb80023294ce1347",f.callServer,void 0,f.findSourceMapURL,"installHooksWebAction"),w=(0,f.createServerReference)("60b8958733656edd4d0e5e917cf53daa36f3c558e2",f.callServer,void 0,f.findSourceMapURL,"removeHooksWebAction"),P=(0,f.createServerReference)("60fbabb64346355eb2c28e1ab4eff1fc2d739463fd",f.callServer,void 0,f.findSourceMapURL,"updatePolicyParamsAction");var C=e.i(85881),_=e.i(12344),T=e.i(80060),U=e.i(2711),R=e.i(24578);let I={claude:{PreToolUse:"block",UserPromptSubmit:"block",PermissionRequest:"block",Stop:"block",SubagentStop:"block",PreCompact:"block",PostToolBatch:"block",ConfigChange:"block",UserPromptExpansion:"block",TaskCreated:"block",TaskCompleted:"block",TeammateIdle:"block",Elicitation:"block",ElicitationResult:"block",PostToolUse:"observe",PostToolUseFailure:"observe",SessionStart:"observe",Setup:"observe",SubagentStart:"observe",SessionEnd:"observe",StopFailure:"observe",PermissionDenied:"observe",Notification:"observe",InstructionsLoaded:"observe",CwdChanged:"observe",FileChanged:"observe",PostCompact:"observe",WorktreeRemove:"observe"},codex:{PreToolUse:"block",PermissionRequest:"block",UserPromptSubmit:"block",Stop:"block",SubagentStop:"block",PostToolUse:"observe",SessionStart:"observe",SubagentStart:"observe",PreCompact:"observe",PostCompact:"observe"},copilot:{PreToolUse:"block",Stop:"block",SubagentStop:"block",UserPromptSubmit:"block",PermissionRequest:"block",PostToolUse:"observe",SessionStart:"observe",SessionEnd:"observe",PostToolUseFailure:"observe",PreCompact:"observe",Notification:"observe"},cursor:{PreToolUse:"block",Stop:"block",UserPromptSubmit:"block",PostToolUse:"observe",SessionStart:"observe",SessionEnd:"observe"},opencode:{PreToolUse:"block",PostToolUse:"observe",SessionStart:"observe",SessionEnd:"observe",UserPromptSubmit:"observe",PermissionRequest:"observe"},pi:{PreToolUse:"block",UserPromptSubmit:"block",PostToolUse:"observe",SessionStart:"observe",SessionEnd:"observe",Stop:"observe"},hermes:{PreToolUse:"block",PostToolUse:"observe",SubagentStop:"observe",SessionStart:"observe",SessionEnd:"observe"},openclaw:{PreToolUse:"block",UserPromptSubmit:"block",Stop:"block",PostToolUse:"observe",SessionStart:"observe",SessionEnd:"observe",SubagentStop:"observe",PreCompact:"observe"},factory:{PreToolUse:"block",UserPromptSubmit:"block",Stop:"block",PreCompact:"block",PostToolUse:"observe",SubagentStop:"observe",SessionStart:"observe",SessionEnd:"observe",Notification:"observe"},devin:{PreToolUse:"block",UserPromptSubmit:"block",Stop:"block",PermissionRequest:"block",PostToolUse:"observe",SessionStart:"observe",SessionEnd:"observe"},antigravity:{PreToolUse:"block",Stop:"block",PostToolUse:"observe",UserPromptSubmit:"observe"},goose:{PreToolUse:"block",UserPromptSubmit:"observe",PostToolUse:"observe",SessionStart:"observe",SessionEnd:"observe"}};var E=e.i(34713),$=e.i(67881);function A({sessionId:e,transcriptPath:s,integration:r,cwd:n}){if(!e)return(0,t.jsx)("span",{className:"text-muted-foreground",children:"\\u2014"});let l=e?e.slice(0,8):"—",a="codex"===r||(s?.includes("/.codex/")??!1),i="copilot"===r||(s?.includes("/.copilot/session-state/")??!1),c="cursor"===r||(s?.includes("/.cursor/")??!1),d="opencode"===r||(s?.includes("/.local/share/opencode/")??!1)||(s?.includes("/.opencode/")??!1),m="pi"===r||(s?.includes("/.pi/")??!1);if(a||i||c||d||m){let s,r=n?(s=/^([A-Za-z]):[\\/](.*)$/.exec(n))?s[1]+"--"+s[2].replace(/[\\/]/g,"-"):n.replace(/[\\/]/g,"-"):a?"codex":i?"copilot":c?"cursor":d?"opencode":"pi";return(0,t.jsx)(o.default,{href:`/project/${encodeURIComponent(r)}/session/${encodeURIComponent(e)}`,className:"text-primary hover:underline font-mono",onClick:e=>e.stopPropagation(),children:l})}let u=s?function(e){let t=e.replace(/\\/g,"/").split("/").filter(Boolean);if(t.length<2)return null;let s=t[t.length-2];return!s||s.startsWith(".")?null:s}(s):null;return u?(0,t.jsx)(o.default,{href:`/project/${encodeURIComponent(u)}/session/${encodeURIComponent(e)}`,className:"text-primary hover:underline font-mono",onClick:e=>e.stopPropagation(),children:l}):(0,t.jsx)("span",{className:"text-muted-foreground font-mono",children:l})}function L({decision:e}){return"deny"===e?(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-[0.65rem] font-semibold tracking-wide uppercase bg-red-500/10 text-red-400 border border-red-500/20",children:[(0,t.jsx)(p.ShieldX,{className:"h-3 w-3"}),"Deny"]}):"instruct"===e?(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-[0.65rem] font-semibold tracking-wide uppercase bg-amber-500/10 text-amber-400 border border-amber-500/20",children:[(0,t.jsx)(u.ShieldAlert,{className:"h-3 w-3"}),"Instruct"]}):(0,t.jsxs)("span",{className:"inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-[0.65rem] font-semibold tracking-wide uppercase bg-emerald-500/10 text-emerald-400 border border-emerald-500/20",children:[(0,t.jsx)(x.ShieldCheck,{className:"h-3 w-3"}),"Allow"]})}function F({eventType:e}){return(0,t.jsx)("span",{className:"inline-flex items-center rounded px-1.5 py-0.5 text-[0.6rem] font-medium bg-muted text-muted-foreground border border-border/50",children:e})}function z({integration:e}){if(!e)return null;let s=(0,R.getCliLabel)(e),r=(0,R.getCliBadgeClasses)(e);return(0,t.jsx)("span",{className:`inline-flex items-center rounded px-1.5 py-0.5 text-[0.6rem] font-medium border ${r}`,title:`Agent CLI: ${s}`,children:s})}function D({mode:e}){let s="default"===e;return(0,t.jsx)("span",{title:e,className:`inline-block max-w-full truncate rounded px-1.5 py-0.5 align-middle text-[0.6rem] font-medium border ${s?"bg-sky-500/10 text-sky-400 border-sky-500/20":"bg-amber-500/10 text-amber-400 border-amber-500/20"}`,children:e})}function M({ms:e}){return(0,t.jsx)("span",{className:`font-mono text-[0.7rem] ${e>500?"text-red-400":e>100?"text-amber-400":"text-muted-foreground"}`,children:e<1e3?`${e}ms`:`${(e/1e3).toFixed(1)}s`})}function B({text:e,field:r}){let[o,l]=(0,s.useState)(!1),{capture:a}=(0,_.usePostHog)(),i=async t=>{t.stopPropagation(),a("activity_copy_clicked",{field:r??"unknown"});try{await navigator.clipboard.writeText(e),l(!0),setTimeout(()=>l(!1),1500)}catch{let t=document.createElement("textarea");t.value=e,t.style.position="fixed",t.style.opacity="0",document.body.appendChild(t),t.select(),document.execCommand("copy"),document.body.removeChild(t),l(!0),setTimeout(()=>l(!1),1500)}};return(0,t.jsx)("button",{onClick:i,className:"inline-flex items-center justify-center h-5 w-5 rounded hover:bg-muted/50 text-muted-foreground hover:text-foreground transition-colors",title:"Copy",children:o?(0,t.jsx)(n.Check,{className:"h-3 w-3 text-emerald-400"}):(0,t.jsx)(c.Copy,{className:"h-3 w-3"})})}function O({value:e,onChange:s}){return(0,t.jsx)("div",{className:"inline-flex items-center rounded-md border border-border bg-muted/30 p-0.5",children:[{label:"All",value:""},{label:"Allow",value:"allow"},{label:"Instruct",value:"instruct"},{label:"Deny",value:"deny"}].map(r=>(0,t.jsx)("button",{onClick:()=>s(r.value),className:`px-2.5 py-1 text-[0.65rem] font-medium rounded transition-all ${e===r.value?"deny"===r.value?"bg-red-500/15 text-red-400 shadow-sm":"allow"===r.value?"bg-emerald-500/15 text-emerald-400 shadow-sm":"instruct"===r.value?"bg-amber-500/15 text-amber-400 shadow-sm":"bg-background text-foreground shadow-sm":"text-muted-foreground hover:text-foreground"}`,children:r.label},r.value))})}function W({stats:e}){let s=e.totalEvents>0?e.denyCount/e.totalEvents*100:0,r=s.toFixed(s>=10?0:1),o=0===e.denyCount?"":s>=5?" is-deny":s>=2?" is-warn":"";return(0,t.jsxs)("div",{className:"stat-bar",role:"group","aria-label":"Activity stats",children:[(0,t.jsxs)("div",{className:"stat-cell",children:[(0,t.jsx)("span",{className:"eyebrow",children:"total events"}),(0,t.jsx)("span",{className:"value",children:e.totalEvents.toLocaleString()}),(0,t.jsx)("span",{className:"meta",children:"across all installed agents"})]}),(0,t.jsxs)("div",{className:"stat-cell",children:[(0,t.jsx)("span",{className:"eyebrow",children:"deny rate"}),(0,t.jsxs)("span",{className:`value${o}`,children:[r,"%"]}),(0,t.jsxs)("span",{className:"meta",children:[e.denyCount.toLocaleString()," of ",e.totalEvents.toLocaleString()," denied"]})]}),(0,t.jsxs)("div",{className:"stat-cell",children:[(0,t.jsx)("span",{className:"eyebrow",children:"top policy"}),(0,t.jsx)("span",{className:"value",style:{fontSize:16,fontWeight:500,color:e.topPolicy?"var(--accent-pink)":"var(--dim)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},title:e.topPolicy??void 0,children:e.topPolicy??"—"}),(0,t.jsx)("span",{className:"meta",children:"most-evaluated policy in scope"})]})]})}function H({item:e}){if("observe"!==function(e,t){if(!e||!t)return;let s=I[e];if(s)return s[t]}(e.integration,e.eventType))return null;let s=e.matchedPolicies??[];if(0===s.length)return null;let r=e.integration?(0,R.getCliLabel)(e.integration):"This CLI",o=s.map(e=>e.replace(/^(custom|\.failproofai-(project|user))\//,"")),n=1===o.length?o[0]:`${o.length} policies`,l="deny"===e.decision;return(0,t.jsxs)("div",{className:"sm:col-span-2 lg:col-span-3 mt-1 flex items-start gap-2 rounded border border-amber-500/30 bg-amber-500/5 px-2.5 py-2",children:[(0,t.jsx)(h,{className:"h-3.5 w-3.5 shrink-0 text-amber-500/80 mt-0.5","aria-hidden":"true"}),(0,t.jsxs)("p",{className:"text-[0.7rem] leading-relaxed text-muted-foreground",children:[(0,t.jsx)("span",{className:"font-medium text-foreground",children:l?"Not enforced.":"Ran, but cannot enforce here."})," ",(0,t.jsx)("span",{className:"font-mono",children:n})," ran on"," ",(0,t.jsx)("span",{className:"font-mono",children:e.eventType}),", but ",r," discards hook verdicts for this event",l?" — the action went ahead anyway.":", so a policy cannot block here."," ","Move the check to an event ",r," enforces on, such as"," ",(0,t.jsx)("span",{className:"font-mono",children:"PreToolUse"}),"."]})]})}function q({item:e}){return(0,t.jsx)("tr",{children:(0,t.jsx)("td",{colSpan:11,className:"px-0 py-0",children:(0,t.jsxs)("div",{className:"activity-detail animate-expand text-xs",children:[(0,t.jsxs)("span",{className:"activity-detail-eyebrow",children:[(0,t.jsx)("span",{"aria-hidden":"true",children:"▾"}),"event detail"]}),(0,t.jsxs)("div",{className:"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-x-8 gap-y-2",children:[(0,t.jsx)(H,{item:e}),(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"text-muted-foreground",children:"Session ID: "}),(0,t.jsx)("span",{className:"font-mono text-foreground",children:e.sessionId??"—"}),e.sessionId&&(0,t.jsx)(B,{text:e.sessionId,field:"session_id"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"text-muted-foreground",children:"CWD: "}),(0,t.jsx)("span",{className:"font-mono text-foreground",children:e.cwd??"—"}),e.cwd&&(0,t.jsx)(B,{text:e.cwd,field:"cwd"})]}),(0,t.jsxs)("div",{children:[(0,t.jsx)("span",{className:"text-muted-foreground",children:"Transcript: "}),(0,t.jsx)("span",{className:"font-mono text-foreground break-all",children:e.transcriptPath??"—"}),e.transcriptPath?.startsWith("opencode-db://")&&(0,t.jsx)("span",{className:"text-muted-foreground ml-1",children:"(stored in opencode DB)"})]})]}),e.policyNames&&e.policyNames.length>1&&(0,t.jsxs)("div",{style:{marginTop:8},children:[(0,t.jsx)("span",{className:"text-muted-foreground",children:"Policies: "}),(0,t.jsx)("span",{className:"font-mono text-foreground",children:e.policyNames.join(", ")})]}),e.reason&&(0,t.jsxs)("div",{style:{marginTop:8},children:[(0,t.jsx)("span",{className:"text-muted-foreground",children:"Full reason: "}),(0,t.jsx)("span",{className:"text-foreground",children:e.reason})]})]})})})}function X({hooksInstalled:e,onSwitchTab:r}){let{intervalSec:o}=(0,C.useAutoRefresh)(),{capture:n}=(0,_.usePostHog)(),a=(0,T.useUrlParams)(),i=(0,s.useRef)(!1),[c,d]=(0,s.useState)(()=>(0,U.paramToPage)(a.get("page"))),[u,x]=(0,s.useState)(null),[p,h]=(0,s.useState)(null),[b,f]=(0,s.useState)(()=>{let e=a.get("decision");return"allow"===e||"deny"===e||"instruct"===e?e:""}),[y,N]=(0,s.useState)(()=>a.get("event")??""),[k,S]=(0,s.useState)(()=>a.get("policy")??""),[w,P]=(0,s.useState)(()=>a.get("session")??""),[I,$]=(0,s.useState)(()=>{let e=a.get("cli");return(0,R.isKnownCli)(e)?e:""}),B=(0,s.useRef)(null),H=(0,s.useRef)(!0),K=(0,s.useRef)({filterDecision:b,filterEventType:y,filterPolicy:k,filterSessionId:w,filterCli:I});K.current={filterDecision:b,filterEventType:y,filterPolicy:k,filterSessionId:w,filterCli:I},(0,s.useEffect)(()=>{if(!i.current){i.current=!0;return}a.setAll({decision:b||void 0,event:y||void 0,policy:k||void 0,session:w||void 0,cli:I||void 0,page:(0,U.pageToParam)(c)})},[b,y,k,w,I,c]);let J=""!==b||""!==y||""!==k||""!==w||""!==I,G=(0,s.useCallback)(async e=>{try{let t,{filterDecision:s,filterEventType:r,filterPolicy:o,filterSessionId:n,filterCli:l}=K.current;t=""!==s||""!==r||""!==o||""!==n||""!==l?await (0,j.searchHookActivityAction)({decision:s||void 0,eventType:r||void 0,policyName:o||void 0,sessionId:n||void 0,integration:l||void 0},e):await v(e),x(t)}catch{}},[]);(0,s.useEffect)(()=>{G(c);let e=setInterval(()=>G(c),o>0?1e3*o:5e3);return()=>clearInterval(e)},[c,G,o]),(0,s.useEffect)(()=>(B.current&&clearTimeout(B.current),B.current=setTimeout(()=>{if(d(1),h(null),G(1),H.current){H.current=!1;return}n("activity_filter_changed",{active_filter_count:+(""!==b)+ +(""!==y)+ +(""!==k)+ +(""!==w)+ +(""!==I),has_decision:""!==b,has_event_type:""!==y,has_policy:""!==k,has_session:""!==w,has_cli:""!==I,decision:b||null,event_type:y||null,cli:I||null})},300),()=>{B.current&&clearTimeout(B.current)}),[b,y,k,w,I]);let V=u?.entries??[],Z=u?.totalPages??1;return(0,t.jsxs)(t.Fragment,{children:[u?.stats&&u.stats.totalEvents>0&&(0,t.jsx)("div",{style:{marginBottom:18},children:(0,t.jsx)(W,{stats:u.stats})}),(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"filter-bar",children:[(0,t.jsxs)("div",{className:"filter-group",children:[(0,t.jsx)("span",{className:"filter-label",children:"decision"}),(0,t.jsx)(O,{value:b,onChange:f})]}),(0,t.jsxs)("div",{className:"filter-group",children:[(0,t.jsx)("span",{className:"filter-label",children:"event"}),(0,t.jsxs)("select",{value:y,onChange:e=>N(e.target.value),className:"filter-input",children:[(0,t.jsx)("option",{value:"",children:"all events"}),(0,t.jsx)("option",{value:"PreToolUse",children:"PreToolUse"}),(0,t.jsx)("option",{value:"PostToolUse",children:"PostToolUse"}),(0,t.jsx)("option",{value:"SessionStart",children:"SessionStart"}),(0,t.jsx)("option",{value:"SessionEnd",children:"SessionEnd"}),(0,t.jsx)("option",{value:"UserPromptSubmit",children:"UserPromptSubmit"}),(0,t.jsx)("option",{value:"PermissionRequest",children:"PermissionRequest"})]})]}),(0,t.jsxs)("div",{className:"filter-group",children:[(0,t.jsx)("span",{className:"filter-label",children:"cli"}),(0,t.jsxs)("select",{value:I,onChange:e=>{let t=e.target.value;$(""===t||(0,R.isKnownCli)(t)?t:"")},className:"filter-input","aria-label":"Filter by CLI",children:[(0,t.jsx)("option",{value:"",children:"all clis"}),R.KNOWN_CLI_IDS.map(e=>(0,t.jsx)("option",{value:e,children:(0,R.getCliLabel)(e)},e))]})]}),(0,t.jsxs)("div",{className:"filter-group filter-group--grow",children:[(0,t.jsx)("span",{className:"filter-label",children:"policy"}),(0,t.jsx)("input",{type:"text",value:k,onChange:e=>S(e.target.value),placeholder:"filter by policy…",className:"filter-input"})]}),(0,t.jsxs)("div",{className:"filter-group filter-group--grow",children:[(0,t.jsx)("span",{className:"filter-label",children:"session"}),(0,t.jsx)("input",{type:"text",value:w,onChange:e=>P(e.target.value),placeholder:"filter by session…",className:"filter-input"})]}),J&&(0,t.jsx)("button",{type:"button",className:"filter-clear",onClick:()=>{f(""),N(""),$(""),S(""),P("")},"aria-label":"Clear all filters",children:"[ clear ]"})]}),0===V.length?(0,t.jsxs)("div",{className:"flex flex-col items-center justify-center py-16 px-4 text-center",children:[(0,t.jsx)(m.Shield,{className:"h-12 w-12 text-muted-foreground/30"}),!1===e?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("p",{className:"text-sm text-muted-foreground mt-4 font-medium",children:"Policies are not installed"}),(0,t.jsxs)("p",{className:"text-xs text-muted-foreground mt-1 max-w-sm",children:["Go to the"," ",(0,t.jsx)("button",{className:"underline hover:text-foreground transition-colors",onClick:()=>r?.("policies"),children:"Policies tab"})," ","and click ",(0,t.jsx)("span",{className:"font-mono bg-muted px-1 rounded",children:"Install"})," to enable policy monitoring."]})]}):(0,t.jsx)("p",{className:"text-sm text-muted-foreground mt-4",children:J?"No matching activity.":"Waiting for hook events…"})]}):(0,t.jsx)("div",{className:"overflow-x-auto activity-table-wrap",children:(0,t.jsxs)("table",{className:"w-full text-xs activity-table",style:{tableLayout:"fixed"},children:[(0,t.jsxs)("colgroup",{children:[(0,t.jsx)("col",{style:{width:32}}),(0,t.jsx)("col",{style:{width:"7%"}}),(0,t.jsx)("col",{style:{width:"9%"}}),(0,t.jsx)("col",{style:{width:"12%"}}),(0,t.jsx)("col",{style:{width:"11%"}}),(0,t.jsx)("col",{style:{width:"9%"}}),(0,t.jsx)("col",{style:{width:"13%"}}),(0,t.jsx)("col",{style:{width:"12%"}}),(0,t.jsx)("col",{style:{width:"11%"}}),(0,t.jsx)("col",{style:{width:"8%"}}),(0,t.jsx)("col",{style:{width:"8%"}})]}),(0,t.jsx)("thead",{className:"activity-thead",children:(0,t.jsxs)("tr",{children:[(0,t.jsx)("th",{className:"px-4 py-3"}),(0,t.jsx)("th",{className:"px-3 py-3 activity-th",children:"Time"}),(0,t.jsx)("th",{className:"px-3 py-3 activity-th",children:"Decision"}),(0,t.jsx)("th",{className:"px-3 py-3 activity-th",children:"Event"}),(0,t.jsx)("th",{className:"px-3 py-3 activity-th",children:"CLI"}),(0,t.jsx)("th",{className:"px-3 py-3 activity-th",children:"Tool"}),(0,t.jsx)("th",{className:"px-3 py-3 activity-th",children:"Policy"}),(0,t.jsx)("th",{className:"px-3 py-3 activity-th",children:"Reason"}),(0,t.jsx)("th",{className:"px-3 py-3 activity-th",children:"Mode"}),(0,t.jsx)("th",{className:"px-3 py-3 activity-th",children:"Duration"}),(0,t.jsx)("th",{className:"px-3 py-3 activity-th",children:"Session"})]})}),(0,t.jsx)("tbody",{className:"divide-y divide-border/30",children:V.map((e,r)=>{let o="deny"===e.decision,a=p===r,i="instruct"===e.decision;return(0,t.jsxs)(s.default.Fragment,{children:[(0,t.jsxs)("tr",{onClick:()=>{h(e=>{let t=e===r?null:r,s=V[r];return n("activity_row_toggled",{expanded:null!==t,decision:s?.decision??null,policy_name:s?.policyName??null,event_type:s?.eventType??null}),t})},className:`activity-data-row cursor-pointer transition-colors ${o?"bg-red-500/[0.03] hover:bg-red-500/[0.07] border-l-2 border-l-red-500/40":i?"bg-amber-500/[0.03] hover:bg-amber-500/[0.07] border-l-2 border-l-amber-500/40":r%2==0?"hover:bg-muted/30":"bg-muted/[0.04] hover:bg-muted/30"} ${a?"bg-muted/20":""}`,children:[(0,t.jsx)("td",{className:"px-4 py-2",children:(0,t.jsx)(l.ChevronDown,{className:`h-3.5 w-3.5 text-muted-foreground transition-transform duration-150 ${a?"rotate-0":"-rotate-90"}`})}),(0,t.jsx)("td",{className:"px-3 py-2 text-muted-foreground whitespace-nowrap",title:new Date(e.timestamp).toLocaleString(void 0,{month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"}),children:(0,E.formatRelativeTime)(e.timestamp)}),(0,t.jsx)("td",{className:"px-3 py-2",children:(0,t.jsx)(L,{decision:e.decision})}),(0,t.jsx)("td",{className:"px-3 py-2",children:(0,t.jsx)(F,{eventType:e.eventType})}),(0,t.jsx)("td",{className:"px-3 py-2",children:(0,t.jsx)(z,{integration:e.integration})}),(0,t.jsx)("td",{className:"px-3 py-2 font-mono text-foreground",children:e.toolName??"—"}),(0,t.jsx)("td",{className:"px-3 py-2 font-mono text-foreground",children:e.policyNames&&e.policyNames.length>1?(0,t.jsxs)("span",{title:e.policyNames.join(", "),children:[e.policyNames[0],(0,t.jsxs)("span",{className:"text-muted-foreground text-[0.6rem]",children:[" +",e.policyNames.length-1]})]}):e.policyName??"—"}),(0,t.jsx)("td",{className:"px-3 py-2 text-muted-foreground truncate",title:e.reason??"",children:e.reason??"—"}),(0,t.jsx)("td",{className:"px-3 py-2",children:e.permissionMode?(0,t.jsx)(D,{mode:e.permissionMode}):"—"}),(0,t.jsx)("td",{className:"px-3 py-2",children:(0,t.jsx)(M,{ms:e.durationMs})}),(0,t.jsx)("td",{className:"px-3 py-2",title:e.sessionId??"",children:(0,t.jsx)(A,{sessionId:e.sessionId,transcriptPath:e.transcriptPath,integration:e.integration,cwd:e.cwd})})]}),a&&(0,t.jsx)(q,{item:e})]},`${e.timestamp}-${r}`)})})]})}),(0,t.jsx)(g.default,{currentPage:c,totalPages:Z,onPageChange:e=>{n("activity_pagination_changed",{from_page:c,to_page:e,total_pages:Z}),d(e),h(null)}})]})]})}function K({enabled:e,onChange:s,disabled:r}){return(0,t.jsx)("button",{onClick:s,disabled:r,className:`relative inline-flex h-4 w-7 shrink-0 items-center rounded-full transition-colors disabled:opacity-40 ${e?"bg-emerald-500":"bg-muted-foreground/30"}`,"aria-label":e?"Disable policy":"Enable policy",children:(0,t.jsx)("span",{className:`inline-block h-3 w-3 rounded-full bg-white shadow transition-transform ${e?"translate-x-3.5":"translate-x-0.5"}`})})}function J({policy:e,onClose:r,onSave:o}){let n=e.params??{},l=e.currentParams??{},[a,i]=(0,s.useState)(()=>{let e={};for(let[t,s]of Object.entries(n)){let r=t in l?l[t]:s.default;e[t]=r}return e});(0,s.useEffect)(()=>{let e=e=>{"Escape"===e.key&&r()};return document.addEventListener("keydown",e),()=>document.removeEventListener("keydown",e)},[r]);let c=(e,t)=>{i(s=>({...s,[e]:t}))};return(0,t.jsx)("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50",onClick:e=>{e.target===e.currentTarget&&r()},children:(0,t.jsxs)("div",{className:"bg-card border border-border rounded-lg shadow-xl w-full max-w-lg mx-4 max-h-[80vh] flex flex-col",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-4 py-3 border-b border-border",children:[(0,t.jsxs)("div",{children:[(0,t.jsx)("p",{className:"text-sm font-mono font-semibold text-foreground",children:e.name}),(0,t.jsx)("p",{className:"text-xs text-muted-foreground mt-0.5",children:e.description})]}),(0,t.jsx)("button",{onClick:r,className:"text-muted-foreground hover:text-foreground transition-colors",children:(0,t.jsx)(b.X,{className:"h-4 w-4"})})]}),(0,t.jsx)("div",{className:"overflow-y-auto flex-1 px-4 py-4 space-y-4",children:Object.entries(n).map(([e,s])=>(0,t.jsxs)("div",{children:[(0,t.jsx)("label",{className:"block text-xs font-semibold text-foreground mb-1 font-mono",children:e}),(0,t.jsx)("p",{className:"text-[0.65rem] text-muted-foreground mb-1.5",children:s.description}),((e,s)=>{let r=a[e];if("boolean"===s.type)return(0,t.jsxs)("label",{className:"flex items-center gap-2 cursor-pointer",children:[(0,t.jsx)("input",{type:"checkbox",checked:!!r,onChange:t=>c(e,t.target.checked),className:"rounded border-border"}),(0,t.jsx)("span",{className:"text-xs text-muted-foreground",children:s.description})]});if("number"===s.type)return(0,t.jsx)("input",{type:"number",value:"number"==typeof r?r:"",onChange:t=>c(e,Number(t.target.value)),className:"w-full h-7 rounded border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-2 focus:ring-primary/40"});if("string[]"===s.type){let s=Array.isArray(r)?r.join("\n"):"";return(0,t.jsx)("textarea",{value:s,onChange:t=>c(e,t.target.value.split("\n").filter(e=>""!==e.trim())),rows:4,placeholder:"One entry per line",className:"w-full rounded border border-border bg-background px-2 py-1.5 text-xs text-foreground font-mono focus:outline-none focus:ring-2 focus:ring-primary/40 resize-y"})}if("pattern[]"===s.type){let s=Array.isArray(r)?r:[];return(0,t.jsxs)("div",{className:"space-y-1.5",children:[s.map((r,o)=>(0,t.jsxs)("div",{className:"flex gap-1.5 items-center",children:[(0,t.jsx)("input",{type:"text",value:r.regex,onChange:t=>{let r=[...s];r[o]={...r[o],regex:t.target.value},c(e,r)},placeholder:"regex",className:"flex-1 h-6 rounded border border-border bg-background px-2 text-xs font-mono focus:outline-none focus:ring-2 focus:ring-primary/40"}),(0,t.jsx)("input",{type:"text",value:r.label,onChange:t=>{let r=[...s];r[o]={...r[o],label:t.target.value},c(e,r)},placeholder:"label",className:"flex-1 h-6 rounded border border-border bg-background px-2 text-xs focus:outline-none focus:ring-2 focus:ring-primary/40"}),(0,t.jsx)("button",{onClick:()=>c(e,s.filter((e,t)=>t!==o)),className:"text-muted-foreground/50 hover:text-destructive transition-colors",children:(0,t.jsx)(b.X,{className:"h-3.5 w-3.5"})})]},o)),(0,t.jsx)("button",{onClick:()=>c(e,[...s,{regex:"",label:""}]),className:"text-xs text-primary hover:underline",children:"+ Add pattern"})]})}return(0,t.jsx)("input",{type:"text",value:"string"==typeof r?r:"",onChange:t=>c(e,t.target.value),className:"w-full h-7 rounded border border-border bg-background px-2 text-xs text-foreground focus:outline-none focus:ring-2 focus:ring-primary/40"})})(e,s)]},e))}),(0,t.jsxs)("div",{className:"flex items-center justify-end gap-2 px-4 py-3 border-t border-border",children:[(0,t.jsx)($.Button,{variant:"outline",size:"sm",onClick:r,className:"h-7 text-xs",children:"Cancel"}),(0,t.jsx)($.Button,{size:"sm",onClick:()=>o(a),className:"h-7 text-xs",children:"Save"})]})]})})}function G({message:e,onDismiss:s,onInstall:o,isPending:n}){let{capture:l}=(0,_.usePostHog)();return(0,r.createPortal)((0,t.jsxs)("div",{className:"fixed top-4 right-4 z-[9999] w-full max-w-sm",style:{animation:"slideInFromRight 0.25s ease-out"},children:[(0,t.jsx)("style",{children:`
2
- @keyframes slideInFromRight {
3
- from { transform: translateX(calc(100% + 1rem)); opacity: 0; }
4
- to { transform: translateX(0); opacity: 1; }
5
- }
6
- `}),(0,t.jsxs)("div",{className:"rounded-lg border border-red-500/40 bg-red-950/95 shadow-2xl shadow-red-900/40 overflow-hidden backdrop-blur-sm",children:[(0,t.jsx)("div",{className:"h-0.5 w-full bg-gradient-to-r from-red-600 via-red-400 to-red-600"}),(0,t.jsxs)("div",{className:"p-4",children:[(0,t.jsxs)("div",{className:"flex items-start gap-3",children:[(0,t.jsx)("div",{className:"shrink-0 mt-0.5 flex h-5 w-5 items-center justify-center rounded-full bg-red-500 ring-2 ring-red-500/30",children:(0,t.jsx)(b.X,{className:"h-3 w-3 text-white",strokeWidth:3})}),(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,t.jsx)("p",{className:"text-[0.65rem] font-bold uppercase tracking-widest text-red-400 mb-0.5",children:"Error"}),(0,t.jsx)("p",{className:"text-sm text-red-100 leading-snug",children:e})]}),(0,t.jsx)("button",{onClick:s,className:"shrink-0 -mt-0.5 -mr-0.5 rounded p-0.5 text-red-400/60 transition-colors hover:bg-red-500/20 hover:text-red-200","aria-label":"Dismiss",children:(0,t.jsx)(b.X,{className:"h-4 w-4"})})]}),(0,t.jsxs)("div",{className:"mt-3 flex gap-2",children:[(0,t.jsx)($.Button,{size:"sm",onClick:()=>{l("hooks_install_from_error_clicked",{error_message:e.slice(0,200)}),s(),o()},disabled:n,className:"h-7 flex-1 border-0 bg-red-500 px-3 text-xs font-semibold text-white hover:bg-red-400 disabled:opacity-50",children:"Install hooks"}),(0,t.jsx)($.Button,{variant:"ghost",size:"sm",onClick:s,className:"h-7 px-3 text-xs text-red-400 hover:bg-red-500/10 hover:text-red-200",children:"Dismiss"})]})]})]})]}),document.body)}function V({onHooksInstallChange:e}){let[r,o]=(0,s.useState)(null),[n,l]=(0,s.useTransition)(),[a,c]=(0,s.useState)(null),[u,x]=(0,s.useState)(null),[p,h]=(0,s.useState)(null),[b,g]=(0,s.useState)(()=>new Set),f=(0,s.useRef)(!1),{capture:v}=(0,_.usePostHog)(),j=(0,s.useCallback)((e,t)=>{v("action_error_displayed",{error_type:e,error_message:t.slice(0,200)}),c(t)},[v]),C=(0,s.useCallback)(async()=>{try{let t=await y();o(t),e?.(t.clis.some(e=>e.installed))}catch{}},[e]);(0,s.useEffect)(()=>{C()},[C]),(0,s.useEffect)(()=>{r&&(f.current?g(new Set(r.clis.filter(e=>e.installed).map(e=>e.id))):(f.current=!0,g(new Set(r.clis.filter(e=>e.installed||e.detected).map(e=>e.id)))))},[r?.clis]);let T=(0,s.useMemo)(()=>new Set((r?.clis??[]).filter(e=>e.installed).map(e=>e.id)),[r?.clis]),U=(0,s.useMemo)(()=>{let e=[],t=[];for(let s of r?.clis??[]){let r=b.has(s.id);r&&!T.has(s.id)&&e.push(s.id),!r&&T.has(s.id)&&t.push(s.id)}return{toInstall:e,toRemove:t}},[r?.clis,b,T]),I=U.toInstall.length>0||U.toRemove.length>0,E=(e,t)=>{r&&(o(s=>s?{...s,customPolicies:s.customPolicies?.map(s=>s.id===e?{...s,enabled:!t}:s),conventionPolicies:s.conventionPolicies.map(s=>({...s,policies:s.policies.map(s=>s.id===e?{...s,enabled:!t}:s)}))}:s),l(async()=>{try{await N(e,!t)}catch{j("custom_policy_toggle","Failed to save custom policy change."),C()}}))},A=()=>{let{toInstall:e,toRemove:t}=U;(0!==e.length||0!==t.length)&&(v("cli_install_remove_submitted",{to_install:e,to_remove:t,count_install:e.length,count_remove:t.length}),l(async()=>{try{c(null),e.length>0&&await S("user",e),t.length>0&&await w("user",t)}catch(e){j("cli_apply",e instanceof Error?e.message:"Failed to apply changes.")}finally{await C()}}))};if(!r)return(0,t.jsx)("div",{className:"flex items-center justify-center py-16",children:(0,t.jsxs)("span",{className:"text-sm text-muted-foreground",children:["Loading","…"]})});let L=r.clis.some(e=>e.installed),F=T.size,z=b.size,D=Array.from(new Set(r.policies.map(e=>e.category)));return(0,t.jsxs)(t.Fragment,{children:[p&&(0,t.jsx)(J,{policy:p,onClose:()=>{v("policy_config_modal_closed",{policy_name:p.name,action:"cancel"}),h(null)},onSave:e=>{if(!p)return;let t=p.name;h(null),l(async()=>{try{c(null),await P(t,e),await C()}catch(e){j("param_update",e instanceof Error?e.message:"Failed to save configuration.")}})}}),(0,t.jsxs)("div",{className:"bg-card border border-border rounded-lg overflow-hidden",children:[(0,t.jsxs)("div",{className:"flex items-center justify-between gap-4 px-5 py-3.5 border-b border-border/60 bg-muted/10",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3 min-w-0 flex-wrap",children:[(0,t.jsxs)("div",{className:"flex items-center gap-2",children:[(0,t.jsx)("span",{className:`h-2 w-2 rounded-full transition-shadow ${L?"bg-emerald-400 shadow-[0_0_8px_rgba(52,211,153,0.6)]":"bg-muted-foreground/40"}`,"aria-hidden":!0}),(0,t.jsx)("span",{className:"text-[0.65rem] uppercase tracking-[0.2em] font-mono text-foreground/90",children:"Integrations"})]}),(0,t.jsx)("span",{className:"text-[0.65rem] font-mono text-muted-foreground/40",children:"·"}),(0,t.jsxs)("div",{className:"text-[0.65rem] uppercase tracking-[0.2em] font-mono text-muted-foreground",children:[(0,t.jsx)("span",{className:"text-foreground tabular-nums",children:F.toString().padStart(2,"0")}),(0,t.jsxs)("span",{className:"opacity-50",children:[" / 0",r.clis.length," active"]})]}),I&&(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("span",{className:"text-[0.65rem] font-mono text-muted-foreground/40",children:"·"}),(0,t.jsxs)("span",{className:"inline-flex items-center gap-1.5 text-[0.65rem] uppercase tracking-[0.2em] font-mono text-pink-400",children:[(0,t.jsx)("span",{className:"h-1 w-1 rounded-full bg-pink-400 animate-pulse"}),U.toInstall.length+U.toRemove.length," pending"]})]})]}),(0,t.jsxs)("div",{className:"flex items-center gap-2 shrink-0",children:[(0,t.jsx)($.Button,{variant:"outline",size:"sm",onClick:()=>{let e=Array.from(T).filter(e=>b.has(e));0!==e.length&&(v("cli_reinstall_submitted",{cli_ids:e,count:e.length}),l(async()=>{try{c(null),await S("user",e)}catch(e){j("cli_reinstall",e instanceof Error?e.message:"Failed to reinstall.")}finally{await C()}}))},disabled:n||0===z,className:"text-xs h-7 px-3 font-mono",children:"Reinstall"}),(0,t.jsx)($.Button,{variant:"default",size:"sm",onClick:A,disabled:n||!I,className:"text-xs h-7 px-3 font-mono",children:"Apply changes"})]})]}),(0,t.jsx)("div",{className:"divide-y divide-border/30 border-b border-border/60",children:r.clis.map((e,s)=>{let o=b.has(e.id),l=T.has(e.id),a=o!==l,i=(0,R.getCliBadgeClasses)(e.id),c=i.split(" ").find(e=>e.startsWith("text-"))??"text-foreground";return(0,t.jsxs)("label",{className:`group relative flex items-center gap-3 pl-6 pr-5 py-3 cursor-pointer transition-colors hover:bg-muted/15 ${a?"bg-pink-500/[0.04]":""}`,children:[(0,t.jsx)("div",{className:`absolute left-0 top-0 bottom-0 w-[3px] ${c} bg-current transition-opacity ${o?"opacity-100":"opacity-25 group-hover:opacity-60"}`,"aria-hidden":!0}),(0,t.jsx)("div",{className:"font-mono text-[0.65rem] text-muted-foreground/40 tabular-nums w-6 select-none",children:(s+1).toString().padStart(2,"0")}),(0,t.jsxs)("div",{className:"relative shrink-0",children:[(0,t.jsx)("input",{type:"checkbox",checked:o,onChange:()=>{var t;return t=e.id,void g(e=>{let s=new Set(e),o=!s.has(t);o?s.add(t):s.delete(t);let n=r?.clis.find(e=>e.id===t);return v("cli_selection_toggled",{cli_id:t,checked:o,current_state:n?.installed?"installed":n?.detected?"detected":"inactive"}),s})},disabled:n,className:"sr-only peer","aria-label":`Toggle ${e.label}`}),(0,t.jsx)("div",{className:`h-[18px] w-[18px] rounded-sm border transition-all peer-focus-visible:ring-2 peer-focus-visible:ring-primary/40 ${o?"bg-primary border-primary":"bg-background/50 border-border group-hover:border-foreground/40"}`,children:o&&(0,t.jsx)("svg",{viewBox:"0 0 18 18",className:"h-full w-full text-primary-foreground",fill:"none","aria-hidden":!0,children:(0,t.jsx)("path",{d:"M4 9.5L7.5 12.5L14 6",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})})]}),(0,t.jsx)("div",{className:"min-w-[150px] shrink-0",children:(0,t.jsx)("div",{className:"text-sm font-medium text-foreground",children:e.label})}),(0,t.jsxs)("div",{className:"flex items-center gap-1.5 shrink-0",children:[l?(0,t.jsxs)("span",{className:`inline-flex items-center gap-1.5 px-2 py-0.5 rounded-sm text-[0.6rem] uppercase tracking-[0.15em] font-mono border ${i}`,children:[(0,t.jsx)("span",{className:"h-1 w-1 rounded-full bg-current shadow-[0_0_4px_currentColor]"}),"Active"]}):e.detected?(0,t.jsxs)("span",{className:"inline-flex items-center gap-1.5 px-2 py-0.5 rounded-sm text-[0.6rem] uppercase tracking-[0.15em] font-mono border border-border/60 text-muted-foreground/80 bg-muted/20",children:[(0,t.jsx)("span",{className:"h-1 w-1 rounded-full bg-current opacity-60"}),"Detected"]}):(0,t.jsx)("span",{className:"inline-flex items-center px-2 py-0.5 rounded-sm text-[0.6rem] uppercase tracking-[0.15em] font-mono border border-border/30 text-muted-foreground/40",children:"Inactive"}),a&&(0,t.jsx)("span",{className:"inline-flex items-center px-2 py-0.5 rounded-sm text-[0.6rem] uppercase tracking-[0.15em] font-mono border border-pink-500/40 text-pink-400 bg-pink-500/10",children:o?"+ install":"− remove"})]}),(0,t.jsx)("div",{className:"ml-auto hidden lg:block text-[0.7rem] font-mono text-muted-foreground/50 truncate max-w-[420px] group-hover:text-muted-foreground/80 transition-colors",title:e.settingsPath,children:e.settingsPath})]},e.id)})}),(0,t.jsxs)("div",{className:"flex items-center gap-2 px-4 py-2 border-b border-border/40 bg-muted/5",children:[(0,t.jsxs)("span",{className:"text-xs text-muted-foreground",children:[(0,t.jsx)("span",{className:"font-semibold text-foreground",children:r.enabledPolicies.length})," / ",r.policies.length+(r.customPolicies?.length??0)+(r.conventionPolicies?.reduce((e,t)=>e+t.policies.length,0)??0)," ","policies enabled"]}),L&&(0,t.jsxs)("span",{className:"text-[0.65rem] text-muted-foreground/60",children:["· shared across ",F," active CLI",1===F?"":"s"]})]}),a&&(0,t.jsx)("div",{className:"px-4 py-2 bg-red-500/10 border-b border-red-500/20 text-xs text-red-400",children:a}),u&&(0,t.jsx)(G,{message:u,onDismiss:()=>x(null),onInstall:A,isPending:n}),D.map(e=>{let s=r.policies.filter(t=>t.category===e),a=s.filter(e=>e.enabled).length;return(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-4 py-2.5 bg-muted/20 border-b border-border/50",children:[(0,t.jsx)("span",{className:"text-[0.7rem] font-semibold uppercase tracking-wider text-muted-foreground",children:e}),(0,t.jsxs)("span",{className:"text-[0.7rem] text-muted-foreground",children:[a," / ",s.length," enabled"]})]}),s.map(e=>(0,t.jsxs)("div",{className:"flex items-start gap-3 px-4 py-3 border-b border-border/20 hover:bg-muted/20 transition-colors",children:[(0,t.jsx)("div",{className:"mt-0.5 shrink-0",children:(0,t.jsx)(K,{enabled:e.enabled,onChange:()=>{var t,s;return t=e.name,s=e.enabled,void(!r||(!r.clis.some(e=>e.installed)?x("Policies are not installed. Install policies to continue."):(x(null),o(e=>e?{...e,policies:e.policies.map(e=>e.name===t?{...e,enabled:!s}:e),enabledPolicies:s?e.enabledPolicies.filter(e=>e!==t):[...e.enabledPolicies,t]}:e),l(async()=>{try{await k(t,!s)}catch{j("policy_toggle","Failed to save policy change."),C()}}))))},disabled:n})}),(0,t.jsxs)("div",{className:"flex items-center gap-1.5 min-w-0 w-56 shrink-0 mt-0.5",children:[(0,t.jsx)("span",{className:"text-xs font-mono text-foreground truncate",children:e.name}),e.beta&&(0,t.jsx)("span",{className:"shrink-0 text-[0.6rem] px-1 py-0.5 rounded border bg-violet-500/10 text-violet-400 border-violet-500/20",children:"beta"})]}),(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,t.jsx)("span",{className:"text-xs text-muted-foreground leading-relaxed",children:e.description}),e.eventScope&&(0,t.jsx)("span",{className:"block text-[0.65rem] text-muted-foreground/40 font-mono mt-0.5 hidden lg:block",children:e.eventScope}),e.params&&Object.keys(e.params).length>0&&(0,t.jsx)("div",{className:"flex flex-wrap gap-1 mt-1.5",children:Object.entries(e.params).map(([s,r])=>{let o=e.currentParams?.[s]??r.default,n=JSON.stringify(o)!==JSON.stringify(r.default);return(0,t.jsxs)("span",{className:`inline-flex items-center gap-1 font-mono text-[0.6rem] px-1.5 py-0.5 rounded border ${n?"bg-primary/10 text-primary/70 border-primary/20":"bg-muted/40 text-muted-foreground/55 border-border/40"}`,children:[(0,t.jsxs)("span",{className:"opacity-70",children:[s,":"]}),(0,t.jsx)("span",{children:function(e,t){if("string[]"===e||"pattern[]"===e){let s=Array.isArray(t)?t:[];return 0===s.length?"none":"pattern[]"===e?`${s.length} pattern${1!==s.length?"s":""}`:1===s.length?String(s[0]).slice(0,24):`${s.length} values`}return"boolean"===e?t?"on":"off":null==t||""===t?"—":String(t).slice(0,32)}(r.type,o)})]},s)})})]}),e.params&&Object.keys(e.params).length>0&&(0,t.jsx)("button",{className:"shrink-0 mt-0.5 text-muted-foreground hover:text-primary transition-colors",onClick:()=>{let t=Object.entries(e.params??{}).filter(([t,s])=>JSON.stringify(e.currentParams?.[t]??s.default)!==JSON.stringify(s.default)).length;v("policy_config_modal_opened",{policy_name:e.name,param_count:Object.keys(e.params??{}).length,has_customized_params:t>0,customized_count:t}),h(e)},title:"Edit parameters",children:(0,t.jsx)(d.Settings,{className:"h-3.5 w-3.5"})})]},e.name))]},e)}),(r.customPoliciesPaths?.length||r.customPoliciesPath)&&(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-4 py-2.5 bg-muted/20 border-b border-border/50",children:[(0,t.jsx)("span",{className:"text-[0.7rem] font-semibold uppercase tracking-wider text-muted-foreground",children:"Custom Policies"}),(0,t.jsxs)("span",{className:"text-[0.7rem] text-muted-foreground",children:[r.customPolicies?.length??0," detected"]})]}),(r.customPoliciesPaths??[r.customPoliciesPath]).map(e=>(0,t.jsxs)("div",{className:"flex items-center gap-3 px-4 py-3 border-b border-border/20",children:[(0,t.jsx)(i,{className:"h-3.5 w-3.5 text-muted-foreground shrink-0"}),(0,t.jsx)("span",{className:"text-xs font-mono text-muted-foreground truncate",children:e})]},e)),(0,t.jsxs)("div",{className:"flex items-start gap-2 px-4 py-2.5 border-b border-border/20 bg-muted/10",children:[(0,t.jsx)(m.Shield,{className:"h-3.5 w-3.5 text-muted-foreground/60 shrink-0 mt-0.5"}),(0,t.jsx)("p",{className:"text-[0.7rem] text-muted-foreground/70 leading-relaxed",children:"Re-run the install command to add, remove, or reorder files."})]}),r.customPolicies?.map(e=>(0,t.jsxs)("div",{className:"flex items-start gap-3 px-4 py-3 border-b border-border/20 hover:bg-muted/20 transition-colors",children:[(0,t.jsx)("div",{className:"mt-0.5 shrink-0",children:(0,t.jsx)(K,{enabled:e.enabled,onChange:()=>E(e.id,e.enabled),disabled:n})}),(0,t.jsx)("div",{className:"flex items-center gap-1.5 min-w-0 w-56 shrink-0 mt-0.5",children:(0,t.jsx)("span",{className:"text-xs font-mono text-foreground truncate",children:e.name})}),(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[e.description&&(0,t.jsx)("span",{className:"text-xs text-muted-foreground leading-relaxed",children:e.description}),e.eventScope&&(0,t.jsx)("span",{className:"block text-[0.65rem] text-muted-foreground/40 font-mono mt-0.5 hidden lg:block",children:e.eventScope})]})]},e.id))]}),r.conventionPolicies?.map(e=>(0,t.jsxs)("div",{children:[(0,t.jsxs)("div",{className:"flex items-center justify-between px-4 py-2.5 bg-muted/20 border-b border-border/50",children:[(0,t.jsxs)("span",{className:"text-[0.7rem] font-semibold uppercase tracking-wider text-muted-foreground",children:["Convention Policies — ","project"===e.scope?"Project":"User"]}),(0,t.jsxs)("span",{className:"text-[0.7rem] text-muted-foreground",children:[e.policies.length," hook",1===e.policies.length?"":"s"]})]}),(0,t.jsxs)("div",{className:"flex items-center gap-3 px-4 py-3 border-b border-border/20",children:[(0,t.jsx)(i,{className:"h-3.5 w-3.5 text-muted-foreground shrink-0"}),(0,t.jsx)("span",{className:"text-xs font-mono text-muted-foreground truncate",children:e.path})]}),0===e.policies.length?(0,t.jsxs)("div",{className:"flex items-start gap-2 px-4 py-2.5 border-b border-border/20 bg-muted/10",children:[(0,t.jsx)(m.Shield,{className:"h-3.5 w-3.5 text-muted-foreground/60 shrink-0 mt-0.5"}),(0,t.jsxs)("p",{className:"text-[0.7rem] text-muted-foreground/70 leading-relaxed",children:["No policies could be read from this file. It is still loaded at runtime — run ",(0,t.jsx)("span",{className:"font-mono",children:"failproofai policies"})," to see what it registers."]})]}):e.policies.map(s=>(0,t.jsxs)("div",{className:"flex items-start gap-3 px-4 py-3 border-b border-border/20 hover:bg-muted/20 transition-colors",children:[(0,t.jsx)("div",{className:"mt-0.5 shrink-0",children:(0,t.jsx)(K,{enabled:s.enabled,onChange:()=>E(s.id,s.enabled),disabled:n})}),(0,t.jsx)("div",{className:"flex items-center gap-1.5 min-w-0 w-56 shrink-0 mt-0.5",children:(0,t.jsx)("span",{className:"text-xs font-mono text-foreground truncate",children:s.name})}),(0,t.jsxs)("div",{className:"flex-1 min-w-0",children:[s.description&&(0,t.jsx)("span",{className:"text-xs text-muted-foreground leading-relaxed",children:s.description}),s.eventScope&&(0,t.jsx)("span",{className:"block text-[0.65rem] text-muted-foreground/40 font-mono mt-0.5 hidden lg:block",children:s.eventScope})]})]},`${e.path}:${s.name}`))]},e.path))]})]})}function Z({activeTab:e,onChange:s}){return(0,t.jsx)("div",{className:"tabs",style:{padding:0,marginBottom:24},children:[{id:"activity",label:"Activity"},{id:"policies",label:"Configure"}].map(r=>(0,t.jsx)("button",{type:"button",onClick:()=>s(r.id),className:`tab${e===r.id?" is-active":""}`,children:r.label.toLowerCase()},r.id))})}e.s(["default",0,function({initialTab:e="activity"}){let r=(0,T.useUrlParams)(),{capture:o}=(0,_.usePostHog)(),[n,l]=(0,s.useState)(e),[a,i]=(0,s.useState)(void 0),[c,d]=(0,s.useState)(null),[m,u]=(0,s.useState)([]);(0,s.useEffect)(()=>{y().then(e=>{i(e.clis.some(e=>e.installed)),d({enabled:e.enabledPolicies.length,total:e.policies.length+(e.customPolicies?.length??0)+(e.conventionPolicies?.reduce((e,t)=>e+t.policies.length,0)??0)}),u(e.clis.filter(e=>e.installed).map(e=>e.label))}).catch(()=>i(void 0))},[]);let x=0===m.length?"Policy evaluations":m.length<=3?`Policy evaluations across ${m.join(", ")}`:`Policy evaluations across ${m.length} agents`,p=e=>{e!==n&&o("policies_tab_switched",{tab:e,from_tab:n}),l(e),r.setAll({tab:"activity"===e?void 0:e})};return(0,t.jsx)("main",{className:"report",children:(0,t.jsxs)("section",{className:"section","data-screen-label":"policies",children:[(0,t.jsx)("h2",{style:{fontFamily:"var(--font-mono)",fontSize:24,fontWeight:600,letterSpacing:"-0.01em",color:"var(--ink)",margin:"0 0 16px"},children:"activity"===n?"Policies":"Configure Policies"}),"activity"===n?(0,t.jsxs)("div",{style:{display:"flex",alignItems:"flex-start",justifyContent:"space-between",gap:32,flexWrap:"wrap",margin:"0 0 24px"},children:[(0,t.jsxs)("div",{style:{fontFamily:"var(--font-mono)",fontSize:14,color:"var(--ink-2)",lineHeight:1.7,flex:"1 1 480px",minWidth:0},children:[x,c&&(0,t.jsxs)("span",{style:{color:"var(--dim)"},children:[" · ","enabled policies"," ",(0,t.jsxs)("span",{style:{color:"var(--ink)",fontVariantNumeric:"tabular-nums"},children:[c.enabled,"/",c.total]})]})]}),(0,t.jsxs)("div",{style:{display:"flex",flexDirection:"column",alignItems:"flex-end",gap:6,flex:"0 0 auto"},children:[(0,t.jsx)("span",{style:{fontFamily:"var(--font-mono)",fontSize:10,letterSpacing:"0.22em",textTransform:"uppercase",color:"var(--dim)"},children:"want to change which policies fire?"}),(0,t.jsx)("button",{type:"button",className:"btn btn-primary",onClick:()=>p("policies"),children:"[ configure policies → ]"})]})]}):(0,t.jsx)("p",{style:{fontFamily:"var(--font-mono)",fontSize:14,color:"var(--ink-2)",lineHeight:1.7,maxWidth:720,margin:"0 0 24px"},children:"switch policies on or off across your installed agent CLIs."}),(0,t.jsx)(Z,{activeTab:n,onChange:p}),"activity"===n?(0,t.jsx)(X,{hooksInstalled:a,onSwitchTab:p}):(0,t.jsx)(V,{onHooksInstallChange:i})]})})}],64245)}]);