failproofai 0.0.11-beta.1 → 0.0.11-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +3 -3
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  6. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  10. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  11. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  12. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  13. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  14. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  15. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  16. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  19. package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
  20. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  21. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  22. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +9 -9
  23. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  24. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  25. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  26. package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
  27. package/.next/standalone/.next/server/app/index.html +1 -1
  28. package/.next/standalone/.next/server/app/index.rsc +14 -14
  29. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  30. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
  31. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  32. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +9 -9
  33. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  34. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  35. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  37. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
  38. package/.next/standalone/.next/server/app/policies/page.js +1 -1
  39. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  40. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  41. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  42. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  43. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  44. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  45. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  46. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  47. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  48. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  49. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  51. package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d_ob4n._.js +1 -1
  52. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
  53. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-wn51s._.js +2 -2
  54. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__12y7xmt._.js → [root-of-the-server]__01as125._.js} +2 -2
  55. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0agrcb8._.js +2 -2
  56. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ehh6vp._.js +2 -2
  57. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__09i-rsi._.js → [root-of-the-server]__0k5n2kz._.js} +3 -3
  58. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0yaqw._.js +2 -2
  59. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0t8juvy._.js +2 -2
  60. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ts150~._.js +3 -0
  61. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0uylufv._.js +2 -2
  62. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ymlddl._.js +5 -5
  63. package/.next/standalone/.next/server/chunks/ssr/app_0cdqd9w._.js +1 -1
  64. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
  65. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +2 -2
  66. package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0a_7sdg.js +1 -1
  67. package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
  68. package/.next/standalone/.next/server/pages/404.html +1 -1
  69. package/.next/standalone/.next/server/pages/500.html +1 -1
  70. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  71. package/.next/standalone/.next/server/server-reference-manifest.json +9 -9
  72. package/.next/standalone/.next/static/chunks/07kpqoo7kuckx.js +6 -0
  73. package/.next/standalone/.next/static/chunks/{0zg~cpc5ysg6d.js → 0azb~vy9ds_uy.js} +1 -1
  74. package/.next/standalone/.next/static/chunks/{13-bt.3~irg00.js → 0bke.~atnsbeb.js} +1 -1
  75. package/.next/standalone/.next/static/chunks/{0_vk1wsgf~q3o.js → 0bv1oyxspkpkb.js} +1 -1
  76. package/.next/standalone/.next/static/chunks/{0wtiofzdt-l2u.js → 0dvhi-prcsh3~.js} +1 -1
  77. package/.next/standalone/.next/static/chunks/0spktq7xqab9h.js +1 -0
  78. package/.next/standalone/.next/static/chunks/{16vev.do1oho7.js → 118q3uljozd5z.js} +1 -1
  79. package/.next/standalone/.next/static/chunks/{07kfzzinhsl7e.js → 11w14gnqzprir.js} +1 -1
  80. package/.next/standalone/app/policies/hooks-client.tsx +102 -13
  81. package/.next/standalone/lib/claude-sessions.ts +181 -0
  82. package/.next/standalone/package.json +1 -1
  83. package/.next/standalone/server.js +1 -1
  84. package/README.md +2 -2
  85. package/bin/failproofai.mjs +229 -72
  86. package/dist/cli.mjs +3025 -1450
  87. package/lib/claude-sessions.ts +181 -0
  88. package/package.json +1 -1
  89. package/scripts/postinstall.mjs +89 -1
  90. package/src/audit/cache.ts +113 -0
  91. package/src/audit/cli-adapters/claude.ts +97 -0
  92. package/src/audit/cli-adapters/codex.ts +56 -0
  93. package/src/audit/cli-adapters/copilot.ts +51 -0
  94. package/src/audit/cli-adapters/cursor.ts +51 -0
  95. package/src/audit/cli-adapters/gemini.ts +51 -0
  96. package/src/audit/cli-adapters/index.ts +70 -0
  97. package/src/audit/cli-adapters/opencode.ts +52 -0
  98. package/src/audit/cli-adapters/pi.ts +51 -0
  99. package/src/audit/cli-adapters/shared.ts +85 -0
  100. package/src/audit/detectors/find-from-root.ts +27 -0
  101. package/src/audit/detectors/git-commit-no-verify.ts +22 -0
  102. package/src/audit/detectors/index.ts +33 -0
  103. package/src/audit/detectors/prefer-edit-over-read-cat.ts +31 -0
  104. package/src/audit/detectors/prefer-edit-over-sed-awk.ts +27 -0
  105. package/src/audit/detectors/prefer-write-over-heredoc.ts +36 -0
  106. package/src/audit/detectors/redundant-cd-cwd.ts +28 -0
  107. package/src/audit/detectors/reread-after-edit.ts +58 -0
  108. package/src/audit/detectors/sleep-polling-loop.ts +34 -0
  109. package/src/audit/index.ts +369 -0
  110. package/src/audit/replay.ts +121 -0
  111. package/src/audit/report.ts +349 -0
  112. package/src/audit/telemetry.ts +113 -0
  113. package/src/audit/types.ts +193 -0
  114. package/src/hooks/builtin-policies.ts +78 -0
  115. package/src/hooks/custom-hooks-loader.ts +19 -3
  116. package/src/hooks/first-run-nudge.ts +146 -0
  117. package/src/hooks/handler.ts +21 -102
  118. package/src/hooks/install-prompt.ts +34 -4
  119. package/src/hooks/manager.ts +72 -5
  120. package/src/hooks/policy-evaluator.ts +16 -1
  121. package/src/hooks/policy-types.ts +9 -0
  122. package/src/hooks/tool-name-canonicalize.ts +65 -0
  123. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__101v4_7._.js +0 -3
  124. package/.next/standalone/.next/static/chunks/03xhjwk6zhi8f.js +0 -1
  125. package/.next/standalone/.next/static/chunks/0wq808vlc8l04.js +0 -6
  126. package/src/auth/login.ts +0 -104
  127. package/src/auth/logout.ts +0 -50
  128. package/src/auth/token-store.ts +0 -64
  129. package/src/relay/daemon.ts +0 -362
  130. package/src/relay/pid.ts +0 -76
  131. package/src/relay/queue.ts +0 -225
  132. /package/.next/standalone/.next/static/{s5Nn6KwDdLpPhjG3l2WNf → tGVQM5SE3NvbVu0gbAJm7}/_buildManifest.js +0 -0
  133. /package/.next/standalone/.next/static/{s5Nn6KwDdLpPhjG3l2WNf → tGVQM5SE3NvbVu0gbAJm7}/_clientMiddlewareManifest.js +0 -0
  134. /package/.next/standalone/.next/static/{s5Nn6KwDdLpPhjG3l2WNf → tGVQM5SE3NvbVu0gbAJm7}/_ssgManifest.js +0 -0
@@ -19,15 +19,8 @@ import {
19
19
  CURSOR_EVENT_MAP,
20
20
  PI_EVENT_MAP,
21
21
  GEMINI_EVENT_MAP,
22
- GEMINI_TOOL_MAP,
23
- COPILOT_TOOL_MAP,
24
- CURSOR_TOOL_MAP,
25
- CODEX_TOOL_MAP,
26
- OPENCODE_TOOL_MAP,
27
- OPENCODE_TOOL_INPUT_MAP,
28
- PI_TOOL_MAP,
29
- PI_TOOL_INPUT_MAP,
30
22
  } from "./types";
23
+ import { canonicalizeToolName, canonicalizeToolInput } from "./tool-name-canonicalize";
31
24
  import type { PolicyFunction, PolicyResult } from "./policy-types";
32
25
  import { readMergedHooksConfig } from "./hooks-config";
33
26
  import { registerBuiltinPolicies } from "./builtin-policies";
@@ -77,80 +70,6 @@ function canonicalizeEventType(raw: string, cli: IntegrationType): HookEventType
77
70
  return raw as HookEventType;
78
71
  }
79
72
 
