failproofai 0.0.11-beta.4 → 0.0.11-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +9 -9
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/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/reminder/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 +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +9 -9
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0sb_5m8._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__13ra2jq._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1_mqemn._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1b9z5-i._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1rhmvod._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1-1804f._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +8 -8
- 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]__00jkjmt._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013du6r._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0-wdurj._.js → [root-of-the-server]__09sb8gm._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e85wxv._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0gfxvb1._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1cd25c7._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__06f-yix._.js → [root-of-the-server]__1hldld5._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1hlrq6y._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ihxdo5._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1mt35_w._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pcxxwg._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1vvfde2._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +15 -15
- 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/{node_modules_html2canvas_dist_html2canvas_esm_0hmsdod.js → node_modules_html2canvas_dist_html2canvas_esm_0jar0u6.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_1d_onnt._.js +2 -2
- 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/{2zjavpea8glet.js → 0faafgt7it9wg.js} +1 -1
- package/.next/standalone/.next/static/chunks/{36l507r2mbf5h.js → 1ha7bu3h33vlg.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1e0o-6kjfnwzh.js → 28ktbb6r1yts-.js} +1 -1
- package/.next/standalone/.next/static/chunks/{41jjdgqqpl7em.js → 2msp6lxlj6y58.js} +1 -1
- package/.next/standalone/.next/static/chunks/2posnfuhnwuc9.js +41 -0
- package/.next/standalone/.next/static/chunks/{20b5bz43so-1k.js → 3-hps4mh626t-.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3y3l184vijlfg.js → 35vxydl4wq7x_.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1btx2c49fk9xt.css → 3co9znvxzaj4r.css} +1 -1
- package/.next/standalone/.next/static/chunks/{0nbmu4_n1j2-c.js → 3yg0zz4h9pe--.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0fkntmojmibda.js → 445x6v-0e8vzo.js} +1 -1
- package/.next/standalone/app/actions/get-audit-result.ts +14 -3
- package/.next/standalone/app/audit/_components/audit-dashboard.tsx +108 -20
- package/.next/standalone/app/audit/_components/audit-progress-strip.tsx +98 -0
- package/.next/standalone/app/audit/_components/rerun-button.tsx +4 -1
- package/.next/standalone/app/audit/_components/return-section.tsx +17 -29
- package/.next/standalone/app/audit/_components/top-audit-bar.tsx +153 -0
- package/.next/standalone/app/audit/audit-styles.css +258 -0
- package/.next/standalone/app/audit/page.tsx +19 -9
- package/.next/standalone/lib/fetch-with-timeout.ts +37 -20
- package/.next/standalone/package.json +1 -1
- package/.next/standalone/server.js +1 -1
- package/README.md +6 -0
- package/dist/cli.mjs +6 -3
- package/lib/fetch-with-timeout.ts +37 -20
- package/package.json +1 -1
- package/src/audit/archetypes.ts +24 -4
- package/src/audit/cache.ts +20 -1
- package/src/audit/dashboard-cache.ts +40 -0
- package/src/audit/features.ts +65 -19
- package/.next/standalone/.next/static/chunks/1bxdpd036n3l9.js +0 -41
- /package/.next/standalone/.next/static/{t4nu8RTRp3Z2srol-9pVb → eWoFUCYXiD-HNIeHw6fYp}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{t4nu8RTRp3Z2srol-9pVb → eWoFUCYXiD-HNIeHw6fYp}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{t4nu8RTRp3Z2srol-9pVb → eWoFUCYXiD-HNIeHw6fYp}/_ssgManifest.js +0 -0
|
@@ -2064,3 +2064,261 @@
|
|
|
2064
2064
|
.share-dock-fab { transition: none; }
|
|
2065
2065
|
.share-dock-caret { transition: none; }
|
|
2066
2066
|
}
|
|
2067
|
+
|
|
2068
|
+
/* ─────────────────────────────────────────────────────────────────────
|
|
2069
|
+
top-audit-bar — thin strip above the IdentitySection. Echoes
|
|
2070
|
+
.arch-mast's dashed bottom border so the bar reads as a sibling band.
|
|
2071
|
+
Lowercase mono throughout; bracketed [ ... ] button label keeps it
|
|
2072
|
+
visually paired with the bottom `[ re-audit now ]` in return-section.
|
|
2073
|
+
───────────────────────────────────────────────────────────────────── */
|
|
2074
|
+
.top-audit-bar {
|
|
2075
|
+
display: grid;
|
|
2076
|
+
grid-template-columns: minmax(0, 1fr) auto auto;
|
|
2077
|
+
align-items: center;
|
|
2078
|
+
gap: 18px;
|
|
2079
|
+
padding: 14px 4px;
|
|
2080
|
+
margin-bottom: 18px;
|
|
2081
|
+
border-bottom: 1px dashed var(--line);
|
|
2082
|
+
font-family: var(--font-mono);
|
|
2083
|
+
font-size: 12px;
|
|
2084
|
+
color: var(--ink-2);
|
|
2085
|
+
/* Subtle left rail mark — keeps the strip from reading as a plain hr */
|
|
2086
|
+
position: relative;
|
|
2087
|
+
}
|
|
2088
|
+
.top-audit-bar::before {
|
|
2089
|
+
content: "";
|
|
2090
|
+
position: absolute;
|
|
2091
|
+
left: -10px;
|
|
2092
|
+
top: 50%;
|
|
2093
|
+
width: 6px;
|
|
2094
|
+
height: 6px;
|
|
2095
|
+
transform: translateY(-50%) rotate(45deg);
|
|
2096
|
+
background: var(--accent-pink);
|
|
2097
|
+
opacity: 0.55;
|
|
2098
|
+
}
|
|
2099
|
+
.top-audit-bar--expired::before { background: var(--amber); opacity: 0.85; }
|
|
2100
|
+
.top-audit-bar--empty::before { background: var(--accent-green); opacity: 0.65; }
|
|
2101
|
+
|
|
2102
|
+
.top-audit-bar__left {
|
|
2103
|
+
display: flex;
|
|
2104
|
+
align-items: baseline;
|
|
2105
|
+
gap: 14px;
|
|
2106
|
+
min-width: 0;
|
|
2107
|
+
}
|
|
2108
|
+
.top-audit-bar__label {
|
|
2109
|
+
text-transform: lowercase;
|
|
2110
|
+
letter-spacing: 0.16em;
|
|
2111
|
+
font-size: 11px;
|
|
2112
|
+
color: var(--dim);
|
|
2113
|
+
white-space: nowrap;
|
|
2114
|
+
}
|
|
2115
|
+
.top-audit-bar__label--warn { color: var(--amber); }
|
|
2116
|
+
.top-audit-bar__glyph {
|
|
2117
|
+
color: var(--accent-pink);
|
|
2118
|
+
letter-spacing: -2px;
|
|
2119
|
+
margin-right: 4px;
|
|
2120
|
+
}
|
|
2121
|
+
.top-audit-bar--expired .top-audit-bar__glyph { color: var(--amber); }
|
|
2122
|
+
.top-audit-bar--empty .top-audit-bar__glyph { color: var(--accent-green); }
|
|
2123
|
+
|
|
2124
|
+
.top-audit-bar__time {
|
|
2125
|
+
display: inline-flex;
|
|
2126
|
+
align-items: center;
|
|
2127
|
+
gap: 8px;
|
|
2128
|
+
color: var(--ink);
|
|
2129
|
+
letter-spacing: 0.02em;
|
|
2130
|
+
white-space: nowrap;
|
|
2131
|
+
}
|
|
2132
|
+
.top-audit-bar__time--fresh { color: var(--accent-green); }
|
|
2133
|
+
|
|
2134
|
+
.top-audit-bar__dot {
|
|
2135
|
+
width: 6px;
|
|
2136
|
+
height: 6px;
|
|
2137
|
+
border-radius: 50%;
|
|
2138
|
+
background: var(--accent-green);
|
|
2139
|
+
display: inline-block;
|
|
2140
|
+
box-shadow: 0 0 0 2px rgba(102, 209, 181, 0.16);
|
|
2141
|
+
}
|
|
2142
|
+
.top-audit-bar__time:not(.top-audit-bar__time--fresh) .top-audit-bar__dot {
|
|
2143
|
+
background: var(--dim);
|
|
2144
|
+
box-shadow: none;
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
.top-audit-bar__expired-copy { color: var(--ink); }
|
|
2148
|
+
|
|
2149
|
+
.top-audit-bar__center {
|
|
2150
|
+
display: inline-flex;
|
|
2151
|
+
align-items: center;
|
|
2152
|
+
gap: 8px;
|
|
2153
|
+
padding: 6px 12px;
|
|
2154
|
+
background: var(--amber-bg);
|
|
2155
|
+
border: 1px dashed var(--amber);
|
|
2156
|
+
color: var(--amber);
|
|
2157
|
+
font-size: 11px;
|
|
2158
|
+
text-transform: lowercase;
|
|
2159
|
+
letter-spacing: 0.04em;
|
|
2160
|
+
justify-self: end;
|
|
2161
|
+
}
|
|
2162
|
+
.top-audit-bar__amber-dot {
|
|
2163
|
+
width: 6px;
|
|
2164
|
+
height: 6px;
|
|
2165
|
+
border-radius: 50%;
|
|
2166
|
+
background: var(--amber);
|
|
2167
|
+
animation: top-audit-amber-pulse 1.6s ease-in-out infinite;
|
|
2168
|
+
}
|
|
2169
|
+
@keyframes top-audit-amber-pulse {
|
|
2170
|
+
0%, 100% { opacity: 0.5; transform: scale(0.85); }
|
|
2171
|
+
50% { opacity: 1; transform: scale(1); }
|
|
2172
|
+
}
|
|
2173
|
+
|
|
2174
|
+
.top-audit-bar__right {
|
|
2175
|
+
justify-self: end;
|
|
2176
|
+
}
|
|
2177
|
+
/* Compact override of `.share-btn` so it fits the bar's 14px padding. The
|
|
2178
|
+
parent class drives the colors, hard-offset hover shadow, and disabled
|
|
2179
|
+
state — we only tweak geometry. */
|
|
2180
|
+
.top-audit-bar__btn {
|
|
2181
|
+
grid-template-columns: 1fr;
|
|
2182
|
+
padding: 8px 14px;
|
|
2183
|
+
gap: 0;
|
|
2184
|
+
font-size: 12px;
|
|
2185
|
+
letter-spacing: 0.06em;
|
|
2186
|
+
text-transform: lowercase;
|
|
2187
|
+
color: var(--ink);
|
|
2188
|
+
}
|
|
2189
|
+
.top-audit-bar__btn[data-state="scanning"] {
|
|
2190
|
+
color: var(--accent-pink);
|
|
2191
|
+
border-right-color: var(--accent-pink);
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2194
|
+
@media (max-width: 720px) {
|
|
2195
|
+
.top-audit-bar {
|
|
2196
|
+
grid-template-columns: 1fr;
|
|
2197
|
+
gap: 10px;
|
|
2198
|
+
}
|
|
2199
|
+
.top-audit-bar__right { justify-self: stretch; }
|
|
2200
|
+
.top-audit-bar__btn { text-align: center; }
|
|
2201
|
+
}
|
|
2202
|
+
@media (prefers-reduced-motion: reduce) {
|
|
2203
|
+
.top-audit-bar__amber-dot { animation: none; }
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
/* ─────────────────────────────────────────────────────────────────────
|
|
2207
|
+
audit-progress-strip — sticky banner pinned to the top of the viewport
|
|
2208
|
+
while a re-audit is in flight. Pink hard-offset shadow matches the
|
|
2209
|
+
page's `.share-btn:hover` vocabulary. Right-edge pulse is a CSS-only
|
|
2210
|
+
keyframe (transform-only — no layout thrash) and is not a fake
|
|
2211
|
+
progress bar.
|
|
2212
|
+
───────────────────────────────────────────────────────────────────── */
|
|
2213
|
+
.audit-progress-strip {
|
|
2214
|
+
position: sticky;
|
|
2215
|
+
top: 0;
|
|
2216
|
+
left: 0;
|
|
2217
|
+
right: 0;
|
|
2218
|
+
z-index: 60;
|
|
2219
|
+
background: var(--bg-2);
|
|
2220
|
+
border-bottom: 1px solid var(--accent-pink);
|
|
2221
|
+
box-shadow: 0 4px 0 0 var(--accent-pink-shadow);
|
|
2222
|
+
font-family: var(--font-mono);
|
|
2223
|
+
/* Slide in from above on mount */
|
|
2224
|
+
animation: audit-progress-slide-in 220ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
2225
|
+
}
|
|
2226
|
+
.audit-progress-strip--failed {
|
|
2227
|
+
border-bottom-color: var(--accent-pink);
|
|
2228
|
+
background: linear-gradient(to right, var(--accent-pink-bg), var(--bg-2));
|
|
2229
|
+
}
|
|
2230
|
+
.audit-progress-strip__inner {
|
|
2231
|
+
position: relative;
|
|
2232
|
+
max-width: 1480px;
|
|
2233
|
+
margin: 0 auto;
|
|
2234
|
+
padding: 12px clamp(20px, 3vw, 48px);
|
|
2235
|
+
display: flex;
|
|
2236
|
+
align-items: center;
|
|
2237
|
+
justify-content: space-between;
|
|
2238
|
+
gap: 16px;
|
|
2239
|
+
}
|
|
2240
|
+
.audit-progress-strip__label {
|
|
2241
|
+
display: inline-flex;
|
|
2242
|
+
align-items: center;
|
|
2243
|
+
gap: 10px;
|
|
2244
|
+
color: var(--ink);
|
|
2245
|
+
font-size: 12px;
|
|
2246
|
+
letter-spacing: 0.06em;
|
|
2247
|
+
text-transform: lowercase;
|
|
2248
|
+
}
|
|
2249
|
+
.audit-progress-strip--failed .audit-progress-strip__label { color: var(--accent-pink); }
|
|
2250
|
+
.audit-progress-strip__elapsed {
|
|
2251
|
+
font-variant-numeric: tabular-nums;
|
|
2252
|
+
font-size: 12px;
|
|
2253
|
+
color: var(--accent-pink);
|
|
2254
|
+
letter-spacing: 0.08em;
|
|
2255
|
+
}
|
|
2256
|
+
.audit-progress-strip__spinner {
|
|
2257
|
+
width: 9px;
|
|
2258
|
+
height: 9px;
|
|
2259
|
+
border-radius: 50%;
|
|
2260
|
+
background: transparent;
|
|
2261
|
+
border: 1.5px solid var(--accent-pink);
|
|
2262
|
+
border-top-color: transparent;
|
|
2263
|
+
animation: audit-progress-spin 800ms linear infinite;
|
|
2264
|
+
}
|
|
2265
|
+
.audit-progress-strip__x {
|
|
2266
|
+
display: inline-flex;
|
|
2267
|
+
align-items: center;
|
|
2268
|
+
justify-content: center;
|
|
2269
|
+
width: 14px;
|
|
2270
|
+
height: 14px;
|
|
2271
|
+
border: 1px solid var(--accent-pink);
|
|
2272
|
+
color: var(--accent-pink);
|
|
2273
|
+
font-size: 11px;
|
|
2274
|
+
line-height: 1;
|
|
2275
|
+
}
|
|
2276
|
+
.audit-progress-strip__dismiss {
|
|
2277
|
+
background: transparent;
|
|
2278
|
+
border: 1px solid var(--line-2);
|
|
2279
|
+
color: var(--ink-2);
|
|
2280
|
+
padding: 5px 10px;
|
|
2281
|
+
font-family: var(--font-mono);
|
|
2282
|
+
font-size: 11px;
|
|
2283
|
+
text-transform: lowercase;
|
|
2284
|
+
letter-spacing: 0.06em;
|
|
2285
|
+
cursor: pointer;
|
|
2286
|
+
transition: border-color 140ms ease, color 140ms ease;
|
|
2287
|
+
}
|
|
2288
|
+
.audit-progress-strip__dismiss:hover {
|
|
2289
|
+
border-color: var(--accent-pink);
|
|
2290
|
+
color: var(--accent-pink);
|
|
2291
|
+
}
|
|
2292
|
+
.audit-progress-strip__pulse {
|
|
2293
|
+
position: absolute;
|
|
2294
|
+
bottom: -1px;
|
|
2295
|
+
left: 0;
|
|
2296
|
+
right: 0;
|
|
2297
|
+
height: 1px;
|
|
2298
|
+
background: linear-gradient(
|
|
2299
|
+
90deg,
|
|
2300
|
+
transparent 0%,
|
|
2301
|
+
var(--accent-pink) 20%,
|
|
2302
|
+
var(--accent-pink) 80%,
|
|
2303
|
+
transparent 100%
|
|
2304
|
+
);
|
|
2305
|
+
transform-origin: left center;
|
|
2306
|
+
animation: audit-progress-pulse 2400ms cubic-bezier(0.55, 0.1, 0.45, 0.9) infinite;
|
|
2307
|
+
}
|
|
2308
|
+
@keyframes audit-progress-spin {
|
|
2309
|
+
to { transform: rotate(360deg); }
|
|
2310
|
+
}
|
|
2311
|
+
@keyframes audit-progress-pulse {
|
|
2312
|
+
0% { transform: scaleX(0) translateX(0%); opacity: 0.4; }
|
|
2313
|
+
50% { transform: scaleX(0.6) translateX(20%); opacity: 1; }
|
|
2314
|
+
100% { transform: scaleX(0) translateX(100%); opacity: 0.2; }
|
|
2315
|
+
}
|
|
2316
|
+
@keyframes audit-progress-slide-in {
|
|
2317
|
+
from { transform: translateY(-100%); opacity: 0; }
|
|
2318
|
+
to { transform: translateY(0); opacity: 1; }
|
|
2319
|
+
}
|
|
2320
|
+
@media (prefers-reduced-motion: reduce) {
|
|
2321
|
+
.audit-progress-strip { animation: none; }
|
|
2322
|
+
.audit-progress-strip__spinner { animation: none; border-top-color: var(--accent-pink); }
|
|
2323
|
+
.audit-progress-strip__pulse { animation: none; opacity: 0.4; transform: scaleX(0.4) translateX(30%); }
|
|
2324
|
+
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { Suspense } from "react";
|
|
10
10
|
import { notFound } from "next/navigation";
|
|
11
|
-
import { readDashboardCache } from "@/src/audit/dashboard-cache";
|
|
11
|
+
import { readDashboardCache, readDashboardCacheMeta } from "@/src/audit/dashboard-cache";
|
|
12
12
|
import { BUILTIN_POLICIES } from "@/src/hooks/builtin-policies";
|
|
13
13
|
import { AUDIT_DETECTORS } from "@/src/audit/detectors";
|
|
14
14
|
import { AuditDashboard } from "./_components/audit-dashboard";
|
|
@@ -32,14 +32,24 @@ export default async function AuditPage({ searchParams }: PageProps) {
|
|
|
32
32
|
const { p } = await searchParams;
|
|
33
33
|
|
|
34
34
|
const cache = readDashboardCache();
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
35
|
+
let initial;
|
|
36
|
+
if (cache) {
|
|
37
|
+
initial = {
|
|
38
|
+
status: "cached" as const,
|
|
39
|
+
cachedAt: cache.cachedAt,
|
|
40
|
+
params: cache.params,
|
|
41
|
+
result: cache.result,
|
|
42
|
+
};
|
|
43
|
+
} else {
|
|
44
|
+
// No fresh cache. Probe meta so we can distinguish "first run" from
|
|
45
|
+
// "your last audit expired" and surface the right top-bar nudge.
|
|
46
|
+
const meta = readDashboardCacheMeta();
|
|
47
|
+
initial = {
|
|
48
|
+
status: "empty" as const,
|
|
49
|
+
expired: meta !== null,
|
|
50
|
+
expiredAt: meta?.cachedAt ?? null,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
43
53
|
|
|
44
54
|
return (
|
|
45
55
|
<Suspense>
|
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared fetch wrapper with per-request timeout
|
|
2
|
+
* Shared fetch wrapper with per-request timeout and external-signal
|
|
3
|
+
* composition.
|
|
3
4
|
*
|
|
4
5
|
* Replaces three byte-equivalent implementations that had drifted on the
|
|
5
6
|
* default timeout (15s in two client components, 10s in the server-side
|
|
6
7
|
* api-server-client). Co-locates the `isAbortError` predicate so callers
|
|
7
8
|
* can classify timeout vs network failures consistently.
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* Built on the platform primitives `AbortSignal.timeout()` — which
|
|
11
|
+
* aborts with a typed `DOMException(..., "TimeoutError")` rather than
|
|
12
|
+
* the default bare abort that surfaces as Next.js 16's dev-overlay
|
|
13
|
+
* "signal is aborted without reason" warning — and `AbortSignal.any()`,
|
|
14
|
+
* which composes the timeout signal with any caller-supplied
|
|
15
|
+
* `init.signal` so a component-unmount or parent-controller abort
|
|
16
|
+
* actually stops the in-flight fetch. The prior `AbortController` +
|
|
17
|
+
* `setTimeout` implementation called `controller.abort()` with no
|
|
18
|
+
* reason AND silently dropped `init.signal` by spreading then
|
|
19
|
+
* overwriting it with the controller's own signal.
|
|
20
|
+
*
|
|
21
|
+
* Both APIs are available in every runtime Next.js 16 supports:
|
|
22
|
+
* `AbortSignal.timeout` since Node 17.3 / 16.14, `AbortSignal.any`
|
|
23
|
+
* since Node 20.3 (also backported to 18.17). Next.js 16's minimum
|
|
24
|
+
* runtime (Node >= 20.9, per its engines field) covers both. Browser
|
|
25
|
+
* support: Chrome 116+, Firefox 124+, Safari 17.4+.
|
|
12
26
|
*/
|
|
13
27
|
|
|
14
28
|
/** Hard cap on every fetch using this helper unless overridden. Picked to
|
|
@@ -16,27 +30,30 @@
|
|
|
16
30
|
* so a slow but successful upstream response still lands. */
|
|
17
31
|
export const DEFAULT_FETCH_TIMEOUT_MS = 15_000;
|
|
18
32
|
|
|
19
|
-
export
|
|
33
|
+
export function fetchWithTimeout(
|
|
20
34
|
input: RequestInfo | URL,
|
|
21
35
|
init: RequestInit = {},
|
|
22
36
|
timeoutMs: number = DEFAULT_FETCH_TIMEOUT_MS,
|
|
23
37
|
): Promise<Response> {
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
clearTimeout(id);
|
|
30
|
-
}
|
|
38
|
+
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
39
|
+
const signal = init.signal
|
|
40
|
+
? AbortSignal.any([init.signal, timeoutSignal])
|
|
41
|
+
: timeoutSignal;
|
|
42
|
+
return fetch(input, { ...init, signal });
|
|
31
43
|
}
|
|
32
44
|
|
|
33
|
-
/** True when an error came from an AbortController.abort() OR
|
|
34
|
-
* `AbortSignal.timeout` firing. Both surface as
|
|
35
|
-
*
|
|
36
|
-
*
|
|
45
|
+
/** True when an error came from an `AbortController.abort()` OR an
|
|
46
|
+
* `AbortSignal.timeout()` firing. Both surface as objects whose `name`
|
|
47
|
+
* is "AbortError" or "TimeoutError" respectively — depending on the
|
|
48
|
+
* runtime, they may be `Error` subclasses, `DOMException` instances,
|
|
49
|
+
* both, or neither (the jsdom polyfill, for one, breaks the Error
|
|
50
|
+
* prototype chain), so we duck-type on `name` rather than the
|
|
51
|
+
* provenance. Callers always pass values caught from a try/catch, so
|
|
52
|
+
* the universe of inputs is narrow enough that name-matching is
|
|
53
|
+
* unambiguous. Keeping the two names in one predicate prevents the
|
|
54
|
+
* "I forgot TimeoutError" drift class. */
|
|
37
55
|
export function isAbortError(err: unknown): boolean {
|
|
38
|
-
return
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
);
|
|
56
|
+
if (err === null || typeof err !== "object") return false;
|
|
57
|
+
const name = (err as { name?: unknown }).name;
|
|
58
|
+
return name === "AbortError" || name === "TimeoutError";
|
|
42
59
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "failproofai",
|
|
3
|
-
"version": "0.0.11-beta.
|
|
3
|
+
"version": "0.0.11-beta.6",
|
|
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"
|
|
@@ -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.11-beta.
|
|
12
|
+
const nextConfig = {"env":{"NEXT_PUBLIC_APP_VERSION":"0.0.11-beta.6"},"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
|
@@ -166,6 +166,12 @@ MIT with [Commons Clause](https://commonsclause.com/) — free for internal and
|
|
|
166
166
|
|
|
167
167
|
See [CONTRIBUTING.md](./CONTRIBUTING.md). New policies, edge cases, and translations all welcome.
|
|
168
168
|
|
|
169
|
+
> **Build before you start.** Run `bun install && bun run build` first. This repo runs
|
|
170
|
+
> failproofai's own hooks on itself, and they resolve the `failproofai` import against the
|
|
171
|
+
> compiled `dist/` bundle — without a build you'll hit `Cannot find package 'failproofai'`
|
|
172
|
+
> hook errors. Rebuild after changing `src/`. See
|
|
173
|
+
> [Build before the in-repo dev hooks will work](./CONTRIBUTING.md#build-before-the-in-repo-dev-hooks-will-work).
|
|
174
|
+
|
|
169
175
|
---
|
|
170
176
|
|
|
171
177
|
Built by [Nivedit Jain](https://github.com/NiveditJain) and [Nikita Agarwal](https://github.com/nk-ag).
|
package/dist/cli.mjs
CHANGED
|
@@ -16,7 +16,7 @@ var __export = (target, all) => {
|
|
|
16
16
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
17
17
|
|
|
18
18
|
// package.json
|
|
19
|
-
var version2 = "0.0.11-beta.
|
|
19
|
+
var version2 = "0.0.11-beta.6";
|
|
20
20
|
var init_package = () => {};
|
|
21
21
|
|
|
22
22
|
// src/posthog-key.ts
|
|
@@ -8747,7 +8747,10 @@ var init_telemetry = __esm(() => {
|
|
|
8747
8747
|
|
|
8748
8748
|
// lib/fetch-with-timeout.ts
|
|
8749
8749
|
function isAbortError(err) {
|
|
8750
|
-
|
|
8750
|
+
if (err === null || typeof err !== "object")
|
|
8751
|
+
return false;
|
|
8752
|
+
const name = err.name;
|
|
8753
|
+
return name === "AbortError" || name === "TimeoutError";
|
|
8751
8754
|
}
|
|
8752
8755
|
|
|
8753
8756
|
// lib/auth/api-server-client.ts
|
|
@@ -9900,7 +9903,7 @@ import { realpathSync as realpathSync3 } from "fs";
|
|
|
9900
9903
|
import { dirname as dirname8, resolve as resolve16 } from "path";
|
|
9901
9904
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
9902
9905
|
// package.json
|
|
9903
|
-
var version = "0.0.11-beta.
|
|
9906
|
+
var version = "0.0.11-beta.6";
|
|
9904
9907
|
|
|
9905
9908
|
// bin/failproofai.mjs
|
|
9906
9909
|
if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
|
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared fetch wrapper with per-request timeout
|
|
2
|
+
* Shared fetch wrapper with per-request timeout and external-signal
|
|
3
|
+
* composition.
|
|
3
4
|
*
|
|
4
5
|
* Replaces three byte-equivalent implementations that had drifted on the
|
|
5
6
|
* default timeout (15s in two client components, 10s in the server-side
|
|
6
7
|
* api-server-client). Co-locates the `isAbortError` predicate so callers
|
|
7
8
|
* can classify timeout vs network failures consistently.
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* Built on the platform primitives `AbortSignal.timeout()` — which
|
|
11
|
+
* aborts with a typed `DOMException(..., "TimeoutError")` rather than
|
|
12
|
+
* the default bare abort that surfaces as Next.js 16's dev-overlay
|
|
13
|
+
* "signal is aborted without reason" warning — and `AbortSignal.any()`,
|
|
14
|
+
* which composes the timeout signal with any caller-supplied
|
|
15
|
+
* `init.signal` so a component-unmount or parent-controller abort
|
|
16
|
+
* actually stops the in-flight fetch. The prior `AbortController` +
|
|
17
|
+
* `setTimeout` implementation called `controller.abort()` with no
|
|
18
|
+
* reason AND silently dropped `init.signal` by spreading then
|
|
19
|
+
* overwriting it with the controller's own signal.
|
|
20
|
+
*
|
|
21
|
+
* Both APIs are available in every runtime Next.js 16 supports:
|
|
22
|
+
* `AbortSignal.timeout` since Node 17.3 / 16.14, `AbortSignal.any`
|
|
23
|
+
* since Node 20.3 (also backported to 18.17). Next.js 16's minimum
|
|
24
|
+
* runtime (Node >= 20.9, per its engines field) covers both. Browser
|
|
25
|
+
* support: Chrome 116+, Firefox 124+, Safari 17.4+.
|
|
12
26
|
*/
|
|
13
27
|
|
|
14
28
|
/** Hard cap on every fetch using this helper unless overridden. Picked to
|
|
@@ -16,27 +30,30 @@
|
|
|
16
30
|
* so a slow but successful upstream response still lands. */
|
|
17
31
|
export const DEFAULT_FETCH_TIMEOUT_MS = 15_000;
|
|
18
32
|
|
|
19
|
-
export
|
|
33
|
+
export function fetchWithTimeout(
|
|
20
34
|
input: RequestInfo | URL,
|
|
21
35
|
init: RequestInit = {},
|
|
22
36
|
timeoutMs: number = DEFAULT_FETCH_TIMEOUT_MS,
|
|
23
37
|
): Promise<Response> {
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
clearTimeout(id);
|
|
30
|
-
}
|
|
38
|
+
const timeoutSignal = AbortSignal.timeout(timeoutMs);
|
|
39
|
+
const signal = init.signal
|
|
40
|
+
? AbortSignal.any([init.signal, timeoutSignal])
|
|
41
|
+
: timeoutSignal;
|
|
42
|
+
return fetch(input, { ...init, signal });
|
|
31
43
|
}
|
|
32
44
|
|
|
33
|
-
/** True when an error came from an AbortController.abort() OR
|
|
34
|
-
* `AbortSignal.timeout` firing. Both surface as
|
|
35
|
-
*
|
|
36
|
-
*
|
|
45
|
+
/** True when an error came from an `AbortController.abort()` OR an
|
|
46
|
+
* `AbortSignal.timeout()` firing. Both surface as objects whose `name`
|
|
47
|
+
* is "AbortError" or "TimeoutError" respectively — depending on the
|
|
48
|
+
* runtime, they may be `Error` subclasses, `DOMException` instances,
|
|
49
|
+
* both, or neither (the jsdom polyfill, for one, breaks the Error
|
|
50
|
+
* prototype chain), so we duck-type on `name` rather than the
|
|
51
|
+
* provenance. Callers always pass values caught from a try/catch, so
|
|
52
|
+
* the universe of inputs is narrow enough that name-matching is
|
|
53
|
+
* unambiguous. Keeping the two names in one predicate prevents the
|
|
54
|
+
* "I forgot TimeoutError" drift class. */
|
|
37
55
|
export function isAbortError(err: unknown): boolean {
|
|
38
|
-
return
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
);
|
|
56
|
+
if (err === null || typeof err !== "object") return false;
|
|
57
|
+
const name = (err as { name?: unknown }).name;
|
|
58
|
+
return name === "AbortError" || name === "TimeoutError";
|
|
42
59
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "failproofai",
|
|
3
|
-
"version": "0.0.11-beta.
|
|
3
|
+
"version": "0.0.11-beta.6",
|
|
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"
|
package/src/audit/archetypes.ts
CHANGED
|
@@ -820,9 +820,20 @@ const ARCHITECT_CAUTION_MIN = 0.35;
|
|
|
820
820
|
/** Architect only applies when cowboy isn't itself over-indexing. */
|
|
821
821
|
const ARCHITECT_COWBOY_MAX_LIFT = 1.0;
|
|
822
822
|
/** Normalised lift entropy above this (with enough distinct clusters lit)
|
|
823
|
-
* → goldfish (genuinely scattered).
|
|
824
|
-
|
|
823
|
+
* → goldfish (genuinely scattered). Retuned from 0.75 → 0.70 when the lift
|
|
824
|
+
* denominator moved from catalog weights to empirical firing shares
|
|
825
|
+
* (see features.ts BASELINE_SHARE): the empirical baseline reshapes the lift
|
|
826
|
+
* vector, and 0.75 left goldfish under-reachable (< 4% of the population). */
|
|
827
|
+
const GOLDFISH_ENTROPY = 0.70;
|
|
825
828
|
const GOLDFISH_MIN_NONZERO = 4;
|
|
829
|
+
/** Goldfish also requires the SECOND-highest cluster lift to be meaningfully
|
|
830
|
+
* above baseline. Entropy on its own is satisfied by a uniform-at-baseline
|
|
831
|
+
* lift vector (every cluster firing at typical ambient rate → all lifts ≈ 1.0
|
|
832
|
+
* → entropy = max), which would otherwise collapse every "typical" agent onto
|
|
833
|
+
* goldfish. Requiring secondLift > 1.3 means at least TWO clusters are
|
|
834
|
+
* genuinely over-indexing — the actual definition of scatter, not just
|
|
835
|
+
* "average-volume noise spread across many clusters". */
|
|
836
|
+
const GOLDFISH_MIN_SECOND_LIFT = 1.3;
|
|
826
837
|
/** When the top-two lifts are within this ratio, resolve deterministically by
|
|
827
838
|
* the behaviour fingerprint instead of always taking the arithmetic winner —
|
|
828
839
|
* spreads near-ties across the population without any RNG. */
|
|
@@ -888,9 +899,18 @@ export function classifyAgent(result: AuditResult, seed = ""): Classification {
|
|
|
888
899
|
return { archetype: "architect", secondary: ARCHETYPES.architect.secondary, ...base };
|
|
889
900
|
}
|
|
890
901
|
|
|
891
|
-
// 3. goldfish — genuinely scattered across many clusters.
|
|
902
|
+
// 3. goldfish — genuinely scattered across many clusters. Both the entropy
|
|
903
|
+
// and the second-lift gate must clear: entropy catches "many clusters
|
|
904
|
+
// contribute", secondLift catches "the contribution is actually elevated
|
|
905
|
+
// relative to ambient". Without secondLift, a high-volume average user
|
|
906
|
+
// (lifts ≈ 1.0 everywhere) passes the entropy gate and collapses onto
|
|
907
|
+
// goldfish — that's the bug fixed alongside this gate.
|
|
892
908
|
const nonZero = MAPPABLE_KEYS.filter((k) => f.clusterLift[k] > 0).length;
|
|
893
|
-
if (
|
|
909
|
+
if (
|
|
910
|
+
nonZero >= GOLDFISH_MIN_NONZERO &&
|
|
911
|
+
f.entropy > GOLDFISH_ENTROPY &&
|
|
912
|
+
f.secondLift >= GOLDFISH_MIN_SECOND_LIFT
|
|
913
|
+
) {
|
|
894
914
|
const strongest = rankByLift(f, MAPPABLE_KEYS)[0];
|
|
895
915
|
return { archetype: "goldfish", secondary: strongest, ...base };
|
|
896
916
|
}
|