failproofai 1.0.2-beta.8 → 1.0.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 +4 -4
- 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 +6 -6
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- 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/_not-found/__PAGE__.segment.rsc +13 -13
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/audit/invite/route.js +3 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -3
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -2
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +4 -3
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js +4 -4
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js +4 -4
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +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 +13 -13
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
- 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 +14 -14
- package/.next/standalone/.next/server/app/policies/page.js +4 -4
- 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/app/settings/page/server-reference-manifest.json +4 -4
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/[externals]__0-9ti7z._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[externals]__1lt47k4._.js → [externals]__0sg9-3p._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[externals]__0u3wrvq._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__01eqny5._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__1p8poxd._.js → [root-of-the-server]__0igxt32._.js} +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zlqo2t._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1anxb5k._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1le9jqc._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1p-qi2t._.js +5 -0
- package/.next/standalone/.next/server/chunks/_09dz7xv._.js +27 -0
- package/.next/standalone/.next/server/chunks/_0bs-v8p._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0tovk6q._.js +3 -0
- package/.next/standalone/.next/server/chunks/_0trp3yc._.js +3 -0
- package/.next/standalone/.next/server/chunks/{_19uwam-._.js → _1-akg6w._.js} +2 -2
- package/.next/standalone/.next/server/chunks/_185gyk9._.js +3 -0
- package/.next/standalone/.next/server/chunks/_1ek68ln._.js +5 -7
- package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_09d5c79._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_04op_ou._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_1d2g73o._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_0dr20uz._.js} +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_0iu54mz._.js +3 -0
- package/.next/standalone/.next/server/chunks/src_hooks_custom-hooks-loader_ts_0lnb3n3._.js +10 -0
- package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n_lxhg._.js +5 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0oa1lav._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p-5p8u._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s740oi._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1yh7hlv._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0ehudfr._.js +23 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1n2ywfz._.js → _1es2j7i._.js} +4 -4
- package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_1h33neq._.js → _1un1pug._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +9 -9
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_settings_settings-client_tsx_20lq-mq._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1cv9_c4._.js +10 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/middleware.js +1 -1
- 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 +19 -19
- package/.next/standalone/.next/static/chunks/0nkpwjk01ei3t.js +1 -0
- package/.next/standalone/.next/static/chunks/{2iryw37qfqy5y.js → 0ofdelz65_517.js} +1 -1
- package/.next/standalone/.next/static/chunks/{34j7nmidlcuni.js → 12uhnpwgsmcev.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0i3a6wf-f_yky.js → 1_1eb_149xyt9.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3927pu4ss_l4k.js → 1tx9pnxyjrkoj.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1n04wzsaes73g.js → 1x0jrl3a4_i2m.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3r0udrtpn78-e.js → 1zpv6omeln7al.js} +1 -1
- package/.next/standalone/.next/static/chunks/{416zumre3fvfw.js → 20hbg-r3io_ip.js} +1 -1
- package/.next/standalone/.next/static/chunks/{11a_m8yksthtf.js → 32bhi32ym8yrz.js} +2 -2
- package/.next/standalone/.next/static/chunks/{0u2ojcw25c_np.js → 3fr78ugeb4tjc.js} +1 -1
- package/.next/standalone/app/actions/get-hooks-config.ts +8 -1
- package/.next/standalone/app/actions/pack-actions.ts +12 -1
- package/.next/standalone/app/policies/hooks-client.tsx +41 -4
- package/.next/standalone/fp-cloud-cli/tests/test_pagination.py +204 -0
- package/.next/standalone/package.json +9 -9
- package/.next/standalone/server.js +1 -1
- package/README.md +58 -13
- package/bin/failproofai.mjs +10 -1
- package/dist/cli.mjs +22429 -21292
- package/dist/worker.mjs +1247 -540
- package/package.json +9 -9
- package/src/audit/index.ts +24 -4
- package/src/hooks/builtin-policies.ts +933 -8
- package/src/hooks/custom-hooks-loader.ts +98 -8
- package/src/hooks/handler.ts +26 -14
- package/src/hooks/manager.ts +36 -2
- package/src/hooks/pack-cli.ts +415 -42
- package/src/hooks/pack-failclosed.ts +100 -4
- package/src/hooks/pack-manifest.ts +29 -0
- package/src/hooks/pack-param-key.ts +36 -0
- package/src/hooks/pack-store.ts +101 -9
- package/src/hooks/policy-catalog.ts +9 -1
- package/src/hooks/policy-evaluator.ts +77 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06cuf1y._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_usx0j._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_zk340._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jnjf2t._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0oy4kxb._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zf034w._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1tg4pu6._.js +0 -3
- package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +0 -3
- package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0mgrjnx._.js +0 -10
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1-wzs7f._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1wlvpe5._.js +0 -5
- package/.next/standalone/.next/server/chunks/ssr/_0l7zv8b._.js +0 -23
- package/.next/standalone/.next/static/chunks/1ch5l9t2p16y4.js +0 -1
- /package/.next/standalone/.next/static/{NgD5HvuyPxwgrpeIiafJL → 5-xDMxcnrcXDFPQiy3yhg}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{NgD5HvuyPxwgrpeIiafJL → 5-xDMxcnrcXDFPQiy3yhg}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{NgD5HvuyPxwgrpeIiafJL → 5-xDMxcnrcXDFPQiy3yhg}/_ssgManifest.js +0 -0
|
@@ -59,16 +59,40 @@ export const PERMANENT_LOAD_FAILURES: ReadonlySet<string> = new Set([
|
|
|
59
59
|
"path_missing",
|
|
60
60
|
]);
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* A declared list, or null when it cannot be read as one.
|
|
64
|
+
*
|
|
65
|
+
* Null means UNKNOWN, and unknown has to widen the deny rather than narrow it —
|
|
66
|
+
* this whole function exists to say where a missing guard applied, and a
|
|
67
|
+
* narrowing derived from metadata nobody can parse says nothing true.
|
|
68
|
+
*
|
|
69
|
+
* A malformed list is not hypothetical: `match` was validated only as
|
|
70
|
+
* `typeof === "object"`, so a manifest declaring `events: "PreToolUse"` reached
|
|
71
|
+
* here as a STRING, was iterated character by character, and narrowed the
|
|
72
|
+
* fail-closed deny to `["P","r","e","T","o","l","U","s"]` — a set matching no
|
|
73
|
+
* event that exists. The pack failed to load, the guard fired on nothing, and
|
|
74
|
+
* the machine went on running unguarded with a deny it never used. `events: 5`
|
|
75
|
+
* was worse still: `for (const e of 5)` throws, on the hook path.
|
|
76
|
+
*/
|
|
77
|
+
function declaredList(value: unknown): string[] | null {
|
|
78
|
+
if (value === undefined || value === null) return null;
|
|
79
|
+
if (!Array.isArray(value)) return null;
|
|
80
|
+
if (value.some((entry) => typeof entry !== "string" || entry.length === 0)) return null;
|
|
81
|
+
return value as string[];
|
|
82
|
+
}
|
|
83
|
+
|
|
62
84
|
function unionMatch(matchers: PolicyMatcher[]): PolicyMatcher {
|
|
63
85
|
const events = new Set<HookEventType>();
|
|
64
86
|
const toolNames = new Set<string>();
|
|
65
87
|
let anyEvent = false;
|
|
66
88
|
let anyTool = false;
|
|
67
89
|
for (const m of matchers) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (!
|
|
71
|
-
else for (const
|
|
90
|
+
const declaredEvents = declaredList(m?.events);
|
|
91
|
+
const declaredTools = declaredList(m?.toolNames);
|
|
92
|
+
if (!declaredEvents || declaredEvents.length === 0) anyEvent = true;
|
|
93
|
+
else for (const e of declaredEvents) events.add(e as HookEventType);
|
|
94
|
+
if (!declaredTools || declaredTools.length === 0) anyTool = true;
|
|
95
|
+
else for (const t of declaredTools) toolNames.add(t);
|
|
72
96
|
}
|
|
73
97
|
const scoped: PolicyMatcher = {};
|
|
74
98
|
// Every declared event is kept, INCLUDING UserPromptSubmit. This says where
|
|
@@ -88,6 +112,26 @@ function unionMatch(matchers: PolicyMatcher[]): PolicyMatcher {
|
|
|
88
112
|
* user took 3 of 40 from is not a failure because the other 37 did not load.
|
|
89
113
|
* `disabled` is the `disabledCustomPolicies` set, keyed `pack:<id>@<ver>:<name>`.
|
|
90
114
|
*/
|
|
115
|
+
/**
|
|
116
|
+
* True when a pack scoped to specific agents does not cover the one running.
|
|
117
|
+
*
|
|
118
|
+
* The registration path already skips a pack whose `clis` excludes this agent;
|
|
119
|
+
* the fail-closed path did not, so a pack scoped to `codex` that failed to load
|
|
120
|
+
* denied on `claude` too — locking an agent out over enforcement it was never
|
|
121
|
+
* configured to have, until a human repaired a pack it does not use. `null` or
|
|
122
|
+
* absent means every agent, as it does everywhere else.
|
|
123
|
+
*/
|
|
124
|
+
function outOfScope(clis: string[] | null | undefined, cli: string | undefined): boolean {
|
|
125
|
+
if (!cli) return false;
|
|
126
|
+
// `Array.isArray`, not truthiness. A `clis` of `"codex"` is a truthy value
|
|
127
|
+
// with a `length` and an `includes`, so a string scope silently narrowed this
|
|
128
|
+
// to nothing and skipped the guard for every agent — a check meant to stop
|
|
129
|
+
// over-denying turning into the thing that under-denies. Unreadable scope
|
|
130
|
+
// means every agent, exactly as an unreadable `match` means every event.
|
|
131
|
+
if (!Array.isArray(clis) || clis.length === 0) return false;
|
|
132
|
+
return !clis.every((c) => typeof c === "string") ? false : !clis.includes(cli);
|
|
133
|
+
}
|
|
134
|
+
|
|
91
135
|
export function missingGuards(input: {
|
|
92
136
|
errors: PackError[];
|
|
93
137
|
packs: ResolvedPack[];
|
|
@@ -96,6 +140,8 @@ export function missingGuards(input: {
|
|
|
96
140
|
/** Packs handed to the loader whose entry artifact failed to import. */
|
|
97
141
|
failed: Map<string, PolicyLoadFailure>;
|
|
98
142
|
disabled: ReadonlySet<string>;
|
|
143
|
+
/** The agent this evaluation is for, so a pack scoped away from it stays quiet. */
|
|
144
|
+
cli?: string;
|
|
99
145
|
}): MissingGuard[] {
|
|
100
146
|
const out: MissingGuard[] = [];
|
|
101
147
|
|
|
@@ -104,6 +150,7 @@ export function missingGuards(input: {
|
|
|
104
150
|
// An observe pack denying on failure would deny for something that, had it
|
|
105
151
|
// loaded, would have allowed.
|
|
106
152
|
if (err.effect === "observe") continue;
|
|
153
|
+
if (outOfScope(err.clis, input.cli)) continue;
|
|
107
154
|
const declared = err.declared ?? [];
|
|
108
155
|
out.push({
|
|
109
156
|
packId: err.id ?? "(unnamed pack)",
|
|
@@ -119,6 +166,7 @@ export function missingGuards(input: {
|
|
|
119
166
|
// (c) Resolved, but registered less than it declared.
|
|
120
167
|
for (const pack of input.packs) {
|
|
121
168
|
if (pack.effect === "observe") continue;
|
|
169
|
+
if (outOfScope(pack.clis, input.cli)) continue;
|
|
122
170
|
const loadFailure = input.failed.get(pack.id);
|
|
123
171
|
if (loadFailure && PERMANENT_LOAD_FAILURES.has(loadFailure.type)) {
|
|
124
172
|
const taken = pack.enabled ?? pack.policies.map((p) => p.name);
|
|
@@ -172,6 +220,54 @@ export function missingGuards(input: {
|
|
|
172
220
|
* because the agent cannot run it: `block-failproofai-commands` denies every
|
|
173
221
|
* `failproofai` invocation from a tool call, deliberately and unconditionally.
|
|
174
222
|
*/
|
|
223
|
+
/**
|
|
224
|
+
* One matcher covering every missing guard, for the single policy that stands
|
|
225
|
+
* in for all of them.
|
|
226
|
+
*
|
|
227
|
+
* Narrow only where EVERY guard is narrow: a guard that declared no events
|
|
228
|
+
* applied everywhere, so a union that dropped it would deny less than the packs
|
|
229
|
+
* did. Both axes by the same rule — `toolNames` used to be left out of the
|
|
230
|
+
* combined object entirely, which reads as "every tool", so two failed packs
|
|
231
|
+
* each scoped to Bash denied Write and Read as well. One failed pack narrowed
|
|
232
|
+
* correctly and two widened to everything, which is the wrong way round:
|
|
233
|
+
* combining two limited scopes cannot produce a larger one.
|
|
234
|
+
*/
|
|
235
|
+
/**
|
|
236
|
+
* True when at least one guard actually applied to this event and tool.
|
|
237
|
+
*
|
|
238
|
+
* `combinedGuardMatch` unions the two axes independently, and the registry ANDs
|
|
239
|
+
* them — so guards scoped to (PreToolUse, Bash) and (PostToolUse, Write) produce
|
|
240
|
+
* a matcher that also catches (PreToolUse, Write) and (PostToolUse, Bash), pairs
|
|
241
|
+
* neither pack ever asked to guard. The union cannot be tightened without
|
|
242
|
+
* losing dispatch: the matcher has to be a SUPERSET or the policy is never
|
|
243
|
+
* reached. So the matcher stays wide enough to be called, and the pairing is
|
|
244
|
+
* checked here, where the real event and tool are known.
|
|
245
|
+
*/
|
|
246
|
+
export function guardsCover(
|
|
247
|
+
guards: MissingGuard[],
|
|
248
|
+
eventType: string,
|
|
249
|
+
toolName: string | undefined,
|
|
250
|
+
): boolean {
|
|
251
|
+
return guards.some((g) => {
|
|
252
|
+
const events = g.match.events;
|
|
253
|
+
if (events && events.length > 0 && !events.includes(eventType as (typeof events)[number])) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
const tools = g.match.toolNames;
|
|
257
|
+
if (tools && tools.length > 0 && (!toolName || !tools.includes(toolName))) return false;
|
|
258
|
+
return true;
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export function combinedGuardMatch(guards: MissingGuard[]): PolicyMatcher {
|
|
263
|
+
if (guards.length === 1) return guards[0].match;
|
|
264
|
+
const axis = <K extends "events" | "toolNames">(key: K): PolicyMatcher[K] | undefined =>
|
|
265
|
+
guards.every((g) => g.match[key]?.length)
|
|
266
|
+
? ([...new Set(guards.flatMap((g) => g.match[key] ?? []))] as PolicyMatcher[K])
|
|
267
|
+
: undefined;
|
|
268
|
+
return { events: axis("events"), toolNames: axis("toolNames") };
|
|
269
|
+
}
|
|
270
|
+
|
|
175
271
|
export function packFailureReason(guards: MissingGuard[]): string {
|
|
176
272
|
const named = guards
|
|
177
273
|
.map((g) => {
|
|
@@ -157,6 +157,14 @@ export interface PackError {
|
|
|
157
157
|
* Lets the deny name what is missing instead of being blanket.
|
|
158
158
|
*/
|
|
159
159
|
declared?: PolicyCatalogEntry[];
|
|
160
|
+
/**
|
|
161
|
+
* The agents this pack was scoped to, when the manifest got far enough to say.
|
|
162
|
+
*
|
|
163
|
+
* Carried for the same reason `effect` is. A pack scoped to one CLI that fails
|
|
164
|
+
* to load must not deny on the others: they were never guarded by it, so a
|
|
165
|
+
* deny on their behalf locks an agent out over enforcement it never had.
|
|
166
|
+
*/
|
|
167
|
+
clis?: string[] | null;
|
|
160
168
|
}
|
|
161
169
|
|
|
162
170
|
export interface PackReadResult {
|
|
@@ -253,6 +261,19 @@ export function parsePackPolicy(packId: string, value: unknown, index: number):
|
|
|
253
261
|
if (!raw.match || typeof raw.match !== "object") {
|
|
254
262
|
throw new Error(`${where} is missing a match`);
|
|
255
263
|
}
|
|
264
|
+
// The SHAPE, not just the presence. `match` was accepted as any object, so a
|
|
265
|
+
// manifest declaring `events: "PreToolUse"` installed cleanly and then
|
|
266
|
+
// narrowed the fail-closed deny to the letters of that string — a guard
|
|
267
|
+
// matching no event that exists. Refused at install now, where the publisher
|
|
268
|
+
// can still fix it, rather than surviving as metadata nothing can read.
|
|
269
|
+
const matchShape = raw.match as { events?: unknown; toolNames?: unknown };
|
|
270
|
+
for (const key of ["events", "toolNames"] as const) {
|
|
271
|
+
const value = matchShape[key];
|
|
272
|
+
if (value === undefined) continue;
|
|
273
|
+
if (!Array.isArray(value) || value.some((e) => typeof e !== "string" || e.length === 0)) {
|
|
274
|
+
throw new Error(`${where} has a match.${key} that is not a list of names`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
256
277
|
return raw as unknown as PolicyCatalogEntry;
|
|
257
278
|
}
|
|
258
279
|
|
|
@@ -390,6 +411,14 @@ export function readInstalledPacks(): PackReadResult {
|
|
|
390
411
|
// Best effort: an entry too malformed to list policies yields nothing
|
|
391
412
|
// here, and a deny built from it is unavoidably blanket.
|
|
392
413
|
...(Array.isArray(rec?.policies) ? { declared: safeDeclared(rec.policies) } : {}),
|
|
414
|
+
// A list of names, or nothing. Anything else is unreadable scope, and
|
|
415
|
+
// unreadable scope has to mean "every agent" — the same reasoning that
|
|
416
|
+
// widens an unreadable `match`: a narrowing nobody can parse says
|
|
417
|
+
// nothing true, and here the narrowing would be the thing that lets an
|
|
418
|
+
// unguarded agent through.
|
|
419
|
+
...(Array.isArray(rec?.clis) && rec.clis.every((c) => typeof c === "string")
|
|
420
|
+
? { clis: rec.clis }
|
|
421
|
+
: {}),
|
|
393
422
|
});
|
|
394
423
|
}
|
|
395
424
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The config key a pack policy's parameters are stored under.
|
|
3
|
+
*
|
|
4
|
+
* A LEAF module on purpose: no imports at all, so it can be reached from the
|
|
5
|
+
* browser. `packPolicyParamKey` used to live in `policy-evaluator.ts`, which
|
|
6
|
+
* the dashboard's client component then imported — dragging `pack-store` and
|
|
7
|
+
* its `node:fs` into the browser bundle and failing the Next build with
|
|
8
|
+
* `Module not found: Can't resolve 'fs/promises'`. The key is pure string
|
|
9
|
+
* formatting and belongs where both sides can have it.
|
|
10
|
+
*
|
|
11
|
+
* VERSION-LESS, and that is the whole design. A pack policy registers as
|
|
12
|
+
* `pack/<id>@<version>/<name>`, so a key carrying the version would be orphaned
|
|
13
|
+
* by the publisher's next release — a parameter somebody set would silently
|
|
14
|
+
* revert to its default on upgrade, which is the same failure `enabled` avoids
|
|
15
|
+
* by outliving the version it was chosen against.
|
|
16
|
+
*/
|
|
17
|
+
export function packPolicyParamKey(packId: string, policyName: string): string {
|
|
18
|
+
return `pack/${packId}/${policyName}`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** `pack/<id>@<version>/<name>` split back into the parts a key is built from,
|
|
22
|
+
* or null when the name is not a pack policy's. */
|
|
23
|
+
export function parsePackPolicyName(
|
|
24
|
+
canonicalName: string,
|
|
25
|
+
): { packId: string; name: string } | null {
|
|
26
|
+
if (!canonicalName.startsWith("pack/")) return null;
|
|
27
|
+
const rest = canonicalName.slice("pack/".length);
|
|
28
|
+
const slash = rest.lastIndexOf("/");
|
|
29
|
+
if (slash <= 0) return null;
|
|
30
|
+
const idWithVersion = rest.slice(0, slash);
|
|
31
|
+
const at = idWithVersion.lastIndexOf("@");
|
|
32
|
+
return {
|
|
33
|
+
packId: at > 0 ? idWithVersion.slice(0, at) : idWithVersion,
|
|
34
|
+
name: rest.slice(slash + 1),
|
|
35
|
+
};
|
|
36
|
+
}
|
package/src/hooks/pack-store.ts
CHANGED
|
@@ -906,8 +906,15 @@ export async function addPack(
|
|
|
906
906
|
const at = source.lastIndexOf("@");
|
|
907
907
|
return at > source.indexOf(":") ? source.slice(0, at) : source;
|
|
908
908
|
};
|
|
909
|
+
// Only when it is the SAME id. This binds an id to the origin it first came
|
|
910
|
+
// from, and `priorRecordFor` also answers with a same-DIGEST record under a
|
|
911
|
+
// different id — for which the check is not just unnecessary but wrong: a
|
|
912
|
+
// second pack that happens to ship identical bytes from another repository is
|
|
913
|
+
// not the installed one being hijacked, and refusing it said `pack id X is
|
|
914
|
+
// already installed from Y` while naming an id the user never asked for.
|
|
909
915
|
if (
|
|
910
916
|
prior &&
|
|
917
|
+
prior.id === fetched.id &&
|
|
911
918
|
!prior.source.startsWith("bundled:") &&
|
|
912
919
|
repoOf(prior.source) !== repoOf(formatPackSpec(spec))
|
|
913
920
|
) {
|
|
@@ -954,7 +961,12 @@ export async function addPack(
|
|
|
954
961
|
: {}),
|
|
955
962
|
};
|
|
956
963
|
|
|
957
|
-
|
|
964
|
+
// `--all` is an ANSWER, not a silence. `upsertInstalled` carries an absorbed
|
|
965
|
+
// row's narrower selection onto a record that names none — which is right for
|
|
966
|
+
// a rename nobody expressed an opinion about, and wrong for a caller who just
|
|
967
|
+
// said "everything". Left ungated, `policies add <renamed pack> --all`
|
|
968
|
+
// reported the whole catalog and wrote the old id's one-policy list.
|
|
969
|
+
const absorbed = upsertInstalled(record, reason !== "all");
|
|
958
970
|
return {
|
|
959
971
|
replaced: absorbed,
|
|
960
972
|
id: fetched.id,
|
|
@@ -1008,23 +1020,93 @@ export function setPackPolicyEnabled(
|
|
|
1008
1020
|
return { ok: true };
|
|
1009
1021
|
}
|
|
1010
1022
|
|
|
1011
|
-
|
|
1023
|
+
/**
|
|
1024
|
+
* The spellings of a pack id that `remove` accepts.
|
|
1025
|
+
*
|
|
1026
|
+
* Exactly one used to work — the stored id, byte for byte — and it was a form
|
|
1027
|
+
* shown nowhere on its own, so every spelling a user could SEE or had TYPED
|
|
1028
|
+
* failed:
|
|
1029
|
+
*
|
|
1030
|
+
* add failproofai/policies stores `FailproofAI/policies`
|
|
1031
|
+
* remove failproofai/policies no installed pack with id …
|
|
1032
|
+
* remove FailproofAI/policies@06b802b63f4f no installed pack with id …
|
|
1033
|
+
*
|
|
1034
|
+
* The first is what they installed it with — GitHub is case-insensitive, so
|
|
1035
|
+
* `add` accepts any case and then records the CANONICAL id off the manifest.
|
|
1036
|
+
* The second is the listing's own heading, copied. Both are refused, and the
|
|
1037
|
+
* one that works appears only as half of that heading. A pack whose owner
|
|
1038
|
+
* happens to be lowercase (`chhhee10/deploy-guard`) removes on the first try,
|
|
1039
|
+
* which is what makes this look like the core pack being unremovable rather
|
|
1040
|
+
* than a name-matching bug.
|
|
1041
|
+
*
|
|
1042
|
+
* So: case-insensitive, and an `@<version>` suffix is dropped. A pack id cannot
|
|
1043
|
+
* contain `@` — `PACK_ID_RE` forbids it — so splitting at the last one is
|
|
1044
|
+
* unambiguous. The version is not checked against what is installed: there is
|
|
1045
|
+
* only ever one row per id, and refusing `pack@1.0.0` because 1.0.1 is
|
|
1046
|
+
* installed would be the same unhelpfulness in a new hat.
|
|
1047
|
+
*/
|
|
1048
|
+
function packIdMatches(stored: string, typed: string): boolean {
|
|
1049
|
+
return bareId(stored).toLowerCase() === bareId(typed).toLowerCase();
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
/** The id with any `@<version>` suffix and surrounding space removed, CASE
|
|
1053
|
+
* INTACT — the exact-match pass needs the original spelling. */
|
|
1054
|
+
function bareId(value: string): string {
|
|
1055
|
+
const trimmed = value.trim();
|
|
1056
|
+
const at = trimmed.lastIndexOf("@");
|
|
1057
|
+
return (at > 0 ? trimmed.slice(0, at) : trimmed).trim();
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
/** Two installed packs answer to one loosely-typed name. Thrown rather than
|
|
1061
|
+
* guessed at: the caller prints the canonical ids so the user can say which. */
|
|
1062
|
+
export class AmbiguousPackId extends Error {
|
|
1063
|
+
constructor(readonly candidates: string[], typed: string) {
|
|
1064
|
+
super(
|
|
1065
|
+
`${typed} matches ${candidates.length} installed packs: ${candidates.join(", ")}. ` +
|
|
1066
|
+
`Name one of them exactly.`,
|
|
1067
|
+
);
|
|
1068
|
+
this.name = "AmbiguousPackId";
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
/** The id actually removed — the CANONICAL one, not the spelling that was
|
|
1073
|
+
* typed — or null when nothing matched. Callers report it back so a user who
|
|
1074
|
+
* typed a different case learns the name the machine holds. */
|
|
1075
|
+
export function removePack(id: string): string | null {
|
|
1012
1076
|
const manifestPath = resolve(packsRoot(), "installed.json");
|
|
1013
|
-
if (!existsSync(manifestPath)) return
|
|
1077
|
+
if (!existsSync(manifestPath)) return null;
|
|
1014
1078
|
let raw: { schemaVersion?: number; packs?: InstalledPackRecord[] };
|
|
1015
1079
|
try {
|
|
1016
1080
|
raw = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
1017
1081
|
} catch {
|
|
1018
|
-
return
|
|
1082
|
+
return null;
|
|
1019
1083
|
}
|
|
1020
1084
|
const packs = Array.isArray(raw.packs) ? raw.packs : [];
|
|
1021
|
-
|
|
1022
|
-
|
|
1085
|
+
// EXACT first, and a loose match only when it is the only one.
|
|
1086
|
+
//
|
|
1087
|
+
// Ids are stored and upserted with `===`, so `Acme/guard` and `acme/guard`
|
|
1088
|
+
// are two rows on one machine — and a `find()` over the loose matcher then
|
|
1089
|
+
// removed whichever happened to sit first, which is not the pack that was
|
|
1090
|
+
// named. A convenience for typing a name is not worth uninstalling something
|
|
1091
|
+
// else, so an ambiguous name is REFUSED and the candidates are printed:
|
|
1092
|
+
// asking again with the exact id is a keystroke, and the alternative is
|
|
1093
|
+
// silently deactivating a pack the user still wanted enforcing.
|
|
1094
|
+
const exact = packs.find((p) => p?.id === bareId(id));
|
|
1095
|
+
const loose = packs.filter((p) => p?.id && packIdMatches(p.id, id));
|
|
1096
|
+
if (!exact && loose.length > 1) {
|
|
1097
|
+
throw new AmbiguousPackId(
|
|
1098
|
+
loose.map((p) => p.id).filter((v): v is string => typeof v === "string"),
|
|
1099
|
+
id,
|
|
1100
|
+
);
|
|
1101
|
+
}
|
|
1102
|
+
const removed = exact ?? loose[0];
|
|
1103
|
+
const remaining = packs.filter((p) => p !== removed);
|
|
1104
|
+
if (!removed || remaining.length === packs.length) return null;
|
|
1023
1105
|
// The artifact is left on disk deliberately: it is content-addressed and inert
|
|
1024
1106
|
// once nothing points at it, so keeping it makes a re-add offline-safe. Same
|
|
1025
1107
|
// choice the cloud reconciler makes.
|
|
1026
1108
|
writeAtomic(manifestPath, JSON.stringify({ schemaVersion: 1, packs: remaining }, null, 2) + "\n");
|
|
1027
|
-
return
|
|
1109
|
+
return removed.id;
|
|
1028
1110
|
}
|
|
1029
1111
|
|
|
1030
1112
|
/**
|
|
@@ -1047,7 +1129,17 @@ export function removePack(id: string): boolean {
|
|
|
1047
1129
|
* say so — an earlier version deleted the old row silently, taking the user's
|
|
1048
1130
|
* selection and the enforcement it gave them with it.
|
|
1049
1131
|
*/
|
|
1050
|
-
function upsertInstalled(
|
|
1132
|
+
function upsertInstalled(
|
|
1133
|
+
record: InstalledPackRecord,
|
|
1134
|
+
/**
|
|
1135
|
+
* False when the record's absent `enabled` is an EXPRESSED "everything"
|
|
1136
|
+
* (`--all`) rather than an unexpressed one. Carrying there overrides the
|
|
1137
|
+
* user's own answer with a set they left behind under the old id, and the
|
|
1138
|
+
* returned `AddedPack` still reports the whole catalog — installed says
|
|
1139
|
+
* three, disk enforces one.
|
|
1140
|
+
*/
|
|
1141
|
+
carryAbsorbedSelection = true,
|
|
1142
|
+
): string[] {
|
|
1051
1143
|
const manifestPath = resolve(packsRoot(), "installed.json");
|
|
1052
1144
|
let packs: InstalledPackRecord[] = [];
|
|
1053
1145
|
if (existsSync(manifestPath)) {
|
|
@@ -1068,7 +1160,7 @@ function upsertInstalled(record: InstalledPackRecord): string[] {
|
|
|
1068
1160
|
.map((p) => p.id);
|
|
1069
1161
|
// The selection the user had under the old id is theirs — carry it, rather
|
|
1070
1162
|
// than resetting them to defaults because a publisher renamed something.
|
|
1071
|
-
if (!record.enabled) {
|
|
1163
|
+
if (carryAbsorbedSelection && !record.enabled) {
|
|
1072
1164
|
const prior = packs.find((p) => absorbed.includes(p?.id));
|
|
1073
1165
|
const carried = prior?.enabled?.filter((n) =>
|
|
1074
1166
|
(record.policies as Array<{ name?: unknown }> | undefined)?.some((rp) => rp?.name === n),
|
|
@@ -169,7 +169,15 @@ export const POLICY_CATALOG: PolicyCatalogEntry[] = [
|
|
|
169
169
|
// PermissionRequest is carried over from the merged-in `block-self-pause`.
|
|
170
170
|
// It is a real enforcement point on Copilot and Devin, and dropping it would
|
|
171
171
|
// have left this guard blind on both.
|
|
172
|
-
|
|
172
|
+
// Write/Edit are here because the Bash-only surface left the shortest way
|
|
173
|
+
// through this guard unguarded: the agent never needs a shell to overwrite
|
|
174
|
+
// `~/.failproofai/policies-config.json` with `{"enabledPolicies":[]}` — it
|
|
175
|
+
// just writes the file. Every CLI canonicalizes its own file tool's path
|
|
176
|
+
// key to `file_path`, so one branch covers all of them.
|
|
177
|
+
match: {
|
|
178
|
+
events: ["PreToolUse", "PermissionRequest"],
|
|
179
|
+
toolNames: ["Bash", "Write", "Edit", "NotebookEdit"],
|
|
180
|
+
},
|
|
173
181
|
defaultEnabled: true,
|
|
174
182
|
alwaysOn: true,
|
|
175
183
|
category: "Dangerous Commands",
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { HookEventType, SessionMetadata } from "./types";
|
|
6
6
|
import type { PolicyContext, HooksConfig } from "./policy-types";
|
|
7
|
+
// Read from the layer that owns it rather than restated here — restating a
|
|
8
|
+
// pack id is exactly how `failproofai/builtins` and `failproofai/core` both
|
|
9
|
+
// outlived their rename. This is on the hook path, so the cost was measured
|
|
10
|
+
// rather than assumed: bundling policy-evaluator with this import is 38,627
|
|
11
|
+
// bytes against 37,491 without it, because only the constant survives
|
|
12
|
+
// tree-shaking. 1.1 KB is not worth a second copy of a name that has already
|
|
13
|
+
// drifted twice.
|
|
14
|
+
import { CORE_SOURCE } from "./pack-store";
|
|
15
|
+
import { packPolicyParamKey, parsePackPolicyName } from "./pack-param-key";
|
|
16
|
+
export { packPolicyParamKey } from "./pack-param-key";
|
|
7
17
|
import { DEFAULT_POLICY_NAMESPACE, getPoliciesForEvent } from "./policy-registry";
|
|
8
18
|
import { hookLogInfo, hookLogWarn } from "./hook-logger";
|
|
9
19
|
import { trackHookEvent } from "./hook-telemetry";
|
|
@@ -28,6 +38,61 @@ export interface EvaluationResult {
|
|
|
28
38
|
}
|
|
29
39
|
|
|
30
40
|
|
|
41
|
+
/**
|
|
42
|
+
* The config key a PACK policy's parameters are stored under.
|
|
43
|
+
*
|
|
44
|
+
* Version-less on purpose. A pack policy registers as
|
|
45
|
+
* `pack/<id>@<version>/<name>`, so a key carrying the version would be orphaned
|
|
46
|
+
* by every republish — the parameters would read as unset the moment the pack
|
|
47
|
+
* was upgraded, which is the same failure `enabled` avoids by outliving the
|
|
48
|
+
* version it was chosen against.
|
|
49
|
+
*
|
|
50
|
+
* Exported because the DASHBOARD writes this key and the evaluator reads it.
|
|
51
|
+
* They disagreed before — the dashboard wrote the bare policy name while the
|
|
52
|
+
* evaluator looked up the fully qualified one and fell back to bare only inside
|
|
53
|
+
* the `failproofai/` namespace — so a parameter saved through the UI was
|
|
54
|
+
* displayed as saved and ignored at runtime, on every pack including our own.
|
|
55
|
+
* One function so the two cannot drift again.
|
|
56
|
+
*/
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The parameters a PACK policy actually runs with, resolved out of a config's
|
|
60
|
+
* `policyParams` map: the stable qualified key first, then the BARE name for
|
|
61
|
+
* our own pack alone.
|
|
62
|
+
*
|
|
63
|
+
* The bare read is the migration. Every `policyParams["block-sudo"]` already on
|
|
64
|
+
* disk — written by a build that predates packs, or by the dashboard before it
|
|
65
|
+
* qualified its keys — means the builtin under the name it always had.
|
|
66
|
+
*
|
|
67
|
+
* It is scoped to our pack because a policy name is unique only WITHIN a pack:
|
|
68
|
+
* two installed packs may each declare a `block-sudo`, and a bare key cannot
|
|
69
|
+
* say which was meant. Handing a stranger's pack our pack's configuration runs
|
|
70
|
+
* a third party's code on parameters chosen for ours.
|
|
71
|
+
*
|
|
72
|
+
* Exported because the DASHBOARD's read side resolves the same lookup, and it
|
|
73
|
+
* resolved it differently — an UNSCOPED bare fallback — so a stranger's pack
|
|
74
|
+
* declaring `block-sudo` was SHOWN our saved parameters while this function
|
|
75
|
+
* handed that policy the schema defaults. The config modal seeds its inputs
|
|
76
|
+
* from what was shown and Save writes them back under the stranger's own key,
|
|
77
|
+
* which is the point a display lie turns into configuration that really runs.
|
|
78
|
+
* One function so the two cannot diverge again.
|
|
79
|
+
*/
|
|
80
|
+
export function readPackPolicyParams(
|
|
81
|
+
policyParams: Record<string, Record<string, unknown>> | undefined,
|
|
82
|
+
packId: string,
|
|
83
|
+
policyName: string,
|
|
84
|
+
): Record<string, unknown> | undefined {
|
|
85
|
+
if (!policyParams) return undefined;
|
|
86
|
+
const qualified = policyParams[packPolicyParamKey(packId, policyName)];
|
|
87
|
+
if (qualified) return qualified;
|
|
88
|
+
// Case-insensitively: the id reaches here from a manifest and from a source
|
|
89
|
+
// somebody typed, and GitHub treats `failproofai/policies` and
|
|
90
|
+
// `FailproofAI/policies` as one repository.
|
|
91
|
+
if (packId.toLowerCase() === CORE_SOURCE.toLowerCase()) return policyParams[policyName];
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
31
96
|
/**
|
|
32
97
|
* Look up policy params for a canonical policy name in the user config,
|
|
33
98
|
* tolerating either flat ("block-force-push") or qualified
|
|
@@ -35,7 +100,9 @@ export interface EvaluationResult {
|
|
|
35
100
|
*
|
|
36
101
|
* The flat-key fallback is intentionally limited to the default namespace
|
|
37
102
|
* so namespace isolation is preserved: `policyParams.foo` only matches
|
|
38
|
-
* `failproofai/foo`, never `myorg/foo` or `custom/foo`.
|
|
103
|
+
* `failproofai/foo`, never `myorg/foo` or `custom/foo`. A `pack/...` name gets
|
|
104
|
+
* the same isolation from `readPackPolicyParams` and returns before reaching
|
|
105
|
+
* that branch, so the two fallbacks never both apply to one name.
|
|
39
106
|
*/
|
|
40
107
|
function getConfigParamsFor(
|
|
41
108
|
config: HooksConfig | undefined,
|
|
@@ -44,6 +111,15 @@ function getConfigParamsFor(
|
|
|
44
111
|
if (!config?.policyParams) return undefined;
|
|
45
112
|
const canonicalParams = config.policyParams[canonicalName];
|
|
46
113
|
if (canonicalParams) return canonicalParams;
|
|
114
|
+
|
|
115
|
+
// A pack policy: qualified key, then the bare name for our pack only. Shared
|
|
116
|
+
// with the dashboard's read side rather than restated, so what is displayed
|
|
117
|
+
// stays what runs.
|
|
118
|
+
const packPolicy = parsePackPolicyName(canonicalName);
|
|
119
|
+
if (packPolicy) {
|
|
120
|
+
return readPackPolicyParams(config.policyParams, packPolicy.packId, packPolicy.name);
|
|
121
|
+
}
|
|
122
|
+
|
|
47
123
|
const defaultPrefix = `${DEFAULT_POLICY_NAMESPACE}/`;
|
|
48
124
|
if (!canonicalName.startsWith(defaultPrefix)) return undefined;
|
|
49
125
|
return config.policyParams[canonicalName.slice(defaultPrefix.length)];
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
module.exports=[66680,(e,t,s)=>{t.exports=e.x("node:crypto",()=>require("node:crypto"))},2157,(e,t,s)=>{t.exports=e.x("node:fs",()=>require("node:fs"))},60526,(e,t,s)=>{t.exports=e.x("node:os",()=>require("node:os"))},64828,e=>{"use strict";var t=e.i(79708),s=e.i(3605),n=e.i(28898),i=e.i(83534),r=e.i(28557);async function a(){let e=[];for(let{profile:t,dbPath:n}of(0,s.hermesDbPaths)())e.push(...await o(n,t));return e.sort((e,t)=>t.mtimeMs-e.mtimeMs),e}async function o(e,n){let i=await (0,t.openSqliteReadonly)(e);if(!i)return[];try{return i.query("SELECT s.id, s.source, s.cwd, s.title, s.user_id, s.chat_id, s.chat_type, s.started_at, s.ended_at, s.message_count, lm.last_activity FROM sessions s LEFT JOIN (SELECT session_id, MAX(timestamp) AS last_activity FROM messages GROUP BY session_id) lm ON lm.session_id = s.id ORDER BY lm.last_activity DESC").map(e=>({sessionId:e.id,profile:n,source:e.source??void 0,cwd:e.cwd??void 0,title:e.title??void 0,userId:e.user_id??void 0,chatId:e.chat_id??void 0,chatType:e.chat_type??void 0,mtimeMs:(0,s.epochToMs)(e.last_activity??e.ended_at??e.started_at),messageCount:"number"==typeof e.message_count?e.message_count:0,hasMessages:null!=e.last_activity}))}catch{return[]}finally{i.close()}}let l=(0,i.runtimeCache)(a,2);async function u(){let e=await a(),t=new Map;for(let s of e){if(s.messageCount<=0&&!s.hasMessages)continue;let e=s.profile||n.HERMES_DEFAULT_PROFILE,i=s.source??"unknown",r=JSON.stringify([e,i]),a=t.get(r);a?(a.latest=Math.max(a.latest,s.mtimeMs),a.count+=1):t.set(r,{profile:e,source:i,latest:s.mtimeMs,count:1})}let s=[];for(let{profile:e,source:i,latest:a,count:o}of t.values()){let t=new Date(a);s.push({name:(0,n.hermesProjectName)(e,i),path:(0,n.hermesProjectPath)(e,i),isDirectory:!0,lastModified:t,lastModifiedFormatted:(0,r.formatDate)(t),cli:["hermes"],sessionCount:o})}return s.sort((e,t)=>t.lastModified.getTime()-e.lastModified.getTime()),s}async function m(e){let t=(0,n.hermesProjectNameCandidates)(e);if(0===t.length)return{cwd:null,sessions:[]};let s=await a(),i=e=>s.filter(t=>(t.messageCount>0||t.hasMessages)&&(t.profile||n.HERMES_DEFAULT_PROFILE)===e.profile&&(t.source??"unknown")===e.source),o=t[0],l=i(o);if(0===l.length)for(let e of t.slice(1)){let t=i(e);if(t.length>0){o=e,l=t;break}}let{profile:u,source:m}=o;return{cwd:(0,n.hermesProjectPath)(u,m),sessions:l.map(e=>{let t=new Date(e.mtimeMs);return{name:e.title??e.sessionId,path:`hermes://${e.sessionId}`,lastModified:t,lastModifiedFormatted:(0,r.formatDate)(t),sessionId:e.sessionId,cli:"hermes",userId:e.userId,channelId:e.chatId,channelType:e.chatType}})}}let c=(0,i.runtimeCache)(u,2),f=(0,i.runtimeCache)(e=>m(e),2,{maxSize:50});e.s(["getCachedHermesProjects",0,c,"getCachedHermesSessions",0,l,"getCachedHermesSessionsByEncodedName",0,f,"getHermesProjects",0,u,"getHermesSessions",0,a,"getHermesSessionsByEncodedName",0,m])},3605,28898,e=>{"use strict";var t=e.i(50227),s=e.i(79708),n=e.i(2157),i=e.i(60526);let r="profiles",a="default";function o(){let e,s=function(){let e=(process.env.HERMES_HOME||"").trim();if(e){let s=(0,t.resolve)(e),n=(0,t.dirname)(s);return(0,t.basename)(n)===r?(0,t.dirname)(n):s}return(0,t.join)((0,i.homedir)(),".hermes")}(),o=[{name:a,home:s}],l=new Set([a]);try{e=(0,n.readdirSync)((0,t.join)(s,r),{withFileTypes:!0}).filter(e=>(e.isDirectory()||e.isSymbolicLink())&&!e.name.startsWith(".")).map(e=>e.name).sort()}catch{return o}for(let n of e)l.has(n)||(l.add(n),o.push({name:n,home:(0,t.join)(s,r,n)}));return o}function l(e,t){return`hermes:${e}:${t}`}e.s(["HERMES_DEFAULT_PROFILE",0,a,"hermesProjectName",0,function(e,t){return`hermes-${e}-${t}`},"hermesProjectNameCandidates",0,function(e){if(!e.startsWith("hermes-"))return[];let t=e.slice(7);if(!t)return[];let s=[];for(let e of o().map(e=>e.name).sort((e,t)=>t.length-e.length)){let n=`${e}-`;t.startsWith(n)&&t.length>n.length&&s.push({profile:e,source:t.slice(n.length)})}return s.push({profile:a,source:t}),s},"hermesProjectPath",0,l,"listHermesProfiles",0,o],28898);var u=e.i(83534),m=e.i(54214),c=e.i(67405);function f(){let e=process.env.HERMES_DB_PATH;return e?[{profile:a,dbPath:e}]:o().map(e=>({profile:e.name,dbPath:(0,t.join)(e.home,"state.db")}))}function d(e){if("string"==typeof e&&0!==e.length)try{return JSON.parse(e)}catch{return}}function p(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function h(e){return"string"==typeof e?e:Array.isArray(e)?e.map(e=>p(e)&&"string"==typeof e.text?e.text:"").filter(Boolean).join("\n"):""}async function y(e){if(!e||!/^[A-Za-z0-9_-]+$/.test(e))return null;for(let{profile:t,dbPath:s}of f()){let n=await g(s,t,e);if(n)return n}return null}async function g(e,t,n){let i=await (0,s.openSqliteReadonly)(e);if(!i)return null;try{let e=i.query("SELECT source, cwd FROM sessions WHERE id = ?",[n]);if(0===e.length)return null;let{source:s,cwd:r}=e[0],a=i.query("SELECT id, role, content, tool_call_id, tool_calls, tool_name, timestamp FROM messages WHERE session_id = ? ORDER BY timestamp ASC",[n]),o=function(e,t="session"){let s=[],n=new Map,i=new Map,r=Date.now();for(let a=0;a<e.length;a++){let o=e[a];if(!p(o))continue;let l="string"==typeof o.role?o.role:"system",u=function(e,t){if("number"==typeof e&&Number.isFinite(e)){if(e>1e12)return new Date(e);if(e>1e9)return new Date(1e3*e)}if("string"==typeof e){let t=Date.parse(e);if(!Number.isNaN(t))return new Date(t)}return new Date(t)}(o.timestamp??o.time_created,r+a),f=u.toISOString(),y={uuid:null!=o.id?String(o.id):`hermes-${a}`,parentUuid:null},g=(0,m.baseEntry)(y,f,u,t);if("user"===l){s.push({type:"user",...g,message:{role:"user",content:h(o.content)}});continue}if("assistant"===l){let e=[],t=h(o.content);for(let s of(t&&e.push({type:"text",text:t}),function(e){let t=Array.isArray(e)?e:d(e);if(!Array.isArray(t))return[];let s=[];for(let e of t){if(!p(e))continue;let t=p(e.function)?e.function:{},n="string"==typeof t.name?t.name:"string"==typeof e.name?e.name:"tool",i="string"==typeof e.id&&e.id||"string"==typeof e.call_id&&e.call_id||`${n}-${s.length}`,r=p(t.arguments)?t.arguments:d(t.arguments);s.push({id:i,name:n,input:p(r)?r:{}})}return s}(o.tool_calls))){let t={type:"tool_use",id:s.id,name:s.name,input:s.input};e.push(t),n.set(s.id,t),i.set(s.id,u.getTime())}if(0===e.length)continue;s.push({type:"assistant",...g,message:{role:"assistant",content:e}});continue}if("tool"===l){let e="string"==typeof o.tool_call_id?o.tool_call_id:void 0,t=e?n.get(e):void 0;if(t){let s=e&&i.get(e)||u.getTime(),n=Math.max(0,u.getTime()-s);t.result={timestamp:f,timestampFormatted:(0,m.formatTimestamp)(u),content:h(o.content),durationMs:n,durationFormatted:(0,c.formatDuration)(n)};continue}}s.push({type:"system",...g,raw:y})}return s.sort((e,t)=>e.timestampMs-t.timestampMs),s}(a,"session"),u=r&&r.length>0?r:s?l(t,s):void 0;return{entries:o,rawLines:a,cwd:u,filePath:`hermes://${n}`,profile:t}}catch{return null}finally{i.close()}}(0,u.runtimeCache)(e=>y(e),2,{maxSize:50}),e.s(["epochToMs",0,function(e){if("number"==typeof e&&Number.isFinite(e)){if(e>1e12)return e;if(e>1e9)return 1e3*e}return Date.now()},"getHermesSessionLog",0,y,"hermesDbPaths",0,f],3605)},54214,67405,e=>{"use strict";var t=e.i(24868),s=e.i(14747),n=e.i(81580),i=e.i(56936);async function r(e,n,i,r){let a=`agent-${r}.jsonl`;for(let r of[(0,s.join)(e,n,a),(0,s.join)(e,n,i,a),(0,s.join)(e,n,i,"subagents",a)])if(!(0,s.relative)(e,r).startsWith(".."))try{return await (0,t.access)(r),r}catch(e){if("ENOENT"===e.code)continue;break}return null}var a=e.i(83534),o=e.i(71809),l=e.i(28557);function u(e){if(e<1e3)return`${e}ms`;let t=Math.round(e/100);if(t<600)return`${(t/10).toFixed(1)}s`;let s=Math.round(e/1e3);if(s<3600){let e=Math.floor(s/60);return`${e}m ${s%60}s`}let n=Math.round(e/6e4),i=Math.floor(n/60);return`${i}h ${n%60}m`}function m(e){let t=(0,l.formatDate)(e),s=e.getMilliseconds().toString().padStart(3,"0");return`${t}.${s}`}function c(e,t,s,n){return{_source:n,uuid:e.uuid||"",parentUuid:e.parentUuid??null,timestamp:t,timestampMs:s.getTime(),timestampFormatted:m(s)}}async function f(e,t){let s=e.split("\n").filter(e=>""!==e.trim()),n=new Map,i=[],r=[],a=new Set,o=!1;for(let e=0;e<s.length;e++){let l;e>0&&e%200==0&&await new Promise(e=>setImmediate(e));let u=s[e];try{l=JSON.parse(u)}catch{continue}let m={...l,_source:t};r.push(m);let f=l.type,d=l.timestamp;if(!d)continue;let p=new Date(d),h=p.getTime();if("user"===f){let e=l.message;if(Array.isArray(e?.content)){let t=e.content;if(t.some(e=>"tool_result"===e.type)){let e=l.toolUseResult,s="string"==typeof e?.agentId?e.agentId:void 0;for(let e of(s&&/^[a-f0-9]+$/.test(s)&&a.add(s),t)){if("tool_result"!==e.type)continue;let t=e.tool_use_id;if(!t)continue;let{text:i,images:r}=function(e){let t=e.content;if("string"==typeof t)return{text:t};if(Array.isArray(t)){let e=t.filter(e=>"text"===e.type).map(e=>e.text),s=t.filter(e=>"image"===e.type).map(e=>{let t=e.source;return{base64:t.data,mediaType:t.media_type}}).filter(e=>e.base64&&e.mediaType);return{text:e.length>0?e.join("\n"):void 0,images:s.length>0?s:void 0}}return{}}(e);n.set(t,{timestamp:d,timestampMs:h,content:i,images:r,agentId:s})}continue}}let s="string"==typeof e?.content?e.content:"";i.push({type:"user",...c(l,d,p,t),message:{role:"user",content:s}});continue}if("assistant"===f){let e=l.message,s=[];if(Array.isArray(e?.content)&&(s=e.content.filter(e=>["text","tool_use","thinking"].includes(e.type)).map(e=>{if("text"===e.type)return{type:"text",text:e.text};if("tool_use"===e.type){let t=e.input;return{type:"tool_use",id:e.id,name:e.name,input:e.input??{},..."Task"===e.name&&t?{subagentType:t.subagent_type,subagentDescription:t.description}:{}}}return{type:"thinking",thinking:e.thinking,signature:e.signature}})),0===s.length)continue;i.push({type:"assistant",...c(l,d,p,t),message:{role:"assistant",content:s,model:e?.model}});continue}if("file-history-snapshot"===f||"progress"===f||"system"===f){i.push({type:f,...c(l,d,p,t),raw:{...l}});continue}if("queue-operation"===f){let e=o?"Session Resumed":"Session Started";o=!0,i.push({type:"queue-operation",...c(l,d,p,t),label:e});continue}}let l=0;for(let e of i)if("assistant"===e.type)for(let t of(++l%200==0&&await new Promise(e=>setImmediate(e)),e.message.content)){if("tool_use"!==t.type)continue;let s=n.get(t.id);if(!s)continue;let i=new Date(s.timestamp),r=Math.max(0,s.timestampMs-e.timestampMs);t.result={timestamp:s.timestamp,timestampFormatted:m(i),content:s.content,images:s.images,durationMs:r,durationFormatted:u(r)},s.agentId&&(t.subagentId=s.agentId)}return i.length>500&&await new Promise(e=>setImmediate(e)),i.sort((e,t)=>e.timestampMs-t.timestampMs),{entries:i,rawLines:r,subagentIds:Array.from(a)}}async function d(e,t="session"){return(await f(e,t)).entries}async function p(e,a){let l=(0,i.resolveProjectPath)(e),u=(0,n.getClaudeProjectsPath)(),m=(0,s.join)(l,`${a}.jsonl`),c=await (0,t.readFile)(m,"utf-8"),{entries:d,rawLines:p,subagentIds:h}=await f(c,"session");if(0===h.length)return{entries:d,rawLines:p,subagentIds:[]};let y=await (0,o.batchAll)(h.map(s=>async()=>{let n=`agent-${s}`,i=await r(u,e,a,s);if(!i)return null;let o=await (0,t.readFile)(i,"utf-8"),{entries:l,rawLines:m}=await f(o,n);return{entries:l,rawLines:m}}),4),g=[...d],_=[...p];for(let e of y)"fulfilled"===e.status&&e.value&&(g.push(...e.value.entries),_.push(...e.value.rawLines));return g.length>500&&await new Promise(e=>setImmediate(e)),g.sort((e,t)=>e.timestampMs-t.timestampMs),{entries:g,rawLines:_,subagentIds:h}}e.s(["formatDuration",0,u],67405),(0,a.runtimeCache)((e,t)=>p(e,t),60,{maxSize:50}),e.s(["baseEntry",0,c,"formatTimestamp",0,m,"parseLogContent",0,d,"parseRawLines",0,function(e,t){return e.split("\n").filter(e=>""!==e.trim()).flatMap(e=>{try{let s=JSON.parse(e);return void 0!==t&&(s._source=t),[s]}catch{return[]}})}],54214)}];
|
|
2
|
-
|
|
3
|
-
//# sourceMappingURL=%5Broot-of-the-server%5D__06cuf1y._.js.map
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
module.exports=[70406,(e,t,r)=>{t.exports=e.x("next/dist/compiled/@opentelemetry/api",()=>require("next/dist/compiled/@opentelemetry/api"))},18622,(e,t,r)=>{t.exports=e.x("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js",()=>require("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js"))},20635,(e,t,r)=>{t.exports=e.x("next/dist/server/app-render/action-async-storage.external.js",()=>require("next/dist/server/app-render/action-async-storage.external.js"))},24725,(e,t,r)=>{t.exports=e.x("next/dist/server/app-render/after-task-async-storage.external.js",()=>require("next/dist/server/app-render/after-task-async-storage.external.js"))},56704,(e,t,r)=>{t.exports=e.x("next/dist/server/app-render/work-async-storage.external.js",()=>require("next/dist/server/app-render/work-async-storage.external.js"))},32319,(e,t,r)=>{t.exports=e.x("next/dist/server/app-render/work-unit-async-storage.external.js",()=>require("next/dist/server/app-render/work-unit-async-storage.external.js"))},59043,(e,t,r)=>{t.exports=e.x("next/dist/server/runtime-reacts.external.js",()=>require("next/dist/server/runtime-reacts.external.js"))},93695,(e,t,r)=>{t.exports=e.x("next/dist/shared/lib/no-fallback-error.external.js",()=>require("next/dist/shared/lib/no-fallback-error.external.js"))},74533,(e,t,r)=>{t.exports=e.x("node:child_process",()=>require("node:child_process"))},66680,(e,t,r)=>{t.exports=e.x("node:crypto",()=>require("node:crypto"))},2157,(e,t,r)=>{t.exports=e.x("node:fs",()=>require("node:fs"))},60526,(e,t,r)=>{t.exports=e.x("node:os",()=>require("node:os"))},50227,(e,t,r)=>{t.exports=e.x("node:path",()=>require("node:path"))},81111,(e,t,r)=>{t.exports=e.x("node:stream",()=>require("node:stream"))},94930,e=>{"use strict";var t=e.i(2157),r=e.i(50227),n=e.i(66680);e.s(["writeJsonAtomically",0,function(e,s,o={}){let a=o.mode??384,i=o.dirMode??448,c=(0,r.dirname)(e);(0,t.existsSync)(c)||(0,t.mkdirSync)(c,{recursive:!0,mode:i});let u=`${e}.${process.pid}.${(0,n.randomBytes)(6).toString("hex")}.tmp`;try{(0,t.writeFileSync)(u,JSON.stringify(s,null,2),{mode:a});try{(63&(0,t.statSync)(u).mode)!=0&&(0,t.chmodSync)(u,a)}catch{}(0,t.renameSync)(u,e);try{(63&(0,t.statSync)(e).mode)!=0&&(0,t.chmodSync)(e,a)}catch{}}catch(e){try{(0,t.rmSync)(u,{force:!0})}catch{}throw e}}])},6375,e=>{"use strict";var t=e.i(46501);function r(){return(process.env.FAILPROOF_API_URL??process.env.FAILPROOFAI_API_URL??"https://api.befailproof.ai").replace(/\/+$/,"")}class n extends Error{status;code;retryAfterSecs;constructor(e,t,r,n){super(r),this.status=e,this.code=t,this.retryAfterSecs=n,this.name="AuthApiError"}}async function s(e){let t={};try{t=await e.json()}catch{}let r=t.code??`http_${e.status}`,s=t.message??t.detail??e.statusText??"request failed",o=t.retry_after_secs;if(void 0===o){let t=e.headers.get("retry-after");if(t){let e=Number(t);Number.isFinite(e)&&(o=e)}}return void 0!==o&&(o=Math.max(0,Math.min(86400,o))),new n(e.status,r,s,o)}async function o(e,r){try{return await fetch(e,{...r,signal:function(e){let t=AbortSignal.timeout(1e4);if(!e)return t;let r=AbortSignal.any;if(r)return r([t,e]);let n=new AbortController;if(t.aborted)n.abort(t.reason);else t.addEventListener("abort",()=>n.abort(t.reason),{once:!0});if(e.aborted)n.abort(e.reason);else e.addEventListener("abort",()=>n.abort(e.reason),{once:!0});return n.signal}(r.signal??void 0)})}catch(o){let s=function(e){if(null===e||"object"!=typeof e)return!1;let t=e.name;return"AbortError"===t||"TimeoutError"===t}(o);if((0,t.trackEvent)("api_server_unreachable",{kind:s?"timeout":"network",path:function(e){try{return new URL(e).pathname}catch{return e}}(e),method:"string"==typeof r.method?r.method:"GET"}),s)throw new n(0,"timeout",`request to ${e} timed out after 10000ms`);throw o}}async function a(e,t,n){let a={"content-type":"application/json"};n?.accessToken&&(a.authorization=`Bearer ${n.accessToken}`);let i=await o(`${r()}${e}`,{method:"POST",headers:a,body:JSON.stringify(t)});if(204!==i.status){if(!i.ok)throw await s(i);return await i.json()}}async function i(e,t){let n=await o(`${r()}${e}`,{method:"GET",headers:{authorization:`Bearer ${t}`}});if(!n.ok)throw await s(n);return await n.json()}async function c(e){return a("/v0/auth/login/request",{email:e})}async function u(e,t){return a("/v0/auth/login/verify",{email:e,code:t})}async function l(e){return a("/v0/auth/token/refresh",{refresh_token:e})}async function f(e,t){await a("/v0/auth/logout",{refresh_token:t},{accessToken:e})}async function d(e){return i("/v0/auth/me",e)}async function p(e,t,r){return a("/v0/invite",void 0===r?{to:t}:{to:t,score:r},{accessToken:e})}e.s(["AuthApiError",0,n,"fetchMe",0,d,"logoutSession",0,f,"refreshAccessToken",0,l,"requestLoginCode",0,c,"sendInvites",0,p,"verifyLoginCode",0,u],6375)},17707,e=>{"use strict";var t=e.i(2157),r=e.i(50227),n=e.i(94930),s=e.i(79857),o=e.i(6375);function a(){let e=process.env.FAILPROOFAI_AUTH_DIR;return e?(0,r.join)(e,"session.json"):(0,s.auditSessionFile)()}function i(){let e=a();if(!(0,t.existsSync)(e))return null;try{let r=(0,t.readFileSync)(e,"utf-8"),n=JSON.parse(r);if("string"!=typeof n.access_token||"string"!=typeof n.refresh_token||"number"!=typeof n.access_expires_at||"object"!=typeof n.user||!n.user||"string"!=typeof n.user.id||"string"!=typeof n.user.email)return null;return{access_token:n.access_token,refresh_token:n.refresh_token,access_expires_at:n.access_expires_at,refresh_expires_at:"number"==typeof n.refresh_expires_at?n.refresh_expires_at:n.access_expires_at,user:{id:n.user.id,email:n.user.email}}}catch{return null}}function c(e){(0,n.writeJsonAtomically)(a(),e)}function u(){let e=a();(0,t.existsSync)(e)&&(0,t.rmSync)(e,{force:!0});try{let e=(0,s.migrationsDir)();if(!(0,t.existsSync)(e))return;for(let n of(0,t.readdirSync)(e)){if(!n.startsWith("backup-layout"))continue;let s=(0,r.resolve)(e,n,"auth.json");(0,t.existsSync)(s)&&(0,t.rmSync)(s,{force:!0})}}catch{}}function l(e,t){let r=Math.floor(Date.now()/1e3),n=e.user??t;if(!n)throw Error("authFromTokenResponse: missing user identity");return{access_token:e.access_token,refresh_token:e.refresh_token,access_expires_at:r+e.access_expires_in,refresh_expires_at:r+e.refresh_expires_in,user:n}}let f=new Map;async function d(e){let t=f.get(e.refresh_token);if(t)return t;let r=(async()=>{let t=l(await (0,o.refreshAccessToken)(e.refresh_token),e.user);return c(t),t})();f.set(e.refresh_token,r);try{return await r}finally{f.delete(e.refresh_token)}}async function p(){let e=i();if(!e)return null;let t=Math.floor(Date.now()/1e3);if(e.access_expires_at-t>60)return e;try{return await d(e)}catch(e){return e instanceof o.AuthApiError&&401===e.status&&u(),null}}async function h(){let e=await p();if(!e)return null;try{return{me:await (0,o.fetchMe)(e.access_token),auth:e}}catch(e){if(e instanceof o.AuthApiError&&401===e.status){let e=i();if(!e)return null;try{let t=await d(e);return{me:await (0,o.fetchMe)(t.access_token),auth:t}}catch(e){e instanceof o.AuthApiError&&401===e.status&&u()}}return null}}e.s(["authFromTokenResponse",0,l,"deleteAuth",0,u,"readAuth",0,i,"whoAmI",0,h,"writeAuth",0,c])},78081,e=>{e.v(t=>Promise.all(["server/chunks/[externals]__0qxhecv._.js","server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js"].map(t=>e.l(t))).then(()=>t(39702)))}];
|
|
2
|
-
|
|
3
|
-
//# sourceMappingURL=%5Broot-of-the-server%5D__0_usx0j._.js.map
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
module.exports=[70406,(e,t,r)=>{t.exports=e.x("next/dist/compiled/@opentelemetry/api",()=>require("next/dist/compiled/@opentelemetry/api"))},18622,(e,t,r)=>{t.exports=e.x("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js",()=>require("next/dist/compiled/next-server/app-page-turbo.runtime.prod.js"))},20635,(e,t,r)=>{t.exports=e.x("next/dist/server/app-render/action-async-storage.external.js",()=>require("next/dist/server/app-render/action-async-storage.external.js"))},24725,(e,t,r)=>{t.exports=e.x("next/dist/server/app-render/after-task-async-storage.external.js",()=>require("next/dist/server/app-render/after-task-async-storage.external.js"))},56704,(e,t,r)=>{t.exports=e.x("next/dist/server/app-render/work-async-storage.external.js",()=>require("next/dist/server/app-render/work-async-storage.external.js"))},32319,(e,t,r)=>{t.exports=e.x("next/dist/server/app-render/work-unit-async-storage.external.js",()=>require("next/dist/server/app-render/work-unit-async-storage.external.js"))},59043,(e,t,r)=>{t.exports=e.x("next/dist/server/runtime-reacts.external.js",()=>require("next/dist/server/runtime-reacts.external.js"))},93695,(e,t,r)=>{t.exports=e.x("next/dist/shared/lib/no-fallback-error.external.js",()=>require("next/dist/shared/lib/no-fallback-error.external.js"))},74533,(e,t,r)=>{t.exports=e.x("node:child_process",()=>require("node:child_process"))},66680,(e,t,r)=>{t.exports=e.x("node:crypto",()=>require("node:crypto"))},2157,(e,t,r)=>{t.exports=e.x("node:fs",()=>require("node:fs"))},60526,(e,t,r)=>{t.exports=e.x("node:os",()=>require("node:os"))},50227,(e,t,r)=>{t.exports=e.x("node:path",()=>require("node:path"))},81111,(e,t,r)=>{t.exports=e.x("node:stream",()=>require("node:stream"))},94930,e=>{"use strict";var t=e.i(2157),r=e.i(50227),n=e.i(66680);e.s(["writeJsonAtomically",0,function(e,s,o={}){let a=o.mode??384,i=o.dirMode??448,c=(0,r.dirname)(e);(0,t.existsSync)(c)||(0,t.mkdirSync)(c,{recursive:!0,mode:i});let u=`${e}.${process.pid}.${(0,n.randomBytes)(6).toString("hex")}.tmp`;try{(0,t.writeFileSync)(u,JSON.stringify(s,null,2),{mode:a});try{(63&(0,t.statSync)(u).mode)!=0&&(0,t.chmodSync)(u,a)}catch{}(0,t.renameSync)(u,e);try{(63&(0,t.statSync)(e).mode)!=0&&(0,t.chmodSync)(e,a)}catch{}}catch(e){try{(0,t.rmSync)(u,{force:!0})}catch{}throw e}}])},6375,e=>{"use strict";var t=e.i(46501);function r(){return(process.env.FAILPROOF_API_URL??process.env.FAILPROOFAI_API_URL??"https://api.befailproof.ai").replace(/\/+$/,"")}class n extends Error{status;code;retryAfterSecs;constructor(e,t,r,n){super(r),this.status=e,this.code=t,this.retryAfterSecs=n,this.name="AuthApiError"}}async function s(e){let t={};try{t=await e.json()}catch{}let r=t.code??`http_${e.status}`,s=t.message??t.detail??e.statusText??"request failed",o=t.retry_after_secs;if(void 0===o){let t=e.headers.get("retry-after");if(t){let e=Number(t);Number.isFinite(e)&&(o=e)}}return void 0!==o&&(o=Math.max(0,Math.min(86400,o))),new n(e.status,r,s,o)}async function o(e,r){try{return await fetch(e,{...r,signal:function(e){let t=AbortSignal.timeout(1e4);if(!e)return t;let r=AbortSignal.any;if(r)return r([t,e]);let n=new AbortController;if(t.aborted)n.abort(t.reason);else t.addEventListener("abort",()=>n.abort(t.reason),{once:!0});if(e.aborted)n.abort(e.reason);else e.addEventListener("abort",()=>n.abort(e.reason),{once:!0});return n.signal}(r.signal??void 0)})}catch(o){let s=function(e){if(null===e||"object"!=typeof e)return!1;let t=e.name;return"AbortError"===t||"TimeoutError"===t}(o);if((0,t.trackEvent)("api_server_unreachable",{kind:s?"timeout":"network",path:function(e){try{return new URL(e).pathname}catch{return e}}(e),method:"string"==typeof r.method?r.method:"GET"}),s)throw new n(0,"timeout",`request to ${e} timed out after 10000ms`);throw o}}async function a(e,t,n){let a={"content-type":"application/json"};n?.accessToken&&(a.authorization=`Bearer ${n.accessToken}`);let i=await o(`${r()}${e}`,{method:"POST",headers:a,body:JSON.stringify(t)});if(204!==i.status){if(!i.ok)throw await s(i);return await i.json()}}async function i(e,t){let n=await o(`${r()}${e}`,{method:"GET",headers:{authorization:`Bearer ${t}`}});if(!n.ok)throw await s(n);return await n.json()}async function c(e){return a("/v0/auth/login/request",{email:e})}async function u(e,t){return a("/v0/auth/login/verify",{email:e,code:t})}async function l(e){return a("/v0/auth/token/refresh",{refresh_token:e})}async function f(e,t){await a("/v0/auth/logout",{refresh_token:t},{accessToken:e})}async function d(e){return i("/v0/auth/me",e)}async function p(e,t,r){return a("/v0/invite",void 0===r?{to:t}:{to:t,score:r},{accessToken:e})}e.s(["AuthApiError",0,n,"fetchMe",0,d,"logoutSession",0,f,"refreshAccessToken",0,l,"requestLoginCode",0,c,"sendInvites",0,p,"verifyLoginCode",0,u],6375)},17707,e=>{"use strict";var t=e.i(2157),r=e.i(50227),n=e.i(94930),s=e.i(79857),o=e.i(6375);function a(){let e=process.env.FAILPROOFAI_AUTH_DIR;return e?(0,r.join)(e,"session.json"):(0,s.auditSessionFile)()}function i(){let e=a();if(!(0,t.existsSync)(e))return null;try{let r=(0,t.readFileSync)(e,"utf-8"),n=JSON.parse(r);if("string"!=typeof n.access_token||"string"!=typeof n.refresh_token||"number"!=typeof n.access_expires_at||"object"!=typeof n.user||!n.user||"string"!=typeof n.user.id||"string"!=typeof n.user.email)return null;return{access_token:n.access_token,refresh_token:n.refresh_token,access_expires_at:n.access_expires_at,refresh_expires_at:"number"==typeof n.refresh_expires_at?n.refresh_expires_at:n.access_expires_at,user:{id:n.user.id,email:n.user.email}}}catch{return null}}function c(e){(0,n.writeJsonAtomically)(a(),e)}function u(){let e=a();(0,t.existsSync)(e)&&(0,t.rmSync)(e,{force:!0});try{let e=(0,s.migrationsDir)();if(!(0,t.existsSync)(e))return;for(let n of(0,t.readdirSync)(e)){if(!n.startsWith("backup-layout"))continue;let s=(0,r.resolve)(e,n,"auth.json");(0,t.existsSync)(s)&&(0,t.rmSync)(s,{force:!0})}}catch{}}function l(e,t){let r=Math.floor(Date.now()/1e3),n=e.user??t;if(!n)throw Error("authFromTokenResponse: missing user identity");return{access_token:e.access_token,refresh_token:e.refresh_token,access_expires_at:r+e.access_expires_in,refresh_expires_at:r+e.refresh_expires_in,user:n}}let f=new Map;async function d(e){let t=f.get(e.refresh_token);if(t)return t;let r=(async()=>{let t=l(await (0,o.refreshAccessToken)(e.refresh_token),e.user);return c(t),t})();f.set(e.refresh_token,r);try{return await r}finally{f.delete(e.refresh_token)}}async function p(){let e=i();if(!e)return null;let t=Math.floor(Date.now()/1e3);if(e.access_expires_at-t>60)return e;try{return await d(e)}catch(e){return e instanceof o.AuthApiError&&401===e.status&&u(),null}}async function h(){let e=await p();if(!e)return null;try{return{me:await (0,o.fetchMe)(e.access_token),auth:e}}catch(e){if(e instanceof o.AuthApiError&&401===e.status){let e=i();if(!e)return null;try{let t=await d(e);return{me:await (0,o.fetchMe)(t.access_token),auth:t}}catch(e){e instanceof o.AuthApiError&&401===e.status&&u()}}return null}}e.s(["authFromTokenResponse",0,l,"deleteAuth",0,u,"readAuth",0,i,"whoAmI",0,h,"writeAuth",0,c])},78081,e=>{e.v(t=>Promise.all(["server/chunks/[externals]__0qxhecv._.js","server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js"].map(t=>e.l(t))).then(()=>t(39702)))}];
|
|
2
|
-
|
|
3
|
-
//# sourceMappingURL=%5Broot-of-the-server%5D__0_zk340._.js.map
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
module.exports=[66680,(e,t,n)=>{t.exports=e.x("node:crypto",()=>require("node:crypto"))},2157,(e,t,n)=>{t.exports=e.x("node:fs",()=>require("node:fs"))},60526,(e,t,n)=>{t.exports=e.x("node:os",()=>require("node:os"))},3605,28898,e=>{"use strict";var t=e.i(50227),n=e.i(79708),i=e.i(2157),r=e.i(60526);let s="profiles",a="default";function o(){let e,n=function(){let e=(process.env.HERMES_HOME||"").trim();if(e){let n=(0,t.resolve)(e),i=(0,t.dirname)(n);return(0,t.basename)(i)===s?(0,t.dirname)(i):n}return(0,t.join)((0,r.homedir)(),".hermes")}(),o=[{name:a,home:n}],u=new Set([a]);try{e=(0,i.readdirSync)((0,t.join)(n,s),{withFileTypes:!0}).filter(e=>(e.isDirectory()||e.isSymbolicLink())&&!e.name.startsWith(".")).map(e=>e.name).sort()}catch{return o}for(let i of e)u.has(i)||(u.add(i),o.push({name:i,home:(0,t.join)(n,s,i)}));return o}function u(e,t){return`hermes:${e}:${t}`}e.s(["HERMES_DEFAULT_PROFILE",0,a,"hermesProjectName",0,function(e,t){return`hermes-${e}-${t}`},"hermesProjectNameCandidates",0,function(e){if(!e.startsWith("hermes-"))return[];let t=e.slice(7);if(!t)return[];let n=[];for(let e of o().map(e=>e.name).sort((e,t)=>t.length-e.length)){let i=`${e}-`;t.startsWith(i)&&t.length>i.length&&n.push({profile:e,source:t.slice(i.length)})}return n.push({profile:a,source:t}),n},"hermesProjectPath",0,u,"listHermesProfiles",0,o],28898);var l=e.i(83534),m=e.i(54214),f=e.i(67405);function p(){let e=process.env.HERMES_DB_PATH;return e?[{profile:a,dbPath:e}]:o().map(e=>({profile:e.name,dbPath:(0,t.join)(e.home,"state.db")}))}function c(e){if("string"==typeof e&&0!==e.length)try{return JSON.parse(e)}catch{return}}function d(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function y(e){return"string"==typeof e?e:Array.isArray(e)?e.map(e=>d(e)&&"string"==typeof e.text?e.text:"").filter(Boolean).join("\n"):""}async function h(e){if(!e||!/^[A-Za-z0-9_-]+$/.test(e))return null;for(let{profile:t,dbPath:n}of p()){let i=await g(n,t,e);if(i)return i}return null}async function g(e,t,i){let r=await (0,n.openSqliteReadonly)(e);if(!r)return null;try{let e=r.query("SELECT source, cwd FROM sessions WHERE id = ?",[i]);if(0===e.length)return null;let{source:n,cwd:s}=e[0],a=r.query("SELECT id, role, content, tool_call_id, tool_calls, tool_name, timestamp FROM messages WHERE session_id = ? ORDER BY timestamp ASC",[i]),o=function(e,t="session"){let n=[],i=new Map,r=new Map,s=Date.now();for(let a=0;a<e.length;a++){let o=e[a];if(!d(o))continue;let u="string"==typeof o.role?o.role:"system",l=function(e,t){if("number"==typeof e&&Number.isFinite(e)){if(e>1e12)return new Date(e);if(e>1e9)return new Date(1e3*e)}if("string"==typeof e){let t=Date.parse(e);if(!Number.isNaN(t))return new Date(t)}return new Date(t)}(o.timestamp??o.time_created,s+a),p=l.toISOString(),h={uuid:null!=o.id?String(o.id):`hermes-${a}`,parentUuid:null},g=(0,m.baseEntry)(h,p,l,t);if("user"===u){n.push({type:"user",...g,message:{role:"user",content:y(o.content)}});continue}if("assistant"===u){let e=[],t=y(o.content);for(let n of(t&&e.push({type:"text",text:t}),function(e){let t=Array.isArray(e)?e:c(e);if(!Array.isArray(t))return[];let n=[];for(let e of t){if(!d(e))continue;let t=d(e.function)?e.function:{},i="string"==typeof t.name?t.name:"string"==typeof e.name?e.name:"tool",r="string"==typeof e.id&&e.id||"string"==typeof e.call_id&&e.call_id||`${i}-${n.length}`,s=d(t.arguments)?t.arguments:c(t.arguments);n.push({id:r,name:i,input:d(s)?s:{}})}return n}(o.tool_calls))){let t={type:"tool_use",id:n.id,name:n.name,input:n.input};e.push(t),i.set(n.id,t),r.set(n.id,l.getTime())}if(0===e.length)continue;n.push({type:"assistant",...g,message:{role:"assistant",content:e}});continue}if("tool"===u){let e="string"==typeof o.tool_call_id?o.tool_call_id:void 0,t=e?i.get(e):void 0;if(t){let n=e&&r.get(e)||l.getTime(),i=Math.max(0,l.getTime()-n);t.result={timestamp:p,timestampFormatted:(0,m.formatTimestamp)(l),content:y(o.content),durationMs:i,durationFormatted:(0,f.formatDuration)(i)};continue}}n.push({type:"system",...g,raw:h})}return n.sort((e,t)=>e.timestampMs-t.timestampMs),n}(a,"session"),l=s&&s.length>0?s:n?u(t,n):void 0;return{entries:o,rawLines:a,cwd:l,filePath:`hermes://${i}`,profile:t}}catch{return null}finally{r.close()}}(0,l.runtimeCache)(e=>h(e),2,{maxSize:50}),e.s(["epochToMs",0,function(e){if("number"==typeof e&&Number.isFinite(e)){if(e>1e12)return e;if(e>1e9)return 1e3*e}return Date.now()},"getHermesSessionLog",0,h,"hermesDbPaths",0,p],3605)},54214,67405,e=>{"use strict";var t=e.i(24868),n=e.i(14747),i=e.i(81580),r=e.i(56936);async function s(e,i,r,s){let a=`agent-${s}.jsonl`;for(let s of[(0,n.join)(e,i,a),(0,n.join)(e,i,r,a),(0,n.join)(e,i,r,"subagents",a)])if(!(0,n.relative)(e,s).startsWith(".."))try{return await (0,t.access)(s),s}catch(e){if("ENOENT"===e.code)continue;break}return null}var a=e.i(83534),o=e.i(71809),u=e.i(28557);function l(e){if(e<1e3)return`${e}ms`;let t=Math.round(e/100);if(t<600)return`${(t/10).toFixed(1)}s`;let n=Math.round(e/1e3);if(n<3600){let e=Math.floor(n/60);return`${e}m ${n%60}s`}let i=Math.round(e/6e4),r=Math.floor(i/60);return`${r}h ${i%60}m`}function m(e){let t=(0,u.formatDate)(e),n=e.getMilliseconds().toString().padStart(3,"0");return`${t}.${n}`}function f(e,t,n,i){return{_source:i,uuid:e.uuid||"",parentUuid:e.parentUuid??null,timestamp:t,timestampMs:n.getTime(),timestampFormatted:m(n)}}async function p(e,t){let n=e.split("\n").filter(e=>""!==e.trim()),i=new Map,r=[],s=[],a=new Set,o=!1;for(let e=0;e<n.length;e++){let u;e>0&&e%200==0&&await new Promise(e=>setImmediate(e));let l=n[e];try{u=JSON.parse(l)}catch{continue}let m={...u,_source:t};s.push(m);let p=u.type,c=u.timestamp;if(!c)continue;let d=new Date(c),y=d.getTime();if("user"===p){let e=u.message;if(Array.isArray(e?.content)){let t=e.content;if(t.some(e=>"tool_result"===e.type)){let e=u.toolUseResult,n="string"==typeof e?.agentId?e.agentId:void 0;for(let e of(n&&/^[a-f0-9]+$/.test(n)&&a.add(n),t)){if("tool_result"!==e.type)continue;let t=e.tool_use_id;if(!t)continue;let{text:r,images:s}=function(e){let t=e.content;if("string"==typeof t)return{text:t};if(Array.isArray(t)){let e=t.filter(e=>"text"===e.type).map(e=>e.text),n=t.filter(e=>"image"===e.type).map(e=>{let t=e.source;return{base64:t.data,mediaType:t.media_type}}).filter(e=>e.base64&&e.mediaType);return{text:e.length>0?e.join("\n"):void 0,images:n.length>0?n:void 0}}return{}}(e);i.set(t,{timestamp:c,timestampMs:y,content:r,images:s,agentId:n})}continue}}let n="string"==typeof e?.content?e.content:"";r.push({type:"user",...f(u,c,d,t),message:{role:"user",content:n}});continue}if("assistant"===p){let e=u.message,n=[];if(Array.isArray(e?.content)&&(n=e.content.filter(e=>["text","tool_use","thinking"].includes(e.type)).map(e=>{if("text"===e.type)return{type:"text",text:e.text};if("tool_use"===e.type){let t=e.input;return{type:"tool_use",id:e.id,name:e.name,input:e.input??{},..."Task"===e.name&&t?{subagentType:t.subagent_type,subagentDescription:t.description}:{}}}return{type:"thinking",thinking:e.thinking,signature:e.signature}})),0===n.length)continue;r.push({type:"assistant",...f(u,c,d,t),message:{role:"assistant",content:n,model:e?.model}});continue}if("file-history-snapshot"===p||"progress"===p||"system"===p){r.push({type:p,...f(u,c,d,t),raw:{...u}});continue}if("queue-operation"===p){let e=o?"Session Resumed":"Session Started";o=!0,r.push({type:"queue-operation",...f(u,c,d,t),label:e});continue}}let u=0;for(let e of r)if("assistant"===e.type)for(let t of(++u%200==0&&await new Promise(e=>setImmediate(e)),e.message.content)){if("tool_use"!==t.type)continue;let n=i.get(t.id);if(!n)continue;let r=new Date(n.timestamp),s=Math.max(0,n.timestampMs-e.timestampMs);t.result={timestamp:n.timestamp,timestampFormatted:m(r),content:n.content,images:n.images,durationMs:s,durationFormatted:l(s)},n.agentId&&(t.subagentId=n.agentId)}return r.length>500&&await new Promise(e=>setImmediate(e)),r.sort((e,t)=>e.timestampMs-t.timestampMs),{entries:r,rawLines:s,subagentIds:Array.from(a)}}async function c(e,t="session"){return(await p(e,t)).entries}async function d(e,a){let u=(0,r.resolveProjectPath)(e),l=(0,i.getClaudeProjectsPath)(),m=(0,n.join)(u,`${a}.jsonl`),f=await (0,t.readFile)(m,"utf-8"),{entries:c,rawLines:d,subagentIds:y}=await p(f,"session");if(0===y.length)return{entries:c,rawLines:d,subagentIds:[]};let h=await (0,o.batchAll)(y.map(n=>async()=>{let i=`agent-${n}`,r=await s(l,e,a,n);if(!r)return null;let o=await (0,t.readFile)(r,"utf-8"),{entries:u,rawLines:m}=await p(o,i);return{entries:u,rawLines:m}}),4),g=[...c],w=[...d];for(let e of h)"fulfilled"===e.status&&e.value&&(g.push(...e.value.entries),w.push(...e.value.rawLines));return g.length>500&&await new Promise(e=>setImmediate(e)),g.sort((e,t)=>e.timestampMs-t.timestampMs),{entries:g,rawLines:w,subagentIds:y}}e.s(["formatDuration",0,l],67405),(0,a.runtimeCache)((e,t)=>d(e,t),60,{maxSize:50}),e.s(["baseEntry",0,f,"formatTimestamp",0,m,"parseLogContent",0,c,"parseRawLines",0,function(e,t){return e.split("\n").filter(e=>""!==e.trim()).flatMap(e=>{try{let n=JSON.parse(e);return void 0!==t&&(n._source=t),[n]}catch{return[]}})}],54214)}];
|
|
2
|
-
|
|
3
|
-
//# sourceMappingURL=%5Broot-of-the-server%5D__0jnjf2t._.js.map
|