failproofai 1.0.10 → 1.0.11-beta.0
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 +6 -6
- package/.next/standalone/.next/prerender-manifest.json +4 -4
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +3 -3
- 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 +4 -4
- 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.meta +8 -0
- 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/build-manifest.json +3 -3
- 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 +4 -4
- 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.meta +8 -0
- 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 +4 -4
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +4 -4
- 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 +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js +2 -2
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +4 -4
- 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 +3 -3
- 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 +3 -3
- 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/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js +4 -4
- 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.meta +8 -0
- 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/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +4 -4
- 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/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
- package/.next/standalone/.next/server/app/policies/page.js +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/build-manifest.json +3 -3
- 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 +5 -5
- 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/build-manifest.json +3 -3
- 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 +5 -5
- 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/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +5 -5
- 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/build-manifest.json +3 -3
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/settings/page.js +9 -9
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__0qxhecv._.js → [externals]__0d7i9ea._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{[externals]__0sg9-3p._.js → [externals]__0hjaw70._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[externals]__1_9ze9b._.js +3 -0
- package/.next/standalone/.next/server/chunks/[externals]__1oenfmn._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__08dchfu._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ga9hs7._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0l3yhx4._.js +2 -2
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0moxohc._.js +22 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0z2ll-a._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1adacul._.js +11 -11
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1autwno._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1v25n-6._.js +3 -0
- package/.next/standalone/.next/server/chunks/_09dz7xv._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0tovk6q._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0trp3yc._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1ek68ln._.js +2 -2
- package/.next/standalone/.next/server/chunks/_1fz8m31._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1jrv3hg._.js +3 -0
- package/.next/standalone/.next/server/chunks/_1nx8fim._.js +3 -0
- package/.next/standalone/.next/server/chunks/_1ogwigf._.js +1 -1
- package/.next/standalone/.next/server/chunks/{_1q5i8mb._.js → _1q27azx._.js} +2 -2
- package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +1 -1
- package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_0el6rg8._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_0ol5pa3._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_04op_ou._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_1rqmk27._.js} +2 -2
- package/.next/standalone/.next/server/chunks/{node_modules_posthog-node_dist_entrypoints_index_node_mjs_0dr20uz._.js → node_modules_posthog-node_dist_entrypoints_index_node_mjs_1w7tiq4._.js} +2 -2
- 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]__04usis8._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1-bm5zf._.js → [root-of-the-server]__0502lat._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_gn5iz._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0f765xr._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__01bmjsj._.js → [root-of-the-server]__0h38gzz._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hoaz1g._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1ouobn4._.js → [root-of-the-server]__0mxmwtx._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__19evfi8._.js → [root-of-the-server]__0uescqv._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1484zv2._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1mf3zp6._.js → [root-of-the-server]__19dutr7._.js} +4 -4
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0oqrl71._.js → [root-of-the-server]__1_qv8oh._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__1u6sn69._.js → [root-of-the-server]__1ab4ifb._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1fbrk56._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pprgri._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1um4yxn._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1wb4yt2._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1y3n3cn._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0bqoto4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_16pa9ht._.js → _0lnpwk8._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_0yq5_3a._.js → _15y8myg._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1gb0ifp._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_042cgl1._.js → _1o95rf0._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_1zopuov._.js → _1thr5rf._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +12 -14
- package/.next/standalone/.next/server/chunks/ssr/app_actions_get-scheduled-audit_ts_0ei9sni._.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_02tf1h4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_1hl81y4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_0nkkbfv._.js +6 -0
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-home_ts_0je3xkv._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +6 -6
- package/.next/standalone/.next/server/middleware.js +1 -1
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +23 -23
- package/.next/standalone/.next/static/chunks/{03h3b-uomi7_d.js → 0pra9i676pym1.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2kj826h1w9r47.js → 1-lpi0m-hc1kb.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3ob2161ap37ul.js → 17yvyyblr_eb5.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3nkc2jlgyygda.js → 1mylcr99gccyz.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2j92xul6y24_v.js → 1wozchtn2etvh.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3mjfvng11xnoo.js → 23thtelz1a-ur.js} +2 -2
- package/.next/standalone/.next/static/chunks/{1fqukzzowjflt.js → 2bc17tohgs4bs.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3u1s8dsqiean5.js → 2xq-ejo8kti18.js} +1 -1
- package/.next/standalone/.next/static/chunks/3-_pth_c9n938.js +1 -0
- package/.next/standalone/.next/static/chunks/{3i8rg2fv9nd6e.js → 3n46e45atic-m.js} +1 -1
- package/.next/standalone/.next/static/chunks/{078dofaxvjgpd.js → 3q7sndqftqhw9.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0542cuk_va8g1.js → 3sg07wnn969xq.js} +1 -1
- package/.next/standalone/.next/static/chunks/{turbopack-11dn2pegmg9_9.js → turbopack-1opxka4dtjbc5.js} +1 -1
- package/.next/standalone/app/actions/install-hooks-web.ts +10 -2
- package/.next/standalone/hermes-plugin/plugin.yaml +1 -1
- package/.next/standalone/node_modules/@next/env/package.json +1 -1
- package/.next/standalone/node_modules/next/dist/build/swc/index.js +1 -1
- package/.next/standalone/node_modules/next/dist/compiled/hash.js/sha256/256.js +1 -0
- package/.next/standalone/node_modules/next/dist/compiled/hash.js/sha256/package.json +1 -0
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo-experimental.runtime.prod.js +17 -17
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-page-turbo.runtime.prod.js +18 -18
- package/.next/standalone/node_modules/next/dist/compiled/next-server/app-route-turbo.runtime.prod.js +3 -3
- package/.next/standalone/node_modules/next/dist/compiled/next-server/pages-turbo.runtime.prod.js +13 -13
- package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
- package/.next/standalone/node_modules/next/dist/server/base-server.js +1 -2
- package/.next/standalone/node_modules/next/dist/server/config.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-turbopack.js +2 -2
- package/.next/standalone/node_modules/next/dist/server/dev/hot-reloader-webpack.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/image-optimizer.js +265 -53
- package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/incremental-cache/file-system-cache.js +177 -19
- package/.next/standalone/node_modules/next/dist/server/lib/incremental-cache/index.js +36 -17
- package/.next/standalone/node_modules/next/dist/server/lib/incremental-cache/shared-cache-controls.external.js +14 -6
- package/.next/standalone/node_modules/next/dist/server/lib/match-next-data-pathname.js +3 -1
- package/.next/standalone/node_modules/next/dist/server/lib/node-fs-methods.js +14 -0
- package/.next/standalone/node_modules/next/dist/server/lib/route-cache-key.js +77 -0
- package/.next/standalone/node_modules/next/dist/server/lib/router-utils/block-cross-site-dev.js +9 -11
- package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/mcp/get-mcp-middleware.js +4 -2
- package/.next/standalone/node_modules/next/dist/server/next-server.js +7 -3
- package/.next/standalone/node_modules/next/dist/server/response-cache/index.js +32 -16
- package/.next/standalone/node_modules/next/dist/server/route-matcher-providers/app-page-route-matcher-provider.js +2 -2
- package/.next/standalone/node_modules/next/dist/server/route-modules/pages/pages-handler.js +6 -1
- package/.next/standalone/node_modules/next/dist/server/route-modules/route-module.js +9 -2
- package/.next/standalone/node_modules/next/dist/server/use-cache/use-cache-wrapper.js +30 -29
- package/.next/standalone/node_modules/next/dist/shared/lib/router/utils/app-paths.js +18 -1
- package/.next/standalone/node_modules/next/dist/telemetry/anonymous-meta.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/swc-load-failure.js +1 -1
- package/.next/standalone/node_modules/next/dist/telemetry/events/version.js +2 -2
- package/.next/standalone/node_modules/next/package.json +10 -10
- package/.next/standalone/package.json +14 -11
- package/.next/standalone/sdk/python/README.md +41 -0
- package/.next/standalone/sdk/python/docs/README.md +1 -0
- package/.next/standalone/sdk/python/docs/otel/README.md +36 -0
- package/.next/standalone/sdk/python/docs/otel/examples/agent_trace.py +30 -0
- package/.next/standalone/sdk/python/docs/otel/examples/quickstart.py +22 -0
- package/.next/standalone/sdk/python/failproofai_sdk/__init__.py +8 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/__init__.py +3 -0
- package/.next/standalone/sdk/python/failproofai_sdk/integrations/otel.py +189 -0
- package/.next/standalone/sdk/python/pyproject.toml +2 -1
- package/.next/standalone/sdk/python/tests/test_docs.py +16 -3
- package/.next/standalone/sdk/python/tests/test_integrations.py +1 -1
- package/.next/standalone/sdk/python/tests/test_otel.py +147 -0
- package/.next/standalone/sdk/python/tests/test_zero_dependencies.py +4 -1
- package/.next/standalone/sdk/python/uv.lock +258 -147
- package/.next/standalone/sdk/typescript/README.md +43 -0
- package/.next/standalone/sdk/typescript/integration/ai.test.ts +9 -2
- package/.next/standalone/sdk/typescript/package-lock.json +57 -5
- package/.next/standalone/sdk/typescript/package.json +2 -0
- package/.next/standalone/sdk/typescript/src/edge/index.ts +9 -0
- package/.next/standalone/sdk/typescript/src/index.ts +2 -0
- package/.next/standalone/sdk/typescript/src/integrations/index.ts +4 -1
- package/.next/standalone/sdk/typescript/src/integrations/otel.ts +204 -0
- package/.next/standalone/sdk/typescript/test/integrations.test.ts +1 -1
- package/.next/standalone/sdk/typescript/test/otel.test.ts +125 -0
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +653 -1077
- package/dist/cli.mjs +8781 -4050
- package/dist/worker.mjs +170 -62
- package/hermes-plugin/plugin.yaml +1 -1
- package/package.json +14 -11
- package/scripts/launch-facts.ts +157 -0
- package/scripts/launch-ready.ts +228 -0
- package/scripts/launch-screen.ts +202 -0
- package/scripts/launch.ts +106 -49
- package/scripts/skew-log-filter.ts +38 -0
- package/src/audit/cli-login.ts +39 -59
- package/src/audit/cli.ts +308 -228
- package/src/audit/index.ts +45 -2
- package/src/audit/schedule-cli.ts +83 -120
- package/src/audit/types.ts +31 -0
- package/src/hooks/agent-selection.ts +155 -0
- package/src/hooks/backfill-cli.ts +151 -137
- package/src/hooks/backfill-request.ts +149 -0
- package/src/hooks/cloud-connection.ts +1 -1
- package/src/hooks/cloud-enrollment-cli.ts +78 -28
- package/src/hooks/cloud-introspect.ts +3 -0
- package/src/hooks/collector-config.ts +10 -1
- package/src/hooks/config-status.ts +717 -0
- package/src/hooks/configure-wizard.ts +967 -988
- package/src/hooks/daemon-service.ts +16 -6
- package/src/hooks/did-you-mean.ts +185 -0
- package/src/hooks/flush-cli.ts +33 -7
- package/src/hooks/fp-config.ts +96 -0
- package/src/hooks/fp-home.ts +11 -0
- package/src/hooks/fp-reset.ts +102 -95
- package/src/hooks/handler.ts +4 -0
- package/src/hooks/harness-cli.ts +87 -138
- package/src/hooks/install-prompt.ts +38 -477
- package/src/hooks/integrations.ts +1 -1
- package/src/hooks/jev-cli.ts +183 -196
- package/src/hooks/manager.ts +554 -358
- package/src/hooks/onboarding-attempt.ts +11 -9
- package/src/hooks/otel-cli.ts +350 -0
- package/src/hooks/otel-output.ts +24 -0
- package/src/hooks/otel-writers.ts +215 -0
- package/src/hooks/pack-cli.ts +219 -204
- package/src/hooks/report-body.ts +50 -0
- package/src/hooks/safe-config-write.ts +4 -2
- package/src/hooks/session-pause-cli.ts +93 -73
- package/src/hooks/tui.ts +849 -389
- package/src/hooks/uninstall-cli.ts +136 -149
- package/src/hooks/untraced-note.ts +52 -0
- package/.next/standalone/.next/server/chunks/[externals]__19_pzeq._.js +0 -3
- package/.next/standalone/.next/server/chunks/[externals]__20kzpkf._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__01eqny5._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__05ja_05._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0igxt32._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0zyc_nm._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ttrwnd._.js +0 -22
- package/.next/standalone/.next/server/chunks/_0bs-v8p._.js +0 -3
- package/.next/standalone/.next/server/chunks/_185gyk9._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__056wjo4._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n0xg95._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rwtwpm._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0yrsbd_._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11mayhe._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__15578wp._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1m_svbe._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1q4p5b8._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js +0 -6
- package/.next/standalone/.next/static/chunks/1lyg_puttohbc.js +0 -1
- /package/.next/standalone/.next/static/{ECs8__hcNabYV58WfDh-3 → xtcpqBNBdjQVerPMkI2HI}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{ECs8__hcNabYV58WfDh-3 → xtcpqBNBdjQVerPMkI2HI}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{ECs8__hcNabYV58WfDh-3 → xtcpqBNBdjQVerPMkI2HI}/_ssgManifest.js +0 -0
|
@@ -1,48 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* No external dependencies.
|
|
2
|
+
* Which agent CLIs a `policies --install / --uninstall` acts on, asked with the
|
|
3
|
+
* shared `selectOne` when more than one is detected.
|
|
5
4
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* This file used to carry two hand-rolled raw-mode menus of its own: this one,
|
|
6
|
+
* with a two-write (non-atomic) repaint and an escape-gate that ignored pipes,
|
|
7
|
+
* and a searchable policy picker that nothing had called since `--install`
|
|
8
|
+
* stopped choosing policies. The picker is gone and the menu is `selectOne`,
|
|
9
|
+
* so it draws, windows and repaints like every other prompt in the CLI.
|
|
11
10
|
*/
|
|
12
|
-
import
|
|
13
|
-
// Brand palette, ANSI-aware truncation, and glyphs shared with the configure
|
|
14
|
-
// wizard (tui.ts) so every failproofai menu reads as one system.
|
|
15
|
-
import {
|
|
16
|
-
paint,
|
|
17
|
-
truncate as truncateLine,
|
|
18
|
-
BAR,
|
|
19
|
-
STEP_ACTIVE as STEP,
|
|
20
|
-
STEP_DONE as DONE,
|
|
21
|
-
CHECK_ON as BOX_ON,
|
|
22
|
-
CHECK_OFF as BOX_OFF,
|
|
23
|
-
} from "./tui";
|
|
24
|
-
import { BUILTIN_POLICIES } from "./builtin-policies";
|
|
11
|
+
import { colorsEnabled, optsFor, screenKit, selectOne, type SelectChoice } from "./tui";
|
|
25
12
|
import { detectInstalledClis, getIntegration, listInstallableIds } from "./integrations";
|
|
26
13
|
import { type IntegrationType } from "./types";
|
|
27
14
|
import { trackHookEvent } from "./hook-telemetry";
|
|
28
15
|
import { getInstanceId } from "../../lib/telemetry-id";
|
|
29
16
|
|
|
30
|
-
interface SelectItem {
|
|
31
|
-
name: string;
|
|
32
|
-
description: string;
|
|
33
|
-
category: string;
|
|
34
|
-
selected: boolean;
|
|
35
|
-
beta: boolean;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
type DisplayRow =
|
|
39
|
-
| { kind: "header"; category: string; enabledCount: number; totalCount: number }
|
|
40
|
-
| { kind: "item"; item: SelectItem; filteredIndex: number };
|
|
41
|
-
|
|
42
|
-
export interface PromptOptions {
|
|
43
|
-
includeBeta?: boolean;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
17
|
/** Whether the prompt is being shown for an install or an uninstall flow.
|
|
47
18
|
* Drives heading + hint text so `policies --uninstall` no longer says
|
|
48
19
|
* "Install Hooks". */
|
|
@@ -93,15 +64,17 @@ export async function resolveTargetClis(
|
|
|
93
64
|
// Uninstall flow: no agent CLIs detected — nothing to remove from. Default to
|
|
94
65
|
// claude so removeHooks operates over Claude's scopes (no-op if no settings file).
|
|
95
66
|
console.log(
|
|
96
|
-
|
|
97
|
-
"
|
|
67
|
+
screenKit({ color: colorsEnabled(process.stdout) }).caution(
|
|
68
|
+
"No agent CLI was found on PATH, so this acts on Claude Code. Nothing is removed if it has no settings file.",
|
|
69
|
+
),
|
|
98
70
|
);
|
|
99
71
|
fireDetectionEvent(["claude"], "defaulted_to_claude");
|
|
100
72
|
return ["claude"];
|
|
101
73
|
}
|
|
102
74
|
console.log(
|
|
103
|
-
|
|
104
|
-
"
|
|
75
|
+
screenKit({ color: colorsEnabled(process.stdout) }).caution(
|
|
76
|
+
"No agent CLI was found on PATH, so hooks go into Claude Code. They take effect once it is installed.",
|
|
77
|
+
),
|
|
105
78
|
);
|
|
106
79
|
fireDetectionEvent(["claude"], "defaulted_to_claude");
|
|
107
80
|
return ["claude"];
|
|
@@ -159,9 +132,8 @@ export function buildCliMenuOptions(
|
|
|
159
132
|
|
|
160
133
|
const options: CliMenuOption[] = [];
|
|
161
134
|
if (detected.length > 1) {
|
|
162
|
-
const verb = action === "uninstall" ? "Remove from" : "Install for";
|
|
163
135
|
options.push({
|
|
164
|
-
label:
|
|
136
|
+
label: `All ${detected.length} agents`,
|
|
165
137
|
value: detected,
|
|
166
138
|
detected: true,
|
|
167
139
|
isAll: true,
|
|
@@ -187,446 +159,35 @@ export function buildCliMenuOptions(
|
|
|
187
159
|
}
|
|
188
160
|
|
|
189
161
|
/**
|
|
190
|
-
*
|
|
191
|
-
* multiple agent CLIs are detected.
|
|
162
|
+
* "Install / remove hooks for which agent?" when more than one is detected.
|
|
192
163
|
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
* Cursor skips section headers — it only lands on selectable item rows.
|
|
164
|
+
* Detected agents first — with an "All N agents" row when there are several —
|
|
165
|
+
* then, for an install, every undetected agent as a forward install, so hooks
|
|
166
|
+
* can be in place before the agent is. Esc exits 130, as it always has: the
|
|
167
|
+
* caller has no "cancelled" path, and an install that quietly picked something
|
|
168
|
+
* would be worse.
|
|
200
169
|
*/
|
|
201
170
|
async function promptCliTargetSelection(
|
|
202
171
|
detected: IntegrationType[],
|
|
203
172
|
action: CliPromptAction = "install",
|
|
204
173
|
): Promise<IntegrationType[]> {
|
|
205
|
-
const { options
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
title: `Detected (${detected.length})`,
|
|
219
|
-
});
|
|
220
|
-
for (const opt of options) {
|
|
221
|
-
if (opt.detected) {
|
|
222
|
-
rows.push({ kind: "item", option: opt, itemIndex: itemIndex++ });
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
if (undetected.length > 0) {
|
|
227
|
-
rows.push({ kind: "blank" });
|
|
228
|
-
rows.push({
|
|
229
|
-
kind: "header",
|
|
230
|
-
title: `Not installed (${undetected.length})`,
|
|
231
|
-
hint: "install hooks ahead of time",
|
|
232
|
-
});
|
|
233
|
-
for (const opt of options) {
|
|
234
|
-
if (!opt.detected) {
|
|
235
|
-
rows.push({ kind: "item", option: opt, itemIndex: itemIndex++ });
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
return rows;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
let cursor = 0;
|
|
244
|
-
let lastLineCount = 0;
|
|
245
|
-
let cursorHidden = false;
|
|
246
|
-
|
|
247
|
-
function hideCursor(): void {
|
|
248
|
-
if (!cursorHidden) {
|
|
249
|
-
process.stdout.write("\x1B[?25l");
|
|
250
|
-
cursorHidden = true;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
function showCursor(): void {
|
|
254
|
-
if (cursorHidden) {
|
|
255
|
-
process.stdout.write("\x1B[?25h");
|
|
256
|
-
cursorHidden = false;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// Shared brand painter from tui.ts (NO_COLOR-gated like the rest of this file).
|
|
261
|
-
const { dim, bold, guide: teal, pink, pinkBold } = paint(!process.env.NO_COLOR);
|
|
262
|
-
|
|
263
|
-
const heading =
|
|
264
|
-
action === "uninstall" ? "Remove failproofai hooks" : "Install failproofai hooks";
|
|
265
|
-
|
|
266
|
-
function render(): void {
|
|
267
|
-
const cols = process.stdout.columns || 100;
|
|
268
|
-
hideCursor();
|
|
269
|
-
|
|
270
|
-
const g = dim(BAR);
|
|
271
|
-
const lines: string[] = [g, `${teal(STEP)} ${bold(heading)}`];
|
|
272
|
-
|
|
273
|
-
for (const row of buildDisplayRows()) {
|
|
274
|
-
if (row.kind === "blank") {
|
|
275
|
-
lines.push(g);
|
|
276
|
-
continue;
|
|
277
|
-
}
|
|
278
|
-
if (row.kind === "header") {
|
|
279
|
-
const hint = row.hint ? ` ${dim("· " + row.hint)}` : "";
|
|
280
|
-
lines.push(`${g} ${dim(row.title)}${hint}`);
|
|
281
|
-
continue;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
const opt = row.option;
|
|
285
|
-
const isActive = row.itemIndex === cursor;
|
|
286
|
-
const caret = isActive ? pink("❯") : " ";
|
|
287
|
-
const marker = opt.isAll ? teal("★") : opt.detected ? pink("●") : dim("○");
|
|
288
|
-
const label = isActive
|
|
289
|
-
? pinkBold(opt.label)
|
|
290
|
-
: opt.detected
|
|
291
|
-
? opt.label
|
|
292
|
-
: dim(opt.label);
|
|
293
|
-
lines.push(`${g} ${caret} ${marker} ${label}`);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
lines.push(g);
|
|
297
|
-
lines.push(`${g} ${dim("↑/↓ move · ↵ select · esc cancel")}`);
|
|
298
|
-
|
|
299
|
-
if (lastLineCount > 0) {
|
|
300
|
-
process.stdout.write(`\x1B[${lastLineCount}A\x1B[J`);
|
|
301
|
-
}
|
|
302
|
-
process.stdout.write(lines.map((l) => truncateLine(l, cols)).join("\n") + "\n");
|
|
303
|
-
lastLineCount = lines.length;
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
const itemCount = options.length;
|
|
307
|
-
|
|
308
|
-
return new Promise<IntegrationType[]>((resolve) => {
|
|
309
|
-
render();
|
|
310
|
-
readline.emitKeypressEvents(process.stdin);
|
|
311
|
-
const wasRaw = process.stdin.isRaw;
|
|
312
|
-
if (process.stdin.setRawMode) process.stdin.setRawMode(true);
|
|
313
|
-
process.stdin.resume();
|
|
314
|
-
|
|
315
|
-
function cleanup(): void {
|
|
316
|
-
showCursor();
|
|
317
|
-
process.stdin.removeListener("keypress", onKey);
|
|
318
|
-
if (process.stdin.setRawMode) process.stdin.setRawMode(wasRaw ?? false);
|
|
319
|
-
process.stdin.pause();
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
function onKey(_str: string | undefined, key: readline.Key): void {
|
|
323
|
-
if (!key) return;
|
|
324
|
-
if ((key.ctrl && (key.name === "c" || key.name === "d")) || key.name === "escape") {
|
|
325
|
-
cleanup();
|
|
326
|
-
process.stdout.write("\n");
|
|
327
|
-
process.exit(130); // SIGINT-equivalent
|
|
328
|
-
}
|
|
329
|
-
if (key.name === "up") {
|
|
330
|
-
cursor = cursor > 0 ? cursor - 1 : itemCount - 1;
|
|
331
|
-
render();
|
|
332
|
-
} else if (key.name === "down") {
|
|
333
|
-
cursor = cursor < itemCount - 1 ? cursor + 1 : 0;
|
|
334
|
-
render();
|
|
335
|
-
} else if (key.name === "return" || key.name === "space") {
|
|
336
|
-
cleanup();
|
|
337
|
-
process.stdout.write("\n");
|
|
338
|
-
resolve(options[cursor].value);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
process.stdin.on("keypress", onKey);
|
|
174
|
+
const { options } = buildCliMenuOptions(detected, action);
|
|
175
|
+
const kit = screenKit(optsFor(process.stdout));
|
|
176
|
+
process.stdout.write(`\n${kit.header(action === "uninstall" ? "Remove hooks" : "Install hooks")}\n\n`);
|
|
177
|
+
const choices: SelectChoice<IntegrationType[]>[] = options.map((option) => ({
|
|
178
|
+
label: option.label,
|
|
179
|
+
value: option.value,
|
|
180
|
+
section: option.detected ? "found on this machine" : "not installed, set up ahead of time",
|
|
181
|
+
}));
|
|
182
|
+
const picked = await selectOne<IntegrationType[]>({
|
|
183
|
+
message: "Choose agents",
|
|
184
|
+
meta: `${detected.length} found on this machine`,
|
|
185
|
+
choices,
|
|
186
|
+
spaceSelects: true,
|
|
343
187
|
});
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
* Show interactive searchable policy selector.
|
|
348
|
-
* @param preSelected — policy names to pre-check (e.g. from existing config).
|
|
349
|
-
* When omitted, uses each policy's defaultEnabled flag.
|
|
350
|
-
* @param options — prompt options (e.g. includeBeta)
|
|
351
|
-
*/
|
|
352
|
-
export async function promptPolicySelection(
|
|
353
|
-
preSelected?: string[],
|
|
354
|
-
options: PromptOptions = {},
|
|
355
|
-
): Promise<string[]> {
|
|
356
|
-
const { includeBeta = false } = options;
|
|
357
|
-
|
|
358
|
-
// If stdin is not a TTY (piped/CI), return defaults
|
|
359
|
-
if (!process.stdin.isTTY) {
|
|
360
|
-
const available = BUILTIN_POLICIES.filter((p) => includeBeta || !p.beta);
|
|
361
|
-
// Returned UNCHANGED, deliberately. This used to intersect with the builtin
|
|
362
|
-
// catalog, and manager.ts writes the result straight back — so a piped
|
|
363
|
-
// `policies --install` silently deleted every enabled name the catalog did
|
|
364
|
-
// not contain: a `failproofai/`-qualified name (a form the enforcement path
|
|
365
|
-
// explicitly accepts, `registerBuiltinPolicies` canonicalizes both), a beta
|
|
366
|
-
// policy enabled with `--beta`, and now any pack policy. The line that
|
|
367
|
-
// reports what was enabled prints only the survivors, so the loss was
|
|
368
|
-
// invisible. Carrying an unknown name costs nothing — registration looks it
|
|
369
|
-
// up in a Set and finds nothing — while dropping one destroys configuration.
|
|
370
|
-
if (preSelected) return [...preSelected];
|
|
371
|
-
return available.filter((p) => p.defaultEnabled).map((p) => p.name);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
const preSelectedSet = preSelected ? new Set(preSelected) : null;
|
|
375
|
-
|
|
376
|
-
const items: SelectItem[] = BUILTIN_POLICIES
|
|
377
|
-
.filter((p) => includeBeta || !p.beta)
|
|
378
|
-
.map((p) => ({
|
|
379
|
-
name: p.name,
|
|
380
|
-
description: p.description,
|
|
381
|
-
category: p.category,
|
|
382
|
-
selected: preSelectedSet ? preSelectedSet.has(p.name) : p.defaultEnabled,
|
|
383
|
-
beta: !!p.beta,
|
|
384
|
-
}));
|
|
385
|
-
|
|
386
|
-
// Everything the user has enabled that this picker cannot show a row for, for
|
|
387
|
-
// the same reason as the non-TTY branch above: the picker's universe is the
|
|
388
|
-
// builtin catalog, and resolving from it alone deletes anything else. Kept in
|
|
389
|
-
// their original order and appended to whatever the user picks.
|
|
390
|
-
const carried = preSelected
|
|
391
|
-
? preSelected.filter((name) => !items.some((i) => i.name === name))
|
|
392
|
-
: [];
|
|
393
|
-
|
|
394
|
-
const total = items.length;
|
|
395
|
-
const WINDOW_SIZE = 10;
|
|
396
|
-
|
|
397
|
-
// Shared brand painter from tui.ts, bound to role names so a reader never has
|
|
398
|
-
// to decode which hue a role happens to use today (glyphs imported above).
|
|
399
|
-
const useColor = !process.env.NO_COLOR;
|
|
400
|
-
const c = paint(useColor);
|
|
401
|
-
const { dim, bold } = c;
|
|
402
|
-
const stepMark = c.guide; // ◆ step marker + live selected-count
|
|
403
|
-
const activeName = c.pinkBold; // row under the cursor
|
|
404
|
-
const selectedMark = c.pink; // checked boxes / selected names
|
|
405
|
-
const betaTag = c.softPink; // "beta" pill
|
|
406
|
-
// Fixed name column so descriptions align into a clean, scannable second column.
|
|
407
|
-
const NAME_COL = Math.min(34, Math.max(10, ...items.map((i) => i.name.length)));
|
|
408
|
-
|
|
409
|
-
let cursor = 0;
|
|
410
|
-
let search = "";
|
|
411
|
-
let lastLineCount = 0;
|
|
412
|
-
let cursorHidden = false;
|
|
413
|
-
|
|
414
|
-
function hideCursor(): void {
|
|
415
|
-
if (!cursorHidden) {
|
|
416
|
-
process.stdout.write("\x1B[?25l");
|
|
417
|
-
cursorHidden = true;
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
function showCursor(): void {
|
|
422
|
-
if (cursorHidden) {
|
|
423
|
-
process.stdout.write("\x1B[?25h");
|
|
424
|
-
cursorHidden = false;
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
function getFiltered(): SelectItem[] {
|
|
429
|
-
if (!search) return items;
|
|
430
|
-
const q = search.toLowerCase();
|
|
431
|
-
return items.filter(
|
|
432
|
-
(i) => i.name.toLowerCase().includes(q) || i.description.toLowerCase().includes(q),
|
|
433
|
-
);
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// Build display rows: category header rows interspersed with item rows.
|
|
437
|
-
// Categories appear in the order they first appear in BUILTIN_POLICIES.
|
|
438
|
-
function buildDisplayRows(filtered: SelectItem[]): DisplayRow[] {
|
|
439
|
-
// Single pass: compute category order, enabled counts, and total counts together.
|
|
440
|
-
const categoryOrder: string[] = [];
|
|
441
|
-
const categoryEnabledCount = new Map<string, number>();
|
|
442
|
-
const categoryTotalCount = new Map<string, number>();
|
|
443
|
-
for (const p of items) {
|
|
444
|
-
if (!categoryEnabledCount.has(p.category)) {
|
|
445
|
-
categoryOrder.push(p.category);
|
|
446
|
-
categoryEnabledCount.set(p.category, 0);
|
|
447
|
-
categoryTotalCount.set(p.category, 0);
|
|
448
|
-
}
|
|
449
|
-
categoryTotalCount.set(p.category, categoryTotalCount.get(p.category)! + 1);
|
|
450
|
-
if (p.selected) categoryEnabledCount.set(p.category, categoryEnabledCount.get(p.category)! + 1);
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
const filteredByCategory = new Map<string, SelectItem[]>();
|
|
454
|
-
for (const item of filtered) {
|
|
455
|
-
const bucket = filteredByCategory.get(item.category) ?? [];
|
|
456
|
-
bucket.push(item);
|
|
457
|
-
filteredByCategory.set(item.category, bucket);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
const rows: DisplayRow[] = [];
|
|
461
|
-
let idx = 0;
|
|
462
|
-
for (const cat of categoryOrder) {
|
|
463
|
-
const catFiltered = filteredByCategory.get(cat);
|
|
464
|
-
if (!catFiltered || catFiltered.length === 0) continue;
|
|
465
|
-
rows.push({ kind: "header", category: cat, enabledCount: categoryEnabledCount.get(cat)!, totalCount: categoryTotalCount.get(cat)! });
|
|
466
|
-
for (const item of catFiltered) {
|
|
467
|
-
rows.push({ kind: "item", item, filteredIndex: idx++ });
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
return rows;
|
|
188
|
+
if (picked === null) {
|
|
189
|
+
process.stdout.write("\n");
|
|
190
|
+
process.exit(130); // SIGINT-equivalent
|
|
471
191
|
}
|
|
472
|
-
|
|
473
|
-
function render(): void {
|
|
474
|
-
const cols = process.stdout.columns || 100;
|
|
475
|
-
hideCursor();
|
|
476
|
-
|
|
477
|
-
const filtered = getFiltered();
|
|
478
|
-
const shown = filtered.length;
|
|
479
|
-
if (shown > 0 && cursor >= shown) cursor = shown - 1;
|
|
480
|
-
const selectedCount = items.filter((i) => i.selected).length;
|
|
481
|
-
|
|
482
|
-
const g = dim(BAR);
|
|
483
|
-
const lines: string[] = [];
|
|
484
|
-
|
|
485
|
-
// header
|
|
486
|
-
lines.push(g);
|
|
487
|
-
lines.push(
|
|
488
|
-
`${stepMark(STEP)} ${bold("Choose the policies to enable")} ${dim("·")} ` +
|
|
489
|
-
`${stepMark(String(selectedCount))} ${dim("selected")}`,
|
|
490
|
-
);
|
|
491
|
-
|
|
492
|
-
// search
|
|
493
|
-
const blockCursor = useColor ? "\x1B[7m \x1B[0m" : "_";
|
|
494
|
-
const countLabel = search ? dim(`${shown}/${total} shown`) : dim(`${total} policies`);
|
|
495
|
-
lines.push(`${g} ${dim("filter ›")} ${search}${blockCursor} ${countLabel}`);
|
|
496
|
-
lines.push(g);
|
|
497
|
-
|
|
498
|
-
if (shown === 0) {
|
|
499
|
-
lines.push(`${g} ${dim(`no policies match “${search}”`)}`);
|
|
500
|
-
for (let i = 0; i < WINDOW_SIZE + 1; i++) lines.push(g);
|
|
501
|
-
} else {
|
|
502
|
-
const displayRows = buildDisplayRows(filtered);
|
|
503
|
-
|
|
504
|
-
let cursorDisplayRow = 0;
|
|
505
|
-
for (let i = 0; i < displayRows.length; i++) {
|
|
506
|
-
const row = displayRows[i];
|
|
507
|
-
if (row.kind === "item" && row.filteredIndex === cursor) {
|
|
508
|
-
cursorDisplayRow = i;
|
|
509
|
-
break;
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
let windowStart = cursorDisplayRow - Math.floor(WINDOW_SIZE / 2);
|
|
513
|
-
windowStart = Math.max(0, windowStart);
|
|
514
|
-
windowStart = Math.min(windowStart, Math.max(0, displayRows.length - WINDOW_SIZE));
|
|
515
|
-
const windowEnd = Math.min(displayRows.length, windowStart + WINDOW_SIZE);
|
|
516
|
-
|
|
517
|
-
const aboveItems = displayRows.slice(0, windowStart).filter((r) => r.kind === "item").length;
|
|
518
|
-
lines.push(aboveItems > 0 ? `${g} ${dim(`↑ ${aboveItems} more`)}` : g);
|
|
519
|
-
|
|
520
|
-
for (let i = windowStart; i < windowEnd; i++) {
|
|
521
|
-
const row = displayRows[i];
|
|
522
|
-
if (row.kind === "header") {
|
|
523
|
-
lines.push(`${g} ${dim(row.category.toUpperCase())} ${dim(`${row.enabledCount}/${row.totalCount}`)}`);
|
|
524
|
-
} else {
|
|
525
|
-
const item = row.item;
|
|
526
|
-
const active = row.filteredIndex === cursor;
|
|
527
|
-
const box = item.selected ? selectedMark(BOX_ON) : dim(BOX_OFF);
|
|
528
|
-
const rawName = item.name.padEnd(NAME_COL);
|
|
529
|
-
const name = active ? activeName(rawName) : item.selected ? rawName : dim(rawName);
|
|
530
|
-
const beta = item.beta ? ` ${betaTag("beta")}` : "";
|
|
531
|
-
const descWidth = Math.max(8, cols - NAME_COL - 8 - (item.beta ? 5 : 0));
|
|
532
|
-
const desc = dim(truncateLine(item.description, descWidth));
|
|
533
|
-
lines.push(`${g} ${box} ${name}${beta} ${desc}`);
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
for (let i = windowEnd - windowStart; i < WINDOW_SIZE; i++) lines.push(g);
|
|
537
|
-
|
|
538
|
-
const belowItems = displayRows.slice(windowEnd).filter((r) => r.kind === "item").length;
|
|
539
|
-
lines.push(belowItems > 0 ? `${g} ${dim(`↓ ${belowItems} more`)}` : g);
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
// footer
|
|
543
|
-
lines.push(g);
|
|
544
|
-
lines.push(`${g} ${dim("↑/↓ move · space select · ctrl+a all · ↵ save · type to filter · esc clear")}`);
|
|
545
|
-
|
|
546
|
-
if (lastLineCount > 0) process.stdout.write(`\x1B[${lastLineCount}A\x1B[J`);
|
|
547
|
-
process.stdout.write(lines.map((l) => truncateLine(l, cols)).join("\n") + "\n");
|
|
548
|
-
lastLineCount = lines.length;
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
return new Promise<string[]>((resolve) => {
|
|
552
|
-
render();
|
|
553
|
-
|
|
554
|
-
process.stdin.setRawMode(true);
|
|
555
|
-
process.stdin.resume();
|
|
556
|
-
// Use a single data→keypress pipeline with no readline.Interface.
|
|
557
|
-
// readline.createInterface would register its own competing data listener
|
|
558
|
-
// and its close() call would unexpectedly pause stdin, breaking arrow keys.
|
|
559
|
-
readline.emitKeypressEvents(process.stdin);
|
|
560
|
-
|
|
561
|
-
function keypressHandler(_str: string | undefined, key: readline.Key): void {
|
|
562
|
-
if (!key) return;
|
|
563
|
-
|
|
564
|
-
if (key.ctrl && key.name === "c") {
|
|
565
|
-
cleanup();
|
|
566
|
-
process.exit(0);
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
const filtered = getFiltered();
|
|
570
|
-
|
|
571
|
-
if (key.name === "up") {
|
|
572
|
-
if (filtered.length > 0) {
|
|
573
|
-
cursor = cursor > 0 ? cursor - 1 : filtered.length - 1;
|
|
574
|
-
}
|
|
575
|
-
render();
|
|
576
|
-
} else if (key.name === "down") {
|
|
577
|
-
if (filtered.length > 0) {
|
|
578
|
-
cursor = cursor < filtered.length - 1 ? cursor + 1 : 0;
|
|
579
|
-
}
|
|
580
|
-
render();
|
|
581
|
-
} else if (key.name === "space") {
|
|
582
|
-
const item = filtered[cursor];
|
|
583
|
-
if (item) item.selected = !item.selected;
|
|
584
|
-
render();
|
|
585
|
-
} else if (key.name === "return" || (key.ctrl && key.name === "s")) {
|
|
586
|
-
// Save — collapse the picker to a one-line summary, then resolve.
|
|
587
|
-
cleanup();
|
|
588
|
-
const selected = items.filter((i) => i.selected).map((i) => i.name);
|
|
589
|
-
if (lastLineCount > 0) process.stdout.write(`\x1B[${lastLineCount}A\x1B[J`);
|
|
590
|
-
// Carried entries are NAMED, not counted. "3 kept" reads as fine right
|
|
591
|
-
// up until someone needs to know which three.
|
|
592
|
-
const summary = carried.length > 0
|
|
593
|
-
? `${selected.length} selected, kept ${carried.join(", ")}`
|
|
594
|
-
: `${selected.length} selected`;
|
|
595
|
-
process.stdout.write(
|
|
596
|
-
`${dim(BAR)}\n${dim(DONE)} Policies\n${dim(BAR)} ${dim(summary)}\n`,
|
|
597
|
-
);
|
|
598
|
-
resolve([...selected, ...carried]);
|
|
599
|
-
} else if (key.name === "escape") {
|
|
600
|
-
// Clear search filter
|
|
601
|
-
search = "";
|
|
602
|
-
cursor = 0;
|
|
603
|
-
render();
|
|
604
|
-
} else if (key.ctrl && key.name === "a") {
|
|
605
|
-
// Toggle all visible items
|
|
606
|
-
const allSelected = filtered.length > 0 && filtered.every((i) => i.selected);
|
|
607
|
-
for (const item of filtered) item.selected = !allSelected;
|
|
608
|
-
render();
|
|
609
|
-
} else if (key.name === "backspace" || key.name === "delete") {
|
|
610
|
-
if (search.length > 0) {
|
|
611
|
-
search = search.slice(0, -1);
|
|
612
|
-
cursor = 0;
|
|
613
|
-
render();
|
|
614
|
-
}
|
|
615
|
-
} else if (_str && _str.length === 1 && !key.ctrl && !key.meta) {
|
|
616
|
-
// All printable characters (including 'a', 's') go to search
|
|
617
|
-
search += _str;
|
|
618
|
-
cursor = 0;
|
|
619
|
-
render();
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
function cleanup(): void {
|
|
624
|
-
showCursor();
|
|
625
|
-
process.stdin.removeListener("keypress", keypressHandler);
|
|
626
|
-
process.stdin.setRawMode(false);
|
|
627
|
-
process.stdin.pause();
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
process.stdin.on("keypress", keypressHandler);
|
|
631
|
-
});
|
|
192
|
+
return picked;
|
|
632
193
|
}
|
|
@@ -85,7 +85,7 @@ export class UnreadableAgentConfigError extends Error {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
function readJsonFile(path: string): Record<string, unknown> {
|
|
88
|
+
export function readJsonFile(path: string): Record<string, unknown> {
|
|
89
89
|
if (!existsSync(path)) return {};
|
|
90
90
|
let raw: string;
|
|
91
91
|
try {
|