failproofai 0.0.13 → 0.0.14-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.codex/hooks.json +6 -6
- package/.next/standalone/.cursor/hooks.json +6 -6
- package/.next/standalone/.factory/hooks.json +112 -0
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +5 -5
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/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 +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/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/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +3 -3
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js +2 -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 +2 -2
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/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 +8 -8
- 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 -2
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/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 +5 -3
- 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/chunks/[root-of-the-server]__0--lkk6._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0-219ec._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__04_h-a5._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06cuf1y._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__08w4wmd._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0g6bbuw._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jllheg._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0jnjf2t._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q-v9z2._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q0qzx1._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0q2nbsl._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0rv7m0k._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__16le-kd._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__17g9wh7._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1d9qen3._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1ffkmds._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1fwl2mz._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1legmza._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1mrihkj._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1myjm-d._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qb590j._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1qxztj-._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1shcqgr._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1xuedea._.js +3 -0
- package/.next/standalone/.next/server/chunks/{_1z062h5._.js → _1vslkoe._.js} +2 -2
- package/.next/standalone/.next/server/chunks/lib_factory-projects_ts_1eo_bk-._.js +3 -0
- package/.next/standalone/.next/server/chunks/lib_openclaw-projects_ts_0gc-p24._.js +3 -0
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +24 -12
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__00cz9as._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__015_i4t._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__030k0c6._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__03lv-pe._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__042d3cd._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__05r_17v._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09q1168._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__108slqn._.js → [root-of-the-server]__0brjczq._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e2l3c1._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hci7t3._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hdsupo._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0p84xee._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qeuy9c._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0s89hoe._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__07iom4f._.js → [root-of-the-server]__0wp9w6i._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ynf7tx._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__170799-._.js +12 -9
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17ai7sy._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1d8omgc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1nq7ivq._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1tkjqka._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_05whahf._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0_9_ytf._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0ul5rf_._.js → _1_ozgif._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_1p0-leb._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_087bt9w._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_1fvisnp._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_209u41o._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/lib_0xkhw_v._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/lib_antigravity-projects_ts_0_6zf11._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/lib_devin-projects_ts_0a64qdy._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/lib_factory-projects_ts_1uyaahq._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/lib_goose-projects_ts_0zkscri._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/lib_openclaw-projects_ts_0qxq3bp._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_13p7zob.js → node_modules_html-to-image_es_index_12rjfea.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1ezd2jf._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_1tnuifj._.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 +10 -10
- package/.next/standalone/.next/static/chunks/{13f1kmjea-0md.js → 02jcotghcxrbu.js} +1 -1
- package/.next/standalone/.next/static/chunks/{30ysv-_8jj052.js → 0d5lypu1zs21r.js} +1 -1
- package/.next/standalone/.next/static/chunks/0emg30_6svycu.js +1 -0
- package/.next/standalone/.next/static/chunks/0o9wpnze1ey8y.js +6 -0
- package/.next/standalone/.next/static/chunks/{05apzuand0c22.js → 1359o5785rmve.js} +2 -2
- package/.next/standalone/.next/static/chunks/20tuctw38jbgw.js +1 -0
- package/.next/standalone/.next/static/chunks/{0vc0eak148vo6.js → 2ldhnaweu9ew3.js} +1 -1
- package/.next/standalone/.next/static/chunks/{23c7v2svx90dp.js → 2vav_x0_336ds.js} +1 -1
- package/.next/standalone/.next/static/chunks/3-ogr79xqbw0h.js +1 -0
- package/.next/standalone/.next/static/chunks/36j05kb2x323i.css +2 -0
- package/.next/standalone/.next/static/chunks/3cg7x0joi2b98.js +1 -0
- package/.next/standalone/.next/static/chunks/{36wdtkgdf0zrd.js → 3k87p-tijud-4.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2cejn75gug3j8.js → 3kmaqcp7rldad.js} +1 -1
- package/.next/standalone/.next/static/chunks/{turbopack-0vavqo2d-tlt3.js → turbopack-10hj8t5pf33tu.js} +1 -1
- package/.next/standalone/.opencode/plugins/failproofai.mjs +30 -11
- package/.next/standalone/app/api/audit/run/route.ts +2 -0
- package/.next/standalone/app/audit/_components/empty-state.tsx +1 -1
- package/.next/standalone/app/components/global-error-listeners.tsx +27 -0
- package/.next/standalone/app/globals.css +25 -1
- package/.next/standalone/app/policies/hooks-client.tsx +2 -4
- package/.next/standalone/app/project/[name]/page.tsx +30 -10
- package/.next/standalone/app/project/[name]/session/[sessionId]/page.tsx +71 -21
- package/.next/standalone/assets/logos/antigravity.svg +1 -0
- package/.next/standalone/assets/logos/devin.svg +1 -0
- package/.next/standalone/assets/logos/factory-dark.png +0 -0
- package/.next/standalone/assets/logos/factory-light.png +0 -0
- package/.next/standalone/assets/logos/goose-dark.svg +1 -0
- package/.next/standalone/assets/logos/goose-light.svg +1 -0
- package/.next/standalone/assets/logos/openclaw.svg +22 -0
- package/.next/standalone/ci/cli-integration/Dockerfile +47 -0
- package/.next/standalone/ci/cli-integration/README.md +69 -0
- package/.next/standalone/ci/cli-integration/canary-policies.mjs +45 -0
- package/.next/standalone/ci/cli-integration/capture-tokens.sh +48 -0
- package/.next/standalone/ci/cli-integration/inject-tokens.sh +44 -0
- package/.next/standalone/ci/cli-integration/install-clis.sh +91 -0
- package/.next/standalone/ci/cli-integration/probe-cli.sh +208 -0
- package/.next/standalone/ci/cli-integration/report.js +74 -0
- package/.next/standalone/ci/cli-integration/run.sh +107 -0
- package/.next/standalone/components/navbar.tsx +5 -11
- package/.next/standalone/components/reach-developers.tsx +2 -2
- package/.next/standalone/docker-hook-sync/Dockerfile +8 -4
- package/.next/standalone/lib/antigravity-projects.ts +224 -0
- package/.next/standalone/lib/antigravity-sessions.ts +283 -0
- package/.next/standalone/lib/cli-registry.ts +26 -6
- package/.next/standalone/lib/devin-projects.ts +141 -0
- package/.next/standalone/lib/devin-sessions.ts +343 -0
- package/.next/standalone/lib/download-session.ts +56 -5
- package/.next/standalone/lib/error-origin.ts +67 -0
- package/.next/standalone/lib/factory-projects.ts +109 -0
- package/.next/standalone/lib/factory-sessions.ts +312 -0
- package/.next/standalone/lib/goose-projects.ts +148 -0
- package/.next/standalone/lib/goose-sessions.ts +296 -0
- package/.next/standalone/lib/install-check.ts +231 -0
- package/.next/standalone/lib/openclaw-projects.ts +182 -0
- package/.next/standalone/lib/openclaw-sessions.ts +284 -0
- package/.next/standalone/lib/projects.ts +33 -9
- package/.next/standalone/lib/telemetry-sanitize.ts +43 -0
- package/.next/standalone/openclaw-plugin/index.js +223 -0
- package/.next/standalone/openclaw-plugin/openclaw.plugin.json +6 -0
- package/.next/standalone/openclaw-plugin/package.json +12 -0
- package/.next/standalone/package.json +2 -3
- package/.next/standalone/server.js +1 -1
- package/README.md +94 -62
- package/bin/failproofai.mjs +98 -30
- package/dist/cli.mjs +12499 -9243
- package/lib/antigravity-projects.ts +224 -0
- package/lib/antigravity-sessions.ts +283 -0
- package/lib/cli-registry.ts +26 -6
- package/lib/devin-projects.ts +141 -0
- package/lib/devin-sessions.ts +343 -0
- package/lib/download-session.ts +56 -5
- package/lib/error-origin.ts +67 -0
- package/lib/factory-projects.ts +109 -0
- package/lib/factory-sessions.ts +312 -0
- package/lib/goose-projects.ts +148 -0
- package/lib/goose-sessions.ts +296 -0
- package/lib/install-check.ts +231 -0
- package/lib/openclaw-projects.ts +182 -0
- package/lib/openclaw-sessions.ts +284 -0
- package/lib/projects.ts +33 -9
- package/lib/telemetry-sanitize.ts +43 -0
- package/openclaw-plugin/index.js +223 -0
- package/openclaw-plugin/openclaw.plugin.json +6 -0
- package/openclaw-plugin/package.json +12 -0
- package/package.json +2 -3
- package/scripts/dev-hook.mjs +292 -0
- package/scripts/install-diagnosis.mjs +5 -8
- package/scripts/install-telemetry.mjs +12 -4
- package/scripts/launch.ts +4 -8
- package/scripts/sync-agent-cli-harnesses-prompt.md +7 -10
- package/scripts/translate-docs/cli.ts +120 -53
- package/scripts/translate-docs/config.ts +57 -13
- package/scripts/translate-docs/mdx-translator.ts +177 -28
- package/scripts/translate-docs/mintlify-nav.ts +91 -10
- package/scripts/translate-docs/readme-translator.ts +13 -5
- package/scripts/translate-docs/translator.ts +38 -2
- package/scripts/translate-docs/types.ts +3 -0
- package/scripts/validate-mdx.ts +12 -4
- package/src/audit/cli-adapters/antigravity.ts +87 -0
- package/src/audit/cli-adapters/devin.ts +53 -0
- package/src/audit/cli-adapters/factory.ts +75 -0
- package/src/audit/cli-adapters/goose.ts +53 -0
- package/src/audit/cli-adapters/index.ts +30 -6
- package/src/audit/cli-adapters/openclaw.ts +56 -0
- package/src/audit/cli.ts +83 -8
- package/src/audit/report.ts +1 -1
- package/src/audit/types.ts +1 -1
- package/src/hooks/builtin-policies.ts +5 -5
- package/src/hooks/configure-wizard.ts +356 -0
- package/src/hooks/handler.ts +283 -218
- package/src/hooks/hook-telemetry.ts +43 -3
- package/src/hooks/install-prompt.ts +92 -173
- package/src/hooks/integrations.ts +739 -138
- package/src/hooks/manager.ts +46 -2
- package/src/hooks/policy-evaluator.ts +301 -121
- package/src/hooks/policy-presets.ts +71 -0
- package/src/hooks/resolve-cwd.ts +1 -1
- package/src/hooks/resolve-permission-mode.ts +1 -5
- package/src/hooks/resolve-transcript-path.ts +25 -7
- package/src/hooks/tool-name-canonicalize.ts +36 -3
- package/src/hooks/tui.ts +578 -0
- package/src/hooks/types.ts +447 -109
- package/.next/standalone/.gemini/settings.json +0 -147
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cag8qd._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0cefjd9._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0ekj92q._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__12v-lma._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__136y39g._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__13h8pzr._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1hgv_75._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04bqvos._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0dqgs96._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0q5rfxg._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0qukut7._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1ql-mch._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_11v0g3z._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/lib_gemini-projects_ts_1c7bgx-._.js +0 -3
- package/.next/standalone/.next/static/chunks/0fa7j157kg9_d.js +0 -1
- package/.next/standalone/.next/static/chunks/0nrah-qv6smeg.js +0 -6
- package/.next/standalone/.next/static/chunks/0wtagd8a5gwq-.js +0 -1
- package/.next/standalone/.next/static/chunks/1c8i78p7t1i-5.js +0 -1
- package/.next/standalone/.next/static/chunks/25qr0e6ez0ei0.js +0 -1
- package/.next/standalone/.next/static/chunks/25s52un3k_wht.css +0 -2
- package/.next/standalone/assets/logos/gemini-dark.svg +0 -13
- package/.next/standalone/assets/logos/gemini-light.svg +0 -13
- package/.next/standalone/lib/gemini-projects.ts +0 -243
- package/.next/standalone/lib/gemini-sessions.ts +0 -365
- package/lib/gemini-projects.ts +0 -243
- package/lib/gemini-sessions.ts +0 -365
- package/scripts/postinstall.mjs +0 -243
- package/scripts/preuninstall.mjs +0 -131
- package/src/audit/cli-adapters/gemini.ts +0 -51
- package/src/hooks/first-run-nudge.ts +0 -146
- /package/.next/standalone/.next/static/{kmzdjTLVs6LqsfyOaUf69 → LkN-JjmhKGmL-WklH7WVi}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{kmzdjTLVs6LqsfyOaUf69 → LkN-JjmhKGmL-WklH7WVi}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{kmzdjTLVs6LqsfyOaUf69 → LkN-JjmhKGmL-WklH7WVi}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antigravity (agy) project discovery + session enumeration — AUDIT-ONLY.
|
|
3
|
+
*
|
|
4
|
+
* Antigravity keeps a SQLite index of conversations at
|
|
5
|
+
* `~/.gemini/antigravity-cli/conversation_summaries.db` (table
|
|
6
|
+
* `conversation_summaries`: conversation_id, title, preview, step_count,
|
|
7
|
+
* workspace_uris, project_id, last_modified_time, agent_name, …) and one
|
|
8
|
+
* plain-JSONL transcript per conversation under `brain/<id>/…`. Verified live
|
|
9
|
+
* against agy v1.1.2.
|
|
10
|
+
*
|
|
11
|
+
* The on-disk `brain/` transcripts are the source of truth for a conversation's
|
|
12
|
+
* EXISTENCE (the summaries DB can lag / be checkpointed empty), so we enumerate
|
|
13
|
+
* from disk (lib/antigravity-sessions.ts) and ENRICH each with title + cwd from
|
|
14
|
+
* the SQLite index when a row is present. `workspace_uris` gives the project cwd
|
|
15
|
+
* → per-project grouping; when absent we recover cwd from the transcript's first
|
|
16
|
+
* `run_command` Cwd, else fall back to a synthetic "antigravity" project.
|
|
17
|
+
*
|
|
18
|
+
* DB / home override: set `ANTIGRAVITY_HOME` (used by tests).
|
|
19
|
+
*/
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
import { openSqliteReadonly } from "./sqlite-reader";
|
|
22
|
+
import {
|
|
23
|
+
antigravityHome,
|
|
24
|
+
listAntigravityTranscripts,
|
|
25
|
+
getAntigravitySessionLog,
|
|
26
|
+
} from "./antigravity-sessions";
|
|
27
|
+
import { runtimeCache } from "./runtime-cache";
|
|
28
|
+
import type { ProjectFolder, SessionFile } from "./projects";
|
|
29
|
+
import { encodeFolderName, decodeFolderName } from "./paths";
|
|
30
|
+
import { formatDate } from "./format-date";
|
|
31
|
+
import { logWarn } from "./logger";
|
|
32
|
+
|
|
33
|
+
/** Absolute path to the conversation-index SQLite DB. */
|
|
34
|
+
export function antigravitySummariesDbPath(): string {
|
|
35
|
+
return join(antigravityHome(), "conversation_summaries.db");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface SummaryRow {
|
|
39
|
+
conversation_id: string;
|
|
40
|
+
title: string | null;
|
|
41
|
+
step_count: number | null;
|
|
42
|
+
workspace_uris: string | null;
|
|
43
|
+
last_modified_time: string | number | null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface AntigravityIndexMeta {
|
|
47
|
+
title?: string;
|
|
48
|
+
cwd?: string;
|
|
49
|
+
stepCount?: number;
|
|
50
|
+
lastMs?: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Parse the first workspace URI (a JSON array, or a plain string) into a cwd,
|
|
54
|
+
* stripping any `file://` scheme. */
|
|
55
|
+
function parseWorkspaceCwd(raw: string | null): string | undefined {
|
|
56
|
+
if (!raw) return undefined;
|
|
57
|
+
let first: string | undefined;
|
|
58
|
+
try {
|
|
59
|
+
const parsed = JSON.parse(raw);
|
|
60
|
+
if (Array.isArray(parsed) && typeof parsed[0] === "string") first = parsed[0];
|
|
61
|
+
else if (typeof parsed === "string") first = parsed;
|
|
62
|
+
} catch {
|
|
63
|
+
first = raw;
|
|
64
|
+
}
|
|
65
|
+
if (!first) return undefined;
|
|
66
|
+
const stripped = first.replace(/^file:\/\//, "");
|
|
67
|
+
return stripped.length > 0 ? stripped : undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function toMs(value: string | number | null): number | undefined {
|
|
71
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
72
|
+
return value > 1e12 ? value : value > 1e9 ? value * 1000 : undefined;
|
|
73
|
+
}
|
|
74
|
+
if (typeof value === "string") {
|
|
75
|
+
const ms = Date.parse(value);
|
|
76
|
+
if (!Number.isNaN(ms)) return ms;
|
|
77
|
+
}
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Read the conversation index → conversationId → metadata. Returns an empty
|
|
82
|
+
* map when the DB is missing/unreadable/empty (fail-open). */
|
|
83
|
+
export async function getAntigravityIndex(): Promise<Map<string, AntigravityIndexMeta>> {
|
|
84
|
+
const out = new Map<string, AntigravityIndexMeta>();
|
|
85
|
+
const db = await openSqliteReadonly(antigravitySummariesDbPath());
|
|
86
|
+
if (!db) return out;
|
|
87
|
+
try {
|
|
88
|
+
const rows = db.query<SummaryRow>(
|
|
89
|
+
"SELECT conversation_id, title, step_count, workspace_uris, last_modified_time FROM conversation_summaries",
|
|
90
|
+
);
|
|
91
|
+
for (const r of rows) {
|
|
92
|
+
if (!r.conversation_id) continue;
|
|
93
|
+
out.set(r.conversation_id, {
|
|
94
|
+
title: r.title ?? undefined,
|
|
95
|
+
cwd: parseWorkspaceCwd(r.workspace_uris),
|
|
96
|
+
stepCount: typeof r.step_count === "number" ? r.step_count : undefined,
|
|
97
|
+
lastMs: toMs(r.last_modified_time),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
} catch {
|
|
101
|
+
// corrupt / unexpected schema — fall open with whatever we have
|
|
102
|
+
} finally {
|
|
103
|
+
db.close();
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
interface AntigravityConversation {
|
|
109
|
+
conversationId: string;
|
|
110
|
+
cwd: string | null;
|
|
111
|
+
title?: string;
|
|
112
|
+
mtimeMs: number;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Resolve every on-disk conversation to {cwd, title, mtime}, enriched from the
|
|
116
|
+
* SQLite index (cwd/title/lastMs) and, when the index lacks a cwd, from the
|
|
117
|
+
* transcript's first run_command Cwd. */
|
|
118
|
+
async function resolveConversations(): Promise<AntigravityConversation[]> {
|
|
119
|
+
let transcripts;
|
|
120
|
+
try {
|
|
121
|
+
transcripts = listAntigravityTranscripts();
|
|
122
|
+
} catch (error) {
|
|
123
|
+
logWarn("Failed to scan Antigravity brain dir:", error);
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
const index = await getAntigravityIndex();
|
|
127
|
+
|
|
128
|
+
const out: AntigravityConversation[] = [];
|
|
129
|
+
for (const t of transcripts) {
|
|
130
|
+
const meta = index.get(t.conversationId);
|
|
131
|
+
let cwd = meta?.cwd ?? null;
|
|
132
|
+
if (!cwd) {
|
|
133
|
+
// No index cwd — recover it from the transcript itself (best-effort).
|
|
134
|
+
try {
|
|
135
|
+
const log = await getAntigravitySessionLog(t.conversationId);
|
|
136
|
+
cwd = log?.cwd ?? null;
|
|
137
|
+
} catch {
|
|
138
|
+
cwd = null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
out.push({
|
|
142
|
+
conversationId: t.conversationId,
|
|
143
|
+
cwd,
|
|
144
|
+
title: meta?.title,
|
|
145
|
+
mtimeMs: meta?.lastMs ?? t.mtimeMs,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return out;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** Synthetic project name for conversations whose cwd could not be resolved. */
|
|
152
|
+
const ANTIGRAVITY_UNGROUPED = "antigravity";
|
|
153
|
+
|
|
154
|
+
/** Returns one ProjectFolder per resolved cwd (grouped), plus a synthetic
|
|
155
|
+
* "antigravity" project for conversations without a cwd. */
|
|
156
|
+
export async function getAntigravityProjects(): Promise<ProjectFolder[]> {
|
|
157
|
+
const conversations = await resolveConversations();
|
|
158
|
+
|
|
159
|
+
const byName = new Map<string, { latest: number; path: string }>();
|
|
160
|
+
for (const c of conversations) {
|
|
161
|
+
const name = c.cwd ? encodeFolderName(c.cwd) : ANTIGRAVITY_UNGROUPED;
|
|
162
|
+
const path = c.cwd ?? "antigravity";
|
|
163
|
+
const existing = byName.get(name);
|
|
164
|
+
if (!existing || c.mtimeMs > existing.latest) {
|
|
165
|
+
byName.set(name, { latest: c.mtimeMs, path });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const folders: ProjectFolder[] = [];
|
|
170
|
+
for (const [name, { latest, path }] of byName) {
|
|
171
|
+
const lastModified = new Date(latest);
|
|
172
|
+
folders.push({
|
|
173
|
+
name,
|
|
174
|
+
path,
|
|
175
|
+
isDirectory: true,
|
|
176
|
+
lastModified,
|
|
177
|
+
lastModifiedFormatted: formatDate(lastModified),
|
|
178
|
+
cli: ["antigravity"],
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
folders.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());
|
|
182
|
+
return folders;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export interface AntigravityProjectByName {
|
|
186
|
+
cwd: string | null;
|
|
187
|
+
sessions: SessionFile[];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Resolve the Antigravity conversations for a project URL slug (an encoded-cwd
|
|
191
|
+
* folder name, or the synthetic "antigravity" bucket). */
|
|
192
|
+
export async function getAntigravitySessionsByEncodedName(
|
|
193
|
+
name: string,
|
|
194
|
+
): Promise<AntigravityProjectByName> {
|
|
195
|
+
const conversations = await resolveConversations();
|
|
196
|
+
const matched = conversations.filter((c) => {
|
|
197
|
+
const encoded = c.cwd ? encodeFolderName(c.cwd) : ANTIGRAVITY_UNGROUPED;
|
|
198
|
+
return encoded === name;
|
|
199
|
+
});
|
|
200
|
+
if (matched.length === 0) return { cwd: null, sessions: [] };
|
|
201
|
+
|
|
202
|
+
const sorted = [...matched].sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
203
|
+
const cwd = sorted.find((c) => c.cwd)?.cwd ?? (name === ANTIGRAVITY_UNGROUPED ? null : decodeFolderName(name));
|
|
204
|
+
|
|
205
|
+
const sessions: SessionFile[] = sorted.map((c) => {
|
|
206
|
+
const lastModified = new Date(c.mtimeMs);
|
|
207
|
+
return {
|
|
208
|
+
name: c.title ?? c.conversationId,
|
|
209
|
+
path: `antigravity://${c.conversationId}`,
|
|
210
|
+
lastModified,
|
|
211
|
+
lastModifiedFormatted: formatDate(lastModified),
|
|
212
|
+
sessionId: c.conversationId,
|
|
213
|
+
cli: "antigravity" as const,
|
|
214
|
+
};
|
|
215
|
+
});
|
|
216
|
+
return { cwd, sessions };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export const getCachedAntigravityProjects = runtimeCache(getAntigravityProjects, 30);
|
|
220
|
+
export const getCachedAntigravitySessionsByEncodedName = runtimeCache(
|
|
221
|
+
(name: string) => getAntigravitySessionsByEncodedName(name),
|
|
222
|
+
30,
|
|
223
|
+
{ maxSize: 50 },
|
|
224
|
+
);
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Antigravity (agy) session transcript loader + parser.
|
|
3
|
+
*
|
|
4
|
+
* AUDIT-ONLY (Pillar 2). Antigravity writes one plain-JSONL transcript per
|
|
5
|
+
* conversation at
|
|
6
|
+
* `~/.gemini/antigravity-cli/brain/<conversationId>/.system_generated/logs/transcript_full.jsonl`
|
|
7
|
+
* (one step per line). Verified live against agy v1.1.2. Sibling
|
|
8
|
+
* `<conversationId>.trajectory.jsonl` / `.trajectory-path.json` files are
|
|
9
|
+
* IGNORED — we only read `transcript_full.jsonl`.
|
|
10
|
+
*
|
|
11
|
+
* Each transcript line is a step:
|
|
12
|
+
* {step_index, source, type, status, created_at, content?, tool_calls?}
|
|
13
|
+
* The `type` enum (uppercase) drives parsing:
|
|
14
|
+
* • USER_INPUT — content = user text
|
|
15
|
+
* • PLANNER_RESPONSE — content = assistant text, OR tool_calls =
|
|
16
|
+
* [{name:"run_command", args:{CommandLine, Cwd, …}}]
|
|
17
|
+
* • <TOOL_STEP> (e.g. RUN_COMMAND) — content = the tool result string; the
|
|
18
|
+
* `type` is the uppercased tool name, so we pair it
|
|
19
|
+
* with the preceding PLANNER_RESPONSE tool_call of
|
|
20
|
+
* the same name.
|
|
21
|
+
* • CONVERSATION_HISTORY / CHECKPOINT — metadata (skipped).
|
|
22
|
+
*
|
|
23
|
+
* `antigravityLinesToLogEntries` is PURE (a function of the parsed line
|
|
24
|
+
* objects), so it is unit-testable without touching disk.
|
|
25
|
+
*
|
|
26
|
+
* Home override: set `ANTIGRAVITY_HOME` (used by tests / to point at a copied
|
|
27
|
+
* brain dir). Default: `~/.gemini/antigravity-cli`.
|
|
28
|
+
*/
|
|
29
|
+
import { readFile } from "node:fs/promises";
|
|
30
|
+
import { readdirSync, statSync } from "node:fs";
|
|
31
|
+
import { homedir } from "node:os";
|
|
32
|
+
import { join } from "node:path";
|
|
33
|
+
import { runtimeCache } from "./runtime-cache";
|
|
34
|
+
import {
|
|
35
|
+
baseEntry,
|
|
36
|
+
formatTimestamp,
|
|
37
|
+
parseRawLines,
|
|
38
|
+
type LogEntry,
|
|
39
|
+
type UserEntry,
|
|
40
|
+
type AssistantEntry,
|
|
41
|
+
type GenericEntry,
|
|
42
|
+
type ContentBlock,
|
|
43
|
+
type ToolUseBlock,
|
|
44
|
+
type LogSource,
|
|
45
|
+
} from "./log-entries";
|
|
46
|
+
import { formatDuration } from "./format-duration";
|
|
47
|
+
|
|
48
|
+
/** Antigravity conversations are UUID-named directories. */
|
|
49
|
+
export const ANTIGRAVITY_CONVERSATION_ID_RE =
|
|
50
|
+
/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
51
|
+
|
|
52
|
+
/** Step `type` values that are metadata, not turns. */
|
|
53
|
+
const ANTIGRAVITY_META_STEP_TYPES = new Set(["CONVERSATION_HISTORY", "CHECKPOINT"]);
|
|
54
|
+
|
|
55
|
+
/** Absolute path to Antigravity's config home (override with ANTIGRAVITY_HOME). */
|
|
56
|
+
export function antigravityHome(): string {
|
|
57
|
+
return process.env.ANTIGRAVITY_HOME || join(homedir(), ".gemini", "antigravity-cli");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Absolute path to the `brain/` root (one subdir per conversation). */
|
|
61
|
+
export function antigravityBrainRoot(): string {
|
|
62
|
+
return join(antigravityHome(), "brain");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Relative path of a conversation's full transcript inside its brain dir. */
|
|
66
|
+
export function antigravityTranscriptRelPath(): string {
|
|
67
|
+
return join(".system_generated", "logs", "transcript_full.jsonl");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ── Parsing helpers ──
|
|
71
|
+
|
|
72
|
+
function isPlainObject(v: unknown): v is Record<string, unknown> {
|
|
73
|
+
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function toDate(value: unknown, fallbackMs: number): Date {
|
|
77
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
78
|
+
if (value > 1e12) return new Date(value);
|
|
79
|
+
if (value > 1e9) return new Date(value * 1000);
|
|
80
|
+
}
|
|
81
|
+
if (typeof value === "string") {
|
|
82
|
+
const ms = Date.parse(value);
|
|
83
|
+
if (!Number.isNaN(ms)) return new Date(ms);
|
|
84
|
+
}
|
|
85
|
+
return new Date(fallbackMs);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ── Pure parser: transcript lines → LogEntry[] ──
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Convert Antigravity transcript JSONL lines (parsed objects, in file order)
|
|
92
|
+
* into `LogEntry[]`. USER_INPUT → user turns; PLANNER_RESPONSE → assistant
|
|
93
|
+
* turns (text and/or `tool_use` blocks); a following tool-result step
|
|
94
|
+
* (type === uppercased tool name, e.g. RUN_COMMAND) is paired back onto the
|
|
95
|
+
* matching `tool_use` block. Metadata steps (CONVERSATION_HISTORY, CHECKPOINT)
|
|
96
|
+
* are skipped. Pure — unit-testable with plain line objects.
|
|
97
|
+
*/
|
|
98
|
+
export function antigravityLinesToLogEntries(
|
|
99
|
+
lines: Record<string, unknown>[],
|
|
100
|
+
source: LogSource = "session",
|
|
101
|
+
): LogEntry[] {
|
|
102
|
+
const entries: LogEntry[] = [];
|
|
103
|
+
// FIFO of pending tool_use blocks keyed by uppercased tool name, so a later
|
|
104
|
+
// RUN_COMMAND-type result step attaches to the right run_command call.
|
|
105
|
+
const pendingByType = new Map<string, Array<{ block: ToolUseBlock; startMs: number }>>();
|
|
106
|
+
const baseMs = Date.now();
|
|
107
|
+
|
|
108
|
+
for (let i = 0; i < lines.length; i++) {
|
|
109
|
+
const line = lines[i];
|
|
110
|
+
if (!isPlainObject(line)) continue;
|
|
111
|
+
const type = typeof line.type === "string" ? line.type : "";
|
|
112
|
+
if (!type || ANTIGRAVITY_META_STEP_TYPES.has(type)) continue;
|
|
113
|
+
|
|
114
|
+
const date = toDate(line.created_at, baseMs + i);
|
|
115
|
+
const timestamp = date.toISOString();
|
|
116
|
+
const stepIndex = typeof line.step_index === "number" ? line.step_index : i;
|
|
117
|
+
const raw: Record<string, unknown> = {
|
|
118
|
+
uuid: `antigravity-${stepIndex}`,
|
|
119
|
+
parentUuid: null,
|
|
120
|
+
};
|
|
121
|
+
const base = baseEntry(raw, timestamp, date, source);
|
|
122
|
+
|
|
123
|
+
if (type === "USER_INPUT") {
|
|
124
|
+
const text = typeof line.content === "string" ? line.content : "";
|
|
125
|
+
entries.push({
|
|
126
|
+
type: "user",
|
|
127
|
+
...base,
|
|
128
|
+
message: { role: "user", content: text },
|
|
129
|
+
} satisfies UserEntry);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (type === "PLANNER_RESPONSE") {
|
|
134
|
+
const blocks: ContentBlock[] = [];
|
|
135
|
+
if (typeof line.content === "string" && line.content.length > 0) {
|
|
136
|
+
blocks.push({ type: "text", text: line.content });
|
|
137
|
+
}
|
|
138
|
+
if (Array.isArray(line.tool_calls)) {
|
|
139
|
+
for (let j = 0; j < line.tool_calls.length; j++) {
|
|
140
|
+
const call = line.tool_calls[j];
|
|
141
|
+
if (!isPlainObject(call)) continue;
|
|
142
|
+
const name = typeof call.name === "string" ? call.name : "tool";
|
|
143
|
+
const input = isPlainObject(call.args) ? call.args : {};
|
|
144
|
+
const id = `${name}-${stepIndex}-${j}`;
|
|
145
|
+
const block: ToolUseBlock = { type: "tool_use", id, name, input };
|
|
146
|
+
blocks.push(block);
|
|
147
|
+
const key = name.toUpperCase();
|
|
148
|
+
const queue = pendingByType.get(key) ?? [];
|
|
149
|
+
queue.push({ block, startMs: date.getTime() });
|
|
150
|
+
pendingByType.set(key, queue);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (blocks.length === 0) continue;
|
|
154
|
+
entries.push({
|
|
155
|
+
type: "assistant",
|
|
156
|
+
...base,
|
|
157
|
+
message: { role: "assistant", content: blocks },
|
|
158
|
+
} satisfies AssistantEntry);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Any other step type is a tool-result step whose `type` is the uppercased
|
|
163
|
+
// tool name (e.g. RUN_COMMAND for a run_command call). Pair it back onto the
|
|
164
|
+
// oldest matching pending tool_use block.
|
|
165
|
+
const queue = pendingByType.get(type);
|
|
166
|
+
if (queue && queue.length > 0) {
|
|
167
|
+
const { block, startMs } = queue.shift()!;
|
|
168
|
+
const durationMs = Math.max(0, date.getTime() - startMs);
|
|
169
|
+
block.result = {
|
|
170
|
+
timestamp,
|
|
171
|
+
timestampFormatted: formatTimestamp(date),
|
|
172
|
+
content: typeof line.content === "string" ? line.content : "",
|
|
173
|
+
durationMs,
|
|
174
|
+
durationFormatted: formatDuration(durationMs),
|
|
175
|
+
};
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
// Unpaired non-meta step — record as generic so nothing is silently lost.
|
|
179
|
+
entries.push({ type: "system", ...base, raw } satisfies GenericEntry);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
entries.sort((a, b) => a.timestampMs - b.timestampMs);
|
|
183
|
+
return entries;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** Best-effort cwd recovery: the first `run_command` tool_call's `Cwd` arg. */
|
|
187
|
+
function recoverCwd(lines: Record<string, unknown>[]): string | undefined {
|
|
188
|
+
for (const line of lines) {
|
|
189
|
+
if (!isPlainObject(line) || !Array.isArray(line.tool_calls)) continue;
|
|
190
|
+
for (const call of line.tool_calls) {
|
|
191
|
+
if (!isPlainObject(call) || !isPlainObject(call.args)) continue;
|
|
192
|
+
const cwd = call.args.Cwd ?? call.args.cwd;
|
|
193
|
+
if (typeof cwd === "string" && cwd.length > 0) return cwd;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ── Discovery + file loader ──
|
|
200
|
+
|
|
201
|
+
export interface AntigravityTranscriptFile {
|
|
202
|
+
conversationId: string;
|
|
203
|
+
transcriptPath: string;
|
|
204
|
+
mtimeMs: number;
|
|
205
|
+
sizeBytes: number;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Enumerate `brain/<conversationId>/.system_generated/logs/transcript_full.jsonl`
|
|
209
|
+
* transcripts. Skips conversation dirs without a full transcript. */
|
|
210
|
+
export function listAntigravityTranscripts(): AntigravityTranscriptFile[] {
|
|
211
|
+
const root = antigravityBrainRoot();
|
|
212
|
+
const rel = antigravityTranscriptRelPath();
|
|
213
|
+
const out: AntigravityTranscriptFile[] = [];
|
|
214
|
+
let convoDirs: import("node:fs").Dirent[];
|
|
215
|
+
try {
|
|
216
|
+
convoDirs = readdirSync(root, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
217
|
+
} catch {
|
|
218
|
+
return out;
|
|
219
|
+
}
|
|
220
|
+
for (const dir of convoDirs) {
|
|
221
|
+
const conversationId = dir.name;
|
|
222
|
+
if (!ANTIGRAVITY_CONVERSATION_ID_RE.test(conversationId)) continue;
|
|
223
|
+
const transcriptPath = join(root, conversationId, rel);
|
|
224
|
+
try {
|
|
225
|
+
const st = statSync(transcriptPath);
|
|
226
|
+
if (!st.isFile()) continue;
|
|
227
|
+
out.push({ conversationId, transcriptPath, mtimeMs: st.mtimeMs, sizeBytes: st.size });
|
|
228
|
+
} catch {
|
|
229
|
+
// no full transcript for this conversation yet — skip
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return out;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** Resolve a conversation UUID to its on-disk transcript path (host-side).
|
|
236
|
+
* Guards against traversal by requiring a UUID. Shared by the audit adapter,
|
|
237
|
+
* the hook transcript resolver, and download-session. Synchronous. */
|
|
238
|
+
export function findAntigravityTranscript(conversationId: string): string | null {
|
|
239
|
+
if (!ANTIGRAVITY_CONVERSATION_ID_RE.test(conversationId)) return null;
|
|
240
|
+
const transcriptPath = join(
|
|
241
|
+
antigravityBrainRoot(),
|
|
242
|
+
conversationId,
|
|
243
|
+
antigravityTranscriptRelPath(),
|
|
244
|
+
);
|
|
245
|
+
try {
|
|
246
|
+
if (statSync(transcriptPath).isFile()) return transcriptPath;
|
|
247
|
+
} catch {
|
|
248
|
+
// fall through
|
|
249
|
+
}
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export interface AntigravitySessionLogData {
|
|
254
|
+
entries: LogEntry[];
|
|
255
|
+
rawLines: Record<string, unknown>[];
|
|
256
|
+
cwd?: string;
|
|
257
|
+
filePath: string;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** Load and parse one conversation transcript by UUID. Returns `null` when the
|
|
261
|
+
* file is missing/unreadable or the id fails validation. */
|
|
262
|
+
export async function getAntigravitySessionLog(
|
|
263
|
+
conversationId: string,
|
|
264
|
+
): Promise<AntigravitySessionLogData | null> {
|
|
265
|
+
const filePath = findAntigravityTranscript(conversationId);
|
|
266
|
+
if (!filePath) return null;
|
|
267
|
+
let content: string;
|
|
268
|
+
try {
|
|
269
|
+
content = await readFile(filePath, "utf-8");
|
|
270
|
+
} catch {
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
const rawLines = parseRawLines(content, "session");
|
|
274
|
+
const entries = antigravityLinesToLogEntries(rawLines, "session");
|
|
275
|
+
const cwd = recoverCwd(rawLines);
|
|
276
|
+
return { entries, rawLines, cwd, filePath };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export const getCachedAntigravitySessionLog = runtimeCache(
|
|
280
|
+
(conversationId: string) => getAntigravitySessionLog(conversationId),
|
|
281
|
+
60,
|
|
282
|
+
{ maxSize: 50 },
|
|
283
|
+
);
|
package/lib/cli-registry.ts
CHANGED
|
@@ -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", "
|
|
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. */
|
|
@@ -69,16 +69,36 @@ const CLI_ENTRIES: Record<CliId, CliEntry> = {
|
|
|
69
69
|
label: "Pi",
|
|
70
70
|
badgeClasses: "bg-pink-500/10 text-pink-400 border-pink-500/20",
|
|
71
71
|
},
|
|
72
|
-
gemini: {
|
|
73
|
-
id: "gemini",
|
|
74
|
-
label: "Gemini CLI",
|
|
75
|
-
badgeClasses: "bg-sky-500/10 text-sky-400 border-sky-500/20",
|
|
76
|
-
},
|
|
77
72
|
hermes: {
|
|
78
73
|
id: "hermes",
|
|
79
74
|
label: "Hermes",
|
|
80
75
|
badgeClasses: "bg-indigo-500/10 text-indigo-400 border-indigo-500/20",
|
|
81
76
|
},
|
|
77
|
+
openclaw: {
|
|
78
|
+
id: "openclaw",
|
|
79
|
+
label: "OpenClaw",
|
|
80
|
+
badgeClasses: "bg-teal-500/10 text-teal-400 border-teal-500/20",
|
|
81
|
+
},
|
|
82
|
+
factory: {
|
|
83
|
+
id: "factory",
|
|
84
|
+
label: "Factory Droid",
|
|
85
|
+
badgeClasses: "bg-rose-500/10 text-rose-400 border-rose-500/20",
|
|
86
|
+
},
|
|
87
|
+
devin: {
|
|
88
|
+
id: "devin",
|
|
89
|
+
label: "Devin CLI",
|
|
90
|
+
badgeClasses: "bg-violet-500/10 text-violet-400 border-violet-500/20",
|
|
91
|
+
},
|
|
92
|
+
antigravity: {
|
|
93
|
+
id: "antigravity",
|
|
94
|
+
label: "Antigravity CLI",
|
|
95
|
+
badgeClasses: "bg-cyan-500/10 text-cyan-400 border-cyan-500/20",
|
|
96
|
+
},
|
|
97
|
+
goose: {
|
|
98
|
+
id: "goose",
|
|
99
|
+
label: "Goose",
|
|
100
|
+
badgeClasses: "bg-lime-500/10 text-lime-400 border-lime-500/20",
|
|
101
|
+
},
|
|
82
102
|
};
|
|
83
103
|
|
|
84
104
|
export function getCliEntry(id: string): CliEntry | undefined {
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Devin CLI (Cognition) session enumeration — AUDIT-ONLY.
|
|
3
|
+
*
|
|
4
|
+
* Reads the `sessions` table directly from `~/.local/share/devin/cli/sessions.db`
|
|
5
|
+
* via the bundled sql.js reader. Unlike Hermes (cwd-less, grouped by channel),
|
|
6
|
+
* each Devin session carries a real `working_directory`, so Devin sessions group
|
|
7
|
+
* by project cwd like Claude/Factory — one `ProjectFolder` per encoded cwd, and
|
|
8
|
+
* a cwd present in both Claude and Devin stores merges on the shared encoded
|
|
9
|
+
* slug (see `mergeProjectFolders` in lib/projects.ts).
|
|
10
|
+
*/
|
|
11
|
+
import { openSqliteReadonly } from "./sqlite-reader";
|
|
12
|
+
import { devinDbPath, devinEpochToMs } from "./devin-sessions";
|
|
13
|
+
import { encodeFolderName } from "./paths";
|
|
14
|
+
import { runtimeCache } from "./runtime-cache";
|
|
15
|
+
import type { ProjectFolder, SessionFile } from "./projects";
|
|
16
|
+
import { formatDate } from "./format-date";
|
|
17
|
+
|
|
18
|
+
export interface DevinSessionRef {
|
|
19
|
+
sessionId: string;
|
|
20
|
+
cwd?: string;
|
|
21
|
+
title?: string;
|
|
22
|
+
/** Encoded-cwd folder slug (matches Claude's `-home-user-project` scheme). */
|
|
23
|
+
projectName: string;
|
|
24
|
+
/** From `last_activity_at` (falls back to `created_at`) — epoch ms. */
|
|
25
|
+
mtimeMs: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface SessionRow {
|
|
29
|
+
id: string;
|
|
30
|
+
working_directory: string | null;
|
|
31
|
+
title: string | null;
|
|
32
|
+
created_at: number | null;
|
|
33
|
+
last_activity_at: number | null;
|
|
34
|
+
hidden: number | null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* List every Devin session. Returns `[]` when the DB is missing or unreadable
|
|
39
|
+
* (fail-open — the audit just skips Devin). Hidden sessions are excluded.
|
|
40
|
+
*/
|
|
41
|
+
export async function getDevinSessions(): Promise<DevinSessionRef[]> {
|
|
42
|
+
const db = await openSqliteReadonly(devinDbPath());
|
|
43
|
+
if (!db) return [];
|
|
44
|
+
try {
|
|
45
|
+
const rows = db.query<SessionRow>(
|
|
46
|
+
"SELECT id, working_directory, title, created_at, last_activity_at, hidden " +
|
|
47
|
+
"FROM sessions ORDER BY last_activity_at DESC",
|
|
48
|
+
);
|
|
49
|
+
return rows
|
|
50
|
+
.filter((r) => !r.hidden)
|
|
51
|
+
.map((r) => {
|
|
52
|
+
const cwd = r.working_directory ?? undefined;
|
|
53
|
+
return {
|
|
54
|
+
sessionId: r.id,
|
|
55
|
+
cwd,
|
|
56
|
+
title: r.title ?? undefined,
|
|
57
|
+
projectName: cwd ? encodeFolderName(cwd) : "devin",
|
|
58
|
+
mtimeMs: devinEpochToMs(r.last_activity_at ?? r.created_at),
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
} catch {
|
|
62
|
+
return [];
|
|
63
|
+
} finally {
|
|
64
|
+
db.close();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const getCachedDevinSessions = runtimeCache(getDevinSessions, 2);
|
|
69
|
+
|
|
70
|
+
// ── Dashboard history browser (projects list + project-detail sessions) ──
|
|
71
|
+
|
|
72
|
+
/** One `ProjectFolder` per encoded-cwd discovered in the Devin DB. */
|
|
73
|
+
export async function getDevinProjects(): Promise<ProjectFolder[]> {
|
|
74
|
+
const sessions = await getDevinSessions();
|
|
75
|
+
const byName = new Map<string, { latest: number; cwd: string; name: string }>();
|
|
76
|
+
for (const s of sessions) {
|
|
77
|
+
if (!s.cwd) continue;
|
|
78
|
+
const existing = byName.get(s.projectName);
|
|
79
|
+
if (!existing || s.mtimeMs > existing.latest) {
|
|
80
|
+
byName.set(s.projectName, { latest: s.mtimeMs, cwd: s.cwd, name: s.projectName });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const folders: ProjectFolder[] = [];
|
|
84
|
+
for (const { name, cwd, latest } of byName.values()) {
|
|
85
|
+
const lastModified = new Date(latest);
|
|
86
|
+
folders.push({
|
|
87
|
+
name,
|
|
88
|
+
path: cwd,
|
|
89
|
+
isDirectory: true,
|
|
90
|
+
lastModified,
|
|
91
|
+
lastModifiedFormatted: formatDate(lastModified),
|
|
92
|
+
cli: ["devin"],
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
folders.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());
|
|
96
|
+
return folders;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface DevinProjectByName {
|
|
100
|
+
/** Canonical cwd recovered from the session's `working_directory`. */
|
|
101
|
+
cwd: string | null;
|
|
102
|
+
sessions: SessionFile[];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Resolve the Devin sessions for a project URL slug (the encoded-cwd folder
|
|
107
|
+
* name). Because Devin's `working_directory` re-encodes to the same slug Claude
|
|
108
|
+
* uses, the slug matches directly and the canonical cwd is the session's real
|
|
109
|
+
* `working_directory` (no lossy folder-decode needed).
|
|
110
|
+
*/
|
|
111
|
+
export async function getDevinSessionsByEncodedName(
|
|
112
|
+
name: string,
|
|
113
|
+
): Promise<DevinProjectByName> {
|
|
114
|
+
const sessions = await getDevinSessions();
|
|
115
|
+
const matched = sessions.filter((s) => s.cwd && s.projectName === name);
|
|
116
|
+
if (matched.length === 0) return { cwd: null, sessions: [] };
|
|
117
|
+
|
|
118
|
+
const sorted = [...matched].sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
119
|
+
const cwd = sorted[0].cwd ?? null;
|
|
120
|
+
return {
|
|
121
|
+
cwd,
|
|
122
|
+
sessions: sorted.map((s) => {
|
|
123
|
+
const lastModified = new Date(s.mtimeMs);
|
|
124
|
+
return {
|
|
125
|
+
name: s.title ?? s.sessionId,
|
|
126
|
+
path: `devin-db://${s.sessionId}`,
|
|
127
|
+
lastModified,
|
|
128
|
+
lastModifiedFormatted: formatDate(lastModified),
|
|
129
|
+
sessionId: s.sessionId,
|
|
130
|
+
cli: "devin" as const,
|
|
131
|
+
};
|
|
132
|
+
}),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export const getCachedDevinProjects = runtimeCache(getDevinProjects, 2);
|
|
137
|
+
export const getCachedDevinSessionsByEncodedName = runtimeCache(
|
|
138
|
+
(name: string) => getDevinSessionsByEncodedName(name),
|
|
139
|
+
2,
|
|
140
|
+
{ maxSize: 50 },
|
|
141
|
+
);
|