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.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +9 -9
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +9 -9
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/policies/page.js +1 -1
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d_ob4n._.js +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_0z7w.hh._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0-wn51s._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__12y7xmt._.js → [root-of-the-server]__01as125._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0agrcb8._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ehh6vp._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__09i-rsi._.js → [root-of-the-server]__0k5n2kz._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0yaqw._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0t8juvy._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ts150~._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0uylufv._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ymlddl._.js +5 -5
- package/.next/standalone/.next/server/chunks/ssr/app_0cdqd9w._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_0xerkr6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_0q-m0y-._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0a_7sdg.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +9 -9
- package/.next/standalone/.next/static/chunks/07kpqoo7kuckx.js +6 -0
- package/.next/standalone/.next/static/chunks/{0zg~cpc5ysg6d.js → 0azb~vy9ds_uy.js} +1 -1
- package/.next/standalone/.next/static/chunks/{13-bt.3~irg00.js → 0bke.~atnsbeb.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0_vk1wsgf~q3o.js → 0bv1oyxspkpkb.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0wtiofzdt-l2u.js → 0dvhi-prcsh3~.js} +1 -1
- package/.next/standalone/.next/static/chunks/0spktq7xqab9h.js +1 -0
- package/.next/standalone/.next/static/chunks/{16vev.do1oho7.js → 118q3uljozd5z.js} +1 -1
- package/.next/standalone/.next/static/chunks/{07kfzzinhsl7e.js → 11w14gnqzprir.js} +1 -1
- package/.next/standalone/app/policies/hooks-client.tsx +102 -13
- package/.next/standalone/lib/claude-sessions.ts +181 -0
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/server.js +1 -1
- package/README.md +2 -2
- package/bin/failproofai.mjs +229 -72
- package/dist/cli.mjs +3025 -1450
- package/lib/claude-sessions.ts +181 -0
- package/package.json +1 -1
- package/scripts/postinstall.mjs +89 -1
- package/src/audit/cache.ts +113 -0
- package/src/audit/cli-adapters/claude.ts +97 -0
- package/src/audit/cli-adapters/codex.ts +56 -0
- package/src/audit/cli-adapters/copilot.ts +51 -0
- package/src/audit/cli-adapters/cursor.ts +51 -0
- package/src/audit/cli-adapters/gemini.ts +51 -0
- package/src/audit/cli-adapters/index.ts +70 -0
- package/src/audit/cli-adapters/opencode.ts +52 -0
- package/src/audit/cli-adapters/pi.ts +51 -0
- package/src/audit/cli-adapters/shared.ts +85 -0
- package/src/audit/detectors/find-from-root.ts +27 -0
- package/src/audit/detectors/git-commit-no-verify.ts +22 -0
- package/src/audit/detectors/index.ts +33 -0
- package/src/audit/detectors/prefer-edit-over-read-cat.ts +31 -0
- package/src/audit/detectors/prefer-edit-over-sed-awk.ts +27 -0
- package/src/audit/detectors/prefer-write-over-heredoc.ts +36 -0
- package/src/audit/detectors/redundant-cd-cwd.ts +28 -0
- package/src/audit/detectors/reread-after-edit.ts +58 -0
- package/src/audit/detectors/sleep-polling-loop.ts +34 -0
- package/src/audit/index.ts +369 -0
- package/src/audit/replay.ts +121 -0
- package/src/audit/report.ts +349 -0
- package/src/audit/telemetry.ts +113 -0
- package/src/audit/types.ts +193 -0
- package/src/hooks/builtin-policies.ts +78 -0
- package/src/hooks/custom-hooks-loader.ts +19 -3
- package/src/hooks/first-run-nudge.ts +146 -0
- package/src/hooks/handler.ts +21 -102
- package/src/hooks/install-prompt.ts +34 -4
- package/src/hooks/manager.ts +72 -5
- package/src/hooks/policy-evaluator.ts +16 -1
- package/src/hooks/policy-types.ts +9 -0
- package/src/hooks/tool-name-canonicalize.ts +65 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__101v4_7._.js +0 -3
- package/.next/standalone/.next/static/chunks/03xhjwk6zhi8f.js +0 -1
- package/.next/standalone/.next/static/chunks/0wq808vlc8l04.js +0 -6
- package/src/auth/login.ts +0 -104
- package/src/auth/logout.ts +0 -50
- package/src/auth/token-store.ts +0 -64
- package/src/relay/daemon.ts +0 -362
- package/src/relay/pid.ts +0 -76
- package/src/relay/queue.ts +0 -225
- /package/.next/standalone/.next/static/{s5Nn6KwDdLpPhjG3l2WNf → tGVQM5SE3NvbVu0gbAJm7}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{s5Nn6KwDdLpPhjG3l2WNf → tGVQM5SE3NvbVu0gbAJm7}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{s5Nn6KwDdLpPhjG3l2WNf → tGVQM5SE3NvbVu0gbAJm7}/_ssgManifest.js +0 -0
package/src/hooks/handler.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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)
|
|
108
|
+
if (!process.stdin.isTTY) {
|
|
109
|
+
fireDetectionEvent(detected, "all_detected");
|
|
110
|
+
return detected;
|
|
111
|
+
}
|
|
84
112
|
|
|
85
|
-
|
|
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. */
|
package/src/hooks/manager.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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
|
-
|
|
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)}]);
|