@swarmify/agents-cli 1.13.4 → 1.14.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/README.md +2 -319
- package/bin/agents.js +2 -0
- package/package.json +13 -79
- package/scripts/postinstall.js +4 -71
- package/CHANGELOG.md +0 -316
- package/LICENSE +0 -21
- package/dist/commands/__tests__/sessions-tail.test.d.ts +0 -2
- package/dist/commands/__tests__/sessions-tail.test.d.ts.map +0 -1
- package/dist/commands/__tests__/sessions-tail.test.js +0 -108
- package/dist/commands/__tests__/sessions-tail.test.js.map +0 -1
- 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 +0 -11
- package/dist/commands/cloud.d.ts.map +0 -1
- package/dist/commands/cloud.js +0 -363
- package/dist/commands/cloud.js.map +0 -1
- package/dist/commands/commands.d.ts +0 -12
- package/dist/commands/commands.d.ts.map +0 -1
- package/dist/commands/commands.js +0 -629
- package/dist/commands/commands.js.map +0 -1
- package/dist/commands/daemon.d.ts +0 -11
- package/dist/commands/daemon.d.ts.map +0 -1
- package/dist/commands/daemon.js +0 -119
- package/dist/commands/daemon.js.map +0 -1
- package/dist/commands/drive.d.ts +0 -11
- package/dist/commands/drive.d.ts.map +0 -1
- package/dist/commands/drive.js +0 -175
- package/dist/commands/drive.js.map +0 -1
- package/dist/commands/exec.d.ts +0 -11
- package/dist/commands/exec.d.ts.map +0 -1
- package/dist/commands/exec.js +0 -251
- package/dist/commands/exec.js.map +0 -1
- package/dist/commands/factory.d.ts +0 -11
- package/dist/commands/factory.d.ts.map +0 -1
- package/dist/commands/factory.js +0 -445
- package/dist/commands/factory.js.map +0 -1
- package/dist/commands/fork.d.ts +0 -11
- package/dist/commands/fork.d.ts.map +0 -1
- package/dist/commands/fork.js +0 -147
- package/dist/commands/fork.js.map +0 -1
- package/dist/commands/hooks.d.ts +0 -12
- package/dist/commands/hooks.d.ts.map +0 -1
- package/dist/commands/hooks.js +0 -690
- package/dist/commands/hooks.js.map +0 -1
- package/dist/commands/init.d.ts +0 -15
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -137
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/mcp.d.ts +0 -12
- package/dist/commands/mcp.d.ts.map +0 -1
- package/dist/commands/mcp.js +0 -583
- package/dist/commands/mcp.js.map +0 -1
- package/dist/commands/models.d.ts +0 -11
- package/dist/commands/models.d.ts.map +0 -1
- package/dist/commands/models.js +0 -170
- package/dist/commands/models.js.map +0 -1
- package/dist/commands/packages.d.ts +0 -11
- package/dist/commands/packages.d.ts.map +0 -1
- package/dist/commands/packages.js +0 -551
- package/dist/commands/packages.js.map +0 -1
- package/dist/commands/permissions.d.ts +0 -12
- package/dist/commands/permissions.d.ts.map +0 -1
- package/dist/commands/permissions.js +0 -724
- package/dist/commands/permissions.js.map +0 -1
- package/dist/commands/plugins.d.ts +0 -11
- package/dist/commands/plugins.d.ts.map +0 -1
- package/dist/commands/plugins.js +0 -393
- package/dist/commands/plugins.js.map +0 -1
- package/dist/commands/profiles.d.ts +0 -12
- package/dist/commands/profiles.d.ts.map +0 -1
- package/dist/commands/profiles.js +0 -255
- package/dist/commands/profiles.js.map +0 -1
- package/dist/commands/pty.d.ts +0 -21
- package/dist/commands/pty.d.ts.map +0 -1
- package/dist/commands/pty.js +0 -391
- package/dist/commands/pty.js.map +0 -1
- package/dist/commands/pull.d.ts +0 -11
- package/dist/commands/pull.d.ts.map +0 -1
- package/dist/commands/pull.js +0 -456
- package/dist/commands/pull.js.map +0 -1
- package/dist/commands/push.d.ts +0 -11
- package/dist/commands/push.d.ts.map +0 -1
- package/dist/commands/push.js +0 -188
- package/dist/commands/push.js.map +0 -1
- package/dist/commands/refresh-memory.d.ts +0 -16
- package/dist/commands/refresh-memory.d.ts.map +0 -1
- package/dist/commands/refresh-memory.js +0 -52
- package/dist/commands/refresh-memory.js.map +0 -1
- package/dist/commands/resource-view.d.ts +0 -39
- package/dist/commands/resource-view.d.ts.map +0 -1
- package/dist/commands/resource-view.js +0 -197
- package/dist/commands/resource-view.js.map +0 -1
- package/dist/commands/routines.d.ts +0 -11
- package/dist/commands/routines.d.ts.map +0 -1
- package/dist/commands/routines.js +0 -590
- package/dist/commands/routines.js.map +0 -1
- package/dist/commands/rules.d.ts +0 -12
- package/dist/commands/rules.d.ts.map +0 -1
- package/dist/commands/rules.js +0 -489
- package/dist/commands/rules.js.map +0 -1
- package/dist/commands/secrets.d.ts +0 -11
- package/dist/commands/secrets.d.ts.map +0 -1
- package/dist/commands/secrets.js +0 -352
- package/dist/commands/secrets.js.map +0 -1
- package/dist/commands/sessions-picker.d.ts +0 -18
- package/dist/commands/sessions-picker.d.ts.map +0 -1
- package/dist/commands/sessions-picker.js +0 -265
- package/dist/commands/sessions-picker.js.map +0 -1
- package/dist/commands/sessions-tail.d.ts +0 -20
- package/dist/commands/sessions-tail.d.ts.map +0 -1
- package/dist/commands/sessions-tail.js +0 -236
- package/dist/commands/sessions-tail.js.map +0 -1
- package/dist/commands/sessions.d.ts +0 -18
- package/dist/commands/sessions.d.ts.map +0 -1
- package/dist/commands/sessions.js +0 -1173
- package/dist/commands/sessions.js.map +0 -1
- package/dist/commands/skills.d.ts +0 -12
- package/dist/commands/skills.d.ts.map +0 -1
- package/dist/commands/skills.js +0 -717
- package/dist/commands/skills.js.map +0 -1
- package/dist/commands/status.d.ts +0 -10
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/status.js +0 -26
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/subagents.d.ts +0 -11
- package/dist/commands/subagents.d.ts.map +0 -1
- package/dist/commands/subagents.js +0 -361
- package/dist/commands/subagents.js.map +0 -1
- package/dist/commands/sync.d.ts +0 -11
- package/dist/commands/sync.d.ts.map +0 -1
- package/dist/commands/sync.js +0 -70
- package/dist/commands/sync.js.map +0 -1
- package/dist/commands/teams-picker.d.ts +0 -18
- package/dist/commands/teams-picker.d.ts.map +0 -1
- package/dist/commands/teams-picker.js +0 -290
- package/dist/commands/teams-picker.js.map +0 -1
- package/dist/commands/teams.d.ts +0 -18
- package/dist/commands/teams.d.ts.map +0 -1
- package/dist/commands/teams.js +0 -1144
- package/dist/commands/teams.js.map +0 -1
- package/dist/commands/utils.d.ts +0 -45
- package/dist/commands/utils.d.ts.map +0 -1
- package/dist/commands/utils.js +0 -106
- package/dist/commands/utils.js.map +0 -1
- package/dist/commands/versions.d.ts +0 -11
- package/dist/commands/versions.d.ts.map +0 -1
- package/dist/commands/versions.js +0 -701
- package/dist/commands/versions.js.map +0 -1
- package/dist/commands/view.d.ts +0 -43
- package/dist/commands/view.d.ts.map +0 -1
- package/dist/commands/view.js +0 -894
- package/dist/commands/view.js.map +0 -1
- package/dist/index.d.ts +0 -9
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -496
- 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 -57
- 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 +0 -158
- package/dist/lib/agents.d.ts.map +0 -1
- package/dist/lib/agents.js +0 -1159
- package/dist/lib/agents.js.map +0 -1
- package/dist/lib/artifact-actions.d.ts +0 -27
- package/dist/lib/artifact-actions.d.ts.map +0 -1
- package/dist/lib/artifact-actions.js +0 -58
- package/dist/lib/artifact-actions.js.map +0 -1
- package/dist/lib/cloud/codex.d.ts +0 -26
- package/dist/lib/cloud/codex.d.ts.map +0 -1
- package/dist/lib/cloud/codex.js +0 -237
- package/dist/lib/cloud/codex.js.map +0 -1
- package/dist/lib/cloud/factory.d.ts +0 -32
- package/dist/lib/cloud/factory.d.ts.map +0 -1
- package/dist/lib/cloud/factory.js +0 -43
- package/dist/lib/cloud/factory.js.map +0 -1
- package/dist/lib/cloud/registry.d.ts +0 -16
- package/dist/lib/cloud/registry.d.ts.map +0 -1
- package/dist/lib/cloud/registry.js +0 -68
- package/dist/lib/cloud/registry.js.map +0 -1
- package/dist/lib/cloud/rush.d.ts +0 -37
- package/dist/lib/cloud/rush.d.ts.map +0 -1
- package/dist/lib/cloud/rush.js +0 -230
- package/dist/lib/cloud/rush.js.map +0 -1
- package/dist/lib/cloud/rush.test.d.ts +0 -2
- package/dist/lib/cloud/rush.test.d.ts.map +0 -1
- package/dist/lib/cloud/rush.test.js +0 -63
- package/dist/lib/cloud/rush.test.js.map +0 -1
- package/dist/lib/cloud/store.d.ts +0 -23
- package/dist/lib/cloud/store.d.ts.map +0 -1
- package/dist/lib/cloud/store.js +0 -116
- package/dist/lib/cloud/store.js.map +0 -1
- package/dist/lib/cloud/stream.d.ts +0 -24
- package/dist/lib/cloud/stream.d.ts.map +0 -1
- package/dist/lib/cloud/stream.js +0 -145
- package/dist/lib/cloud/stream.js.map +0 -1
- package/dist/lib/cloud/types.d.ts +0 -109
- package/dist/lib/cloud/types.d.ts.map +0 -1
- package/dist/lib/cloud/types.js +0 -33
- package/dist/lib/cloud/types.js.map +0 -1
- package/dist/lib/cloud/types.test.d.ts +0 -2
- package/dist/lib/cloud/types.test.d.ts.map +0 -1
- package/dist/lib/cloud/types.test.js +0 -41
- package/dist/lib/cloud/types.test.js.map +0 -1
- package/dist/lib/commands.d.ts +0 -141
- package/dist/lib/commands.d.ts.map +0 -1
- package/dist/lib/commands.js +0 -514
- package/dist/lib/commands.js.map +0 -1
- package/dist/lib/convert.d.ts +0 -21
- package/dist/lib/convert.d.ts.map +0 -1
- package/dist/lib/convert.js +0 -54
- package/dist/lib/convert.js.map +0 -1
- package/dist/lib/daemon.d.ts +0 -43
- package/dist/lib/daemon.d.ts.map +0 -1
- package/dist/lib/daemon.js +0 -332
- package/dist/lib/daemon.js.map +0 -1
- package/dist/lib/drive-sync.d.ts +0 -46
- package/dist/lib/drive-sync.d.ts.map +0 -1
- package/dist/lib/drive-sync.js +0 -209
- package/dist/lib/drive-sync.js.map +0 -1
- package/dist/lib/exec.d.ts +0 -101
- package/dist/lib/exec.d.ts.map +0 -1
- package/dist/lib/exec.js +0 -450
- package/dist/lib/exec.js.map +0 -1
- package/dist/lib/factory/__tests__/config.test.d.ts +0 -2
- package/dist/lib/factory/__tests__/config.test.d.ts.map +0 -1
- package/dist/lib/factory/__tests__/config.test.js +0 -128
- package/dist/lib/factory/__tests__/config.test.js.map +0 -1
- package/dist/lib/factory/config.d.ts +0 -49
- package/dist/lib/factory/config.d.ts.map +0 -1
- package/dist/lib/factory/config.js +0 -127
- package/dist/lib/factory/config.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 -107
- package/dist/lib/factory.js.map +0 -1
- package/dist/lib/git.d.ts +0 -157
- package/dist/lib/git.d.ts.map +0 -1
- package/dist/lib/git.js +0 -647
- package/dist/lib/git.js.map +0 -1
- package/dist/lib/help.d.ts +0 -10
- package/dist/lib/help.d.ts.map +0 -1
- package/dist/lib/help.js +0 -66
- package/dist/lib/help.js.map +0 -1
- package/dist/lib/hooks.d.ts +0 -125
- package/dist/lib/hooks.d.ts.map +0 -1
- package/dist/lib/hooks.js +0 -846
- package/dist/lib/hooks.js.map +0 -1
- package/dist/lib/ledger/__tests__/local.test.d.ts +0 -2
- package/dist/lib/ledger/__tests__/local.test.d.ts.map +0 -1
- package/dist/lib/ledger/__tests__/local.test.js +0 -177
- package/dist/lib/ledger/__tests__/local.test.js.map +0 -1
- package/dist/lib/ledger/__tests__/sync.test.d.ts +0 -2
- package/dist/lib/ledger/__tests__/sync.test.d.ts.map +0 -1
- package/dist/lib/ledger/__tests__/sync.test.js +0 -117
- package/dist/lib/ledger/__tests__/sync.test.js.map +0 -1
- package/dist/lib/ledger/index.d.ts +0 -18
- package/dist/lib/ledger/index.d.ts.map +0 -1
- package/dist/lib/ledger/index.js +0 -32
- package/dist/lib/ledger/index.js.map +0 -1
- package/dist/lib/ledger/local.d.ts +0 -22
- package/dist/lib/ledger/local.d.ts.map +0 -1
- package/dist/lib/ledger/local.js +0 -333
- package/dist/lib/ledger/local.js.map +0 -1
- package/dist/lib/ledger/r2.d.ts +0 -41
- package/dist/lib/ledger/r2.d.ts.map +0 -1
- package/dist/lib/ledger/r2.js +0 -335
- package/dist/lib/ledger/r2.js.map +0 -1
- package/dist/lib/ledger/sync.d.ts +0 -33
- package/dist/lib/ledger/sync.d.ts.map +0 -1
- package/dist/lib/ledger/sync.js +0 -106
- package/dist/lib/ledger/sync.js.map +0 -1
- package/dist/lib/ledger/types.d.ts +0 -100
- package/dist/lib/ledger/types.d.ts.map +0 -1
- package/dist/lib/ledger/types.js +0 -21
- package/dist/lib/ledger/types.js.map +0 -1
- package/dist/lib/manifest.d.ts +0 -14
- package/dist/lib/manifest.d.ts.map +0 -1
- package/dist/lib/manifest.js +0 -48
- package/dist/lib/manifest.js.map +0 -1
- package/dist/lib/markdown.d.ts +0 -5
- package/dist/lib/markdown.d.ts.map +0 -1
- package/dist/lib/markdown.js +0 -17
- package/dist/lib/markdown.js.map +0 -1
- package/dist/lib/mcp.d.ts +0 -64
- package/dist/lib/mcp.d.ts.map +0 -1
- package/dist/lib/mcp.js +0 -327
- package/dist/lib/mcp.js.map +0 -1
- package/dist/lib/memory-compile.d.ts +0 -65
- package/dist/lib/memory-compile.d.ts.map +0 -1
- package/dist/lib/memory-compile.js +0 -174
- package/dist/lib/memory-compile.js.map +0 -1
- package/dist/lib/memory.d.ts +0 -64
- package/dist/lib/memory.d.ts.map +0 -1
- package/dist/lib/memory.js +0 -275
- package/dist/lib/memory.js.map +0 -1
- package/dist/lib/models.d.ts +0 -98
- package/dist/lib/models.d.ts.map +0 -1
- package/dist/lib/models.js +0 -728
- package/dist/lib/models.js.map +0 -1
- package/dist/lib/permissions.d.ts +0 -227
- package/dist/lib/permissions.d.ts.map +0 -1
- package/dist/lib/permissions.js +0 -1085
- package/dist/lib/permissions.js.map +0 -1
- package/dist/lib/picker.d.ts +0 -27
- package/dist/lib/picker.d.ts.map +0 -1
- package/dist/lib/picker.js +0 -110
- package/dist/lib/picker.js.map +0 -1
- package/dist/lib/plugins.d.ts +0 -80
- package/dist/lib/plugins.d.ts.map +0 -1
- package/dist/lib/plugins.js +0 -556
- package/dist/lib/plugins.js.map +0 -1
- package/dist/lib/profiles-keychain.d.ts +0 -11
- package/dist/lib/profiles-keychain.d.ts.map +0 -1
- package/dist/lib/profiles-keychain.js +0 -14
- package/dist/lib/profiles-keychain.js.map +0 -1
- package/dist/lib/profiles-presets.d.ts +0 -25
- package/dist/lib/profiles-presets.d.ts.map +0 -1
- package/dist/lib/profiles-presets.js +0 -104
- package/dist/lib/profiles-presets.js.map +0 -1
- package/dist/lib/profiles.d.ts +0 -70
- package/dist/lib/profiles.d.ts.map +0 -1
- package/dist/lib/profiles.js +0 -145
- package/dist/lib/profiles.js.map +0 -1
- package/dist/lib/pty-client.d.ts +0 -23
- package/dist/lib/pty-client.d.ts.map +0 -1
- package/dist/lib/pty-client.js +0 -181
- package/dist/lib/pty-client.js.map +0 -1
- package/dist/lib/pty-server.d.ts +0 -21
- package/dist/lib/pty-server.d.ts.map +0 -1
- package/dist/lib/pty-server.js +0 -427
- package/dist/lib/pty-server.js.map +0 -1
- package/dist/lib/registry.d.ts +0 -45
- package/dist/lib/registry.d.ts.map +0 -1
- package/dist/lib/registry.js +0 -220
- package/dist/lib/registry.js.map +0 -1
- package/dist/lib/resources.d.ts +0 -55
- package/dist/lib/resources.d.ts.map +0 -1
- package/dist/lib/resources.js +0 -103
- package/dist/lib/resources.js.map +0 -1
- package/dist/lib/rotate.d.ts +0 -58
- package/dist/lib/rotate.d.ts.map +0 -1
- package/dist/lib/rotate.js +0 -93
- package/dist/lib/rotate.js.map +0 -1
- package/dist/lib/routines.d.ts +0 -99
- package/dist/lib/routines.d.ts.map +0 -1
- package/dist/lib/routines.js +0 -352
- package/dist/lib/routines.js.map +0 -1
- package/dist/lib/runner.d.ts +0 -26
- package/dist/lib/runner.d.ts.map +0 -1
- package/dist/lib/runner.js +0 -325
- package/dist/lib/runner.js.map +0 -1
- package/dist/lib/sandbox.d.ts +0 -26
- package/dist/lib/sandbox.d.ts.map +0 -1
- package/dist/lib/sandbox.js +0 -218
- package/dist/lib/sandbox.js.map +0 -1
- package/dist/lib/scheduler.d.ts +0 -26
- package/dist/lib/scheduler.d.ts.map +0 -1
- package/dist/lib/scheduler.js +0 -77
- package/dist/lib/scheduler.js.map +0 -1
- package/dist/lib/secrets-bundles.d.ts +0 -38
- package/dist/lib/secrets-bundles.d.ts.map +0 -1
- package/dist/lib/secrets-bundles.js +0 -176
- package/dist/lib/secrets-bundles.js.map +0 -1
- package/dist/lib/secrets.d.ts +0 -53
- package/dist/lib/secrets.d.ts.map +0 -1
- package/dist/lib/secrets.js +0 -140
- 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/active.d.ts +0 -44
- package/dist/lib/session/active.d.ts.map +0 -1
- package/dist/lib/session/active.js +0 -379
- package/dist/lib/session/active.js.map +0 -1
- package/dist/lib/session/artifacts.d.ts +0 -15
- package/dist/lib/session/artifacts.d.ts.map +0 -1
- package/dist/lib/session/artifacts.js +0 -86
- package/dist/lib/session/artifacts.js.map +0 -1
- package/dist/lib/session/db.d.ts +0 -140
- package/dist/lib/session/db.d.ts.map +0 -1
- package/dist/lib/session/db.js +0 -599
- package/dist/lib/session/db.js.map +0 -1
- package/dist/lib/session/discover.d.ts +0 -72
- package/dist/lib/session/discover.d.ts.map +0 -1
- package/dist/lib/session/discover.js +0 -1315
- package/dist/lib/session/discover.js.map +0 -1
- package/dist/lib/session/parse.d.ts +0 -34
- package/dist/lib/session/parse.d.ts.map +0 -1
- package/dist/lib/session/parse.js +0 -663
- package/dist/lib/session/parse.js.map +0 -1
- package/dist/lib/session/prompt.d.ts +0 -13
- package/dist/lib/session/prompt.d.ts.map +0 -1
- package/dist/lib/session/prompt.js +0 -79
- 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 +0 -103
- package/dist/lib/session/render.d.ts.map +0 -1
- package/dist/lib/session/render.js +0 -798
- package/dist/lib/session/render.js.map +0 -1
- package/dist/lib/session/team-filter.d.ts +0 -35
- package/dist/lib/session/team-filter.d.ts.map +0 -1
- package/dist/lib/session/team-filter.js +0 -75
- 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 +0 -84
- package/dist/lib/session/types.d.ts.map +0 -1
- package/dist/lib/session/types.js +0 -11
- package/dist/lib/session/types.js.map +0 -1
- package/dist/lib/shims.d.ts +0 -272
- package/dist/lib/shims.d.ts.map +0 -1
- package/dist/lib/shims.js +0 -1322
- package/dist/lib/shims.js.map +0 -1
- package/dist/lib/skills.d.ts +0 -142
- package/dist/lib/skills.d.ts.map +0 -1
- package/dist/lib/skills.js +0 -791
- package/dist/lib/skills.js.map +0 -1
- package/dist/lib/state.d.ts +0 -87
- package/dist/lib/state.d.ts.map +0 -1
- package/dist/lib/state.js +0 -333
- package/dist/lib/state.js.map +0 -1
- package/dist/lib/subagents.d.ts +0 -84
- package/dist/lib/subagents.d.ts.map +0 -1
- package/dist/lib/subagents.js +0 -410
- package/dist/lib/subagents.js.map +0 -1
- package/dist/lib/teams/__tests__/oracle.test.d.ts +0 -2
- package/dist/lib/teams/__tests__/oracle.test.d.ts.map +0 -1
- package/dist/lib/teams/__tests__/oracle.test.js +0 -89
- package/dist/lib/teams/__tests__/oracle.test.js.map +0 -1
- package/dist/lib/teams/__tests__/supervisor.test.d.ts +0 -2
- package/dist/lib/teams/__tests__/supervisor.test.d.ts.map +0 -1
- package/dist/lib/teams/__tests__/supervisor.test.js +0 -179
- package/dist/lib/teams/__tests__/supervisor.test.js.map +0 -1
- package/dist/lib/teams/agents.d.ts +0 -247
- package/dist/lib/teams/agents.d.ts.map +0 -1
- package/dist/lib/teams/agents.js +0 -1244
- package/dist/lib/teams/agents.js.map +0 -1
- package/dist/lib/teams/api.d.ts +0 -91
- package/dist/lib/teams/api.d.ts.map +0 -1
- package/dist/lib/teams/api.js +0 -239
- 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 +0 -8
- package/dist/lib/teams/debug.d.ts.map +0 -1
- package/dist/lib/teams/debug.js +0 -12
- package/dist/lib/teams/debug.js.map +0 -1
- package/dist/lib/teams/file_ops.d.ts +0 -13
- package/dist/lib/teams/file_ops.d.ts.map +0 -1
- package/dist/lib/teams/file_ops.js +0 -66
- package/dist/lib/teams/file_ops.js.map +0 -1
- package/dist/lib/teams/index.d.ts +0 -16
- package/dist/lib/teams/index.d.ts.map +0 -1
- package/dist/lib/teams/index.js +0 -15
- package/dist/lib/teams/index.js.map +0 -1
- package/dist/lib/teams/oracle.d.ts +0 -20
- package/dist/lib/teams/oracle.d.ts.map +0 -1
- package/dist/lib/teams/oracle.js +0 -59
- package/dist/lib/teams/oracle.js.map +0 -1
- package/dist/lib/teams/parsers.d.ts +0 -9
- package/dist/lib/teams/parsers.d.ts.map +0 -1
- package/dist/lib/teams/parsers.js +0 -837
- package/dist/lib/teams/parsers.js.map +0 -1
- package/dist/lib/teams/persistence.d.ts +0 -43
- package/dist/lib/teams/persistence.d.ts.map +0 -1
- package/dist/lib/teams/persistence.js +0 -299
- 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 +0 -18
- package/dist/lib/teams/registry.d.ts.map +0 -1
- package/dist/lib/teams/registry.js +0 -68
- package/dist/lib/teams/registry.js.map +0 -1
- package/dist/lib/teams/summarizer.d.ts +0 -73
- package/dist/lib/teams/summarizer.d.ts.map +0 -1
- package/dist/lib/teams/summarizer.js +0 -780
- package/dist/lib/teams/summarizer.js.map +0 -1
- package/dist/lib/teams/supervisor.d.ts +0 -49
- package/dist/lib/teams/supervisor.d.ts.map +0 -1
- package/dist/lib/teams/supervisor.js +0 -74
- package/dist/lib/teams/supervisor.js.map +0 -1
- package/dist/lib/template.d.ts +0 -27
- package/dist/lib/template.d.ts.map +0 -1
- package/dist/lib/template.js +0 -60
- package/dist/lib/template.js.map +0 -1
- package/dist/lib/types.d.ts +0 -331
- package/dist/lib/types.d.ts.map +0 -1
- package/dist/lib/types.js +0 -29
- package/dist/lib/types.js.map +0 -1
- package/dist/lib/usage.d.ts +0 -105
- package/dist/lib/usage.d.ts.map +0 -1
- package/dist/lib/usage.js +0 -686
- package/dist/lib/usage.js.map +0 -1
- package/dist/lib/versions.d.ts +0 -253
- package/dist/lib/versions.d.ts.map +0 -1
- package/dist/lib/versions.js +0 -1796
- package/dist/lib/versions.js.map +0 -1
- package/scripts/rebuild-sqlite.sh +0 -46
|
@@ -1,1315 +0,0 @@
|
|
|
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
|
-
*/
|
|
9
|
-
import * as fs from 'fs';
|
|
10
|
-
import * as path from 'path';
|
|
11
|
-
import * as os from 'os';
|
|
12
|
-
import * as crypto from 'crypto';
|
|
13
|
-
import * as readline from 'readline';
|
|
14
|
-
import { execSync } from 'child_process';
|
|
15
|
-
import { AGENTS, getCliVersion } from '../agents.js';
|
|
16
|
-
import { getConfigSymlinkVersion } from '../shims.js';
|
|
17
|
-
import { SESSION_AGENTS } from './types.js';
|
|
18
|
-
import { extractSessionTopic } from './prompt.js';
|
|
19
|
-
import { getDB, getScanStampByPath, getScanStampsForPaths, recordScans, syncLabels, upsertSessionsBatch, querySessions, countSessions, ftsSearch, } from './db.js';
|
|
20
|
-
const HOME = os.homedir();
|
|
21
|
-
const AGENTS_DIR = path.join(HOME, '.agents');
|
|
22
|
-
/** How long OpenClaw channel/cron snapshots stay valid before we re-shell-out. */
|
|
23
|
-
const OPENCLAW_TTL_MS = 60_000;
|
|
24
|
-
let cachedOpenClawWorkspaces = null;
|
|
25
|
-
const cachedAgentVersions = new Map();
|
|
26
|
-
/**
|
|
27
|
-
* Discover sessions. Scans only files whose (mtime, size) have changed since
|
|
28
|
-
* the last run; everything else is served from the SQLite cache.
|
|
29
|
-
*/
|
|
30
|
-
export async function discoverSessions(options) {
|
|
31
|
-
// Touch the DB so the schema is ready and connection is cached for this run.
|
|
32
|
-
getDB();
|
|
33
|
-
const agents = options?.agent ? [options.agent] : SESSION_AGENTS;
|
|
34
|
-
const onProgress = options?.onProgress;
|
|
35
|
-
// Incrementally re-scan changed files across all selected agents in parallel.
|
|
36
|
-
await Promise.all(agents.map(agent => {
|
|
37
|
-
switch (agent) {
|
|
38
|
-
case 'claude': return scanClaudeIncremental(onProgress);
|
|
39
|
-
case 'codex': return scanCodexIncremental(onProgress);
|
|
40
|
-
case 'gemini': return scanGeminiIncremental(onProgress);
|
|
41
|
-
case 'opencode': return scanOpenCodeIncremental();
|
|
42
|
-
case 'openclaw': return scanOpenClawIncremental();
|
|
43
|
-
}
|
|
44
|
-
}));
|
|
45
|
-
const sessions = querySessions(buildQueryOptions(options, agents, { includeLimit: true }));
|
|
46
|
-
return sessions;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Count sessions in scope without running an incremental scan. Assumes the DB
|
|
50
|
-
* is already fresh (typically true because `discoverSessions` ran first this
|
|
51
|
-
* turn). Uses the exact same filter shape as the discover query.
|
|
52
|
-
*/
|
|
53
|
-
export function countSessionsInScope(options) {
|
|
54
|
-
const agents = options.agent ? [options.agent] : SESSION_AGENTS;
|
|
55
|
-
return countSessions(buildQueryOptions(options, agents, { includeLimit: false }));
|
|
56
|
-
}
|
|
57
|
-
/** Translate DiscoverOptions into the QueryOptions shape expected by the DB layer. */
|
|
58
|
-
function buildQueryOptions(options, agents, opts) {
|
|
59
|
-
const projectQuery = options?.project?.trim();
|
|
60
|
-
const sinceMs = options?.since ? parseTimeFilter(options.since) : undefined;
|
|
61
|
-
const untilMs = options?.until ? new Date(options.until).getTime() : undefined;
|
|
62
|
-
let cwdFilter;
|
|
63
|
-
let cwdPrefixFilter;
|
|
64
|
-
if (options?.cwdPrefix) {
|
|
65
|
-
cwdPrefixFilter = normalizeCwd(options.cwdPrefix);
|
|
66
|
-
}
|
|
67
|
-
else if (!options?.all && !projectQuery) {
|
|
68
|
-
cwdFilter = normalizeCwd(options?.cwd || process.cwd());
|
|
69
|
-
}
|
|
70
|
-
return {
|
|
71
|
-
agent: options?.agent,
|
|
72
|
-
agents: options?.agent ? undefined : agents,
|
|
73
|
-
version: options?.version,
|
|
74
|
-
cwd: cwdFilter,
|
|
75
|
-
cwdPrefix: cwdPrefixFilter,
|
|
76
|
-
project: projectQuery,
|
|
77
|
-
sinceMs,
|
|
78
|
-
untilMs: Number.isFinite(untilMs) ? untilMs : undefined,
|
|
79
|
-
limit: opts.includeLimit ? (options?.limit ?? 50) : undefined,
|
|
80
|
-
excludeTeamOrigin: options?.excludeTeamOrigin,
|
|
81
|
-
onlyTeamOrigin: options?.onlyTeamOrigin,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
/** Resolve and canonicalize a working directory path (follows symlinks). */
|
|
85
|
-
function normalizeCwd(cwd) {
|
|
86
|
-
if (!cwd)
|
|
87
|
-
return '';
|
|
88
|
-
const resolved = path.resolve(cwd);
|
|
89
|
-
return safeRealpathSync(resolved) || resolved;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Resolve a session by full or short ID. Accepts a pre-loaded session list
|
|
93
|
-
* (fast path from discoverSessions) and falls back to a DB lookup for the
|
|
94
|
-
* "I only know the id" case.
|
|
95
|
-
*/
|
|
96
|
-
export function resolveSessionById(sessions, idQuery) {
|
|
97
|
-
const query = idQuery.toLowerCase();
|
|
98
|
-
const exact = sessions.filter(s => s.id.toLowerCase() === query || s.shortId.toLowerCase() === query);
|
|
99
|
-
if (exact.length > 0)
|
|
100
|
-
return exact;
|
|
101
|
-
return sessions.filter(s => s.id.toLowerCase().startsWith(query) || s.shortId.toLowerCase().startsWith(query));
|
|
102
|
-
}
|
|
103
|
-
// ---------------------------------------------------------------------------
|
|
104
|
-
// Content-index search (FTS5-backed)
|
|
105
|
-
// ---------------------------------------------------------------------------
|
|
106
|
-
/**
|
|
107
|
-
* Run an FTS5 search over the DB and intersect with the given session list,
|
|
108
|
-
* preserving the existing SessionMeta[] contract so sessions.ts is unchanged.
|
|
109
|
-
*/
|
|
110
|
-
export function searchContentIndex(sessions, query) {
|
|
111
|
-
if (!query.trim())
|
|
112
|
-
return new Map();
|
|
113
|
-
const hits = ftsSearch(query);
|
|
114
|
-
if (hits.length === 0)
|
|
115
|
-
return new Map();
|
|
116
|
-
const byId = new Map(sessions.map(s => [s.id, s]));
|
|
117
|
-
const result = new Map();
|
|
118
|
-
for (const hit of hits) {
|
|
119
|
-
const session = byId.get(hit.sessionId);
|
|
120
|
-
if (!session)
|
|
121
|
-
continue;
|
|
122
|
-
result.set(hit.sessionId, {
|
|
123
|
-
...session,
|
|
124
|
-
_matchedTerms: hit.matchedTerms,
|
|
125
|
-
_bm25Score: hit.score,
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
return result;
|
|
129
|
-
}
|
|
130
|
-
// ---------------------------------------------------------------------------
|
|
131
|
-
// Incremental scan orchestration
|
|
132
|
-
// ---------------------------------------------------------------------------
|
|
133
|
-
/**
|
|
134
|
-
* For a list of files, stat each, compare to the DB ledger, and return only
|
|
135
|
-
* the ones that need rescanning. One bulk DB query for the whole list.
|
|
136
|
-
*/
|
|
137
|
-
function filterChangedFiles(filePaths) {
|
|
138
|
-
const ledger = getScanStampsForPaths(filePaths);
|
|
139
|
-
const out = [];
|
|
140
|
-
for (const filePath of filePaths) {
|
|
141
|
-
const stat = safeStatSync(filePath);
|
|
142
|
-
if (!stat)
|
|
143
|
-
continue;
|
|
144
|
-
const scan = {
|
|
145
|
-
fileMtimeMs: Math.floor(stat.mtimeMs),
|
|
146
|
-
fileSize: stat.size,
|
|
147
|
-
};
|
|
148
|
-
const prev = ledger.get(filePath);
|
|
149
|
-
if (prev && prev.fileMtimeMs === scan.fileMtimeMs && prev.fileSize === scan.fileSize) {
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
out.push({ filePath, scan });
|
|
153
|
-
}
|
|
154
|
-
return out;
|
|
155
|
-
}
|
|
156
|
-
// ---------------------------------------------------------------------------
|
|
157
|
-
// Multi-version directory scanning
|
|
158
|
-
// ---------------------------------------------------------------------------
|
|
159
|
-
/**
|
|
160
|
-
* Collect all directories to scan for an agent's sessions. Deduplicates by
|
|
161
|
-
* realpath to avoid double-counting symlinked version homes.
|
|
162
|
-
*/
|
|
163
|
-
export function getAgentSessionDirs(agent, subdir) {
|
|
164
|
-
const resolved = new Set();
|
|
165
|
-
const dirs = [];
|
|
166
|
-
function addDir(dir) {
|
|
167
|
-
if (!fs.existsSync(dir))
|
|
168
|
-
return;
|
|
169
|
-
const real = safeRealpathSync(dir);
|
|
170
|
-
const key = real || dir;
|
|
171
|
-
if (resolved.has(key))
|
|
172
|
-
return;
|
|
173
|
-
resolved.add(key);
|
|
174
|
-
dirs.push(dir);
|
|
175
|
-
}
|
|
176
|
-
addDir(path.join(HOME, `.${agent}`, subdir));
|
|
177
|
-
const versionsBase = path.join(AGENTS_DIR, 'versions', agent);
|
|
178
|
-
if (fs.existsSync(versionsBase)) {
|
|
179
|
-
try {
|
|
180
|
-
for (const version of fs.readdirSync(versionsBase)) {
|
|
181
|
-
addDir(path.join(versionsBase, version, 'home', `.${agent}`, subdir));
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
catch { /* dir unreadable */ }
|
|
185
|
-
}
|
|
186
|
-
const backupsBase = path.join(AGENTS_DIR, 'backups', agent);
|
|
187
|
-
if (fs.existsSync(backupsBase)) {
|
|
188
|
-
try {
|
|
189
|
-
for (const ts of fs.readdirSync(backupsBase)) {
|
|
190
|
-
addDir(path.join(backupsBase, ts, subdir));
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
catch { /* dir unreadable */ }
|
|
194
|
-
}
|
|
195
|
-
return dirs;
|
|
196
|
-
}
|
|
197
|
-
// ---------------------------------------------------------------------------
|
|
198
|
-
// Claude account info
|
|
199
|
-
// ---------------------------------------------------------------------------
|
|
200
|
-
let cachedClaudeAccount;
|
|
201
|
-
/** Read the Claude OAuth account email from .claude.json across all version homes. */
|
|
202
|
-
function getClaudeAccount() {
|
|
203
|
-
if (cachedClaudeAccount !== undefined)
|
|
204
|
-
return cachedClaudeAccount || undefined;
|
|
205
|
-
// Claude's active config lives at $CLAUDE_CONFIG_DIR/.claude.json; for our shim
|
|
206
|
-
// that's <version>/home/.claude/.claude.json. The home-level .claude.json is a
|
|
207
|
-
// legacy path used when Claude runs without CLAUDE_CONFIG_DIR set.
|
|
208
|
-
const candidates = [
|
|
209
|
-
path.join(HOME, '.claude', '.claude.json'),
|
|
210
|
-
path.join(HOME, '.claude.json'),
|
|
211
|
-
];
|
|
212
|
-
const versionsBase = path.join(AGENTS_DIR, 'versions', 'claude');
|
|
213
|
-
if (fs.existsSync(versionsBase)) {
|
|
214
|
-
try {
|
|
215
|
-
for (const version of fs.readdirSync(versionsBase)) {
|
|
216
|
-
candidates.push(path.join(versionsBase, version, 'home', '.claude', '.claude.json'));
|
|
217
|
-
candidates.push(path.join(versionsBase, version, 'home', '.claude.json'));
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
catch { /* versions dir unreadable */ }
|
|
221
|
-
}
|
|
222
|
-
for (const candidate of candidates) {
|
|
223
|
-
try {
|
|
224
|
-
if (!fs.existsSync(candidate))
|
|
225
|
-
continue;
|
|
226
|
-
const data = JSON.parse(fs.readFileSync(candidate, 'utf-8'));
|
|
227
|
-
const name = data.oauthAccount?.emailAddress || data.oauthAccount?.displayName;
|
|
228
|
-
if (name) {
|
|
229
|
-
cachedClaudeAccount = name;
|
|
230
|
-
return name;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
catch { /* auth file unreadable or malformed */ }
|
|
234
|
-
}
|
|
235
|
-
cachedClaudeAccount = '';
|
|
236
|
-
return undefined;
|
|
237
|
-
}
|
|
238
|
-
// ---------------------------------------------------------------------------
|
|
239
|
-
// Claude
|
|
240
|
-
// ---------------------------------------------------------------------------
|
|
241
|
-
/**
|
|
242
|
-
* Build a map of Claude sessionId -> user-given label from ~/.claude/sessions/*.json.
|
|
243
|
-
* Each JSON has shape { pid, sessionId, cwd, startedAt, name?, ... }. The
|
|
244
|
-
* `name` field only exists if the user ran /rename in that session.
|
|
245
|
-
* For sessionId collisions (re-resume of the same session), prefer the most
|
|
246
|
-
* recent startedAt.
|
|
247
|
-
*/
|
|
248
|
-
function buildClaudeLabelMap() {
|
|
249
|
-
const map = new Map();
|
|
250
|
-
const dir = path.join(HOME, '.claude', 'sessions');
|
|
251
|
-
if (!fs.existsSync(dir))
|
|
252
|
-
return new Map();
|
|
253
|
-
let files;
|
|
254
|
-
try {
|
|
255
|
-
files = fs.readdirSync(dir).filter(f => f.endsWith('.json'));
|
|
256
|
-
}
|
|
257
|
-
catch {
|
|
258
|
-
return new Map();
|
|
259
|
-
}
|
|
260
|
-
for (const f of files) {
|
|
261
|
-
try {
|
|
262
|
-
const data = JSON.parse(fs.readFileSync(path.join(dir, f), 'utf-8'));
|
|
263
|
-
if (typeof data.sessionId !== 'string')
|
|
264
|
-
continue;
|
|
265
|
-
const name = typeof data.name === 'string' && data.name.trim() ? data.name.trim() : null;
|
|
266
|
-
const startedAt = typeof data.startedAt === 'number' ? data.startedAt : 0;
|
|
267
|
-
const existing = map.get(data.sessionId);
|
|
268
|
-
if (!existing || startedAt > existing.startedAt) {
|
|
269
|
-
map.set(data.sessionId, { label: name, startedAt });
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
catch { /* unreadable session metadata file */ }
|
|
273
|
-
}
|
|
274
|
-
const out = new Map();
|
|
275
|
-
for (const [sid, { label }] of map)
|
|
276
|
-
out.set(sid, label);
|
|
277
|
-
return out;
|
|
278
|
-
}
|
|
279
|
-
/** Incrementally re-scan changed Claude session files and upsert into the DB. */
|
|
280
|
-
async function scanClaudeIncremental(onProgress) {
|
|
281
|
-
const account = getClaudeAccount();
|
|
282
|
-
const labelMap = buildClaudeLabelMap();
|
|
283
|
-
const filePaths = [];
|
|
284
|
-
const seen = new Set();
|
|
285
|
-
for (const projectsDir of getAgentSessionDirs('claude', 'projects')) {
|
|
286
|
-
let projectDirs;
|
|
287
|
-
try {
|
|
288
|
-
projectDirs = fs.readdirSync(projectsDir);
|
|
289
|
-
}
|
|
290
|
-
catch {
|
|
291
|
-
continue;
|
|
292
|
-
}
|
|
293
|
-
for (const dirName of projectDirs) {
|
|
294
|
-
const dirPath = path.join(projectsDir, dirName);
|
|
295
|
-
const stat = safeStatSync(dirPath);
|
|
296
|
-
if (!stat?.isDirectory())
|
|
297
|
-
continue;
|
|
298
|
-
let files;
|
|
299
|
-
try {
|
|
300
|
-
files = fs.readdirSync(dirPath).filter(f => f.endsWith('.jsonl'));
|
|
301
|
-
}
|
|
302
|
-
catch {
|
|
303
|
-
continue;
|
|
304
|
-
}
|
|
305
|
-
for (const file of files) {
|
|
306
|
-
const sessionId = file.replace('.jsonl', '');
|
|
307
|
-
if (seen.has(sessionId))
|
|
308
|
-
continue;
|
|
309
|
-
seen.add(sessionId);
|
|
310
|
-
filePaths.push(path.join(dirPath, file));
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
const changed = filterChangedFiles(filePaths);
|
|
315
|
-
if (changed.length > 0) {
|
|
316
|
-
onProgress?.({ agent: 'claude', parsed: 0, total: changed.length });
|
|
317
|
-
const entries = [];
|
|
318
|
-
const touched = [];
|
|
319
|
-
let parsed = 0;
|
|
320
|
-
for (const { filePath, scan } of changed) {
|
|
321
|
-
try {
|
|
322
|
-
const sessionId = path.basename(filePath).replace('.jsonl', '');
|
|
323
|
-
const label = labelMap.get(sessionId) ?? undefined;
|
|
324
|
-
const result = await readClaudeMeta(filePath, sessionId, account, label);
|
|
325
|
-
if (result) {
|
|
326
|
-
entries.push({ meta: result.meta, content: result.content, scan });
|
|
327
|
-
}
|
|
328
|
-
else {
|
|
329
|
-
touched.push({ filePath, scan });
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
catch {
|
|
333
|
-
touched.push({ filePath, scan });
|
|
334
|
-
}
|
|
335
|
-
parsed++;
|
|
336
|
-
onProgress?.({ agent: 'claude', parsed, total: changed.length });
|
|
337
|
-
}
|
|
338
|
-
upsertSessionsBatch(entries);
|
|
339
|
-
recordScans(touched);
|
|
340
|
-
}
|
|
341
|
-
// Pick up /rename changes on sessions whose JSONL didn't change.
|
|
342
|
-
// Only bother for sessions we actually have a Claude row for.
|
|
343
|
-
if (labelMap.size > 0)
|
|
344
|
-
syncLabels(labelMap);
|
|
345
|
-
}
|
|
346
|
-
/** Stream-parse a single Claude JSONL file to extract session metadata. */
|
|
347
|
-
async function readClaudeMeta(filePath, sessionId, account, label) {
|
|
348
|
-
const scan = await scanClaudeSession(filePath);
|
|
349
|
-
const isTeamOrigin = scan.entrypoint === 'sdk-cli';
|
|
350
|
-
let meta;
|
|
351
|
-
if (scan.timestamp) {
|
|
352
|
-
const cwd = normalizeCwd(scan.cwd || '');
|
|
353
|
-
meta = {
|
|
354
|
-
id: sessionId,
|
|
355
|
-
shortId: sessionId.slice(0, 8),
|
|
356
|
-
agent: 'claude',
|
|
357
|
-
timestamp: scan.timestamp,
|
|
358
|
-
project: cwd ? path.basename(cwd) : undefined,
|
|
359
|
-
cwd,
|
|
360
|
-
filePath,
|
|
361
|
-
gitBranch: scan.gitBranch,
|
|
362
|
-
version: scan.version,
|
|
363
|
-
account,
|
|
364
|
-
topic: scan.topic,
|
|
365
|
-
label,
|
|
366
|
-
messageCount: scan.messageCount,
|
|
367
|
-
tokenCount: scan.tokenCount,
|
|
368
|
-
isTeamOrigin,
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
else {
|
|
372
|
-
const stat = safeStatSync(filePath);
|
|
373
|
-
meta = {
|
|
374
|
-
id: sessionId,
|
|
375
|
-
shortId: sessionId.slice(0, 8),
|
|
376
|
-
agent: 'claude',
|
|
377
|
-
timestamp: stat ? stat.mtime.toISOString() : new Date().toISOString(),
|
|
378
|
-
filePath,
|
|
379
|
-
account,
|
|
380
|
-
label,
|
|
381
|
-
messageCount: scan.messageCount,
|
|
382
|
-
tokenCount: scan.tokenCount,
|
|
383
|
-
topic: scan.topic,
|
|
384
|
-
isTeamOrigin,
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
return { meta, content: scan.contentText || '' };
|
|
388
|
-
}
|
|
389
|
-
// ---------------------------------------------------------------------------
|
|
390
|
-
// Codex account info
|
|
391
|
-
// ---------------------------------------------------------------------------
|
|
392
|
-
let cachedCodexAccount;
|
|
393
|
-
/** Extract the Codex account email from the JWT id_token in auth.json. */
|
|
394
|
-
function getCodexAccount() {
|
|
395
|
-
if (cachedCodexAccount !== undefined)
|
|
396
|
-
return cachedCodexAccount || undefined;
|
|
397
|
-
const candidates = [path.join(HOME, '.codex', 'auth.json')];
|
|
398
|
-
const versionsBase = path.join(AGENTS_DIR, 'versions', 'codex');
|
|
399
|
-
if (fs.existsSync(versionsBase)) {
|
|
400
|
-
try {
|
|
401
|
-
for (const version of fs.readdirSync(versionsBase)) {
|
|
402
|
-
candidates.push(path.join(versionsBase, version, 'home', '.codex', 'auth.json'));
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
catch { /* versions dir unreadable */ }
|
|
406
|
-
}
|
|
407
|
-
for (const candidate of candidates) {
|
|
408
|
-
try {
|
|
409
|
-
if (!fs.existsSync(candidate))
|
|
410
|
-
continue;
|
|
411
|
-
const data = JSON.parse(fs.readFileSync(candidate, 'utf-8'));
|
|
412
|
-
const idToken = data.tokens?.id_token;
|
|
413
|
-
if (idToken) {
|
|
414
|
-
const parts = idToken.split('.');
|
|
415
|
-
if (parts.length >= 2) {
|
|
416
|
-
const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf-8'));
|
|
417
|
-
if (payload.email) {
|
|
418
|
-
cachedCodexAccount = payload.email;
|
|
419
|
-
return payload.email;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
catch { /* auth file or JWT malformed */ }
|
|
425
|
-
}
|
|
426
|
-
cachedCodexAccount = '';
|
|
427
|
-
return undefined;
|
|
428
|
-
}
|
|
429
|
-
// ---------------------------------------------------------------------------
|
|
430
|
-
// Codex
|
|
431
|
-
// ---------------------------------------------------------------------------
|
|
432
|
-
/** Incrementally re-scan changed Codex session files and upsert into the DB. */
|
|
433
|
-
async function scanCodexIncremental(onProgress) {
|
|
434
|
-
const account = getCodexAccount();
|
|
435
|
-
const currentVersion = await getCurrentAgentVersion('codex');
|
|
436
|
-
const filePaths = [];
|
|
437
|
-
for (const sessionsDir of getAgentSessionDirs('codex', 'sessions')) {
|
|
438
|
-
// High limit: we only stat files here, parsing is gated by ledger match.
|
|
439
|
-
for (const fp of walkForFiles(sessionsDir, '.jsonl', 100_000)) {
|
|
440
|
-
filePaths.push(fp);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
const changed = filterChangedFiles(filePaths);
|
|
444
|
-
if (changed.length === 0)
|
|
445
|
-
return;
|
|
446
|
-
onProgress?.({ agent: 'codex', parsed: 0, total: changed.length });
|
|
447
|
-
const entries = [];
|
|
448
|
-
const touched = [];
|
|
449
|
-
const seen = new Set();
|
|
450
|
-
let parsed = 0;
|
|
451
|
-
for (const { filePath, scan } of changed) {
|
|
452
|
-
try {
|
|
453
|
-
const result = await readCodexMeta(filePath, account, currentVersion);
|
|
454
|
-
if (result && !seen.has(result.meta.id)) {
|
|
455
|
-
seen.add(result.meta.id);
|
|
456
|
-
entries.push({ meta: result.meta, content: result.content, scan });
|
|
457
|
-
}
|
|
458
|
-
else {
|
|
459
|
-
touched.push({ filePath, scan });
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
catch {
|
|
463
|
-
touched.push({ filePath, scan });
|
|
464
|
-
}
|
|
465
|
-
parsed++;
|
|
466
|
-
onProgress?.({ agent: 'codex', parsed, total: changed.length });
|
|
467
|
-
}
|
|
468
|
-
upsertSessionsBatch(entries);
|
|
469
|
-
recordScans(touched);
|
|
470
|
-
}
|
|
471
|
-
/** Stream-parse a single Codex JSONL file to extract session metadata. */
|
|
472
|
-
async function readCodexMeta(filePath, account, currentVersion) {
|
|
473
|
-
const scan = await scanCodexSession(filePath);
|
|
474
|
-
const sessionId = scan.sessionId || '';
|
|
475
|
-
if (!sessionId)
|
|
476
|
-
return null;
|
|
477
|
-
const cwd = normalizeCwd(scan.cwd || '');
|
|
478
|
-
const meta = {
|
|
479
|
-
id: sessionId,
|
|
480
|
-
shortId: sessionId.slice(0, 8),
|
|
481
|
-
agent: 'codex',
|
|
482
|
-
timestamp: scan.timestamp || new Date().toISOString(),
|
|
483
|
-
project: cwd ? path.basename(cwd) : undefined,
|
|
484
|
-
cwd,
|
|
485
|
-
filePath,
|
|
486
|
-
gitBranch: scan.gitBranch,
|
|
487
|
-
version: resolveSessionVersion('codex', filePath, scan.version, currentVersion),
|
|
488
|
-
topic: scan.topic,
|
|
489
|
-
messageCount: scan.messageCount,
|
|
490
|
-
tokenCount: scan.tokenCount,
|
|
491
|
-
account,
|
|
492
|
-
};
|
|
493
|
-
return { meta, content: scan.contentText || '' };
|
|
494
|
-
}
|
|
495
|
-
// ---------------------------------------------------------------------------
|
|
496
|
-
// Gemini
|
|
497
|
-
// ---------------------------------------------------------------------------
|
|
498
|
-
/** Incrementally re-scan changed Gemini session files and upsert into the DB. */
|
|
499
|
-
async function scanGeminiIncremental(onProgress) {
|
|
500
|
-
const currentVersion = await getCurrentAgentVersion('gemini');
|
|
501
|
-
const projectMap = buildGeminiProjectMap();
|
|
502
|
-
const filePaths = [];
|
|
503
|
-
for (const tmpDir of getAgentSessionDirs('gemini', 'tmp')) {
|
|
504
|
-
let hashDirs;
|
|
505
|
-
try {
|
|
506
|
-
hashDirs = fs.readdirSync(tmpDir);
|
|
507
|
-
}
|
|
508
|
-
catch {
|
|
509
|
-
continue;
|
|
510
|
-
}
|
|
511
|
-
for (const hashDir of hashDirs) {
|
|
512
|
-
const chatsDir = path.join(tmpDir, hashDir, 'chats');
|
|
513
|
-
if (!fs.existsSync(chatsDir))
|
|
514
|
-
continue;
|
|
515
|
-
let chatFiles;
|
|
516
|
-
try {
|
|
517
|
-
chatFiles = fs.readdirSync(chatsDir).filter(f => f.endsWith('.json'));
|
|
518
|
-
}
|
|
519
|
-
catch {
|
|
520
|
-
continue;
|
|
521
|
-
}
|
|
522
|
-
for (const file of chatFiles) {
|
|
523
|
-
filePaths.push({ filePath: path.join(chatsDir, file), hashDir });
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
const changedPaths = filterChangedFiles(filePaths.map(f => f.filePath));
|
|
528
|
-
const changedByPath = new Map(changedPaths.map(c => [c.filePath, c.scan]));
|
|
529
|
-
if (changedByPath.size === 0)
|
|
530
|
-
return;
|
|
531
|
-
onProgress?.({ agent: 'gemini', parsed: 0, total: changedByPath.size });
|
|
532
|
-
const entries = [];
|
|
533
|
-
const touched = [];
|
|
534
|
-
const seen = new Set();
|
|
535
|
-
let parsed = 0;
|
|
536
|
-
for (const { filePath, hashDir } of filePaths) {
|
|
537
|
-
const scan = changedByPath.get(filePath);
|
|
538
|
-
if (!scan)
|
|
539
|
-
continue;
|
|
540
|
-
try {
|
|
541
|
-
const result = readGeminiMeta(filePath, hashDir, projectMap, currentVersion);
|
|
542
|
-
if (result && !seen.has(result.meta.id)) {
|
|
543
|
-
seen.add(result.meta.id);
|
|
544
|
-
entries.push({ meta: result.meta, content: result.content, scan });
|
|
545
|
-
}
|
|
546
|
-
else {
|
|
547
|
-
// Gemini file without a sessionId — record scan so we don't re-parse it next run.
|
|
548
|
-
touched.push({ filePath, scan });
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
catch {
|
|
552
|
-
touched.push({ filePath, scan });
|
|
553
|
-
}
|
|
554
|
-
parsed++;
|
|
555
|
-
onProgress?.({ agent: 'gemini', parsed, total: changedByPath.size });
|
|
556
|
-
}
|
|
557
|
-
upsertSessionsBatch(entries);
|
|
558
|
-
recordScans(touched);
|
|
559
|
-
}
|
|
560
|
-
/** Parse a single Gemini JSON session file to extract session metadata. */
|
|
561
|
-
function readGeminiMeta(filePath, hashDir, projectMap, currentVersion) {
|
|
562
|
-
let session;
|
|
563
|
-
try {
|
|
564
|
-
session = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
565
|
-
}
|
|
566
|
-
catch {
|
|
567
|
-
return null;
|
|
568
|
-
}
|
|
569
|
-
const sessionId = typeof session.sessionId === 'string' ? session.sessionId : '';
|
|
570
|
-
const startTime = typeof session.startTime === 'string' ? session.startTime : '';
|
|
571
|
-
const projectHash = typeof session.projectHash === 'string' ? session.projectHash : '';
|
|
572
|
-
const embeddedVersion = typeof session.version === 'string'
|
|
573
|
-
? session.version
|
|
574
|
-
: typeof session.cliVersion === 'string'
|
|
575
|
-
? session.cliVersion
|
|
576
|
-
: undefined;
|
|
577
|
-
if (!sessionId)
|
|
578
|
-
return null;
|
|
579
|
-
const projectInfo = projectMap.get(projectHash || hashDir);
|
|
580
|
-
const project = projectInfo?.name || hashDir.slice(0, 12);
|
|
581
|
-
const cwd = projectInfo?.path ? normalizeCwd(projectInfo.path) : undefined;
|
|
582
|
-
const stat = safeStatSync(filePath);
|
|
583
|
-
const messages = Array.isArray(session.messages) ? session.messages : [];
|
|
584
|
-
let topic;
|
|
585
|
-
let messageCount = 0;
|
|
586
|
-
let tokenCount = 0;
|
|
587
|
-
let sawTokenCount = false;
|
|
588
|
-
const userTexts = [];
|
|
589
|
-
for (const message of messages) {
|
|
590
|
-
if (message.type === 'user') {
|
|
591
|
-
const text = extractGeminiMessageText(message.content);
|
|
592
|
-
if (text) {
|
|
593
|
-
messageCount++;
|
|
594
|
-
userTexts.push(text);
|
|
595
|
-
if (!topic)
|
|
596
|
-
topic = extractSessionTopic(text);
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
else if (message.type === 'gemini') {
|
|
600
|
-
if (extractGeminiMessageText(message.content)) {
|
|
601
|
-
messageCount++;
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
const total = getGeminiTokenCount(message.tokens);
|
|
605
|
-
if (total !== null) {
|
|
606
|
-
tokenCount += total;
|
|
607
|
-
sawTokenCount = true;
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
const meta = {
|
|
611
|
-
id: sessionId,
|
|
612
|
-
shortId: sessionId.slice(0, 8),
|
|
613
|
-
agent: 'gemini',
|
|
614
|
-
timestamp: startTime || (stat ? stat.mtime.toISOString() : new Date().toISOString()),
|
|
615
|
-
project,
|
|
616
|
-
cwd,
|
|
617
|
-
filePath,
|
|
618
|
-
version: resolveSessionVersion('gemini', filePath, embeddedVersion, currentVersion),
|
|
619
|
-
topic,
|
|
620
|
-
messageCount,
|
|
621
|
-
tokenCount: sawTokenCount ? tokenCount : undefined,
|
|
622
|
-
};
|
|
623
|
-
return { meta, content: userTexts.join('\n') };
|
|
624
|
-
}
|
|
625
|
-
/** Build a hash-to-project mapping from Gemini's projects.json and history directories. */
|
|
626
|
-
function buildGeminiProjectMap() {
|
|
627
|
-
const map = new Map();
|
|
628
|
-
const projectsJsonPath = path.join(HOME, '.gemini', 'projects.json');
|
|
629
|
-
if (fs.existsSync(projectsJsonPath)) {
|
|
630
|
-
try {
|
|
631
|
-
const data = JSON.parse(fs.readFileSync(projectsJsonPath, 'utf-8'));
|
|
632
|
-
const projects = data.projects;
|
|
633
|
-
if (typeof projects === 'object' && projects !== null) {
|
|
634
|
-
if (Array.isArray(projects)) {
|
|
635
|
-
for (const p of projects) {
|
|
636
|
-
if (typeof p === 'string') {
|
|
637
|
-
const hash = sha256(p);
|
|
638
|
-
map.set(hash, { name: path.basename(p), path: p });
|
|
639
|
-
map.set(p, { name: path.basename(p), path: p });
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
else {
|
|
644
|
-
for (const [p, name] of Object.entries(projects)) {
|
|
645
|
-
const hash = sha256(p);
|
|
646
|
-
map.set(hash, { name: String(name), path: p });
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
catch { /* projects.json missing or malformed */ }
|
|
652
|
-
}
|
|
653
|
-
const historyDir = path.join(HOME, '.gemini', 'history');
|
|
654
|
-
if (fs.existsSync(historyDir)) {
|
|
655
|
-
try {
|
|
656
|
-
for (const name of fs.readdirSync(historyDir)) {
|
|
657
|
-
const rootFile = path.join(historyDir, name, '.project_root');
|
|
658
|
-
if (fs.existsSync(rootFile)) {
|
|
659
|
-
try {
|
|
660
|
-
const projectPath = fs.readFileSync(rootFile, 'utf-8').trim();
|
|
661
|
-
if (projectPath) {
|
|
662
|
-
const hash = sha256(projectPath);
|
|
663
|
-
map.set(hash, { name, path: projectPath });
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
catch { /* history entry unreadable */ }
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
catch { /* history entry unreadable */ }
|
|
671
|
-
}
|
|
672
|
-
return map;
|
|
673
|
-
}
|
|
674
|
-
// ---------------------------------------------------------------------------
|
|
675
|
-
// OpenCode
|
|
676
|
-
// ---------------------------------------------------------------------------
|
|
677
|
-
const OPENCODE_DB = path.join(HOME, '.local', 'share', 'opencode', 'opencode.db');
|
|
678
|
-
let cachedOpenCodeAccount;
|
|
679
|
-
/** Query the active OpenCode account email from its SQLite database. */
|
|
680
|
-
function getOpenCodeAccount() {
|
|
681
|
-
if (cachedOpenCodeAccount !== undefined)
|
|
682
|
-
return cachedOpenCodeAccount || undefined;
|
|
683
|
-
try {
|
|
684
|
-
if (fs.existsSync(OPENCODE_DB)) {
|
|
685
|
-
const out = execSync(`sqlite3 "${OPENCODE_DB}" "SELECT email FROM control_account WHERE active=1 LIMIT 1;"`, { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
|
|
686
|
-
if (out) {
|
|
687
|
-
cachedOpenCodeAccount = out;
|
|
688
|
-
return out;
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
catch { /* sqlite3 unavailable or DB locked */ }
|
|
693
|
-
cachedOpenCodeAccount = '';
|
|
694
|
-
return undefined;
|
|
695
|
-
}
|
|
696
|
-
/** Scan OpenCode sessions from its SQLite database when the DB file has changed. */
|
|
697
|
-
async function scanOpenCodeIncremental() {
|
|
698
|
-
if (!fs.existsSync(OPENCODE_DB))
|
|
699
|
-
return;
|
|
700
|
-
const stat = safeStatSync(OPENCODE_DB);
|
|
701
|
-
if (!stat)
|
|
702
|
-
return;
|
|
703
|
-
// OpenCode is one big DB; we use its mtime/size as the ledger for the
|
|
704
|
-
// entire fleet of OpenCode sessions.
|
|
705
|
-
const currentScan = {
|
|
706
|
-
fileMtimeMs: Math.floor(stat.mtimeMs),
|
|
707
|
-
fileSize: stat.size,
|
|
708
|
-
};
|
|
709
|
-
const prev = getScanStampByPath(OPENCODE_DB);
|
|
710
|
-
if (prev && prev.fileMtimeMs === currentScan.fileMtimeMs && prev.fileSize === currentScan.fileSize) {
|
|
711
|
-
return;
|
|
712
|
-
}
|
|
713
|
-
const account = getOpenCodeAccount();
|
|
714
|
-
const currentVersion = await getCurrentAgentVersion('opencode');
|
|
715
|
-
try {
|
|
716
|
-
const query = `
|
|
717
|
-
SELECT
|
|
718
|
-
s.id,
|
|
719
|
-
s.title,
|
|
720
|
-
s.directory,
|
|
721
|
-
s.version,
|
|
722
|
-
s.time_created,
|
|
723
|
-
COALESCE(stats.message_count, 0),
|
|
724
|
-
stats.token_count,
|
|
725
|
-
COALESCE(stats.has_token_data, 0)
|
|
726
|
-
FROM session s
|
|
727
|
-
LEFT JOIN (
|
|
728
|
-
SELECT
|
|
729
|
-
session_id,
|
|
730
|
-
COUNT(*) AS message_count,
|
|
731
|
-
SUM(
|
|
732
|
-
COALESCE(json_extract(data, '$.tokens.input'), 0) +
|
|
733
|
-
COALESCE(json_extract(data, '$.tokens.output'), 0) +
|
|
734
|
-
COALESCE(json_extract(data, '$.tokens.reasoning'), 0) +
|
|
735
|
-
COALESCE(json_extract(data, '$.tokens.cache.read'), 0) +
|
|
736
|
-
COALESCE(json_extract(data, '$.tokens.cache.write'), 0)
|
|
737
|
-
) AS token_count,
|
|
738
|
-
MAX(CASE WHEN json_type(data, '$.tokens') IS NOT NULL THEN 1 ELSE 0 END) AS has_token_data
|
|
739
|
-
FROM message
|
|
740
|
-
GROUP BY session_id
|
|
741
|
-
) stats ON stats.session_id = s.id
|
|
742
|
-
WHERE s.parent_id IS NULL
|
|
743
|
-
ORDER BY time_created DESC
|
|
744
|
-
LIMIT 1000;
|
|
745
|
-
`.replace(/\n/g, ' ');
|
|
746
|
-
const out = execSync(`sqlite3 -separator '|||' "${OPENCODE_DB}"`, { encoding: 'utf-8', input: query, stdio: ['pipe', 'pipe', 'ignore'], timeout: 5000 });
|
|
747
|
-
const entries = [];
|
|
748
|
-
for (const line of out.split('\n')) {
|
|
749
|
-
if (!line.trim())
|
|
750
|
-
continue;
|
|
751
|
-
const [id, title, directory, version, timeCreatedStr, messageCountStr, tokenCountStr, hasTokenDataStr] = line.split('|||');
|
|
752
|
-
if (!id)
|
|
753
|
-
continue;
|
|
754
|
-
const timeCreated = parseInt(timeCreatedStr, 10);
|
|
755
|
-
const messageCount = parseInt(messageCountStr, 10);
|
|
756
|
-
const tokenCount = parseInt(tokenCountStr, 10);
|
|
757
|
-
const hasTokenData = hasTokenDataStr === '1';
|
|
758
|
-
const timestamp = isNaN(timeCreated) ? new Date().toISOString() : new Date(timeCreated).toISOString();
|
|
759
|
-
const topic = title || undefined;
|
|
760
|
-
const meta = {
|
|
761
|
-
id,
|
|
762
|
-
shortId: id.replace(/^ses_/, '').slice(0, 8),
|
|
763
|
-
agent: 'opencode',
|
|
764
|
-
timestamp,
|
|
765
|
-
project: directory ? path.basename(directory) : undefined,
|
|
766
|
-
cwd: directory ? normalizeCwd(directory) : undefined,
|
|
767
|
-
filePath: `${OPENCODE_DB}#${id}`,
|
|
768
|
-
version: resolveSessionVersion('opencode', OPENCODE_DB, version || undefined, currentVersion),
|
|
769
|
-
account,
|
|
770
|
-
topic,
|
|
771
|
-
messageCount: Number.isNaN(messageCount) ? undefined : messageCount,
|
|
772
|
-
tokenCount: hasTokenData && !Number.isNaN(tokenCount) ? tokenCount : undefined,
|
|
773
|
-
};
|
|
774
|
-
entries.push({ meta, content: topic || '', scan: currentScan });
|
|
775
|
-
}
|
|
776
|
-
upsertSessionsBatch(entries);
|
|
777
|
-
// Stamp the OpenCode DB itself so we can short-circuit on the next run.
|
|
778
|
-
recordScans([{ filePath: OPENCODE_DB, scan: currentScan }]);
|
|
779
|
-
}
|
|
780
|
-
catch (err) {
|
|
781
|
-
if (process.stderr.isTTY) {
|
|
782
|
-
console.error(`Warning: Could not query OpenCode sessions: ${err.message}`);
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
// ---------------------------------------------------------------------------
|
|
787
|
-
// OpenClaw
|
|
788
|
-
// ---------------------------------------------------------------------------
|
|
789
|
-
/** Scan active OpenClaw channels and cron jobs via the openclaw CLI. */
|
|
790
|
-
async function scanOpenClawIncremental() {
|
|
791
|
-
// Check if openclaw is installed — silently skip if not.
|
|
792
|
-
try {
|
|
793
|
-
execSync('which openclaw', { stdio: 'ignore' });
|
|
794
|
-
}
|
|
795
|
-
catch {
|
|
796
|
-
return;
|
|
797
|
-
}
|
|
798
|
-
// TTL cache: skip subprocess calls if we scanned recently. Stored in the
|
|
799
|
-
// meta table so we skip even when no channels/cron exist to produce rows.
|
|
800
|
-
const db = getDB();
|
|
801
|
-
const row = db.prepare(`SELECT value FROM meta WHERE key = 'openclaw_last_scan_ms'`).get();
|
|
802
|
-
const lastScanMs = row ? parseInt(row.value, 10) : 0;
|
|
803
|
-
if (lastScanMs && Date.now() - lastScanMs < OPENCLAW_TTL_MS) {
|
|
804
|
-
return;
|
|
805
|
-
}
|
|
806
|
-
const currentVersion = await getCurrentAgentVersion('openclaw');
|
|
807
|
-
const now = Date.now();
|
|
808
|
-
const scan = { fileMtimeMs: now, fileSize: 0 };
|
|
809
|
-
const entries = [];
|
|
810
|
-
try {
|
|
811
|
-
const output = execSync('openclaw channels status', {
|
|
812
|
-
encoding: 'utf-8',
|
|
813
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
814
|
-
});
|
|
815
|
-
for (const line of output.split('\n')) {
|
|
816
|
-
const match = line.match(/^-\s+\w+\s+(\S+)\s+\((\w+)\):\s*(.+)/);
|
|
817
|
-
if (!match)
|
|
818
|
-
continue;
|
|
819
|
-
const [, agentId, name, statusStr] = match;
|
|
820
|
-
if (!statusStr.includes('running'))
|
|
821
|
-
continue;
|
|
822
|
-
entries.push({
|
|
823
|
-
meta: {
|
|
824
|
-
id: `openclaw-${agentId}`,
|
|
825
|
-
shortId: agentId.slice(0, 8),
|
|
826
|
-
agent: 'openclaw',
|
|
827
|
-
timestamp: new Date().toISOString(),
|
|
828
|
-
project: name,
|
|
829
|
-
cwd: getOpenClawSessionCwd(agentId),
|
|
830
|
-
version: currentVersion,
|
|
831
|
-
filePath: '',
|
|
832
|
-
},
|
|
833
|
-
content: `${name} ${agentId}`,
|
|
834
|
-
scan,
|
|
835
|
-
});
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
catch {
|
|
839
|
-
/* channels command failed */
|
|
840
|
-
}
|
|
841
|
-
try {
|
|
842
|
-
const output = execSync('openclaw cron list', {
|
|
843
|
-
encoding: 'utf-8',
|
|
844
|
-
stdio: ['ignore', 'pipe', 'ignore'],
|
|
845
|
-
});
|
|
846
|
-
const lines = output.split('\n');
|
|
847
|
-
for (let i = 1; i < lines.length; i++) {
|
|
848
|
-
const line = lines[i].trim();
|
|
849
|
-
if (!line)
|
|
850
|
-
continue;
|
|
851
|
-
const headMatch = line.match(/^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\s+(\S+)/);
|
|
852
|
-
if (!headMatch)
|
|
853
|
-
continue;
|
|
854
|
-
const jobId = headMatch[1];
|
|
855
|
-
const jobName = headMatch[2];
|
|
856
|
-
const rest = line.slice(headMatch[0].length).trim();
|
|
857
|
-
const cols = rest.split(/\s{2,}/);
|
|
858
|
-
const agentId = cols[4] || '';
|
|
859
|
-
entries.push({
|
|
860
|
-
meta: {
|
|
861
|
-
id: `openclaw-cron-${jobId}`,
|
|
862
|
-
shortId: jobId.slice(0, 8),
|
|
863
|
-
agent: 'openclaw',
|
|
864
|
-
timestamp: new Date().toISOString(),
|
|
865
|
-
project: `${jobName} (${agentId || 'unknown'})`,
|
|
866
|
-
cwd: getOpenClawSessionCwd(agentId),
|
|
867
|
-
version: currentVersion,
|
|
868
|
-
filePath: '',
|
|
869
|
-
},
|
|
870
|
-
content: `${jobName} ${agentId}`,
|
|
871
|
-
scan,
|
|
872
|
-
});
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
catch {
|
|
876
|
-
/* cron command failed */
|
|
877
|
-
}
|
|
878
|
-
upsertSessionsBatch(entries);
|
|
879
|
-
db.prepare(`INSERT OR REPLACE INTO meta (key, value) VALUES ('openclaw_last_scan_ms', ?)`).run(String(Date.now()));
|
|
880
|
-
}
|
|
881
|
-
/** Stream a Claude JSONL file and extract scan-level metadata (timestamp, cwd, topic, tokens). */
|
|
882
|
-
async function scanClaudeSession(filePath) {
|
|
883
|
-
const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });
|
|
884
|
-
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
885
|
-
let timestamp;
|
|
886
|
-
let cwd;
|
|
887
|
-
let gitBranch;
|
|
888
|
-
let version;
|
|
889
|
-
let topic;
|
|
890
|
-
let entrypoint;
|
|
891
|
-
let messageCount = 0;
|
|
892
|
-
let tokenCount = 0;
|
|
893
|
-
let sawTokenCount = false;
|
|
894
|
-
const seenAssistantIds = new Set();
|
|
895
|
-
const userTexts = [];
|
|
896
|
-
try {
|
|
897
|
-
for await (const line of rl) {
|
|
898
|
-
if (!line.trim())
|
|
899
|
-
continue;
|
|
900
|
-
let parsed;
|
|
901
|
-
try {
|
|
902
|
-
parsed = JSON.parse(line);
|
|
903
|
-
}
|
|
904
|
-
catch {
|
|
905
|
-
continue;
|
|
906
|
-
}
|
|
907
|
-
// entrypoint ships on the first envelope event (attachment/user/assistant)
|
|
908
|
-
// and is the clean structural signal for "was this a team spawn?"
|
|
909
|
-
if (!entrypoint && typeof parsed.entrypoint === 'string') {
|
|
910
|
-
entrypoint = parsed.entrypoint;
|
|
911
|
-
}
|
|
912
|
-
if (!timestamp && (parsed.type === 'user' || parsed.type === 'assistant') && parsed.timestamp) {
|
|
913
|
-
timestamp = parsed.timestamp;
|
|
914
|
-
cwd = parsed.cwd || '';
|
|
915
|
-
gitBranch = parsed.gitBranch || undefined;
|
|
916
|
-
version = parsed.version || undefined;
|
|
917
|
-
}
|
|
918
|
-
if (parsed.type === 'user') {
|
|
919
|
-
const text = extractClaudeUserText(parsed);
|
|
920
|
-
if (text) {
|
|
921
|
-
messageCount++;
|
|
922
|
-
userTexts.push(text);
|
|
923
|
-
if (!topic)
|
|
924
|
-
topic = extractSessionTopic(text);
|
|
925
|
-
}
|
|
926
|
-
continue;
|
|
927
|
-
}
|
|
928
|
-
if (parsed.type !== 'assistant')
|
|
929
|
-
continue;
|
|
930
|
-
const assistantId = typeof parsed.message?.id === 'string'
|
|
931
|
-
? parsed.message.id
|
|
932
|
-
: typeof parsed.uuid === 'string'
|
|
933
|
-
? parsed.uuid
|
|
934
|
-
: undefined;
|
|
935
|
-
const logicalId = assistantId || `${parsed.timestamp || ''}:${seenAssistantIds.size}`;
|
|
936
|
-
if (seenAssistantIds.has(logicalId))
|
|
937
|
-
continue;
|
|
938
|
-
seenAssistantIds.add(logicalId);
|
|
939
|
-
messageCount++;
|
|
940
|
-
const usage = getClaudeUsageTotal(parsed.message?.usage || parsed.usage);
|
|
941
|
-
if (usage !== null) {
|
|
942
|
-
tokenCount += usage;
|
|
943
|
-
sawTokenCount = true;
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
}
|
|
947
|
-
finally {
|
|
948
|
-
rl.close();
|
|
949
|
-
stream.destroy();
|
|
950
|
-
}
|
|
951
|
-
return {
|
|
952
|
-
timestamp,
|
|
953
|
-
cwd,
|
|
954
|
-
gitBranch,
|
|
955
|
-
version,
|
|
956
|
-
topic,
|
|
957
|
-
entrypoint,
|
|
958
|
-
messageCount,
|
|
959
|
-
tokenCount: sawTokenCount ? tokenCount : undefined,
|
|
960
|
-
contentText: userTexts.length > 0 ? userTexts.join('\n') : undefined,
|
|
961
|
-
};
|
|
962
|
-
}
|
|
963
|
-
/** Stream a Codex JSONL file and extract scan-level metadata (session ID, cwd, topic, tokens). */
|
|
964
|
-
async function scanCodexSession(filePath) {
|
|
965
|
-
const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });
|
|
966
|
-
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
967
|
-
let sessionId;
|
|
968
|
-
let timestamp;
|
|
969
|
-
let cwd;
|
|
970
|
-
let gitBranch;
|
|
971
|
-
let version;
|
|
972
|
-
let topic;
|
|
973
|
-
let messageCount = 0;
|
|
974
|
-
let tokenCount;
|
|
975
|
-
const userTexts = [];
|
|
976
|
-
try {
|
|
977
|
-
for await (const line of rl) {
|
|
978
|
-
if (!line.trim())
|
|
979
|
-
continue;
|
|
980
|
-
let parsed;
|
|
981
|
-
try {
|
|
982
|
-
parsed = JSON.parse(line);
|
|
983
|
-
}
|
|
984
|
-
catch {
|
|
985
|
-
continue;
|
|
986
|
-
}
|
|
987
|
-
if (parsed.type === 'session_meta') {
|
|
988
|
-
const payload = parsed.payload || {};
|
|
989
|
-
sessionId = payload.id || sessionId;
|
|
990
|
-
timestamp = payload.timestamp || parsed.timestamp || timestamp;
|
|
991
|
-
cwd = payload.cwd || cwd;
|
|
992
|
-
gitBranch = payload.git?.branch || gitBranch;
|
|
993
|
-
version = payload.cli_version || payload.version || version;
|
|
994
|
-
continue;
|
|
995
|
-
}
|
|
996
|
-
if (parsed.type === 'response_item' && parsed.payload?.type === 'message') {
|
|
997
|
-
const role = parsed.payload.role === 'user' || parsed.payload.role === 'developer'
|
|
998
|
-
? 'user'
|
|
999
|
-
: 'assistant';
|
|
1000
|
-
const text = extractCodexMessageText(parsed.payload.content, role);
|
|
1001
|
-
if (!text)
|
|
1002
|
-
continue;
|
|
1003
|
-
messageCount++;
|
|
1004
|
-
if (role === 'user') {
|
|
1005
|
-
userTexts.push(text);
|
|
1006
|
-
if (!topic)
|
|
1007
|
-
topic = extractSessionTopic(text);
|
|
1008
|
-
}
|
|
1009
|
-
continue;
|
|
1010
|
-
}
|
|
1011
|
-
if (parsed.type === 'event_msg' && parsed.payload?.type === 'token_count') {
|
|
1012
|
-
const total = getCodexTokenCount(parsed.payload.info?.total_token_usage);
|
|
1013
|
-
if (total !== null)
|
|
1014
|
-
tokenCount = total;
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
}
|
|
1018
|
-
finally {
|
|
1019
|
-
rl.close();
|
|
1020
|
-
stream.destroy();
|
|
1021
|
-
}
|
|
1022
|
-
return {
|
|
1023
|
-
sessionId,
|
|
1024
|
-
timestamp,
|
|
1025
|
-
cwd,
|
|
1026
|
-
gitBranch,
|
|
1027
|
-
version,
|
|
1028
|
-
topic,
|
|
1029
|
-
messageCount,
|
|
1030
|
-
tokenCount,
|
|
1031
|
-
contentText: userTexts.length > 0 ? userTexts.join('\n') : undefined,
|
|
1032
|
-
};
|
|
1033
|
-
}
|
|
1034
|
-
/** Resolve the working directory for an OpenClaw agent from its workspace config. */
|
|
1035
|
-
function getOpenClawSessionCwd(agentId) {
|
|
1036
|
-
const workspace = agentId ? getOpenClawWorkspaceMap().get(agentId) : undefined;
|
|
1037
|
-
if (workspace)
|
|
1038
|
-
return workspace;
|
|
1039
|
-
const configDir = AGENTS.openclaw.configDir;
|
|
1040
|
-
return safeRealpathSync(configDir) || configDir;
|
|
1041
|
-
}
|
|
1042
|
-
/** Build a cached map of OpenClaw agent ID to workspace path from openclaw.json. */
|
|
1043
|
-
function getOpenClawWorkspaceMap() {
|
|
1044
|
-
if (cachedOpenClawWorkspaces)
|
|
1045
|
-
return cachedOpenClawWorkspaces;
|
|
1046
|
-
const workspaces = new Map();
|
|
1047
|
-
const configPath = path.join(AGENTS.openclaw.configDir, 'openclaw.json');
|
|
1048
|
-
if (!fs.existsSync(configPath)) {
|
|
1049
|
-
cachedOpenClawWorkspaces = workspaces;
|
|
1050
|
-
return workspaces;
|
|
1051
|
-
}
|
|
1052
|
-
try {
|
|
1053
|
-
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
1054
|
-
for (const agent of config.agents?.list || []) {
|
|
1055
|
-
if (!agent.id || !agent.workspace)
|
|
1056
|
-
continue;
|
|
1057
|
-
workspaces.set(agent.id, safeRealpathSync(agent.workspace) || agent.workspace);
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
catch {
|
|
1061
|
-
// Ignore invalid OpenClaw config and fall back to ~/.openclaw.
|
|
1062
|
-
}
|
|
1063
|
-
cachedOpenClawWorkspaces = workspaces;
|
|
1064
|
-
return workspaces;
|
|
1065
|
-
}
|
|
1066
|
-
// ---------------------------------------------------------------------------
|
|
1067
|
-
// Utilities
|
|
1068
|
-
// ---------------------------------------------------------------------------
|
|
1069
|
-
/** Read up to maxLines non-empty lines from the beginning of a file. */
|
|
1070
|
-
export function readFirstLines(filePath, maxLines) {
|
|
1071
|
-
return new Promise((resolve) => {
|
|
1072
|
-
const lines = [];
|
|
1073
|
-
const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });
|
|
1074
|
-
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
1075
|
-
rl.on('line', (line) => {
|
|
1076
|
-
if (line.trim()) {
|
|
1077
|
-
lines.push(line);
|
|
1078
|
-
}
|
|
1079
|
-
if (lines.length >= maxLines) {
|
|
1080
|
-
rl.close();
|
|
1081
|
-
stream.destroy();
|
|
1082
|
-
}
|
|
1083
|
-
});
|
|
1084
|
-
rl.on('close', () => resolve(lines));
|
|
1085
|
-
rl.on('error', () => resolve(lines));
|
|
1086
|
-
});
|
|
1087
|
-
}
|
|
1088
|
-
/**
|
|
1089
|
-
* Walk a directory recursively for files with a given extension.
|
|
1090
|
-
*/
|
|
1091
|
-
export function walkForFiles(dir, ext, limit) {
|
|
1092
|
-
const results = [];
|
|
1093
|
-
function walk(d, depth) {
|
|
1094
|
-
if (depth > 5)
|
|
1095
|
-
return;
|
|
1096
|
-
let entries;
|
|
1097
|
-
try {
|
|
1098
|
-
entries = fs.readdirSync(d);
|
|
1099
|
-
}
|
|
1100
|
-
catch {
|
|
1101
|
-
return;
|
|
1102
|
-
}
|
|
1103
|
-
for (const entry of entries) {
|
|
1104
|
-
const full = path.join(d, entry);
|
|
1105
|
-
const stat = safeStatSync(full);
|
|
1106
|
-
if (!stat)
|
|
1107
|
-
continue;
|
|
1108
|
-
if (stat.isDirectory()) {
|
|
1109
|
-
walk(full, depth + 1);
|
|
1110
|
-
}
|
|
1111
|
-
else if (entry.endsWith(ext)) {
|
|
1112
|
-
results.push({ path: full, mtime: stat.mtimeMs });
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
walk(dir, 0);
|
|
1117
|
-
results.sort((a, b) => b.mtime - a.mtime);
|
|
1118
|
-
return results.slice(0, limit).map(r => r.path);
|
|
1119
|
-
}
|
|
1120
|
-
/** Compute the SHA-256 hex digest of a string. */
|
|
1121
|
-
function sha256(input) {
|
|
1122
|
-
return crypto.createHash('sha256').update(input).digest('hex');
|
|
1123
|
-
}
|
|
1124
|
-
/** Stat a path, returning null on any error. */
|
|
1125
|
-
function safeStatSync(p) {
|
|
1126
|
-
try {
|
|
1127
|
-
return fs.statSync(p);
|
|
1128
|
-
}
|
|
1129
|
-
catch {
|
|
1130
|
-
return null;
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
/** Resolve a path to its real path, returning null on any error. */
|
|
1134
|
-
function safeRealpathSync(p) {
|
|
1135
|
-
try {
|
|
1136
|
-
return fs.realpathSync(p);
|
|
1137
|
-
}
|
|
1138
|
-
catch {
|
|
1139
|
-
return null;
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
/** Extract meaningful user text from a Claude JSONL user event, skipping meta and local-command messages. */
|
|
1143
|
-
function extractClaudeUserText(parsed) {
|
|
1144
|
-
if (parsed.isMeta === true)
|
|
1145
|
-
return undefined;
|
|
1146
|
-
const content = parsed.message?.content;
|
|
1147
|
-
if (typeof content === 'string') {
|
|
1148
|
-
const text = content.trim();
|
|
1149
|
-
return isLocalCommandMessage(text) ? undefined : text || undefined;
|
|
1150
|
-
}
|
|
1151
|
-
if (!Array.isArray(content))
|
|
1152
|
-
return undefined;
|
|
1153
|
-
const text = content
|
|
1154
|
-
.filter((block) => block.type === 'text')
|
|
1155
|
-
.map((block) => String(block.text || '').trim())
|
|
1156
|
-
.find((value) => value && !value.startsWith('[Request interrupted'));
|
|
1157
|
-
if (!text || isLocalCommandMessage(text))
|
|
1158
|
-
return undefined;
|
|
1159
|
-
return text;
|
|
1160
|
-
}
|
|
1161
|
-
/** Check whether a message is a local-command wrapper rather than real user input. */
|
|
1162
|
-
function isLocalCommandMessage(text) {
|
|
1163
|
-
return /<local-command-caveat>|<bash-(input|stdout|stderr)>/i.test(text);
|
|
1164
|
-
}
|
|
1165
|
-
/** Sum all token usage fields from a Claude assistant message's usage object. */
|
|
1166
|
-
function getClaudeUsageTotal(usage) {
|
|
1167
|
-
if (!usage || typeof usage !== 'object')
|
|
1168
|
-
return null;
|
|
1169
|
-
return sumKnownNumbers([
|
|
1170
|
-
usage.input_tokens,
|
|
1171
|
-
usage.output_tokens,
|
|
1172
|
-
usage.cache_creation_input_tokens,
|
|
1173
|
-
usage.cache_read_input_tokens,
|
|
1174
|
-
]);
|
|
1175
|
-
}
|
|
1176
|
-
/** Extract text from Codex message content blocks, filtering out system instructions for user messages. */
|
|
1177
|
-
function extractCodexMessageText(contentBlocks, role) {
|
|
1178
|
-
if (!Array.isArray(contentBlocks))
|
|
1179
|
-
return undefined;
|
|
1180
|
-
const matches = role === 'user'
|
|
1181
|
-
? contentBlocks.filter((block) => block.type === 'input_text')
|
|
1182
|
-
: contentBlocks.filter((block) => block.type === 'output_text');
|
|
1183
|
-
const text = matches
|
|
1184
|
-
.map((block) => String(block.text || '').trim())
|
|
1185
|
-
.find((value) => {
|
|
1186
|
-
if (!value)
|
|
1187
|
-
return false;
|
|
1188
|
-
if (role === 'user' && (value.length >= 2000 || value.includes('<permissions instructions>') || value.startsWith('# AGENTS.md instructions'))) {
|
|
1189
|
-
return false;
|
|
1190
|
-
}
|
|
1191
|
-
return true;
|
|
1192
|
-
});
|
|
1193
|
-
return text || undefined;
|
|
1194
|
-
}
|
|
1195
|
-
/** Trim and normalize a version string, returning undefined for empty values. */
|
|
1196
|
-
function normalizeVersion(version) {
|
|
1197
|
-
const trimmed = version?.trim();
|
|
1198
|
-
return trimmed ? trimmed : undefined;
|
|
1199
|
-
}
|
|
1200
|
-
/** Extract the version number from a managed ~/.agents/versions/<agent>/<version>/... path. */
|
|
1201
|
-
function extractVersionFromManagedPath(agent, sourcePath) {
|
|
1202
|
-
if (!sourcePath)
|
|
1203
|
-
return undefined;
|
|
1204
|
-
const candidates = [sourcePath, safeRealpathSync(sourcePath) || ''];
|
|
1205
|
-
const marker = `/.agents/versions/${agent}/`;
|
|
1206
|
-
for (const candidate of candidates) {
|
|
1207
|
-
if (!candidate)
|
|
1208
|
-
continue;
|
|
1209
|
-
const normalized = candidate.split(path.sep).join('/');
|
|
1210
|
-
const start = normalized.indexOf(marker);
|
|
1211
|
-
if (start === -1)
|
|
1212
|
-
continue;
|
|
1213
|
-
const version = normalized.slice(start + marker.length).split('/')[0];
|
|
1214
|
-
if (version)
|
|
1215
|
-
return version;
|
|
1216
|
-
}
|
|
1217
|
-
return undefined;
|
|
1218
|
-
}
|
|
1219
|
-
/** Resolve the current version of an agent CLI (symlink version or live CLI output, cached). */
|
|
1220
|
-
async function getCurrentAgentVersion(agent) {
|
|
1221
|
-
const cached = cachedAgentVersions.get(agent);
|
|
1222
|
-
if (cached)
|
|
1223
|
-
return cached;
|
|
1224
|
-
const promise = (async () => {
|
|
1225
|
-
const symlinkVersion = normalizeVersion(getConfigSymlinkVersion(agent));
|
|
1226
|
-
if (symlinkVersion)
|
|
1227
|
-
return symlinkVersion;
|
|
1228
|
-
return normalizeVersion(await getCliVersion(agent));
|
|
1229
|
-
})();
|
|
1230
|
-
cachedAgentVersions.set(agent, promise);
|
|
1231
|
-
return promise;
|
|
1232
|
-
}
|
|
1233
|
-
/** Resolve a session's version: embedded in file > extracted from managed path > current CLI version. */
|
|
1234
|
-
function resolveSessionVersion(agent, sourcePath, embeddedVersion, currentVersion) {
|
|
1235
|
-
return normalizeVersion(embeddedVersion)
|
|
1236
|
-
|| extractVersionFromManagedPath(agent, sourcePath)
|
|
1237
|
-
|| normalizeVersion(currentVersion);
|
|
1238
|
-
}
|
|
1239
|
-
/** Sum all token usage fields from a Codex total_token_usage object. */
|
|
1240
|
-
function getCodexTokenCount(totalTokenUsage) {
|
|
1241
|
-
if (!totalTokenUsage || typeof totalTokenUsage !== 'object')
|
|
1242
|
-
return null;
|
|
1243
|
-
return sumKnownNumbers([
|
|
1244
|
-
totalTokenUsage.input_tokens,
|
|
1245
|
-
totalTokenUsage.cached_input_tokens,
|
|
1246
|
-
totalTokenUsage.output_tokens,
|
|
1247
|
-
totalTokenUsage.reasoning_output_tokens,
|
|
1248
|
-
]);
|
|
1249
|
-
}
|
|
1250
|
-
/** Extract text from a Gemini message content field (string or array of parts). */
|
|
1251
|
-
function extractGeminiMessageText(content) {
|
|
1252
|
-
if (typeof content === 'string')
|
|
1253
|
-
return content.trim();
|
|
1254
|
-
if (Array.isArray(content)) {
|
|
1255
|
-
return content
|
|
1256
|
-
.map((part) => {
|
|
1257
|
-
if (typeof part === 'string')
|
|
1258
|
-
return part;
|
|
1259
|
-
if (typeof part?.text === 'string')
|
|
1260
|
-
return part.text;
|
|
1261
|
-
return '';
|
|
1262
|
-
})
|
|
1263
|
-
.join('\n')
|
|
1264
|
-
.trim();
|
|
1265
|
-
}
|
|
1266
|
-
return '';
|
|
1267
|
-
}
|
|
1268
|
-
/** Extract the total token count from a Gemini message's tokens object. */
|
|
1269
|
-
function getGeminiTokenCount(tokens) {
|
|
1270
|
-
if (!tokens || typeof tokens !== 'object')
|
|
1271
|
-
return null;
|
|
1272
|
-
if (typeof tokens.total === 'number')
|
|
1273
|
-
return tokens.total;
|
|
1274
|
-
return sumKnownNumbers([
|
|
1275
|
-
tokens.input,
|
|
1276
|
-
tokens.output,
|
|
1277
|
-
tokens.cached,
|
|
1278
|
-
tokens.thoughts,
|
|
1279
|
-
tokens.tool,
|
|
1280
|
-
]);
|
|
1281
|
-
}
|
|
1282
|
-
/** Sum all numeric values in an array, returning null if none are valid numbers. */
|
|
1283
|
-
function sumKnownNumbers(values) {
|
|
1284
|
-
let total = 0;
|
|
1285
|
-
let found = false;
|
|
1286
|
-
for (const value of values) {
|
|
1287
|
-
if (typeof value !== 'number' || Number.isNaN(value))
|
|
1288
|
-
continue;
|
|
1289
|
-
total += value;
|
|
1290
|
-
found = true;
|
|
1291
|
-
}
|
|
1292
|
-
return found ? total : null;
|
|
1293
|
-
}
|
|
1294
|
-
// ---------------------------------------------------------------------------
|
|
1295
|
-
// Time range parsing
|
|
1296
|
-
// ---------------------------------------------------------------------------
|
|
1297
|
-
/** Parse a time filter string (relative like '7d' or ISO timestamp) into epoch milliseconds. */
|
|
1298
|
-
export function parseTimeFilter(input) {
|
|
1299
|
-
const relativeMatch = input.match(/^(\d+)([mhdw])$/i);
|
|
1300
|
-
if (relativeMatch) {
|
|
1301
|
-
const value = parseInt(relativeMatch[1], 10);
|
|
1302
|
-
const unit = relativeMatch[2].toLowerCase();
|
|
1303
|
-
if (unit === 'm')
|
|
1304
|
-
return Date.now() - value * 60_000;
|
|
1305
|
-
if (unit === 'h')
|
|
1306
|
-
return Date.now() - value * 3_600_000;
|
|
1307
|
-
if (unit === 'd')
|
|
1308
|
-
return Date.now() - value * 86_400_000;
|
|
1309
|
-
if (unit === 'w')
|
|
1310
|
-
return Date.now() - value * 7 * 86_400_000;
|
|
1311
|
-
}
|
|
1312
|
-
const ts = new Date(input).getTime();
|
|
1313
|
-
return Number.isNaN(ts) ? 0 : ts;
|
|
1314
|
-
}
|
|
1315
|
-
//# sourceMappingURL=discover.js.map
|