failproofai 1.0.4-beta.1 → 1.0.4-beta.4
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 +5 -5
- package/.next/standalone/.next/prerender-manifest.json +5 -5
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +2 -2
- 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/build-manifest.json +2 -2
- 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 +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/invite/route_client-reference-manifest.js +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/run/route_client-reference-manifest.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/audit/status/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route_client-reference-manifest.js +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/login-verify/route_client-reference-manifest.js +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/logout/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route_client-reference-manifest.js +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/api/download/[project]/[session]/route_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/audit/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +37 -4
- package/.next/standalone/.next/server/app/audit/page.js +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 +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/build-manifest.json +2 -2
- 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/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +14 -14
- package/.next/standalone/.next/server/app/policies/page.js +1 -1
- 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 +2 -2
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js +3 -3
- 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 +2 -2
- 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 +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/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +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/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__1zndo1i._.js → [externals]__0v1hz15._.js} +1 -1
- package/.next/standalone/.next/server/chunks/{[externals]__0_gzk8q._.js → [externals]__1nb206a._.js} +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0--lkk6._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__08dchfu._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cuho4x._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0o07qi9._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q0qzx1._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1adacul._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1le9jqc._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1p-qi2t._.js +5 -0
- package/.next/standalone/.next/server/chunks/_09dz7xv._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0otft92._.js +3 -0
- 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 +14 -21
- package/.next/standalone/.next/server/chunks/_1vslkoe._.js +1 -1
- package/.next/standalone/.next/server/chunks/lib_factory-projects_ts_1eo_bk-._.js +1 -1
- 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_01r25oi._.js +2 -2
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +2 -2
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_0iu54mz._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_hooks_fp-home_ts_09kv0bn._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00-s7h8._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__013jr2b._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01wy8d-._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02npjtd._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0da85px._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ftmoxc._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0wvusu0._.js → [root-of-the-server]__0n_lxhg._.js} +2 -2
- 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]__16gamwq._.js → [root-of-the-server]__0yl9wb5._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__190won8._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ctpynv._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1p2otjt._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1qapotl._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1sc84bb._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1zl_r0t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0-yi74u._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_08x1r5t._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_1byck5v._.js → _0guxnh-._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_0l2hi_d._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0oq1dh6._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_0wso5d3._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1_ozgif._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1es2j7i._.js +61 -168
- package/.next/standalone/.next/server/chunks/ssr/{_08f0jd2._.js → _1if9ixi._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1u8-lu2._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_next-internal_server_app_policies_page_actions_1sp2-yo.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -69
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_rerun-button_tsx_0blihgw._.js +3 -0
- 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/chunks/ssr/node_modules_13n822a._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_builtin-policies_ts_09j2ndl._.js +1 -1
- 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 +5 -5
- 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 +54 -21
- package/.next/standalone/.next/static/chunks/04o5zfl7p5lhx.js +1 -0
- package/.next/standalone/.next/static/chunks/{29-iqnp9v_axt.css → 0jpd8dv2vk930.css} +1 -1
- package/.next/standalone/.next/static/chunks/{1po3lirgk2riw.js → 0po8n4tyotjf2.js} +1 -1
- package/.next/standalone/.next/static/chunks/0qmsunv04x4na.css +2 -0
- package/.next/standalone/.next/static/chunks/0qx7gav1c2_vu.js +1 -0
- package/.next/standalone/.next/static/chunks/17tfki9x5rd_7.js +1 -0
- package/.next/standalone/.next/static/chunks/{1_bxotmf9qngs.js → 1i-i0pxg9q_8y.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1_2jsatfuthrw.js → 2bxr2_2h4kaqq.js} +1 -1
- package/.next/standalone/.next/static/chunks/{01hvwwrhvbzyh.js → 2zafgs90r_leq.js} +1 -1
- package/.next/standalone/.next/static/chunks/{00gv0v91mycm-.js → 323cyb3a2s06y.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0qn9khv0oo9ex.js → 364cqbpeg1y5i.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2bvwsyu6x__ia.js → 38dqur43qthrl.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3_--3ibia6ba1.js → 3l36d73kj18zw.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2k9f4tyv04809.css → 3uyhmm01g64k4.css} +1 -0
- package/.next/standalone/.next/static/chunks/{2bnf_4pgyk1rq.js → 40lpt2o2b283e.js} +1 -1
- package/.next/standalone/.next/static/chunks/42gwu2bsz4ske.js +6 -0
- package/.next/standalone/.next/static/chunks/{turbopack-18qf4jodtft6b.js → turbopack-3s3c-u_u_l0u9.js} +1 -1
- package/.next/standalone/.opencode/plugins/failproofai.mjs +51 -27
- package/.next/standalone/app/actions/get-leaks.ts +109 -0
- package/.next/standalone/app/audit/_components/audit-dashboard.tsx +140 -34
- package/.next/standalone/app/audit/_components/audit-poster.tsx +29 -10
- package/.next/standalone/app/audit/_components/come-back-better-section.tsx +6 -1
- package/.next/standalone/app/audit/_components/empty-state.tsx +4 -1
- package/.next/standalone/app/audit/_components/how-to-improve-section.tsx +19 -5
- package/.next/standalone/app/audit/_components/leak-section.tsx +192 -0
- package/.next/standalone/app/audit/_components/share-templates.ts +110 -44
- package/.next/standalone/app/audit/audit-styles.css +132 -1
- package/.next/standalone/app/project/[name]/page.tsx +4 -24
- package/.next/standalone/fp-cloud-cli/CHANGELOG.md +26 -3
- package/.next/standalone/fp-cloud-cli/fp_cli/_click_compat.py +31 -8
- package/.next/standalone/fp-cloud-cli/fp_cli/permissions.py +1 -0
- package/.next/standalone/fp-cloud-cli/pyproject.toml +9 -2
- package/.next/standalone/fp-cloud-cli/tests/test_click_compat.py +54 -0
- package/.next/standalone/fp-cloud-cli/uv.lock +9 -12
- package/.next/standalone/lib/auth/api-server-client.ts +28 -0
- package/.next/standalone/lib/claude-sessions.ts +101 -27
- package/.next/standalone/lib/cli-registry.ts +1 -33
- package/.next/standalone/lib/download-session.ts +0 -37
- package/.next/standalone/lib/projects.ts +3 -27
- package/.next/standalone/lib/sqlite-reader.ts +78 -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/next-server/pages-turbo.runtime.prod.js +1 -1
- package/.next/standalone/node_modules/next/dist/experimental/testmode/fetch.js +10 -2
- package/.next/standalone/node_modules/next/dist/lib/patch-incorrect-lockfile.js +3 -3
- package/.next/standalone/node_modules/next/dist/lib/typescript/runTypeScriptCli.js +2 -2
- package/.next/standalone/node_modules/next/dist/lib/verify-typescript-setup.js +3 -1
- 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 +2 -2
- package/.next/standalone/node_modules/next/dist/server/lib/app-info-log.js +1 -1
- package/.next/standalone/node_modules/next/dist/server/lib/start-server.js +1 -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 +11 -11
- package/.next/standalone/package.json +15 -14
- package/.next/standalone/sdk/python/CHANGELOG.md +155 -0
- package/.next/standalone/sdk/python/README.md +8 -0
- package/.next/standalone/sdk/python/examples/evaluator_worker.py +121 -0
- package/.next/standalone/sdk/python/failproofai_sdk/_version.py +1 -1
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/__init__.py +101 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/__main__.py +49 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/_sandbox_runner.py +63 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/authoring.py +404 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/client.py +299 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/protocol.py +754 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/runtime.py +936 -0
- package/.next/standalone/sdk/python/failproofai_sdk/evaluator/source.py +684 -0
- package/.next/standalone/sdk/python/tests/fixtures/evaluator_v2/README.md +28 -0
- package/.next/standalone/sdk/python/tests/fixtures/evaluator_v2/contract.json +252 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_authoring.py +124 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_client.py +253 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_example.py +35 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_http_e2e.py +636 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_main.py +47 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_protocol.py +246 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_review_fixes.py +164 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_runtime.py +1103 -0
- package/.next/standalone/sdk/python/tests/test_evaluator_source.py +430 -0
- package/.next/standalone/sdk/python/tests/test_zero_dependencies.py +17 -0
- package/.next/standalone/sdk/python/uv.lock +18 -18
- package/.next/standalone/server.js +1 -1
- package/README.md +19 -95
- package/bin/failproofai.mjs +8 -25
- package/dist/cli.mjs +20091 -25864
- package/dist/worker.mjs +4881 -6361
- package/lib/auth/api-server-client.ts +28 -0
- package/lib/claude-sessions.ts +101 -27
- package/lib/cli-registry.ts +1 -33
- package/lib/download-session.ts +0 -37
- package/lib/projects.ts +3 -27
- package/lib/sqlite-reader.ts +78 -1
- package/package.json +15 -14
- package/pi-extension/index.ts +61 -8
- package/scripts/changelog-open.py +115 -0
- package/src/audit/cache.ts +6 -0
- package/src/audit/cli-adapters/claude.ts +13 -0
- package/src/audit/cli-adapters/index.ts +0 -24
- package/src/audit/cli-login.ts +4 -1
- package/src/audit/cli.ts +164 -5
- package/src/audit/desktop-notify.ts +420 -0
- package/src/audit/harm-report.ts +101 -0
- package/src/audit/index.ts +284 -15
- package/src/audit/leak-fingerprint.ts +200 -0
- package/src/audit/leak-notice.ts +259 -0
- package/src/audit/leak-record.ts +232 -0
- package/src/audit/leak-scan.ts +268 -0
- package/src/audit/leak-store.ts +265 -0
- package/src/audit/macos-notifier.ts +310 -0
- package/src/audit/redact-example.ts +322 -15
- package/src/audit/report-harm.ts +12 -1
- package/src/audit/report.ts +6 -3
- package/src/audit/schedule-cli.ts +37 -0
- package/src/audit/scoring.ts +49 -0
- package/src/audit/types.ts +47 -0
- package/src/hooks/builtin-policies.ts +71 -8
- package/src/hooks/configure-wizard.ts +20 -0
- package/src/hooks/enforcement-capability.ts +0 -97
- package/src/hooks/fp-config.ts +71 -11
- package/src/hooks/fp-home.ts +27 -0
- package/src/hooks/handler.ts +84 -62
- package/src/hooks/harness-cli.ts +1 -3
- package/src/hooks/integrations.ts +63 -769
- package/src/hooks/normalize-cli-payload.ts +0 -126
- package/src/hooks/notice.ts +191 -0
- package/src/hooks/policy-evaluator.ts +6 -297
- package/src/hooks/resolve-transcript-path.ts +0 -10
- package/src/hooks/tool-name-canonicalize.ts +0 -64
- package/src/hooks/types.ts +2 -533
- package/src/hooks/uninstall-cli.ts +15 -0
- package/.next/standalone/.grok/hooks/failproofai.json +0 -172
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__07hor7h._.js +0 -5
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0elsuli._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0gnj_qa._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ljuzm_._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0w23bpg._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0x5c7sh._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0yik9_w._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1jg6s9m._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1s6qci9._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1xfm05z._.js +0 -3
- package/.next/standalone/.next/server/chunks/_0tdy_6l._.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_grok-projects_ts_1i2epl_._.js +0 -3
- package/.next/standalone/.next/server/chunks/lib_qwen-projects_ts_0wu_a8e._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0_4gcz8._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0d--wmy._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qqrlf_._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s11fx1._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1bbk-si._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1c3ybxr._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1izi7zn._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__21bj7uw._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_00z5uuq._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1ylae7o._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_1zopuov._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/lib_cline-projects_ts_13_hbdd._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/lib_grok-projects_ts_0rc-d0o._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/lib_ori-projects_ts_04tofqo._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/lib_qwen-projects_ts_0w3i9o7._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/node_modules_html-to-image_es_index_1ao30b1.js +0 -3
- package/.next/standalone/.next/static/chunks/0hzmxwb2pvk5p.js +0 -6
- package/.next/standalone/.next/static/chunks/0j884dwnwtyrt.js +0 -1
- package/.next/standalone/.next/static/chunks/0mr9dg3bnloa1.js +0 -1
- package/.next/standalone/.next/static/chunks/0u64yey446k4f.css +0 -1
- package/.next/standalone/.next/static/chunks/3gf1jg-5m-u1t.css +0 -2
- package/.next/standalone/.next/static/chunks/3qfoeqhy5l10x.js +0 -1
- package/.next/standalone/.next/static/chunks/3ws7eljkq25wg.js +0 -69
- package/.next/standalone/.next/static/chunks/3zkg2s2vzxc3d.js +0 -1
- package/.next/standalone/.qwen/settings.json +0 -251
- package/.next/standalone/assets/logos/cline.png +0 -0
- package/.next/standalone/assets/logos/grok-dark.svg +0 -1
- package/.next/standalone/assets/logos/grok-light.svg +0 -1
- package/.next/standalone/assets/logos/ori-dark.svg +0 -1
- package/.next/standalone/assets/logos/ori-light.svg +0 -1
- package/.next/standalone/assets/logos/qwen.svg +0 -1
- package/.next/standalone/lib/cline-projects.ts +0 -155
- package/.next/standalone/lib/cline-sessions.ts +0 -268
- package/.next/standalone/lib/grok-projects.ts +0 -123
- package/.next/standalone/lib/grok-sessions.ts +0 -355
- package/.next/standalone/lib/ori-projects.ts +0 -141
- package/.next/standalone/lib/ori-sessions.ts +0 -221
- package/.next/standalone/lib/qwen-projects.ts +0 -106
- package/.next/standalone/lib/qwen-sessions.ts +0 -313
- package/lib/cline-projects.ts +0 -155
- package/lib/cline-sessions.ts +0 -268
- package/lib/grok-projects.ts +0 -123
- package/lib/grok-sessions.ts +0 -355
- package/lib/ori-projects.ts +0 -141
- package/lib/ori-sessions.ts +0 -221
- package/lib/qwen-projects.ts +0 -106
- package/lib/qwen-sessions.ts +0 -313
- package/src/audit/cli-adapters/cline.ts +0 -50
- package/src/audit/cli-adapters/grok.ts +0 -70
- package/src/audit/cli-adapters/ori.ts +0 -55
- package/src/audit/cli-adapters/qwen.ts +0 -71
- package/src/hooks/batch-expand.ts +0 -380
- package/src/hooks/batch-fanout.ts +0 -142
- package/src/hooks/risk-patterns.ts +0 -26
- /package/.next/standalone/.next/static/{qJx3mbOQV-5ElrcRb4Sp7 → P6icI2V2PvVuePJrqjHCr}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{qJx3mbOQV-5ElrcRb4Sp7 → P6icI2V2PvVuePJrqjHCr}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{qJx3mbOQV-5ElrcRb4Sp7 → P6icI2V2PvVuePJrqjHCr}/_ssgManifest.js +0 -0
|
@@ -12,10 +12,6 @@ import { getCachedFactorySessionsByEncodedName } from "@/lib/factory-projects";
|
|
|
12
12
|
import { getCachedDevinSessionsByEncodedName } from "@/lib/devin-projects";
|
|
13
13
|
import { getCachedAntigravitySessionsByEncodedName } from "@/lib/antigravity-projects";
|
|
14
14
|
import { getCachedGooseSessionsByEncodedName } from "@/lib/goose-projects";
|
|
15
|
-
import { getCachedGrokSessionsByEncodedName } from "@/lib/grok-projects";
|
|
16
|
-
import { getCachedQwenSessionsByEncodedName } from "@/lib/qwen-projects";
|
|
17
|
-
import { getCachedOriSessionsByEncodedName } from "@/lib/ori-projects";
|
|
18
|
-
import { getCachedClineSessionsByEncodedName } from "@/lib/cline-projects";
|
|
19
15
|
import { logWarn } from "@/lib/logger";
|
|
20
16
|
import { decodeFolderName, projectDisplayName, isSyntheticProjectPath } from "@/lib/paths";
|
|
21
17
|
import { notFound } from "next/navigation";
|
|
@@ -54,7 +50,7 @@ export default async function ProjectPage({ params }: ProjectPageProps) {
|
|
|
54
50
|
}
|
|
55
51
|
// Note: decodeFolderName is lossy when cwds contain `-` (every `-` becomes `/`),
|
|
56
52
|
// so each external CLI looks up sessions by re-encoding cwd and matching the slug.
|
|
57
|
-
const [codex, copilot, cursor, opencode, pi, hermes, openclaw, factory, devin, antigravity, goose
|
|
53
|
+
const [codex, copilot, cursor, opencode, pi, hermes, openclaw, factory, devin, antigravity, goose] = await Promise.all([
|
|
58
54
|
getCachedCodexSessionsByEncodedName(name),
|
|
59
55
|
getCachedCopilotSessionsByEncodedName(name),
|
|
60
56
|
getCachedCursorSessionsByEncodedName(name),
|
|
@@ -66,10 +62,6 @@ export default async function ProjectPage({ params }: ProjectPageProps) {
|
|
|
66
62
|
getCachedDevinSessionsByEncodedName(name),
|
|
67
63
|
getCachedAntigravitySessionsByEncodedName(name),
|
|
68
64
|
getCachedGooseSessionsByEncodedName(name),
|
|
69
|
-
getCachedGrokSessionsByEncodedName(name),
|
|
70
|
-
getCachedQwenSessionsByEncodedName(name),
|
|
71
|
-
getCachedOriSessionsByEncodedName(name),
|
|
72
|
-
getCachedClineSessionsByEncodedName(name),
|
|
73
65
|
]);
|
|
74
66
|
const codexSessions = codex.sessions;
|
|
75
67
|
const copilotSessions = copilot.sessions;
|
|
@@ -82,10 +74,6 @@ export default async function ProjectPage({ params }: ProjectPageProps) {
|
|
|
82
74
|
const devinSessions = devin.sessions;
|
|
83
75
|
const antigravitySessions = antigravity.sessions;
|
|
84
76
|
const gooseSessions = goose.sessions;
|
|
85
|
-
const grokSessions = grok.sessions;
|
|
86
|
-
const qwenSessions = qwen.sessions;
|
|
87
|
-
const oriSessions = ori.sessions;
|
|
88
|
-
const clineSessions = cline.sessions;
|
|
89
77
|
|
|
90
78
|
if (
|
|
91
79
|
!claudeExists &&
|
|
@@ -99,11 +87,7 @@ export default async function ProjectPage({ params }: ProjectPageProps) {
|
|
|
99
87
|
factorySessions.length === 0 &&
|
|
100
88
|
devinSessions.length === 0 &&
|
|
101
89
|
antigravitySessions.length === 0 &&
|
|
102
|
-
gooseSessions.length === 0
|
|
103
|
-
grokSessions.length === 0 &&
|
|
104
|
-
qwenSessions.length === 0 &&
|
|
105
|
-
oriSessions.length === 0 &&
|
|
106
|
-
clineSessions.length === 0
|
|
90
|
+
gooseSessions.length === 0
|
|
107
91
|
) {
|
|
108
92
|
notFound();
|
|
109
93
|
}
|
|
@@ -112,7 +96,7 @@ export default async function ProjectPage({ params }: ProjectPageProps) {
|
|
|
112
96
|
// `decodeFolderName(name)` is ambiguous for cwds containing `-` (every `-`
|
|
113
97
|
// becomes `/`). Each external transcript records the literal cwd, so they
|
|
114
98
|
// round-trip correctly. First non-null wins (Codex → Copilot → Cursor → OpenCode → Pi).
|
|
115
|
-
const canonicalRoot = codex.cwd ?? copilot.cwd ?? cursor.cwd ?? opencode.cwd ?? pi.cwd ?? hermes.cwd ?? openclaw.cwd ?? factory.cwd ?? devin.cwd ?? antigravity.cwd ?? goose.cwd ??
|
|
99
|
+
const canonicalRoot = codex.cwd ?? copilot.cwd ?? cursor.cwd ?? opencode.cwd ?? pi.cwd ?? hermes.cwd ?? openclaw.cwd ?? factory.cwd ?? devin.cwd ?? antigravity.cwd ?? goose.cwd ?? decodedName;
|
|
116
100
|
|
|
117
101
|
// Project header metadata
|
|
118
102
|
let lastModified: Date | null = null;
|
|
@@ -126,7 +110,7 @@ export default async function ProjectPage({ params }: ProjectPageProps) {
|
|
|
126
110
|
logWarn(`Failed to get stats for project ${decodedName}:`, error);
|
|
127
111
|
}
|
|
128
112
|
}
|
|
129
|
-
const newestExternal = [codexSessions[0], copilotSessions[0], cursorSessions[0], opencodeSessions[0], piSessions[0], hermesSessions[0], openclawSessions[0], factorySessions[0], devinSessions[0], antigravitySessions[0], gooseSessions[0]
|
|
113
|
+
const newestExternal = [codexSessions[0], copilotSessions[0], cursorSessions[0], opencodeSessions[0], piSessions[0], hermesSessions[0], openclawSessions[0], factorySessions[0], devinSessions[0], antigravitySessions[0], gooseSessions[0]]
|
|
130
114
|
.filter((s): s is SessionFile => !!s)
|
|
131
115
|
.map((s) => s.lastModified)
|
|
132
116
|
.reduce<Date | null>((acc, d) => (!acc || d.getTime() > acc.getTime() ? d : acc), null);
|
|
@@ -148,10 +132,6 @@ export default async function ProjectPage({ params }: ProjectPageProps) {
|
|
|
148
132
|
...devinSessions,
|
|
149
133
|
...antigravitySessions,
|
|
150
134
|
...gooseSessions,
|
|
151
|
-
...grokSessions,
|
|
152
|
-
...qwenSessions,
|
|
153
|
-
...oriSessions,
|
|
154
|
-
...clineSessions,
|
|
155
135
|
].sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());
|
|
156
136
|
|
|
157
137
|
// Path line: prefer the Claude storage dir if present (matches existing UX);
|
|
@@ -3,9 +3,32 @@
|
|
|
3
3
|
## 0.0.1b2 — 2026-08-25
|
|
4
4
|
|
|
5
5
|
Open for the next release. `0.0.1b1` published on 2026-08-24 and the `bump` job
|
|
6
|
-
moved the version here automatically
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
moved the version here automatically. Add entries as changes merge — this section
|
|
7
|
+
becomes the GitHub Release body when it ships.
|
|
8
|
+
|
|
9
|
+
### Fixes
|
|
10
|
+
|
|
11
|
+
- **Typed errors keep their exit codes under typer 0.27.2.** That release moved
|
|
12
|
+
`Abort` out of its vendored `typer._click.exceptions`, and `_click_compat`
|
|
13
|
+
imported all six of its symbols under a single
|
|
14
|
+
`try: … except ImportError: from click import …`. One missing name was enough
|
|
15
|
+
to send the whole block to the fallback, binding `ClickException`,
|
|
16
|
+
`UsageError`, `BadParameter`, `Command` and `Parameter` to the pip `click`
|
|
17
|
+
distribution — which is *not* the Click Typer runs, and Typer catches only its
|
|
18
|
+
own. So every typed error escaped its handler: `fp alerts show ghost` exited
|
|
19
|
+
**1 with an empty stderr** instead of **6** with `no alert named "ghost"`, and
|
|
20
|
+
likewise for exits 2, 3, 4 and 5. Nothing warned; the CLI imported and every
|
|
21
|
+
happy path passed. The Click is now decided **once**, on whether `typer._click`
|
|
22
|
+
exists at all, and every symbol imported from that decision, so a future move
|
|
23
|
+
fails at import — a CLI that refuses to start — instead of silently flattening
|
|
24
|
+
the exit-code contract. `Abort` is resolved from `typer.Abort`, which is by
|
|
25
|
+
construction the class `typer.prompt` raises and typer's own `_main` catches on
|
|
26
|
+
every version in range. Suite verified green against typer 0.25.1, 0.27.0,
|
|
27
|
+
0.27.1 and 0.27.2 (#771)
|
|
28
|
+
|
|
29
|
+
### Dependencies
|
|
30
|
+
|
|
31
|
+
- typer 0.27.1 → 0.27.2, click 8.4.2 → 8.5.0, posthog 7.42.0 → 7.44.2 (#771)
|
|
9
32
|
|
|
10
33
|
## 0.0.1b1 — 2026-08-24
|
|
11
34
|
|
|
@@ -11,9 +11,10 @@ compiles, and every happy path still passes:
|
|
|
11
11
|
should print ``✗ …`` and exit 5 exits **1 with an empty stderr**, and the
|
|
12
12
|
``rich_format_error`` hook in ``app.py`` (reached only *after* that catch) never
|
|
13
13
|
runs. Same for the ``UsageError``/``BadParameter`` we raise by hand.
|
|
14
|
-
* ``Abort`` — ``typer.prompt`` raises
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
* ``Abort`` — ``typer.prompt`` raises the ``Abort`` **typer** exports on closed stdin
|
|
15
|
+
(0.27.2 moved that class out of the vendored Click entirely), so a pip-Click
|
|
16
|
+
``except click.Abort`` stops matching and the clean "no TTY, pass a slug" usage error
|
|
17
|
+
becomes a bare abort.
|
|
17
18
|
* Options — Typer 0.26+ has no ``Option`` class in its vendored Click *at all*: every
|
|
18
19
|
option in a Typer-built tree is a ``typer.core.TyperOption``, subclassing
|
|
19
20
|
``Parameter`` directly. ``isinstance(param, click.Option)`` is then quietly always
|
|
@@ -27,14 +28,36 @@ again, and that our errors are still the class Typer catches.
|
|
|
27
28
|
|
|
28
29
|
from __future__ import annotations
|
|
29
30
|
|
|
31
|
+
# `Abort` is resolved from `typer` itself rather than from either Click, because it is
|
|
32
|
+
# the one symbol here that is not stably a Click class: typer 0.27.2 moved it out of the
|
|
33
|
+
# vendored `typer._click.exceptions` into a plain `typer.exceptions.Abort(RuntimeError)`.
|
|
34
|
+
# `typer.Abort` tracks that move — it is `click.Abort` before 0.26, the vendored class
|
|
35
|
+
# through 0.27.1, the RuntimeError from 0.27.2 — and it is by construction the class
|
|
36
|
+
# `typer.prompt` raises and typer's own `_main` catches, which is the only property
|
|
37
|
+
# `select.py`'s `except click.Abort` needs.
|
|
38
|
+
from typer import Abort as Abort
|
|
39
|
+
|
|
40
|
+
# Pick the Click ONCE, on whether typer vendors one at all, then import every symbol
|
|
41
|
+
# from that choice. Deciding per symbol — a single `try` around the whole vendored
|
|
42
|
+
# import block, falling back to pip `click` on any ImportError — is what shipped
|
|
43
|
+
# through 0.27.1 and it failed exactly as silently as this module exists to prevent:
|
|
44
|
+
# 0.27.2 removing `typer._click.exceptions.Abort` made that one missing name rebind ALL
|
|
45
|
+
# SIX symbols to pip Click, so every typed error escaped Typer's handler as exit 1 with
|
|
46
|
+
# an empty stderr. A name that goes missing inside the chosen Click must raise here, at
|
|
47
|
+
# import, where it is a CLI that refuses to start rather than one that silently stops
|
|
48
|
+
# reporting errors.
|
|
30
49
|
try:
|
|
31
|
-
# typer >= 0.26
|
|
32
|
-
# Click in play, so binding to it here would reintroduce the whole class of bug.
|
|
33
|
-
from typer._click import ClickException, Command, Parameter
|
|
34
|
-
from typer._click.exceptions import Abort, BadParameter, UsageError
|
|
50
|
+
import typer._click as _typer_click # typer >= 0.26 vendors its own Click
|
|
35
51
|
except ImportError: # typer < 0.26 drives the pip `click` distribution directly
|
|
52
|
+
_typer_click = None # type: ignore[assignment]
|
|
53
|
+
|
|
54
|
+
if _typer_click is not None:
|
|
55
|
+
# pip `click` may well still be installed — it is simply not the Click in play, so
|
|
56
|
+
# binding to it here would reintroduce the whole class of bug.
|
|
57
|
+
from typer._click import ClickException, Command, Parameter
|
|
58
|
+
from typer._click.exceptions import BadParameter, UsageError
|
|
59
|
+
else:
|
|
36
60
|
from click import ( # type: ignore[assignment]
|
|
37
|
-
Abort,
|
|
38
61
|
BadParameter,
|
|
39
62
|
ClickException,
|
|
40
63
|
Command,
|
|
@@ -31,7 +31,14 @@ dependencies = [
|
|
|
31
31
|
# through that — which is what makes both sides of the split work. Import Click from
|
|
32
32
|
# there and nowhere else; `tests/test_click_compat.py` enforces it, because every way
|
|
33
33
|
# this breaks is silent (typed errors collapse to exit 1 with an empty stderr, and the
|
|
34
|
-
# telemetry flag catalog empties). Suite verified against 0.25.1
|
|
34
|
+
# telemetry flag catalog empties). Suite verified against 0.25.1, 0.27.0, 0.27.1 and
|
|
35
|
+
# 0.27.2.
|
|
36
|
+
#
|
|
37
|
+
# The split keeps moving INSIDE the vendored tree, so the shim resolves each symbol
|
|
38
|
+
# separately: 0.27.2 moved `Abort` out of `typer._click.exceptions` into
|
|
39
|
+
# `typer.exceptions`, and the one all-or-nothing `try/except ImportError` that used to
|
|
40
|
+
# wrap the vendored import sent every OTHER symbol to pip Click over that single
|
|
41
|
+
# missing name — 105 tests red, every typed error at exit 1.
|
|
35
42
|
#
|
|
36
43
|
# The floor is 0.13, not 0.12, because 0.12 cannot BUILD this app: the global
|
|
37
44
|
# `--insecure/--secure` option in `app.py` is an `Optional[bool]` with a
|
|
@@ -39,7 +46,7 @@ dependencies = [
|
|
|
39
46
|
# rejects with `TypeError: Secondary flag is not valid for non-boolean flag`.
|
|
40
47
|
# That fires while the command tree is constructed, before any parsing, so
|
|
41
48
|
# `fp --version`, `fp --help` and every subcommand die identically — an
|
|
42
|
-
# installed CLI that cannot run one command. `uv.lock` pins 0.27.
|
|
49
|
+
# installed CLI that cannot run one command. `uv.lock` pins 0.27.2, so
|
|
43
50
|
# neither CI nor the publish smoke test ever installed the broken part of the
|
|
44
51
|
# range. Measured across 0.12.0/0.12.3/0.12.5 (all fail) and 0.13.0 upward
|
|
45
52
|
# (all pass).
|
|
@@ -11,6 +11,7 @@ from __future__ import annotations
|
|
|
11
11
|
import ast
|
|
12
12
|
import pathlib
|
|
13
13
|
|
|
14
|
+
import pytest
|
|
14
15
|
import typer
|
|
15
16
|
from typer.testing import CliRunner
|
|
16
17
|
|
|
@@ -95,6 +96,59 @@ def test_error_exit_codes_are_distinct_per_class():
|
|
|
95
96
|
assert issubclass(KeyModeUnsupportedError, _click_compat.ClickException)
|
|
96
97
|
|
|
97
98
|
|
|
99
|
+
def test_every_symbol_comes_from_the_click_typer_runs():
|
|
100
|
+
"""No symbol may quietly come from pip Click while Typer is running its own.
|
|
101
|
+
|
|
102
|
+
This is the alarm for a *partial* miss. `_click_compat` used to wrap the whole
|
|
103
|
+
vendored import in one `try: … except ImportError: from click import …`, so a single
|
|
104
|
+
name disappearing from `typer._click` rebound **all six** symbols to pip Click — and
|
|
105
|
+
that is not hypothetical: typer 0.27.2 moved `Abort` out of
|
|
106
|
+
`typer._click.exceptions`, and the fallback fired, and 105 tests went red at once
|
|
107
|
+
with typed errors collapsing to exit 1. Assert the provenance of each symbol
|
|
108
|
+
separately, so the next move is one failure naming one symbol.
|
|
109
|
+
"""
|
|
110
|
+
typer_click = pytest.importorskip(
|
|
111
|
+
"typer._click", reason="typer < 0.26 has no vendored Click; pip click IS the right one"
|
|
112
|
+
)
|
|
113
|
+
wrong = {
|
|
114
|
+
name: obj.__module__
|
|
115
|
+
for name in ("ClickException", "UsageError", "BadParameter", "Command", "Parameter")
|
|
116
|
+
if not (obj := getattr(_click_compat, name)).__module__.startswith(typer_click.__name__)
|
|
117
|
+
}
|
|
118
|
+
assert not wrong, f"these came from pip Click, not the Click Typer runs: {wrong}"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def test_abort_is_the_one_typer_raises():
|
|
122
|
+
"""`Abort` is the exception NOT to pin to a Click — pin it to Typer.
|
|
123
|
+
|
|
124
|
+
It is `click.Abort` before typer 0.26, the vendored class through 0.27.1, and a
|
|
125
|
+
plain `typer.exceptions.Abort(RuntimeError)` from 0.27.2 on. `typer.Abort` is the
|
|
126
|
+
class `typer.prompt` raises and typer's own `_main` catches on every one of those,
|
|
127
|
+
which is the only thing `select.py`'s `except click.Abort` needs to be true.
|
|
128
|
+
"""
|
|
129
|
+
assert _click_compat.Abort is typer.Abort
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def test_hand_raised_usage_errors_reach_typers_handler():
|
|
133
|
+
"""The other half of the contract: `UsageError`/`BadParameter` we raise ourselves.
|
|
134
|
+
|
|
135
|
+
`test_typed_errors_reach_typers_handler` covers the `ClickException` subclasses in
|
|
136
|
+
`errors.py`; these two are raised directly through the shim (`raise
|
|
137
|
+
click.UsageError(...)`) from a dozen call sites, and bound to the wrong Click they
|
|
138
|
+
escape uncaught the same way — exit 1, empty stderr, instead of a clean exit 2.
|
|
139
|
+
"""
|
|
140
|
+
for exc_class in (_click_compat.UsageError, _click_compat.BadParameter):
|
|
141
|
+
app = typer.Typer()
|
|
142
|
+
|
|
143
|
+
@app.command()
|
|
144
|
+
def boom() -> None:
|
|
145
|
+
raise exc_class("bad input")
|
|
146
|
+
|
|
147
|
+
result = CliRunner().invoke(app, [])
|
|
148
|
+
assert result.exit_code == 2, (exc_class, result.output)
|
|
149
|
+
assert "bad input" in result.output
|
|
150
|
+
|
|
151
|
+
|
|
98
152
|
def test_is_option_recognises_typer_options():
|
|
99
153
|
"""Typer's vendored Click has no `Option` class, so `isinstance` cannot answer this.
|
|
100
154
|
|
|
@@ -208,14 +208,11 @@ wheels = [
|
|
|
208
208
|
|
|
209
209
|
[[package]]
|
|
210
210
|
name = "click"
|
|
211
|
-
version = "8.
|
|
211
|
+
version = "8.5.0"
|
|
212
212
|
source = { registry = "https://pypi.org/simple" }
|
|
213
|
-
|
|
214
|
-
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
215
|
-
]
|
|
216
|
-
sdist = { url = "https://files.pythonhosted.org/packages/76/d4/81420972a676e8ffea40450d8c8c92943e7218a78fe9b64359836cc9876b/click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6", size = 338000, upload-time = "2026-06-24T17:45:15.148Z" }
|
|
213
|
+
sdist = { url = "https://files.pythonhosted.org/packages/c7/0e/7fa0ef50764b67090eca4114772a2abf8b6148198475e54c660b97caeee6/click-8.5.0.tar.gz", hash = "sha256:ba0d2089de75ea0310e2dde03160e6ca10009947fb95a182f9b54021bb272e34", size = 382235, upload-time = "2026-08-26T13:33:14.56Z" }
|
|
217
214
|
wheels = [
|
|
218
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
215
|
+
{ url = "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl", hash = "sha256:255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360", size = 125251, upload-time = "2026-08-26T13:33:12.928Z" },
|
|
219
216
|
]
|
|
220
217
|
|
|
221
218
|
[[package]]
|
|
@@ -375,7 +372,7 @@ wheels = [
|
|
|
375
372
|
|
|
376
373
|
[[package]]
|
|
377
374
|
name = "posthog"
|
|
378
|
-
version = "7.
|
|
375
|
+
version = "7.47.0"
|
|
379
376
|
source = { registry = "https://pypi.org/simple" }
|
|
380
377
|
dependencies = [
|
|
381
378
|
{ name = "backoff" },
|
|
@@ -383,9 +380,9 @@ dependencies = [
|
|
|
383
380
|
{ name = "requests" },
|
|
384
381
|
{ name = "typing-extensions" },
|
|
385
382
|
]
|
|
386
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
383
|
+
sdist = { url = "https://files.pythonhosted.org/packages/e4/1b/61eccf2257847def7d01ccae29f9680156cb1cd2b4f00d3e9afaabe236fa/posthog-7.47.0.tar.gz", hash = "sha256:62767af8b0808cb103da37aa3974e728467fed9527e4f201f23e718740debd30", size = 508993, upload-time = "2026-09-04T16:52:31.715Z" }
|
|
387
384
|
wheels = [
|
|
388
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
385
|
+
{ url = "https://files.pythonhosted.org/packages/a6/28/16b9b229b9c2380211249377df5bbb4c33cb8b224b7b27ecd46c89bcedac/posthog-7.47.0-py3-none-any.whl", hash = "sha256:c87daf7830eb5ef779d0ff1ec25b5de6d316926d6bbbcde74b80e055172a0ddc", size = 601509, upload-time = "2026-09-04T16:52:29.935Z" },
|
|
389
386
|
]
|
|
390
387
|
|
|
391
388
|
[[package]]
|
|
@@ -520,7 +517,7 @@ wheels = [
|
|
|
520
517
|
|
|
521
518
|
[[package]]
|
|
522
519
|
name = "typer"
|
|
523
|
-
version = "0.27.
|
|
520
|
+
version = "0.27.2"
|
|
524
521
|
source = { registry = "https://pypi.org/simple" }
|
|
525
522
|
dependencies = [
|
|
526
523
|
{ name = "annotated-doc" },
|
|
@@ -528,9 +525,9 @@ dependencies = [
|
|
|
528
525
|
{ name = "rich" },
|
|
529
526
|
{ name = "shellingham" },
|
|
530
527
|
]
|
|
531
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
528
|
+
sdist = { url = "https://files.pythonhosted.org/packages/16/f7/57713ba479fd405eb76de31404b2c744c289e336b2d999511ebf51e496f7/typer-0.27.2.tar.gz", hash = "sha256:269b7eb9d3c202ca84b4bc9618cb04ebb43d3d4d1e567e4c768607232c05f945", size = 204045, upload-time = "2026-08-28T10:26:55.046Z" }
|
|
532
529
|
wheels = [
|
|
533
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
530
|
+
{ url = "https://files.pythonhosted.org/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl", hash = "sha256:b3a5fc4342d5fc8fda8fc3010b1cf117e9249aab7fae800c2eff62fd3842d97d", size = 123130, upload-time = "2026-08-28T10:26:53.752Z" },
|
|
534
531
|
]
|
|
535
532
|
|
|
536
533
|
[[package]]
|
|
@@ -253,6 +253,34 @@ export interface AuditReportBody {
|
|
|
253
253
|
last_seen?: string;
|
|
254
254
|
examples: string[];
|
|
255
255
|
}[];
|
|
256
|
+
/**
|
|
257
|
+
* Credentials this machine found in its own transcripts.
|
|
258
|
+
*
|
|
259
|
+
* Optional on the wire, so a CLI newer than the api-server sends a field the
|
|
260
|
+
* server ignores rather than failing the whole digest — the harmful counts
|
|
261
|
+
* are the older half of the contract and must keep arriving either way.
|
|
262
|
+
*
|
|
263
|
+
* Every field here is a mask, a label, a length or a location. There is no
|
|
264
|
+
* shape of this object that carries a secret, because the record it is built
|
|
265
|
+
* from never stores one: `recordLeaks` fingerprints at detection time and
|
|
266
|
+
* keeps only the masked rendering.
|
|
267
|
+
*/
|
|
268
|
+
leaks?: {
|
|
269
|
+
id: string;
|
|
270
|
+
display: string;
|
|
271
|
+
label: string;
|
|
272
|
+
length: number;
|
|
273
|
+
attributed: boolean;
|
|
274
|
+
name: string | null;
|
|
275
|
+
confidence: string;
|
|
276
|
+
first_seen: string;
|
|
277
|
+
last_seen: string;
|
|
278
|
+
occurrences: number;
|
|
279
|
+
cli: string;
|
|
280
|
+
project: string;
|
|
281
|
+
mechanism: string;
|
|
282
|
+
direction: "input" | "result";
|
|
283
|
+
}[];
|
|
256
284
|
}
|
|
257
285
|
|
|
258
286
|
export interface AuditReportResult {
|
|
@@ -4,8 +4,14 @@
|
|
|
4
4
|
* Claude stores transcripts at:
|
|
5
5
|
* <CLAUDE_PROJECTS_PATH>/<encoded-cwd>/<sessionId>.jsonl
|
|
6
6
|
*
|
|
7
|
-
* Subagent transcripts (when a session spawned subagents) live alongside
|
|
7
|
+
* Subagent transcripts (when a session spawned subagents) live alongside, in two
|
|
8
|
+
* shapes — a direct child, and one nested per workflow run:
|
|
8
9
|
* <CLAUDE_PROJECTS_PATH>/<encoded-cwd>/<sessionId>/subagents/<agentId>.jsonl
|
|
10
|
+
* <CLAUDE_PROJECTS_PATH>/<encoded-cwd>/<sessionId>/subagents/workflows/<runId>/<agentId>.jsonl
|
|
11
|
+
*
|
|
12
|
+
* Everything below `subagents/` is walked to a bounded depth rather than one
|
|
13
|
+
* level, because the second shape arrived after this module was written and the
|
|
14
|
+
* miss was most of the corpus. See `collectSubagentTranscripts`.
|
|
9
15
|
*
|
|
10
16
|
* The parser for these files lives in `lib/log-entries.ts` (`parseLogContent`,
|
|
11
17
|
* `parseSessionLog`). This module exposes discovery only — the audit pipeline
|
|
@@ -70,6 +76,99 @@ export function listClaudeProjects(): ClaudeProjectFolder[] {
|
|
|
70
76
|
/** Lists every JSONL transcript under one Claude project folder, including
|
|
71
77
|
* subagent transcripts under `<sessionId>/subagents/`. Returns [] on missing
|
|
72
78
|
* or unreadable paths. */
|
|
79
|
+
/**
|
|
80
|
+
* Depth of nesting allowed below `subagents/`.
|
|
81
|
+
*
|
|
82
|
+
* The two shapes that exist today need 0 and 2 (`<agent>.jsonl` and
|
|
83
|
+
* `workflows/<runId>/<agent>.jsonl`). The cap is here so an unexpected layout —
|
|
84
|
+
* or a symlink cycle a future Claude build introduces — costs a bounded walk
|
|
85
|
+
* rather than an audit that never returns, and it is deliberately loose enough
|
|
86
|
+
* that a third shape lands inside it without another release.
|
|
87
|
+
*/
|
|
88
|
+
const MAX_SUBAGENT_DEPTH = 5;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Collect every `.jsonl` beneath a session's `subagents/` directory.
|
|
92
|
+
*
|
|
93
|
+
* This used to read only the DIRECT children of `subagents/`, which was correct
|
|
94
|
+
* for the layout Claude shipped when it was written and silently wrong the day
|
|
95
|
+
* workflow runs started nesting their agents one level further down. On a
|
|
96
|
+
* machine that uses them the miss is most of the corpus: 1,839 transcripts on
|
|
97
|
+
* disk, 1,741 under `subagents/`, and 1,679 of those inside
|
|
98
|
+
* `subagents/workflows/<runId>/` — so the audit was walking 160 files, 8.7% of
|
|
99
|
+
* the evidence, and reporting the result as though it had read everything.
|
|
100
|
+
*
|
|
101
|
+
* ## Session ids come from the relative path, not the basename
|
|
102
|
+
*
|
|
103
|
+
* Every workflow run writes a `journal.jsonl` beside its agents, so basenames
|
|
104
|
+
* are NOT unique below this directory — 1,741 files share 1,613 distinct names
|
|
105
|
+
* on the machine this was found on. A basename id would collide those 128 files
|
|
106
|
+
* onto ~one row each, and `sessionId` is what the cache, the per-session
|
|
107
|
+
* detector state and the example attribution are keyed by, so the collision
|
|
108
|
+
* would silently merge unrelated sessions rather than fail.
|
|
109
|
+
*
|
|
110
|
+
* Nor is the path below `subagents/` unique on its own. A workflow run id is
|
|
111
|
+
* reused when its session is resumed, so `wf_3d609e92-a38/journal.jsonl` exists
|
|
112
|
+
* under two different parent sessions in the same project — found by asserting
|
|
113
|
+
* uniqueness over the real corpus, not by reasoning about it.
|
|
114
|
+
*
|
|
115
|
+
* The id is therefore the PARENT SESSION id followed by the path relative to
|
|
116
|
+
* `subagents/`, minus the extension, joined with `__`:
|
|
117
|
+
* `<parentUuid>__workflows__wf_123__agent-abc`. That is a filesystem path
|
|
118
|
+
* within the project, so it is unique by construction rather than by argument,
|
|
119
|
+
* and it names the session the subagent belongs to. `__` is safe as the joiner
|
|
120
|
+
* because no id Claude generates contains one — verified against 1,741 real
|
|
121
|
+
* files, zero hits. Top-level session ids are untouched.
|
|
122
|
+
*
|
|
123
|
+
* Symlinks are not followed. Nothing in the layout uses them, and following one
|
|
124
|
+
* is how a directory walk turns into an infinite loop.
|
|
125
|
+
*/
|
|
126
|
+
function collectSubagentTranscripts(
|
|
127
|
+
dir: string,
|
|
128
|
+
relPrefix: string,
|
|
129
|
+
project: ClaudeProjectFolder,
|
|
130
|
+
out: ClaudeTranscriptFile[],
|
|
131
|
+
depth: number,
|
|
132
|
+
): void {
|
|
133
|
+
if (depth > MAX_SUBAGENT_DEPTH) return;
|
|
134
|
+
let entries: import("node:fs").Dirent[];
|
|
135
|
+
try {
|
|
136
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
137
|
+
} catch {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
for (const entry of entries) {
|
|
141
|
+
if (entry.isSymbolicLink()) continue;
|
|
142
|
+
if (entry.isDirectory()) {
|
|
143
|
+
collectSubagentTranscripts(
|
|
144
|
+
join(dir, entry.name),
|
|
145
|
+
relPrefix ? `${relPrefix}__${entry.name}` : entry.name,
|
|
146
|
+
project,
|
|
147
|
+
out,
|
|
148
|
+
depth + 1,
|
|
149
|
+
);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
|
|
153
|
+
const stem = entry.name.slice(0, -".jsonl".length);
|
|
154
|
+
const transcriptPath = join(dir, entry.name);
|
|
155
|
+
try {
|
|
156
|
+
const s = statSync(transcriptPath);
|
|
157
|
+
out.push({
|
|
158
|
+
projectName: project.name,
|
|
159
|
+
cwd: project.cwd,
|
|
160
|
+
sessionId: relPrefix ? `${relPrefix}__${stem}` : stem,
|
|
161
|
+
transcriptPath,
|
|
162
|
+
mtimeMs: s.mtimeMs,
|
|
163
|
+
sizeBytes: s.size,
|
|
164
|
+
isSubagent: true,
|
|
165
|
+
});
|
|
166
|
+
} catch {
|
|
167
|
+
// unreadable — skip
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
73
172
|
export function listClaudeTranscripts(project: ClaudeProjectFolder): ClaudeTranscriptFile[] {
|
|
74
173
|
const out: ClaudeTranscriptFile[] = [];
|
|
75
174
|
let entries: import("node:fs").Dirent[];
|
|
@@ -99,34 +198,9 @@ export function listClaudeTranscripts(project: ClaudeProjectFolder): ClaudeTrans
|
|
|
99
198
|
// unreadable — skip
|
|
100
199
|
}
|
|
101
200
|
} else if (entry.isDirectory() && UUID_RE.test(entry.name)) {
|
|
102
|
-
// Subagent transcripts at <sessionId>/subagents/<agentId>.jsonl
|
|
103
201
|
const subDir = join(project.path, entry.name, "subagents");
|
|
104
202
|
if (!existsSync(subDir)) continue;
|
|
105
|
-
|
|
106
|
-
try {
|
|
107
|
-
subEntries = readdirSync(subDir, { withFileTypes: true });
|
|
108
|
-
} catch {
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
for (const sub of subEntries) {
|
|
112
|
-
if (!sub.isFile() || !sub.name.endsWith(".jsonl")) continue;
|
|
113
|
-
const agentId = sub.name.slice(0, -".jsonl".length);
|
|
114
|
-
const transcriptPath = join(subDir, sub.name);
|
|
115
|
-
try {
|
|
116
|
-
const s = statSync(transcriptPath);
|
|
117
|
-
out.push({
|
|
118
|
-
projectName: project.name,
|
|
119
|
-
cwd: project.cwd,
|
|
120
|
-
sessionId: agentId,
|
|
121
|
-
transcriptPath,
|
|
122
|
-
mtimeMs: s.mtimeMs,
|
|
123
|
-
sizeBytes: s.size,
|
|
124
|
-
isSubagent: true,
|
|
125
|
-
});
|
|
126
|
-
} catch {
|
|
127
|
-
// unreadable — skip
|
|
128
|
-
}
|
|
129
|
-
}
|
|
203
|
+
collectSubagentTranscripts(subDir, entry.name, project, out, 0);
|
|
130
204
|
}
|
|
131
205
|
}
|
|
132
206
|
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
import type { IntegrationType } from "@/src/hooks/types";
|
|
28
28
|
|
|
29
29
|
/** Canonical CLI ids the registry knows about. Mirrors `INTEGRATION_TYPES`. */
|
|
30
|
-
export const KNOWN_CLI_IDS = ["claude", "codex", "copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"
|
|
30
|
+
export const KNOWN_CLI_IDS = ["claude", "codex", "copilot", "cursor", "opencode", "pi", "hermes", "openclaw", "factory", "devin", "antigravity", "goose"] as const satisfies readonly IntegrationType[];
|
|
31
31
|
export type CliId = (typeof KNOWN_CLI_IDS)[number];
|
|
32
32
|
|
|
33
33
|
/** Per-CLI metadata consumed by the dashboard. */
|
|
@@ -99,38 +99,6 @@ const CLI_ENTRIES: Record<CliId, CliEntry> = {
|
|
|
99
99
|
label: "Goose",
|
|
100
100
|
badgeClasses: "bg-lime-500/10 text-lime-400 border-lime-500/20",
|
|
101
101
|
},
|
|
102
|
-
grok: {
|
|
103
|
-
id: "grok",
|
|
104
|
-
label: "grok CLI",
|
|
105
|
-
// Neutral zinc, matching the design system's `--color-default`. Deliberately
|
|
106
|
-
// NOT a status hue: green/amber/red carry health meaning in this dashboard
|
|
107
|
-
// and must never be spent on identity. Neutral also happens to suit xAI's
|
|
108
|
-
// monochrome brand, and it is maximally far from qwen's magenta — the two
|
|
109
|
-
// were previously indistinguishable.
|
|
110
|
-
badgeClasses: "bg-zinc-500/10 text-zinc-200 border-zinc-500/20",
|
|
111
|
-
},
|
|
112
|
-
qwen: {
|
|
113
|
-
id: "qwen",
|
|
114
|
-
label: "Qwen Code",
|
|
115
|
-
// Magenta — the opposite pole from grok's neutral, and outside the
|
|
116
|
-
// status set (success/amber/orange/error) so it reads as identity.
|
|
117
|
-
badgeClasses: "bg-fuchsia-500/10 text-fuchsia-400 border-fuchsia-500/20",
|
|
118
|
-
},
|
|
119
|
-
ori: {
|
|
120
|
-
id: "ori",
|
|
121
|
-
label: "Ori",
|
|
122
|
-
// Sky — the badge set must be UNIQUE per CLI (a test asserts it), and
|
|
123
|
-
// violet/teal were already taken. Still outside the status set
|
|
124
|
-
// (success/amber/orange/error) so it reads as identity, not state.
|
|
125
|
-
badgeClasses: "bg-sky-500/10 text-sky-400 border-sky-500/20",
|
|
126
|
-
},
|
|
127
|
-
cline: {
|
|
128
|
-
id: "cline",
|
|
129
|
-
label: "Cline",
|
|
130
|
-
// Stone — the remaining neutral that is not zinc (grok's) and not a status
|
|
131
|
-
// colour.
|
|
132
|
-
badgeClasses: "bg-stone-500/10 text-stone-300 border-stone-500/20",
|
|
133
|
-
},
|
|
134
102
|
};
|
|
135
103
|
|
|
136
104
|
export function getCliEntry(id: string): CliEntry | undefined {
|
|
@@ -125,21 +125,6 @@ export async function resolveDownloadSource(
|
|
|
125
125
|
return path ? { kind: "file", path } : null;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
if (cli === "grok") {
|
|
129
|
-
// grok writes a real chat_history.jsonl per session directory — stream it
|
|
130
|
-
// verbatim (no synthesis, like Factory).
|
|
131
|
-
const { findGrokTranscript } = await import("./grok-sessions");
|
|
132
|
-
const path = findGrokTranscript(sessionId);
|
|
133
|
-
return path ? { kind: "file", path } : null;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (cli === "qwen") {
|
|
137
|
-
// qwen writes a real JSONL transcript per session — stream it verbatim.
|
|
138
|
-
const { findQwenTranscript } = await import("./qwen-sessions");
|
|
139
|
-
const path = findQwenTranscript(sessionId);
|
|
140
|
-
return path ? { kind: "file", path } : null;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
128
|
if (cli === "devin") {
|
|
144
129
|
// Devin keeps sessions in SQLite (~/.local/share/devin/cli/sessions.db).
|
|
145
130
|
// Synthesize a JSONL export of the session's raw chat_message rows.
|
|
@@ -167,28 +152,6 @@ export async function resolveDownloadSource(
|
|
|
167
152
|
return { kind: "synthesized", body, contentType: "application/x-ndjson", extension: "jsonl" };
|
|
168
153
|
}
|
|
169
154
|
|
|
170
|
-
if (cli === "ori") {
|
|
171
|
-
// Ori keeps the whole conversation in one SQLite column
|
|
172
|
-
// (ori_agent_loop_history.prompt). Synthesize a JSONL export from the
|
|
173
|
-
// parsed entries — there is no per-session file to stream.
|
|
174
|
-
const { getOriSessionLog } = await import("./ori-sessions");
|
|
175
|
-
const result = await getOriSessionLog(sessionId);
|
|
176
|
-
if (!result) return null;
|
|
177
|
-
const body = result.entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
178
|
-
return { kind: "synthesized", body, contentType: "application/x-ndjson", extension: "jsonl" };
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (cli === "cline") {
|
|
182
|
-
// Cline stores a real per-session messages file, but it is a single JSON
|
|
183
|
-
// document rather than JSONL, so stream the parsed entries as JSONL for
|
|
184
|
-
// consistency with every other synthesized export.
|
|
185
|
-
const { getClineSessionLog } = await import("./cline-sessions");
|
|
186
|
-
const result = await getClineSessionLog(sessionId);
|
|
187
|
-
if (!result) return null;
|
|
188
|
-
const body = result.entries.map((e) => JSON.stringify(e)).join("\n") + "\n";
|
|
189
|
-
return { kind: "synthesized", body, contentType: "application/x-ndjson", extension: "jsonl" };
|
|
190
|
-
}
|
|
191
|
-
|
|
192
155
|
// Exhaustive — but TypeScript can't always see CliId is exhausted across the
|
|
193
156
|
// if-chain above, so guard with a runtime fallback.
|
|
194
157
|
const _exhaustive: never = cli;
|