80
- /**
81
- * Canonicalize a per-CLI tool name to the Claude PascalCase form that builtin
82
- * policies match on (e.g. `Bash`, `Read`, `Write`, `Edit`). The registry filter
83
- * at policy-registry.ts:93-95 is case-sensitive `Array.includes`, so any
84
- * mismatch silently no-ops every Bash/Read/Write/Edit builtin.
85
- *
86
- * Per-CLI tool-name shapes (verified from in-repo evidence and vendor docs):
87
- * • Claude: PascalCase native — passthrough
88
- * • Codex: `Bash` PascalCase passthrough; `apply_patch` → `Edit`,
89
- * `write_stdin` → `Bash` via CODEX_TOOL_MAP
90
- * • Copilot: lowercase IDs (`bash`, `read`, `view`, …) — COPILOT_TOOL_MAP
91
- * • Cursor: PascalCase per Cursor docs but uses `Shell` for the bash-
92
- * equivalent — CURSOR_TOOL_MAP rewrites `Shell → Bash`; other
93
- * tool names already canonical and pass through
94
- * • OpenCode: lowercase IDs (`bash`, `read`, …) — OPENCODE_TOOL_MAP. The
95
- * OpenCode plugin shim ALSO canonicalizes inline as defense-in-
96
- * depth; both passes are idempotent. Handler-side coverage
97
- * here means a stale user-scope shim that pre-dates #337 still
98
- * gets the canonicalization, without forcing a re-install.
99
- * • Pi: lowercase IDs (`bash`, `read`, …) — PI_TOOL_MAP. Same dual-
100
- * canonicalization story as OpenCode (shim + handler).
101
- * • Gemini: snake_case — GEMINI_TOOL_MAP
102
- *
103
- * Unknown tool names (MCP `mcp_*`, third-party extensions, Skills) pass
104
- * through unchanged so non-builtin tooling isn't lost.
105
- */
106
- function canonicalizeToolName(raw: string | undefined, cli: IntegrationType): string | undefined {
107
- if (!raw) return raw;
108
- if (cli === "copilot") return COPILOT_TOOL_MAP[raw] ?? raw;
109
- if (cli === "cursor") return CURSOR_TOOL_MAP[raw] ?? raw;
110
- if (cli === "codex") return CODEX_TOOL_MAP[raw] ?? raw;
111
- if (cli === "gemini") return GEMINI_TOOL_MAP[raw] ?? raw;
112
- if (cli === "opencode") return OPENCODE_TOOL_MAP[raw] ?? raw;
113
- if (cli === "pi") return PI_TOOL_MAP[raw] ?? raw;
114
- return raw;
115
- }
116
-
117
- /**
118
- * Canonicalize per-CLI tool-input keys to the snake_case shape that builtin
119
- * policies read (e.g. `file_path`, `old_string`). OpenCode delivers args as
120
- * camelCase (`filePath`, `oldString`, `newString`, `replaceAll`); Pi delivers
121
- * `path` for Read/Write/Edit. Without translation, `getFilePath()` reads "" and
122
- * the path-checking builtins (`block-read-outside-cwd`, `block-env-files`,
123
- * `block-secrets-write`) silently no-op.
124
- *
125
- * Both CLIs' shims canonicalize inline before the JSON crosses to this binary.
126
- * Handler-side coverage here is defense-in-depth: a user-scope shim that pre-
127
- * dates #337 still passes the raw camelCase keys, and we want those installs
128
- * to start enforcing the moment failproofai upgrades — without requiring a
129
- * `failproofai policies --install --cli opencode` re-run.
130
- *
131
- * Idempotent: when the shim already canonicalized, the keys are snake_case
132
- * and the per-tool map's camelCase keys don't match, so the loop is a no-op.
133
- *
134
- * Tools outside the per-CLI map (MCP `mcp_*`, third-party extensions) pass
135
- * through unchanged so their schemas aren't corrupted.
136
- */
137
- function canonicalizeToolInput(
138
- toolName: string | undefined,
139
- rawInput: unknown,
140
- cli: IntegrationType,
141
- ): unknown {
142
- if (!toolName || !rawInput || typeof rawInput !== "object") return rawInput;
143
- let perToolMap: Record<string, string> | undefined;
144
- if (cli === "opencode") perToolMap = OPENCODE_TOOL_INPUT_MAP[toolName];
145
- else if (cli === "pi") perToolMap = PI_TOOL_INPUT_MAP[toolName];
146
- if (!perToolMap) return rawInput;
147
- const out: Record<string, unknown> = {};
148
- for (const [k, v] of Object.entries(rawInput as Record<string, unknown>)) {
149
- out[perToolMap[k] ?? k] = v;
150
- }
151
- return out;
152
- }
153
-
154
73
  export async function handleHookEvent(
155
74
  eventType: string,
156
75
  cli: IntegrationType = "claude",
@@ -160,6 +79,7 @@ export async function handleHookEvent(
160
79
  // Read stdin payload (Claude passes JSON)
161
80
  const MAX_STDIN_BYTES = 1_048_576; // 1 MB
162
81
  let payload = "";
82
+ let stdinOversized = false;
163
83
  try {
164
84
  payload = await new Promise<string>((resolve, reject) => {
165
85
  const chunks: string[] = [];
@@ -169,6 +89,7 @@ export async function handleHookEvent(
169
89
  totalBytes += Buffer.byteLength(chunk);
170
90
  if (totalBytes > MAX_STDIN_BYTES) {
171
91
  hookLogWarn(`stdin payload exceeds 1 MB for ${eventType}, discarding`);
92
+ stdinOversized = true;
172
93
  process.stdin.destroy();
173
94
  resolve("");
174
95
  return;
@@ -180,8 +101,20 @@ export async function handleHookEvent(
180
101
  // If stdin is already closed or not piped, resolve immediately
181
102
  if (process.stdin.readableEnded) resolve("");
182
103
  });
183
- } catch {
104
+ } catch (err) {
184
105
  hookLogWarn(`stdin read failed for ${eventType}`);
106
+ void trackHookEvent(getInstanceId(), "hook_stdin_error", {
107
+ event_type: eventType,
108
+ cli,
109
+ error_type: err instanceof Error ? err.name : "unknown",
110
+ });
111
+ }
112
+ if (stdinOversized) {
113
+ void trackHookEvent(getInstanceId(), "hook_stdin_error", {
114
+ event_type: eventType,
115
+ cli,
116
+ error_type: "oversized",
117
+ });
185
118
  }
186
119
 
187
120
  let parsed: Record<string, unknown> = {};
@@ -190,6 +123,11 @@ export async function handleHookEvent(
190
123
  parsed = JSON.parse(payload) as Record<string, unknown>;
191
124
  } catch {
192
125
  hookLogWarn(`payload parse failed for ${eventType} (${payload.length} bytes)`);
126
+ void trackHookEvent(getInstanceId(), "hook_payload_parse_error", {
127
+ event_type: eventType,
128
+ cli,
129
+ payload_size: payload.length,
130
+ });
193
131
  }
194
132
  }
195
133
 
@@ -340,25 +278,6 @@ export async function handleHookEvent(
340
278
  hookLogWarn("activity persistence failed");
341
279
  }
342
280
 
343
- // Enqueue for server relay — fire-and-forget, never blocks hook.
344
- // queue.ts is a no-op if the user is not logged in (no auth.json), and
345
- // sanitizes the entry before persisting (drops toolInput/transcriptPath,
346
- // hashes cwd, redacts known secret patterns in `reason`).
347
- try {
348
- const { appendToServerQueue } = await import("../relay/queue");
349
- appendToServerQueue(activityEntry);
350
- } catch {
351
- // Server queue is best-effort; fail-open
352
- }
353
-
354
- // Lazy-start relay daemon if user is logged in — ~1ms when already running
355
- try {
356
- const { ensureRelayRunning } = await import("../relay/daemon");
357
- ensureRelayRunning();
358
- } catch {
359
- // Relay is best-effort; hook must succeed regardless
360
- }
361
-
362
281
  // Fire PostHog telemetry for decisions that affect Claude's behavior
363
282
  if (result.decision === "deny" || result.decision === "instruct") {
364
283
  try {
@@ -13,6 +13,8 @@ import * as readline from "node:readline";
13
13
  import { BUILTIN_POLICIES } from "./builtin-policies";
14
14
  import { detectInstalledClis, getIntegration } from "./integrations";
15
15
  import { INTEGRATION_TYPES, type IntegrationType } from "./types";
16
+ import { trackHookEvent } from "./hook-telemetry";
17
+ import { getInstanceId } from "../../lib/telemetry-id";
16
18
 
17
19
  interface SelectItem {
18
20
  name: string;
@@ -51,9 +53,29 @@ export async function resolveTargetClis(
51
53
  explicit?: IntegrationType[],
52
54
  action: CliPromptAction = "install",
53
55
  ): Promise<IntegrationType[]> {
54
- if (explicit && explicit.length > 0) return [...new Set(explicit)];
56
+ const detected = explicit && explicit.length > 0 ? [] : detectInstalledClis();
57
+ const stdinIsTty = !!process.stdin.isTTY;
58
+ const explicitList = explicit && explicit.length > 0 ? [...new Set(explicit)] : [];
59
+
60
+ const fireDetectionEvent = (
61
+ selected: IntegrationType[],
62
+ resolutionMode: "explicit" | "single_detected" | "all_detected" | "interactive_prompt" | "defaulted_to_claude",
63
+ ): void => {
64
+ void trackHookEvent(getInstanceId(), "cli_detection_summary", {
65
+ action,
66
+ detected_clis: detected,
67
+ explicit_clis: explicitList,
68
+ selected_clis: selected,
69
+ defaulted_to_claude: resolutionMode === "defaulted_to_claude",
70
+ stdin_is_tty: stdinIsTty,
71
+ resolution_mode: resolutionMode,
72
+ });
73
+ };
55
74
 
56
- const detected = detectInstalledClis();
75
+ if (explicit && explicit.length > 0) {
76
+ fireDetectionEvent(explicitList, "explicit");
77
+ return explicitList;
78
+ }
57
79
 
58
80
  if (detected.length === 0) {
59
81
  if (action === "uninstall") {
@@ -63,12 +85,14 @@ export async function resolveTargetClis(
63
85
  "\x1B[33mWarning: no agent CLI binary found in PATH (claude, codex, copilot, cursor-agent, opencode, pi, gemini). " +
64
86
  "Defaulting to Claude Code; nothing will be removed if no settings file exists.\x1B[0m",
65
87
  );
88
+ fireDetectionEvent(["claude"], "defaulted_to_claude");
66
89
  return ["claude"];
67
90
  }
68
91
  console.log(
69
92
  "\x1B[33mWarning: no agent CLI binary found in PATH (claude, codex, copilot, cursor-agent, opencode, pi, gemini). " +
70
93
  "Defaulting to Claude Code; hooks will activate when an agent is installed.\x1B[0m",
71
94
  );
95
+ fireDetectionEvent(["claude"], "defaulted_to_claude");
72
96
  return ["claude"];
73
97
  }
74
98
 
@@ -76,13 +100,19 @@ export async function resolveTargetClis(
76
100
  const integration = getIntegration(detected[0]);
77
101
  const verb = action === "uninstall" ? "removing hooks from" : "installing hooks for";
78
102
  console.log(`Detected ${integration.displayName}; ${verb} it.`);
103
+ fireDetectionEvent(detected, "single_detected");
79
104
  return detected;
80
105
  }
81
106
 
82
107
  // Multiple detected. Prompt or default.
83
- if (!process.stdin.isTTY) return detected; // non-interactive: install/remove for all detected
108
+ if (!process.stdin.isTTY) {
109
+ fireDetectionEvent(detected, "all_detected");
110
+ return detected;
111
+ }
84
112
 
85
- return promptCliTargetSelection(detected, action);
113
+ const selected = await promptCliTargetSelection(detected, action);
114
+ fireDetectionEvent(selected, "interactive_prompt");
115
+ return selected;
86
116
  }
87
117
 
88
118
  /** Selectable row in the CLI target menu. Exported for unit tests. */
@@ -127,6 +127,13 @@ export async function installHooks(
127
127
  for (const cliId of selectedClis) {
128
128
  const integration = getIntegration(cliId);
129
129
  if (!integration.scopes.includes(scope)) {
130
+ try {
131
+ await trackHookEvent(getInstanceId(), "scope_validation_failed", {
132
+ cli: cliId,
133
+ scope,
134
+ supported_scopes: integration.scopes,
135
+ });
136
+ } catch {}
130
137
  throw new CliError(
131
138
  `Scope "${scope}" is not supported by ${integration.displayName}. ` +
132
139
  `Valid scopes: ${integration.scopes.join(", ")}`
@@ -171,10 +178,23 @@ export async function installHooks(
171
178
  try {
172
179
  validatedHooks = await loadCustomHooks(configToWrite.customPoliciesPath, { strict: true });
173
180
  } catch (err) {
174
- console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
181
+ const msg = err instanceof Error ? err.message : String(err);
182
+ try {
183
+ await trackHookEvent(getInstanceId(), "custom_policy_validation_failed", {
184
+ scope,
185
+ error_type: /not found/i.test(msg) ? "file_not_found" : "load_error",
186
+ });
187
+ } catch {}
188
+ console.error(`Error: ${msg}`);
175
189
  process.exit(1);
176
190
  }
177
191
  if (validatedHooks.length === 0) {
192
+ try {
193
+ await trackHookEvent(getInstanceId(), "custom_policy_validation_failed", {
194
+ scope,
195
+ error_type: "no_hooks_registered",
196
+ });
197
+ } catch {}
178
198
  console.error(
179
199
  `Error: no hooks registered in ${customPoliciesPath}. ` +
180
200
  `Make sure your file calls customPolicies.add(...) at least once.`,
@@ -198,10 +218,26 @@ export async function installHooks(
198
218
  for (const cliId of selectedClis) {
199
219
  const integration = getIntegration(cliId);
200
220
  const settingsPath = integration.getSettingsPath(scope, cwd);
201
- const settings = integration.readSettings(settingsPath);
202
- integration.writeHookEntries(settings, binaryPath, scope);
203
- integration.writeSettings(settingsPath, settings);
204
- writtenSettingsPaths.push({ cli: cliId, path: settingsPath });
221
+ try {
222
+ const settings = integration.readSettings(settingsPath);
223
+ integration.writeHookEntries(settings, binaryPath, scope);
224
+ integration.writeSettings(settingsPath, settings);
225
+ writtenSettingsPaths.push({ cli: cliId, path: settingsPath });
226
+ } catch (err) {
227
+ const errorType = err instanceof Error && /EACCES|EPERM/.test(err.message)
228
+ ? "permission_denied"
229
+ : err instanceof Error && /ENOENT|ENOTDIR/.test(err.message)
230
+ ? "path_not_found"
231
+ : "write_error";
232
+ try {
233
+ await trackHookEvent(getInstanceId(), "hook_write_failed", {
234
+ cli: cliId,
235
+ scope,
236
+ error_type: errorType,
237
+ });
238
+ } catch {}
239
+ throw err;
240
+ }
205
241
  }
206
242
 
207
243
  // Telemetry: track successful hook installation (with diff vs previous config)
@@ -228,6 +264,20 @@ export async function installHooks(
228
264
  param_policy_names: configToWrite.policyParams ? Object.keys(configToWrite.policyParams) : [],
229
265
  command_format: scope === "project" ? "npx" : "absolute",
230
266
  });
267
+
268
+ if (includeBeta) {
269
+ const betaNames = new Set(BUILTIN_POLICIES.filter((p) => p.beta).map((p) => p.name));
270
+ const installedBeta = selectedPolicies.filter((p) => betaNames.has(p));
271
+ if (installedBeta.length > 0) {
272
+ await trackHookEvent(distinctId, "beta_policies_installed", {
273
+ scope,
274
+ cli: selectedClis,
275
+ beta_count: installedBeta.length,
276
+ beta_policy_names: installedBeta,
277
+ ...(source ? { source } : {}),
278
+ });
279
+ }
280
+ }
231
281
  } catch {
232
282
  // Telemetry is best-effort — never block the operation
233
283
  }
@@ -257,6 +307,13 @@ export async function installHooks(
257
307
  console.log(`Having hooks in multiple scopes may cause duplicate policy evaluation.`);
258
308
  console.log(`Use \`failproofai policies --uninstall --scope ${duplicates[0]}\` to remove the other installation,`);
259
309
  console.log(`or \`failproofai policies\` to see all scopes.`);
310
+ try {
311
+ await trackHookEvent(getInstanceId(), "multi_scope_warning_shown", {
312
+ new_scope: scope,
313
+ existing_scopes: duplicates,
314
+ cli: selectedClis,
315
+ });
316
+ } catch {}
260
317
  }
261
318
  }
262
319
 
@@ -558,11 +615,21 @@ export async function listHooks(cwd?: string): Promise<void> {
558
615
 
559
616
  // Warn about unknown policyParams keys
560
617
  if (config.policyParams) {
618
+ const unknownKeys: string[] = [];
561
619
  for (const key of Object.keys(config.policyParams)) {
562
620
  if (!builtinPolicyNames.has(key)) {
563
621
  console.log(` \x1B[33mWarning: unknown policyParams key "${key}" — possible typo\x1B[0m`);
622
+ unknownKeys.push(key);
564
623
  }
565
624
  }
625
+ if (unknownKeys.length > 0) {
626
+ try {
627
+ await trackHookEvent(getInstanceId(), "policy_params_validation_warning", {
628
+ unknown_keys_count: unknownKeys.length,
629
+ unknown_keys: unknownKeys,
630
+ });
631
+ } catch {}
632
+ }
566
633
  }
567
634
 
568
635
  // Custom Policies section
@@ -7,6 +7,8 @@ import type { PolicyContext, HooksConfig } from "./policy-types";
7
7
  import { BUILTIN_POLICIES } from "./builtin-policies";
8
8
  import { DEFAULT_POLICY_NAMESPACE, getPoliciesForEvent, normalizePolicyName } from "./policy-registry";
9
9
  import { hookLogInfo, hookLogWarn } from "./hook-logger";
10
+ import { trackHookEvent } from "./hook-telemetry";
11
+ import { getInstanceId } from "../../lib/telemetry-id";
10
12
 
11
13
  function appendHint(baseReason: string, hint: unknown): string {
12
14
  const base = baseReason.trim();
@@ -107,7 +109,20 @@ export async function evaluatePolicies(
107
109
  try {
108
110
  result = await policy.fn(ctx);
109
111
  } catch (err) {
110
- hookLogWarn(`policy "${policy.name}" threw: ${err instanceof Error ? err.message : String(err)}`);
112
+ const msg = err instanceof Error ? err.message : String(err);
113
+ hookLogWarn(`policy "${policy.name}" threw: ${msg}`);
114
+ // Custom hooks are wrapped in handler.ts with their own try/catch that
115
+ // emits custom_hook_error. Anything reaching here is a builtin policy
116
+ // crash — track separately so we can surface regressions in builtins.
117
+ const isCustom = policy.name.startsWith("custom/") || policy.name.startsWith(".failproofai-");
118
+ if (!isCustom) {
119
+ void trackHookEvent(getInstanceId(), "policy_evaluation_error", {
120
+ policy_name: policy.name,
121
+ event_type: eventType,
122
+ cli: session?.cli ?? null,
123
+ error_type: err instanceof Error ? err.name : "unknown",
124
+ });
125
+ }
111
126
  continue;
112
127
  }
113
128
 
@@ -54,6 +54,15 @@ export interface BuiltinPolicyDefinition {
54
54
  category: string;
55
55
  beta?: boolean;
56
56
  params?: PolicyParamsSchema;
57
+ /** User-facing past-tense phrase used in `failproofai audit` output.
58
+ * Frames the agent's action as something the user observes after-the-fact,
59
+ * e.g. "Tried to push to main branch" or "Redacted JWT from tool output".
60
+ * Falls back to `description` when omitted. */
61
+ displayTitle?: string;
62
+ /** One short clause describing the consequence of the action, used as a
63
+ * secondary line in the audit report. e.g. "Could leak code from neighboring
64
+ * repos to the model." */
65
+ impact?: string;
57
66
  }
58
67
 
59
68
  export interface CustomHook {
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Per-CLI canonicalization of tool names and tool-input keys.
3
+ *
4
+ * Extracted from handler.ts so the audit replay engine and the live hook
5
+ * handler share one implementation. Re-importing this module from
6
+ * `src/audit/cli-adapters/*.ts` keeps the per-CLI maps in one place.
7
+ */
8
+ import type { IntegrationType } from "./types";
9
+ import {
10
+ CODEX_TOOL_MAP,
11
+ COPILOT_TOOL_MAP,
12
+ CURSOR_TOOL_MAP,
13
+ OPENCODE_TOOL_MAP,
14
+ OPENCODE_TOOL_INPUT_MAP,
15
+ PI_TOOL_MAP,
16
+ PI_TOOL_INPUT_MAP,
17
+ GEMINI_TOOL_MAP,
18
+ } from "./types";
19
+
20
+ /**
21
+ * Canonicalize a per-CLI tool name to the Claude PascalCase form that builtin
22
+ * policies match on (e.g. `Bash`, `Read`, `Write`, `Edit`). Unknown tool names
23
+ * (MCP `mcp_*`, third-party extensions, Skills) pass through unchanged.
24
+ */
25
+ export function canonicalizeToolName(
26
+ raw: string | undefined,
27
+ cli: IntegrationType,
28
+ ): string | undefined {
29
+ if (!raw) return raw;
30
+ if (cli === "copilot") return COPILOT_TOOL_MAP[raw] ?? raw;
31
+ if (cli === "cursor") return CURSOR_TOOL_MAP[raw] ?? raw;
32
+ if (cli === "codex") return CODEX_TOOL_MAP[raw] ?? raw;
33
+ if (cli === "gemini") return GEMINI_TOOL_MAP[raw] ?? raw;
34
+ if (cli === "opencode") return OPENCODE_TOOL_MAP[raw] ?? raw;
35
+ if (cli === "pi") return PI_TOOL_MAP[raw] ?? raw;
36
+ return raw;
37
+ }
38
+
39
+ /**
40
+ * Canonicalize per-CLI tool-input keys to the snake_case shape that builtin
41
+ * policies read (e.g. `file_path`, `old_string`). OpenCode delivers args as
42
+ * camelCase; Pi delivers `path` for Read/Write/Edit. Idempotent — when already
43
+ * canonical the loop is a no-op.
44
+ */
45
+ export function canonicalizeToolInput(
46
+ toolName: string | undefined,
47
+ rawInput: unknown,
48
+ cli: IntegrationType,
49
+ ): unknown {
50
+ // Arrays are objects too — pass them through verbatim instead of letting
51
+ // Object.entries flatten them into a numeric-keyed plain object (which would
52
+ // silently corrupt array-shaped tool inputs).
53
+ if (!toolName || !rawInput || typeof rawInput !== "object" || Array.isArray(rawInput)) {
54
+ return rawInput;
55
+ }
56
+ let perToolMap: Record<string, string> | undefined;
57
+ if (cli === "opencode") perToolMap = OPENCODE_TOOL_INPUT_MAP[toolName];
58
+ else if (cli === "pi") perToolMap = PI_TOOL_INPUT_MAP[toolName];
59
+ if (!perToolMap) return rawInput;
60
+ const out: Record<string, unknown> = {};
61
+ for (const [k, v] of Object.entries(rawInput as Record<string, unknown>)) {
62
+ out[perToolMap[k] ?? k] = v;
63
+ }
64
+ return out;
65
+ }
@@ -1,3 +0,0 @@
1
- module.exports=[18622,(a,b,c)=>{b.exports=a.x("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js",()=>require("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js"))},56704,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/work-async-storage.external.js",()=>require("next/dist/server/app-render/work-async-storage.external.js"))},32319,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/work-unit-async-storage.external.js",()=>require("next/dist/server/app-render/work-unit-async-storage.external.js"))},20635,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/action-async-storage.external.js",()=>require("next/dist/server/app-render/action-async-storage.external.js"))},24725,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/after-task-async-storage.external.js",()=>require("next/dist/server/app-render/after-task-async-storage.external.js"))},43285,(a,b,c)=>{b.exports=a.x("next/dist/server/app-render/dynamic-access-async-storage.external.js",()=>require("next/dist/server/app-render/dynamic-access-async-storage.external.js"))},42602,(a,b,c)=>{"use strict";b.exports=a.r(18622)},87924,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactJsxRuntime},72131,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].React},38783,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactServerDOMTurbopackClient},9270,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.AppRouterContext},36313,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.HooksClientContext},18341,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored.contexts.ServerInsertedHtml},35112,(a,b,c)=>{"use strict";b.exports=a.r(42602).vendored["react-ssr"].ReactDOM},66036,a=>{"use strict";a.s(["captureClientEvent",0,function(a,b){},"setClientTelemetryConfig",0,function(a){}])},88347,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d,e,f={ACTION_HMR_REFRESH:function(){return l},ACTION_NAVIGATE:function(){return i},ACTION_REFRESH:function(){return h},ACTION_RESTORE:function(){return j},ACTION_SERVER_ACTION:function(){return m},ACTION_SERVER_PATCH:function(){return k},PrefetchKind:function(){return n},ScrollBehavior:function(){return o}};for(var g in f)Object.defineProperty(c,g,{enumerable:!0,get:f[g]});let h="refresh",i="navigate",j="restore",k="server-patch",l="hmr-refresh",m="server-action";var n=((d={}).AUTO="auto",d.FULL="full",d),o=((e={})[e.Default=0]="Default",e[e.NoScroll=1]="NoScroll",e);("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},46058,(a,b,c)=>{"use strict";function d(a){if("function"!=typeof WeakMap)return null;var b=new WeakMap,c=new WeakMap;return(d=function(a){return a?c:b})(a)}c._=function(a,b){if(!b&&a&&a.__esModule)return a;if(null===a||"object"!=typeof a&&"function"!=typeof a)return{default:a};var c=d(b);if(c&&c.has(a))return c.get(a);var e={__proto__:null},f=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var g in a)if("default"!==g&&Object.prototype.hasOwnProperty.call(a,g)){var h=f?Object.getOwnPropertyDescriptor(a,g):null;h&&(h.get||h.set)?Object.defineProperty(e,g,h):e[g]=a[g]}return e.default=a,c&&c.set(a,e),e}},67009,(a,b,c)=>{"use strict";function d(a){return null!==a&&"object"==typeof a&&"then"in a&&"function"==typeof a.then}Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"isThenable",{enumerable:!0,get:function(){return d}})},90841,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={dispatchAppRouterAction:function(){return i},dispatchGestureState:function(){return j},refreshOnInstantNavigationUnlock:function(){return h},useActionQueue:function(){return k}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});let f=a.r(46058)._(a.r(72131)),g=a.r(67009);a.r(88347);function h(){}function i(a){!0;throw Object.defineProperty(Error("Internal Next.js error: Router action dispatched before initialization."),"__NEXT_ERROR_CODE",{value:"E668",enumerable:!1,configurable:!0})}function j(a){!0;throw Object.defineProperty(Error("Internal Next.js error: Router action dispatched before initialization."),"__NEXT_ERROR_CODE",{value:"E668",enumerable:!1,configurable:!0})}function k(a){let[b,c]=f.default.useState(a.state),[d,e]=(0,f.useOptimistic)(b),h=(0,f.useMemo)(()=>d,[d]);return(0,g.isThenable)(h)?(0,f.use)(h):h}("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},20611,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"callServer",{enumerable:!0,get:function(){return g}});let d=a.r(72131),e=a.r(88347),f=a.r(90841);async function g(a,b){return new Promise((c,g)=>{(0,d.startTransition)(()=>{(0,f.dispatchAppRouterAction)({type:e.ACTION_SERVER_ACTION,actionId:a,actionArgs:b,resolve:c,reject:g})})})}("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},1722,(a,b,c)=>{"use strict";let d;Object.defineProperty(c,"__esModule",{value:!0}),Object.defineProperty(c,"findSourceMapURL",{enumerable:!0,get:function(){return d}});("function"==typeof c.default||"object"==typeof c.default&&null!==c.default)&&void 0===c.default.__esModule&&(Object.defineProperty(c.default,"__esModule",{value:!0}),Object.assign(c.default,c),b.exports=c.default)},5050,(a,b,c)=>{"use strict";Object.defineProperty(c,"__esModule",{value:!0});var d={callServer:function(){return f.callServer},createServerReference:function(){return h.createServerReference},findSourceMapURL:function(){return g.findSourceMapURL}};for(var e in d)Object.defineProperty(c,e,{enumerable:!0,get:d[e]});let f=a.r(20611),g=a.r(1722),h=a.r(38783)},66014,a=>{"use strict";var b=a.i(5050);let c=(0,b.createServerReference)("0014ee7d8223527f1163c06ddaa02e702fda5fde5f",b.callServer,void 0,b.findSourceMapURL,"getTelemetryConfig");a.s(["getTelemetryConfig",0,c])},3171,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(66014),e=a.i(66036);a.s(["default",0,function({error:a,reset:f}){return(0,c.useEffect)(()=>{(0,d.getTelemetryConfig)().then(b=>{(0,e.setClientTelemetryConfig)(b),(0,e.captureClientEvent)("client_error",{error_message:a.message,error_name:a.name,error_digest:a.digest,boundary:"global"})}).catch(()=>{})},[a]),(0,b.jsx)("html",{children:(0,b.jsx)("body",{children:(0,b.jsx)("main",{style:{minHeight:"100vh",display:"flex",alignItems:"center",justifyContent:"center",background:"#031035",color:"#f8fafc",fontFamily:"system-ui, sans-serif"},children:(0,b.jsxs)("div",{style:{textAlign:"center",padding:"2rem",border:"1px solid rgba(239,68,68,0.4)",borderRadius:"0.5rem",maxWidth:"500px"},children:[(0,b.jsx)("h2",{style:{color:"#ef4444",marginBottom:"0.5rem",fontSize:"1.25rem"},children:"Something went wrong"}),(0,b.jsx)("p",{style:{color:"#94a3b8",marginBottom:"1.5rem"},children:a.message||"An unexpected error occurred."}),(0,b.jsx)("button",{onClick:f,style:{padding:"0.5rem 1.25rem",background:"#3b82f6",color:"white",border:"none",borderRadius:"0.375rem",cursor:"pointer",fontSize:"0.875rem"},children:"Try again"})]})})})})}])}];
2
-
3
- //# sourceMappingURL=%5Broot-of-the-server%5D__101v4_7._.js.map
@@ -1 +0,0 @@
1
- (globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,9969,e=>{"use strict";let t=null;e.s(["captureClientEvent",0,function(e,r){if(!t||!t.enabled)return;let n=JSON.stringify({api_key:t.apiKey,event:e,distinct_id:t.distinctId,properties:{...r,$lib:"failproofai-web",failproofai_version:t.version,$current_url:window.location.href,$pathname:window.location.pathname}});fetch(t.host.replace(/\/+$/,"")+"/capture/",{method:"POST",headers:{"Content-Type":"application/json"},body:n,signal:AbortSignal.timeout(5e3)}).catch(()=>{})},"setClientTelemetryConfig",0,function(e){t=e}])},98183,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n={assign:function(){return l},searchParamsToUrlQuery:function(){return a},urlQueryToSearchParams:function(){return s}};for(var o in n)Object.defineProperty(r,o,{enumerable:!0,get:n[o]});function a(e){let t={};for(let[r,n]of e.entries()){let e=t[r];void 0===e?t[r]=n:Array.isArray(e)?e.push(n):t[r]=[e,n]}return t}function i(e){return"string"==typeof e?e:("number"!=typeof e||isNaN(e))&&"boolean"!=typeof e?"":String(e)}function s(e){let t=new URLSearchParams;for(let[r,n]of Object.entries(e))if(Array.isArray(n))for(let e of n)t.append(r,i(e));else t.set(r,i(n));return t}function l(e,...t){for(let r of t){for(let t of r.keys())e.delete(t);for(let[t,n]of r.entries())e.append(t,n)}return e}},18967,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n={DecodeError:function(){return b},MiddlewareNotFoundError:function(){return j},MissingStaticPage:function(){return x},NormalizeError:function(){return v},PageNotFoundError:function(){return y},SP:function(){return m},ST:function(){return g},WEB_VITALS:function(){return a},execOnce:function(){return i},getDisplayName:function(){return d},getLocationOrigin:function(){return u},getURL:function(){return c},isAbsoluteUrl:function(){return l},isResSent:function(){return f},loadGetInitialProps:function(){return h},normalizeRepeatedSlashes:function(){return p},stringifyError:function(){return w}};for(var o in n)Object.defineProperty(r,o,{enumerable:!0,get:n[o]});let a=["CLS","FCP","FID","INP","LCP","TTFB"];function i(e){let t,r=!1;return(...n)=>(r||(r=!0,t=e(...n)),t)}let s=/^[a-zA-Z][a-zA-Z\d+\-.]*?:/,l=e=>s.test(e);function u(){let{protocol:e,hostname:t,port:r}=window.location;return`${e}//${t}${r?":"+r:""}`}function c(){let{href:e}=window.location,t=u();return e.substring(t.length)}function d(e){return"string"==typeof e?e:e.displayName||e.name||"Unknown"}function f(e){return e.finished||e.headersSent}function p(e){let t=e.split("?");return t[0].replace(/\\/g,"/").replace(/\/\/+/g,"/")+(t[1]?`?${t.slice(1).join("?")}`:"")}async function h(e,t){let r=t.res||t.ctx&&t.ctx.res;if(!e.getInitialProps)return t.ctx&&t.Component?{pageProps:await h(t.Component,t.ctx)}:{};let n=await e.getInitialProps(t);if(r&&f(r))return n;if(!n)throw Object.defineProperty(Error(`"${d(e)}.getInitialProps()" should resolve to an object. But found "${n}" instead.`),"__NEXT_ERROR_CODE",{value:"E1025",enumerable:!1,configurable:!0});return n}let m="u">typeof performance,g=m&&["mark","measure","getEntriesByName"].every(e=>"function"==typeof performance[e]);class b extends Error{}class v extends Error{}class y extends Error{constructor(e){super(),this.code="ENOENT",this.name="PageNotFoundError",this.message=`Cannot find module for page: ${e}`}}class x extends Error{constructor(e,t){super(),this.message=`Failed to load static file for page: ${e} ${t}`}}class j extends Error{constructor(){super(),this.code="ENOENT",this.message="Cannot find the middleware module"}}function w(e){return JSON.stringify({message:e.message,stack:e.stack})}},33525,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0}),Object.defineProperty(r,"warnOnce",{enumerable:!0,get:function(){return n}});let n=e=>{}},96661,5014,e=>{"use strict";let t=(...e)=>e.filter((e,t,r)=>!!e&&""!==e.trim()&&r.indexOf(e)===t).join(" ").trim();e.s(["mergeClasses",0,t],96661);var r=e.i(71645),n={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};let o=(0,r.createContext)({}),a=(0,r.forwardRef)(({color:e,size:a,strokeWidth:i,absoluteStrokeWidth:s,className:l="",children:u,iconNode:c,...d},f)=>{let{size:p=24,strokeWidth:h=2,absoluteStrokeWidth:m=!1,color:g="currentColor",className:b=""}=(0,r.useContext)(o)??{},v=s??m?24*Number(i??h)/Number(a??p):i??h;return(0,r.createElement)("svg",{ref:f,...n,width:a??p??n.width,height:a??p??n.height,stroke:e??g,strokeWidth:v,className:t("lucide",b,l),...!u&&!(e=>{for(let t in e)if(t.startsWith("aria-")||"role"===t||"title"===t)return!0;return!1})(d)&&{"aria-hidden":"true"},...d},[...c.map(([e,t])=>(0,r.createElement)(e,t)),...Array.isArray(u)?u:[u]])});e.s(["default",0,a],5014)},56420,e=>{"use strict";var t=e.i(71645),r=e.i(96661);let n=e=>{let t=e.replace(/^([A-Z])|[\s-_]+(\w)/g,(e,t,r)=>r?r.toUpperCase():t.toLowerCase());return t.charAt(0).toUpperCase()+t.slice(1)};var o=e.i(5014);e.s(["default",0,(e,a)=>{let i=(0,t.forwardRef)(({className:i,...s},l)=>(0,t.createElement)(o.default,{ref:l,iconNode:a,className:(0,r.mergeClasses)(`lucide-${n(e).replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}`,`lucide-${e}`,i),...s}));return i.displayName=n(e),i}],56420)},95057,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n={formatUrl:function(){return s},formatWithValidation:function(){return u},urlObjectKeys:function(){return l}};for(var o in n)Object.defineProperty(r,o,{enumerable:!0,get:n[o]});let a=e.r(90809)._(e.r(98183)),i=/https?|ftp|gopher|file/;function s(e){let{auth:t,hostname:r}=e,n=e.protocol||"",o=e.pathname||"",s=e.hash||"",l=e.query||"",u=!1;t=t?encodeURIComponent(t).replace(/%3A/i,":")+"@":"",e.host?u=t+e.host:r&&(u=t+(~r.indexOf(":")?`[${r}]`:r),e.port&&(u+=":"+e.port)),l&&"object"==typeof l&&(l=String(a.urlQueryToSearchParams(l)));let c=e.search||l&&`?${l}`||"";return n&&!n.endsWith(":")&&(n+=":"),e.slashes||(!n||i.test(n))&&!1!==u?(u="//"+(u||""),o&&"/"!==o[0]&&(o="/"+o)):u||(u=""),s&&"#"!==s[0]&&(s="#"+s),c&&"?"!==c[0]&&(c="?"+c),o=o.replace(/[?#]/g,encodeURIComponent),c=c.replace("#","%23"),`${n}${u}${o}${c}${s}`}let l=["auth","hash","host","hostname","href","path","pathname","port","protocol","query","search","slashes"];function u(e){return s(e)}},18581,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0}),Object.defineProperty(r,"useMergedRef",{enumerable:!0,get:function(){return o}});let n=e.r(71645);function o(e,t){let r=(0,n.useRef)(null),o=(0,n.useRef)(null);return(0,n.useCallback)(n=>{if(null===n){let e=r.current;e&&(r.current=null,e());let t=o.current;t&&(o.current=null,t())}else e&&(r.current=a(e,n)),t&&(o.current=a(t,n))},[e,t])}function a(e,t){if("function"!=typeof e)return e.current=t,()=>{e.current=null};{let r=e(t);return"function"==typeof r?r:()=>e(null)}}("function"==typeof r.default||"object"==typeof r.default&&null!==r.default)&&void 0===r.default.__esModule&&(Object.defineProperty(r.default,"__esModule",{value:!0}),Object.assign(r.default,r),t.exports=r.default)},73668,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0}),Object.defineProperty(r,"isLocalURL",{enumerable:!0,get:function(){return a}});let n=e.r(18967),o=e.r(52817);function a(e){if(!(0,n.isAbsoluteUrl)(e))return!0;try{let t=(0,n.getLocationOrigin)(),r=new URL(e,t);return r.origin===t&&(0,o.hasBasePath)(r.pathname)}catch(e){return!1}}},84508,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0}),Object.defineProperty(r,"errorOnce",{enumerable:!0,get:function(){return n}});let n=e=>{}},22016,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n={default:function(){return b},useLinkStatus:function(){return y}};for(var o in n)Object.defineProperty(r,o,{enumerable:!0,get:n[o]});let a=e.r(90809),i=e.r(43476),s=a._(e.r(71645)),l=e.r(95057),u=e.r(8372),c=e.r(18581),d=e.r(18967),f=e.r(5550);e.r(33525);let p=e.r(88540),h=e.r(91949),m=e.r(73668),g=e.r(9396);function b(t){var r,n;let o,a,b,[y,x]=(0,s.useOptimistic)(h.IDLE_LINK_STATUS),j=(0,s.useRef)(null),{href:w,as:k,children:N,prefetch:C=null,passHref:P,replace:_,shallow:E,scroll:S,onClick:R,onMouseEnter:M,onTouchStart:O,legacyBehavior:T=!1,onNavigate:A,transitionTypes:L,ref:$,unstable_dynamicOnHover:U,...z}=t;o=N,T&&("string"==typeof o||"number"==typeof o)&&(o=(0,i.jsx)("a",{children:o}));let I=s.default.useContext(u.AppRouterContext),B=!1!==C,D=!1!==C?null===(n=C)||"auto"===n?g.FetchStrategy.PPR:g.FetchStrategy.Full:g.FetchStrategy.PPR,q="string"==typeof(r=k||w)?r:(0,l.formatUrl)(r);if(T){if(o?.$$typeof===Symbol.for("react.lazy"))throw Object.defineProperty(Error("`<Link legacyBehavior>` received a direct child that is either a Server Component, or JSX that was loaded with React.lazy(). This is not supported. Either remove legacyBehavior, or make the direct child a Client Component that renders the Link's `<a>` tag."),"__NEXT_ERROR_CODE",{value:"E863",enumerable:!1,configurable:!0});a=s.default.Children.only(o)}let F=T?a&&"object"==typeof a&&a.ref:$,H=s.default.useCallback(e=>(null!==I&&(j.current=(0,h.mountLinkInstance)(e,q,I,D,B,x)),()=>{j.current&&((0,h.unmountLinkForCurrentNavigation)(j.current),j.current=null),(0,h.unmountPrefetchableInstance)(e)}),[B,q,I,D,x]),K={ref:(0,c.useMergedRef)(H,F),onClick(t){T||"function"!=typeof R||R(t),T&&a.props&&"function"==typeof a.props.onClick&&a.props.onClick(t),!I||t.defaultPrevented||function(t,r,n,o,a,i,l){if("u">typeof window){let u,{nodeName:c}=t.currentTarget;if("A"===c.toUpperCase()&&((u=t.currentTarget.getAttribute("target"))&&"_self"!==u||t.metaKey||t.ctrlKey||t.shiftKey||t.altKey||t.nativeEvent&&2===t.nativeEvent.which)||t.currentTarget.hasAttribute("download"))return;if(!(0,m.isLocalURL)(r)){o&&(t.preventDefault(),location.replace(r));return}if(t.preventDefault(),i){let e=!1;if(i({preventDefault:()=>{e=!0}}),e)return}let{dispatchNavigateAction:d}=e.r(99781);s.default.startTransition(()=>{d(r,o?"replace":"push",!1===a?p.ScrollBehavior.NoScroll:p.ScrollBehavior.Default,n.current,l)})}}(t,q,j,_,S,A,L)},onMouseEnter(e){T||"function"!=typeof M||M(e),T&&a.props&&"function"==typeof a.props.onMouseEnter&&a.props.onMouseEnter(e),I&&B&&(0,h.onNavigationIntent)(e.currentTarget,!0===U)},onTouchStart:function(e){T||"function"!=typeof O||O(e),T&&a.props&&"function"==typeof a.props.onTouchStart&&a.props.onTouchStart(e),I&&B&&(0,h.onNavigationIntent)(e.currentTarget,!0===U)}};return(0,d.isAbsoluteUrl)(q)?K.href=q:T&&!P&&("a"!==a.type||"href"in a.props)||(K.href=(0,f.addBasePath)(q)),b=T?s.default.cloneElement(a,K):(0,i.jsx)("a",{...z,...K,children:o}),(0,i.jsx)(v.Provider,{value:y,children:b})}e.r(84508);let v=(0,s.createContext)(h.IDLE_LINK_STATUS),y=()=>(0,s.useContext)(v);("function"==typeof r.default||"object"==typeof r.default&&null!==r.default)&&void 0===r.default.__esModule&&(Object.defineProperty(r.default,"__esModule",{value:!0}),Object.assign(r.default,r),t.exports=r.default)},18566,(e,t,r)=>{t.exports=e.r(76562)},22548,e=>{"use strict";var t=e.i(95187);let r=(0,t.createServerReference)("0014ee7d8223527f1163c06ddaa02e702fda5fde5f",t.callServer,void 0,t.findSourceMapURL,"getTelemetryConfig");e.s(["getTelemetryConfig",0,r])},68590,e=>{"use strict";let t=(0,e.i(56420).default)("message-square",[["path",{d:"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z",key:"18887p"}]]);e.s(["MessageSquare",0,t],68590)},55574,e=>{"use strict";var t=e.i(43476),r=e.i(71645);let n=[],o=0,a=new Set;function i(){for(let e of a)e()}function s(e){return a.add(e),()=>a.delete(e)}function l(){return n}function u({message:e}){let[n,o]=(0,r.useState)(!1);return(0,r.useEffect)(()=>{requestAnimationFrame(()=>o(!0));let e=setTimeout(()=>o(!1),2e3);return()=>clearTimeout(e)},[]),(0,t.jsx)("div",{className:`bg-card border border-border text-foreground text-sm px-4 py-2 rounded-lg shadow-lg transition-opacity duration-300 ${n?"opacity-100":"opacity-0"}`,children:e})}e.s(["Toaster",0,function(){let e=(0,r.useSyncExternalStore)(s,l,l);return(0,t.jsx)("div",{className:"fixed bottom-4 right-4 z-50 flex flex-col gap-2",children:e.map(e=>(0,t.jsx)(u,{message:e.message},e.id))})},"toast",0,function(e){let t=o++;n=[...n,{id:t,message:e}],i(),setTimeout(()=>{n=n.filter(e=>e.id!==t),i()},2500)}])},95187,(e,t,r)=>{"use strict";Object.defineProperty(r,"__esModule",{value:!0});var n={callServer:function(){return a.callServer},createServerReference:function(){return s.createServerReference},findSourceMapURL:function(){return i.findSourceMapURL}};for(var o in n)Object.defineProperty(r,o,{enumerable:!0,get:n[o]});let a=e.r(32120),i=e.r(92245),s=e.r(35326)},85881,e=>{"use strict";var t=e.i(43476),r=e.i(71645);let n=(0,r.createContext)(void 0);e.s(["AutoRefreshProvider",0,function({children:e}){let[o,a]=(0,r.useState)(0);return(0,t.jsx)(n.Provider,{value:{intervalSec:o,setIntervalSec:a},children:e})},"useAutoRefresh",0,function(){let e=(0,r.useContext)(n);if(!e)throw Error("useAutoRefresh must be used within AutoRefreshProvider");return e}])},82954,e=>{"use strict";let t=(0,e.i(56420).default)("shield",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}]]);e.s(["Shield",0,t],82954)},16327,e=>{"use strict";let t=(0,e.i(56420).default)("chevron-down",[["path",{d:"m6 9 6 6 6-6",key:"qrunsl"}]]);e.s(["ChevronDown",0,t],16327)},67881,e=>{"use strict";var t=e.i(43476),r=e.i(71645),n=e.i(47163);let o=r.forwardRef(({className:e,variant:r="default",size:o="default",...a},i)=>(0,t.jsx)("button",{className:(0,n.cn)("inline-flex items-center justify-center rounded-md text-sm font-medium transition-[background-color,color,box-shadow,border-color] duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:opacity-50 disabled:pointer-events-none",{"bg-primary text-primary-foreground hover:bg-primary/90 hover:shadow-[0_0_0_1px_var(--primary)]":"default"===r,"text-foreground hover:bg-muted":"ghost"===r,"border border-border bg-transparent hover:border-primary/60 hover:bg-card":"outline"===r,"h-10 py-2 px-4":"default"===o,"h-10 w-10":"icon"===o,"h-9 px-3":"sm"===o,"h-11 px-8":"lg"===o},e),ref:i,...a}));o.displayName="Button",e.s(["Button",0,o])},12344,e=>{"use strict";var t=e.i(43476),r=e.i(71645),n=e.i(18566),o=e.i(22548),a=e.i(9969);let i=(0,r.createContext)(void 0);e.s(["PostHogProvider",0,function({children:e}){let s=(0,n.usePathname)(),l=(0,r.useRef)(null),u=(0,r.useRef)(!1);(0,r.useEffect)(()=>{let e=!1;return(0,o.getTelemetryConfig)().then(t=>{e||((0,a.setClientTelemetryConfig)(t),u.current=!0,(0,a.captureClientEvent)("$pageview"),l.current=window.location.pathname)}),()=>{e=!0}},[]),(0,r.useEffect)(()=>{u.current&&l.current!==s&&(l.current=s,(0,a.captureClientEvent)("$pageview"))},[s]);let c=r.default.useCallback((e,t)=>{(0,a.captureClientEvent)(e,t)},[]);return(0,t.jsx)(i.Provider,{value:{capture:c},children:e})},"usePostHog",0,function(){let e=(0,r.useContext)(i);if(void 0===e)throw Error("usePostHog must be used within a PostHogProvider");return e}])},97917,e=>{"use strict";var t=e.i(71645),r=e.i(9969);e.s(["GlobalErrorListeners",0,function(){return(0,t.useEffect)(()=>{let e=e=>{(0,r.captureClientEvent)("unhandled_exception",{error_message:e.message,error_name:e.error?.name,error_filename:e.filename,error_lineno:e.lineno,error_colno:e.colno})},t=e=>{let t=e.reason;(0,r.captureClientEvent)("unhandled_rejection",{error_message:t instanceof Error?t.message:String(t),error_name:t instanceof Error?t.name:void 0})};return window.addEventListener("error",e),window.addEventListener("unhandledrejection",t),()=>{window.removeEventListener("error",e),window.removeEventListener("unhandledrejection",t)}},[]),null}])},63780,e=>{"use strict";e.i(47167);var t=e.i(43476),r=e.i(22016),n=e.i(18566),o=e.i(56420);let a=(0,o.default)("folder-open",[["path",{d:"m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2",key:"usdka0"}]]);var i=e.i(82954),s=e.i(71645);let l=(0,o.default)("git-branch",[["path",{d:"M15 6a9 9 0 0 0-9 9V3",key:"1cii5b"}],["circle",{cx:"18",cy:"6",r:"3",key:"1h7g24"}],["circle",{cx:"6",cy:"18",r:"3",key:"fqmcym"}]]),u=(0,o.default)("lightbulb",[["path",{d:"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5",key:"1gvzjb"}],["path",{d:"M9 18h6",key:"x1upvd"}],["path",{d:"M10 22h4",key:"ceow96"}]]),c=(0,o.default)("bug",[["path",{d:"M12 20v-9",key:"1qisl0"}],["path",{d:"M14 7a4 4 0 0 1 4 4v3a6 6 0 0 1-12 0v-3a4 4 0 0 1 4-4z",key:"uouzyp"}],["path",{d:"M14.12 3.88 16 2",key:"qol33r"}],["path",{d:"M21 21a4 4 0 0 0-3.81-4",key:"1b0z45"}],["path",{d:"M21 5a4 4 0 0 1-3.55 3.97",key:"5cxbf6"}],["path",{d:"M22 13h-4",key:"1jl80f"}],["path",{d:"M3 21a4 4 0 0 1 3.81-4",key:"1fjd4g"}],["path",{d:"M3 5a4 4 0 0 0 3.55 3.97",key:"1d7oge"}],["path",{d:"M6 13H2",key:"82j7cp"}],["path",{d:"m8 2 1.88 1.88",key:"fmnt4t"}],["path",{d:"M9 7.13V6a3 3 0 1 1 6 0v1.13",key:"1vgav8"}]]);var d=e.i(68590),f=e.i(16327);let p=(0,o.default)("star",[["path",{d:"M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z",key:"r04s7s"}]]),h=(0,o.default)("book-open",[["path",{d:"M12 7v14",key:"1akyts"}],["path",{d:"M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z",key:"ruj8y"}]]),m=(0,o.default)("hash",[["line",{x1:"4",x2:"20",y1:"9",y2:"9",key:"4lhtct"}],["line",{x1:"4",x2:"20",y1:"15",y2:"15",key:"vyu0kd"}],["line",{x1:"10",x2:"8",y1:"3",y2:"21",key:"1ggp8o"}],["line",{x1:"16",x2:"14",y1:"3",y2:"21",key:"weycgp"}]]);var g=e.i(67881);let b="https://github.com/failproofai/failproofai",v="failproofai@exosphere.host",y=[{label:"Star us on GitHub",icon:p,href:"https://github.com/failproofai/failproofai"},{label:"Documentation",icon:h,href:"https://befailproof.ai"},{label:"Join our Slack",icon:m,href:"https://join.slack.com/t/failproofai/shared_invite/zt-3v63b7k5e-O3NBHmj8X6n9gZSGDx6ggQ"},{label:"Request a Feature",icon:u,href:`${b}/issues/new?labels=enhancement&title=Feature+Request%3A+`},{label:"Report an Issue",icon:c,href:`${b}/issues/new?labels=bug&title=Bug+Report%3A+`},{label:"Ask a Question",icon:d.MessageSquare,href:`${b}/discussions/new?category=q-a`}],x=()=>{let[e,r]=(0,s.useState)(!1),n=(0,s.useCallback)(()=>r(!1),[]),o=(0,s.useCallback)(e=>{"Escape"===e.key&&r(!1)},[]);return(0,t.jsxs)("div",{className:"relative",onKeyDown:o,children:[e&&(0,t.jsx)("div",{className:"fixed inset-0 z-40",onClick:n,"aria-hidden":"true"}),(0,t.jsxs)(g.Button,{type:"button",variant:"ghost",size:"sm",onClick:()=>r(e=>!e),"aria-expanded":e,"aria-haspopup":"true",className:"relative z-50 flex items-center gap-1.5 text-muted-foreground hover:text-foreground",children:[(0,t.jsx)(l,{className:"h-4 w-4"}),(0,t.jsx)("span",{className:"hidden sm:inline text-xs",children:"Reach Us"}),(0,t.jsx)(f.ChevronDown,{className:`h-3 w-3 transition-transform ${e?"rotate-180":""}`})]}),e&&(0,t.jsxs)("div",{className:"absolute right-0 mt-2 w-56 rounded-lg border border-border bg-card shadow-lg z-50",role:"menu",children:[(0,t.jsxs)("div",{className:"px-3 py-2 border-b border-border",children:[(0,t.jsx)("p",{className:"text-xs font-medium text-foreground",children:"Reach Developers"}),(0,t.jsx)("p",{className:"text-[0.65rem] text-muted-foreground mt-0.5",children:"We'd love to hear from you"})]}),(0,t.jsx)("div",{className:"py-1",children:y.map(({label:e,icon:r,href:o})=>(0,t.jsxs)("a",{href:o,target:"_blank",rel:"noopener noreferrer",role:"menuitem",className:"flex items-center gap-2.5 px-3 py-2 text-xs text-muted-foreground hover:text-foreground hover:bg-muted/50 transition-colors",onClick:n,children:[(0,t.jsx)(r,{className:"h-3.5 w-3.5 flex-shrink-0"}),e]},e))}),(0,t.jsx)("div",{className:"px-3 py-2 border-t border-border",children:(0,t.jsxs)("p",{className:"text-[0.65rem] text-muted-foreground",children:["or email"," ",(0,t.jsx)("a",{href:`mailto:${v}`,className:"text-primary hover:text-primary/80 transition-colors",children:v})]})})]})]})},j=(0,o.default)("refresh-cw",[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8",key:"v9h5vc"}],["path",{d:"M21 3v5h-5",key:"1q7to0"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16",key:"3uifl3"}],["path",{d:"M8 16H3v5",key:"1cv678"}]]);var w=e.i(47163),k=e.i(85881);let N=[{label:"Off",value:0},{label:"5s",value:5},{label:"10s",value:10},{label:"30s",value:30}];function C({className:e}){let r=(0,n.useRouter)(),[o,a]=(0,s.useTransition)(),{intervalSec:i,setIntervalSec:l}=(0,k.useAutoRefresh)(),u=(0,s.useCallback)(()=>{a(()=>r.refresh())},[r]);(0,s.useEffect)(()=>{if(i<=0)return;let e=setInterval(u,1e3*i);return()=>clearInterval(e)},[i,u]);let c=i>0;return(0,t.jsxs)("div",{className:(0,w.cn)("inline-flex items-center rounded-lg border border-border bg-muted/50 p-0.5 gap-0.5",e),children:[(0,t.jsx)("button",{onClick:u,title:"Refresh",className:(0,w.cn)("inline-flex items-center justify-center rounded-md p-1.5 transition-colors",c?"text-primary hover:bg-primary/10":"text-muted-foreground hover:text-foreground hover:bg-muted"),children:(0,t.jsx)(j,{className:(0,w.cn)("w-3.5 h-3.5",o&&"animate-spin")})}),(0,t.jsx)("div",{className:"w-px h-4 bg-border"}),(0,t.jsx)("div",{className:"inline-flex items-center gap-0.5",role:"group","aria-label":"Auto-refresh interval",children:N.map(e=>(0,t.jsx)("button",{onClick:()=>l(e.value),"aria-pressed":i===e.value,className:(0,w.cn)("px-2 py-1 text-[11px] font-medium rounded-md transition-colors",i===e.value?"bg-background text-foreground shadow-sm":"text-muted-foreground hover:text-foreground hover:bg-muted"),children:e.label},e.value))})]})}let P=[{href:"/policies",label:"Policies",icon:i.Shield},{href:"/projects",label:"Projects",icon:a}];e.s(["Navbar",0,({disabledPages:e=[]})=>{let o=(0,n.usePathname)();return(0,t.jsx)("header",{className:"relative z-50 border-b border-border bg-card/60 backdrop-blur supports-[backdrop-filter]:bg-card/60",children:(0,t.jsx)("div",{className:"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8",children:(0,t.jsxs)("div",{className:"flex items-center justify-between h-16",children:[(0,t.jsxs)("div",{className:"flex items-center gap-3",children:[(0,t.jsx)("a",{href:"https://github.com/failproofai/failproofai",target:"_blank",rel:"noopener noreferrer",className:"flex items-center hover:opacity-80 transition-opacity","aria-label":"failproof ai · GitHub",children:(0,t.jsx)("img",{src:"https://d2wq11aau0arks.cloudfront.net/failproof/logo-wordmark.png",alt:"failproof ai",style:{height:24,width:"auto"},className:"select-none"})}),(0,t.jsxs)("span",{className:"font-mono text-[0.6rem] leading-none text-muted-foreground/70 border border-border/60 rounded px-1.5 py-0.5 select-none tracking-wider uppercase",children:["v","0.0.11-beta.1"]}),(0,t.jsx)("div",{className:"w-px h-8 bg-border ml-2"}),(0,t.jsx)("nav",{className:"flex items-center h-16",children:P.filter(({href:t})=>{let r=t.slice(1);return!e.includes(r)}).map(({href:e,label:n,icon:a})=>{let i="/projects"===e?"/projects"===o||o.startsWith("/project/"):o.startsWith(e);return(0,t.jsxs)(r.default,{href:e,className:`relative flex items-center gap-1.5 px-3 h-full text-sm transition-colors ${i?"text-foreground font-medium":"text-muted-foreground hover:text-foreground"}`,children:[(0,t.jsx)(a,{className:`w-4 h-4 ${i?"text-primary":""}`}),n,(0,t.jsx)("span",{className:`absolute inset-x-1 bottom-0 h-[2px] transition-all ${i?"bg-primary":"bg-transparent"}`})]},e)})})]}),(0,t.jsxs)("div",{className:"flex items-center gap-1",children:[(0,t.jsx)(C,{}),(0,t.jsx)("div",{className:"w-px h-6 bg-border mx-1"}),(0,t.jsx)(x,{})]})]})})})}],63780)}]);