@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,1173 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session discovery, search, and rendering commands.
|
|
3
|
-
*
|
|
4
|
-
* Implements `agents sessions` -- the unified interface for finding, browsing,
|
|
5
|
-
* and reading agent conversation transcripts across Claude, Codex, Gemini,
|
|
6
|
-
* and OpenCode. Supports interactive picker mode, text/path search, markdown
|
|
7
|
-
* and JSON rendering, role/turn filtering, artifact inspection, and session
|
|
8
|
-
* resume via agent-native CLI flags.
|
|
9
|
-
*/
|
|
10
|
-
import * as fs from 'fs';
|
|
11
|
-
import * as os from 'os';
|
|
12
|
-
import * as path from 'path';
|
|
13
|
-
import { spawn } from 'child_process';
|
|
14
|
-
import chalk from 'chalk';
|
|
15
|
-
import ora from 'ora';
|
|
16
|
-
import { SESSION_AGENTS } from '../lib/session/types.js';
|
|
17
|
-
import { discoverArtifacts, readArtifact, resolveArtifact } from '../lib/session/artifacts.js';
|
|
18
|
-
import { getActiveSessions } from '../lib/session/active.js';
|
|
19
|
-
import { discoverSessions, countSessionsInScope, resolveSessionById, searchContentIndex } from '../lib/session/discover.js';
|
|
20
|
-
import { filterTeamSessions } from '../lib/session/team-filter.js';
|
|
21
|
-
import { parseSession } from '../lib/session/parse.js';
|
|
22
|
-
import { renderConversationMarkdown, renderSummary, renderSummaryHeader, computeSummaryStats, renderJson, filterEvents, parseRoleList } from '../lib/session/render.js';
|
|
23
|
-
import { renderMarkdown } from '../lib/markdown.js';
|
|
24
|
-
import { colorAgent } from '../lib/agents.js';
|
|
25
|
-
import { resolveVersion } from '../lib/versions.js';
|
|
26
|
-
import { isInteractiveTerminal, isPromptCancelled } from './utils.js';
|
|
27
|
-
import { sessionPicker } from './sessions-picker.js';
|
|
28
|
-
import { registerSessionsTailCommand } from './sessions-tail.js';
|
|
29
|
-
const SESSION_AGENT_FILTER_HELP = `Filter by agent, e.g. claude, codex, claude@2.0.65`;
|
|
30
|
-
const CLAUDE_RESUME_MATCH_WINDOW_MS = 10 * 60_000;
|
|
31
|
-
const LOAD_VERBS = ['Loading', 'Scanning', 'Gathering', 'Indexing', 'Reading'];
|
|
32
|
-
const FIND_VERBS = ['Finding', 'Searching', 'Locating', 'Matching'];
|
|
33
|
-
/** Build a spinner-backed progress tracker that cycles through verbs while scanning sessions. */
|
|
34
|
-
function createScanProgressTracker(verbs, suffix, spinner) {
|
|
35
|
-
const counts = new Map();
|
|
36
|
-
let verbIndex = 0;
|
|
37
|
-
const render = () => {
|
|
38
|
-
if (!spinner)
|
|
39
|
-
return;
|
|
40
|
-
const verb = verbs[verbIndex % verbs.length];
|
|
41
|
-
const parts = [];
|
|
42
|
-
for (const agent of SESSION_AGENTS) {
|
|
43
|
-
const c = counts.get(agent);
|
|
44
|
-
if (!c || c.total === 0)
|
|
45
|
-
continue;
|
|
46
|
-
parts.push(`${agent} ${c.parsed}/${c.total}`);
|
|
47
|
-
}
|
|
48
|
-
const base = `${verb} ${suffix}...`;
|
|
49
|
-
spinner.text = parts.length > 0 ? `${base} (${parts.join(' · ')})` : base;
|
|
50
|
-
};
|
|
51
|
-
const interval = spinner
|
|
52
|
-
? setInterval(() => {
|
|
53
|
-
verbIndex++;
|
|
54
|
-
render();
|
|
55
|
-
}, 900)
|
|
56
|
-
: null;
|
|
57
|
-
render();
|
|
58
|
-
return {
|
|
59
|
-
onProgress: (progress) => {
|
|
60
|
-
counts.set(progress.agent, { parsed: progress.parsed, total: progress.total });
|
|
61
|
-
render();
|
|
62
|
-
},
|
|
63
|
-
stop: () => {
|
|
64
|
-
if (interval)
|
|
65
|
-
clearInterval(interval);
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
const PICKER_RECENT_COUNT = 15;
|
|
70
|
-
const PICKER_POOL_LIMIT = 200;
|
|
71
|
-
/**
|
|
72
|
-
* Detect whether a positional argument looks like a filesystem path.
|
|
73
|
-
* Naked paths (., ./, ../, /, ~) filter sessions by project directory.
|
|
74
|
-
* Everything else is treated as a search query string.
|
|
75
|
-
*/
|
|
76
|
-
function isPathLike(query) {
|
|
77
|
-
return query === '.' || query.startsWith('./') || query.startsWith('../')
|
|
78
|
-
|| query.startsWith('/') || query.startsWith('~');
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Resolve a path-like query to an absolute directory path.
|
|
82
|
-
*/
|
|
83
|
-
function resolvePathFilter(query) {
|
|
84
|
-
const expanded = query.startsWith('~')
|
|
85
|
-
? path.join(os.homedir(), query.slice(1))
|
|
86
|
-
: query;
|
|
87
|
-
return path.resolve(expanded);
|
|
88
|
-
}
|
|
89
|
-
function formatBytes(n) {
|
|
90
|
-
if (n < 1024)
|
|
91
|
-
return `${n} B`;
|
|
92
|
-
if (n < 1024 * 1024)
|
|
93
|
-
return `${(n / 1024).toFixed(1)} KB`;
|
|
94
|
-
return `${(n / (1024 * 1024)).toFixed(1)} MB`;
|
|
95
|
-
}
|
|
96
|
-
async function renderArtifactsForSession(session, listAll, name) {
|
|
97
|
-
const artifacts = discoverArtifacts(session);
|
|
98
|
-
if (name !== undefined) {
|
|
99
|
-
const artifact = resolveArtifact(artifacts, name);
|
|
100
|
-
if (!artifact) {
|
|
101
|
-
console.error(chalk.red(`No artifact matching "${name}" in session ${session.shortId}.`));
|
|
102
|
-
if (artifacts.length > 0) {
|
|
103
|
-
console.error(chalk.gray('Available artifacts:'));
|
|
104
|
-
for (const a of artifacts) {
|
|
105
|
-
console.error(chalk.gray(` ${a.path}`));
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
process.exit(1);
|
|
109
|
-
}
|
|
110
|
-
if (!artifact.exists) {
|
|
111
|
-
console.error(chalk.red(`Artifact exists in session history but the file is no longer on disk: ${artifact.path}`));
|
|
112
|
-
process.exit(1);
|
|
113
|
-
}
|
|
114
|
-
process.stdout.write(readArtifact(artifact));
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
if (artifacts.length === 0) {
|
|
118
|
-
console.log(chalk.gray('No file-write artifacts found in this session.'));
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
const agentColor = colorAgent(session.agent);
|
|
122
|
-
console.log('');
|
|
123
|
-
console.log(agentColor(session.agent) +
|
|
124
|
-
chalk.gray(` · ${session.shortId} · ${formatRelativeTime(session.timestamp)}`));
|
|
125
|
-
console.log(chalk.gray('─'.repeat(72)));
|
|
126
|
-
for (const a of artifacts) {
|
|
127
|
-
const exists = a.exists ? chalk.green('yes') : chalk.red('no');
|
|
128
|
-
const size = a.exists && a.sizeBytes !== undefined ? chalk.cyan(formatBytes(a.sizeBytes)) : chalk.gray('-');
|
|
129
|
-
const tool = chalk.yellow(padRight(a.tool, 10));
|
|
130
|
-
const when = chalk.gray(formatRelativeTime(a.timestamp));
|
|
131
|
-
const p = chalk.white(a.path);
|
|
132
|
-
console.log(` ${exists} ${size.padEnd(10)} ${tool} ${when.padEnd(16)} ${p}`);
|
|
133
|
-
}
|
|
134
|
-
console.log(chalk.gray(`\n${artifacts.length} artifact${artifacts.length !== 1 ? 's' : ''}.`));
|
|
135
|
-
}
|
|
136
|
-
function statusColor(status) {
|
|
137
|
-
switch (status) {
|
|
138
|
-
case 'running': return chalk.green;
|
|
139
|
-
case 'idle': return chalk.gray;
|
|
140
|
-
case 'queued': return chalk.blue;
|
|
141
|
-
case 'input_required': return chalk.yellow;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
function contextColor(context) {
|
|
145
|
-
switch (context) {
|
|
146
|
-
case 'terminal': return chalk.magenta;
|
|
147
|
-
case 'teams': return chalk.cyan;
|
|
148
|
-
case 'cloud': return chalk.blue;
|
|
149
|
-
case 'headless': return chalk.gray;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
function shortCwd(cwd) {
|
|
153
|
-
if (!cwd)
|
|
154
|
-
return '-';
|
|
155
|
-
const home = os.homedir();
|
|
156
|
-
return cwd.startsWith(home) ? '~' + cwd.slice(home.length) : cwd;
|
|
157
|
-
}
|
|
158
|
-
function formatStartedAt(startedAtMs) {
|
|
159
|
-
if (!startedAtMs)
|
|
160
|
-
return '-';
|
|
161
|
-
return formatRelativeTime(new Date(startedAtMs).toISOString());
|
|
162
|
-
}
|
|
163
|
-
/** Render the unified active-session view. */
|
|
164
|
-
async function renderActiveSessions(asJson) {
|
|
165
|
-
const sessions = await getActiveSessions();
|
|
166
|
-
if (asJson) {
|
|
167
|
-
process.stdout.write(JSON.stringify(sessions, null, 2) + '\n');
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
if (sessions.length === 0) {
|
|
171
|
-
console.log(chalk.gray('No active agent sessions.'));
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
for (const s of sessions) {
|
|
175
|
-
const kindCol = colorAgent(s.kind)(padRight(truncate(s.kind, 8), 9));
|
|
176
|
-
const ctxCol = contextColor(s.context)(padRight(truncate(s.context, 8), 9));
|
|
177
|
-
const hostCol = chalk.gray(padRight(truncate(s.host ?? '-', 8), 9));
|
|
178
|
-
const statusCol = statusColor(s.status)(padRight(truncate(s.status, 8), 9));
|
|
179
|
-
const pidCol = chalk.yellow(padRight(s.pid ? String(s.pid) : '-', 7));
|
|
180
|
-
const idCol = chalk.white(padRight(s.sessionId ? s.sessionId.slice(0, 8) : '-', 10));
|
|
181
|
-
const detail = s.context === 'cloud'
|
|
182
|
-
? `${s.cloudProvider ?? ''}${s.cloudTaskId ? ` · ${s.cloudTaskId.slice(0, 12)}` : ''}`
|
|
183
|
-
: s.context === 'teams'
|
|
184
|
-
? `${s.teamName ?? ''}${s.label ? ` · ${s.label}` : ''}`
|
|
185
|
-
: s.label ?? shortCwd(s.cwd);
|
|
186
|
-
console.log(pidCol +
|
|
187
|
-
kindCol +
|
|
188
|
-
ctxCol +
|
|
189
|
-
hostCol +
|
|
190
|
-
statusCol +
|
|
191
|
-
idCol +
|
|
192
|
-
chalk.cyan(padRight(truncate(detail || '-', 30), 32)) +
|
|
193
|
-
chalk.gray(formatStartedAt(s.startedAtMs)));
|
|
194
|
-
}
|
|
195
|
-
const runningCount = sessions.filter(s => s.status === 'running').length;
|
|
196
|
-
const idleCount = sessions.filter(s => s.status === 'idle').length;
|
|
197
|
-
const queuedCount = sessions.filter(s => s.status === 'queued' || s.status === 'input_required').length;
|
|
198
|
-
const parts = [];
|
|
199
|
-
if (runningCount > 0)
|
|
200
|
-
parts.push(`${runningCount} running`);
|
|
201
|
-
if (idleCount > 0)
|
|
202
|
-
parts.push(`${idleCount} idle`);
|
|
203
|
-
if (queuedCount > 0)
|
|
204
|
-
parts.push(`${queuedCount} queued`);
|
|
205
|
-
console.log(chalk.gray(`\n${sessions.length} active (${parts.join(', ')}).`));
|
|
206
|
-
}
|
|
207
|
-
/** Main action handler for `agents sessions`. Routes to picker, table, or single-session render. */
|
|
208
|
-
async function sessionsAction(query, options) {
|
|
209
|
-
if (options.active) {
|
|
210
|
-
await renderActiveSessions(options.json === true);
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
let filterOpts;
|
|
214
|
-
try {
|
|
215
|
-
filterOpts = buildFilterOptions(options);
|
|
216
|
-
}
|
|
217
|
-
catch (err) {
|
|
218
|
-
console.error(chalk.red(err.message));
|
|
219
|
-
process.exit(1);
|
|
220
|
-
}
|
|
221
|
-
const { agent, version } = parseAgentFilter(options.agent);
|
|
222
|
-
// Path-like queries filter by project directory instead of text search.
|
|
223
|
-
let pathFilter;
|
|
224
|
-
let searchQuery;
|
|
225
|
-
if (query && isPathLike(query)) {
|
|
226
|
-
const resolved = resolvePathFilter(query);
|
|
227
|
-
if (!fs.existsSync(resolved)) {
|
|
228
|
-
console.log(chalk.yellow(`Path not found: ${resolved}`));
|
|
229
|
-
console.log(chalk.gray('Did you mean to search? Use quotes: agents sessions "' + query + '"'));
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
pathFilter = fs.realpathSync(resolved);
|
|
233
|
-
}
|
|
234
|
-
else {
|
|
235
|
-
searchQuery = query;
|
|
236
|
-
}
|
|
237
|
-
// Artifact flags require a session query.
|
|
238
|
-
if ((options.artifacts || options.artifact !== undefined) && !query) {
|
|
239
|
-
console.error(chalk.red('--artifacts and --artifact require a session ID or query.'));
|
|
240
|
-
process.exit(1);
|
|
241
|
-
}
|
|
242
|
-
const mode = resolveViewMode(options, filterOpts);
|
|
243
|
-
// --markdown or any filter flag forces single-session render.
|
|
244
|
-
const wantsRender = mode === 'markdown' || hasAnyFilter(filterOpts);
|
|
245
|
-
// Artifact-list or artifact-read paths: widen scope and resolve session globally.
|
|
246
|
-
if ((options.artifacts || options.artifact !== undefined) && searchQuery) {
|
|
247
|
-
await renderArtifactsGlobal(searchQuery, options.artifacts ?? false, options.artifact, { agent: options.agent, project: options.project });
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
// When the user explicitly asks to render (via mode flag), resolve the
|
|
251
|
-
// query globally so sessions outside the default cwd/30d window are found.
|
|
252
|
-
if (wantsRender && searchQuery) {
|
|
253
|
-
await renderOneSession(searchQuery, mode, { agent: options.agent, project: options.project, filter: filterOpts });
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
// Interactive picker loads a deep pool but shows only recent sessions
|
|
257
|
-
// until the user starts typing. Non-interactive/JSON uses the explicit limit.
|
|
258
|
-
const isInteractive = !options.json && isInteractiveTerminal();
|
|
259
|
-
const limit = parseInt(options.limit || (isInteractive ? String(PICKER_POOL_LIMIT) : '50'), 10);
|
|
260
|
-
const since = options.since ?? (isInteractive && !options.all ? '30d' : undefined);
|
|
261
|
-
const spinner = options.json ? null : ora().start();
|
|
262
|
-
const tracker = createScanProgressTracker(LOAD_VERBS, 'sessions', spinner);
|
|
263
|
-
try {
|
|
264
|
-
// Team-origin filter is pushed down to SQL so the LIMIT applies AFTER it.
|
|
265
|
-
// Without this, a dev dir with heavy SDK spawn activity (Task subagents,
|
|
266
|
-
// `agents run`, team agents) can fill the top-N window entirely with
|
|
267
|
-
// hidden rows and make real CLI sessions appear to vanish.
|
|
268
|
-
const scope = {
|
|
269
|
-
agent,
|
|
270
|
-
version,
|
|
271
|
-
all: pathFilter ? undefined : options.all,
|
|
272
|
-
cwd: process.cwd(),
|
|
273
|
-
cwdPrefix: pathFilter,
|
|
274
|
-
project: options.project,
|
|
275
|
-
since,
|
|
276
|
-
until: options.until,
|
|
277
|
-
};
|
|
278
|
-
let sessions = await discoverSessions({
|
|
279
|
-
...scope,
|
|
280
|
-
limit,
|
|
281
|
-
excludeTeamOrigin: !options.teams,
|
|
282
|
-
onProgress: tracker.onProgress,
|
|
283
|
-
});
|
|
284
|
-
tracker.stop();
|
|
285
|
-
spinner?.stop();
|
|
286
|
-
// Version filter is pushed down to SQL via scope.version above; no
|
|
287
|
-
// post-filter needed. Defensive: the team-origin SQL filter covers the
|
|
288
|
-
// ~100% case, but classifyTeamSession also recognizes sessions with a
|
|
289
|
-
// meta.json in ~/.agents/teams/agents whose is_team_origin flag was
|
|
290
|
-
// never set (legacy rows). Keep the in-memory pass so those are still
|
|
291
|
-
// enriched/hidden.
|
|
292
|
-
const { visible: visibleSessions } = filterTeamSessions(sessions, !!options.teams);
|
|
293
|
-
sessions = visibleSessions;
|
|
294
|
-
const hiddenCount = options.teams
|
|
295
|
-
? 0
|
|
296
|
-
: countSessionsInScope({ ...scope, onlyTeamOrigin: true });
|
|
297
|
-
// Smart ID routing: a bare query that resolves to one session renders
|
|
298
|
-
// directly. If nothing matches in the scoped window and the query looks
|
|
299
|
-
// like a session ID, widen to global scope (incl. Claude /resume history).
|
|
300
|
-
if (searchQuery) {
|
|
301
|
-
const idMatches = resolveSessionById(sessions, searchQuery);
|
|
302
|
-
if (idMatches.length === 1) {
|
|
303
|
-
await renderSession(idMatches[0], mode, filterOpts);
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
if (idMatches.length === 0 && looksLikeSessionId(searchQuery)) {
|
|
307
|
-
await renderOneSession(searchQuery, mode, { agent: options.agent, project: options.project, filter: filterOpts });
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
if (options.json) {
|
|
312
|
-
const filtered = searchQuery ? filterSessionsByQuery(sessions, searchQuery) : sessions;
|
|
313
|
-
const serializable = filtered.map(s => {
|
|
314
|
-
const { _matchedTerms, _bm25Score, ...rest } = s;
|
|
315
|
-
return rest;
|
|
316
|
-
});
|
|
317
|
-
process.stdout.write(JSON.stringify(serializable, null, 2) + '\n');
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
if (sessions.length === 0) {
|
|
321
|
-
if (pathFilter) {
|
|
322
|
-
console.log(chalk.gray(`No sessions found for ${pathFilter}.`));
|
|
323
|
-
}
|
|
324
|
-
else {
|
|
325
|
-
console.log(chalk.gray(formatNoSessionsMessage(options.all, options.project)));
|
|
326
|
-
}
|
|
327
|
-
if (hiddenCount > 0) {
|
|
328
|
-
console.log(chalk.gray(formatTeamHiddenFooter(hiddenCount)));
|
|
329
|
-
}
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
if (isInteractiveTerminal()) {
|
|
333
|
-
const message = pathFilter
|
|
334
|
-
? `Search sessions (${path.basename(pathFilter)}):`
|
|
335
|
-
: formatSearchMessage(options);
|
|
336
|
-
const picked = await pickSessionInteractive(sessions, message, searchQuery, hiddenCount);
|
|
337
|
-
if (picked) {
|
|
338
|
-
await handlePickedSession(picked);
|
|
339
|
-
return;
|
|
340
|
-
}
|
|
341
|
-
return;
|
|
342
|
-
}
|
|
343
|
-
// Non-interactive fallback (piped output)
|
|
344
|
-
const filtered = searchQuery ? filterSessionsByQuery(sessions, searchQuery) : sessions;
|
|
345
|
-
printSessionTable(filtered, hiddenCount);
|
|
346
|
-
}
|
|
347
|
-
catch (err) {
|
|
348
|
-
tracker.stop();
|
|
349
|
-
spinner?.stop();
|
|
350
|
-
console.error(chalk.red(`Failed to discover sessions: ${err.message}`));
|
|
351
|
-
process.exit(1);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
function looksLikeSessionId(query) {
|
|
355
|
-
return /^[0-9a-f-]{6,}$/i.test(query.trim());
|
|
356
|
-
}
|
|
357
|
-
function teamTag(session) {
|
|
358
|
-
const origin = session.teamOrigin;
|
|
359
|
-
if (!origin)
|
|
360
|
-
return '';
|
|
361
|
-
const parts = [origin.handle, origin.mode].filter(Boolean).join(' · ');
|
|
362
|
-
return parts ? `[${parts}] ` : '[team] ';
|
|
363
|
-
}
|
|
364
|
-
function printSessionTable(sessions, hiddenCount = 0) {
|
|
365
|
-
for (const session of sessions) {
|
|
366
|
-
const agentColor = colorAgent(session.agent);
|
|
367
|
-
const when = formatRelativeTime(session.timestamp);
|
|
368
|
-
const project = session.project || '-';
|
|
369
|
-
const tag = teamTag(session);
|
|
370
|
-
const label = session.label;
|
|
371
|
-
const topic = tag ? `${tag}${session.topic ?? ''}` : session.topic;
|
|
372
|
-
const versionStr = session.version || '-';
|
|
373
|
-
console.log(chalk.white(padRight(session.shortId, 10)) +
|
|
374
|
-
agentColor(padRight(truncate(session.agent, 8), 9)) +
|
|
375
|
-
chalk.yellow(padRight(truncate(versionStr, 7), 8)) +
|
|
376
|
-
chalk.cyan(padRight(truncate(project, 14), 16)) +
|
|
377
|
-
renderTopicCell(label, topic, '', 48, 50) +
|
|
378
|
-
chalk.gray(when));
|
|
379
|
-
}
|
|
380
|
-
const countLine = `${sessions.length} session${sessions.length === 1 ? '' : 's'}.`;
|
|
381
|
-
console.log(chalk.gray(`\n${countLine}`));
|
|
382
|
-
if (hiddenCount > 0) {
|
|
383
|
-
console.log(chalk.gray(formatTeamHiddenFooter(hiddenCount)));
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
function buildFilterOptions(options) {
|
|
387
|
-
const opts = {};
|
|
388
|
-
if (options.include)
|
|
389
|
-
opts.include = parseRoleList(options.include, '--include');
|
|
390
|
-
if (options.exclude)
|
|
391
|
-
opts.exclude = parseRoleList(options.exclude, '--exclude');
|
|
392
|
-
if (opts.include && opts.exclude) {
|
|
393
|
-
throw new Error('--include and --exclude are mutually exclusive');
|
|
394
|
-
}
|
|
395
|
-
const parseCount = (raw, flag) => {
|
|
396
|
-
const n = Number(raw);
|
|
397
|
-
if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
|
|
398
|
-
throw new Error(`${flag} expects a positive integer, got "${raw}"`);
|
|
399
|
-
}
|
|
400
|
-
return n;
|
|
401
|
-
};
|
|
402
|
-
if (options.first !== undefined)
|
|
403
|
-
opts.first = parseCount(options.first, '--first');
|
|
404
|
-
if (options.last !== undefined)
|
|
405
|
-
opts.last = parseCount(options.last, '--last');
|
|
406
|
-
if (opts.first !== undefined && opts.last !== undefined) {
|
|
407
|
-
throw new Error('--first and --last are mutually exclusive');
|
|
408
|
-
}
|
|
409
|
-
return opts;
|
|
410
|
-
}
|
|
411
|
-
function hasAnyFilter(opts) {
|
|
412
|
-
return !!(opts.include?.length || opts.exclude?.length || opts.first !== undefined || opts.last !== undefined);
|
|
413
|
-
}
|
|
414
|
-
/**
|
|
415
|
-
* Default is summary. Any explicit format flag wins. When filters are present
|
|
416
|
-
* without a format, default to markdown since summary is an aggregate view
|
|
417
|
-
* that filters don't meaningfully narrow.
|
|
418
|
-
*/
|
|
419
|
-
function resolveViewMode(options, filters) {
|
|
420
|
-
if (options.markdown)
|
|
421
|
-
return 'markdown';
|
|
422
|
-
if (options.json)
|
|
423
|
-
return 'json';
|
|
424
|
-
if (hasAnyFilter(filters))
|
|
425
|
-
return 'markdown';
|
|
426
|
-
return 'summary';
|
|
427
|
-
}
|
|
428
|
-
async function renderSession(session, mode, filters) {
|
|
429
|
-
// OpenCode stores sessions in SQLite; filePath is "db_path#session_id"
|
|
430
|
-
const realPath = session.filePath.split('#')[0];
|
|
431
|
-
if (!fs.existsSync(realPath)) {
|
|
432
|
-
console.log(chalk.yellow('Session transcript not available (file no longer exists).'));
|
|
433
|
-
console.log(chalk.gray(`Path: ${session.filePath}`));
|
|
434
|
-
if (session.version)
|
|
435
|
-
console.log(chalk.gray(`Version: ${session.agent} ${session.version}`));
|
|
436
|
-
if (session.project)
|
|
437
|
-
console.log(chalk.gray(`Project: ${session.project}`));
|
|
438
|
-
if (session.account)
|
|
439
|
-
console.log(chalk.gray(`Account: ${session.account}`));
|
|
440
|
-
console.log(chalk.gray(`Time: ${session.timestamp}`));
|
|
441
|
-
return;
|
|
442
|
-
}
|
|
443
|
-
const spinner = ora(`Parsing ${session.agent} session...`).start();
|
|
444
|
-
let events = parseSession(session.filePath, session.agent);
|
|
445
|
-
spinner.stop();
|
|
446
|
-
events = filterEvents(events, filters);
|
|
447
|
-
const agentColor = colorAgent(session.agent);
|
|
448
|
-
console.log('');
|
|
449
|
-
if (mode === 'summary') {
|
|
450
|
-
const stats = computeSummaryStats(events);
|
|
451
|
-
const modelStr = stats.models.length > 0 ? chalk.yellow(` ${stats.models.join(', ')}`) : '';
|
|
452
|
-
const branchStr = session.gitBranch ? chalk.gray(` (${session.gitBranch})`) : '';
|
|
453
|
-
const absTime = formatAbsoluteTime(session.timestamp);
|
|
454
|
-
console.log(agentColor(session.agent) +
|
|
455
|
-
(session.version ? chalk.yellow(` ${session.version}`) : '') +
|
|
456
|
-
modelStr +
|
|
457
|
-
(session.project ? chalk.cyan(` ${session.project}`) + branchStr : branchStr) +
|
|
458
|
-
chalk.gray(` ${absTime} (${formatRelativeTime(session.timestamp)})`) +
|
|
459
|
-
(session.account ? chalk.gray(` · ${session.account}`) : ''));
|
|
460
|
-
const statsLine = renderSummaryHeader(stats);
|
|
461
|
-
if (statsLine)
|
|
462
|
-
console.log(chalk.gray(statsLine));
|
|
463
|
-
console.log(chalk.gray('─'.repeat(60)));
|
|
464
|
-
process.stdout.write(renderSummary(events, session.cwd));
|
|
465
|
-
return;
|
|
466
|
-
}
|
|
467
|
-
if (mode === 'markdown') {
|
|
468
|
-
console.log(agentColor(session.agent) +
|
|
469
|
-
(session.version ? chalk.yellow(` ${session.version}`) : '') +
|
|
470
|
-
(session.project ? chalk.cyan(` ${session.project}`) : '') +
|
|
471
|
-
chalk.gray(` ${formatRelativeTime(session.timestamp)}`) +
|
|
472
|
-
(session.account ? chalk.gray(` (${session.account})`) : ''));
|
|
473
|
-
console.log(chalk.gray('─'.repeat(60)));
|
|
474
|
-
process.stdout.write(renderMarkdown(renderConversationMarkdown(events)));
|
|
475
|
-
return;
|
|
476
|
-
}
|
|
477
|
-
// json — no header, raw events only (pipeable)
|
|
478
|
-
process.stdout.write(renderJson(events));
|
|
479
|
-
}
|
|
480
|
-
function renderTopicCell(label, topic, query, visibleWidth, paddedWidth) {
|
|
481
|
-
const lbl = (label ?? '').trim();
|
|
482
|
-
const tpc = (topic ?? '').trim();
|
|
483
|
-
const sep = ' · ';
|
|
484
|
-
const raw = lbl && tpc ? `${lbl}${sep}${tpc}` : (lbl || tpc);
|
|
485
|
-
const visible = truncate(raw, visibleWidth);
|
|
486
|
-
const padding = ' '.repeat(Math.max(0, paddedWidth - visible.length));
|
|
487
|
-
const labelEnd = lbl ? Math.min(lbl.length, visible.length) : 0;
|
|
488
|
-
let matchStart = -1, matchEnd = -1;
|
|
489
|
-
const q = query.trim().toLowerCase();
|
|
490
|
-
if (q) {
|
|
491
|
-
const lower = visible.toLowerCase();
|
|
492
|
-
for (const term of q.split(/\s+/).filter(Boolean)) {
|
|
493
|
-
const idx = lower.indexOf(term);
|
|
494
|
-
if (idx !== -1) {
|
|
495
|
-
matchStart = idx;
|
|
496
|
-
matchEnd = idx + term.length;
|
|
497
|
-
break;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
const cuts = new Set([0, labelEnd, visible.length]);
|
|
502
|
-
if (matchStart >= 0) {
|
|
503
|
-
cuts.add(matchStart);
|
|
504
|
-
cuts.add(matchEnd);
|
|
505
|
-
}
|
|
506
|
-
const boundaries = [...cuts].sort((a, b) => a - b);
|
|
507
|
-
let out = '';
|
|
508
|
-
for (let i = 0; i < boundaries.length - 1; i++) {
|
|
509
|
-
const s = boundaries[i], e = boundaries[i + 1];
|
|
510
|
-
if (s >= e)
|
|
511
|
-
continue;
|
|
512
|
-
const text = visible.slice(s, e);
|
|
513
|
-
const isLabel = s < labelEnd;
|
|
514
|
-
const isMatch = matchStart >= 0 && s >= matchStart && e <= matchEnd;
|
|
515
|
-
out += (isMatch || isLabel) ? chalk.bold.white(text) : chalk.white(text);
|
|
516
|
-
}
|
|
517
|
-
return out + padding;
|
|
518
|
-
}
|
|
519
|
-
function formatPickerLabel(s, query) {
|
|
520
|
-
const agentColor = colorAgent(s.agent);
|
|
521
|
-
const when = formatRelativeTime(s.timestamp);
|
|
522
|
-
const project = s.project || '-';
|
|
523
|
-
const tag = teamTag(s);
|
|
524
|
-
const label = s.label;
|
|
525
|
-
const topic = tag ? `${tag}${s.topic ?? ''}` : s.topic;
|
|
526
|
-
const versionStr = s.version || '-';
|
|
527
|
-
return (chalk.white(padRight(s.shortId, 10)) +
|
|
528
|
-
agentColor(padRight(truncate(s.agent, 8), 9)) +
|
|
529
|
-
chalk.yellow(padRight(truncate(versionStr, 7), 8)) +
|
|
530
|
-
chalk.cyan(padRight(truncate(project, 14), 16)) +
|
|
531
|
-
renderTopicCell(label, topic, query, 48, 50) +
|
|
532
|
-
chalk.gray(when));
|
|
533
|
-
}
|
|
534
|
-
async function pickSessionInteractive(sessions, message = 'Search sessions:', initialSearch, hiddenCount = 0) {
|
|
535
|
-
if (hiddenCount > 0) {
|
|
536
|
-
console.log(chalk.gray(formatTeamHiddenFooter(hiddenCount)));
|
|
537
|
-
}
|
|
538
|
-
try {
|
|
539
|
-
return await sessionPicker({
|
|
540
|
-
message,
|
|
541
|
-
sessions,
|
|
542
|
-
filter: (query) => {
|
|
543
|
-
// No query: show the full pool (picker viewport still paginates via pageSize).
|
|
544
|
-
// Typing: search the full pool.
|
|
545
|
-
if (!query.trim())
|
|
546
|
-
return sessions;
|
|
547
|
-
return filterSessionsByQuery(sessions, query);
|
|
548
|
-
},
|
|
549
|
-
labelFor: (s, query) => formatPickerLabel(s, query),
|
|
550
|
-
pageSize: PICKER_RECENT_COUNT,
|
|
551
|
-
initialSearch,
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
catch (err) {
|
|
555
|
-
if (isPromptCancelled(err))
|
|
556
|
-
return null;
|
|
557
|
-
throw err;
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
async function handlePickedSession(picked) {
|
|
561
|
-
if (picked.action === 'view') {
|
|
562
|
-
await renderSession(picked.session, 'summary', {});
|
|
563
|
-
return;
|
|
564
|
-
}
|
|
565
|
-
const cwd = picked.session.cwd && fs.existsSync(picked.session.cwd)
|
|
566
|
-
? picked.session.cwd
|
|
567
|
-
: process.cwd();
|
|
568
|
-
const activeVersion = resolveVersion(picked.session.agent, cwd) ?? undefined;
|
|
569
|
-
const resume = buildResumeCommand(picked.session, activeVersion);
|
|
570
|
-
if (!resume) {
|
|
571
|
-
console.log(chalk.yellow(`Resume is not supported for ${picked.session.agent} sessions yet. Showing summary instead.`));
|
|
572
|
-
await renderSession(picked.session, 'summary', {});
|
|
573
|
-
return;
|
|
574
|
-
}
|
|
575
|
-
if (picked.session.version && activeVersion && picked.session.version !== activeVersion) {
|
|
576
|
-
console.log(chalk.gray(`Cross-version handoff: session is ${picked.session.agent} ${picked.session.version}, ` +
|
|
577
|
-
`default is ${activeVersion}. Starting fresh and passing /continue so the new agent ` +
|
|
578
|
-
`reads the prior transcript via 'agents sessions'.`));
|
|
579
|
-
}
|
|
580
|
-
console.log(chalk.gray(`Resuming: ${resume.join(' ')} (cwd: ${cwd})`));
|
|
581
|
-
await new Promise((resolve) => {
|
|
582
|
-
const child = spawn(resume[0], resume.slice(1), {
|
|
583
|
-
cwd,
|
|
584
|
-
stdio: 'inherit',
|
|
585
|
-
shell: false,
|
|
586
|
-
});
|
|
587
|
-
child.on('error', (err) => {
|
|
588
|
-
console.error(chalk.red(`Failed to launch ${resume[0]}: ${err.message}`));
|
|
589
|
-
if (err.code === 'ENOENT') {
|
|
590
|
-
console.error(chalk.gray(`Make sure '${resume[0]}' is on your PATH.`));
|
|
591
|
-
}
|
|
592
|
-
resolve();
|
|
593
|
-
});
|
|
594
|
-
child.on('close', () => resolve());
|
|
595
|
-
});
|
|
596
|
-
}
|
|
597
|
-
/**
|
|
598
|
-
* Build the shell command that resumes a picked session.
|
|
599
|
-
*
|
|
600
|
-
* Cross-version handoff: when the session was created on a different version
|
|
601
|
-
* than the one the shim will launch (activeVersion), the session file lives in
|
|
602
|
-
* the other version's isolated home and `--resume <id>` would silently fail to
|
|
603
|
-
* find it. Fall back to a fresh session seeded with `/continue <id>`, which is
|
|
604
|
-
* wired (~/.claude/commands/continue.md) to read the prior transcript via
|
|
605
|
-
* `agents sessions <id>` — that reader is version-agnostic.
|
|
606
|
-
*/
|
|
607
|
-
export function buildResumeCommand(session, activeVersion) {
|
|
608
|
-
const versionMismatch = !!(session.version && activeVersion && session.version !== activeVersion);
|
|
609
|
-
switch (session.agent) {
|
|
610
|
-
case 'claude':
|
|
611
|
-
if (versionMismatch)
|
|
612
|
-
return ['claude', `/continue ${session.id}`];
|
|
613
|
-
return ['claude', '--resume', session.id];
|
|
614
|
-
case 'codex':
|
|
615
|
-
if (versionMismatch)
|
|
616
|
-
return ['codex', `/continue ${session.id}`];
|
|
617
|
-
return ['codex', 'resume', session.id];
|
|
618
|
-
case 'opencode':
|
|
619
|
-
return ['opencode', '--session', session.id];
|
|
620
|
-
case 'gemini':
|
|
621
|
-
case 'openclaw':
|
|
622
|
-
return null;
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
function parseAgentFilter(agentName) {
|
|
626
|
-
if (!agentName)
|
|
627
|
-
return {};
|
|
628
|
-
const [name, version] = agentName.split('@', 2);
|
|
629
|
-
const agent = name;
|
|
630
|
-
if (!SESSION_AGENTS.includes(agent)) {
|
|
631
|
-
console.error(chalk.red(`Unknown agent: ${name}. Use: ${SESSION_AGENTS.join(', ')}`));
|
|
632
|
-
process.exit(1);
|
|
633
|
-
}
|
|
634
|
-
return { agent, version };
|
|
635
|
-
}
|
|
636
|
-
function formatSearchMessage(options) {
|
|
637
|
-
const filters = [];
|
|
638
|
-
if (options.agent)
|
|
639
|
-
filters.push(`agent: ${options.agent}`);
|
|
640
|
-
if (options.project?.trim())
|
|
641
|
-
filters.push(`project: ${options.project.trim()}`);
|
|
642
|
-
if (filters.length === 0)
|
|
643
|
-
return 'Search sessions:';
|
|
644
|
-
return `Search sessions (${filters.join(', ')}):`;
|
|
645
|
-
}
|
|
646
|
-
/** Filter and rank sessions by a multi-term search query across metadata and content. */
|
|
647
|
-
export function filterSessionsByQuery(sessions, query) {
|
|
648
|
-
const trimmed = query?.trim().toLowerCase() || '';
|
|
649
|
-
if (!trimmed)
|
|
650
|
-
return sessions;
|
|
651
|
-
const terms = trimmed.split(/\s+/).filter(Boolean);
|
|
652
|
-
const contentIndex = searchContentIndex(sessions, trimmed);
|
|
653
|
-
// If the query exactly matches a session label, short-circuit the structural
|
|
654
|
-
// scorer (which would otherwise surface every session whose topic happens to
|
|
655
|
-
// contain the same words) and return only the label hits.
|
|
656
|
-
const EXACT_LABEL_SCORE = 1_000_000;
|
|
657
|
-
const exactLabelHits = [...contentIndex.values()].filter(s => (s._bm25Score ?? 0) >= EXACT_LABEL_SCORE);
|
|
658
|
-
if (exactLabelHits.length > 0) {
|
|
659
|
-
return exactLabelHits.sort((a, b) => (b._bm25Score ?? 0) - (a._bm25Score ?? 0));
|
|
660
|
-
}
|
|
661
|
-
return sessions
|
|
662
|
-
.map(session => ({ session, score: scoreSessionQuery(session, terms) }))
|
|
663
|
-
.filter(entry => {
|
|
664
|
-
// Include if scored by topic/project/etc, or matched by content search
|
|
665
|
-
if (entry.score > 0)
|
|
666
|
-
return true;
|
|
667
|
-
const contentMatch = contentIndex.get(entry.session.id);
|
|
668
|
-
if (contentMatch && contentMatch._matchedTerms && contentMatch._matchedTerms.length > 0) {
|
|
669
|
-
return true;
|
|
670
|
-
}
|
|
671
|
-
return false;
|
|
672
|
-
})
|
|
673
|
-
.sort((a, b) => {
|
|
674
|
-
if (b.score !== a.score)
|
|
675
|
-
return b.score - a.score;
|
|
676
|
-
const cmA = contentIndex.get(a.session.id);
|
|
677
|
-
const cmB = contentIndex.get(b.session.id);
|
|
678
|
-
const bmA = cmA?._bm25Score ?? 0;
|
|
679
|
-
const bmB = cmB?._bm25Score ?? 0;
|
|
680
|
-
if (bmB !== bmA)
|
|
681
|
-
return bmB - bmA;
|
|
682
|
-
return new Date(b.session.timestamp).getTime() - new Date(a.session.timestamp).getTime();
|
|
683
|
-
})
|
|
684
|
-
.map(entry => {
|
|
685
|
-
// Attach content match terms for highlighting
|
|
686
|
-
const cm = contentIndex.get(entry.session.id);
|
|
687
|
-
if (cm && cm._matchedTerms) {
|
|
688
|
-
return { ...cm };
|
|
689
|
-
}
|
|
690
|
-
return entry.session;
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
function scoreSessionQuery(session, terms) {
|
|
694
|
-
let score = 0;
|
|
695
|
-
for (const term of terms) {
|
|
696
|
-
const exactId = session.id.toLowerCase() === term || session.shortId.toLowerCase() === term;
|
|
697
|
-
const prefixId = session.id.toLowerCase().startsWith(term) || session.shortId.toLowerCase().startsWith(term);
|
|
698
|
-
const topic = session.topic?.toLowerCase() || '';
|
|
699
|
-
const project = session.project?.toLowerCase() || '';
|
|
700
|
-
const account = session.account?.toLowerCase() || '';
|
|
701
|
-
const cwd = session.cwd?.toLowerCase() || '';
|
|
702
|
-
const agent = session.agent.toLowerCase();
|
|
703
|
-
const version = session.version?.toLowerCase() || '';
|
|
704
|
-
let termScore = 0;
|
|
705
|
-
if (exactId)
|
|
706
|
-
termScore = 1000;
|
|
707
|
-
else if (prefixId)
|
|
708
|
-
termScore = 900;
|
|
709
|
-
else if (topic.startsWith(term))
|
|
710
|
-
termScore = 700;
|
|
711
|
-
else if (project.startsWith(term))
|
|
712
|
-
termScore = 600;
|
|
713
|
-
else if (account.startsWith(term))
|
|
714
|
-
termScore = 550;
|
|
715
|
-
else if (agent.startsWith(term) || version.startsWith(term))
|
|
716
|
-
termScore = 500;
|
|
717
|
-
else if (topic.includes(term))
|
|
718
|
-
termScore = 400;
|
|
719
|
-
else if (project.includes(term))
|
|
720
|
-
termScore = 300;
|
|
721
|
-
else if (account.includes(term))
|
|
722
|
-
termScore = 250;
|
|
723
|
-
else if (cwd.includes(term))
|
|
724
|
-
termScore = 200;
|
|
725
|
-
else if (version.includes(term) || agent.includes(term))
|
|
726
|
-
termScore = 150;
|
|
727
|
-
else
|
|
728
|
-
return 0;
|
|
729
|
-
score += termScore;
|
|
730
|
-
}
|
|
731
|
-
return score;
|
|
732
|
-
}
|
|
733
|
-
/**
|
|
734
|
-
* Narrow a session list by --project and --agent before search resolution.
|
|
735
|
-
* Without this, a query like "scoped search" could match sessions in BOTH
|
|
736
|
-
* the project you specified AND elsewhere, producing an ambiguity error
|
|
737
|
-
* even though the user already pointed at the correct scope.
|
|
738
|
-
*/
|
|
739
|
-
function applyScopeFilters(sessions, scope) {
|
|
740
|
-
let filtered = sessions;
|
|
741
|
-
if (scope.project) {
|
|
742
|
-
const projectQuery = scope.project.toLowerCase();
|
|
743
|
-
filtered = filtered.filter((s) => {
|
|
744
|
-
const project = (s.project || '').toLowerCase();
|
|
745
|
-
const cwd = (s.cwd || '').toLowerCase();
|
|
746
|
-
return project.includes(projectQuery) || cwd.includes(projectQuery);
|
|
747
|
-
});
|
|
748
|
-
}
|
|
749
|
-
if (scope.agent) {
|
|
750
|
-
// Accept "claude" or "claude@2.1.112". Version suffix narrows further.
|
|
751
|
-
const [wantAgent, wantVersion] = scope.agent.split('@');
|
|
752
|
-
filtered = filtered.filter((s) => {
|
|
753
|
-
if (s.agent !== wantAgent)
|
|
754
|
-
return false;
|
|
755
|
-
if (wantVersion && s.version !== wantVersion)
|
|
756
|
-
return false;
|
|
757
|
-
return true;
|
|
758
|
-
});
|
|
759
|
-
}
|
|
760
|
-
return filtered;
|
|
761
|
-
}
|
|
762
|
-
async function renderArtifactsGlobal(query, listAll, name, scope) {
|
|
763
|
-
const spinner = ora().start();
|
|
764
|
-
const tracker = createScanProgressTracker(FIND_VERBS, 'session', spinner);
|
|
765
|
-
try {
|
|
766
|
-
const discovered = await discoverSessions({
|
|
767
|
-
all: true,
|
|
768
|
-
cwd: process.cwd(),
|
|
769
|
-
limit: 5000,
|
|
770
|
-
onProgress: tracker.onProgress,
|
|
771
|
-
});
|
|
772
|
-
tracker.stop();
|
|
773
|
-
const allSessions = applyScopeFilters(discovered, scope);
|
|
774
|
-
const matches = resolveSessionById(allSessions, query);
|
|
775
|
-
const queryMatches = matches.length > 0 ? matches : filterSessionsByQuery(allSessions, query);
|
|
776
|
-
if (queryMatches.length === 0) {
|
|
777
|
-
spinner.stop();
|
|
778
|
-
console.error(chalk.red(`No session found matching: ${query}`));
|
|
779
|
-
process.exit(1);
|
|
780
|
-
}
|
|
781
|
-
if (queryMatches.length > 1) {
|
|
782
|
-
spinner.stop();
|
|
783
|
-
console.error(chalk.red(`Multiple sessions match "${query}":`));
|
|
784
|
-
for (const m of queryMatches.slice(0, 10)) {
|
|
785
|
-
console.error(chalk.cyan(` ${m.shortId} ${m.id} ${m.label ?? m.topic ?? ''}`));
|
|
786
|
-
}
|
|
787
|
-
console.error(chalk.gray('Pass a longer ID to narrow it down.'));
|
|
788
|
-
process.exit(1);
|
|
789
|
-
}
|
|
790
|
-
spinner.stop();
|
|
791
|
-
await renderArtifactsForSession(queryMatches[0], listAll, name);
|
|
792
|
-
}
|
|
793
|
-
catch (err) {
|
|
794
|
-
if (isPromptCancelled(err))
|
|
795
|
-
return;
|
|
796
|
-
tracker.stop();
|
|
797
|
-
spinner.stop();
|
|
798
|
-
console.error(chalk.red(`Failed to read session: ${err.message}`));
|
|
799
|
-
process.exit(1);
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
async function renderOneSession(query, mode, scope) {
|
|
803
|
-
const spinner = ora().start();
|
|
804
|
-
const tracker = createScanProgressTracker(FIND_VERBS, 'session', spinner);
|
|
805
|
-
try {
|
|
806
|
-
const discovered = await discoverSessions({
|
|
807
|
-
all: true,
|
|
808
|
-
cwd: process.cwd(),
|
|
809
|
-
limit: 5000,
|
|
810
|
-
onProgress: tracker.onProgress,
|
|
811
|
-
});
|
|
812
|
-
tracker.stop();
|
|
813
|
-
const allSessions = applyScopeFilters(discovered, scope);
|
|
814
|
-
let session;
|
|
815
|
-
const matches = resolveSessionById(allSessions, query);
|
|
816
|
-
let queryMatches = matches.length > 0 ? matches : filterSessionsByQuery(allSessions, query);
|
|
817
|
-
if (queryMatches.length === 0) {
|
|
818
|
-
const contentResults = searchContentIndex(allSessions, query);
|
|
819
|
-
if (contentResults.size > 0) {
|
|
820
|
-
const matchedSessions = Array.from(contentResults.values())
|
|
821
|
-
.sort((a, b) => (b._bm25Score ?? 0) - (a._bm25Score ?? 0));
|
|
822
|
-
if (matchedSessions.length === 1) {
|
|
823
|
-
session = matchedSessions[0];
|
|
824
|
-
}
|
|
825
|
-
else {
|
|
826
|
-
queryMatches = matchedSessions;
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
if (queryMatches.length === 0 && !session) {
|
|
831
|
-
spinner.stop();
|
|
832
|
-
const historyEntry = findClaudeHistoryEntry(query);
|
|
833
|
-
if (historyEntry) {
|
|
834
|
-
const resumeMatch = resolveClaudeHistoryEntryToTranscript(historyEntry, allSessions);
|
|
835
|
-
if (resumeMatch) {
|
|
836
|
-
session = resumeMatch.session;
|
|
837
|
-
}
|
|
838
|
-
else {
|
|
839
|
-
renderClaudeHistoryOnlyId(query, historyEntry, allSessions);
|
|
840
|
-
process.exit(1);
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
else {
|
|
844
|
-
console.error(chalk.red(`No session found matching: ${query}`));
|
|
845
|
-
console.error(chalk.gray('Run "agents sessions" to browse sessions.'));
|
|
846
|
-
process.exit(1);
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
if (!session) {
|
|
850
|
-
if (queryMatches.length > 1) {
|
|
851
|
-
spinner.stop();
|
|
852
|
-
console.error(chalk.red(`Multiple sessions match "${query}":`));
|
|
853
|
-
for (const match of queryMatches.slice(0, 10)) {
|
|
854
|
-
console.error(chalk.cyan(` ${match.shortId} ${match.id} ${match.label ?? match.topic ?? ''}`));
|
|
855
|
-
}
|
|
856
|
-
console.error(chalk.gray('Pass a longer ID to narrow it down.'));
|
|
857
|
-
process.exit(1);
|
|
858
|
-
}
|
|
859
|
-
else {
|
|
860
|
-
session = queryMatches[0];
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
if (!session) {
|
|
864
|
-
throw new Error('Session resolution failed');
|
|
865
|
-
}
|
|
866
|
-
spinner.stop();
|
|
867
|
-
await renderSession(session, mode, scope.filter);
|
|
868
|
-
}
|
|
869
|
-
catch (err) {
|
|
870
|
-
if (isPromptCancelled(err))
|
|
871
|
-
return;
|
|
872
|
-
tracker.stop();
|
|
873
|
-
spinner.stop();
|
|
874
|
-
console.error(chalk.red(`Failed to read session: ${err.message}`));
|
|
875
|
-
process.exit(1);
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
/** Register the `agents sessions` command with all its options and help text. */
|
|
879
|
-
export function registerSessionsCommands(program) {
|
|
880
|
-
const sessionsCmd = program
|
|
881
|
-
.command('sessions')
|
|
882
|
-
.argument('[query]', 'Session ID, search query, or path (., ../, /path) to filter by project')
|
|
883
|
-
.description('Find, browse, and read agent conversation transcripts across Claude, Codex, Gemini, and OpenCode.')
|
|
884
|
-
.option('-a, --agent <agent>', 'Filter by agent type and version (e.g., claude, codex@0.116.0)')
|
|
885
|
-
.option('--all', 'Include sessions from every directory (not just current project)')
|
|
886
|
-
.option('--teams', 'Include team-spawned sessions (hidden by default)')
|
|
887
|
-
.option('--project <name>', 'Filter by project name (searches across all directories)')
|
|
888
|
-
.option('--since <time>', 'Only sessions newer than this (e.g., 2h, 7d, 4w, or ISO date)')
|
|
889
|
-
.option('--until <time>', 'Only sessions older than this (ISO timestamp)')
|
|
890
|
-
.option('-n, --limit <n>', 'Maximum number of sessions to return', '50')
|
|
891
|
-
.option('--markdown', 'Render the session as markdown (user, assistant, thinking, tool calls)')
|
|
892
|
-
.option('--json', 'Output JSON (session list when browsing, event array when rendering one session)')
|
|
893
|
-
.option('--include <roles>', 'Only include these roles (comma-separated): user, assistant, thinking, tools')
|
|
894
|
-
.option('--exclude <roles>', 'Exclude these roles (comma-separated): user, assistant, thinking, tools')
|
|
895
|
-
.option('--first <n>', 'Keep only the first N turns (a turn starts at each user message)')
|
|
896
|
-
.option('--last <n>', 'Keep only the last N turns (a turn starts at each user message)')
|
|
897
|
-
.option('--artifacts', 'List all files written or edited during a session')
|
|
898
|
-
.option('--artifact <name>', 'Read a specific artifact by filename or path (outputs to stdout)')
|
|
899
|
-
.option('--active', 'Show only sessions running right now across terminals, teams, cloud, and headless agents')
|
|
900
|
-
.addHelpText('after', `
|
|
901
|
-
Examples:
|
|
902
|
-
# Interactive picker: browse and search recent sessions (TTY only)
|
|
903
|
-
agents sessions
|
|
904
|
-
|
|
905
|
-
# List sessions from current project (last 30 days, piped output shows table)
|
|
906
|
-
agents sessions | head -20
|
|
907
|
-
|
|
908
|
-
# Search sessions by text (topic, file paths, commands)
|
|
909
|
-
agents sessions "add auth middleware"
|
|
910
|
-
|
|
911
|
-
# Filter by project across all directories
|
|
912
|
-
agents sessions --project agents-cli --all
|
|
913
|
-
|
|
914
|
-
# Filter by agent and time window
|
|
915
|
-
agents sessions --agent claude --since 7d
|
|
916
|
-
|
|
917
|
-
# Filter sessions in a specific directory
|
|
918
|
-
agents sessions /Users/muqsit/src/my-project
|
|
919
|
-
|
|
920
|
-
# Default summary view for one session
|
|
921
|
-
agents sessions a1b2c3d4
|
|
922
|
-
|
|
923
|
-
# Full conversation (user + assistant + thinking + tools) as markdown
|
|
924
|
-
agents sessions a1b2c3d4 --markdown
|
|
925
|
-
|
|
926
|
-
# Same conversation as structured JSON events
|
|
927
|
-
agents sessions a1b2c3d4 --json
|
|
928
|
-
|
|
929
|
-
# Only user messages (filter flags auto-select markdown)
|
|
930
|
-
agents sessions a1b2c3d4 --include user
|
|
931
|
-
|
|
932
|
-
# Everything except thinking, as markdown
|
|
933
|
-
agents sessions a1b2c3d4 --exclude thinking --markdown
|
|
934
|
-
|
|
935
|
-
# Last 3 turns as markdown
|
|
936
|
-
agents sessions a1b2c3d4 --last 3
|
|
937
|
-
|
|
938
|
-
# First 10 turns, user messages only, as JSON
|
|
939
|
-
agents sessions a1b2c3d4 --first 10 --include user --json
|
|
940
|
-
|
|
941
|
-
# Export all recent sessions as JSON for analysis
|
|
942
|
-
agents sessions --since 30d --limit 200 --json > sessions.json
|
|
943
|
-
|
|
944
|
-
# Include team-spawned sessions in results
|
|
945
|
-
agents sessions --teams
|
|
946
|
-
|
|
947
|
-
# Show only live sessions across terminals, teams, cloud, and headless agents
|
|
948
|
-
agents sessions --active
|
|
949
|
-
agents sessions --active --json
|
|
950
|
-
|
|
951
|
-
Notes:
|
|
952
|
-
- --include and --exclude are mutually exclusive.
|
|
953
|
-
- --first and --last are mutually exclusive.
|
|
954
|
-
- A filter flag without --markdown/--json defaults to --markdown output.
|
|
955
|
-
`)
|
|
956
|
-
.action(async (query, options) => {
|
|
957
|
-
await sessionsAction(query, options);
|
|
958
|
-
});
|
|
959
|
-
registerSessionsTailCommand(sessionsCmd);
|
|
960
|
-
}
|
|
961
|
-
function formatNoSessionsMessage(showAll, project) {
|
|
962
|
-
const projectQuery = project?.trim();
|
|
963
|
-
if (projectQuery) {
|
|
964
|
-
return `No sessions found for project "${projectQuery}".`;
|
|
965
|
-
}
|
|
966
|
-
if (showAll)
|
|
967
|
-
return 'No sessions found.';
|
|
968
|
-
const command = 'agents sessions --all';
|
|
969
|
-
return `No sessions found for ${process.cwd()}. Run "${command}" to see sessions from every directory.`;
|
|
970
|
-
}
|
|
971
|
-
function formatTeamHiddenFooter(hiddenCount) {
|
|
972
|
-
const noun = hiddenCount === 1 ? 'team session' : 'team sessions';
|
|
973
|
-
return `(${hiddenCount} ${noun} hidden — use --teams to show, or \`agents teams status\`)`;
|
|
974
|
-
}
|
|
975
|
-
function findClaudeHistoryEntry(idQuery) {
|
|
976
|
-
const historyPath = path.join(os.homedir(), '.claude', 'history.jsonl');
|
|
977
|
-
if (!fs.existsSync(historyPath))
|
|
978
|
-
return null;
|
|
979
|
-
try {
|
|
980
|
-
const lines = fs.readFileSync(historyPath, 'utf-8').split('\n');
|
|
981
|
-
for (let i = lines.length - 1; i >= 0; i--) {
|
|
982
|
-
const line = lines[i].trim();
|
|
983
|
-
if (!line)
|
|
984
|
-
continue;
|
|
985
|
-
let parsed;
|
|
986
|
-
try {
|
|
987
|
-
parsed = JSON.parse(line);
|
|
988
|
-
}
|
|
989
|
-
catch {
|
|
990
|
-
continue;
|
|
991
|
-
}
|
|
992
|
-
if (parsed.sessionId !== idQuery)
|
|
993
|
-
continue;
|
|
994
|
-
const timestampMs = typeof parsed.timestamp === 'number'
|
|
995
|
-
? parsed.timestamp
|
|
996
|
-
: typeof parsed.timestamp === 'string'
|
|
997
|
-
? Date.parse(parsed.timestamp)
|
|
998
|
-
: undefined;
|
|
999
|
-
return {
|
|
1000
|
-
sessionId: parsed.sessionId,
|
|
1001
|
-
display: typeof parsed.display === 'string' ? parsed.display : undefined,
|
|
1002
|
-
project: typeof parsed.project === 'string' ? parsed.project : undefined,
|
|
1003
|
-
timestampMs: Number.isFinite(timestampMs) ? timestampMs : undefined,
|
|
1004
|
-
historyPath,
|
|
1005
|
-
};
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
catch {
|
|
1009
|
-
return null;
|
|
1010
|
-
}
|
|
1011
|
-
return null;
|
|
1012
|
-
}
|
|
1013
|
-
function renderClaudeHistoryOnlyId(idQuery, historyEntry, allSessions) {
|
|
1014
|
-
console.error(chalk.red(`No transcript session found matching: ${idQuery}`));
|
|
1015
|
-
console.error(chalk.yellow('This ID exists in Claude history, but not as a saved transcript session.'));
|
|
1016
|
-
console.error(chalk.gray(`History file: ${historyEntry.historyPath}`));
|
|
1017
|
-
if (historyEntry.display) {
|
|
1018
|
-
console.error(chalk.gray(`History entry: ${historyEntry.display}`));
|
|
1019
|
-
}
|
|
1020
|
-
if (historyEntry.project) {
|
|
1021
|
-
console.error(chalk.gray(`Project root: ${historyEntry.project}`));
|
|
1022
|
-
}
|
|
1023
|
-
if (historyEntry.timestampMs) {
|
|
1024
|
-
console.error(chalk.gray(`History time: ${new Date(historyEntry.timestampMs).toISOString()}`));
|
|
1025
|
-
}
|
|
1026
|
-
const relatedSessions = findClaudeSessionsInProject(allSessions, historyEntry);
|
|
1027
|
-
if (relatedSessions.length > 0) {
|
|
1028
|
-
console.error(chalk.gray('Claude transcript sessions in the same project tree:'));
|
|
1029
|
-
for (const session of relatedSessions) {
|
|
1030
|
-
console.error(chalk.gray(` ${session.shortId} ${session.id} ${session.project || '-'} ${formatRelativeTime(session.timestamp)}`));
|
|
1031
|
-
}
|
|
1032
|
-
console.error(chalk.gray('Use one of the transcript IDs above with "agents sessions <id>".'));
|
|
1033
|
-
return;
|
|
1034
|
-
}
|
|
1035
|
-
if (historyEntry.display === '/resume') {
|
|
1036
|
-
console.error(chalk.gray('This looks like a Claude /resume history entry. In this case, the resumed conversation continued under a different transcript session ID.'));
|
|
1037
|
-
}
|
|
1038
|
-
const projectHint = historyEntry.project ? path.basename(historyEntry.project) : 'the project';
|
|
1039
|
-
console.error(chalk.gray(`Try "agents sessions --agent claude --project ${projectHint}" to find the resumed transcript session.`));
|
|
1040
|
-
}
|
|
1041
|
-
function findClaudeSessionsInProject(sessions, historyEntry) {
|
|
1042
|
-
return findClaudeProjectSessions(sessions, historyEntry)
|
|
1043
|
-
.sort((a, b) => sessionDistance(a, historyEntry) - sessionDistance(b, historyEntry))
|
|
1044
|
-
.slice(0, 3);
|
|
1045
|
-
}
|
|
1046
|
-
function findClaudeProjectSessions(sessions, historyEntry) {
|
|
1047
|
-
if (!historyEntry.project)
|
|
1048
|
-
return [];
|
|
1049
|
-
// Resolve symlinks (e.g. macOS /var -> /private/var) so we match sessions
|
|
1050
|
-
// whose cwd was canonicalized at scan time.
|
|
1051
|
-
let projectRoot = historyEntry.project;
|
|
1052
|
-
try {
|
|
1053
|
-
projectRoot = fs.realpathSync(projectRoot);
|
|
1054
|
-
}
|
|
1055
|
-
catch { /* dir gone */ }
|
|
1056
|
-
return sessions.filter(session => session.agent === 'claude' &&
|
|
1057
|
-
typeof session.cwd === 'string' &&
|
|
1058
|
-
isWithinProject(session.cwd, projectRoot));
|
|
1059
|
-
}
|
|
1060
|
-
function resolveClaudeHistoryEntryToTranscript(historyEntry, sessions) {
|
|
1061
|
-
if (historyEntry.display !== '/resume')
|
|
1062
|
-
return null;
|
|
1063
|
-
const candidates = findClaudeProjectSessions(sessions, historyEntry);
|
|
1064
|
-
const matches = [];
|
|
1065
|
-
for (const session of candidates) {
|
|
1066
|
-
const resumeTimestampMs = findClaudeResumeTimestamp(session.filePath, historyEntry.timestampMs);
|
|
1067
|
-
if (resumeTimestampMs === null)
|
|
1068
|
-
continue;
|
|
1069
|
-
const deltaMs = historyEntry.timestampMs === undefined
|
|
1070
|
-
? 0
|
|
1071
|
-
: Math.abs(resumeTimestampMs - historyEntry.timestampMs);
|
|
1072
|
-
if (historyEntry.timestampMs !== undefined && deltaMs > CLAUDE_RESUME_MATCH_WINDOW_MS) {
|
|
1073
|
-
continue;
|
|
1074
|
-
}
|
|
1075
|
-
matches.push({ session, resumeTimestampMs, deltaMs });
|
|
1076
|
-
}
|
|
1077
|
-
if (matches.length === 0)
|
|
1078
|
-
return null;
|
|
1079
|
-
matches.sort((a, b) => {
|
|
1080
|
-
if (a.deltaMs !== b.deltaMs)
|
|
1081
|
-
return a.deltaMs - b.deltaMs;
|
|
1082
|
-
return b.resumeTimestampMs - a.resumeTimestampMs;
|
|
1083
|
-
});
|
|
1084
|
-
const [best, second] = matches;
|
|
1085
|
-
if (second && best.deltaMs === second.deltaMs && best.resumeTimestampMs === second.resumeTimestampMs) {
|
|
1086
|
-
return null;
|
|
1087
|
-
}
|
|
1088
|
-
return best;
|
|
1089
|
-
}
|
|
1090
|
-
function findClaudeResumeTimestamp(filePath, targetTimestampMs) {
|
|
1091
|
-
try {
|
|
1092
|
-
const lines = fs.readFileSync(filePath, 'utf-8').split('\n');
|
|
1093
|
-
let bestTimestampMs = null;
|
|
1094
|
-
for (const line of lines) {
|
|
1095
|
-
if (!line.includes('SessionStart:resume'))
|
|
1096
|
-
continue;
|
|
1097
|
-
let parsed;
|
|
1098
|
-
try {
|
|
1099
|
-
parsed = JSON.parse(line);
|
|
1100
|
-
}
|
|
1101
|
-
catch {
|
|
1102
|
-
continue;
|
|
1103
|
-
}
|
|
1104
|
-
if (parsed.attachment?.hookName !== 'SessionStart:resume')
|
|
1105
|
-
continue;
|
|
1106
|
-
const timestampMs = Date.parse(parsed.timestamp || '');
|
|
1107
|
-
if (Number.isNaN(timestampMs))
|
|
1108
|
-
continue;
|
|
1109
|
-
if (targetTimestampMs === undefined) {
|
|
1110
|
-
return timestampMs;
|
|
1111
|
-
}
|
|
1112
|
-
if (bestTimestampMs === null || Math.abs(timestampMs - targetTimestampMs) < Math.abs(bestTimestampMs - targetTimestampMs)) {
|
|
1113
|
-
bestTimestampMs = timestampMs;
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
return bestTimestampMs;
|
|
1117
|
-
}
|
|
1118
|
-
catch {
|
|
1119
|
-
return null;
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
function isWithinProject(sessionCwd, projectRoot) {
|
|
1123
|
-
return sessionCwd === projectRoot || sessionCwd.startsWith(projectRoot + path.sep);
|
|
1124
|
-
}
|
|
1125
|
-
function sessionDistance(session, historyEntry) {
|
|
1126
|
-
if (!historyEntry.timestampMs)
|
|
1127
|
-
return Number.MAX_SAFE_INTEGER;
|
|
1128
|
-
const sessionTime = new Date(session.timestamp).getTime();
|
|
1129
|
-
if (Number.isNaN(sessionTime))
|
|
1130
|
-
return Number.MAX_SAFE_INTEGER;
|
|
1131
|
-
return Math.abs(sessionTime - historyEntry.timestampMs);
|
|
1132
|
-
}
|
|
1133
|
-
// ---------------------------------------------------------------------------
|
|
1134
|
-
// Formatting helpers
|
|
1135
|
-
// ---------------------------------------------------------------------------
|
|
1136
|
-
function formatAbsoluteTime(isoTimestamp) {
|
|
1137
|
-
const d = new Date(isoTimestamp);
|
|
1138
|
-
if (isNaN(d.getTime()))
|
|
1139
|
-
return isoTimestamp;
|
|
1140
|
-
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
1141
|
-
const hh = String(d.getHours()).padStart(2, '0');
|
|
1142
|
-
const mm = String(d.getMinutes()).padStart(2, '0');
|
|
1143
|
-
return `${months[d.getMonth()]} ${d.getDate()} ${hh}:${mm}`;
|
|
1144
|
-
}
|
|
1145
|
-
function padRight(s, width) {
|
|
1146
|
-
return s.length >= width ? s + ' ' : s + ' '.repeat(width - s.length);
|
|
1147
|
-
}
|
|
1148
|
-
function truncate(s, max) {
|
|
1149
|
-
return s.length > max ? s.slice(0, max - 1) + '.' : s;
|
|
1150
|
-
}
|
|
1151
|
-
function formatRelativeTime(isoTimestamp) {
|
|
1152
|
-
const now = Date.now();
|
|
1153
|
-
const then = new Date(isoTimestamp).getTime();
|
|
1154
|
-
if (isNaN(then))
|
|
1155
|
-
return isoTimestamp;
|
|
1156
|
-
const diffMs = now - then;
|
|
1157
|
-
const diffMin = Math.floor(diffMs / 60_000);
|
|
1158
|
-
const diffHrs = Math.floor(diffMs / 3_600_000);
|
|
1159
|
-
const diffDays = Math.floor(diffMs / 86_400_000);
|
|
1160
|
-
if (diffMin < 1)
|
|
1161
|
-
return 'just now';
|
|
1162
|
-
if (diffMin < 60)
|
|
1163
|
-
return `${diffMin} min ago`;
|
|
1164
|
-
if (diffHrs < 24)
|
|
1165
|
-
return `${diffHrs} hour${diffHrs === 1 ? '' : 's'} ago`;
|
|
1166
|
-
if (diffDays < 7)
|
|
1167
|
-
return `${diffDays} day${diffDays === 1 ? '' : 's'} ago`;
|
|
1168
|
-
// Older: show date
|
|
1169
|
-
const d = new Date(then);
|
|
1170
|
-
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
|
|
1171
|
-
return `${months[d.getMonth()]} ${d.getDate()}`;
|
|
1172
|
-
}
|
|
1173
|
-
//# sourceMappingURL=sessions.js.map
|