failproofai 0.0.13-beta.2 → 0.0.14-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.factory/hooks.json +112 -0
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +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/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/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/policies/page.js +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/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/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/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]__0xuaoik._.js +3 -3
- 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]__1rlmypf._.js → [root-of-the-server]__07qfsfa._.js} +2 -2
- 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]__0e2l3c1._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__09u1pcy._.js → [root-of-the-server]__0ge8e7w._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0h12me5._.js +1 -1
- 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]__0ynf7tx._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__11rtg6s._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__14dd6h8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__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]__1dky4g0._.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/[root-of-the-server]__212nf49._.js +1 -1
- 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_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_09fe3kb.js → node_modules_html-to-image_es_index_0g5r64e.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0-uvagv.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_03c7gi5.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_09p-8om.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0v-kfiu.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_0xrgzyz.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1806lsc.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1j6dd-e.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_next_dist_esm_build_templates_app-page_1sa65r-.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 +3 -3
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +10 -10
- package/.next/standalone/.next/static/chunks/003uz088wbmz7.js +1 -0
- package/.next/standalone/.next/static/chunks/{0l2n5ftar65ox.js → 0405htbxay9vd.js} +1 -1
- package/.next/standalone/.next/static/chunks/0iinhn4417nk1.js +1 -0
- package/.next/standalone/.next/static/chunks/1374x9bv_s_vg.js +6 -0
- package/.next/standalone/.next/static/chunks/{06cw8nbn5c4_r.js → 17sdztgbcc0fi.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0i0joc040j999.js → 2m_tbl39fcedn.js} +1 -1
- package/.next/standalone/.next/static/chunks/{25qvspmcbb_5y.js → 2o3ql0n5owqsw.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2a-k91nsa1lgf.js → 2ufuwhv03yvtb.js} +1 -1
- package/.next/standalone/.next/static/chunks/35-90m9py64d4.js +1 -0
- package/.next/standalone/.next/static/chunks/3r--yyjkp9_7b.css +2 -0
- package/.next/standalone/.next/static/chunks/{23t-i9s-q--nu.js → 43weu8f59tlix.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2oz8ok8fzxaj3.js → 454dyizqik6t9.js} +2 -2
- 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/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/components/navbar.tsx +5 -11
- package/.next/standalone/components/reach-developers.tsx +1 -1
- 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/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/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 +4 -3
- package/.next/standalone/server.js +1 -1
- package/README.md +105 -57
- package/bin/failproofai.mjs +87 -29
- package/dist/cli.mjs +12803 -9809
- 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/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/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 +4 -3
- package/scripts/launch.ts +4 -8
- package/scripts/postinstall.mjs +3 -4
- package/scripts/sync-agent-cli-harnesses-prompt.md +7 -10
- package/scripts/translate-docs/cli.ts +73 -52
- package/scripts/translate-docs/config.ts +57 -13
- package/scripts/translate-docs/mdx-translator.ts +51 -31
- package/scripts/translate-docs/mintlify-nav.ts +91 -10
- package/scripts/translate-docs/types.ts +3 -0
- 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 +44 -1
- 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/1c8i78p7t1i-5.js +0 -1
- package/.next/standalone/.next/static/chunks/1sg8kx5szx42y.js +0 -6
- package/.next/standalone/.next/static/chunks/25s52un3k_wht.css +0 -2
- package/.next/standalone/.next/static/chunks/2rkvn4znvuy4o.js +0 -1
- 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/src/audit/cli-adapters/gemini.ts +0 -51
- package/src/hooks/first-run-nudge.ts +0 -146
- /package/.next/standalone/.next/static/{HgG0mizCfOM3XyN1EW-sL → MNJWFb2jLRrxRKGFNK6Hy}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{HgG0mizCfOM3XyN1EW-sL → MNJWFb2jLRrxRKGFNK6Hy}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{HgG0mizCfOM3XyN1EW-sL → MNJWFb2jLRrxRKGFNK6Hy}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Goose (codename goose, Block) session transcript loader + parser.
|
|
3
|
+
*
|
|
4
|
+
* AUDIT-ONLY (Pillar 2). Goose (≥ v1.10.0) stores every session in one SQLite DB
|
|
5
|
+
* at `~/.local/share/goose/sessions/sessions.db`. We read it DIRECTLY via the
|
|
6
|
+
* bundled sql.js driver (lib/sqlite-reader.ts) — the same reusable path
|
|
7
|
+
* Devin/Hermes/OpenClaw use. Like Devin (and unlike the cwd-less Hermes gateway),
|
|
8
|
+
* each Goose `sessions` row carries a real `working_dir`, so Goose sessions group
|
|
9
|
+
* by project cwd like Claude/Factory/Devin.
|
|
10
|
+
*
|
|
11
|
+
* Schema (verified live against goose v1.43.0, schema_version 15):
|
|
12
|
+
* sessions(id TEXT `YYYYMMDD_N`, name, description, session_type
|
|
13
|
+
* (user|hidden|subagent|scheduled|terminal|acp), working_dir,
|
|
14
|
+
* created_at TIMESTAMP, updated_at TIMESTAMP, total_tokens, …)
|
|
15
|
+
* messages(id INTEGER PK, session_id, role (user|assistant),
|
|
16
|
+
* content_json TEXT=JSON-array-of-blocks, created_timestamp INT, …)
|
|
17
|
+
*
|
|
18
|
+
* `content_json` is a Claude-style typed-block array (NOT OpenAI-style like
|
|
19
|
+
* Devin): `{type:"text",text}`, `{type:"toolRequest",id,toolCall:{value:{name,
|
|
20
|
+
* arguments}},_meta:{goose_extension}}`, and `{type:"toolResponse",id,toolResult:
|
|
21
|
+
* {value:{content:[{type:"text",text}],isError}}}`. Tool RESULTS are stored in
|
|
22
|
+
* `role:"user"` rows (Claude convention). `gooseRowsToLogEntries` pairs each
|
|
23
|
+
* toolRequest with its later toolResponse by id and is a PURE function of the
|
|
24
|
+
* parsed rows, so it is unit-testable without a DB.
|
|
25
|
+
*
|
|
26
|
+
* `session_type = 'hidden'` rows are `goose run --no-session` scratch runs — the
|
|
27
|
+
* enumerator (lib/goose-projects.ts) filters them out.
|
|
28
|
+
*
|
|
29
|
+
* Home override: set `GOOSE_HOME` (the data dir that contains `sessions/`, used
|
|
30
|
+
* by tests) or `GOOSE_DB_PATH` (points directly at a sessions.db).
|
|
31
|
+
*/
|
|
32
|
+
import { homedir } from "node:os";
|
|
33
|
+
import { join } from "node:path";
|
|
34
|
+
import { openSqliteReadonly } from "./sqlite-reader";
|
|
35
|
+
import { runtimeCache } from "./runtime-cache";
|
|
36
|
+
import {
|
|
37
|
+
baseEntry,
|
|
38
|
+
formatTimestamp,
|
|
39
|
+
type LogEntry,
|
|
40
|
+
type UserEntry,
|
|
41
|
+
type AssistantEntry,
|
|
42
|
+
type GenericEntry,
|
|
43
|
+
type ContentBlock,
|
|
44
|
+
type ToolUseBlock,
|
|
45
|
+
type LogSource,
|
|
46
|
+
} from "./log-entries";
|
|
47
|
+
import { formatDuration } from "./format-duration";
|
|
48
|
+
|
|
49
|
+
/** Goose session IDs are date-prefixed counters, e.g. `20260714_3`. */
|
|
50
|
+
export const GOOSE_SESSION_ID_RE = /^\d{8}_\d+$/;
|
|
51
|
+
|
|
52
|
+
/** Absolute path to Goose's data home (override with GOOSE_HOME; respects
|
|
53
|
+
* XDG_DATA_HOME otherwise). */
|
|
54
|
+
export function gooseHome(): string {
|
|
55
|
+
if (process.env.GOOSE_HOME) return process.env.GOOSE_HOME;
|
|
56
|
+
const xdg = process.env.XDG_DATA_HOME;
|
|
57
|
+
return join(xdg && xdg.length > 0 ? xdg : join(homedir(), ".local", "share"), "goose");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Absolute path to Goose's SQLite DB (override with GOOSE_DB_PATH). */
|
|
61
|
+
export function gooseDbPath(): string {
|
|
62
|
+
return process.env.GOOSE_DB_PATH || join(gooseHome(), "sessions", "sessions.db");
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Coerce a Goose timestamp to epoch ms. `messages.created_timestamp` is an
|
|
66
|
+
* INTEGER epoch (seconds or ms); `sessions.created_at`/`updated_at` are SQLite
|
|
67
|
+
* `CURRENT_TIMESTAMP` strings ("YYYY-MM-DD HH:MM:SS", UTC). */
|
|
68
|
+
export function gooseTimestampToMs(value: unknown): number {
|
|
69
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
70
|
+
if (value > 1e12) return value; // already ms
|
|
71
|
+
if (value > 1e9) return value * 1000; // seconds
|
|
72
|
+
}
|
|
73
|
+
if (typeof value === "string" && value.length > 0) {
|
|
74
|
+
// SQLite CURRENT_TIMESTAMP has no zone and is UTC — normalize to ISO-Z so
|
|
75
|
+
// Date.parse doesn't treat it as local time.
|
|
76
|
+
const iso = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(value)
|
|
77
|
+
? value.replace(" ", "T") + "Z"
|
|
78
|
+
: value;
|
|
79
|
+
const ms = Date.parse(iso);
|
|
80
|
+
if (!Number.isNaN(ms)) return ms;
|
|
81
|
+
}
|
|
82
|
+
return Date.now();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ── Parsing helpers ──
|
|
86
|
+
|
|
87
|
+
function safeJsonParse(s: unknown): unknown {
|
|
88
|
+
if (typeof s !== "string" || s.length === 0) return undefined;
|
|
89
|
+
try {
|
|
90
|
+
return JSON.parse(s);
|
|
91
|
+
} catch {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function isPlainObject(v: unknown): v is Record<string, unknown> {
|
|
97
|
+
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Text from a `content` field that may be a string or an array of
|
|
101
|
+
* `{ type:"text", text }` blocks. */
|
|
102
|
+
function extractText(content: unknown): string {
|
|
103
|
+
if (typeof content === "string") return content;
|
|
104
|
+
if (Array.isArray(content)) {
|
|
105
|
+
return content
|
|
106
|
+
.map((c) => (isPlainObject(c) && typeof c.text === "string" ? (c.text as string) : ""))
|
|
107
|
+
.filter(Boolean)
|
|
108
|
+
.join("\n");
|
|
109
|
+
}
|
|
110
|
+
return "";
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function toDate(value: unknown, fallbackMs: number): Date {
|
|
114
|
+
const ms = typeof value === "number" || typeof value === "string" ? gooseTimestampToMs(value) : NaN;
|
|
115
|
+
return Number.isNaN(ms) ? new Date(fallbackMs) : new Date(ms);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Pull `{ id, name, input }` from a Goose `toolRequest` block:
|
|
119
|
+
* `{id, toolCall:{status, value:{name, arguments}}}`. */
|
|
120
|
+
function extractToolRequest(
|
|
121
|
+
block: Record<string, unknown>,
|
|
122
|
+
idx: number,
|
|
123
|
+
): { id: string; name: string; input: Record<string, unknown> } {
|
|
124
|
+
const id = typeof block.id === "string" && block.id ? block.id : `goose-tool-${idx}`;
|
|
125
|
+
const toolCall = isPlainObject(block.toolCall) ? block.toolCall : {};
|
|
126
|
+
const value = isPlainObject(toolCall.value) ? toolCall.value : {};
|
|
127
|
+
const name = typeof value.name === "string" ? value.name : "tool";
|
|
128
|
+
const input = isPlainObject(value.arguments) ? value.arguments : {};
|
|
129
|
+
return { id, name, input };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Text of a Goose `toolResponse` block:
|
|
133
|
+
* `{id, toolResult:{status, value:{content:[{type:"text",text}], …}}}`. */
|
|
134
|
+
function extractToolResult(block: Record<string, unknown>): string {
|
|
135
|
+
const toolResult = isPlainObject(block.toolResult) ? block.toolResult : {};
|
|
136
|
+
const value = toolResult.value;
|
|
137
|
+
if (isPlainObject(value) && Array.isArray(value.content)) return extractText(value.content);
|
|
138
|
+
if (typeof value === "string") return value;
|
|
139
|
+
if (Array.isArray(value)) return extractText(value);
|
|
140
|
+
return "";
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// ── Pure parser: message rows → LogEntry[] ──
|
|
144
|
+
|
|
145
|
+
export interface GooseMessageRow {
|
|
146
|
+
role: string | null;
|
|
147
|
+
content_json: string | null;
|
|
148
|
+
created_timestamp: number | null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Convert Goose `messages` rows (in insertion order) into `LogEntry[]`. Each
|
|
153
|
+
* row's `content_json` is a typed-block array; `toolRequest` blocks become
|
|
154
|
+
* `tool_use` blocks on an assistant entry, and later `toolResponse` blocks
|
|
155
|
+
* (which arrive in `role:"user"` rows) attach as the matching tool_use's result
|
|
156
|
+
* by id. Pure — unit-testable with plain rows.
|
|
157
|
+
*/
|
|
158
|
+
export function gooseRowsToLogEntries(
|
|
159
|
+
rows: GooseMessageRow[],
|
|
160
|
+
source: LogSource = "session",
|
|
161
|
+
): LogEntry[] {
|
|
162
|
+
const entries: LogEntry[] = [];
|
|
163
|
+
const toolUseById = new Map<string, ToolUseBlock>();
|
|
164
|
+
const toolUseStartMs = new Map<string, number>();
|
|
165
|
+
const baseMs = Date.now();
|
|
166
|
+
|
|
167
|
+
for (let i = 0; i < rows.length; i++) {
|
|
168
|
+
const r = rows[i];
|
|
169
|
+
const parsed = safeJsonParse(r.content_json);
|
|
170
|
+
if (!Array.isArray(parsed)) continue;
|
|
171
|
+
|
|
172
|
+
const role = typeof r.role === "string" ? r.role : "system";
|
|
173
|
+
const date = toDate(r.created_timestamp, baseMs + i);
|
|
174
|
+
const timestamp = date.toISOString();
|
|
175
|
+
const raw: Record<string, unknown> = { uuid: `goose-${i}`, parentUuid: null };
|
|
176
|
+
const base = baseEntry(raw, timestamp, date, source);
|
|
177
|
+
|
|
178
|
+
const textParts: string[] = [];
|
|
179
|
+
const toolReqs: Record<string, unknown>[] = [];
|
|
180
|
+
const toolResps: Record<string, unknown>[] = [];
|
|
181
|
+
for (const b of parsed) {
|
|
182
|
+
if (!isPlainObject(b)) continue;
|
|
183
|
+
if (b.type === "text" && typeof b.text === "string") textParts.push(b.text);
|
|
184
|
+
else if (b.type === "toolRequest") toolReqs.push(b);
|
|
185
|
+
else if (b.type === "toolResponse") toolResps.push(b);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Attach tool results to their earlier tool_use blocks (results arrive in
|
|
189
|
+
// role:"user" rows, so this runs before we consider the row a user turn).
|
|
190
|
+
for (const tr of toolResps) {
|
|
191
|
+
const callId = typeof tr.id === "string" ? tr.id : undefined;
|
|
192
|
+
const block = callId ? toolUseById.get(callId) : undefined;
|
|
193
|
+
if (!block) continue;
|
|
194
|
+
const startMs = (callId && toolUseStartMs.get(callId)) || date.getTime();
|
|
195
|
+
const durationMs = Math.max(0, date.getTime() - startMs);
|
|
196
|
+
block.result = {
|
|
197
|
+
timestamp,
|
|
198
|
+
timestampFormatted: formatTimestamp(date),
|
|
199
|
+
content: extractToolResult(tr),
|
|
200
|
+
durationMs,
|
|
201
|
+
durationFormatted: formatDuration(durationMs),
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const text = textParts.join("\n").trim();
|
|
206
|
+
|
|
207
|
+
if (toolReqs.length > 0 || (role === "assistant" && text)) {
|
|
208
|
+
const blocks: ContentBlock[] = [];
|
|
209
|
+
if (text) blocks.push({ type: "text", text });
|
|
210
|
+
for (const req of toolReqs) {
|
|
211
|
+
const { id, name, input } = extractToolRequest(req, blocks.length);
|
|
212
|
+
const block: ToolUseBlock = { type: "tool_use", id, name, input };
|
|
213
|
+
blocks.push(block);
|
|
214
|
+
toolUseById.set(id, block);
|
|
215
|
+
toolUseStartMs.set(id, date.getTime());
|
|
216
|
+
}
|
|
217
|
+
if (blocks.length === 0) continue;
|
|
218
|
+
entries.push({
|
|
219
|
+
type: "assistant",
|
|
220
|
+
...base,
|
|
221
|
+
message: { role: "assistant", content: blocks },
|
|
222
|
+
} satisfies AssistantEntry);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (role === "user" && text) {
|
|
227
|
+
entries.push({
|
|
228
|
+
type: "user",
|
|
229
|
+
...base,
|
|
230
|
+
message: { role: "user", content: text },
|
|
231
|
+
} satisfies UserEntry);
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Pure tool-result rows (no text, no requests) produced no new entry above.
|
|
236
|
+
if (text) {
|
|
237
|
+
entries.push({ type: "system", ...base, raw } satisfies GenericEntry);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
entries.sort((a, b) => a.timestampMs - b.timestampMs);
|
|
242
|
+
return entries;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ── DB loader ──
|
|
246
|
+
|
|
247
|
+
export interface GooseSessionLogData {
|
|
248
|
+
entries: LogEntry[];
|
|
249
|
+
rawLines: Record<string, unknown>[];
|
|
250
|
+
cwd?: string;
|
|
251
|
+
filePath: string; // synthetic — goose keeps sessions in a DB; we use goose-db://<id>
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Load one session by ID from `sessions.db`. Returns `null` when the DB is
|
|
256
|
+
* unavailable or the session doesn't exist.
|
|
257
|
+
*/
|
|
258
|
+
export async function getGooseSessionLog(
|
|
259
|
+
sessionId: string,
|
|
260
|
+
): Promise<GooseSessionLogData | null> {
|
|
261
|
+
if (!sessionId || !GOOSE_SESSION_ID_RE.test(sessionId)) return null;
|
|
262
|
+
const db = await openSqliteReadonly(gooseDbPath());
|
|
263
|
+
if (!db) return null;
|
|
264
|
+
try {
|
|
265
|
+
const sessionRows = db.query<{ working_dir: string | null }>(
|
|
266
|
+
"SELECT working_dir FROM sessions WHERE id = ?",
|
|
267
|
+
[sessionId],
|
|
268
|
+
);
|
|
269
|
+
if (sessionRows.length === 0) return null;
|
|
270
|
+
const realCwd = sessionRows[0].working_dir;
|
|
271
|
+
|
|
272
|
+
const msgRows = db.query<GooseMessageRow>(
|
|
273
|
+
"SELECT role, content_json, created_timestamp FROM messages " +
|
|
274
|
+
"WHERE session_id = ? ORDER BY id ASC",
|
|
275
|
+
[sessionId],
|
|
276
|
+
);
|
|
277
|
+
const entries = gooseRowsToLogEntries(msgRows, "session");
|
|
278
|
+
const cwd = realCwd && realCwd.length > 0 ? realCwd : undefined;
|
|
279
|
+
return {
|
|
280
|
+
entries,
|
|
281
|
+
rawLines: msgRows as unknown as Record<string, unknown>[],
|
|
282
|
+
cwd,
|
|
283
|
+
filePath: `goose-db://${sessionId}`,
|
|
284
|
+
};
|
|
285
|
+
} catch {
|
|
286
|
+
return null;
|
|
287
|
+
} finally {
|
|
288
|
+
db.close();
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export const getCachedGooseSessionLog = runtimeCache(
|
|
293
|
+
(sessionId: string) => getGooseSessionLog(sessionId),
|
|
294
|
+
2,
|
|
295
|
+
{ maxSize: 50 },
|
|
296
|
+
);
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw (openclaw gateway) session enumeration — AUDIT-ONLY.
|
|
3
|
+
*
|
|
4
|
+
* Surfaces the on-disk transcripts (agents/<agentId>/sessions/<uuid>.jsonl) as
|
|
5
|
+
* synthetic dashboard "projects" grouped by agentId. The per-agent
|
|
6
|
+
* `sessions.json` index maps sessionKey → {sessionId, timestamps}; we read it to
|
|
7
|
+
* recover the sessionKey (which encodes the channel for gateway sessions) and a
|
|
8
|
+
* reliable last-activity time. Verified live against openclaw v2026.7.1.
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { runtimeCache } from "./runtime-cache";
|
|
13
|
+
import { listOpenClawTranscripts, openclawHome } from "./openclaw-sessions";
|
|
14
|
+
import type { ProjectFolder, SessionFile } from "./projects";
|
|
15
|
+
import { formatDate } from "./format-date";
|
|
16
|
+
|
|
17
|
+
export interface OpenClawSessionRef {
|
|
18
|
+
sessionId: string;
|
|
19
|
+
agentId: string;
|
|
20
|
+
/** Channel/source the session last ran in (from sessions.json metadata) —
|
|
21
|
+
* e.g. "telegram", "slack", or "local" for a CLI session. Drives grouping. */
|
|
22
|
+
channel: string;
|
|
23
|
+
/** Human-readable label from `origin.label` (e.g. "Chetan (@chhhee10) id:…"). */
|
|
24
|
+
label?: string;
|
|
25
|
+
/** Chat id (e.g. "telegram:8674922496") + type ("direct"/"group") for the
|
|
26
|
+
* gateway-metadata columns. */
|
|
27
|
+
chatId?: string;
|
|
28
|
+
chatType?: string;
|
|
29
|
+
mtimeMs: number;
|
|
30
|
+
sizeBytes: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface SessionIndexMeta {
|
|
34
|
+
lastMs?: number;
|
|
35
|
+
channel?: string;
|
|
36
|
+
chatType?: string;
|
|
37
|
+
label?: string;
|
|
38
|
+
chatId?: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function str(v: unknown): string | undefined {
|
|
42
|
+
return typeof v === "string" && v.length > 0 ? v : undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Read the per-agent sessions.json index → sessionId → routing metadata.
|
|
46
|
+
* OpenClaw routes gateway sessions through the agent's default key
|
|
47
|
+
* (`agent:<id>:main`) and records the channel in metadata fields
|
|
48
|
+
* (`lastChannel`, `chatType`, `origin.{label,provider,from}`, `lastTo`) rather
|
|
49
|
+
* than in the key — verified live against v2026.7.1. */
|
|
50
|
+
function readSessionsIndex(agentId: string): Map<string, SessionIndexMeta> {
|
|
51
|
+
const out = new Map<string, SessionIndexMeta>();
|
|
52
|
+
const indexPath = join(openclawHome(), "agents", agentId, "sessions", "sessions.json");
|
|
53
|
+
let raw: unknown;
|
|
54
|
+
try {
|
|
55
|
+
raw = JSON.parse(readFileSync(indexPath, "utf-8"));
|
|
56
|
+
} catch {
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
if (!raw || typeof raw !== "object") return out;
|
|
60
|
+
for (const v of Object.values(raw as Record<string, unknown>)) {
|
|
61
|
+
if (!v || typeof v !== "object") continue;
|
|
62
|
+
const e = v as Record<string, unknown>;
|
|
63
|
+
const sessionId = str(e.sessionId);
|
|
64
|
+
if (!sessionId) continue;
|
|
65
|
+
const origin = (e.origin && typeof e.origin === "object" ? e.origin : {}) as Record<string, unknown>;
|
|
66
|
+
const lastMs =
|
|
67
|
+
typeof e.lastInteractionAt === "number"
|
|
68
|
+
? e.lastInteractionAt
|
|
69
|
+
: typeof e.updatedAt === "number"
|
|
70
|
+
? (e.updatedAt as number)
|
|
71
|
+
: undefined;
|
|
72
|
+
out.set(sessionId, {
|
|
73
|
+
lastMs,
|
|
74
|
+
channel: str(e.lastChannel) ?? str(origin.provider) ?? str(origin.surface),
|
|
75
|
+
chatType: str(e.chatType) ?? str(origin.chatType),
|
|
76
|
+
label: str(origin.label),
|
|
77
|
+
chatId: str(e.lastTo) ?? str(origin.from),
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** List every OpenClaw session across all agents. Fail-open ([] on any error). */
|
|
84
|
+
export async function getOpenClawSessions(): Promise<OpenClawSessionRef[]> {
|
|
85
|
+
const transcripts = listOpenClawTranscripts();
|
|
86
|
+
const indexByAgent = new Map<string, Map<string, SessionIndexMeta>>();
|
|
87
|
+
const refs: OpenClawSessionRef[] = [];
|
|
88
|
+
for (const t of transcripts) {
|
|
89
|
+
let idx = indexByAgent.get(t.agentId);
|
|
90
|
+
if (!idx) {
|
|
91
|
+
idx = readSessionsIndex(t.agentId);
|
|
92
|
+
indexByAgent.set(t.agentId, idx);
|
|
93
|
+
}
|
|
94
|
+
const meta = idx.get(t.sessionId);
|
|
95
|
+
refs.push({
|
|
96
|
+
sessionId: t.sessionId,
|
|
97
|
+
agentId: t.agentId,
|
|
98
|
+
// Gateway sessions group by channel; CLI/local runs have none.
|
|
99
|
+
channel: meta?.channel ?? "local",
|
|
100
|
+
label: meta?.label,
|
|
101
|
+
chatType: meta?.chatType,
|
|
102
|
+
chatId: meta?.chatId,
|
|
103
|
+
mtimeMs: meta?.lastMs ?? t.mtimeMs,
|
|
104
|
+
sizeBytes: t.sizeBytes,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
refs.sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
108
|
+
return refs;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export const getCachedOpenClawSessions = runtimeCache(getOpenClawSessions, 2);
|
|
112
|
+
|
|
113
|
+
// ── Dashboard history browser (projects list + project-detail sessions) ──
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Surface OpenClaw sessions as synthetic "projects" grouped by **channel**
|
|
117
|
+
* (telegram/slack/…/local) — gateway sessions run per channel, not in a host
|
|
118
|
+
* repo. Mirrors Hermes's group-by-source. One ProjectFolder per channel; its
|
|
119
|
+
* `name` is `openclaw-<channel>`, reversed in `getOpenClawSessionsByEncodedName`.
|
|
120
|
+
*/
|
|
121
|
+
export async function getOpenClawProjects(): Promise<ProjectFolder[]> {
|
|
122
|
+
const sessions = await getOpenClawSessions();
|
|
123
|
+
const latestByChannel = new Map<string, number>();
|
|
124
|
+
for (const s of sessions) {
|
|
125
|
+
latestByChannel.set(s.channel, Math.max(latestByChannel.get(s.channel) ?? 0, s.mtimeMs));
|
|
126
|
+
}
|
|
127
|
+
const out: ProjectFolder[] = [];
|
|
128
|
+
for (const [channel, latest] of latestByChannel) {
|
|
129
|
+
const lastModified = new Date(latest);
|
|
130
|
+
out.push({
|
|
131
|
+
name: `openclaw-${channel}`,
|
|
132
|
+
path: `openclaw:${channel}`,
|
|
133
|
+
isDirectory: true,
|
|
134
|
+
lastModified,
|
|
135
|
+
lastModifiedFormatted: formatDate(lastModified),
|
|
136
|
+
cli: ["openclaw"],
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
out.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());
|
|
140
|
+
return out;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export interface OpenClawProjectByName {
|
|
144
|
+
cwd: string | null;
|
|
145
|
+
sessions: SessionFile[];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Resolve the OpenClaw sessions for a synthetic project name
|
|
149
|
+
* (`openclaw-<channel>`), for the project-detail page. Session names use the
|
|
150
|
+
* human-readable `origin.label` (e.g. "Chetan (@chhhee10) id:…") rather than
|
|
151
|
+
* the raw session key. */
|
|
152
|
+
export async function getOpenClawSessionsByEncodedName(
|
|
153
|
+
name: string,
|
|
154
|
+
): Promise<OpenClawProjectByName> {
|
|
155
|
+
if (!name.startsWith("openclaw-")) return { cwd: null, sessions: [] };
|
|
156
|
+
const channel = name.slice("openclaw-".length);
|
|
157
|
+
const sessions = await getOpenClawSessions();
|
|
158
|
+
const matched = sessions.filter((s) => s.channel === channel);
|
|
159
|
+
return {
|
|
160
|
+
cwd: `openclaw:${channel}`,
|
|
161
|
+
sessions: matched.map((s) => {
|
|
162
|
+
const lastModified = new Date(s.mtimeMs);
|
|
163
|
+
return {
|
|
164
|
+
name: s.label ?? s.chatId ?? s.sessionId,
|
|
165
|
+
path: s.sessionId,
|
|
166
|
+
lastModified,
|
|
167
|
+
lastModifiedFormatted: formatDate(lastModified),
|
|
168
|
+
sessionId: s.sessionId,
|
|
169
|
+
cli: "openclaw" as const,
|
|
170
|
+
channelId: s.chatId,
|
|
171
|
+
channelType: s.chatType,
|
|
172
|
+
};
|
|
173
|
+
}),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export const getCachedOpenClawProjects = runtimeCache(getOpenClawProjects, 2);
|
|
178
|
+
export const getCachedOpenClawSessionsByEncodedName = runtimeCache(
|
|
179
|
+
(name: string) => getOpenClawSessionsByEncodedName(name),
|
|
180
|
+
2,
|
|
181
|
+
{ maxSize: 50 },
|
|
182
|
+
);
|