failproofai 0.0.13-beta.0 → 0.0.13-beta.1
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 +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 +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 +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
- 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 +10 -10
- 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 +2 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js +2 -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 +3 -2
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js +1 -1
- 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 +2 -2
- 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 +2 -2
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js +2 -2
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js +2 -2
- 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 +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 +1 -1
- 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 +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +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 +2 -2
- 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 +3 -2
- 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 +3 -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 +2 -2
- 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]__0_0xu5z._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cefjd9._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ekj92q._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0hv08mx._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0obaznk._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0xvsnvt._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__12v-lma._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__136y39g._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__13h8pzr._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1hkdkmz._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1i9rknc._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1mrihkj._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +3 -0
- package/.next/standalone/.next/server/chunks/{[root-of-the-server]__0cycwg6._.js → [root-of-the-server]__1tvn4wf._.js} +2 -2
- package/.next/standalone/.next/server/chunks/_1z062h5._.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +5 -5
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__015_i4t._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__03lv-pe._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04bqvos._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1-m1rhq._.js → [root-of-the-server]__099afy6._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0dqgs96._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1uvfwgr._.js → [root-of-the-server]__0hdsupo._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0q5rfxg._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qeuy9c._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qukut7._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s89hoe._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0ehe24g._.js → [root-of-the-server]__0ynf7tx._.js} +3 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__170799-._.js +245 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1d8omgc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ql-mch._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0bbpv2d._.js → [root-of-the-server]__1qlh4jx._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tkjqka._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/_05whahf._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0ul5rf_._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_11v0g3z._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_1p0-leb._.js +1 -1
- 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 +1 -1
- package/.next/standalone/.next/server/chunks/ssr/lib_hermes-projects_ts_05b8-it._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_1u91ynr.js → node_modules_html-to-image_es_index_0pv57nx.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 +10 -10
- package/.next/standalone/.next/static/chunks/{0azkpcy8eb1gr.js → 0b6rdtcge_3ec.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1zxtyef-iqede.js → 0pj_6lbbjd000.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1h569gia53ant.js → 0xnrgonfdeivm.js} +1 -1
- package/.next/standalone/.next/static/chunks/{39rn602wszcbd.js → 105w_oznq-van.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0byua6ng1f_ka.js → 13tbm6i1swiru.js} +1 -1
- package/.next/standalone/.next/static/chunks/{41mhnhfkmglpp.js → 1fhuj4fjovzp5.js} +1 -1
- package/.next/standalone/.next/static/chunks/209ful1jrphvy.js +1 -0
- package/.next/standalone/.next/static/chunks/{3jka0hvhqouyv.js → 23odnajn2ltwu.js} +1 -1
- package/.next/standalone/.next/static/chunks/25s52un3k_wht.css +2 -0
- package/.next/standalone/.next/static/chunks/36r2vgi6854za.js +6 -0
- package/.next/standalone/.next/static/chunks/3b77kulbdbrqw.js +1 -0
- package/.next/standalone/.next/static/chunks/3rjg-1s5ouu5r.js +1 -0
- package/.next/standalone/app/components/sessions-list.tsx +19 -0
- package/.next/standalone/app/project/[name]/page.tsx +9 -4
- package/.next/standalone/app/project/[name]/session/[sessionId]/page.tsx +26 -5
- package/.next/standalone/assets/logos/hermes-dark.svg +1 -0
- package/.next/standalone/assets/logos/hermes-light.svg +1 -0
- package/.next/standalone/lib/cli-registry.ts +6 -1
- package/.next/standalone/lib/download-session.ts +16 -0
- package/.next/standalone/lib/hermes-projects.ts +164 -0
- package/.next/standalone/lib/hermes-sessions.ts +273 -0
- package/.next/standalone/lib/projects.ts +14 -3
- package/.next/standalone/lib/sqlite-reader.ts +102 -0
- package/.next/standalone/package.json +5 -3
- package/.next/standalone/server.js +1 -1
- package/README.md +10 -1
- package/bin/failproofai.mjs +17 -16
- package/dist/cli.mjs +7762 -226
- package/lib/cli-registry.ts +6 -1
- package/lib/download-session.ts +16 -0
- package/lib/hermes-projects.ts +164 -0
- package/lib/hermes-sessions.ts +273 -0
- package/lib/projects.ts +14 -3
- package/lib/sql-js-asm.d.ts +26 -0
- package/lib/sqlite-reader.ts +102 -0
- package/package.json +5 -3
- package/src/audit/cli-adapters/hermes.ts +58 -0
- package/src/audit/cli-adapters/index.ts +6 -0
- package/src/hooks/handler.ts +8 -0
- package/src/hooks/install-prompt.ts +7 -3
- package/src/hooks/integrations.ts +179 -5
- package/src/hooks/policy-evaluator.ts +42 -0
- package/src/hooks/resolve-transcript-path.ts +4 -0
- package/src/hooks/tool-name-canonicalize.ts +6 -0
- package/src/hooks/types.ts +67 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0dwpg-h._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0lnenda._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__13i_sva._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1_mqemn._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1m2_4t0._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_0-tu4ot._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_0ttxbz7._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_1bnh1y0._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_1epycqa._.js +0 -3
- package/.next/standalone/.next/server/chunks/node_modules_1wpdcgo._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0808sha._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e4-6d8._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0f62vu9._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g253ve._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0k65l27._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0vxf0_g._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12mcauo._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1e-x7j4._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1mt35_w._.js +0 -221
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pcxxwg._.js +0 -4
- package/.next/standalone/.next/static/chunks/03zg3ms7uaoq3.js +0 -1
- package/.next/standalone/.next/static/chunks/0f7d7hnbh4djs.js +0 -1
- package/.next/standalone/.next/static/chunks/1o0xa47736gi9.css +0 -2
- package/.next/standalone/.next/static/chunks/2ks4pzu5b-l_q.js +0 -6
- package/.next/standalone/.next/static/chunks/2wbuxnsvux4di.js +0 -1
- /package/.next/standalone/.next/static/{W6ELw5VwHTFy2amS2px6e → 31ZoDDYKHEIN_TrgKv85t}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{W6ELw5VwHTFy2amS2px6e → 31ZoDDYKHEIN_TrgKv85t}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{W6ELw5VwHTFy2amS2px6e → 31ZoDDYKHEIN_TrgKv85t}/_ssgManifest.js +0 -0
|
@@ -16,7 +16,7 @@ import { formatDate } from "./format-date";
|
|
|
16
16
|
export const UUID_RE = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/;
|
|
17
17
|
export const PATH_TRAVERSAL_RE = /(^|[\\/])\.\.($|[\\/])/;
|
|
18
18
|
|
|
19
|
-
export type ProjectCli = "claude" | "codex" | "copilot" | "cursor" | "opencode" | "pi" | "gemini";
|
|
19
|
+
export type ProjectCli = "claude" | "codex" | "copilot" | "cursor" | "opencode" | "pi" | "gemini" | "hermes";
|
|
20
20
|
|
|
21
21
|
export interface ProjectFolder {
|
|
22
22
|
name: string;
|
|
@@ -40,6 +40,11 @@ export interface SessionFile {
|
|
|
40
40
|
/** Originating agent CLI. Set when the session list mixes sources from more
|
|
41
41
|
* than one CLI, so the table can render a per-row CLI badge. */
|
|
42
42
|
cli?: ProjectCli;
|
|
43
|
+
/** Gateway session metadata (Hermes only today): who drove it and where.
|
|
44
|
+
* Other CLIs leave these undefined; the list renders them only when present. */
|
|
45
|
+
userId?: string;
|
|
46
|
+
channelId?: string;
|
|
47
|
+
channelType?: string; // e.g. "group" | "dm"
|
|
43
48
|
}
|
|
44
49
|
|
|
45
50
|
/** Stats a path and returns mtime. Falls back to epoch (1970-01-01) on error
|
|
@@ -139,6 +144,7 @@ export async function getProjectFolders(): Promise<ProjectFolder[]> {
|
|
|
139
144
|
{ getOpenCodeProjects },
|
|
140
145
|
{ getPiProjects },
|
|
141
146
|
{ getGeminiProjects },
|
|
147
|
+
{ getHermesProjects },
|
|
142
148
|
] = await Promise.all([
|
|
143
149
|
import("./codex-projects"),
|
|
144
150
|
import("./copilot-projects"),
|
|
@@ -146,8 +152,9 @@ export async function getProjectFolders(): Promise<ProjectFolder[]> {
|
|
|
146
152
|
import("./opencode-projects"),
|
|
147
153
|
import("./pi-projects"),
|
|
148
154
|
import("./gemini-projects"),
|
|
155
|
+
import("./hermes-projects"),
|
|
149
156
|
]);
|
|
150
|
-
const [claude, codex, copilot, cursor, opencode, pi, gemini] = await Promise.all([
|
|
157
|
+
const [claude, codex, copilot, cursor, opencode, pi, gemini, hermes] = await Promise.all([
|
|
151
158
|
getClaudeProjectFolders(),
|
|
152
159
|
getCodexProjects().catch((error) => {
|
|
153
160
|
logError("Error reading Codex projects:", error);
|
|
@@ -173,8 +180,12 @@ export async function getProjectFolders(): Promise<ProjectFolder[]> {
|
|
|
173
180
|
logError("Error reading Gemini projects:", error);
|
|
174
181
|
return [] as ProjectFolder[];
|
|
175
182
|
}),
|
|
183
|
+
getHermesProjects().catch((error) => {
|
|
184
|
+
logError("Error reading Hermes projects:", error);
|
|
185
|
+
return [] as ProjectFolder[];
|
|
186
|
+
}),
|
|
176
187
|
]);
|
|
177
|
-
return mergeProjectFolders(claude, codex, copilot, cursor, opencode, pi, gemini);
|
|
188
|
+
return mergeProjectFolders(claude, codex, copilot, cursor, opencode, pi, gemini, hermes);
|
|
178
189
|
}
|
|
179
190
|
|
|
180
191
|
/**
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reusable read-only SQLite access for audit adapters of SQLite-backed agents.
|
|
3
|
+
*
|
|
4
|
+
* Tiered so we read LIVE data (including the write-ahead log) wherever possible,
|
|
5
|
+
* and still run anywhere:
|
|
6
|
+
* 1. `node:sqlite` — a real connection that reads main DB + WAL together, so
|
|
7
|
+
* brand-new rows are visible immediately. Built into Node ≥ 22.5 (no native
|
|
8
|
+
* module, no flag on recent 22.x). Preferred.
|
|
9
|
+
* 2. `sql.js` (pure-JS/asm) — portable fallback for older Node. Reads the main
|
|
10
|
+
* DB file's bytes only, so it reflects a snapshot up to the last WAL
|
|
11
|
+
* checkpoint (very recent rows may lag). No native module — survives
|
|
12
|
+
* `npm install --ignore-scripts`.
|
|
13
|
+
*
|
|
14
|
+
* Either way: read-only, and `null` on any failure (fail-open, so an absent or
|
|
15
|
+
* locked DB makes the audit skip that agent rather than crash).
|
|
16
|
+
*
|
|
17
|
+
* NOTE: opencode and every CLI that already ships keep their existing CLI
|
|
18
|
+
* shell-out — this layer is only for new SQLite integrations.
|
|
19
|
+
*/
|
|
20
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
21
|
+
import initSqlJs, { type SqlJsStatic } from "sql.js/dist/sql-asm.js";
|
|
22
|
+
|
|
23
|
+
export interface SqliteReader {
|
|
24
|
+
/** Run a parameterized read-only query; returns rows as plain objects. */
|
|
25
|
+
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): T[];
|
|
26
|
+
close(): void;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ── Tier 1: node:sqlite (WAL-aware, Node ≥ 22.5) ──
|
|
30
|
+
|
|
31
|
+
interface NodeSqliteStmt {
|
|
32
|
+
all(...params: unknown[]): Record<string, unknown>[];
|
|
33
|
+
}
|
|
34
|
+
interface NodeSqliteDb {
|
|
35
|
+
prepare(sql: string): NodeSqliteStmt;
|
|
36
|
+
close(): void;
|
|
37
|
+
}
|
|
38
|
+
interface NodeSqliteModule {
|
|
39
|
+
DatabaseSync: new (path: string, options?: { readOnly?: boolean }) => NodeSqliteDb;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function tryNodeSqlite(dbPath: string): Promise<SqliteReader | null> {
|
|
43
|
+
try {
|
|
44
|
+
// Dynamic import: on Node < 22.5 this rejects and we fall through to sql.js.
|
|
45
|
+
const mod = (await import("node:sqlite")) as unknown as NodeSqliteModule;
|
|
46
|
+
const db = new mod.DatabaseSync(dbPath, { readOnly: true });
|
|
47
|
+
return {
|
|
48
|
+
query<T = Record<string, unknown>>(sql: string, params: unknown[] = []): T[] {
|
|
49
|
+
const stmt = db.prepare(sql);
|
|
50
|
+
return (params.length ? stmt.all(...params) : stmt.all()) as T[];
|
|
51
|
+
},
|
|
52
|
+
close() {
|
|
53
|
+
db.close();
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
} catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ── Tier 2: sql.js (portable snapshot) ──
|
|
62
|
+
|
|
63
|
+
let sqlPromise: Promise<SqlJsStatic> | null = null;
|
|
64
|
+
function loadSqlJs(): Promise<SqlJsStatic> {
|
|
65
|
+
if (!sqlPromise) sqlPromise = initSqlJs();
|
|
66
|
+
return sqlPromise;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function trySqlJs(dbPath: string): Promise<SqliteReader | null> {
|
|
70
|
+
try {
|
|
71
|
+
const SQL = await loadSqlJs();
|
|
72
|
+
const db = new SQL.Database(readFileSync(dbPath));
|
|
73
|
+
return {
|
|
74
|
+
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): T[] {
|
|
75
|
+
const stmt = db.prepare(sql);
|
|
76
|
+
try {
|
|
77
|
+
if (params && params.length) stmt.bind(params);
|
|
78
|
+
const rows: T[] = [];
|
|
79
|
+
while (stmt.step()) rows.push(stmt.getAsObject() as T);
|
|
80
|
+
return rows;
|
|
81
|
+
} finally {
|
|
82
|
+
stmt.free();
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
close() {
|
|
86
|
+
db.close();
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
} catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Open a SQLite database file READ-ONLY. Prefers a WAL-aware `node:sqlite`
|
|
96
|
+
* connection (live data), falls back to a `sql.js` snapshot. Returns `null` on
|
|
97
|
+
* any failure. Always `close()` the reader when done.
|
|
98
|
+
*/
|
|
99
|
+
export async function openSqliteReadonly(dbPath: string): Promise<SqliteReader | null> {
|
|
100
|
+
if (!existsSync(dbPath)) return null;
|
|
101
|
+
return (await tryNodeSqlite(dbPath)) ?? (await trySqlJs(dbPath));
|
|
102
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "failproofai",
|
|
3
|
-
"version": "0.0.13-beta.
|
|
3
|
+
"version": "0.0.13-beta.1",
|
|
4
4
|
"description": "The easiest way to manage policies that keep your AI agents reliable, on-task, and running autonomously — for Claude Code & the Agents SDK",
|
|
5
5
|
"bin": {
|
|
6
6
|
"failproofai": "./dist/cli.mjs"
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"scripts": {
|
|
23
23
|
"predev": "bun run build:cli && bun link",
|
|
24
24
|
"dev": "FAILPROOFAI_TELEMETRY_DISABLED=1 bun scripts/dev.ts --port 8020",
|
|
25
|
-
"build:cli": "bun build --target=node --format=esm --outfile=dist/cli.mjs bin/failproofai.mjs --external posthog-node && node -e \"const fs=require('fs');const c=fs.readFileSync('dist/cli.mjs','utf8');fs.writeFileSync('dist/cli.mjs',c.replace('#!/usr/bin/env bun','#!/usr/bin/env node').replace('// @bun\\n',''))\"",
|
|
25
|
+
"build:cli": "bun build --target=node --format=esm --outfile=dist/cli.mjs bin/failproofai.mjs --external posthog-node --external sql.js && node -e \"const fs=require('fs');const c=fs.readFileSync('dist/cli.mjs','utf8');fs.writeFileSync('dist/cli.mjs',c.replace('#!/usr/bin/env bun','#!/usr/bin/env node').replace('// @bun\\n',''))\"",
|
|
26
26
|
"build": "bun build --target=node --format=cjs --outfile=dist/index.js src/index.ts && bun run build:cli && bun --bun next build && node -e \"const {cpSync}=require('fs');cpSync('.next/static','.next/standalone/.next/static',{recursive:true});\" && node scripts/prune-standalone.mjs",
|
|
27
27
|
"prestart": "bun run build:cli && bun link",
|
|
28
28
|
"start": "FAILPROOFAI_TELEMETRY_DISABLED=1 bun scripts/start.ts",
|
|
@@ -99,7 +99,9 @@
|
|
|
99
99
|
"dependencies": {
|
|
100
100
|
"html-to-image": "^1.11.13",
|
|
101
101
|
"html2canvas": "^1.4.1",
|
|
102
|
-
"posthog-node": "^5.37.1"
|
|
102
|
+
"posthog-node": "^5.37.1",
|
|
103
|
+
"sql.js": "^1.14.1",
|
|
104
|
+
"yaml": "^2.9.0"
|
|
103
105
|
},
|
|
104
106
|
"overrides": {
|
|
105
107
|
"postcss": "8.5.14",
|
|
@@ -9,7 +9,7 @@ const currentPort = parseInt(process.env.PORT, 10) || 3000
|
|
|
9
9
|
const hostname = process.env.HOSTNAME || '0.0.0.0'
|
|
10
10
|
|
|
11
11
|
let keepAliveTimeout = parseInt(process.env.KEEP_ALIVE_TIMEOUT, 10)
|
|
12
|
-
const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"0.0.13-beta.
|
|
12
|
+
const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"0.0.13-beta.1"},"typescript":{"ignoreBuildErrors":false},"typedRoutes":false,"distDir":"./.next","cleanDistDir":true,"assetPrefix":"","cacheMaxMemorySize":52428800,"configOrigin":"next.config.ts","useFileSystemPublicRoutes":true,"generateEtags":true,"pageExtensions":["tsx","ts","jsx","js"],"poweredByHeader":true,"compress":true,"images":{"deviceSizes":[640,750,828,1080,1200,1920,2048,3840],"imageSizes":[32,48,64,96,128,256,384],"path":"/_next/image","loader":"default","loaderFile":"","domains":[],"disableStaticImages":false,"minimumCacheTTL":14400,"formats":["image/webp"],"maximumRedirects":3,"maximumResponseBody":50000000,"dangerouslyAllowLocalIP":false,"dangerouslyAllowSVG":false,"contentSecurityPolicy":"script-src 'none'; frame-src 'none'; sandbox;","contentDispositionType":"attachment","localPatterns":[{"pathname":"**","search":""}],"remotePatterns":[],"qualities":[75],"unoptimized":true,"customCacheHandler":false},"devIndicators":{"position":"bottom-left"},"onDemandEntries":{"maxInactiveAge":60000,"pagesBufferLength":5},"basePath":"","sassOptions":{},"trailingSlash":false,"i18n":null,"productionBrowserSourceMaps":false,"excludeDefaultMomentLocales":true,"reactProductionProfiling":false,"reactStrictMode":null,"reactMaxHeadersLength":6000,"httpAgentOptions":{"keepAlive":true},"logging":{"serverFunctions":true,"browserToTerminal":"warn"},"compiler":{},"expireTime":31536000,"staticPageGenerationTimeout":60,"output":"standalone","modularizeImports":{"@mui/icons-material":{"transform":"@mui/icons-material/{{member}}"},"lodash":{"transform":"lodash/{{member}}"}},"outputFileTracingRoot":"/home/runner/work/failproofai/failproofai","cacheComponents":false,"cacheLife":{"default":{"stale":300,"revalidate":900,"expire":4294967294},"seconds":{"stale":30,"revalidate":1,"expire":60},"minutes":{"stale":300,"revalidate":60,"expire":3600},"hours":{"stale":300,"revalidate":3600,"expire":86400},"days":{"stale":300,"revalidate":86400,"expire":604800},"weeks":{"stale":300,"revalidate":604800,"expire":2592000},"max":{"stale":300,"revalidate":2592000,"expire":31536000}},"cacheHandlers":{},"experimental":{"appNewScrollHandler":false,"useSkewCookie":false,"cssChunking":true,"multiZoneDraftMode":false,"appNavFailHandling":false,"prerenderEarlyExit":true,"serverMinification":true,"linkNoTouchStart":false,"caseSensitiveRoutes":false,"cachedNavigations":false,"partialFallbacks":false,"dynamicOnHover":false,"varyParams":false,"prefetchInlining":false,"preloadEntriesOnStart":true,"clientRouterFilter":true,"clientRouterFilterRedirects":false,"fetchCacheKeyPrefix":"","proxyPrefetch":"flexible","optimisticClientCache":true,"manualClientBasePath":false,"cpus":3,"memoryBasedWorkersCount":false,"imgOptConcurrency":null,"imgOptTimeoutInSeconds":7,"imgOptMaxInputPixels":268402689,"imgOptSequentialRead":null,"imgOptSkipMetadata":null,"isrFlushToDisk":true,"workerThreads":false,"optimizeCss":false,"nextScriptWorkers":false,"scrollRestoration":false,"externalDir":false,"disableOptimizedLoading":false,"gzipSize":true,"craCompat":false,"esmExternals":true,"fullySpecified":false,"swcTraceProfiling":false,"forceSwcTransforms":false,"largePageDataBytes":128000,"typedEnv":false,"parallelServerCompiles":false,"parallelServerBuildTraces":false,"ppr":false,"authInterrupts":false,"webpackMemoryOptimizations":false,"optimizeServerReact":true,"strictRouteTypes":false,"viewTransition":false,"removeUncaughtErrorAndRejectionListeners":false,"validateRSCRequestHeaders":false,"staleTimes":{"dynamic":0,"static":300},"reactDebugChannel":true,"serverComponentsHmrCache":true,"staticGenerationMaxConcurrency":8,"staticGenerationMinPagesPerWorker":25,"transitionIndicator":false,"gestureTransition":false,"inlineCss":false,"useCache":false,"globalNotFound":false,"browserDebugInfoInTerminal":"warn","lockDistDir":true,"proxyClientMaxBodySize":10485760,"hideLogsAfterAbort":false,"mcpServer":true,"turbopackFileSystemCacheForDev":true,"turbopackFileSystemCacheForBuild":false,"turbopackInferModuleSideEffects":true,"turbopackPluginRuntimeStrategy":"childProcesses","optimizePackageImports":["lucide-react","date-fns","lodash-es","ramda","antd","react-bootstrap","ahooks","@ant-design/icons","@headlessui/react","@headlessui-float/react","@heroicons/react/20/solid","@heroicons/react/24/solid","@heroicons/react/24/outline","@visx/visx","@tremor/react","rxjs","@mui/material","@mui/icons-material","recharts","react-use","effect","@effect/schema","@effect/platform","@effect/platform-node","@effect/platform-browser","@effect/platform-bun","@effect/sql","@effect/sql-mssql","@effect/sql-mysql2","@effect/sql-pg","@effect/sql-sqlite-node","@effect/sql-sqlite-bun","@effect/sql-sqlite-wasm","@effect/sql-sqlite-react-native","@effect/rpc","@effect/rpc-http","@effect/typeclass","@effect/experimental","@effect/opentelemetry","@material-ui/core","@material-ui/icons","@tabler/icons-react","mui-core","react-icons/ai","react-icons/bi","react-icons/bs","react-icons/cg","react-icons/ci","react-icons/di","react-icons/fa","react-icons/fa6","react-icons/fc","react-icons/fi","react-icons/gi","react-icons/go","react-icons/gr","react-icons/hi","react-icons/hi2","react-icons/im","react-icons/io","react-icons/io5","react-icons/lia","react-icons/lib","react-icons/lu","react-icons/md","react-icons/pi","react-icons/ri","react-icons/rx","react-icons/si","react-icons/sl","react-icons/tb","react-icons/tfi","react-icons/ti","react-icons/vsc","react-icons/wi"],"trustHostHeader":false,"isExperimentalCompile":false},"htmlLimitedBots":"[\\w-]+-Google|Google-[\\w-]+|Chrome-Lighthouse|Slurp|DuckDuckBot|baiduspider|yandex|sogou|bitlybot|tumblr|vkShare|quora link preview|redditbot|ia_archiver|Bingbot|BingPreview|applebot|facebookexternalhit|facebookcatalog|Twitterbot|LinkedInBot|Slackbot|Discordbot|WhatsApp|SkypeUriPreview|Yeti|googleweblight","bundlePagesRouterDependencies":false,"configFileName":"next.config.ts","outputFileTracingExcludes":{"*":["node_modules/@img/**","node_modules/sharp/**"]},"turbopack":{"root":"/home/runner/work/failproofai/failproofai"},"distDirRoot":".next"}
|
|
13
13
|
|
|
14
14
|
process.env.__NEXT_PRIVATE_STANDALONE_CONFIG = JSON.stringify(nextConfig)
|
|
15
15
|
|
package/README.md
CHANGED
|
@@ -72,9 +72,18 @@ before they become incidents. Zero latency. Runs locally.
|
|
|
72
72
|
<img src="assets/logos/gemini-light.svg" alt="Gemini CLI" width="64" height="64" />
|
|
73
73
|
</picture>
|
|
74
74
|
</a>
|
|
75
|
+
|
|
76
|
+
<a href="https://github.com/FailproofAI/failproofai/blob/main/docs/configuration.mdx" title="Hermes (hermes-agent)">
|
|
77
|
+
<picture>
|
|
78
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/logos/hermes-dark.svg" />
|
|
79
|
+
<img src="assets/logos/hermes-light.svg" alt="Hermes" width="64" height="64" />
|
|
80
|
+
</picture>
|
|
81
|
+
</a>
|
|
75
82
|
</p>
|
|
76
83
|
|
|
77
|
-
> Install hooks for one or any combination: `failproofai policies --install --cli opencode pi gemini` (or `--cli claude codex copilot cursor opencode pi gemini`). Omit `--cli` to auto-detect installed CLIs and prompt.
|
|
84
|
+
> Install hooks for one or any combination: `failproofai policies --install --cli opencode pi gemini` (or `--cli claude codex copilot cursor opencode pi gemini hermes`). Omit `--cli` to auto-detect installed CLIs and prompt.
|
|
85
|
+
>
|
|
86
|
+
> **Hermes** (hermes-agent, a Slack/Telegram gateway) is supported for both **live-hook enforcement** (`--cli hermes` — one install intercepts tool calls from every platform and subagent) and offline **audit** replay of its gateway sessions from the single `~/.hermes/state.db`.
|
|
78
87
|
|
|
79
88
|
---
|
|
80
89
|
|
package/bin/failproofai.mjs
CHANGED
|
@@ -65,7 +65,7 @@ const hookIdx = args.indexOf("--hook");
|
|
|
65
65
|
if (hookIdx >= 0) {
|
|
66
66
|
if (!args[hookIdx + 1]) {
|
|
67
67
|
console.error("Error: Missing event type after --hook");
|
|
68
|
-
console.error("Usage: failproofai --hook <event> [--cli <claude|codex|copilot|cursor|opencode|pi|gemini>]");
|
|
68
|
+
console.error("Usage: failproofai --hook <event> [--cli <claude|codex|copilot|cursor|opencode|pi|gemini|hermes>]");
|
|
69
69
|
process.exit(1);
|
|
70
70
|
}
|
|
71
71
|
const eventType = args[hookIdx + 1];
|
|
@@ -82,6 +82,7 @@ if (hookIdx >= 0) {
|
|
|
82
82
|
|| cliArg === "opencode"
|
|
83
83
|
|| cliArg === "pi"
|
|
84
84
|
|| cliArg === "gemini"
|
|
85
|
+
|| cliArg === "hermes"
|
|
85
86
|
)
|
|
86
87
|
? cliArg
|
|
87
88
|
: "claude";
|
|
@@ -129,9 +130,9 @@ COMMANDS
|
|
|
129
130
|
policies, p List all available policies and their status
|
|
130
131
|
policies --install, -i Enable policies in agent CLI settings
|
|
131
132
|
[names...] Specific policy names to enable
|
|
132
|
-
--cli claude|codex|copilot|cursor|opencode|pi|gemini
|
|
133
|
+
--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes
|
|
133
134
|
Agent CLI(s) to install for; space-separated
|
|
134
|
-
(e.g. --cli claude codex copilot cursor opencode pi gemini) or repeated.
|
|
135
|
+
(e.g. --cli claude codex copilot cursor opencode pi gemini hermes) or repeated.
|
|
135
136
|
Default: detect installed CLIs and prompt.
|
|
136
137
|
--scope user|project|local Config scope to write to (default: user)
|
|
137
138
|
(Codex / Copilot / Cursor / OpenCode / Pi / Gemini support user|project only)
|
|
@@ -140,7 +141,7 @@ COMMANDS
|
|
|
140
141
|
|
|
141
142
|
policies --uninstall, -u Disable policies or remove hooks
|
|
142
143
|
[names...] Specific policy names to disable
|
|
143
|
-
--cli claude|codex|copilot|cursor|opencode|pi|gemini
|
|
144
|
+
--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes
|
|
144
145
|
Agent CLI(s) to uninstall from
|
|
145
146
|
--scope user|project|local|all Config scope to remove from (default: user)
|
|
146
147
|
--beta Remove only beta policies
|
|
@@ -176,7 +177,7 @@ EXAMPLES
|
|
|
176
177
|
failproofai policies --install --cli opencode --scope project
|
|
177
178
|
failproofai policies --install --cli pi --scope project
|
|
178
179
|
failproofai policies --install --cli gemini --scope project
|
|
179
|
-
failproofai policies --install --cli claude codex copilot cursor opencode pi gemini
|
|
180
|
+
failproofai policies --install --cli claude codex copilot cursor opencode pi gemini hermes
|
|
180
181
|
failproofai policies --install --custom ./my-policies.js
|
|
181
182
|
failproofai policies -i -c ./my-policies.js
|
|
182
183
|
failproofai policies --uninstall block-sudo
|
|
@@ -225,9 +226,9 @@ USAGE
|
|
|
225
226
|
|
|
226
227
|
OPTIONS (install)
|
|
227
228
|
[names...] Specific policy names to enable (omit for interactive)
|
|
228
|
-
--cli claude|codex|copilot|cursor|opencode|pi|gemini
|
|
229
|
+
--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes
|
|
229
230
|
Agent CLI(s) to install for; space-separated
|
|
230
|
-
(e.g. --cli claude codex copilot cursor opencode pi gemini) or repeated.
|
|
231
|
+
(e.g. --cli claude codex copilot cursor opencode pi gemini hermes) or repeated.
|
|
231
232
|
Omit to detect installed CLIs and prompt (or
|
|
232
233
|
auto-pick if only one is found).
|
|
233
234
|
--scope user|project|local Config scope to write to (default: user)
|
|
@@ -238,7 +239,7 @@ OPTIONS (install)
|
|
|
238
239
|
|
|
239
240
|
OPTIONS (uninstall)
|
|
240
241
|
[names...] Specific policy names to disable (omit to remove hooks)
|
|
241
|
-
--cli claude|codex|copilot|cursor|opencode|pi|gemini
|
|
242
|
+
--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes
|
|
242
243
|
Agent CLI(s) to uninstall from
|
|
243
244
|
--scope user|project|local|all Config scope to remove from (default: user)
|
|
244
245
|
--beta Remove only beta policies
|
|
@@ -254,7 +255,7 @@ EXAMPLES
|
|
|
254
255
|
failproofai policies --install --cli opencode --scope project
|
|
255
256
|
failproofai policies --install --cli pi --scope project
|
|
256
257
|
failproofai policies --install --cli gemini --scope project
|
|
257
|
-
failproofai policies --install --cli claude codex copilot cursor opencode pi gemini
|
|
258
|
+
failproofai policies --install --cli claude codex copilot cursor opencode pi gemini hermes
|
|
258
259
|
failproofai policies --install --custom ./my-policies.js
|
|
259
260
|
failproofai policies -i -c ./my-policies.js
|
|
260
261
|
failproofai policies --uninstall block-sudo
|
|
@@ -295,7 +296,7 @@ EXAMPLES
|
|
|
295
296
|
// --cli claude codex copilot
|
|
296
297
|
// --cli claude --cli codex
|
|
297
298
|
// Values are consumed greedily until the next flag or end of argv.
|
|
298
|
-
const VALID_CLIS = new Set(["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini"]);
|
|
299
|
+
const VALID_CLIS = new Set(["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini", "hermes"]);
|
|
299
300
|
const cliFlagValues = [];
|
|
300
301
|
const cliConsumedIdxs = new Set();
|
|
301
302
|
const cliFlagIdxs = subArgs.map((a, i) => (a === "--cli" ? i : -1)).filter((i) => i >= 0);
|
|
@@ -312,7 +313,7 @@ EXAMPLES
|
|
|
312
313
|
consumed++;
|
|
313
314
|
}
|
|
314
315
|
if (consumed === 0) {
|
|
315
|
-
throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex copilot cursor opencode pi gemini (or any subset)");
|
|
316
|
+
throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex copilot cursor opencode pi gemini hermes (or any subset)");
|
|
316
317
|
}
|
|
317
318
|
}
|
|
318
319
|
|
|
@@ -384,7 +385,7 @@ EXAMPLES
|
|
|
384
385
|
}
|
|
385
386
|
|
|
386
387
|
// --cli accepts one or more space-separated values; same parser as install.
|
|
387
|
-
const VALID_CLIS = new Set(["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini"]);
|
|
388
|
+
const VALID_CLIS = new Set(["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini", "hermes"]);
|
|
388
389
|
const cliFlagValues = [];
|
|
389
390
|
const cliConsumedIdxs = new Set();
|
|
390
391
|
const cliFlagIdxs = subArgs.map((a, i) => (a === "--cli" ? i : -1)).filter((i) => i >= 0);
|
|
@@ -401,7 +402,7 @@ EXAMPLES
|
|
|
401
402
|
consumed++;
|
|
402
403
|
}
|
|
403
404
|
if (consumed === 0) {
|
|
404
|
-
throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex copilot cursor opencode pi gemini (or any subset)");
|
|
405
|
+
throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex copilot cursor opencode pi gemini hermes (or any subset)");
|
|
405
406
|
}
|
|
406
407
|
}
|
|
407
408
|
|
|
@@ -510,7 +511,7 @@ USAGE
|
|
|
510
511
|
failproofai policy remove <name> Disable one policy
|
|
511
512
|
|
|
512
513
|
OPTIONS
|
|
513
|
-
--cli claude|codex|copilot|cursor|opencode|pi|gemini
|
|
514
|
+
--cli claude|codex|copilot|cursor|opencode|pi|gemini|hermes
|
|
514
515
|
Agent CLI(s) to apply to; space-separated or repeated.
|
|
515
516
|
Omit to detect installed CLIs and prompt.
|
|
516
517
|
--scope user|project|local Config scope (default: user)
|
|
@@ -548,7 +549,7 @@ EXAMPLES
|
|
|
548
549
|
}
|
|
549
550
|
|
|
550
551
|
// --cli accepts one or more space-separated values, optionally repeated.
|
|
551
|
-
const VALID_CLIS = new Set(["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini"]);
|
|
552
|
+
const VALID_CLIS = new Set(["claude", "codex", "copilot", "cursor", "opencode", "pi", "gemini", "hermes"]);
|
|
552
553
|
const cliFlagValues = [];
|
|
553
554
|
const cliConsumedIdxs = new Set();
|
|
554
555
|
const cliFlagIdxs = rest.map((a, i) => (a === "--cli" ? i : -1)).filter((i) => i >= 0);
|
|
@@ -563,7 +564,7 @@ EXAMPLES
|
|
|
563
564
|
consumed++;
|
|
564
565
|
}
|
|
565
566
|
if (consumed === 0) {
|
|
566
|
-
throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex copilot cursor opencode pi gemini (or any subset)");
|
|
567
|
+
throw new CliError("Missing value(s) for --cli. Usage: --cli claude codex copilot cursor opencode pi gemini hermes (or any subset)");
|
|
567
568
|
}
|
|
568
569
|
}
|
|
569
570
|
|