@phnx-labs/agents-cli 0.1.0 → 1.14.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/CHANGELOG.md +7 -1
- package/README.md +283 -372
- package/dist/commands/alias.d.ts +11 -0
- package/dist/commands/alias.js +117 -0
- package/dist/commands/beta.d.ts +2 -0
- package/dist/commands/beta.js +53 -0
- package/dist/commands/cloud.d.ts +8 -1
- package/dist/commands/cloud.js +108 -22
- package/dist/commands/commands.d.ts +9 -1
- package/dist/commands/commands.js +24 -172
- package/dist/commands/daemon.d.ts +8 -1
- package/dist/commands/daemon.js +13 -5
- package/dist/commands/doctor.d.ts +15 -0
- package/dist/commands/doctor.js +132 -0
- package/dist/commands/drive.d.ts +8 -1
- package/dist/commands/drive.js +20 -3
- package/dist/commands/exec.d.ts +8 -1
- package/dist/commands/exec.js +96 -27
- package/dist/commands/factory.d.ts +19 -0
- package/dist/commands/factory.js +71 -0
- package/dist/commands/fork.d.ts +8 -1
- package/dist/commands/fork.js +11 -4
- package/dist/commands/hooks.d.ts +9 -1
- package/dist/commands/hooks.js +30 -182
- package/dist/commands/init.d.ts +15 -1
- package/dist/commands/init.js +168 -74
- package/dist/commands/mcp.d.ts +9 -1
- package/dist/commands/mcp.js +11 -7
- package/dist/commands/models.d.ts +8 -1
- package/dist/commands/models.js +16 -4
- package/dist/commands/packages.d.ts +8 -1
- package/dist/commands/packages.js +13 -7
- package/dist/commands/permissions.d.ts +9 -1
- package/dist/commands/permissions.js +3 -3
- package/dist/commands/plugins.d.ts +8 -1
- package/dist/commands/plugins.js +13 -2
- package/dist/commands/profiles.d.ts +9 -1
- package/dist/commands/profiles.js +56 -7
- package/dist/commands/prune.d.ts +22 -0
- package/dist/commands/prune.js +191 -0
- package/dist/commands/pty.d.ts +1 -1
- package/dist/commands/pty.js +2 -1
- package/dist/commands/pull.d.ts +8 -1
- package/dist/commands/pull.js +58 -128
- package/dist/commands/refresh-memory.d.ts +7 -1
- package/dist/commands/refresh-memory.js +7 -1
- package/dist/commands/repo.d.ts +15 -0
- package/dist/commands/repo.js +570 -0
- package/dist/commands/resource-view.d.ts +10 -3
- package/dist/commands/resource-view.js +18 -5
- package/dist/commands/routines.d.ts +8 -1
- package/dist/commands/routines.js +17 -4
- package/dist/commands/rules.d.ts +9 -1
- package/dist/commands/rules.js +16 -11
- package/dist/commands/secrets.d.ts +8 -1
- package/dist/commands/secrets.js +235 -63
- package/dist/commands/sessions-picker.d.ts +2 -1
- package/dist/commands/sessions-picker.js +88 -11
- package/dist/commands/sessions-tail.d.ts +19 -0
- package/dist/commands/sessions-tail.js +235 -0
- package/dist/commands/sessions.d.ts +2 -1
- package/dist/commands/sessions.js +188 -7
- package/dist/commands/skills.d.ts +9 -1
- package/dist/commands/skills.js +28 -178
- package/dist/commands/status.d.ts +7 -1
- package/dist/commands/status.js +7 -1
- package/dist/commands/subagents.d.ts +8 -1
- package/dist/commands/subagents.js +11 -1
- package/dist/commands/sync.d.ts +8 -1
- package/dist/commands/sync.js +8 -1
- package/dist/commands/teams-picker.d.ts +4 -1
- package/dist/commands/teams-picker.js +55 -3
- package/dist/commands/teams.d.ts +15 -1
- package/dist/commands/teams.js +323 -69
- package/dist/commands/usage.d.ts +11 -0
- package/dist/commands/usage.js +60 -0
- package/dist/commands/utils.d.ts +6 -1
- package/dist/commands/utils.js +6 -1
- package/dist/commands/versions.d.ts +8 -1
- package/dist/commands/versions.js +4 -3
- package/dist/commands/view.d.ts +47 -2
- package/dist/commands/view.js +317 -24
- package/dist/index.d.ts +7 -2
- package/dist/index.js +172 -34
- package/dist/lib/acp/client.d.ts +31 -0
- package/dist/lib/acp/client.js +117 -0
- package/dist/lib/acp/harnesses.d.ts +26 -0
- package/dist/lib/acp/harnesses.js +65 -0
- package/dist/lib/acp/run.d.ts +18 -0
- package/dist/lib/acp/run.js +39 -0
- package/dist/lib/agents.d.ts +74 -2
- package/dist/lib/agents.js +197 -21
- package/dist/lib/artifact-actions.d.ts +8 -4
- package/dist/lib/artifact-actions.js +8 -6
- package/dist/lib/auto-pull-worker.d.ts +11 -0
- package/dist/lib/auto-pull-worker.js +121 -0
- package/dist/lib/auto-pull.d.ts +31 -0
- package/dist/lib/auto-pull.js +97 -0
- package/dist/lib/beta.d.ts +23 -0
- package/dist/lib/beta.js +90 -0
- package/dist/lib/capabilities.d.ts +29 -0
- package/dist/lib/capabilities.js +74 -0
- package/dist/lib/cloud/codex.d.ts +9 -3
- package/dist/lib/cloud/codex.js +53 -13
- package/dist/lib/cloud/factory.d.ts +8 -3
- package/dist/lib/cloud/factory.js +19 -3
- package/dist/lib/cloud/registry.d.ts +10 -1
- package/dist/lib/cloud/registry.js +14 -3
- package/dist/lib/cloud/rush.d.ts +63 -3
- package/dist/lib/cloud/rush.js +273 -20
- package/dist/lib/cloud/store.d.ts +13 -1
- package/dist/lib/cloud/store.js +23 -4
- package/dist/lib/cloud/stream.d.ts +6 -1
- package/dist/lib/cloud/stream.js +95 -39
- package/dist/lib/cloud/types.d.ts +153 -8
- package/dist/lib/cloud/types.js +34 -2
- package/dist/lib/command-skills.d.ts +20 -0
- package/dist/lib/command-skills.js +142 -0
- package/dist/lib/commands.d.ts +22 -2
- package/dist/lib/commands.js +51 -11
- package/dist/lib/convert.d.ts +10 -1
- package/dist/lib/convert.js +9 -1
- package/dist/lib/daemon.d.ts +21 -1
- package/dist/lib/daemon.js +97 -4
- package/dist/lib/drive-sync.d.ts +18 -1
- package/dist/lib/drive-sync.js +57 -15
- package/dist/lib/exec.d.ts +23 -6
- package/dist/lib/exec.js +53 -17
- package/dist/lib/fs-walk.d.ts +2 -0
- package/dist/lib/fs-walk.js +40 -0
- package/dist/lib/fuzzy.d.ts +53 -0
- package/dist/lib/fuzzy.js +72 -0
- package/dist/lib/gemini-settings.d.ts +4 -0
- package/dist/lib/gemini-settings.js +33 -0
- package/dist/lib/git.d.ts +12 -2
- package/dist/lib/git.js +17 -6
- package/dist/lib/help.d.ts +20 -1
- package/dist/lib/help.js +45 -6
- package/dist/lib/hooks/match.d.ts +32 -0
- package/dist/lib/hooks/match.js +120 -0
- package/dist/lib/hooks.d.ts +17 -4
- package/dist/lib/hooks.js +119 -101
- package/dist/lib/manifest.d.ts +6 -1
- package/dist/lib/manifest.js +15 -4
- package/dist/lib/markdown.d.ts +0 -1
- package/dist/lib/markdown.js +6 -1
- package/dist/lib/mcp.d.ts +0 -1
- package/dist/lib/mcp.js +29 -33
- package/dist/lib/memory-compile.d.ts +13 -3
- package/dist/lib/memory-compile.js +31 -9
- package/dist/lib/memory.d.ts +14 -7
- package/dist/lib/memory.js +67 -38
- package/dist/lib/migrate.d.ts +8 -0
- package/dist/lib/migrate.js +85 -0
- package/dist/lib/models.d.ts +10 -4
- package/dist/lib/models.js +36 -15
- package/dist/lib/onepassword.d.ts +63 -0
- package/dist/lib/onepassword.js +186 -0
- package/dist/lib/paths.d.ts +8 -0
- package/dist/lib/paths.js +20 -0
- package/dist/lib/permissions.d.ts +24 -2
- package/dist/lib/permissions.js +117 -48
- package/dist/lib/picker.d.ts +10 -1
- package/dist/lib/picker.js +15 -1
- package/dist/lib/plugins.d.ts +7 -1
- package/dist/lib/plugins.js +10 -1
- package/dist/lib/profiles-presets.d.ts +10 -1
- package/dist/lib/profiles-presets.js +9 -1
- package/dist/lib/profiles.d.ts +35 -1
- package/dist/lib/profiles.js +36 -15
- package/dist/lib/pty-client.d.ts +1 -1
- package/dist/lib/pty-client.js +0 -1
- package/dist/lib/pty-server.d.ts +16 -2
- package/dist/lib/pty-server.js +92 -3
- package/dist/lib/registry.d.ts +23 -3
- package/dist/lib/registry.js +153 -8
- package/dist/lib/resources.d.ts +28 -1
- package/dist/lib/resources.js +79 -1
- package/dist/lib/rotate.d.ts +40 -13
- package/dist/lib/rotate.js +238 -40
- package/dist/lib/routines.d.ts +29 -1
- package/dist/lib/routines.js +32 -5
- package/dist/lib/runner.d.ts +14 -1
- package/dist/lib/runner.js +22 -3
- package/dist/lib/sandbox.d.ts +16 -1
- package/dist/lib/sandbox.js +39 -16
- package/dist/lib/scheduler.d.ts +8 -1
- package/dist/lib/scheduler.js +8 -1
- package/dist/lib/secrets/AgentsKeychain.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/AgentsKeychain.app/Contents/Info.plist +22 -0
- package/dist/lib/secrets/AgentsKeychain.app/Contents/MacOS/AgentsKeychain +0 -0
- package/dist/lib/secrets/AgentsKeychain.app/Contents/_CodeSignature/CodeResources +123 -0
- package/dist/lib/secrets/AgentsKeychain.app/Contents/embedded.provisionprofile +0 -0
- package/dist/lib/{secrets-bundles.d.ts → secrets/bundles.d.ts} +12 -2
- package/dist/lib/{secrets-bundles.js → secrets/bundles.js} +38 -17
- package/dist/lib/secrets/index.d.ts +55 -0
- package/dist/lib/secrets/index.js +211 -0
- package/dist/lib/secrets/profiles.d.ts +10 -0
- package/dist/lib/secrets/profiles.js +13 -0
- package/dist/lib/session/active.d.ts +43 -0
- package/dist/lib/session/active.js +392 -0
- package/dist/lib/session/artifacts.d.ts +12 -1
- package/dist/lib/session/artifacts.js +25 -5
- package/dist/lib/session/cloud.d.ts +30 -0
- package/dist/lib/session/cloud.js +121 -0
- package/dist/lib/session/db.d.ts +23 -2
- package/dist/lib/session/db.js +76 -12
- package/dist/lib/session/discover.d.ts +19 -4
- package/dist/lib/session/discover.js +344 -48
- package/dist/lib/session/parse.d.ts +28 -1
- package/dist/lib/session/parse.js +267 -9
- package/dist/lib/session/prompt.d.ts +9 -1
- package/dist/lib/session/prompt.js +17 -3
- package/dist/lib/session/render.d.ts +13 -1
- package/dist/lib/session/render.js +20 -1
- package/dist/lib/session/team-filter.d.ts +9 -1
- package/dist/lib/session/team-filter.js +11 -2
- package/dist/lib/session/types.d.ts +16 -2
- package/dist/lib/session/types.js +10 -2
- package/dist/lib/shims.d.ts +64 -5
- package/dist/lib/shims.js +309 -47
- package/dist/lib/skills.d.ts +27 -2
- package/dist/lib/skills.js +127 -65
- package/dist/lib/sqlite.d.ts +43 -0
- package/dist/lib/sqlite.js +94 -0
- package/dist/lib/state.d.ts +112 -27
- package/dist/lib/state.js +320 -148
- package/dist/lib/subagents.d.ts +9 -1
- package/dist/lib/subagents.js +70 -63
- package/dist/lib/sync-manifest.d.ts +81 -0
- package/dist/lib/sync-manifest.js +450 -0
- package/dist/lib/teams/agents.d.ts +103 -5
- package/dist/lib/teams/agents.js +414 -91
- package/dist/lib/teams/api.d.ts +26 -3
- package/dist/lib/teams/api.js +63 -3
- package/dist/lib/teams/debug.d.ts +6 -1
- package/dist/lib/teams/debug.js +6 -1
- package/dist/lib/teams/file_ops.d.ts +7 -1
- package/dist/lib/teams/file_ops.js +7 -1
- package/dist/lib/teams/index.d.ts +15 -0
- package/dist/lib/teams/index.js +14 -0
- package/dist/lib/teams/parsers.d.ts +4 -1
- package/dist/lib/teams/parsers.js +11 -1
- package/dist/lib/teams/persistence.d.ts +15 -1
- package/dist/lib/teams/persistence.js +102 -20
- package/dist/lib/teams/registry.d.ts +12 -1
- package/dist/lib/teams/registry.js +116 -33
- package/dist/lib/teams/summarizer.d.ts +15 -1
- package/dist/lib/teams/summarizer.js +14 -1
- package/dist/lib/teams/supervisor.d.ts +48 -0
- package/dist/lib/teams/supervisor.js +73 -0
- package/dist/lib/template.d.ts +8 -6
- package/dist/lib/template.js +8 -6
- package/dist/lib/types.d.ts +147 -8
- package/dist/lib/types.js +26 -3
- package/dist/lib/usage.d.ts +32 -1
- package/dist/lib/usage.js +70 -6
- package/dist/lib/version-duplicates.d.ts +21 -0
- package/dist/lib/version-duplicates.js +90 -0
- package/dist/lib/versions.d.ts +33 -4
- package/dist/lib/versions.js +376 -108
- package/package.json +32 -17
- package/scripts/postinstall.js +126 -30
- package/dist/commands/__tests__/sessions.test.d.ts +0 -2
- package/dist/commands/__tests__/sessions.test.d.ts.map +0 -1
- package/dist/commands/__tests__/sessions.test.js +0 -636
- package/dist/commands/__tests__/sessions.test.js.map +0 -1
- package/dist/commands/cloud.d.ts.map +0 -1
- package/dist/commands/cloud.js.map +0 -1
- package/dist/commands/commands.d.ts.map +0 -1
- package/dist/commands/commands.js.map +0 -1
- package/dist/commands/daemon.d.ts.map +0 -1
- package/dist/commands/daemon.js.map +0 -1
- package/dist/commands/drive.d.ts.map +0 -1
- package/dist/commands/drive.js.map +0 -1
- package/dist/commands/exec.d.ts.map +0 -1
- package/dist/commands/exec.js.map +0 -1
- package/dist/commands/fork.d.ts.map +0 -1
- package/dist/commands/fork.js.map +0 -1
- package/dist/commands/hooks.d.ts.map +0 -1
- package/dist/commands/hooks.js.map +0 -1
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/mcp.d.ts.map +0 -1
- package/dist/commands/mcp.js.map +0 -1
- package/dist/commands/models.d.ts.map +0 -1
- package/dist/commands/models.js.map +0 -1
- package/dist/commands/packages.d.ts.map +0 -1
- package/dist/commands/packages.js.map +0 -1
- package/dist/commands/permissions.d.ts.map +0 -1
- package/dist/commands/permissions.js.map +0 -1
- package/dist/commands/plugins.d.ts.map +0 -1
- package/dist/commands/plugins.js.map +0 -1
- package/dist/commands/profiles.d.ts.map +0 -1
- package/dist/commands/profiles.js.map +0 -1
- package/dist/commands/pty.d.ts.map +0 -1
- package/dist/commands/pty.js.map +0 -1
- package/dist/commands/pull.d.ts.map +0 -1
- package/dist/commands/pull.js.map +0 -1
- package/dist/commands/push.d.ts +0 -3
- package/dist/commands/push.d.ts.map +0 -1
- package/dist/commands/push.js +0 -180
- package/dist/commands/push.js.map +0 -1
- package/dist/commands/refresh-memory.d.ts.map +0 -1
- package/dist/commands/refresh-memory.js.map +0 -1
- package/dist/commands/resource-view.d.ts.map +0 -1
- package/dist/commands/resource-view.js.map +0 -1
- package/dist/commands/routines.d.ts.map +0 -1
- package/dist/commands/routines.js.map +0 -1
- package/dist/commands/rules.d.ts.map +0 -1
- package/dist/commands/rules.js.map +0 -1
- package/dist/commands/secrets.d.ts.map +0 -1
- package/dist/commands/secrets.js.map +0 -1
- package/dist/commands/sessions-picker.d.ts.map +0 -1
- package/dist/commands/sessions-picker.js.map +0 -1
- package/dist/commands/sessions.d.ts.map +0 -1
- package/dist/commands/sessions.js.map +0 -1
- package/dist/commands/skills.d.ts.map +0 -1
- package/dist/commands/skills.js.map +0 -1
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/subagents.d.ts.map +0 -1
- package/dist/commands/subagents.js.map +0 -1
- package/dist/commands/sync.d.ts.map +0 -1
- package/dist/commands/sync.js.map +0 -1
- package/dist/commands/teams-picker.d.ts.map +0 -1
- package/dist/commands/teams-picker.js.map +0 -1
- package/dist/commands/teams.d.ts.map +0 -1
- package/dist/commands/teams.js.map +0 -1
- package/dist/commands/utils.d.ts.map +0 -1
- package/dist/commands/utils.js.map +0 -1
- package/dist/commands/versions.d.ts.map +0 -1
- package/dist/commands/versions.js.map +0 -1
- package/dist/commands/view.d.ts.map +0 -1
- package/dist/commands/view.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/__tests__/bugfixes.test.d.ts +0 -2
- package/dist/lib/__tests__/bugfixes.test.d.ts.map +0 -1
- package/dist/lib/__tests__/bugfixes.test.js +0 -192
- package/dist/lib/__tests__/bugfixes.test.js.map +0 -1
- package/dist/lib/__tests__/exec.test.d.ts +0 -2
- package/dist/lib/__tests__/exec.test.d.ts.map +0 -1
- package/dist/lib/__tests__/exec.test.js +0 -446
- package/dist/lib/__tests__/exec.test.js.map +0 -1
- package/dist/lib/__tests__/git-sync.test.d.ts +0 -2
- package/dist/lib/__tests__/git-sync.test.d.ts.map +0 -1
- package/dist/lib/__tests__/git-sync.test.js +0 -138
- package/dist/lib/__tests__/git-sync.test.js.map +0 -1
- package/dist/lib/__tests__/hooks.test.d.ts +0 -2
- package/dist/lib/__tests__/hooks.test.d.ts.map +0 -1
- package/dist/lib/__tests__/hooks.test.js +0 -203
- package/dist/lib/__tests__/hooks.test.js.map +0 -1
- package/dist/lib/__tests__/memory-compile.test.d.ts +0 -2
- package/dist/lib/__tests__/memory-compile.test.d.ts.map +0 -1
- package/dist/lib/__tests__/memory-compile.test.js +0 -95
- package/dist/lib/__tests__/memory-compile.test.js.map +0 -1
- package/dist/lib/__tests__/models.test.d.ts +0 -2
- package/dist/lib/__tests__/models.test.d.ts.map +0 -1
- package/dist/lib/__tests__/models.test.js +0 -239
- package/dist/lib/__tests__/models.test.js.map +0 -1
- package/dist/lib/__tests__/rotate.test.d.ts +0 -2
- package/dist/lib/__tests__/rotate.test.d.ts.map +0 -1
- package/dist/lib/__tests__/rotate.test.js +0 -80
- package/dist/lib/__tests__/rotate.test.js.map +0 -1
- package/dist/lib/__tests__/secrets-bundles.test.d.ts +0 -2
- package/dist/lib/__tests__/secrets-bundles.test.d.ts.map +0 -1
- package/dist/lib/__tests__/secrets-bundles.test.js +0 -104
- package/dist/lib/__tests__/secrets-bundles.test.js.map +0 -1
- package/dist/lib/__tests__/secrets.test.d.ts +0 -2
- package/dist/lib/__tests__/secrets.test.d.ts.map +0 -1
- package/dist/lib/__tests__/secrets.test.js +0 -90
- package/dist/lib/__tests__/secrets.test.js.map +0 -1
- package/dist/lib/__tests__/shims.test.d.ts +0 -2
- package/dist/lib/__tests__/shims.test.d.ts.map +0 -1
- package/dist/lib/__tests__/shims.test.js +0 -39
- package/dist/lib/__tests__/shims.test.js.map +0 -1
- package/dist/lib/__tests__/usage.test.d.ts +0 -2
- package/dist/lib/__tests__/usage.test.d.ts.map +0 -1
- package/dist/lib/__tests__/usage.test.js +0 -220
- package/dist/lib/__tests__/usage.test.js.map +0 -1
- package/dist/lib/__tests__/versions.test.d.ts +0 -2
- package/dist/lib/__tests__/versions.test.d.ts.map +0 -1
- package/dist/lib/__tests__/versions.test.js +0 -63
- package/dist/lib/__tests__/versions.test.js.map +0 -1
- package/dist/lib/agents.d.ts.map +0 -1
- package/dist/lib/agents.js.map +0 -1
- package/dist/lib/artifact-actions.d.ts.map +0 -1
- package/dist/lib/artifact-actions.js.map +0 -1
- package/dist/lib/cloud/codex.d.ts.map +0 -1
- package/dist/lib/cloud/codex.js.map +0 -1
- package/dist/lib/cloud/factory.d.ts.map +0 -1
- package/dist/lib/cloud/factory.js.map +0 -1
- package/dist/lib/cloud/registry.d.ts.map +0 -1
- package/dist/lib/cloud/registry.js.map +0 -1
- package/dist/lib/cloud/rush.d.ts.map +0 -1
- package/dist/lib/cloud/rush.js.map +0 -1
- package/dist/lib/cloud/store.d.ts.map +0 -1
- package/dist/lib/cloud/store.js.map +0 -1
- package/dist/lib/cloud/stream.d.ts.map +0 -1
- package/dist/lib/cloud/stream.js.map +0 -1
- package/dist/lib/cloud/types.d.ts.map +0 -1
- package/dist/lib/cloud/types.js.map +0 -1
- package/dist/lib/commands.d.ts.map +0 -1
- package/dist/lib/commands.js.map +0 -1
- package/dist/lib/convert.d.ts.map +0 -1
- package/dist/lib/convert.js.map +0 -1
- package/dist/lib/daemon.d.ts.map +0 -1
- package/dist/lib/daemon.js.map +0 -1
- package/dist/lib/drive-sync.d.ts.map +0 -1
- package/dist/lib/drive-sync.js.map +0 -1
- package/dist/lib/exec.d.ts.map +0 -1
- package/dist/lib/exec.js.map +0 -1
- package/dist/lib/factory.d.ts +0 -57
- package/dist/lib/factory.d.ts.map +0 -1
- package/dist/lib/factory.js +0 -110
- package/dist/lib/factory.js.map +0 -1
- package/dist/lib/git.d.ts.map +0 -1
- package/dist/lib/git.js.map +0 -1
- package/dist/lib/help.d.ts.map +0 -1
- package/dist/lib/help.js.map +0 -1
- package/dist/lib/hooks.d.ts.map +0 -1
- package/dist/lib/hooks.js.map +0 -1
- package/dist/lib/manifest.d.ts.map +0 -1
- package/dist/lib/manifest.js.map +0 -1
- package/dist/lib/markdown.d.ts.map +0 -1
- package/dist/lib/markdown.js.map +0 -1
- package/dist/lib/mcp.d.ts.map +0 -1
- package/dist/lib/mcp.js.map +0 -1
- package/dist/lib/memory-compile.d.ts.map +0 -1
- package/dist/lib/memory-compile.js.map +0 -1
- package/dist/lib/memory.d.ts.map +0 -1
- package/dist/lib/memory.js.map +0 -1
- package/dist/lib/models.d.ts.map +0 -1
- package/dist/lib/models.js.map +0 -1
- package/dist/lib/permissions.d.ts.map +0 -1
- package/dist/lib/permissions.js.map +0 -1
- package/dist/lib/picker.d.ts.map +0 -1
- package/dist/lib/picker.js.map +0 -1
- package/dist/lib/plugins.d.ts.map +0 -1
- package/dist/lib/plugins.js.map +0 -1
- package/dist/lib/profiles-keychain.d.ts +0 -3
- package/dist/lib/profiles-keychain.d.ts.map +0 -1
- package/dist/lib/profiles-keychain.js +0 -10
- package/dist/lib/profiles-keychain.js.map +0 -1
- package/dist/lib/profiles-presets.d.ts.map +0 -1
- package/dist/lib/profiles-presets.js.map +0 -1
- package/dist/lib/profiles.d.ts.map +0 -1
- package/dist/lib/profiles.js.map +0 -1
- package/dist/lib/pty-client.d.ts.map +0 -1
- package/dist/lib/pty-client.js.map +0 -1
- package/dist/lib/pty-server.d.ts.map +0 -1
- package/dist/lib/pty-server.js.map +0 -1
- package/dist/lib/registry.d.ts.map +0 -1
- package/dist/lib/registry.js.map +0 -1
- package/dist/lib/resources.d.ts.map +0 -1
- package/dist/lib/resources.js.map +0 -1
- package/dist/lib/rotate.d.ts.map +0 -1
- package/dist/lib/rotate.js.map +0 -1
- package/dist/lib/routines.d.ts.map +0 -1
- package/dist/lib/routines.js.map +0 -1
- package/dist/lib/runner.d.ts.map +0 -1
- package/dist/lib/runner.js.map +0 -1
- package/dist/lib/sandbox.d.ts.map +0 -1
- package/dist/lib/sandbox.js.map +0 -1
- package/dist/lib/scheduler.d.ts.map +0 -1
- package/dist/lib/scheduler.js.map +0 -1
- package/dist/lib/secrets-bundles.d.ts.map +0 -1
- package/dist/lib/secrets-bundles.js.map +0 -1
- package/dist/lib/secrets.d.ts +0 -27
- package/dist/lib/secrets.d.ts.map +0 -1
- package/dist/lib/secrets.js +0 -127
- package/dist/lib/secrets.js.map +0 -1
- package/dist/lib/session/__tests__/db.test.d.ts +0 -2
- package/dist/lib/session/__tests__/db.test.d.ts.map +0 -1
- package/dist/lib/session/__tests__/db.test.js +0 -54
- package/dist/lib/session/__tests__/db.test.js.map +0 -1
- package/dist/lib/session/__tests__/discover.test.d.ts +0 -2
- package/dist/lib/session/__tests__/discover.test.d.ts.map +0 -1
- package/dist/lib/session/__tests__/discover.test.js +0 -63
- package/dist/lib/session/__tests__/discover.test.js.map +0 -1
- package/dist/lib/session/__tests__/prompt.test.d.ts +0 -2
- package/dist/lib/session/__tests__/prompt.test.d.ts.map +0 -1
- package/dist/lib/session/__tests__/prompt.test.js +0 -44
- package/dist/lib/session/__tests__/prompt.test.js.map +0 -1
- package/dist/lib/session/__tests__/render.test.d.ts +0 -2
- package/dist/lib/session/__tests__/render.test.d.ts.map +0 -1
- package/dist/lib/session/__tests__/render.test.js +0 -602
- package/dist/lib/session/__tests__/render.test.js.map +0 -1
- package/dist/lib/session/artifacts.d.ts.map +0 -1
- package/dist/lib/session/artifacts.js.map +0 -1
- package/dist/lib/session/db.d.ts.map +0 -1
- package/dist/lib/session/db.js.map +0 -1
- package/dist/lib/session/discover.d.ts.map +0 -1
- package/dist/lib/session/discover.js.map +0 -1
- package/dist/lib/session/parse.d.ts.map +0 -1
- package/dist/lib/session/parse.js.map +0 -1
- package/dist/lib/session/prompt.d.ts.map +0 -1
- package/dist/lib/session/prompt.js.map +0 -1
- package/dist/lib/session/prompt.test.d.ts +0 -2
- package/dist/lib/session/prompt.test.d.ts.map +0 -1
- package/dist/lib/session/prompt.test.js +0 -57
- package/dist/lib/session/prompt.test.js.map +0 -1
- package/dist/lib/session/render.d.ts.map +0 -1
- package/dist/lib/session/render.js.map +0 -1
- package/dist/lib/session/team-filter.d.ts.map +0 -1
- package/dist/lib/session/team-filter.js.map +0 -1
- package/dist/lib/session/team-filter.test.d.ts +0 -2
- package/dist/lib/session/team-filter.test.d.ts.map +0 -1
- package/dist/lib/session/team-filter.test.js +0 -157
- package/dist/lib/session/team-filter.test.js.map +0 -1
- package/dist/lib/session/types.d.ts.map +0 -1
- package/dist/lib/session/types.js.map +0 -1
- package/dist/lib/shims.d.ts.map +0 -1
- package/dist/lib/shims.js.map +0 -1
- package/dist/lib/skills.d.ts.map +0 -1
- package/dist/lib/skills.js.map +0 -1
- package/dist/lib/state.d.ts.map +0 -1
- package/dist/lib/state.js.map +0 -1
- package/dist/lib/subagents.d.ts.map +0 -1
- package/dist/lib/subagents.js.map +0 -1
- package/dist/lib/teams/agents.d.ts.map +0 -1
- package/dist/lib/teams/agents.js.map +0 -1
- package/dist/lib/teams/api.d.ts.map +0 -1
- package/dist/lib/teams/api.js.map +0 -1
- package/dist/lib/teams/cloud.d.ts +0 -11
- package/dist/lib/teams/cloud.d.ts.map +0 -1
- package/dist/lib/teams/cloud.js +0 -169
- package/dist/lib/teams/cloud.js.map +0 -1
- package/dist/lib/teams/debug.d.ts.map +0 -1
- package/dist/lib/teams/debug.js.map +0 -1
- package/dist/lib/teams/file_ops.d.ts.map +0 -1
- package/dist/lib/teams/file_ops.js.map +0 -1
- package/dist/lib/teams/parsers.d.ts.map +0 -1
- package/dist/lib/teams/parsers.js.map +0 -1
- package/dist/lib/teams/persistence.d.ts.map +0 -1
- package/dist/lib/teams/persistence.js.map +0 -1
- package/dist/lib/teams/ralph.d.ts +0 -8
- package/dist/lib/teams/ralph.d.ts.map +0 -1
- package/dist/lib/teams/ralph.js +0 -59
- package/dist/lib/teams/ralph.js.map +0 -1
- package/dist/lib/teams/registry.d.ts.map +0 -1
- package/dist/lib/teams/registry.js.map +0 -1
- package/dist/lib/teams/summarizer.d.ts.map +0 -1
- package/dist/lib/teams/summarizer.js.map +0 -1
- package/dist/lib/template.d.ts.map +0 -1
- package/dist/lib/template.js.map +0 -1
- package/dist/lib/types.d.ts.map +0 -1
- package/dist/lib/types.js.map +0 -1
- package/dist/lib/usage.d.ts.map +0 -1
- package/dist/lib/usage.js.map +0 -1
- package/dist/lib/versions.d.ts.map +0 -1
- package/dist/lib/versions.js.map +0 -1
- package/scripts/rebuild-sqlite.sh +0 -46
|
@@ -1,16 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session discovery across Claude, Codex, Gemini, OpenCode, and OpenClaw.
|
|
3
|
+
*
|
|
4
|
+
* Performs incremental scans: each agent's session files are stat'd and compared
|
|
5
|
+
* to a scan-stamp ledger in SQLite. Only files whose mtime or size changed since
|
|
6
|
+
* the last run are re-parsed. All metadata is upserted into the sessions DB so
|
|
7
|
+
* subsequent queries are served entirely from the cache.
|
|
8
|
+
*/
|
|
1
9
|
import * as fs from 'fs';
|
|
2
10
|
import * as path from 'path';
|
|
3
11
|
import * as os from 'os';
|
|
4
12
|
import * as crypto from 'crypto';
|
|
5
13
|
import * as readline from 'readline';
|
|
6
|
-
import {
|
|
14
|
+
import { execFile } from 'child_process';
|
|
15
|
+
import { promisify } from 'util';
|
|
16
|
+
import { getAgentsDir } from '../state.js';
|
|
17
|
+
const execFileAsync = promisify(execFile);
|
|
7
18
|
import { AGENTS, getCliVersion } from '../agents.js';
|
|
19
|
+
import { walkForFiles } from '../fs-walk.js';
|
|
8
20
|
import { getConfigSymlinkVersion } from '../shims.js';
|
|
9
21
|
import { SESSION_AGENTS } from './types.js';
|
|
10
22
|
import { extractSessionTopic } from './prompt.js';
|
|
11
23
|
import { getDB, getScanStampByPath, getScanStampsForPaths, recordScans, syncLabels, upsertSessionsBatch, querySessions, countSessions, ftsSearch, } from './db.js';
|
|
12
24
|
const HOME = os.homedir();
|
|
13
|
-
const AGENTS_DIR =
|
|
25
|
+
const AGENTS_DIR = getAgentsDir();
|
|
26
|
+
const RUSH_SESSIONS_DIR = path.join(HOME, '.rush', 'sessions');
|
|
27
|
+
const HERMES_SESSIONS_DIR = path.join(HOME, '.hermes', 'sessions');
|
|
14
28
|
/** How long OpenClaw channel/cron snapshots stay valid before we re-shell-out. */
|
|
15
29
|
const OPENCLAW_TTL_MS = 60_000;
|
|
16
30
|
let cachedOpenClawWorkspaces = null;
|
|
@@ -32,6 +46,8 @@ export async function discoverSessions(options) {
|
|
|
32
46
|
case 'gemini': return scanGeminiIncremental(onProgress);
|
|
33
47
|
case 'opencode': return scanOpenCodeIncremental();
|
|
34
48
|
case 'openclaw': return scanOpenClawIncremental();
|
|
49
|
+
case 'rush': return scanRushIncremental(onProgress);
|
|
50
|
+
case 'hermes': return scanHermesIncremental(onProgress);
|
|
35
51
|
}
|
|
36
52
|
}));
|
|
37
53
|
const sessions = querySessions(buildQueryOptions(options, agents, { includeLimit: true }));
|
|
@@ -46,6 +62,7 @@ export function countSessionsInScope(options) {
|
|
|
46
62
|
const agents = options.agent ? [options.agent] : SESSION_AGENTS;
|
|
47
63
|
return countSessions(buildQueryOptions(options, agents, { includeLimit: false }));
|
|
48
64
|
}
|
|
65
|
+
/** Translate DiscoverOptions into the QueryOptions shape expected by the DB layer. */
|
|
49
66
|
function buildQueryOptions(options, agents, opts) {
|
|
50
67
|
const projectQuery = options?.project?.trim();
|
|
51
68
|
const sinceMs = options?.since ? parseTimeFilter(options.since) : undefined;
|
|
@@ -55,7 +72,9 @@ function buildQueryOptions(options, agents, opts) {
|
|
|
55
72
|
if (options?.cwdPrefix) {
|
|
56
73
|
cwdPrefixFilter = normalizeCwd(options.cwdPrefix);
|
|
57
74
|
}
|
|
58
|
-
else if (!options?.all && !projectQuery) {
|
|
75
|
+
else if (!options?.all && !projectQuery && options?.agent !== 'rush' && options?.agent !== 'hermes') {
|
|
76
|
+
// Rush and Hermes sessions are cloud/gateway-bound and have no cwd — skip
|
|
77
|
+
// cwd filtering when the user explicitly asked for them.
|
|
59
78
|
cwdFilter = normalizeCwd(options?.cwd || process.cwd());
|
|
60
79
|
}
|
|
61
80
|
return {
|
|
@@ -72,6 +91,7 @@ function buildQueryOptions(options, agents, opts) {
|
|
|
72
91
|
onlyTeamOrigin: options?.onlyTeamOrigin,
|
|
73
92
|
};
|
|
74
93
|
}
|
|
94
|
+
/** Resolve and canonicalize a working directory path (follows symlinks). */
|
|
75
95
|
function normalizeCwd(cwd) {
|
|
76
96
|
if (!cwd)
|
|
77
97
|
return '';
|
|
@@ -188,6 +208,7 @@ export function getAgentSessionDirs(agent, subdir) {
|
|
|
188
208
|
// Claude account info
|
|
189
209
|
// ---------------------------------------------------------------------------
|
|
190
210
|
let cachedClaudeAccount;
|
|
211
|
+
/** Read the Claude OAuth account email from .claude.json across all version homes. */
|
|
191
212
|
function getClaudeAccount() {
|
|
192
213
|
if (cachedClaudeAccount !== undefined)
|
|
193
214
|
return cachedClaudeAccount || undefined;
|
|
@@ -234,7 +255,7 @@ function getClaudeAccount() {
|
|
|
234
255
|
* For sessionId collisions (re-resume of the same session), prefer the most
|
|
235
256
|
* recent startedAt.
|
|
236
257
|
*/
|
|
237
|
-
function buildClaudeLabelMap() {
|
|
258
|
+
export function buildClaudeLabelMap() {
|
|
238
259
|
const map = new Map();
|
|
239
260
|
const dir = path.join(HOME, '.claude', 'sessions');
|
|
240
261
|
if (!fs.existsSync(dir))
|
|
@@ -265,6 +286,7 @@ function buildClaudeLabelMap() {
|
|
|
265
286
|
out.set(sid, label);
|
|
266
287
|
return out;
|
|
267
288
|
}
|
|
289
|
+
/** Incrementally re-scan changed Claude session files and upsert into the DB. */
|
|
268
290
|
async function scanClaudeIncremental(onProgress) {
|
|
269
291
|
const account = getClaudeAccount();
|
|
270
292
|
const labelMap = buildClaudeLabelMap();
|
|
@@ -331,6 +353,7 @@ async function scanClaudeIncremental(onProgress) {
|
|
|
331
353
|
if (labelMap.size > 0)
|
|
332
354
|
syncLabels(labelMap);
|
|
333
355
|
}
|
|
356
|
+
/** Stream-parse a single Claude JSONL file to extract session metadata. */
|
|
334
357
|
async function readClaudeMeta(filePath, sessionId, account, label) {
|
|
335
358
|
const scan = await scanClaudeSession(filePath);
|
|
336
359
|
const isTeamOrigin = scan.entrypoint === 'sdk-cli';
|
|
@@ -377,6 +400,7 @@ async function readClaudeMeta(filePath, sessionId, account, label) {
|
|
|
377
400
|
// Codex account info
|
|
378
401
|
// ---------------------------------------------------------------------------
|
|
379
402
|
let cachedCodexAccount;
|
|
403
|
+
/** Extract the Codex account email from the JWT id_token in auth.json. */
|
|
380
404
|
function getCodexAccount() {
|
|
381
405
|
if (cachedCodexAccount !== undefined)
|
|
382
406
|
return cachedCodexAccount || undefined;
|
|
@@ -415,6 +439,7 @@ function getCodexAccount() {
|
|
|
415
439
|
// ---------------------------------------------------------------------------
|
|
416
440
|
// Codex
|
|
417
441
|
// ---------------------------------------------------------------------------
|
|
442
|
+
/** Incrementally re-scan changed Codex session files and upsert into the DB. */
|
|
418
443
|
async function scanCodexIncremental(onProgress) {
|
|
419
444
|
const account = getCodexAccount();
|
|
420
445
|
const currentVersion = await getCurrentAgentVersion('codex');
|
|
@@ -453,6 +478,7 @@ async function scanCodexIncremental(onProgress) {
|
|
|
453
478
|
upsertSessionsBatch(entries);
|
|
454
479
|
recordScans(touched);
|
|
455
480
|
}
|
|
481
|
+
/** Stream-parse a single Codex JSONL file to extract session metadata. */
|
|
456
482
|
async function readCodexMeta(filePath, account, currentVersion) {
|
|
457
483
|
const scan = await scanCodexSession(filePath);
|
|
458
484
|
const sessionId = scan.sessionId || '';
|
|
@@ -463,7 +489,9 @@ async function readCodexMeta(filePath, account, currentVersion) {
|
|
|
463
489
|
id: sessionId,
|
|
464
490
|
shortId: sessionId.slice(0, 8),
|
|
465
491
|
agent: 'codex',
|
|
466
|
-
|
|
492
|
+
// Codex `session_meta` only carries the start time; use file mtime when
|
|
493
|
+
// it's newer so long-running sessions register as recently active.
|
|
494
|
+
timestamp: pickLatestCodexTimestamp(scan.timestamp, filePath),
|
|
467
495
|
project: cwd ? path.basename(cwd) : undefined,
|
|
468
496
|
cwd,
|
|
469
497
|
filePath,
|
|
@@ -476,9 +504,30 @@ async function readCodexMeta(filePath, account, currentVersion) {
|
|
|
476
504
|
};
|
|
477
505
|
return { meta, content: scan.contentText || '' };
|
|
478
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* Codex writes `session_meta` (with the start timestamp) on the first line of a
|
|
509
|
+
* rollout and never updates it. For long-running sessions that's stale by
|
|
510
|
+
* hours — `--since 2h` would drop a session still being actively written.
|
|
511
|
+
* Compare against the file's mtime and use whichever is newer.
|
|
512
|
+
*/
|
|
513
|
+
function pickLatestCodexTimestamp(metaTimestamp, filePath) {
|
|
514
|
+
const fallback = new Date().toISOString();
|
|
515
|
+
let mtimeIso = null;
|
|
516
|
+
try {
|
|
517
|
+
mtimeIso = fs.statSync(filePath).mtime.toISOString();
|
|
518
|
+
}
|
|
519
|
+
catch {
|
|
520
|
+
/* file vanished between scan and stat */
|
|
521
|
+
}
|
|
522
|
+
const candidates = [metaTimestamp, mtimeIso].filter((v) => !!v);
|
|
523
|
+
if (candidates.length === 0)
|
|
524
|
+
return fallback;
|
|
525
|
+
return candidates.reduce((best, cur) => (cur > best ? cur : best));
|
|
526
|
+
}
|
|
479
527
|
// ---------------------------------------------------------------------------
|
|
480
528
|
// Gemini
|
|
481
529
|
// ---------------------------------------------------------------------------
|
|
530
|
+
/** Incrementally re-scan changed Gemini session files and upsert into the DB. */
|
|
482
531
|
async function scanGeminiIncremental(onProgress) {
|
|
483
532
|
const currentVersion = await getCurrentAgentVersion('gemini');
|
|
484
533
|
const projectMap = buildGeminiProjectMap();
|
|
@@ -540,6 +589,7 @@ async function scanGeminiIncremental(onProgress) {
|
|
|
540
589
|
upsertSessionsBatch(entries);
|
|
541
590
|
recordScans(touched);
|
|
542
591
|
}
|
|
592
|
+
/** Parse a single Gemini JSON session file to extract session metadata. */
|
|
543
593
|
function readGeminiMeta(filePath, hashDir, projectMap, currentVersion) {
|
|
544
594
|
let session;
|
|
545
595
|
try {
|
|
@@ -604,6 +654,7 @@ function readGeminiMeta(filePath, hashDir, projectMap, currentVersion) {
|
|
|
604
654
|
};
|
|
605
655
|
return { meta, content: userTexts.join('\n') };
|
|
606
656
|
}
|
|
657
|
+
/** Build a hash-to-project mapping from Gemini's projects.json and history directories. */
|
|
607
658
|
function buildGeminiProjectMap() {
|
|
608
659
|
const map = new Map();
|
|
609
660
|
const projectsJsonPath = path.join(HOME, '.gemini', 'projects.json');
|
|
@@ -657,12 +708,17 @@ function buildGeminiProjectMap() {
|
|
|
657
708
|
// ---------------------------------------------------------------------------
|
|
658
709
|
const OPENCODE_DB = path.join(HOME, '.local', 'share', 'opencode', 'opencode.db');
|
|
659
710
|
let cachedOpenCodeAccount;
|
|
660
|
-
|
|
711
|
+
/** Query the active OpenCode account email from its SQLite database. */
|
|
712
|
+
async function getOpenCodeAccount() {
|
|
661
713
|
if (cachedOpenCodeAccount !== undefined)
|
|
662
714
|
return cachedOpenCodeAccount || undefined;
|
|
663
715
|
try {
|
|
664
716
|
if (fs.existsSync(OPENCODE_DB)) {
|
|
665
|
-
const
|
|
717
|
+
const { stdout } = await execFileAsync('sqlite3', [
|
|
718
|
+
OPENCODE_DB,
|
|
719
|
+
'SELECT email FROM control_account WHERE active=1 LIMIT 1;',
|
|
720
|
+
], { encoding: 'utf-8' });
|
|
721
|
+
const out = stdout.trim();
|
|
666
722
|
if (out) {
|
|
667
723
|
cachedOpenCodeAccount = out;
|
|
668
724
|
return out;
|
|
@@ -673,6 +729,7 @@ function getOpenCodeAccount() {
|
|
|
673
729
|
cachedOpenCodeAccount = '';
|
|
674
730
|
return undefined;
|
|
675
731
|
}
|
|
732
|
+
/** Scan OpenCode sessions from its SQLite database when the DB file has changed. */
|
|
676
733
|
async function scanOpenCodeIncremental() {
|
|
677
734
|
if (!fs.existsSync(OPENCODE_DB))
|
|
678
735
|
return;
|
|
@@ -689,7 +746,7 @@ async function scanOpenCodeIncremental() {
|
|
|
689
746
|
if (prev && prev.fileMtimeMs === currentScan.fileMtimeMs && prev.fileSize === currentScan.fileSize) {
|
|
690
747
|
return;
|
|
691
748
|
}
|
|
692
|
-
const account = getOpenCodeAccount();
|
|
749
|
+
const account = await getOpenCodeAccount();
|
|
693
750
|
const currentVersion = await getCurrentAgentVersion('opencode');
|
|
694
751
|
try {
|
|
695
752
|
const query = `
|
|
@@ -722,7 +779,11 @@ async function scanOpenCodeIncremental() {
|
|
|
722
779
|
ORDER BY time_created DESC
|
|
723
780
|
LIMIT 1000;
|
|
724
781
|
`.replace(/\n/g, ' ');
|
|
725
|
-
const
|
|
782
|
+
const { stdout: out } = await execFileAsync('sqlite3', ['-separator', '|||', OPENCODE_DB, query], {
|
|
783
|
+
encoding: 'utf-8',
|
|
784
|
+
timeout: 5000,
|
|
785
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
786
|
+
});
|
|
726
787
|
const entries = [];
|
|
727
788
|
for (const line of out.split('\n')) {
|
|
728
789
|
if (!line.trim())
|
|
@@ -765,10 +826,11 @@ async function scanOpenCodeIncremental() {
|
|
|
765
826
|
// ---------------------------------------------------------------------------
|
|
766
827
|
// OpenClaw
|
|
767
828
|
// ---------------------------------------------------------------------------
|
|
829
|
+
/** Scan active OpenClaw channels and cron jobs via the openclaw CLI. */
|
|
768
830
|
async function scanOpenClawIncremental() {
|
|
769
831
|
// Check if openclaw is installed — silently skip if not.
|
|
770
832
|
try {
|
|
771
|
-
|
|
833
|
+
await execFileAsync('which', ['openclaw']);
|
|
772
834
|
}
|
|
773
835
|
catch {
|
|
774
836
|
return;
|
|
@@ -786,9 +848,8 @@ async function scanOpenClawIncremental() {
|
|
|
786
848
|
const scan = { fileMtimeMs: now, fileSize: 0 };
|
|
787
849
|
const entries = [];
|
|
788
850
|
try {
|
|
789
|
-
const output =
|
|
851
|
+
const { stdout: output } = await execFileAsync('openclaw', ['channels', 'status'], {
|
|
790
852
|
encoding: 'utf-8',
|
|
791
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
792
853
|
});
|
|
793
854
|
for (const line of output.split('\n')) {
|
|
794
855
|
const match = line.match(/^-\s+\w+\s+(\S+)\s+\((\w+)\):\s*(.+)/);
|
|
@@ -817,9 +878,8 @@ async function scanOpenClawIncremental() {
|
|
|
817
878
|
/* channels command failed */
|
|
818
879
|
}
|
|
819
880
|
try {
|
|
820
|
-
const output =
|
|
881
|
+
const { stdout: output } = await execFileAsync('openclaw', ['cron', 'list'], {
|
|
821
882
|
encoding: 'utf-8',
|
|
822
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
823
883
|
});
|
|
824
884
|
const lines = output.split('\n');
|
|
825
885
|
for (let i = 1; i < lines.length; i++) {
|
|
@@ -856,6 +916,255 @@ async function scanOpenClawIncremental() {
|
|
|
856
916
|
upsertSessionsBatch(entries);
|
|
857
917
|
db.prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES ('openclaw_last_scan_ms', ?)`).run(String(Date.now()));
|
|
858
918
|
}
|
|
919
|
+
/** Incrementally re-scan changed Rush session files and upsert into the DB. */
|
|
920
|
+
async function scanRushIncremental(onProgress) {
|
|
921
|
+
if (!fs.existsSync(RUSH_SESSIONS_DIR))
|
|
922
|
+
return;
|
|
923
|
+
const filePaths = [];
|
|
924
|
+
let dirNames;
|
|
925
|
+
try {
|
|
926
|
+
dirNames = fs.readdirSync(RUSH_SESSIONS_DIR);
|
|
927
|
+
}
|
|
928
|
+
catch {
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
for (const dirName of dirNames) {
|
|
932
|
+
const sessionDir = path.join(RUSH_SESSIONS_DIR, dirName);
|
|
933
|
+
const stat = safeStatSync(sessionDir);
|
|
934
|
+
if (!stat?.isDirectory())
|
|
935
|
+
continue;
|
|
936
|
+
const messagesPath = path.join(sessionDir, 'messages.jsonl');
|
|
937
|
+
if (!fs.existsSync(messagesPath))
|
|
938
|
+
continue;
|
|
939
|
+
filePaths.push(messagesPath);
|
|
940
|
+
}
|
|
941
|
+
const changed = filterChangedFiles(filePaths);
|
|
942
|
+
if (changed.length === 0)
|
|
943
|
+
return;
|
|
944
|
+
onProgress?.({ agent: 'rush', parsed: 0, total: changed.length });
|
|
945
|
+
const entries = [];
|
|
946
|
+
const touched = [];
|
|
947
|
+
let parsed = 0;
|
|
948
|
+
for (const { filePath, scan } of changed) {
|
|
949
|
+
try {
|
|
950
|
+
const sessionId = path.basename(path.dirname(filePath));
|
|
951
|
+
const result = await readRushMeta(filePath, sessionId);
|
|
952
|
+
if (result) {
|
|
953
|
+
entries.push({ meta: result.meta, content: result.content, scan });
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
touched.push({ filePath, scan });
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
catch {
|
|
960
|
+
touched.push({ filePath, scan });
|
|
961
|
+
}
|
|
962
|
+
parsed++;
|
|
963
|
+
onProgress?.({ agent: 'rush', parsed, total: changed.length });
|
|
964
|
+
}
|
|
965
|
+
upsertSessionsBatch(entries);
|
|
966
|
+
recordScans(touched);
|
|
967
|
+
}
|
|
968
|
+
/** Stream-parse a single Rush messages.jsonl file to extract session metadata. */
|
|
969
|
+
async function readRushMeta(filePath, sessionId) {
|
|
970
|
+
const scan = await scanRushSession(filePath);
|
|
971
|
+
const stat = safeStatSync(filePath);
|
|
972
|
+
const timestamp = scan.timestamp
|
|
973
|
+
|| (stat ? stat.mtime.toISOString() : new Date().toISOString());
|
|
974
|
+
const shortId = sessionId.replace(/^session_/, '').slice(0, 8);
|
|
975
|
+
const meta = {
|
|
976
|
+
id: sessionId,
|
|
977
|
+
shortId,
|
|
978
|
+
agent: 'rush',
|
|
979
|
+
timestamp,
|
|
980
|
+
project: scan.agentId,
|
|
981
|
+
filePath,
|
|
982
|
+
topic: scan.topic,
|
|
983
|
+
messageCount: scan.messageCount,
|
|
984
|
+
};
|
|
985
|
+
return { meta, content: scan.contentText || '' };
|
|
986
|
+
}
|
|
987
|
+
/** Stream a Rush messages.jsonl file and extract scan-level metadata. */
|
|
988
|
+
async function scanRushSession(filePath) {
|
|
989
|
+
const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });
|
|
990
|
+
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
991
|
+
let timestamp;
|
|
992
|
+
let topic;
|
|
993
|
+
let agentId;
|
|
994
|
+
let messageCount = 0;
|
|
995
|
+
const userTexts = [];
|
|
996
|
+
try {
|
|
997
|
+
for await (const line of rl) {
|
|
998
|
+
if (!line.trim())
|
|
999
|
+
continue;
|
|
1000
|
+
let parsed;
|
|
1001
|
+
try {
|
|
1002
|
+
parsed = JSON.parse(line);
|
|
1003
|
+
}
|
|
1004
|
+
catch {
|
|
1005
|
+
continue;
|
|
1006
|
+
}
|
|
1007
|
+
if (!timestamp && typeof parsed.created_at === 'string') {
|
|
1008
|
+
timestamp = parsed.created_at;
|
|
1009
|
+
}
|
|
1010
|
+
if (!agentId && typeof parsed.agent_id === 'string') {
|
|
1011
|
+
agentId = parsed.agent_id;
|
|
1012
|
+
}
|
|
1013
|
+
if (parsed.type !== 'message')
|
|
1014
|
+
continue;
|
|
1015
|
+
const text = typeof parsed.content?.text === 'string' ? parsed.content.text.trim() : '';
|
|
1016
|
+
if (!text)
|
|
1017
|
+
continue;
|
|
1018
|
+
const cleaned = text
|
|
1019
|
+
.replace(/^<user_input>/, '')
|
|
1020
|
+
.replace(/<\/user_input>$/, '')
|
|
1021
|
+
.trim();
|
|
1022
|
+
if (!cleaned)
|
|
1023
|
+
continue;
|
|
1024
|
+
if (parsed.role === 'system' && cleaned === 'execution_start')
|
|
1025
|
+
continue;
|
|
1026
|
+
messageCount++;
|
|
1027
|
+
if (parsed.role === 'user') {
|
|
1028
|
+
userTexts.push(cleaned);
|
|
1029
|
+
if (!topic)
|
|
1030
|
+
topic = extractSessionTopic(cleaned);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
finally {
|
|
1035
|
+
rl.close();
|
|
1036
|
+
stream.destroy();
|
|
1037
|
+
}
|
|
1038
|
+
return {
|
|
1039
|
+
timestamp,
|
|
1040
|
+
topic,
|
|
1041
|
+
agentId,
|
|
1042
|
+
messageCount,
|
|
1043
|
+
contentText: userTexts.length > 0 ? userTexts.join('\n') : undefined,
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
// ---------------------------------------------------------------------------
|
|
1047
|
+
// Hermes
|
|
1048
|
+
//
|
|
1049
|
+
// Hermes sessions live at ~/.hermes/sessions/session_<id>.json (one JSON
|
|
1050
|
+
// file per session). Shape:
|
|
1051
|
+
// { session_id, model, platform, session_start, last_updated,
|
|
1052
|
+
// system_prompt, message_count, messages: [{role, content}, ...] }
|
|
1053
|
+
// request_dump_*.json files in the same dir are per-turn debug dumps — skip.
|
|
1054
|
+
// Hermes is a gateway/API agent, so cwd is left unset.
|
|
1055
|
+
// ---------------------------------------------------------------------------
|
|
1056
|
+
/** Incrementally re-scan changed Hermes session files and upsert into the DB. */
|
|
1057
|
+
async function scanHermesIncremental(onProgress) {
|
|
1058
|
+
if (!fs.existsSync(HERMES_SESSIONS_DIR))
|
|
1059
|
+
return;
|
|
1060
|
+
let entries;
|
|
1061
|
+
try {
|
|
1062
|
+
entries = fs.readdirSync(HERMES_SESSIONS_DIR);
|
|
1063
|
+
}
|
|
1064
|
+
catch {
|
|
1065
|
+
return;
|
|
1066
|
+
}
|
|
1067
|
+
const filePaths = [];
|
|
1068
|
+
for (const name of entries) {
|
|
1069
|
+
if (!name.startsWith('session_') || !name.endsWith('.json'))
|
|
1070
|
+
continue;
|
|
1071
|
+
filePaths.push(path.join(HERMES_SESSIONS_DIR, name));
|
|
1072
|
+
}
|
|
1073
|
+
const changed = filterChangedFiles(filePaths);
|
|
1074
|
+
if (changed.length === 0)
|
|
1075
|
+
return;
|
|
1076
|
+
onProgress?.({ agent: 'hermes', parsed: 0, total: changed.length });
|
|
1077
|
+
const scanEntries = [];
|
|
1078
|
+
const touched = [];
|
|
1079
|
+
const seen = new Set();
|
|
1080
|
+
let parsed = 0;
|
|
1081
|
+
for (const { filePath, scan } of changed) {
|
|
1082
|
+
try {
|
|
1083
|
+
const result = readHermesMeta(filePath);
|
|
1084
|
+
if (result && !seen.has(result.meta.id)) {
|
|
1085
|
+
seen.add(result.meta.id);
|
|
1086
|
+
scanEntries.push({ meta: result.meta, content: result.content, scan });
|
|
1087
|
+
}
|
|
1088
|
+
else {
|
|
1089
|
+
touched.push({ filePath, scan });
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
catch {
|
|
1093
|
+
touched.push({ filePath, scan });
|
|
1094
|
+
}
|
|
1095
|
+
parsed++;
|
|
1096
|
+
onProgress?.({ agent: 'hermes', parsed, total: changed.length });
|
|
1097
|
+
}
|
|
1098
|
+
upsertSessionsBatch(scanEntries);
|
|
1099
|
+
recordScans(touched);
|
|
1100
|
+
}
|
|
1101
|
+
/** Parse a single Hermes session JSON file to extract session metadata. */
|
|
1102
|
+
function readHermesMeta(filePath) {
|
|
1103
|
+
let session;
|
|
1104
|
+
try {
|
|
1105
|
+
session = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
1106
|
+
}
|
|
1107
|
+
catch {
|
|
1108
|
+
return null;
|
|
1109
|
+
}
|
|
1110
|
+
const sessionId = typeof session.session_id === 'string' ? session.session_id : '';
|
|
1111
|
+
if (!sessionId)
|
|
1112
|
+
return null;
|
|
1113
|
+
const messages = Array.isArray(session.messages) ? session.messages : [];
|
|
1114
|
+
const userTexts = [];
|
|
1115
|
+
let topic;
|
|
1116
|
+
let messageCount = 0;
|
|
1117
|
+
for (const msg of messages) {
|
|
1118
|
+
const text = extractHermesMessageText(msg?.content);
|
|
1119
|
+
if (!text)
|
|
1120
|
+
continue;
|
|
1121
|
+
messageCount++;
|
|
1122
|
+
if (msg?.role === 'user') {
|
|
1123
|
+
userTexts.push(text);
|
|
1124
|
+
if (!topic)
|
|
1125
|
+
topic = extractSessionTopic(text);
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
const stat = safeStatSync(filePath);
|
|
1129
|
+
const timestamp = typeof session.last_updated === 'string'
|
|
1130
|
+
? session.last_updated
|
|
1131
|
+
: typeof session.session_start === 'string'
|
|
1132
|
+
? session.session_start
|
|
1133
|
+
: stat ? stat.mtime.toISOString() : new Date().toISOString();
|
|
1134
|
+
const shortId = sessionId.replace(/^api-/, '').slice(0, 8);
|
|
1135
|
+
const model = typeof session.model === 'string' ? session.model : undefined;
|
|
1136
|
+
const platform = typeof session.platform === 'string' ? session.platform : undefined;
|
|
1137
|
+
const meta = {
|
|
1138
|
+
id: sessionId,
|
|
1139
|
+
shortId,
|
|
1140
|
+
agent: 'hermes',
|
|
1141
|
+
timestamp,
|
|
1142
|
+
project: platform,
|
|
1143
|
+
filePath,
|
|
1144
|
+
version: model,
|
|
1145
|
+
topic,
|
|
1146
|
+
messageCount: messageCount || (typeof session.message_count === 'number' ? session.message_count : undefined),
|
|
1147
|
+
};
|
|
1148
|
+
return { meta, content: userTexts.join('\n') };
|
|
1149
|
+
}
|
|
1150
|
+
/** Extract plain text from a Hermes message content field (string or list of parts). */
|
|
1151
|
+
function extractHermesMessageText(content) {
|
|
1152
|
+
if (typeof content === 'string')
|
|
1153
|
+
return content.trim();
|
|
1154
|
+
if (!Array.isArray(content))
|
|
1155
|
+
return '';
|
|
1156
|
+
return content
|
|
1157
|
+
.map((part) => {
|
|
1158
|
+
if (typeof part === 'string')
|
|
1159
|
+
return part;
|
|
1160
|
+
if (typeof part?.text === 'string')
|
|
1161
|
+
return part.text;
|
|
1162
|
+
return '';
|
|
1163
|
+
})
|
|
1164
|
+
.join('\n')
|
|
1165
|
+
.trim();
|
|
1166
|
+
}
|
|
1167
|
+
/** Stream a Claude JSONL file and extract scan-level metadata (timestamp, cwd, topic, tokens). */
|
|
859
1168
|
async function scanClaudeSession(filePath) {
|
|
860
1169
|
const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });
|
|
861
1170
|
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
@@ -937,6 +1246,7 @@ async function scanClaudeSession(filePath) {
|
|
|
937
1246
|
contentText: userTexts.length > 0 ? userTexts.join('\n') : undefined,
|
|
938
1247
|
};
|
|
939
1248
|
}
|
|
1249
|
+
/** Stream a Codex JSONL file and extract scan-level metadata (session ID, cwd, topic, tokens). */
|
|
940
1250
|
async function scanCodexSession(filePath) {
|
|
941
1251
|
const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });
|
|
942
1252
|
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
@@ -1007,6 +1317,7 @@ async function scanCodexSession(filePath) {
|
|
|
1007
1317
|
contentText: userTexts.length > 0 ? userTexts.join('\n') : undefined,
|
|
1008
1318
|
};
|
|
1009
1319
|
}
|
|
1320
|
+
/** Resolve the working directory for an OpenClaw agent from its workspace config. */
|
|
1010
1321
|
function getOpenClawSessionCwd(agentId) {
|
|
1011
1322
|
const workspace = agentId ? getOpenClawWorkspaceMap().get(agentId) : undefined;
|
|
1012
1323
|
if (workspace)
|
|
@@ -1014,6 +1325,7 @@ function getOpenClawSessionCwd(agentId) {
|
|
|
1014
1325
|
const configDir = AGENTS.openclaw.configDir;
|
|
1015
1326
|
return safeRealpathSync(configDir) || configDir;
|
|
1016
1327
|
}
|
|
1328
|
+
/** Build a cached map of OpenClaw agent ID to workspace path from openclaw.json. */
|
|
1017
1329
|
function getOpenClawWorkspaceMap() {
|
|
1018
1330
|
if (cachedOpenClawWorkspaces)
|
|
1019
1331
|
return cachedOpenClawWorkspaces;
|
|
@@ -1040,6 +1352,7 @@ function getOpenClawWorkspaceMap() {
|
|
|
1040
1352
|
// ---------------------------------------------------------------------------
|
|
1041
1353
|
// Utilities
|
|
1042
1354
|
// ---------------------------------------------------------------------------
|
|
1355
|
+
/** Read up to maxLines non-empty lines from the beginning of a file. */
|
|
1043
1356
|
export function readFirstLines(filePath, maxLines) {
|
|
1044
1357
|
return new Promise((resolve) => {
|
|
1045
1358
|
const lines = [];
|
|
@@ -1058,41 +1371,11 @@ export function readFirstLines(filePath, maxLines) {
|
|
|
1058
1371
|
rl.on('error', () => resolve(lines));
|
|
1059
1372
|
});
|
|
1060
1373
|
}
|
|
1061
|
-
/**
|
|
1062
|
-
* Walk a directory recursively for files with a given extension.
|
|
1063
|
-
*/
|
|
1064
|
-
export function walkForFiles(dir, ext, limit) {
|
|
1065
|
-
const results = [];
|
|
1066
|
-
function walk(d, depth) {
|
|
1067
|
-
if (depth > 5)
|
|
1068
|
-
return;
|
|
1069
|
-
let entries;
|
|
1070
|
-
try {
|
|
1071
|
-
entries = fs.readdirSync(d);
|
|
1072
|
-
}
|
|
1073
|
-
catch {
|
|
1074
|
-
return;
|
|
1075
|
-
}
|
|
1076
|
-
for (const entry of entries) {
|
|
1077
|
-
const full = path.join(d, entry);
|
|
1078
|
-
const stat = safeStatSync(full);
|
|
1079
|
-
if (!stat)
|
|
1080
|
-
continue;
|
|
1081
|
-
if (stat.isDirectory()) {
|
|
1082
|
-
walk(full, depth + 1);
|
|
1083
|
-
}
|
|
1084
|
-
else if (entry.endsWith(ext)) {
|
|
1085
|
-
results.push({ path: full, mtime: stat.mtimeMs });
|
|
1086
|
-
}
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
walk(dir, 0);
|
|
1090
|
-
results.sort((a, b) => b.mtime - a.mtime);
|
|
1091
|
-
return results.slice(0, limit).map(r => r.path);
|
|
1092
|
-
}
|
|
1374
|
+
/** Compute the SHA-256 hex digest of a string. */
|
|
1093
1375
|
function sha256(input) {
|
|
1094
1376
|
return crypto.createHash('sha256').update(input).digest('hex');
|
|
1095
1377
|
}
|
|
1378
|
+
/** Stat a path, returning null on any error. */
|
|
1096
1379
|
function safeStatSync(p) {
|
|
1097
1380
|
try {
|
|
1098
1381
|
return fs.statSync(p);
|
|
@@ -1101,6 +1384,7 @@ function safeStatSync(p) {
|
|
|
1101
1384
|
return null;
|
|
1102
1385
|
}
|
|
1103
1386
|
}
|
|
1387
|
+
/** Resolve a path to its real path, returning null on any error. */
|
|
1104
1388
|
function safeRealpathSync(p) {
|
|
1105
1389
|
try {
|
|
1106
1390
|
return fs.realpathSync(p);
|
|
@@ -1109,6 +1393,7 @@ function safeRealpathSync(p) {
|
|
|
1109
1393
|
return null;
|
|
1110
1394
|
}
|
|
1111
1395
|
}
|
|
1396
|
+
/** Extract meaningful user text from a Claude JSONL user event, skipping meta and local-command messages. */
|
|
1112
1397
|
function extractClaudeUserText(parsed) {
|
|
1113
1398
|
if (parsed.isMeta === true)
|
|
1114
1399
|
return undefined;
|
|
@@ -1127,9 +1412,11 @@ function extractClaudeUserText(parsed) {
|
|
|
1127
1412
|
return undefined;
|
|
1128
1413
|
return text;
|
|
1129
1414
|
}
|
|
1415
|
+
/** Check whether a message is a local-command wrapper rather than real user input. */
|
|
1130
1416
|
function isLocalCommandMessage(text) {
|
|
1131
1417
|
return /<local-command-caveat>|<bash-(input|stdout|stderr)>/i.test(text);
|
|
1132
1418
|
}
|
|
1419
|
+
/** Sum all token usage fields from a Claude assistant message's usage object. */
|
|
1133
1420
|
function getClaudeUsageTotal(usage) {
|
|
1134
1421
|
if (!usage || typeof usage !== 'object')
|
|
1135
1422
|
return null;
|
|
@@ -1140,6 +1427,7 @@ function getClaudeUsageTotal(usage) {
|
|
|
1140
1427
|
usage.cache_read_input_tokens,
|
|
1141
1428
|
]);
|
|
1142
1429
|
}
|
|
1430
|
+
/** Extract text from Codex message content blocks, filtering out system instructions for user messages. */
|
|
1143
1431
|
function extractCodexMessageText(contentBlocks, role) {
|
|
1144
1432
|
if (!Array.isArray(contentBlocks))
|
|
1145
1433
|
return undefined;
|
|
@@ -1158,15 +1446,17 @@ function extractCodexMessageText(contentBlocks, role) {
|
|
|
1158
1446
|
});
|
|
1159
1447
|
return text || undefined;
|
|
1160
1448
|
}
|
|
1449
|
+
/** Trim and normalize a version string, returning undefined for empty values. */
|
|
1161
1450
|
function normalizeVersion(version) {
|
|
1162
1451
|
const trimmed = version?.trim();
|
|
1163
1452
|
return trimmed ? trimmed : undefined;
|
|
1164
1453
|
}
|
|
1454
|
+
/** Extract the version number from a managed ~/.agents-system/versions/<agent>/<version>/... path. */
|
|
1165
1455
|
function extractVersionFromManagedPath(agent, sourcePath) {
|
|
1166
1456
|
if (!sourcePath)
|
|
1167
1457
|
return undefined;
|
|
1168
1458
|
const candidates = [sourcePath, safeRealpathSync(sourcePath) || ''];
|
|
1169
|
-
const marker = `/.agents/versions/${agent}/`;
|
|
1459
|
+
const marker = `/.agents-system/versions/${agent}/`;
|
|
1170
1460
|
for (const candidate of candidates) {
|
|
1171
1461
|
if (!candidate)
|
|
1172
1462
|
continue;
|
|
@@ -1180,6 +1470,7 @@ function extractVersionFromManagedPath(agent, sourcePath) {
|
|
|
1180
1470
|
}
|
|
1181
1471
|
return undefined;
|
|
1182
1472
|
}
|
|
1473
|
+
/** Resolve the current version of an agent CLI (symlink version or live CLI output, cached). */
|
|
1183
1474
|
async function getCurrentAgentVersion(agent) {
|
|
1184
1475
|
const cached = cachedAgentVersions.get(agent);
|
|
1185
1476
|
if (cached)
|
|
@@ -1193,11 +1484,13 @@ async function getCurrentAgentVersion(agent) {
|
|
|
1193
1484
|
cachedAgentVersions.set(agent, promise);
|
|
1194
1485
|
return promise;
|
|
1195
1486
|
}
|
|
1487
|
+
/** Resolve a session's version: embedded in file > extracted from managed path > current CLI version. */
|
|
1196
1488
|
function resolveSessionVersion(agent, sourcePath, embeddedVersion, currentVersion) {
|
|
1197
1489
|
return normalizeVersion(embeddedVersion)
|
|
1198
1490
|
|| extractVersionFromManagedPath(agent, sourcePath)
|
|
1199
1491
|
|| normalizeVersion(currentVersion);
|
|
1200
1492
|
}
|
|
1493
|
+
/** Sum all token usage fields from a Codex total_token_usage object. */
|
|
1201
1494
|
function getCodexTokenCount(totalTokenUsage) {
|
|
1202
1495
|
if (!totalTokenUsage || typeof totalTokenUsage !== 'object')
|
|
1203
1496
|
return null;
|
|
@@ -1208,6 +1501,7 @@ function getCodexTokenCount(totalTokenUsage) {
|
|
|
1208
1501
|
totalTokenUsage.reasoning_output_tokens,
|
|
1209
1502
|
]);
|
|
1210
1503
|
}
|
|
1504
|
+
/** Extract text from a Gemini message content field (string or array of parts). */
|
|
1211
1505
|
function extractGeminiMessageText(content) {
|
|
1212
1506
|
if (typeof content === 'string')
|
|
1213
1507
|
return content.trim();
|
|
@@ -1225,6 +1519,7 @@ function extractGeminiMessageText(content) {
|
|
|
1225
1519
|
}
|
|
1226
1520
|
return '';
|
|
1227
1521
|
}
|
|
1522
|
+
/** Extract the total token count from a Gemini message's tokens object. */
|
|
1228
1523
|
function getGeminiTokenCount(tokens) {
|
|
1229
1524
|
if (!tokens || typeof tokens !== 'object')
|
|
1230
1525
|
return null;
|
|
@@ -1238,6 +1533,7 @@ function getGeminiTokenCount(tokens) {
|
|
|
1238
1533
|
tokens.tool,
|
|
1239
1534
|
]);
|
|
1240
1535
|
}
|
|
1536
|
+
/** Sum all numeric values in an array, returning null if none are valid numbers. */
|
|
1241
1537
|
function sumKnownNumbers(values) {
|
|
1242
1538
|
let total = 0;
|
|
1243
1539
|
let found = false;
|
|
@@ -1252,6 +1548,7 @@ function sumKnownNumbers(values) {
|
|
|
1252
1548
|
// ---------------------------------------------------------------------------
|
|
1253
1549
|
// Time range parsing
|
|
1254
1550
|
// ---------------------------------------------------------------------------
|
|
1551
|
+
/** Parse a time filter string (relative like '7d' or ISO timestamp) into epoch milliseconds. */
|
|
1255
1552
|
export function parseTimeFilter(input) {
|
|
1256
1553
|
const relativeMatch = input.match(/^(\d+)([mhdw])$/i);
|
|
1257
1554
|
if (relativeMatch) {
|
|
@@ -1269,4 +1566,3 @@ export function parseTimeFilter(input) {
|
|
|
1269
1566
|
const ts = new Date(input).getTime();
|
|
1270
1567
|
return Number.isNaN(ts) ? 0 : ts;
|
|
1271
1568
|
}
|
|
1272
|
-
//# sourceMappingURL=discover.js.map
|