failproofai 1.0.2-beta.6 → 1.0.2-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +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.nft.json +1 -1
- 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.nft.json +1 -1
- 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.nft.json +1 -1
- 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 +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.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/[root-of-the-server]__0o07qi9._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +1 -1
- 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]__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]__07gm3zl._.js +12 -15
- 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]__0mgrjnx._.js +10 -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]__128se8m._.js → [root-of-the-server]__1jjjg6g._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1tag8_-._.js → [root-of-the-server]__1opxw-7._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_11fc-hb._.js → _0_nsohj._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0no96tu._.js → _1uvml5y._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.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/app_settings_settings-client_tsx_20lq-mq._.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 +19 -19
- package/.next/standalone/.next/static/chunks/{276n-edifojbd.js → 0icodhlwr9x_e.js} +2 -2
- package/.next/standalone/.next/static/chunks/{0p84npzxdgpc5.js → 0tvmd0p_1i_g6.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3vu_7_eor1m-k.js → 1d6c85605lsgp.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2jfskwd2u8o5r.js → 1d7o3wnt3h6se.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0z7au3njlak0j.js → 1vzyn9h2kvj-i.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0sdgnflvw8kta.js → 2-9lvhuto1iwo.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0h-3zffoy-_ji.js → 3jt6n16p2qpex.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0931avh-06lj5.js → 3swqstog1cd9u.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1id7o44jjegf0.js → 3vqddiy9tvlwf.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2pxr7nr1nyotn.js → 44oamw33aso19.js} +1 -1
- package/.next/standalone/package.json +9 -9
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +796 -679
- package/dist/cli.mjs +3747 -3845
- package/dist/worker.mjs +1 -1
- package/package.json +9 -9
- package/src/audit/cli.ts +40 -39
- package/src/hooks/backfill-cli.ts +1 -1
- package/src/hooks/configure-wizard.ts +24 -10
- package/src/hooks/manager.ts +41 -6
- package/src/hooks/tui.ts +173 -39
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15r6r7w._.js +0 -10
- /package/.next/standalone/.next/static/{mAYN9BOxWVFREnVp3yCHp → PKwyBPAHjy3DB8qqapaH4}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{mAYN9BOxWVFREnVp3yCHp → PKwyBPAHjy3DB8qqapaH4}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{mAYN9BOxWVFREnVp3yCHp → PKwyBPAHjy3DB8qqapaH4}/_ssgManifest.js +0 -0
package/dist/worker.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "failproofai",
|
|
3
|
-
"version": "1.0.2-beta.
|
|
3
|
+
"version": "1.0.2-beta.7",
|
|
4
4
|
"description": "Observability and enforcement for AI agent harnesses. 39 built-in policies hooked into 12 of them — Claude Code, Codex, Cursor, Hermes, OpenClaw and more — blocking the tool call before it runs. Local dashboard included, no account needed.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"failproofai": "./dist/cli.mjs",
|
|
@@ -120,15 +120,15 @@
|
|
|
120
120
|
"sharp": "0.35.0"
|
|
121
121
|
},
|
|
122
122
|
"optionalDependencies": {
|
|
123
|
-
"@failproofai/failproofaid-linux-x64": "1.0.2-beta.
|
|
124
|
-
"@failproofai/failproofaid-linux-arm64": "1.0.2-beta.
|
|
125
|
-
"@failproofai/failproofaid-darwin-x64": "1.0.2-beta.
|
|
126
|
-
"@failproofai/failproofaid-darwin-arm64": "1.0.2-beta.
|
|
123
|
+
"@failproofai/failproofaid-linux-x64": "1.0.2-beta.7",
|
|
124
|
+
"@failproofai/failproofaid-linux-arm64": "1.0.2-beta.7",
|
|
125
|
+
"@failproofai/failproofaid-darwin-x64": "1.0.2-beta.7",
|
|
126
|
+
"@failproofai/failproofaid-darwin-arm64": "1.0.2-beta.7"
|
|
127
127
|
},
|
|
128
128
|
"failproofaidBinaries": {
|
|
129
|
-
"linux-x64": "
|
|
130
|
-
"linux-arm64": "
|
|
131
|
-
"darwin-x64": "
|
|
132
|
-
"darwin-arm64": "
|
|
129
|
+
"linux-x64": "75a8e231e057986f2b357e1fcb596641afd82a4b58f9271bb4b342951a364c2d",
|
|
130
|
+
"linux-arm64": "47d2933d06e70faefa78fe06fdd4e06bc03e94a319d13a8837145d192cd84d8c",
|
|
131
|
+
"darwin-x64": "6eae79c75746efe6922ca84e7dd899d01a50e651879abc8f90de69cd51c403f3",
|
|
132
|
+
"darwin-arm64": "ddca616decc3d2415ce6a58ae5fe15786bd2cfa5a5319803f4207a01d40e4a0a"
|
|
133
133
|
}
|
|
134
134
|
}
|
package/src/audit/cli.ts
CHANGED
|
@@ -35,7 +35,8 @@ import { getInstanceId } from "../../lib/telemetry-id";
|
|
|
35
35
|
import { sanitizeErrorMessage } from "../../lib/telemetry-sanitize";
|
|
36
36
|
import { openWhenReady } from "./open-browser";
|
|
37
37
|
import { describeOutcome, reportHarm } from "./report-harm";
|
|
38
|
-
import { brandAnsi, ANSI_RESET, ANSI_BOLD, ANSI_DIM } from "../hooks/tui";
|
|
38
|
+
import { brandAnsi, ANSI_RESET, ANSI_BOLD, ANSI_DIM, helpScreen, helpOptsFor } from "../hooks/tui";
|
|
39
|
+
import { version } from "../../package.json";
|
|
39
40
|
|
|
40
41
|
/** Port the bundled dashboard binds to. Matches `scripts/launch.ts`'s default
|
|
41
42
|
* for `start` mode, which `failproofai` (bare) already uses. */
|
|
@@ -64,9 +65,6 @@ export const AUDIT_STAGES: ReadonlyArray<{ label: string; detail: string }> = [
|
|
|
64
65
|
{ label: "aggregating results", detail: "counting hits, ranking by frequency" },
|
|
65
66
|
];
|
|
66
67
|
|
|
67
|
-
/** Column the description text starts at. The widest command line is 37 wide. */
|
|
68
|
-
const HELP_DESC_COL = 40;
|
|
69
|
-
|
|
70
68
|
/**
|
|
71
69
|
* `audit --help`.
|
|
72
70
|
*
|
|
@@ -82,41 +80,44 @@ const HELP_DESC_COL = 40;
|
|
|
82
80
|
* one. It still works, and still refuses every argument it always refused.
|
|
83
81
|
*/
|
|
84
82
|
export function helpText(): string {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
83
|
+
// Drawn by the same renderer as `config --help` and `policies --help`, from
|
|
84
|
+
// the same kit `audit`'s output already uses for its palette. It used to
|
|
85
|
+
// build its own rows against a hand-set HELP_DESC_COL, which is how `audit`
|
|
86
|
+
// and `config` ended up with their descriptions in different columns.
|
|
87
|
+
//
|
|
88
|
+
// The `failproofai audit` prefix is dropped from the rows: the heading two
|
|
89
|
+
// lines above already carries it, and repeating it cost 17 of the 80 columns
|
|
90
|
+
// on every row — which is what forced the four-word-per-line descriptions.
|
|
91
|
+
const lines = helpScreen(
|
|
92
|
+
{
|
|
93
|
+
command: "audit",
|
|
94
|
+
version,
|
|
95
|
+
tagline: "review your agent CLIs for risky and wasteful patterns",
|
|
96
|
+
sections: [
|
|
97
|
+
{
|
|
98
|
+
label: "usage",
|
|
99
|
+
entries: [
|
|
100
|
+
["(bare)", `Scan your session history, then open http://localhost:${DASHBOARD_PORT}/audit`],
|
|
101
|
+
["--schedule [days]", "Scan on a timer and email the findings. Default 7 days, range 1-90. Signs you in the first time."],
|
|
102
|
+
// Its own row now, rather than a clause inside --schedule's. It
|
|
103
|
+
// does not stand alone, which is why it used to be a clause — but
|
|
104
|
+
// a clause wraps, and `--email <address>` landing with the flag at
|
|
105
|
+
// the end of one line and its placeholder at the start of the next
|
|
106
|
+
// is not a flag anybody can read or copy.
|
|
107
|
+
["--email <address>", "With --schedule, skips the sign-in prompt."],
|
|
108
|
+
["--no-schedule", "Stop the timer. Leaves you signed in."],
|
|
109
|
+
["--status", "Whether scheduling is on, where reports go, the daemon's state, and when the next scan is due."],
|
|
110
|
+
["-h, --help", "Show this help."],
|
|
111
|
+
],
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
footer: ["Everything runs on this machine; only a scheduled digest ever leaves it."],
|
|
115
|
+
},
|
|
116
|
+
helpOptsFor(process.stdout),
|
|
117
|
+
);
|
|
118
|
+
// The margins `printBlock` would add, spelled out because this one returns
|
|
119
|
+
// its text for a caller to write rather than writing it.
|
|
120
|
+
return ["", ...lines, ""].join("\n") + "\n";
|
|
120
121
|
}
|
|
121
122
|
|
|
122
123
|
// ── ANSI helpers ────────────────────────────────────────────────────────────
|
|
@@ -149,7 +149,7 @@ export function runBackfillCommand(opts: BackfillOptions = {}): BackfillResult {
|
|
|
149
149
|
exitCode: 1,
|
|
150
150
|
lines: [
|
|
151
151
|
"This machine is not connected, so there is nowhere to send history.",
|
|
152
|
-
"Connect first: `failproofai config --
|
|
152
|
+
"Connect first: `failproofai config --token <key>`.",
|
|
153
153
|
],
|
|
154
154
|
};
|
|
155
155
|
}
|
|
@@ -743,6 +743,16 @@ export async function runConfigureWizard(
|
|
|
743
743
|
// reaching this function, so setup never runs off the back of some other
|
|
744
744
|
// command on a headless box.
|
|
745
745
|
const unattended = !stdin.isTTY || !stdout.isTTY;
|
|
746
|
+
// A key on the command line settles the whole run, not just the question it
|
|
747
|
+
// literally answers.
|
|
748
|
+
//
|
|
749
|
+
// Somebody typing `failproofai config --token <key>` has said: set this
|
|
750
|
+
// machine up, connect it, send its data. There is nothing left to confirm —
|
|
751
|
+
// so asking "Connect to Cloud?", then the key, then "Ready to apply?" made
|
|
752
|
+
// the flag look like it had not been read. The only thing still worth
|
|
753
|
+
// stopping for is the sudo password, which is a CREDENTIAL rather than a
|
|
754
|
+
// question, and no flag can supply it.
|
|
755
|
+
const preAnswered = Boolean(answers.token);
|
|
746
756
|
|
|
747
757
|
|
|
748
758
|
// Running the wizard itself under sudo configures the WRONG ACCOUNT, and
|
|
@@ -1020,9 +1030,15 @@ export async function runConfigureWizard(
|
|
|
1020
1030
|
// one — so an unattended run with a token skips straight past the question,
|
|
1021
1031
|
// and one without a token stays local, which is the same "Not now" branch a
|
|
1022
1032
|
// person picks. Neither needs a separate flag to say so.
|
|
1023
|
-
const choice =
|
|
1024
|
-
|
|
1025
|
-
:
|
|
1033
|
+
const choice = answers.token
|
|
1034
|
+
// A key on the command line IS the answer to this question. Gating it on
|
|
1035
|
+
// there being no terminal was wrong: `--token` means "use this key", not
|
|
1036
|
+
// "use this key only if nobody is watching", and a run that asked anyway
|
|
1037
|
+
// made the flag look broken to the person who had just typed it.
|
|
1038
|
+
? "key"
|
|
1039
|
+
: unattended
|
|
1040
|
+
? "local"
|
|
1041
|
+
: await selectOne<"key" | "local">({
|
|
1026
1042
|
message: "Connect this machine to FailproofAI Cloud?",
|
|
1027
1043
|
// The hint says what you GET; the body says what LEAVES.
|
|
1028
1044
|
//
|
|
@@ -1186,12 +1202,10 @@ export async function runConfigureWizard(
|
|
|
1186
1202
|
}
|
|
1187
1203
|
}
|
|
1188
1204
|
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
token = answers.token ?? null;
|
|
1194
|
-
}
|
|
1205
|
+
// Supplied on the command line, so nothing is asked and nothing is
|
|
1206
|
+
// echoed — terminal or not. Prompting for a value the caller already gave
|
|
1207
|
+
// is the failure this whole flag exists to avoid.
|
|
1208
|
+
if (token === null) token = answers.token ?? null;
|
|
1195
1209
|
if (token === null) {
|
|
1196
1210
|
token = await promptText({
|
|
1197
1211
|
// The destination is in the question now that it is no longer a
|
|
@@ -1255,7 +1269,7 @@ export async function runConfigureWizard(
|
|
|
1255
1269
|
// NOT the same call as `uninstall`, which does require --yes: that one
|
|
1256
1270
|
// REMOVES things, so silence there would destroy on a signal as weak as a
|
|
1257
1271
|
// missing terminal. This one does exactly what its name says.
|
|
1258
|
-
const decision = unattended ? "apply" : await selectOne<"apply" | "cancel">({
|
|
1272
|
+
const decision = unattended || preAnswered ? "apply" : await selectOne<"apply" | "cancel">({
|
|
1259
1273
|
message: "Ready to apply?",
|
|
1260
1274
|
body: reviewLines({
|
|
1261
1275
|
target,
|
package/src/hooks/manager.ts
CHANGED
|
@@ -15,7 +15,6 @@ import { INTEGRATION_TYPES,
|
|
|
15
15
|
type IntegrationType,
|
|
16
16
|
} from "./types";
|
|
17
17
|
import { claudeCode, getIntegration, settingsPathsFor, type Integration } from "./integrations";
|
|
18
|
-
import { promptPolicySelection } from "./install-prompt";
|
|
19
18
|
import { configuredCustomPolicyPaths, readMergedHooksConfig, readScopedHooksConfig, writeScopedHooksConfig, syncConventionPolicies, findProjectConfigDir } from "./hooks-config";
|
|
20
19
|
import type { HooksConfig, ConventionPolicyRecord } from "./policy-types";
|
|
21
20
|
import { BUILTIN_POLICIES } from "./builtin-policies";
|
|
@@ -462,9 +461,25 @@ async function installHooksImpl(
|
|
|
462
461
|
? [...new Set(incoming)]
|
|
463
462
|
: [...new Set([...previousConfig.enabledPolicies, ...incoming])];
|
|
464
463
|
} else {
|
|
465
|
-
//
|
|
466
|
-
|
|
467
|
-
|
|
464
|
+
// NOT a policy picker. `--install` wires hooks; choosing what they enforce
|
|
465
|
+
// is `policies add` / `policies remove`.
|
|
466
|
+
//
|
|
467
|
+
// It used to open a second picker here, over `BUILTIN_POLICIES` — the
|
|
468
|
+
// COMPILED catalog, which is no longer how policies arrive. So it offered a
|
|
469
|
+
// list that did not match what was installed, in an older prompt engine
|
|
470
|
+
// that looks nothing like the rest, and wrote its answer to
|
|
471
|
+
// `enabledPolicies` while every pack records its selection in
|
|
472
|
+
// `installed.json`.
|
|
473
|
+
//
|
|
474
|
+
// Two independent enabled-sets, and this one silently overwrote the other:
|
|
475
|
+
// `policies remove block-env-files` followed by `policies --install` put
|
|
476
|
+
// block-env-files straight back on, because the picker pre-ticked from the
|
|
477
|
+
// legacy key and saved all of it again. A command whose job is wiring must
|
|
478
|
+
// not undo a policy decision made somewhere else.
|
|
479
|
+
//
|
|
480
|
+
// Whatever was enabled stays enabled. Explicit names still work
|
|
481
|
+
// (`--install block-sudo`) for the migration shim, which has only this key.
|
|
482
|
+
selectedPolicies = previousConfig.enabledPolicies;
|
|
468
483
|
}
|
|
469
484
|
|
|
470
485
|
// Preserve existing config fields when updating. New writes use the plural
|
|
@@ -556,7 +571,21 @@ async function installHooksImpl(
|
|
|
556
571
|
// pack does not carry it and asking for it by name is a selection the pack
|
|
557
572
|
// cannot satisfy. It ships compiled in and registers regardless.
|
|
558
573
|
const alwaysOnNames = new Set(BUILTIN_POLICIES.filter((p) => p.alwaysOn).map((p) => p.name));
|
|
559
|
-
|
|
574
|
+
// ONLY names the caller actually asked for.
|
|
575
|
+
//
|
|
576
|
+
// This used to take whatever sat in `enabledPolicies` and switch those names
|
|
577
|
+
// on in the pack. It is additive — it can turn a policy on and never off — so
|
|
578
|
+
// a stale entry in that key resurrected a policy the user had deliberately
|
|
579
|
+
// removed, on the next `policies --install`, with no mention of it.
|
|
580
|
+
// `remove block-env-files` then `--install` put it straight back.
|
|
581
|
+
//
|
|
582
|
+
// And the key goes stale by design now: nothing writes pack selections there,
|
|
583
|
+
// so anything left in it is a leftover from before packs, kept only for the
|
|
584
|
+
// migration shim. Re-applying a leftover as if it were a decision is how a
|
|
585
|
+
// machine ends up enforcing something its owner switched off.
|
|
586
|
+
const fromPack = policyNames === undefined
|
|
587
|
+
? []
|
|
588
|
+
: selectedPolicies.filter((name) => !alwaysOnNames.has(name));
|
|
560
589
|
if (fromPack.length > 0) {
|
|
561
590
|
// ONLY when there is no pack yet. Fetching the core pack with
|
|
562
591
|
// `only: <selection>` REPLACES whatever the machine had chosen, and
|
|
@@ -592,7 +621,13 @@ async function installHooksImpl(
|
|
|
592
621
|
}
|
|
593
622
|
}
|
|
594
623
|
}
|
|
595
|
-
|
|
624
|
+
// Only when this run actually changed something. `--install` with no names
|
|
625
|
+
// wires hooks and touches no policy, and announcing "Enabled 0 policy(ies):"
|
|
626
|
+
// with an empty list described work it had not done — or worse, re-stated a
|
|
627
|
+
// stale key as though it were this run's decision.
|
|
628
|
+
if (policyNames !== undefined && selectedPolicies.length > 0) {
|
|
629
|
+
console.log(`\nEnabled ${selectedPolicies.length} policy(ies): ${selectedPolicies.join(", ")}\n`);
|
|
630
|
+
}
|
|
596
631
|
if (removeCustomHooks) {
|
|
597
632
|
console.log("Custom hooks path cleared.");
|
|
598
633
|
} else if (configToWrite.customPoliciesPaths?.length || configToWrite.customPoliciesPath) {
|
package/src/hooks/tui.ts
CHANGED
|
@@ -1254,9 +1254,14 @@ export function rule(label?: string, opts?: RenderOpts): string[] {
|
|
|
1254
1254
|
const { cols, c } = ctx(opts);
|
|
1255
1255
|
const width = Math.max(4, cols - INDENT.length * 2);
|
|
1256
1256
|
if (!label) return [`${INDENT}${c.dim("─".repeat(width))}`];
|
|
1257
|
-
const
|
|
1258
|
-
|
|
1259
|
-
|
|
1257
|
+
const tail = Math.max(3, width - `━━ ${label} `.length);
|
|
1258
|
+
// The one accent every sectioned surface carries: a pink lead into a bold
|
|
1259
|
+
// label. Decoration only — the glyphs and the spacing are identical without
|
|
1260
|
+
// colour, so a piped render and a painted one are the same width and say the
|
|
1261
|
+
// same thing. Changing it here moves `policies`, `harness`, `pack list`,
|
|
1262
|
+
// every `table` section and all twelve help screens together, which is the
|
|
1263
|
+
// reason they share this function instead of each drawing their own line.
|
|
1264
|
+
return [`${INDENT}${c.pink("━━")} ${c.bold(label)} ${c.dim("━".repeat(tail))}`];
|
|
1260
1265
|
}
|
|
1261
1266
|
|
|
1262
1267
|
export interface Row {
|
|
@@ -1524,52 +1529,181 @@ export interface HelpSpec {
|
|
|
1524
1529
|
usage: Array<[string, string?]>;
|
|
1525
1530
|
options?: Array<[string, string]>;
|
|
1526
1531
|
examples?: string[];
|
|
1527
|
-
/** Free lines
|
|
1532
|
+
/** Free lines above the first section. */
|
|
1528
1533
|
lead?: string[];
|
|
1529
1534
|
}
|
|
1530
1535
|
|
|
1531
1536
|
/**
|
|
1532
|
-
*
|
|
1537
|
+
* The description column for one block of entries, derived from its widest
|
|
1538
|
+
* described name and capped.
|
|
1533
1539
|
*
|
|
1534
|
-
*
|
|
1535
|
-
*
|
|
1536
|
-
*
|
|
1537
|
-
* column is computed here from the widest entry, capped so a long flag cannot
|
|
1538
|
-
* push every description off the right edge.
|
|
1540
|
+
* Its own step because the callers differ on the SCOPE they compute it over —
|
|
1541
|
+
* {@link helpBlock} across usage and options together, {@link helpScreen} per
|
|
1542
|
+
* section — and neither should be restating the cap or the floor.
|
|
1539
1543
|
*/
|
|
1540
|
-
export function
|
|
1544
|
+
export function helpColumn(entries: Array<[string, string?]>): number {
|
|
1545
|
+
// Only DESCRIBED entries set the column. A bare usage line — `failproofai
|
|
1546
|
+
// flush [--wait] [--timeout <secs>]`, which describes itself — is 44
|
|
1547
|
+
// characters and has nothing in the second column, so letting it vote pushed
|
|
1548
|
+
// every real description on the screen out to column 38.
|
|
1549
|
+
const named = entries.filter(([, d]) => d).map(([n]) => visibleWidth(n));
|
|
1550
|
+
return Math.min(34, Math.max(12, ...named));
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
/** `<name> <description>` at a column the caller fixed. */
|
|
1554
|
+
export function helpEntries(
|
|
1555
|
+
items: Array<[string, string?]>,
|
|
1556
|
+
nameWidth: number,
|
|
1557
|
+
opts?: RenderOpts,
|
|
1558
|
+
): string[] {
|
|
1541
1559
|
const { cols, c } = ctx(opts);
|
|
1542
|
-
const
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
}
|
|
1562
|
-
continue;
|
|
1560
|
+
const out: string[] = [];
|
|
1561
|
+
for (const [raw, description] of items) {
|
|
1562
|
+
// Pink is what you TYPE, dim is what it means, bold is the section it sits
|
|
1563
|
+
// in. Three tones, the same three on every screen, so a flag looks like a
|
|
1564
|
+
// flag whether you found it on `publish --help` or on the index. Decoration
|
|
1565
|
+
// only: the column already separates the two halves, so the screen reads
|
|
1566
|
+
// the same piped to a file or under NO_COLOR.
|
|
1567
|
+
const name = c.pink(raw);
|
|
1568
|
+
if (!description) {
|
|
1569
|
+
out.push(`${INDENT}${name}`);
|
|
1570
|
+
continue;
|
|
1571
|
+
}
|
|
1572
|
+
const budget = Math.max(12, cols - INDENT.length * 2 - nameWidth - 2);
|
|
1573
|
+
const [first, ...rest] = wrap(description, budget);
|
|
1574
|
+
// A name wider than the column takes its own line rather than shoving the
|
|
1575
|
+
// description out — the top-level help has several of these today.
|
|
1576
|
+
if (visibleWidth(raw) > nameWidth) {
|
|
1577
|
+
out.push(`${INDENT}${name}`);
|
|
1578
|
+
for (const line of [first, ...rest]) {
|
|
1579
|
+
if (line !== undefined) out.push(`${INDENT}${" ".repeat(nameWidth)} ${c.dim(line)}`);
|
|
1563
1580
|
}
|
|
1564
|
-
|
|
1565
|
-
for (const line of rest) out.push(`${INDENT}${" ".repeat(nameWidth)} ${c.dim(line)}`);
|
|
1581
|
+
continue;
|
|
1566
1582
|
}
|
|
1567
|
-
|
|
1568
|
-
|
|
1583
|
+
// Padded on the VISIBLE width, so a painted name still lands the column
|
|
1584
|
+
// where an unpainted one does.
|
|
1585
|
+
const gap = nameWidth - visibleWidth(raw);
|
|
1586
|
+
out.push(`${INDENT}${name}${" ".repeat(gap)} ${c.dim(first ?? "")}`);
|
|
1587
|
+
for (const line of rest) out.push(`${INDENT}${" ".repeat(nameWidth)} ${c.dim(line)}`);
|
|
1588
|
+
}
|
|
1589
|
+
return out;
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
/**
|
|
1593
|
+
* A usage/options/examples block, on one column across all three.
|
|
1594
|
+
*
|
|
1595
|
+
* The plain shape, for a surface with nothing else to say. A screen with prose
|
|
1596
|
+
* sections, a heading, or a footer wants {@link helpScreen}, which is what the
|
|
1597
|
+
* twelve `--help` screens use.
|
|
1598
|
+
*/
|
|
1599
|
+
export function helpBlock(spec: HelpSpec, opts?: RenderOpts): string[] {
|
|
1600
|
+
const nameWidth = helpColumn([...spec.usage, ...(spec.options ?? [])]);
|
|
1601
|
+
const section = (label: string, body: string[]): string[] =>
|
|
1602
|
+
body.length === 0 ? [] : [...rule(label, opts), ...body];
|
|
1569
1603
|
return stack(
|
|
1570
1604
|
spec.lead ? spec.lead.map((l) => `${INDENT}${l}`) : null,
|
|
1571
|
-
section("
|
|
1572
|
-
section("
|
|
1573
|
-
section("
|
|
1605
|
+
section("usage", helpEntries(spec.usage, nameWidth, opts)),
|
|
1606
|
+
section("options", helpEntries(spec.options ?? [], nameWidth, opts)),
|
|
1607
|
+
section("examples", (spec.examples ?? []).map((e) => `${INDENT}${e}`)),
|
|
1574
1608
|
);
|
|
1575
1609
|
}
|
|
1610
|
+
|
|
1611
|
+
/**
|
|
1612
|
+
* Help is the one family of screens read at every width that belongs to no
|
|
1613
|
+
* terminal in particular. Capped at 80 so `publish --help` is the same shape in
|
|
1614
|
+
* a maximised window as in a tmux pane — and never wider than the terminal it
|
|
1615
|
+
* is actually in, so the cap can only ever narrow.
|
|
1616
|
+
*/
|
|
1617
|
+
export const HELP_COLS = 80;
|
|
1618
|
+
|
|
1619
|
+
/** {@link optsFor}, capped to {@link HELP_COLS}. Every help screen uses this. */
|
|
1620
|
+
export function helpOptsFor(stdout: TTYOut = process.stdout): Required<RenderOpts> {
|
|
1621
|
+
const base = optsFor(stdout);
|
|
1622
|
+
return { cols: Math.min(base.cols, HELP_COLS), color: base.color };
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
export interface HelpHeading {
|
|
1626
|
+
/** The command being documented. Omitted for the top-level index. */
|
|
1627
|
+
command?: string;
|
|
1628
|
+
version: string;
|
|
1629
|
+
/** One line: what this command is for. */
|
|
1630
|
+
tagline: string;
|
|
1631
|
+
}
|
|
1632
|
+
|
|
1633
|
+
/**
|
|
1634
|
+
* The two lines every help screen opens with.
|
|
1635
|
+
*
|
|
1636
|
+
* The wordmark carries the same pink on `il` that {@link renderBrandLogo} tints,
|
|
1637
|
+
* so a help screen and the wizard are visibly one product rather than two that
|
|
1638
|
+
* happen to ship together. The version sits right-aligned and dim because it is
|
|
1639
|
+
* the fact you want when a help screen and its binary disagree, and the fact you
|
|
1640
|
+
* never want in the way otherwise.
|
|
1641
|
+
*/
|
|
1642
|
+
export function helpHeading(spec: HelpHeading, opts?: RenderOpts): string[] {
|
|
1643
|
+
const { cols, c } = ctx(opts);
|
|
1644
|
+
const mark = `${c.bold("fa")}${c.pink("il")}${c.bold("proofai")}`;
|
|
1645
|
+
const left = `${INDENT}${mark}${spec.command ? ` ${c.bold(spec.command)}` : ""}`;
|
|
1646
|
+
const right = c.dim(`v${spec.version}`);
|
|
1647
|
+
const gap = cols - visibleWidth(left) - visibleWidth(right) - INDENT.length;
|
|
1648
|
+
// Too narrow for both: the version goes under rather than wrapping into the
|
|
1649
|
+
// middle of the name, where it reads as part of the command.
|
|
1650
|
+
const head = gap < 2 ? [left, `${INDENT}${right}`] : [left + " ".repeat(gap) + right];
|
|
1651
|
+
return [...head, ...note(spec.tagline, opts)];
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
/**
|
|
1655
|
+
* A section of a help screen: a table of names, a paragraph, or lines that are
|
|
1656
|
+
* already laid out. Every one of them gets the same `rule` heading, which is
|
|
1657
|
+
* what makes twelve screens one screen.
|
|
1658
|
+
*/
|
|
1659
|
+
export type HelpSection =
|
|
1660
|
+
/** A table of names. `after` is a paragraph under it, in the same section —
|
|
1661
|
+
* the alternative was a second heading over three lines of caveat, or an
|
|
1662
|
+
* unlabelled `rule` that read as the screen having lost its place. */
|
|
1663
|
+
| { label: string; entries: Array<[string, string?]>; after?: string[] }
|
|
1664
|
+
| { label: string; prose: string }
|
|
1665
|
+
| { label: string; lines: string[] };
|
|
1666
|
+
|
|
1667
|
+
export interface HelpScreenSpec extends HelpHeading {
|
|
1668
|
+
sections: HelpSection[];
|
|
1669
|
+
/** Dim closing lines — where to read more. */
|
|
1670
|
+
footer?: string[];
|
|
1671
|
+
}
|
|
1672
|
+
|
|
1673
|
+
/**
|
|
1674
|
+
* A whole `--help`, assembled the same way twelve times.
|
|
1675
|
+
*
|
|
1676
|
+
* Before this, every screen was its own template literal: `USAGE` here and
|
|
1677
|
+
* `Usage:` there, a description column hand-counted per file, no version on the
|
|
1678
|
+
* page, and no colour on any of them while the index it was reached from had
|
|
1679
|
+
* all three. The screens still say exactly what their authors wrote — this owns
|
|
1680
|
+
* only the shape.
|
|
1681
|
+
*/
|
|
1682
|
+
export function helpScreen(spec: HelpScreenSpec, opts?: RenderOpts): string[] {
|
|
1683
|
+
const { cols, c } = ctx(opts);
|
|
1684
|
+
const width = Math.max(12, cols - INDENT.length * 2);
|
|
1685
|
+
const groups: Array<string[] | null> = [helpHeading(spec, opts)];
|
|
1686
|
+
for (const section of spec.sections) {
|
|
1687
|
+
// Per SECTION, not per screen. One column across the whole page is what a
|
|
1688
|
+
// screen of like-shaped entries wants, and it is exactly wrong on a screen
|
|
1689
|
+
// that has both: `failproofai policies show <owner>/<repo>` is 40 columns
|
|
1690
|
+
// and `--all` is 5, so a shared column left every flag description hanging
|
|
1691
|
+
// 34 columns out with nothing under it. What made two screens read as two
|
|
1692
|
+
// products was the INDENT and the heading, and those are shared here.
|
|
1693
|
+
const body =
|
|
1694
|
+
"entries" in section
|
|
1695
|
+
? [
|
|
1696
|
+
...helpEntries(section.entries, helpColumn(section.entries), opts),
|
|
1697
|
+
...(section.after?.length
|
|
1698
|
+
? ["", ...section.after.map((l) => (l.trim() === "" ? "" : `${INDENT}${l}`))]
|
|
1699
|
+
: []),
|
|
1700
|
+
]
|
|
1701
|
+
: "prose" in section
|
|
1702
|
+
? wrap(section.prose, width).map((l) => `${INDENT}${l}`)
|
|
1703
|
+
: section.lines.map((l) => (l.trim() === "" ? "" : `${INDENT}${l}`));
|
|
1704
|
+
if (body.length === 0) continue;
|
|
1705
|
+
groups.push([...rule(section.label, opts), ...body]);
|
|
1706
|
+
}
|
|
1707
|
+
if (spec.footer?.length) groups.push(spec.footer.map((l) => `${INDENT}${c.dim(l)}`));
|
|
1708
|
+
return stack(...groups);
|
|
1709
|
+
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
module.exports=[57764,(a,b,c)=>{b.exports=a.x("node:url",()=>require("node:url"))},92509,(a,b,c)=>{b.exports=a.x("url",()=>require("url"))},15638,a=>{"use strict";var b=a.i(50227),c=a.i(54799),d=a.i(2157),e=a.i(12714),f=a.i(57764),g=a.i(66680),h=a.i(10695),i=a.i(32352),j=a.i(84948);a.i(28120);var k=a.i(98378),l=a.i(69839);a.i(75818);let m="__FAILPROOFAI_LOADING_HOOKS__",n=/policies\.(js|mjs|ts)$/,o=0,p=new Map;async function q(a){let b,c,d=Number.isFinite(c=Number(process.env.FAILPROOFAI_POLICY_LOAD_TIMEOUT_MS))&&c>0?c:1e4;try{await Promise.race([import(a),new Promise((a,c)=>{b=setTimeout(()=>c(Error(`timed out loading module after ${d}ms`)),d),b.unref?.()})])}finally{b&&clearTimeout(b)}}async function r(a,d){let e=globalThis;e[m]=!0;let g=[];try{let b=await (0,j.findDistIndex)(),e=b?(0,f.pathToFileURL)(b).href:null,h=++o,k=`${j.TMP_SUFFIX}.${process.pid}.${h}.${(0,c.randomUUID)()}.mjs`;g=await (0,j.rewriteFileTree)(a,e,b,k,d?.verifyEntrySha);let l=await s(g,k),m=p.get(a);if(m?.fingerprint===l){for(let a of m.hooks)i.customPolicies.add({...a});return null}let n=a+k,r=(0,f.pathToFileURL)(n).href,t=(0,i.getCustomHooks)().length;return await q(r),p.size>=500&&p.clear(),p.set(a,{fingerprint:l,hooks:(0,i.getCustomHooks)().slice(t).map(a=>({...a}))}),null}catch(f){let c=f instanceof Error?f.message:String(f),e=/Cannot find module|MODULE_NOT_FOUND|ENOENT/i.test(c)?"module_not_found":/SyntaxError|Unexpected token/i.test(c)?"syntax_error":/timed out loading module/i.test(c)?"load_timeout":"runtime_error";if((0,k.trackHookEvent)((0,l.getInstanceId)(),"custom_hooks_load_error",{error_type:e,is_convention:!!d?.conventionScope,convention_scope:d?.conventionScope??null,file_basename:(0,b.basename)(a)}),d?.strict)throw Error(`Failed to load custom hooks from ${a}: ${c}`);return(0,h.hookLogError)(`failed to load custom hooks from ${a}: ${c}`),{type:e,reason:c}}finally{e[m]=!1,await (0,j.cleanupTmpFiles)(g)}}async function s(a,b){let c=(0,g.createHash)("sha256");for(let d of[...a].sort()){c.update(d.replaceAll(b,j.TMP_SUFFIX));let a=await (0,e.readFile)(d,"utf8");c.update(a.replaceAll(b,j.TMP_SUFFIX))}return c.digest("hex")}async function t(a,c){if(!a)return[];let e=(0,b.isAbsolute)(a)?a:(0,b.resolve)(c?.sessionCwd??process.cwd(),a);if(!(0,d.existsSync)(e)){if(c?.strict)throw Error(`Custom hooks file not found: ${e}`);return(0,h.hookLogWarn)(`customPoliciesPath not found: ${e}`),[]}return(0,i.clearCustomHooks)(),await r(e,c),(0,i.getCustomHooks)()}a.s(["conventionPolicyId",0,function(a,b,c){return`convention:${a}:${b}:${c}`},"customPolicyId",0,function(a,b){return`custom:${a}:${b}`},"discoverPolicyFiles",0,function(a){if(!(0,d.existsSync)(a))return[];try{return(0,d.readdirSync)(a,{withFileTypes:!0}).filter(a=>a.isFile()&&n.test(a.name)).sort((a,b)=>a.name.localeCompare(b.name)).map(c=>(0,b.resolve)(a,c.name))}catch{return[]}},"loadCustomHooks",0,t])},32352,84948,a=>{"use strict";let b="__failproofai_custom_hooks__";function c(){let a=globalThis;return Array.isArray(a[b])||(a[b]=[]),a[b]}a.s(["clearCustomHooks",0,function(){globalThis[b]=[]},"customPolicies",0,{add(a){c().push(a)}},"getCustomHooks",0,function(){return c()}],32352);var d=a.i(24868),e=a.i(46786),f=a.i(14747),g=a.i(92509),h=a.i(54799),i=a.i(75818),j=a.i(10695);let k=".__failproofai_tmp__.mjs",l=/(?:import\s+(?:[\s\S]*?\s+from\s+)?|export\s+(?:[\s\S]*?\s+from\s+))(['"])(\.\.?\/[^'"]+)\1/g,m=/require\s*\(\s*(['"])(\.\.?\/[^'"]+)\1\s*\)/g;async function n(a){try{return await (0,d.access)(a),!0}catch{return!1}}async function o(){let a=process.env.FAILPROOFAI_DIST_PATH;if(a){let b=(0,f.resolve)(a,"index.js");if(await n(b))return b}for(let a of[(0,f.resolve)((0,f.dirname)(process.execPath),"..","assets","dist","index.js"),(0,f.resolve)(process.cwd(),"dist","index.js"),(0,f.resolve)(process.cwd(),"node_modules","failproofai","dist","index.js")])if(await n(a))return a;return null}async function p(a,b){let c=(0,f.resolve)(a,b);for(let a of[c,`${c}.js`,`${c}.mjs`,`${c}.ts`,(0,f.resolve)(c,"index.js")])if(await n(a))return a;return null}async function q(a,b,c,e){let g=(0,f.join)(a,b);return await (0,d.writeFile)(g,c,{encoding:"utf-8",mode:384,...e?{flag:"wx"}:{}}),g}async function r(a,b,c=k){let f=`import _cjs from '${b}';
|
|
2
|
-
export const customPolicies = _cjs.customPolicies;
|
|
3
|
-
export const getCustomHooks = _cjs.getCustomHooks;
|
|
4
|
-
export const clearCustomHooks = _cjs.clearCustomHooks;
|
|
5
|
-
export const allow = _cjs.allow;
|
|
6
|
-
export const deny = _cjs.deny;
|
|
7
|
-
export const instruct = _cjs.instruct;
|
|
8
|
-
export default _cjs;`,h=`failproofai-dist${c}.shim.mjs`;try{let a=(0,i.shimsDir)();await (0,d.mkdir)(a,{recursive:!0,mode:448});let b=await (0,d.lstat)(a),c="function"==typeof process.getuid?process.getuid():null;if(!b.isDirectory()||b.isSymbolicLink()||null!==c&&b.uid!==c||63&b.mode)throw Error(`${a} is not a private directory owned by this user`);let e=await q(a,h,f,!1);return{shimPath:e,shimUrl:(0,g.pathToFileURL)(e).href}}catch(a){(0,j.hookLogWarn)(`policy shim directory unusable (${a instanceof Error?a.message:String(a)}); falling back to ${(0,e.tmpdir)()}`)}let l=await q((0,e.tmpdir)(),h,f,!0);return{shimPath:l,shimUrl:(0,g.pathToFileURL)(l).href}}async function s(a,b,c,e=k,g){let i=[a],j=new Set,n=[],o=null;if(c&&b){let a=await r(c,b,e);n.push(a.shimPath),o=a.shimUrl}for(;i.length>0;){let b,k=i.shift();if(j.has(k))continue;if(j.add(k),g&&k===a){let a=await (0,d.readFile)(k),c=(0,h.createHash)("sha256").update(a).digest("hex");if(c!==g)throw Error(`cloud-managed policy failed integrity re-verification at load: expected ${g}, got ${c}`);b=a.toString("utf-8")}else b=await (0,d.readFile)(k,"utf-8");o&&(b=b.replace(/from\s+(['"])(?:claudeye|failproofai)\1/g,`from '${o}'`)),c&&(b=b.replace(/require\s*\(\s*(['"])(?:claudeye|failproofai)\1\s*\)/g,`require('${c.replace(/\\/g,"\\\\")}')`));let q=(0,f.dirname)(k),r=new Map;for(let a of[l,m]){let c,d=new RegExp(a.source,a.flags);for(;null!==(c=d.exec(b));){let a=c[2];if(r.has(a))continue;let b=await p(q,a);if(!b)continue;j.has(b)||i.includes(b)||i.push(b);let d=(0,f.relative)(q,b+e).split("\\").join("/");d.startsWith(".")||(d="./"+d),r.set(a,d)}}for(let a of[...r.keys()].sort((a,b)=>b.length-a.length)){let c=r.get(a),d=a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");b=(b=b.replace(RegExp(`'${d}'`,"g"),`'${c}'`)).replace(RegExp(`"${d}"`,"g"),`"${c}"`)}let s=k+e;await (0,d.writeFile)(s,b,"utf-8"),n.push(s)}return n}async function t(a){for(let b of a)try{await (0,d.unlink)(b)}catch{}}a.s(["TMP_SUFFIX",0,k,"cleanupTmpFiles",0,t,"findDistIndex",0,o,"rewriteFileTree",0,s],84948)},28120,98378,a=>{"use strict";var b=a.i(2157),c=a.i(50227),d=a.i(60526),e=a.i(10695),f=a.i(75818);function g(a){if(!(0,b.existsSync)(a))return{};try{let c=(0,b.readFileSync)(a,"utf8");return JSON.parse(c)}catch(b){return(0,e.hookLogWarn)(`failed to parse config at ${a}: ${b instanceof Error?b.message:String(b)}`),{}}}function h(a){let e=(0,d.homedir)(),f=(0,c.resolve)(a);for(;f!==e;){let a=(0,c.resolve)(f,".failproofai");try{if((0,b.statSync)(a).isDirectory())return f}catch{}let d=(0,c.dirname)(f);if(d===f)break;f=d}return(0,c.resolve)(a)}function i(){return(0,f.globalPolicyConfigFile)()}function j(a,b){switch(a){case"user":return(0,f.globalPolicyConfigFile)();case"project":return(0,c.resolve)(h(b??process.cwd()),".failproofai","policies-config.json");case"local":return(0,c.resolve)(h(b??process.cwd()),".failproofai","policies-config.local.json")}}a.s(["configuredCustomPolicyPaths",0,function(a){return a.customPoliciesPaths??(a.customPoliciesPath?[a.customPoliciesPath]:[])},"findProjectConfigDir",0,h,"readHooksConfig",0,function(){let a=i();if(!(0,b.existsSync)(a))return{enabledPolicies:[]};try{let c=(0,b.readFileSync)(a,"utf8");return JSON.parse(c)}catch(b){return(0,e.hookLogWarn)(`failed to parse config at ${a}: ${b instanceof Error?b.message:String(b)}`),{enabledPolicies:[]}}},"readMergedHooksConfig",0,function(a){let b=h(a??process.cwd()),d=(0,c.resolve)(b,".failproofai","policies-config.json"),e=(0,c.resolve)(b,".failproofai","policies-config.local.json"),i=(0,f.globalPolicyConfigFile)(),j=g(d),k=g(e),l=g(i),m=new Set([...j.enabledPolicies??[],...k.enabledPolicies??[],...l.enabledPolicies??[]]),n={};for(let a of[j,k,l])if(a.policyParams)for(let[b,c]of Object.entries(a.policyParams))b in n||(n[b]=c);let o=[j,k,l].map(a=>void 0!==a.customPoliciesPaths?a.customPoliciesPaths:void 0!==a.customPoliciesPath?[a.customPoliciesPath]:void 0).find(a=>void 0!==a),p=new Set([...j.disabledCustomPolicies??[],...k.disabledCustomPolicies??[],...l.disabledCustomPolicies??[]]),q=j.customPoliciesEnabled??k.customPoliciesEnabled??l.customPoliciesEnabled,r=j.llm??k.llm??l.llm;return{enabledPolicies:[...m],...Object.keys(n).length>0?{policyParams:n}:{},...void 0!==o?{customPoliciesPaths:o}:{},...p.size?{disabledCustomPolicies:[...p]}:{},...void 0!==q?{customPoliciesEnabled:q}:{},...void 0!==r?{llm:r}:{}}},"readScopedHooksConfig",0,function(a,c){let d=j(a,c);if(!(0,b.existsSync)(d))return{enabledPolicies:[]};try{let a=(0,b.readFileSync)(d,"utf8");return JSON.parse(a)}catch(a){return(0,e.hookLogWarn)(`failed to parse config at ${d}: ${a instanceof Error?a.message:String(a)}`),{enabledPolicies:[]}}},"writeHooksConfig",0,function(a){let d=i(),e=(0,c.dirname)(d);(0,b.existsSync)(e)||(0,b.mkdirSync)(e,{recursive:!0}),(0,b.writeFileSync)(d,JSON.stringify(a,null,2)+"\n","utf8")},"writeScopedHooksConfig",0,function(a,d,e){let f=j(d,e),g=(0,c.dirname)(f);(0,b.existsSync)(g)||(0,b.mkdirSync)(g,{recursive:!0}),(0,b.writeFileSync)(f,JSON.stringify(a,null,2)+"\n","utf8")}],28120);var k=a.i(12072),l=a.i(79779),m=a.i(31920);let n=l.POSTHOG_API_KEY,o=new Set;async function p(a,b,c){let d=JSON.stringify({api_key:process.env.FAILPROOFAI_POSTHOG_KEY??n,event:b,distinct_id:a,properties:{...c,$lib:"failproofai-hooks",failproofai_version:k.version,product:l.POSTHOG_PRODUCT}});try{await fetch(process.env.FAILPROOFAI_POSTHOG_HOST?`${process.env.FAILPROOFAI_POSTHOG_HOST}/capture/`:"https://us.i.posthog.com/capture/",{method:"POST",headers:{"Content-Type":"application/json"},body:d,signal:AbortSignal.timeout(5e3)})}catch{}}async function q(a,b,c){if(!(0,m.isTelemetryEnabled)())return;let d=p(a,b,c);o.add(d),d.finally(()=>o.delete(d)),await d}a.s(["trackHookEvent",0,q],98378)}];
|
|
9
|
-
|
|
10
|
-
//# sourceMappingURL=%5Broot-of-the-server%5D__15r6r7w._.js.map
|
|
File without changes
|
|
File without changes
|
|
File without changes
|