@xopcai/xopc 0.0.125 → 0.0.126
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 +56 -102
- package/README.zh-CN.md +51 -98
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/schema/config-schema.d.ts +6 -6
- package/dist/extensions/feishu/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/src/adapters/streaming-adapter.js +1 -1
- package/dist/extensions/telegram/src/config-schema.d.ts +8 -8
- package/dist/extensions/telegram/src/inbound-processor.js +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/api/api.js +1 -1
- package/dist/extensions/weixin/src/config-schema.d.ts +3 -3
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BKDKICZV.js → agent-avatar-dicebear-C70vgt60.js} +1 -1
- package/dist/gateway/static/root/assets/agents-DRYVahI-.js +2 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-DI4BqHKW.js → app-management-settings-panel-D9-HW6cy.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-6_ie3NQ4.js → appearance-settings-BHlahIDL.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BdJ1eQg3.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-kUHEJ1HK.js → archive-plugin-B-aoIt0w.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-Dm-9prpU.js → attachment-load-BD0G0FD5.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-OTxQTPnC.js → automation-suggestion-card-iJRVI7aZ.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-D8hYQbkl.js +4 -0
- package/dist/gateway/static/root/assets/{binary-plugins-DllA_jQ0.js → binary-plugins-B0mNlVSz.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-Cm6CWNj1.js → block-editor-CJY9Lu5G.js} +6 -6
- package/dist/gateway/static/root/assets/browser-settings-page-CiWEO-Iy.js +8 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-VJ89b6I2.js → capability-presets-api-Bgc8ag55.js} +1 -1
- package/dist/gateway/static/root/assets/{capability-presets-settings-panel-BaPj8wC2.js → capability-presets-settings-panel-B1nIi0TC.js} +1 -1
- package/dist/gateway/static/root/assets/{channel-recipient-api-B5PwBEUx.js → channel-recipient-api-0sauApoC.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-BddPdqVo.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-Ba2GDhSE.js +2 -0
- package/dist/gateway/static/root/assets/{directory-picker-path-field-DySMzOF6.js → directory-picker-path-field-CiEc4KmY.js} +1 -1
- package/dist/gateway/static/root/assets/{dreaming-settings-D_AjSnV_.js → dreaming-settings-4bvpk5wr.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-debug-page-BaM0FpW7.js → extension-debug-page-BbyczVZ3.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DuZWVOGA.js → extension-page-DLN1I3DR.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DarVtbmJ.js → extension-settings-page-D9VGHmYJ.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-NFKfkqrd.js → fetch-5V96dUz3.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-CFEm9rgy.js → gateway-config-api-BtIzObwp.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-BMk2S5td.js → gateway-settings-KFsGGDhg.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-Dtwh_yGg.js → gateway-startup-retry-DEMad2wt.js} +1 -1
- package/dist/gateway/static/root/assets/{goal-create-dialog-BKP7ylcG.js → goal-create-dialog-4PcF6Sh6.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-B482PSaG.js +1 -0
- package/dist/gateway/static/root/assets/{goals-config-api-DTWZNA_Y.js → goals-config-api-CVN7-pdM.js} +1 -1
- package/dist/gateway/static/root/assets/{goals-page-CTmA3hWK.js → goals-page-CUdgJuDn.js} +2 -2
- package/dist/gateway/static/root/assets/{goals-settings-Bhct0ZT-.js → goals-settings-IYCH3-Pi.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-C-UxSU4a.js → heartbeat-settings-Cf_a2Bmz.js} +1 -1
- package/dist/gateway/static/root/assets/index-CA2tR2vm.js +256 -0
- package/dist/gateway/static/root/assets/index-Ds3u0LOk.css +1 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-DCjy2y4d.js → keyboard-shortcuts-settings-lKTg6St7.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-BCporcNH.js +2 -0
- package/dist/gateway/static/root/assets/{markdown-split-BaqxP-GQ.js → markdown-split-Bv4k6iGJ.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-DQ_EXloK.js → media-plugins-Bbi8g3N8.js} +1 -1
- package/dist/gateway/static/root/assets/messages-C22hxE1N.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-D68Pyow7.js +2 -0
- package/dist/gateway/static/root/assets/notes-page-CuUMOiyv.js +1 -0
- package/dist/gateway/static/root/assets/notes-workbench-Dx2N5zTk.js +2 -0
- package/dist/gateway/static/root/assets/{page-tabs-EIZhLppK.js → page-tabs-Cp395RYD.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-r_uB4Epr.js → preview-open-alternatives-DqV5OM4m.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-sB8AzZi3.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-LBnJqWK2.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-Dbj0o6SC.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-B132Uf-2.js → save-bar-controls-BItmzAzI.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-B5qshALm.js → schedule-field-BQ8IjjCn.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-CvLmkdS9.js → schema-form-BRpD6x3d.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-DhDZKspB.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-BvXLMNL6.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-pRlvqsAf.js → settings-collapsible-section-BKSPQM4R.js} +1 -1
- package/dist/gateway/static/root/assets/settings-form-section-BmyfthNQ.js +1 -0
- package/dist/gateway/static/root/assets/settings-page-Cfm9UxAr.js +1 -0
- package/dist/gateway/static/root/assets/settings-page-layout-Bls5tfbH.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-kQEsTGAs.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-v6-IOp8t.js → share-preview-page-DbYZNAPb.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-BtR4B0kn.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-CJNVOWoK.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-DcWDHrt3.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-HUU2FFjM.js → system-settings-panel-DKDAojWM.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-AH160QHh.js → typed-models-lib-BCCV4Kkp.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-BXzDmjCQ.js → use-channel-catalog-NBqg3iFY.js} +1 -1
- package/dist/gateway/static/root/assets/{user-profile-settings-panel-DxwnQvQ3.js → user-profile-settings-panel-suQ2x-LB.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-i5POEtqd.js → utils-DPGVr3tS.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-DaJASKFP.js +1 -0
- package/dist/gateway/static/root/assets/{work-item-detail-page-CD6FL_Rs.js → work-item-detail-page-BrCZpAWh.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-ClVVMgN-.js → workflow-run-setup-panel-BTkRVNAh.js} +2 -2
- package/dist/gateway/static/root/assets/{workflow-start-dialog-Dv4ZA1T0.js → workflow-start-dialog-DAImVtdO.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-vyJ8wSXm.js +18 -0
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/package.js +1 -1
- package/dist/src/activity/context.d.ts +11 -0
- package/dist/src/activity/context.js +36 -0
- package/dist/src/activity/context.js.map +1 -0
- package/dist/src/activity/emitter.d.ts +6 -0
- package/dist/src/activity/emitter.js +43 -0
- package/dist/src/activity/emitter.js.map +1 -0
- package/dist/src/activity/index.d.ts +3 -0
- package/dist/src/activity/index.js +3 -0
- package/dist/src/activity/service.d.ts +12 -0
- package/dist/src/activity/service.js +59 -0
- package/dist/src/activity/service.js.map +1 -0
- package/dist/src/activity/types.d.ts +109 -0
- package/dist/src/activity/types.js +1 -0
- package/dist/src/agent/agent-manager.d.ts +7 -0
- package/dist/src/agent/agent-manager.js +7 -4
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/context/project-context.js +2 -2
- package/dist/src/agent/context/workspace-seed.js +2 -2
- package/dist/src/agent/embedded/run-for-session.js +1 -1
- package/dist/src/agent/goals/post-turn.js +2 -2
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +1 -1
- package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js +1 -1
- package/dist/src/agent/service.js +6 -3
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/service.types.d.ts +7 -0
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +1 -1
- package/dist/src/agent/tool-manuals/index.js +15 -6
- package/dist/src/agent/tool-manuals/index.js.map +1 -1
- package/dist/src/agent/tool-manuals/xopc-use.d.ts +1 -0
- package/dist/src/agent/tool-manuals/xopc-use.js +204 -0
- package/dist/src/agent/tool-manuals/xopc-use.js.map +1 -0
- package/dist/src/agent/tools/factory.d.ts +7 -0
- package/dist/src/agent/tools/factory.js +9 -0
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/goal-tool.js +2 -2
- package/dist/src/agent/tools/index.d.ts +1 -0
- package/dist/src/agent/tools/index.js +2 -1
- package/dist/src/agent/tools/workflow-tool.js +1 -1
- package/dist/src/agent/tools/xopc-use-tool.d.ts +34 -0
- package/dist/src/agent/tools/xopc-use-tool.js +636 -0
- package/dist/src/agent/tools/xopc-use-tool.js.map +1 -0
- package/dist/src/agent-manifest/schema.d.ts +27 -27
- package/dist/src/automations/api/routes.js +1 -1
- package/dist/src/automations/domain/validation.d.ts +55 -55
- package/dist/src/automations/draft/automation-draft-validator.d.ts +25 -25
- package/dist/src/automations/service/action-executor.js +2 -2
- package/dist/src/browser/cdp-local-launcher.js +1 -1
- package/dist/src/browser/providers/browser-ext-install.js +3 -3
- package/dist/src/browser/providers/cloakbrowser.js +2 -2
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/chat-commands/agent-edit.js +1 -1
- package/dist/src/chat-commands/builtins/config.js +1 -1
- package/dist/src/chat-commands/builtins/goal.js +2 -2
- package/dist/src/chat-commands/context.js +1 -1
- package/dist/src/cli/commands/agent.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +2 -2
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/extension-pack.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/cli/commands/goal.js +3 -3
- package/dist/src/cli/commands/init.js +1 -1
- package/dist/src/cli/commands/project.js +4 -4
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.js +1 -1
- package/dist/src/config/loader.js +1 -1
- package/dist/src/config/models-json.d.ts +14 -14
- package/dist/src/config/models-json.js +1 -1
- package/dist/src/config/schema.d.ts +60 -60
- package/dist/src/daemon/launchd.js +1 -1
- package/dist/src/daemon/systemd.js +1 -1
- package/dist/src/extensions/discover-extensions.js +1 -1
- package/dist/src/extensions/loader.js +2 -2
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +14 -14
- package/dist/src/gateway/hono/lib/static-ui.js +1 -1
- package/dist/src/gateway/hono/middleware/log-context.js +8 -1
- package/dist/src/gateway/hono/middleware/log-context.js.map +1 -1
- package/dist/src/gateway/hono/routes/activity.d.ts +14 -0
- package/dist/src/gateway/hono/routes/activity.js +72 -0
- package/dist/src/gateway/hono/routes/activity.js.map +1 -0
- package/dist/src/gateway/hono/routes/goals.js +1 -1
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/index.js.map +1 -1
- package/dist/src/gateway/hono/routes/memory.js +2 -2
- package/dist/src/gateway/hono/routes/projects.js +65 -15
- package/dist/src/gateway/hono/routes/projects.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +101 -2
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/workflows.js +2 -2
- package/dist/src/gateway/lock.js +1 -1
- package/dist/src/gateway/ports.js +1 -1
- package/dist/src/gateway/service/sessions-api.d.ts +10 -0
- package/dist/src/gateway/service/sessions-api.js +31 -0
- package/dist/src/gateway/service/sessions-api.js.map +1 -1
- package/dist/src/gateway/service.js +12 -9
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/goals/goal-store.js +1 -1
- package/dist/src/goals/goal-store.js.map +1 -1
- package/dist/src/goals/goal-workflow-judge.js +1 -1
- package/dist/src/infra/ports.js +1 -1
- package/dist/src/infra/ssh-tunnel.js +1 -1
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/mcp/channel-bridge.js +1 -1
- package/dist/src/migrations/runner.js +1 -1
- package/dist/src/notes/service.js +65 -6
- package/dist/src/notes/service.js.map +1 -1
- package/dist/src/notes/store.js +1 -1
- package/dist/src/projects/project-service.d.ts +2 -1
- package/dist/src/projects/project-service.js +59 -2
- package/dist/src/projects/project-service.js.map +1 -1
- package/dist/src/projects/project-store.d.ts +2 -1
- package/dist/src/projects/project-store.js +43 -0
- package/dist/src/projects/project-store.js.map +1 -1
- package/dist/src/projects/types.d.ts +10 -0
- package/dist/src/projects/workspace.js +1 -1
- package/dist/src/routing/agent-session-key.js +1 -1
- package/dist/src/routing/resolve-route.js +1 -1
- package/dist/src/routing/resolve-tui-session-key.js +1 -1
- package/dist/src/session/client-history.d.ts +3 -0
- package/dist/src/session/client-history.js +24 -9
- package/dist/src/session/client-history.js.map +1 -1
- package/dist/src/session/init-session-turn.js +1 -1
- package/dist/src/session/resolve-session.js +1 -1
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/store.js +1 -1
- package/dist/src/session/types.d.ts +4 -0
- package/dist/src/session/types.js.map +1 -1
- package/dist/src/storage/sqlite/activity-repository.d.ts +8 -0
- package/dist/src/storage/sqlite/activity-repository.js +208 -0
- package/dist/src/storage/sqlite/activity-repository.js.map +1 -0
- package/dist/src/storage/sqlite/connection.js +1 -1
- package/dist/src/storage/sqlite/index.d.ts +1 -0
- package/dist/src/storage/sqlite/index.js +2 -1
- package/dist/src/storage/sqlite/migrations/024_activity_events.sql +62 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/row-mappers.js +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/storage/sqlite/schema.sql +63 -0
- package/dist/src/storage/sqlite/session-repository.js +11 -0
- package/dist/src/storage/sqlite/session-repository.js.map +1 -1
- package/dist/src/tui/backends/embedded-backend.d.ts +13 -0
- package/dist/src/tui/backends/embedded-backend.js +76 -7
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +13 -0
- package/dist/src/tui/backends/gateway-sse-backend.js +53 -0
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/chat-history.js +16 -3
- package/dist/src/tui/chat-history.js.map +1 -1
- package/dist/src/tui/clipboard-image.js +1 -1
- package/dist/src/tui/components/chat-log.d.ts +23 -3
- package/dist/src/tui/components/chat-log.js +68 -9
- package/dist/src/tui/components/chat-log.js.map +1 -1
- package/dist/src/tui/components/tui-bottom-bar.js +9 -5
- package/dist/src/tui/components/tui-bottom-bar.js.map +1 -1
- package/dist/src/tui/tui-backend.d.ts +16 -0
- package/dist/src/tui/tui-command-formatters.js +2 -2
- package/dist/src/tui/tui-commands.d.ts +9 -0
- package/dist/src/tui/tui-commands.js +95 -6
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-picker-overlay.d.ts +1 -0
- package/dist/src/tui/tui-picker-overlay.js +36 -1
- package/dist/src/tui/tui-picker-overlay.js.map +1 -1
- package/dist/src/tui/tui-picker-services.d.ts +13 -0
- package/dist/src/tui/tui-run-state.js +11 -0
- package/dist/src/tui/tui-run-state.js.map +1 -1
- package/dist/src/tui/tui-run-status-format.d.ts +3 -0
- package/dist/src/tui/tui-run-status-format.js +33 -0
- package/dist/src/tui/tui-run-status-format.js.map +1 -0
- package/dist/src/tui/tui-session-actions.d.ts +5 -0
- package/dist/src/tui/tui-session-actions.js +24 -0
- package/dist/src/tui/tui-session-actions.js.map +1 -1
- package/dist/src/tui/tui-timeline-picker.d.ts +19 -0
- package/dist/src/tui/tui-timeline-picker.js +81 -0
- package/dist/src/tui/tui-timeline-picker.js.map +1 -0
- package/dist/src/tui/tui-timeline.d.ts +15 -0
- package/dist/src/tui/tui-timeline.js +65 -0
- package/dist/src/tui/tui-timeline.js.map +1 -0
- package/dist/src/tui/tui-types.d.ts +1 -0
- package/dist/src/tui/tui-types.js +1 -0
- package/dist/src/tui/tui-types.js.map +1 -1
- package/dist/src/tui/tui.js +31 -25
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/utils/index.js +1 -1
- package/dist/src/utils/logger/index.js +1 -1
- package/dist/src/utils/logger/stats.d.ts +3 -3
- package/dist/src/utils/logger.js +1 -1
- package/dist/src/work-items/agent-context.d.ts +5 -1
- package/dist/src/work-items/agent-context.js +39 -3
- package/dist/src/work-items/agent-context.js.map +1 -1
- package/dist/src/work-items/work-item-service.d.ts +2 -0
- package/dist/src/work-items/work-item-service.js +97 -0
- package/dist/src/work-items/work-item-service.js.map +1 -1
- package/dist/src/workflows/draft/workflow-draft-service.js +1 -1
- package/dist/src/workflows/service/workflow-session-bridge.js +1 -1
- package/package.json +5 -5
- package/dist/gateway/static/root/assets/agents-BnTB7-c5.js +0 -2
- package/dist/gateway/static/root/assets/apps-page-B6bG65SW.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-1lVbo0dS.js +0 -1
- package/dist/gateway/static/root/assets/browser-settings-page-CzDBlOK0.js +0 -8
- package/dist/gateway/static/root/assets/channels-settings-Df4m7p1k.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-BMTphmHS.js +0 -2
- package/dist/gateway/static/root/assets/goal-detail-page-C2cTxf71.js +0 -1
- package/dist/gateway/static/root/assets/index-BNHDd2j1.css +0 -1
- package/dist/gateway/static/root/assets/index-BPXLPMuY.js +0 -193
- package/dist/gateway/static/root/assets/logs-page-CGc3_CQU.js +0 -2
- package/dist/gateway/static/root/assets/messages-CjuIJcZl.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-Drz4UQMb.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-CY1ylng1.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-X7IaD--t.js +0 -2
- package/dist/gateway/static/root/assets/project-detail-page-DE5adRBE.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-CuOb1k6F.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BOxNrUVA.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CY0IQcGW.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-D4NBNVCB.js +0 -1
- package/dist/gateway/static/root/assets/settings-form-section-BBYUDLVd.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-DaO7zYZM.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-layout-D8g9PAek.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Bks0CLLT.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-CEZsKm9r.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-oTkHbb9W.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-DigsbZ6K.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-CEJklEgb.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-OLQiUpoW.js +0 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat-log.js","names":[],"sources":["../../../../src/tui/components/chat-log.ts"],"sourcesContent":["import type { Component, KeybindingsManager } from '@earendil-works/pi-tui';\nimport { Container, Spacer, Text } from '@earendil-works/pi-tui';\nimport type { AgentMessage, AgentToolResult } from '@earendil-works/pi-agent-core';\n\nimport { BashExecutionComponent } from './bash-execution.js';\nimport { BashSummaryComponent, type BashSummary } from './bash-summary.js';\nimport { BranchMessageSummaryComponent, type BranchMessageSummary } from './branch-message-summary.js';\nimport { BranchSummaryComponent } from './branch-summary.js';\nimport { CompactionSummaryComponent } from './compaction-summary.js';\nimport { CustomMessageComponent, type CustomMessageSummary } from './custom-message.js';\nimport type { TuiMessageRenderer } from '../../extensions/types/tui.js';\nimport { theme } from '../theme.js';\nimport { AssistantMessageComponent } from './assistant-message.js';\nimport { ToolExecutionComponent, type ToolExecutionOptions } from './tool-execution.js';\nimport { UserMessageComponent } from './user-message.js';\nimport type { TuiBranchSummary, TuiCompactionResult } from '../tui-backend.js';\n\nconst MAX_COMPONENTS = 180;\n\ntype ExpandableBlock = { setExpanded(expanded: boolean): void };\n\nfunction assistantPlainText(message: AgentMessage): string {\n const content = (message as { content?: unknown }).content;\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return '';\n return content\n .map((block) => {\n if (!block || typeof block !== 'object') return '';\n const rec = block as { type?: unknown; text?: unknown };\n return rec.type === 'text' && typeof rec.text === 'string' ? rec.text : '';\n })\n .join('');\n}\n\nexport class ChatLog extends Container {\n private toolById = new Map<string, ToolExecutionComponent>();\n private bashBlocks: Array<Component & ExpandableBlock> = [];\n private compactionBlocks: CompactionSummaryComponent[] = [];\n private branchBlocks: BranchSummaryComponent[] = [];\n private branchMessageBlocks: BranchMessageSummaryComponent[] = [];\n private customBlocks: CustomMessageComponent[] = [];\n private customMessageRenderers = new Map<string, TuiMessageRenderer>();\n private assistantMessages: AssistantMessageComponent[] = [];\n private streamingRuns = new Map<string, AssistantMessageComponent>();\n /** After finalizeAssistant, late tool execution events can still arrive; keep the bubble to link tools. */\n private assistantAnchorByRunId = new Map<string, AssistantMessageComponent>();\n private runsWithTools = new Set<string>();\n private toolsExpanded = false;\n private showThinking = true;\n private hiddenThinkingLabel = 'Thinking...';\n private toolImageOptions: ToolExecutionOptions = {};\n private lastAssistantText = '';\n private lastStatusEntry: Container | null = null;\n private lastStatusText: Text | null = null;\n private workflowStatusByRunId = new Map<string, { entry: Container; text: Text }>();\n\n constructor(private readonly keybindings?: KeybindingsManager) {\n super();\n if (keybindings) {\n this.toolImageOptions.keybindings = keybindings;\n }\n }\n\n private pruneOverflow(): void {\n while (this.children.length > MAX_COMPONENTS) {\n const oldest = this.children[0];\n if (!oldest) return;\n this.removeChild(oldest);\n this.dropReferences(oldest);\n }\n }\n\n private dropReferences(component: Component): void {\n for (const [id, tool] of this.toolById.entries()) {\n if (tool === component) this.toolById.delete(id);\n }\n for (const [runId, msg] of this.streamingRuns.entries()) {\n if (msg === component) this.streamingRuns.delete(runId);\n }\n for (const [runId, msg] of this.assistantAnchorByRunId.entries()) {\n if (msg === component) this.assistantAnchorByRunId.delete(runId);\n }\n this.bashBlocks = this.bashBlocks.filter((entry) => entry !== component);\n this.compactionBlocks = this.compactionBlocks.filter((entry) => entry !== component);\n this.branchBlocks = this.branchBlocks.filter((entry) => entry !== component);\n this.branchMessageBlocks = this.branchMessageBlocks.filter((entry) => entry !== component);\n this.customBlocks = this.customBlocks.filter((entry) => entry !== component);\n this.assistantMessages = this.assistantMessages.filter((entry) => entry !== component);\n if (this.lastStatusEntry === component) {\n this.lastStatusEntry = null;\n this.lastStatusText = null;\n }\n for (const [runId, status] of this.workflowStatusByRunId.entries()) {\n if (status.entry === component) this.workflowStatusByRunId.delete(runId);\n }\n }\n\n private append(component: Component): void {\n this.addChild(component);\n this.pruneOverflow();\n }\n\n clearAll(): void {\n this.clear();\n this.toolById.clear();\n this.bashBlocks = [];\n this.compactionBlocks = [];\n this.branchBlocks = [];\n this.branchMessageBlocks = [];\n this.customBlocks = [];\n this.assistantMessages = [];\n this.streamingRuns.clear();\n this.assistantAnchorByRunId.clear();\n this.runsWithTools.clear();\n this.lastAssistantText = '';\n this.lastStatusEntry = null;\n this.lastStatusText = null;\n this.workflowStatusByRunId.clear();\n }\n\n private createAssistantMessage(message?: AgentMessage): AssistantMessageComponent {\n const component = new AssistantMessageComponent(message, {\n hideThinkingBlock: !this.showThinking,\n hiddenThinkingLabel: this.hiddenThinkingLabel,\n });\n this.assistantMessages.push(component);\n return component;\n }\n\n addSystem(text: string): void {\n const entry = new Container();\n entry.addChild(new Spacer(1));\n entry.addChild(new Text(theme.system(text), 1, 0));\n this.append(entry);\n }\n\n addStatus(text: string): void {\n if (\n this.lastStatusEntry &&\n this.lastStatusText &&\n this.children[this.children.length - 1] === this.lastStatusEntry\n ) {\n this.lastStatusText.setText(theme.system(text));\n return;\n }\n\n const entry = new Container();\n const statusText = new Text(theme.system(text), 1, 0);\n entry.addChild(new Spacer(1));\n entry.addChild(statusText);\n this.lastStatusEntry = entry;\n this.lastStatusText = statusText;\n this.append(entry);\n }\n\n updateWorkflowRun(runId: string, text: string): void {\n const existing = this.workflowStatusByRunId.get(runId);\n if (existing) {\n existing.text.setText(theme.system(text));\n return;\n }\n\n const entry = new Container();\n const statusText = new Text(theme.system(text), 1, 0);\n entry.addChild(new Spacer(1));\n entry.addChild(statusText);\n this.workflowStatusByRunId.set(runId, { entry, text: statusText });\n this.append(entry);\n }\n\n addCompactionSummary(result: TuiCompactionResult): void {\n const component = new CompactionSummaryComponent(result, this.keybindings);\n component.setExpanded(this.toolsExpanded);\n this.compactionBlocks.push(component);\n this.append(component);\n }\n\n addBranchSummary(summary: TuiBranchSummary): void {\n const component = new BranchSummaryComponent(summary, this.keybindings);\n component.setExpanded(this.toolsExpanded);\n this.branchBlocks.push(component);\n this.append(component);\n }\n\n addBranchMessageSummary(summary: BranchMessageSummary): void {\n this.assistantAnchorByRunId.clear();\n const component = new BranchMessageSummaryComponent(summary, this.keybindings);\n component.setExpanded(this.toolsExpanded);\n this.branchMessageBlocks.push(component);\n this.append(component);\n }\n\n addCustomMessage(summary: CustomMessageSummary): void {\n this.assistantAnchorByRunId.clear();\n const component = new CustomMessageComponent(\n summary,\n this.customMessageRenderers.get(summary.customType),\n );\n component.setExpanded(this.toolsExpanded);\n this.customBlocks.push(component);\n this.append(component);\n }\n\n setCustomMessageRenderer(customType: string, renderer: TuiMessageRenderer | undefined): void {\n if (renderer) {\n this.customMessageRenderers.set(customType, renderer);\n } else {\n this.customMessageRenderers.delete(customType);\n }\n for (const block of this.customBlocks) {\n if (block.matchesCustomType(customType)) {\n block.setRenderer(renderer);\n }\n }\n }\n\n addUser(text: string | unknown[]): void {\n this.assistantAnchorByRunId.clear();\n this.append(new UserMessageComponent(text));\n }\n\n /** Stream local `!command` output in a bordered block. */\n addBashExecution(\n command: string,\n ui: import('@earendil-works/pi-tui').TUI,\n excludeFromContext: boolean,\n ): BashExecutionComponent {\n this.assistantAnchorByRunId.clear();\n const component = new BashExecutionComponent(command, ui, excludeFromContext, this.keybindings);\n component.setExpanded(this.toolsExpanded);\n this.bashBlocks.push(component);\n this.append(component);\n return component;\n }\n\n /** Replay a completed shell execution from persisted transcript history. */\n addBashSummary(summary: BashSummary): void {\n this.assistantAnchorByRunId.clear();\n const component = new BashSummaryComponent(summary, this.keybindings);\n component.setExpanded(this.toolsExpanded);\n this.bashBlocks.push(component);\n this.append(component);\n }\n\n startAssistant(message: AgentMessage, runId: string): void {\n const text = assistantPlainText(message);\n if (text.trim()) this.lastAssistantText = text;\n const existing = this.streamingRuns.get(runId);\n if (existing) {\n existing.updateContent(message);\n existing.setHasToolCalls(this.runsWithTools.has(runId));\n return;\n }\n const component = this.createAssistantMessage(message);\n component.setHasToolCalls(this.runsWithTools.has(runId));\n this.streamingRuns.set(runId, component);\n this.append(component);\n }\n\n updateAssistant(message: AgentMessage, runId: string): void {\n const text = assistantPlainText(message);\n if (text.trim()) this.lastAssistantText = text;\n const existing = this.streamingRuns.get(runId);\n if (!existing) {\n this.startAssistant(message, runId);\n return;\n }\n existing.updateContent(message);\n existing.setHasToolCalls(this.runsWithTools.has(runId));\n }\n\n finalizeAssistant(message: AgentMessage, runId: string): void {\n const text = assistantPlainText(message);\n if (text.trim()) this.lastAssistantText = text;\n const existing = this.streamingRuns.get(runId);\n if (existing) {\n existing.updateContent(message);\n existing.setHasToolCalls(this.runsWithTools.has(runId));\n this.streamingRuns.delete(runId);\n this.assistantAnchorByRunId.set(runId, existing);\n return;\n }\n const finalMessage = this.createAssistantMessage(message);\n finalMessage.setHasToolCalls(this.runsWithTools.has(runId));\n this.append(finalMessage);\n if (text.trim()) {\n this.assistantAnchorByRunId.set(runId, finalMessage);\n }\n }\n\n dropAssistant(runId: string): void {\n const existing = this.streamingRuns.get(runId);\n if (!existing) return;\n this.removeChild(existing);\n this.streamingRuns.delete(runId);\n }\n\n startTool(toolCallId: string, toolName: string, args: unknown, runId: string): void {\n const existing = this.toolById.get(toolCallId);\n if (existing) {\n existing.setArgs(args);\n return;\n }\n this.runsWithTools.add(runId);\n const component = new ToolExecutionComponent(toolName, toolCallId, args, {\n ...this.toolImageOptions,\n });\n component.setExpanded(this.toolsExpanded);\n this.toolById.set(toolCallId, component);\n\n const assistant = this.streamingRuns.get(runId) ?? this.assistantAnchorByRunId.get(runId);\n assistant?.setHasToolCalls(true);\n this.addChild(component);\n this.pruneOverflow();\n }\n\n markToolExecutionStarted(toolCallId: string): void {\n const existing = this.toolById.get(toolCallId);\n if (!existing) return;\n existing.markExecutionStarted();\n }\n\n markToolArgsComplete(toolCallId: string): void {\n const existing = this.toolById.get(toolCallId);\n if (!existing) return;\n existing.setArgsComplete();\n }\n\n updateToolResult(toolCallId: string, result: AgentToolResult<any> | unknown, isError: boolean, isPartial = false): void {\n const existing = this.toolById.get(toolCallId);\n if (!existing) return;\n existing.updateResult(result, isPartial, isError);\n }\n\n updateToolDetails(toolCallId: string, details: unknown): void {\n const existing = this.toolById.get(toolCallId);\n if (!existing) return;\n existing.setPartialDetails(details);\n }\n\n updateToolArgs(toolCallId: string, args: unknown): void {\n const existing = this.toolById.get(toolCallId);\n if (!existing) return;\n existing.setArgs(args);\n }\n\n setToolsExpanded(expanded: boolean): void {\n this.toolsExpanded = expanded;\n for (const tool of this.toolById.values()) {\n tool.setExpanded(expanded);\n }\n for (const bash of this.bashBlocks) {\n bash.setExpanded(expanded);\n }\n for (const compaction of this.compactionBlocks) {\n compaction.setExpanded(expanded);\n }\n for (const branch of this.branchBlocks) {\n branch.setExpanded(expanded);\n }\n for (const branch of this.branchMessageBlocks) {\n branch.setExpanded(expanded);\n }\n for (const custom of this.customBlocks) {\n custom.setExpanded(expanded);\n }\n }\n\n setShowThinking(showThinking: boolean): void {\n this.showThinking = showThinking;\n for (const assistant of this.assistantMessages) {\n assistant.setHideThinkingBlock(!showThinking);\n }\n }\n\n setHiddenThinkingLabel(label?: string): void {\n this.hiddenThinkingLabel = label ?? 'Thinking...';\n for (const assistant of this.assistantMessages) {\n assistant.setHiddenThinkingLabel(this.hiddenThinkingLabel);\n }\n }\n\n setToolImageOptions(options: ToolExecutionOptions): void {\n this.toolImageOptions = { ...options, keybindings: this.keybindings };\n for (const tool of this.toolById.values()) {\n tool.setImageOptions(this.toolImageOptions);\n }\n }\n\n getLastAssistantText(): string {\n return this.lastAssistantText;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chat-log.js","names":[],"sources":["../../../../src/tui/components/chat-log.ts"],"sourcesContent":["import type { Component, KeybindingsManager } from '@earendil-works/pi-tui';\nimport { Container, Spacer, Text } from '@earendil-works/pi-tui';\nimport type { AgentMessage, AgentToolResult } from '@earendil-works/pi-agent-core';\n\nimport { BashExecutionComponent } from './bash-execution.js';\nimport { BashSummaryComponent, type BashSummary } from './bash-summary.js';\nimport { BranchMessageSummaryComponent, type BranchMessageSummary } from './branch-message-summary.js';\nimport { BranchSummaryComponent } from './branch-summary.js';\nimport { CompactionSummaryComponent } from './compaction-summary.js';\nimport { CustomMessageComponent, type CustomMessageSummary } from './custom-message.js';\nimport type { TuiMessageRenderer } from '../../extensions/types/tui.js';\nimport { theme } from '../theme.js';\nimport { AssistantMessageComponent } from './assistant-message.js';\nimport { ToolExecutionComponent, type ToolExecutionOptions } from './tool-execution.js';\nimport { UserMessageComponent } from './user-message.js';\nimport type { TuiBranchSummary, TuiCompactionResult } from '../tui-backend.js';\n\nconst MAX_COMPONENTS = 180;\n\ntype ExpandableBlock = { setExpanded(expanded: boolean): void };\nexport type ChatLogEntryMeta = {\n displayIndex?: number;\n historyIndex?: number;\n rowNumber?: number;\n role?: 'user' | 'assistant' | 'system';\n};\n\ntype ChatLogEntryRecord = ChatLogEntryMeta & { component: Component };\n\nfunction assistantPlainText(message: AgentMessage): string {\n const content = (message as { content?: unknown }).content;\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return '';\n return content\n .map((block) => {\n if (!block || typeof block !== 'object') return '';\n const rec = block as { type?: unknown; text?: unknown };\n return rec.type === 'text' && typeof rec.text === 'string' ? rec.text : '';\n })\n .join('');\n}\n\nexport class ChatLog extends Container {\n private toolById = new Map<string, ToolExecutionComponent>();\n private bashBlocks: Array<Component & ExpandableBlock> = [];\n private compactionBlocks: CompactionSummaryComponent[] = [];\n private branchBlocks: BranchSummaryComponent[] = [];\n private branchMessageBlocks: BranchMessageSummaryComponent[] = [];\n private customBlocks: CustomMessageComponent[] = [];\n private customMessageRenderers = new Map<string, TuiMessageRenderer>();\n private assistantMessages: AssistantMessageComponent[] = [];\n private streamingRuns = new Map<string, AssistantMessageComponent>();\n /** After finalizeAssistant, late tool execution events can still arrive; keep the bubble to link tools. */\n private assistantAnchorByRunId = new Map<string, AssistantMessageComponent>();\n private runsWithTools = new Set<string>();\n private toolsExpanded = false;\n private showThinking = true;\n private hiddenThinkingLabel = 'Thinking...';\n private toolImageOptions: ToolExecutionOptions = {};\n private lastAssistantText = '';\n private lastStatusEntry: Container | null = null;\n private lastStatusText: Text | null = null;\n private workflowStatusByRunId = new Map<string, { entry: Container; text: Text }>();\n private entryRecords: ChatLogEntryRecord[] = [];\n private viewportRowsProvider: (() => number) | undefined;\n private historyViewDisplayIndex: number | null = null;\n\n constructor(private readonly keybindings?: KeybindingsManager) {\n super();\n if (keybindings) {\n this.toolImageOptions.keybindings = keybindings;\n }\n }\n\n private pruneOverflow(): void {\n while (this.children.length > MAX_COMPONENTS) {\n const oldest = this.children[0];\n if (!oldest) return;\n this.removeChild(oldest);\n this.dropReferences(oldest);\n }\n }\n\n private dropReferences(component: Component): void {\n for (const [id, tool] of this.toolById.entries()) {\n if (tool === component) this.toolById.delete(id);\n }\n for (const [runId, msg] of this.streamingRuns.entries()) {\n if (msg === component) this.streamingRuns.delete(runId);\n }\n for (const [runId, msg] of this.assistantAnchorByRunId.entries()) {\n if (msg === component) this.assistantAnchorByRunId.delete(runId);\n }\n this.bashBlocks = this.bashBlocks.filter((entry) => entry !== component);\n this.compactionBlocks = this.compactionBlocks.filter((entry) => entry !== component);\n this.branchBlocks = this.branchBlocks.filter((entry) => entry !== component);\n this.branchMessageBlocks = this.branchMessageBlocks.filter((entry) => entry !== component);\n this.customBlocks = this.customBlocks.filter((entry) => entry !== component);\n this.assistantMessages = this.assistantMessages.filter((entry) => entry !== component);\n if (this.lastStatusEntry === component) {\n this.lastStatusEntry = null;\n this.lastStatusText = null;\n }\n for (const [runId, status] of this.workflowStatusByRunId.entries()) {\n if (status.entry === component) this.workflowStatusByRunId.delete(runId);\n }\n this.entryRecords = this.entryRecords.filter((entry) => entry.component !== component);\n if (!this.findEntryRecord(this.historyViewDisplayIndex)) {\n this.historyViewDisplayIndex = null;\n }\n }\n\n private append(component: Component, meta?: ChatLogEntryMeta): void {\n this.addChild(component);\n if (meta) {\n this.entryRecords.push({ component, ...meta });\n }\n this.pruneOverflow();\n }\n\n clearAll(): void {\n this.clear();\n this.toolById.clear();\n this.bashBlocks = [];\n this.compactionBlocks = [];\n this.branchBlocks = [];\n this.branchMessageBlocks = [];\n this.customBlocks = [];\n this.assistantMessages = [];\n this.streamingRuns.clear();\n this.assistantAnchorByRunId.clear();\n this.runsWithTools.clear();\n this.lastAssistantText = '';\n this.lastStatusEntry = null;\n this.lastStatusText = null;\n this.workflowStatusByRunId.clear();\n this.entryRecords = [];\n this.historyViewDisplayIndex = null;\n }\n\n private createAssistantMessage(message?: AgentMessage): AssistantMessageComponent {\n const component = new AssistantMessageComponent(message, {\n hideThinkingBlock: !this.showThinking,\n hiddenThinkingLabel: this.hiddenThinkingLabel,\n });\n this.assistantMessages.push(component);\n return component;\n }\n\n addSystem(text: string, meta?: ChatLogEntryMeta): void {\n const entry = new Container();\n entry.addChild(new Spacer(1));\n entry.addChild(new Text(theme.system(text), 1, 0));\n this.append(entry, meta);\n }\n\n addStatus(text: string): void {\n if (\n this.lastStatusEntry &&\n this.lastStatusText &&\n this.children[this.children.length - 1] === this.lastStatusEntry\n ) {\n this.lastStatusText.setText(theme.system(text));\n return;\n }\n\n const entry = new Container();\n const statusText = new Text(theme.system(text), 1, 0);\n entry.addChild(new Spacer(1));\n entry.addChild(statusText);\n this.lastStatusEntry = entry;\n this.lastStatusText = statusText;\n this.append(entry);\n }\n\n updateWorkflowRun(runId: string, text: string): void {\n const existing = this.workflowStatusByRunId.get(runId);\n if (existing) {\n existing.text.setText(theme.system(text));\n return;\n }\n\n const entry = new Container();\n const statusText = new Text(theme.system(text), 1, 0);\n entry.addChild(new Spacer(1));\n entry.addChild(statusText);\n this.workflowStatusByRunId.set(runId, { entry, text: statusText });\n this.append(entry);\n }\n\n addCompactionSummary(result: TuiCompactionResult): void {\n const component = new CompactionSummaryComponent(result, this.keybindings);\n component.setExpanded(this.toolsExpanded);\n this.compactionBlocks.push(component);\n this.append(component);\n }\n\n addBranchSummary(summary: TuiBranchSummary): void {\n const component = new BranchSummaryComponent(summary, this.keybindings);\n component.setExpanded(this.toolsExpanded);\n this.branchBlocks.push(component);\n this.append(component);\n }\n\n addBranchMessageSummary(summary: BranchMessageSummary): void {\n this.assistantAnchorByRunId.clear();\n const component = new BranchMessageSummaryComponent(summary, this.keybindings);\n component.setExpanded(this.toolsExpanded);\n this.branchMessageBlocks.push(component);\n this.append(component);\n }\n\n addCustomMessage(summary: CustomMessageSummary): void {\n this.assistantAnchorByRunId.clear();\n const component = new CustomMessageComponent(\n summary,\n this.customMessageRenderers.get(summary.customType),\n );\n component.setExpanded(this.toolsExpanded);\n this.customBlocks.push(component);\n this.append(component);\n }\n\n setCustomMessageRenderer(customType: string, renderer: TuiMessageRenderer | undefined): void {\n if (renderer) {\n this.customMessageRenderers.set(customType, renderer);\n } else {\n this.customMessageRenderers.delete(customType);\n }\n for (const block of this.customBlocks) {\n if (block.matchesCustomType(customType)) {\n block.setRenderer(renderer);\n }\n }\n }\n\n addUser(text: string | unknown[], meta?: ChatLogEntryMeta): void {\n this.assistantAnchorByRunId.clear();\n this.append(new UserMessageComponent(text), meta);\n }\n\n /** Stream local `!command` output in a bordered block. */\n addBashExecution(\n command: string,\n ui: import('@earendil-works/pi-tui').TUI,\n excludeFromContext: boolean,\n ): BashExecutionComponent {\n this.assistantAnchorByRunId.clear();\n const component = new BashExecutionComponent(command, ui, excludeFromContext, this.keybindings);\n component.setExpanded(this.toolsExpanded);\n this.bashBlocks.push(component);\n this.append(component);\n return component;\n }\n\n /** Replay a completed shell execution from persisted transcript history. */\n addBashSummary(summary: BashSummary): void {\n this.assistantAnchorByRunId.clear();\n const component = new BashSummaryComponent(summary, this.keybindings);\n component.setExpanded(this.toolsExpanded);\n this.bashBlocks.push(component);\n this.append(component);\n }\n\n startAssistant(message: AgentMessage, runId: string): void {\n const text = assistantPlainText(message);\n if (text.trim()) this.lastAssistantText = text;\n const existing = this.streamingRuns.get(runId);\n if (existing) {\n existing.updateContent(message);\n existing.setHasToolCalls(this.runsWithTools.has(runId));\n return;\n }\n const component = this.createAssistantMessage(message);\n component.setHasToolCalls(this.runsWithTools.has(runId));\n this.streamingRuns.set(runId, component);\n this.append(component);\n }\n\n updateAssistant(message: AgentMessage, runId: string): void {\n const text = assistantPlainText(message);\n if (text.trim()) this.lastAssistantText = text;\n const existing = this.streamingRuns.get(runId);\n if (!existing) {\n this.startAssistant(message, runId);\n return;\n }\n existing.updateContent(message);\n existing.setHasToolCalls(this.runsWithTools.has(runId));\n }\n\n finalizeAssistant(message: AgentMessage, runId: string, meta?: ChatLogEntryMeta): void {\n const text = assistantPlainText(message);\n if (text.trim()) this.lastAssistantText = text;\n const existing = this.streamingRuns.get(runId);\n if (existing) {\n existing.updateContent(message);\n existing.setHasToolCalls(this.runsWithTools.has(runId));\n this.streamingRuns.delete(runId);\n this.assistantAnchorByRunId.set(runId, existing);\n return;\n }\n const finalMessage = this.createAssistantMessage(message);\n finalMessage.setHasToolCalls(this.runsWithTools.has(runId));\n this.append(finalMessage, meta);\n if (text.trim()) {\n this.assistantAnchorByRunId.set(runId, finalMessage);\n }\n }\n\n dropAssistant(runId: string): void {\n const existing = this.streamingRuns.get(runId);\n if (!existing) return;\n this.removeChild(existing);\n this.streamingRuns.delete(runId);\n }\n\n startTool(toolCallId: string, toolName: string, args: unknown, runId: string): void {\n const existing = this.toolById.get(toolCallId);\n if (existing) {\n existing.setArgs(args);\n return;\n }\n this.runsWithTools.add(runId);\n const component = new ToolExecutionComponent(toolName, toolCallId, args, {\n ...this.toolImageOptions,\n });\n component.setExpanded(this.toolsExpanded);\n this.toolById.set(toolCallId, component);\n\n const assistant = this.streamingRuns.get(runId) ?? this.assistantAnchorByRunId.get(runId);\n assistant?.setHasToolCalls(true);\n this.append(component);\n }\n\n markToolExecutionStarted(toolCallId: string): void {\n const existing = this.toolById.get(toolCallId);\n if (!existing) return;\n existing.markExecutionStarted();\n }\n\n markToolArgsComplete(toolCallId: string): void {\n const existing = this.toolById.get(toolCallId);\n if (!existing) return;\n existing.setArgsComplete();\n }\n\n updateToolResult(toolCallId: string, result: AgentToolResult<any> | unknown, isError: boolean, isPartial = false): void {\n const existing = this.toolById.get(toolCallId);\n if (!existing) return;\n existing.updateResult(result, isPartial, isError);\n }\n\n updateToolDetails(toolCallId: string, details: unknown): void {\n const existing = this.toolById.get(toolCallId);\n if (!existing) return;\n existing.setPartialDetails(details);\n }\n\n updateToolArgs(toolCallId: string, args: unknown): void {\n const existing = this.toolById.get(toolCallId);\n if (!existing) return;\n existing.setArgs(args);\n }\n\n setToolsExpanded(expanded: boolean): void {\n this.toolsExpanded = expanded;\n for (const tool of this.toolById.values()) {\n tool.setExpanded(expanded);\n }\n for (const bash of this.bashBlocks) {\n bash.setExpanded(expanded);\n }\n for (const compaction of this.compactionBlocks) {\n compaction.setExpanded(expanded);\n }\n for (const branch of this.branchBlocks) {\n branch.setExpanded(expanded);\n }\n for (const branch of this.branchMessageBlocks) {\n branch.setExpanded(expanded);\n }\n for (const custom of this.customBlocks) {\n custom.setExpanded(expanded);\n }\n }\n\n setShowThinking(showThinking: boolean): void {\n this.showThinking = showThinking;\n for (const assistant of this.assistantMessages) {\n assistant.setHideThinkingBlock(!showThinking);\n }\n }\n\n setHiddenThinkingLabel(label?: string): void {\n this.hiddenThinkingLabel = label ?? 'Thinking...';\n for (const assistant of this.assistantMessages) {\n assistant.setHiddenThinkingLabel(this.hiddenThinkingLabel);\n }\n }\n\n setToolImageOptions(options: ToolExecutionOptions): void {\n this.toolImageOptions = { ...options, keybindings: this.keybindings };\n for (const tool of this.toolById.values()) {\n tool.setImageOptions(this.toolImageOptions);\n }\n }\n\n getLastAssistantText(): string {\n return this.lastAssistantText;\n }\n\n setViewportRowsProvider(provider: (() => number) | undefined): void {\n this.viewportRowsProvider = provider;\n }\n\n jumpToDisplayIndex(displayIndex: number): boolean {\n const target = this.findEntryRecord(displayIndex);\n if (!target) return false;\n this.historyViewDisplayIndex = target.displayIndex ?? null;\n return true;\n }\n\n jumpToLatest(): void {\n this.historyViewDisplayIndex = null;\n }\n\n getTimelineViewportState(): { mode: 'latest' } | { mode: 'history'; displayIndex: number } {\n if (this.historyViewDisplayIndex === null) return { mode: 'latest' };\n return { mode: 'history', displayIndex: this.historyViewDisplayIndex };\n }\n\n override render(width: number): string[] {\n const allLines: string[] = [];\n const ranges: Array<{ record: ChatLogEntryRecord; start: number; end: number }> = [];\n for (const child of this.children) {\n const start = allLines.length;\n const childLines = child.render(width);\n allLines.push(...childLines);\n const record = this.entryRecords.find((entry) => entry.component === child);\n if (record) {\n ranges.push({ record, start, end: allLines.length });\n }\n }\n\n if (this.historyViewDisplayIndex === null) return allLines;\n\n const target = this.findEntryRecord(this.historyViewDisplayIndex);\n const range = target\n ? ranges.find((candidate) => candidate.record.component === target.component)\n : undefined;\n if (!range) {\n this.historyViewDisplayIndex = null;\n return allLines;\n }\n\n const viewportRows = Math.max(8, Math.floor(this.viewportRowsProvider?.() ?? 24));\n const start = Math.max(0, range.start - 1);\n const end = Math.min(allLines.length, start + Math.max(1, viewportRows - 1));\n return [\n theme.dim('Viewing previous transcript - /timeline latest returns to live view.'),\n ...allLines.slice(start, end),\n ];\n }\n\n private findEntryRecord(displayIndex: number | null): ChatLogEntryRecord | undefined {\n if (displayIndex === null || !Number.isFinite(displayIndex)) return undefined;\n return this.entryRecords.find((entry) => entry.displayIndex === displayIndex);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { theme } from "../theme.js";
|
|
2
2
|
import { formatContextUsageLabel } from "../tui-context-usage.js";
|
|
3
3
|
import { getGitBranchCached } from "../tui-git-branch.js";
|
|
4
|
+
import { formatActiveRunStatus } from "../tui-run-status-format.js";
|
|
4
5
|
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
5
6
|
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
6
7
|
//#region src/tui/components/tui-bottom-bar.ts
|
|
@@ -8,7 +9,11 @@ const BUSY_ACTIVITY = new Set([
|
|
|
8
9
|
"sending",
|
|
9
10
|
"waiting",
|
|
10
11
|
"streaming",
|
|
11
|
-
"running"
|
|
12
|
+
"running",
|
|
13
|
+
"compacting",
|
|
14
|
+
"stalled",
|
|
15
|
+
"recovering",
|
|
16
|
+
"aborting"
|
|
12
17
|
]);
|
|
13
18
|
/** Compact token counts (aligned with pi coding-agent footer). */
|
|
14
19
|
function formatTokens(count) {
|
|
@@ -86,15 +91,14 @@ var TuiBottomBar = class {
|
|
|
86
91
|
const pwdLine = truncateToWidth(theme.dim(`${cwdWithBranch} · ${sessionLine}`), width, theme.dim("…"));
|
|
87
92
|
const busy = BUSY_ACTIVITY.has(state.activityStatus);
|
|
88
93
|
const leftParts = [state.connectionStatus];
|
|
89
|
-
|
|
94
|
+
const activeRunStatus = formatActiveRunStatus(state);
|
|
95
|
+
if (activeRunStatus) leftParts.push(activeRunStatus);
|
|
96
|
+
else if (!busy && state.activityStatus && state.activityStatus !== "idle") leftParts.push(state.activityStatus);
|
|
90
97
|
if (state.sessionInfo.totalTokens != null) leftParts.push(formatTokens(state.sessionInfo.totalTokens));
|
|
91
98
|
const ctxLabel = formatContextUsageLabel(state.sessionInfo.contextUsagePercent ?? null, state.sessionInfo.contextWindow ?? null);
|
|
92
99
|
if (ctxLabel) leftParts.push(ctxLabel);
|
|
93
100
|
if (state.isCompacting) leftParts.push("compact…");
|
|
94
101
|
else if (state.compactionQueue.length > 0) leftParts.push(`C${state.compactionQueue.length}`);
|
|
95
|
-
if (state.runStatus?.phase === "stalled") leftParts.push("run:stalled");
|
|
96
|
-
else if (state.runStatus?.phase === "recovering") leftParts.push("run:recovering");
|
|
97
|
-
else if (state.runStatus?.source === "agent-resume" && state.activeRunId) leftParts.push("run:resumed");
|
|
98
102
|
if (state.messageFollowUpQueue.length > 0) leftParts.push(`Q${state.messageFollowUpQueue.length}`);
|
|
99
103
|
if (state.steeringQueue.length > 0) leftParts.push(`S${state.steeringQueue.length}`);
|
|
100
104
|
let statsLeft = leftParts.join(" · ");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui-bottom-bar.js","names":[],"sources":["../../../../src/tui/components/tui-bottom-bar.ts"],"sourcesContent":["import { isAbsolute, relative, resolve, sep } from 'node:path';\n\nimport type { Component } from '@earendil-works/pi-tui';\nimport { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nimport { theme } from '../theme.js';\nimport { formatContextUsageLabel } from '../tui-context-usage.js';\nimport { getGitBranchCached } from '../tui-git-branch.js';\nimport type { TuiState } from '../tui-types.js';\n\nconst BUSY_ACTIVITY = new Set(['sending', 'waiting', 'streaming', 'running']);\n\n/** Compact token counts (aligned with pi coding-agent footer). */\nexport function formatTokens(count: number): string {\n if (count < 1000) return count.toString();\n if (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n if (count < 1_000_000) return `${Math.round(count / 1000)}k`;\n if (count < 10_000_000) return `${(count / 1_000_000).toFixed(1)}M`;\n return `${Math.round(count / 1_000_000)}M`;\n}\n\nexport function sanitizeStatusText(text: string): string {\n return text\n .replace(/[\\r\\n\\t]/g, ' ')\n .replace(/ +/g, ' ')\n .trim();\n}\n\nexport function formatQueuedMessageLines(\n state: TuiState,\n width: number,\n dequeueHint: string,\n): string[] {\n const lines: string[] = [];\n const add = (label: string, text: string) => {\n const sanitized = sanitizeStatusText(text);\n if (!sanitized) return;\n lines.push(\n truncateToWidth(theme.dim(`${label}: ${sanitized}`), width, theme.dim('…')),\n );\n };\n\n for (const message of state.steeringQueue) {\n add('Steering', message);\n }\n for (const message of state.messageFollowUpQueue) {\n add('Follow-up', message);\n }\n for (const message of state.compactionQueue) {\n add('Queued', message);\n }\n if (lines.length > 0) {\n lines.push(\n truncateToWidth(theme.dim(`↳ ${dequeueHint} to edit all queued messages`), width, theme.dim('…')),\n );\n }\n return lines;\n}\n\nexport function formatCwdForFooter(cwd: string, home: string | undefined): string {\n if (!home) return cwd;\n\n const resolvedCwd = resolve(cwd);\n const resolvedHome = resolve(home);\n const relativeToHome = relative(resolvedHome, resolvedCwd);\n const isInsideHome =\n relativeToHome === '' ||\n (relativeToHome !== '..' &&\n !relativeToHome.startsWith(`..${sep}`) &&\n !isAbsolute(relativeToHome));\n\n if (!isInsideHome) return cwd;\n return relativeToHome === '' ? '~' : `~${sep}${relativeToHome}`;\n}\n\nfunction shortenPath(cwd: string): string {\n const formatted = formatCwdForFooter(cwd, process.env.HOME || process.env.USERPROFILE);\n if (formatted !== cwd) return formatted;\n return cwd;\n}\n\n/**\n * Multi-line footer below the input editor (pi coding-agent style):\n * cwd · session, then a single padded row: status/tokens on the left, model on the right.\n */\nexport class TuiBottomBar implements Component {\n private extensionLines: string[] = [];\n private extensionComponents: Component[] = [];\n private extensionStatusParts: string[] = [];\n private customComponent: Component | undefined;\n\n constructor(\n private readonly getState: () => TuiState,\n private readonly getThinkingDefault: () => string | undefined,\n private readonly getDequeueHint: () => string = () => 'Alt+Up',\n ) {}\n\n setExtensionLines(lines: string[]): void {\n this.extensionLines = lines;\n }\n\n setExtensionComponents(components: Component[]): void {\n this.extensionComponents = components;\n }\n\n setExtensionStatusParts(parts: string[]): void {\n this.extensionStatusParts = parts;\n }\n\n setCustomComponent(component: Component | undefined): void {\n this.customComponent = component;\n }\n\n invalidate(): void {}\n\n render(width: number): string[] {\n if (this.customComponent) {\n const rendered = this.customComponent.render(width);\n return rendered.map((line) => truncateToWidth(line, width, theme.dim('…')));\n }\n\n const state = this.getState();\n const cwdRaw = state.sessionInfo.effectiveWorkspacePath;\n const cwdWithBranch = cwdRaw\n ? (() => {\n const cwd = shortenPath(cwdRaw);\n const branch = getGitBranchCached(cwdRaw);\n return branch ? `${cwd} (${branch})` : cwd;\n })()\n : 'workspace loading';\n const sessionLine = state.sessionInfo.displayName ?? `session ${state.currentSessionKey}`;\n const pwdLine = truncateToWidth(\n theme.dim(`${cwdWithBranch} · ${sessionLine}`),\n width,\n theme.dim('…'),\n );\n\n const busy = BUSY_ACTIVITY.has(state.activityStatus);\n const leftParts: string[] = [state.connectionStatus];\n if (!busy && state.activityStatus && state.activityStatus !== 'idle') {\n leftParts.push(state.activityStatus);\n }\n if (state.sessionInfo.totalTokens != null) {\n leftParts.push(formatTokens(state.sessionInfo.totalTokens));\n }\n const ctxLabel = formatContextUsageLabel(\n state.sessionInfo.contextUsagePercent ?? null,\n state.sessionInfo.contextWindow ?? null,\n );\n if (ctxLabel) {\n leftParts.push(ctxLabel);\n }\n if (state.isCompacting) {\n leftParts.push('compact…');\n } else if (state.compactionQueue.length > 0) {\n leftParts.push(`C${state.compactionQueue.length}`);\n }\n if (state.runStatus?.phase === 'stalled') {\n leftParts.push('run:stalled');\n } else if (state.runStatus?.phase === 'recovering') {\n leftParts.push('run:recovering');\n } else if (state.runStatus?.source === 'agent-resume' && state.activeRunId) {\n leftParts.push('run:resumed');\n }\n if (state.messageFollowUpQueue.length > 0) {\n leftParts.push(`Q${state.messageFollowUpQueue.length}`);\n }\n if (state.steeringQueue.length > 0) {\n leftParts.push(`S${state.steeringQueue.length}`);\n }\n let statsLeft = leftParts.join(' · ');\n\n const modelId = state.sessionInfo.model ?? 'unknown';\n const prov = state.sessionInfo.modelProvider;\n const thinkingHint = state.showThinking\n ? `thinking:${this.getThinkingDefault() ?? 'on'}`\n : 'thinking:off';\n let rightSide = prov ? `(${prov}) ${modelId}` : modelId;\n rightSide = `${rightSide} • ${thinkingHint}`;\n\n const minPadding = 2;\n let statsLeftWidth = visibleWidth(statsLeft);\n if (statsLeftWidth > width) {\n statsLeft = truncateToWidth(statsLeft, width, '…');\n statsLeftWidth = visibleWidth(statsLeft);\n }\n\n const rightWidth = visibleWidth(rightSide);\n const totalNeeded = statsLeftWidth + minPadding + rightWidth;\n\n let statsLine: string;\n if (totalNeeded <= width) {\n const padding = ' '.repeat(width - statsLeftWidth - rightWidth);\n statsLine = statsLeft + padding + rightSide;\n } else {\n const availableForRight = width - statsLeftWidth - minPadding;\n if (availableForRight > 0) {\n const truncatedRight = truncateToWidth(rightSide, availableForRight, '');\n const tw = visibleWidth(truncatedRight);\n const padding = ' '.repeat(Math.max(0, width - statsLeftWidth - tw));\n statsLine = statsLeft + padding + truncatedRight;\n } else {\n statsLine = statsLeft;\n }\n }\n\n const statsDimmed = theme.dim(statsLine);\n const lines = [pwdLine, statsDimmed];\n if (this.extensionStatusParts.length > 0) {\n const statusLine = this.extensionStatusParts\n .map((part) => sanitizeStatusText(part))\n .filter(Boolean)\n .join(' ');\n if (statusLine) {\n lines.push(truncateToWidth(theme.dim(statusLine), width, theme.dim('…')));\n }\n }\n lines.push(...formatQueuedMessageLines(state, width, this.getDequeueHint()));\n for (const extLine of this.extensionLines) {\n lines.push(truncateToWidth(theme.dim(sanitizeStatusText(extLine)), width, theme.dim('…')));\n }\n for (const component of this.extensionComponents) {\n for (const line of component.render(width)) {\n lines.push(truncateToWidth(line, width, theme.dim('…')));\n }\n }\n return lines;\n }\n}\n"],"mappings":";;;;;;AAUA,MAAM,gBAAgB,IAAI,IAAI;CAAC;CAAW;CAAW;CAAa;CAAU,CAAC;;AAG7E,SAAgB,aAAa,OAAuB;AAClD,KAAI,QAAQ,IAAM,QAAO,MAAM,UAAU;AACzC,KAAI,QAAQ,IAAO,QAAO,IAAI,QAAQ,KAAM,QAAQ,EAAE,CAAC;AACvD,KAAI,QAAQ,IAAW,QAAO,GAAG,KAAK,MAAM,QAAQ,IAAK,CAAC;AAC1D,KAAI,QAAQ,IAAY,QAAO,IAAI,QAAQ,KAAW,QAAQ,EAAE,CAAC;AACjE,QAAO,GAAG,KAAK,MAAM,QAAQ,IAAU,CAAC;;AAG1C,SAAgB,mBAAmB,MAAsB;AACvD,QAAO,KACJ,QAAQ,aAAa,IAAI,CACzB,QAAQ,OAAO,IAAI,CACnB,MAAM;;AAGX,SAAgB,yBACd,OACA,OACA,aACU;CACV,MAAM,QAAkB,EAAE;CAC1B,MAAM,OAAO,OAAe,SAAiB;EAC3C,MAAM,YAAY,mBAAmB,KAAK;AAC1C,MAAI,CAAC,UAAW;AAChB,QAAM,KACJ,gBAAgB,MAAM,IAAI,GAAG,MAAM,IAAI,YAAY,EAAE,OAAO,MAAM,IAAI,IAAI,CAAC,CAC5E;;AAGH,MAAK,MAAM,WAAW,MAAM,cAC1B,KAAI,YAAY,QAAQ;AAE1B,MAAK,MAAM,WAAW,MAAM,qBAC1B,KAAI,aAAa,QAAQ;AAE3B,MAAK,MAAM,WAAW,MAAM,gBAC1B,KAAI,UAAU,QAAQ;AAExB,KAAI,MAAM,SAAS,EACjB,OAAM,KACJ,gBAAgB,MAAM,IAAI,KAAK,YAAY,8BAA8B,EAAE,OAAO,MAAM,IAAI,IAAI,CAAC,CAClG;AAEH,QAAO;;AAGT,SAAgB,mBAAmB,KAAa,MAAkC;AAChF,KAAI,CAAC,KAAM,QAAO;CAElB,MAAM,cAAc,QAAQ,IAAI;CAEhC,MAAM,iBAAiB,SADF,QAAQ,KACe,EAAE,YAAY;AAO1D,KAAI,EALF,mBAAmB,MAClB,mBAAmB,QAClB,CAAC,eAAe,WAAW,KAAK,MAAM,IACtC,CAAC,WAAW,eAAe,EAEZ,QAAO;AAC1B,QAAO,mBAAmB,KAAK,MAAM,IAAI,MAAM;;AAGjD,SAAS,YAAY,KAAqB;CACxC,MAAM,YAAY,mBAAmB,KAAK,QAAQ,IAAI,QAAQ,QAAQ,IAAI,YAAY;AACtF,KAAI,cAAc,IAAK,QAAO;AAC9B,QAAO;;;;;;AAOT,IAAa,eAAb,MAA+C;CAC7C,iBAAmC,EAAE;CACrC,sBAA2C,EAAE;CAC7C,uBAAyC,EAAE;CAC3C;CAEA,YACE,UACA,oBACA,uBAAsD,UACtD;AAHiB,OAAA,WAAA;AACA,OAAA,qBAAA;AACA,OAAA,iBAAA;;CAGnB,kBAAkB,OAAuB;AACvC,OAAK,iBAAiB;;CAGxB,uBAAuB,YAA+B;AACpD,OAAK,sBAAsB;;CAG7B,wBAAwB,OAAuB;AAC7C,OAAK,uBAAuB;;CAG9B,mBAAmB,WAAwC;AACzD,OAAK,kBAAkB;;CAGzB,aAAmB;CAEnB,OAAO,OAAyB;AAC9B,MAAI,KAAK,gBAEP,QADiB,KAAK,gBAAgB,OAAO,MAC9B,CAAC,KAAK,SAAS,gBAAgB,MAAM,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;EAG7E,MAAM,QAAQ,KAAK,UAAU;EAC7B,MAAM,SAAS,MAAM,YAAY;EACjC,MAAM,gBAAgB,gBACX;GACL,MAAM,MAAM,YAAY,OAAO;GAC/B,MAAM,SAAS,mBAAmB,OAAO;AACzC,UAAO,SAAS,GAAG,IAAI,IAAI,OAAO,KAAK;MACrC,GACJ;EACJ,MAAM,cAAc,MAAM,YAAY,eAAe,WAAW,MAAM;EACtE,MAAM,UAAU,gBACd,MAAM,IAAI,GAAG,cAAc,KAAK,cAAc,EAC9C,OACA,MAAM,IAAI,IAAI,CACf;EAED,MAAM,OAAO,cAAc,IAAI,MAAM,eAAe;EACpD,MAAM,YAAsB,CAAC,MAAM,iBAAiB;AACpD,MAAI,CAAC,QAAQ,MAAM,kBAAkB,MAAM,mBAAmB,OAC5D,WAAU,KAAK,MAAM,eAAe;AAEtC,MAAI,MAAM,YAAY,eAAe,KACnC,WAAU,KAAK,aAAa,MAAM,YAAY,YAAY,CAAC;EAE7D,MAAM,WAAW,wBACf,MAAM,YAAY,uBAAuB,MACzC,MAAM,YAAY,iBAAiB,KACpC;AACD,MAAI,SACF,WAAU,KAAK,SAAS;AAE1B,MAAI,MAAM,aACR,WAAU,KAAK,WAAW;WACjB,MAAM,gBAAgB,SAAS,EACxC,WAAU,KAAK,IAAI,MAAM,gBAAgB,SAAS;AAEpD,MAAI,MAAM,WAAW,UAAU,UAC7B,WAAU,KAAK,cAAc;WACpB,MAAM,WAAW,UAAU,aACpC,WAAU,KAAK,iBAAiB;WACvB,MAAM,WAAW,WAAW,kBAAkB,MAAM,YAC7D,WAAU,KAAK,cAAc;AAE/B,MAAI,MAAM,qBAAqB,SAAS,EACtC,WAAU,KAAK,IAAI,MAAM,qBAAqB,SAAS;AAEzD,MAAI,MAAM,cAAc,SAAS,EAC/B,WAAU,KAAK,IAAI,MAAM,cAAc,SAAS;EAElD,IAAI,YAAY,UAAU,KAAK,MAAM;EAErC,MAAM,UAAU,MAAM,YAAY,SAAS;EAC3C,MAAM,OAAO,MAAM,YAAY;EAC/B,MAAM,eAAe,MAAM,eACvB,YAAY,KAAK,oBAAoB,IAAI,SACzC;EACJ,IAAI,YAAY,OAAO,IAAI,KAAK,IAAI,YAAY;AAChD,cAAY,GAAG,UAAU,KAAK;EAE9B,MAAM,aAAa;EACnB,IAAI,iBAAiB,aAAa,UAAU;AAC5C,MAAI,iBAAiB,OAAO;AAC1B,eAAY,gBAAgB,WAAW,OAAO,IAAI;AAClD,oBAAiB,aAAa,UAAU;;EAG1C,MAAM,aAAa,aAAa,UAAU;EAC1C,MAAM,cAAc,iBAAiB,aAAa;EAElD,IAAI;AACJ,MAAI,eAAe,OAAO;GACxB,MAAM,UAAU,IAAI,OAAO,QAAQ,iBAAiB,WAAW;AAC/D,eAAY,YAAY,UAAU;SAC7B;GACL,MAAM,oBAAoB,QAAQ,iBAAiB;AACnD,OAAI,oBAAoB,GAAG;IACzB,MAAM,iBAAiB,gBAAgB,WAAW,mBAAmB,GAAG;IACxE,MAAM,KAAK,aAAa,eAAe;IACvC,MAAM,UAAU,IAAI,OAAO,KAAK,IAAI,GAAG,QAAQ,iBAAiB,GAAG,CAAC;AACpE,gBAAY,YAAY,UAAU;SAElC,aAAY;;EAKhB,MAAM,QAAQ,CAAC,SADK,MAAM,IAAI,UACK,CAAC;AACpC,MAAI,KAAK,qBAAqB,SAAS,GAAG;GACxC,MAAM,aAAa,KAAK,qBACrB,KAAK,SAAS,mBAAmB,KAAK,CAAC,CACvC,OAAO,QAAQ,CACf,KAAK,IAAI;AACZ,OAAI,WACF,OAAM,KAAK,gBAAgB,MAAM,IAAI,WAAW,EAAE,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;;AAG7E,QAAM,KAAK,GAAG,yBAAyB,OAAO,OAAO,KAAK,gBAAgB,CAAC,CAAC;AAC5E,OAAK,MAAM,WAAW,KAAK,eACzB,OAAM,KAAK,gBAAgB,MAAM,IAAI,mBAAmB,QAAQ,CAAC,EAAE,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;AAE5F,OAAK,MAAM,aAAa,KAAK,oBAC3B,MAAK,MAAM,QAAQ,UAAU,OAAO,MAAM,CACxC,OAAM,KAAK,gBAAgB,MAAM,OAAO,MAAM,IAAI,IAAI,CAAC,CAAC;AAG5D,SAAO"}
|
|
1
|
+
{"version":3,"file":"tui-bottom-bar.js","names":[],"sources":["../../../../src/tui/components/tui-bottom-bar.ts"],"sourcesContent":["import { isAbsolute, relative, resolve, sep } from 'node:path';\n\nimport type { Component } from '@earendil-works/pi-tui';\nimport { truncateToWidth, visibleWidth } from '@earendil-works/pi-tui';\n\nimport { theme } from '../theme.js';\nimport { formatContextUsageLabel } from '../tui-context-usage.js';\nimport { getGitBranchCached } from '../tui-git-branch.js';\nimport { formatActiveRunStatus } from '../tui-run-status-format.js';\nimport type { TuiState } from '../tui-types.js';\n\nconst BUSY_ACTIVITY = new Set([\n 'sending',\n 'waiting',\n 'streaming',\n 'running',\n 'compacting',\n 'stalled',\n 'recovering',\n 'aborting',\n]);\n\n/** Compact token counts (aligned with pi coding-agent footer). */\nexport function formatTokens(count: number): string {\n if (count < 1000) return count.toString();\n if (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n if (count < 1_000_000) return `${Math.round(count / 1000)}k`;\n if (count < 10_000_000) return `${(count / 1_000_000).toFixed(1)}M`;\n return `${Math.round(count / 1_000_000)}M`;\n}\n\nexport function sanitizeStatusText(text: string): string {\n return text\n .replace(/[\\r\\n\\t]/g, ' ')\n .replace(/ +/g, ' ')\n .trim();\n}\n\nexport function formatQueuedMessageLines(\n state: TuiState,\n width: number,\n dequeueHint: string,\n): string[] {\n const lines: string[] = [];\n const add = (label: string, text: string) => {\n const sanitized = sanitizeStatusText(text);\n if (!sanitized) return;\n lines.push(\n truncateToWidth(theme.dim(`${label}: ${sanitized}`), width, theme.dim('…')),\n );\n };\n\n for (const message of state.steeringQueue) {\n add('Steering', message);\n }\n for (const message of state.messageFollowUpQueue) {\n add('Follow-up', message);\n }\n for (const message of state.compactionQueue) {\n add('Queued', message);\n }\n if (lines.length > 0) {\n lines.push(\n truncateToWidth(theme.dim(`↳ ${dequeueHint} to edit all queued messages`), width, theme.dim('…')),\n );\n }\n return lines;\n}\n\nexport function formatCwdForFooter(cwd: string, home: string | undefined): string {\n if (!home) return cwd;\n\n const resolvedCwd = resolve(cwd);\n const resolvedHome = resolve(home);\n const relativeToHome = relative(resolvedHome, resolvedCwd);\n const isInsideHome =\n relativeToHome === '' ||\n (relativeToHome !== '..' &&\n !relativeToHome.startsWith(`..${sep}`) &&\n !isAbsolute(relativeToHome));\n\n if (!isInsideHome) return cwd;\n return relativeToHome === '' ? '~' : `~${sep}${relativeToHome}`;\n}\n\nfunction shortenPath(cwd: string): string {\n const formatted = formatCwdForFooter(cwd, process.env.HOME || process.env.USERPROFILE);\n if (formatted !== cwd) return formatted;\n return cwd;\n}\n\n/**\n * Multi-line footer below the input editor (pi coding-agent style):\n * cwd · session, then a single padded row: status/tokens on the left, model on the right.\n */\nexport class TuiBottomBar implements Component {\n private extensionLines: string[] = [];\n private extensionComponents: Component[] = [];\n private extensionStatusParts: string[] = [];\n private customComponent: Component | undefined;\n\n constructor(\n private readonly getState: () => TuiState,\n private readonly getThinkingDefault: () => string | undefined,\n private readonly getDequeueHint: () => string = () => 'Alt+Up',\n ) {}\n\n setExtensionLines(lines: string[]): void {\n this.extensionLines = lines;\n }\n\n setExtensionComponents(components: Component[]): void {\n this.extensionComponents = components;\n }\n\n setExtensionStatusParts(parts: string[]): void {\n this.extensionStatusParts = parts;\n }\n\n setCustomComponent(component: Component | undefined): void {\n this.customComponent = component;\n }\n\n invalidate(): void {}\n\n render(width: number): string[] {\n if (this.customComponent) {\n const rendered = this.customComponent.render(width);\n return rendered.map((line) => truncateToWidth(line, width, theme.dim('…')));\n }\n\n const state = this.getState();\n const cwdRaw = state.sessionInfo.effectiveWorkspacePath;\n const cwdWithBranch = cwdRaw\n ? (() => {\n const cwd = shortenPath(cwdRaw);\n const branch = getGitBranchCached(cwdRaw);\n return branch ? `${cwd} (${branch})` : cwd;\n })()\n : 'workspace loading';\n const sessionLine = state.sessionInfo.displayName ?? `session ${state.currentSessionKey}`;\n const pwdLine = truncateToWidth(\n theme.dim(`${cwdWithBranch} · ${sessionLine}`),\n width,\n theme.dim('…'),\n );\n\n const busy = BUSY_ACTIVITY.has(state.activityStatus);\n const leftParts: string[] = [state.connectionStatus];\n const activeRunStatus = formatActiveRunStatus(state);\n if (activeRunStatus) {\n leftParts.push(activeRunStatus);\n } else if (!busy && state.activityStatus && state.activityStatus !== 'idle') {\n leftParts.push(state.activityStatus);\n }\n if (state.sessionInfo.totalTokens != null) {\n leftParts.push(formatTokens(state.sessionInfo.totalTokens));\n }\n const ctxLabel = formatContextUsageLabel(\n state.sessionInfo.contextUsagePercent ?? null,\n state.sessionInfo.contextWindow ?? null,\n );\n if (ctxLabel) {\n leftParts.push(ctxLabel);\n }\n if (state.isCompacting) {\n leftParts.push('compact…');\n } else if (state.compactionQueue.length > 0) {\n leftParts.push(`C${state.compactionQueue.length}`);\n }\n if (state.messageFollowUpQueue.length > 0) {\n leftParts.push(`Q${state.messageFollowUpQueue.length}`);\n }\n if (state.steeringQueue.length > 0) {\n leftParts.push(`S${state.steeringQueue.length}`);\n }\n let statsLeft = leftParts.join(' · ');\n\n const modelId = state.sessionInfo.model ?? 'unknown';\n const prov = state.sessionInfo.modelProvider;\n const thinkingHint = state.showThinking\n ? `thinking:${this.getThinkingDefault() ?? 'on'}`\n : 'thinking:off';\n let rightSide = prov ? `(${prov}) ${modelId}` : modelId;\n rightSide = `${rightSide} • ${thinkingHint}`;\n\n const minPadding = 2;\n let statsLeftWidth = visibleWidth(statsLeft);\n if (statsLeftWidth > width) {\n statsLeft = truncateToWidth(statsLeft, width, '…');\n statsLeftWidth = visibleWidth(statsLeft);\n }\n\n const rightWidth = visibleWidth(rightSide);\n const totalNeeded = statsLeftWidth + minPadding + rightWidth;\n\n let statsLine: string;\n if (totalNeeded <= width) {\n const padding = ' '.repeat(width - statsLeftWidth - rightWidth);\n statsLine = statsLeft + padding + rightSide;\n } else {\n const availableForRight = width - statsLeftWidth - minPadding;\n if (availableForRight > 0) {\n const truncatedRight = truncateToWidth(rightSide, availableForRight, '');\n const tw = visibleWidth(truncatedRight);\n const padding = ' '.repeat(Math.max(0, width - statsLeftWidth - tw));\n statsLine = statsLeft + padding + truncatedRight;\n } else {\n statsLine = statsLeft;\n }\n }\n\n const statsDimmed = theme.dim(statsLine);\n const lines = [pwdLine, statsDimmed];\n if (this.extensionStatusParts.length > 0) {\n const statusLine = this.extensionStatusParts\n .map((part) => sanitizeStatusText(part))\n .filter(Boolean)\n .join(' ');\n if (statusLine) {\n lines.push(truncateToWidth(theme.dim(statusLine), width, theme.dim('…')));\n }\n }\n lines.push(...formatQueuedMessageLines(state, width, this.getDequeueHint()));\n for (const extLine of this.extensionLines) {\n lines.push(truncateToWidth(theme.dim(sanitizeStatusText(extLine)), width, theme.dim('…')));\n }\n for (const component of this.extensionComponents) {\n for (const line of component.render(width)) {\n lines.push(truncateToWidth(line, width, theme.dim('…')));\n }\n }\n return lines;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ClientHistoryMessage } from '../session/client-history.js';
|
|
2
|
+
import type { SessionTimelineItem } from '../session/transcript-outline.js';
|
|
2
3
|
import type { ExportFormat } from '../session/types.js';
|
|
3
4
|
import type { ReviewContext } from '../review/review-git.js';
|
|
4
5
|
import type { SessionInfo, TuiEventSource } from './tui-types.js';
|
|
@@ -62,6 +63,12 @@ export interface TuiSessionStats {
|
|
|
62
63
|
total: number;
|
|
63
64
|
};
|
|
64
65
|
}
|
|
66
|
+
export interface TuiHistoryWindow {
|
|
67
|
+
messages: HistoryMessage[];
|
|
68
|
+
startRowNumber: number;
|
|
69
|
+
endRowNumber: number;
|
|
70
|
+
totalRows: number;
|
|
71
|
+
}
|
|
65
72
|
export type TuiExportFormat = ExportFormat | 'html';
|
|
66
73
|
export interface TuiCompactionResult {
|
|
67
74
|
compacted: boolean;
|
|
@@ -223,8 +230,17 @@ export interface TuiBackend {
|
|
|
223
230
|
}): Promise<{
|
|
224
231
|
messages: HistoryMessage[];
|
|
225
232
|
}>;
|
|
233
|
+
/** Load a bounded transcript window around a persisted row number. */
|
|
234
|
+
loadHistoryWindow?(opts: {
|
|
235
|
+
sessionKey: string;
|
|
236
|
+
rowNumber: number;
|
|
237
|
+
before?: number;
|
|
238
|
+
after?: number;
|
|
239
|
+
}): Promise<TuiHistoryWindow>;
|
|
226
240
|
/** Load current transcript rows as a tree-shaped list. */
|
|
227
241
|
loadTranscriptTree(sessionKey: string): Promise<TuiTranscriptTreeEntry[]>;
|
|
242
|
+
/** Load current transcript rows as timeline items for turn navigation. */
|
|
243
|
+
loadTimeline(sessionKey: string): Promise<SessionTimelineItem[]>;
|
|
228
244
|
/** Compute transcript message/token statistics. */
|
|
229
245
|
getSessionStats(sessionKey: string): Promise<TuiSessionStats>;
|
|
230
246
|
/** List sessions. */
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { parseAgentSessionKey } from "../routing/session-key-utils.js";
|
|
2
|
-
import { init_agent_session_key } from "../routing/agent-session-key.js";
|
|
3
1
|
import { getLogDir } from "../utils/logger/config.js";
|
|
4
2
|
import { getRuntimeLogStats } from "../utils/logger/stats.js";
|
|
5
3
|
import { init_logger } from "../utils/logger.js";
|
|
4
|
+
import { parseAgentSessionKey } from "../routing/session-key-utils.js";
|
|
5
|
+
import { init_agent_session_key } from "../routing/agent-session-key.js";
|
|
6
6
|
import { resolveConfigPath } from "../config/paths.js";
|
|
7
7
|
import { getProviderDisplayName, getSortedProviders, init_providers, providerSupportsApiKey, providerSupportsOAuth } from "../providers/index.js";
|
|
8
8
|
import { createWorkflowCatalog } from "../agent/workflow/catalog.js";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { KeybindingsManager, TUI } from '@earendil-works/pi-tui';
|
|
2
2
|
import type { TuiCompactionResult, TuiModelChoice, TuiShareRequest, TuiSessionStats, TuiSessionItem, TuiStartupResources, TuiTranscriptTreeEntry, TuiAgentInfo } from './tui-backend.js';
|
|
3
3
|
import type { ChatLog } from './components/chat-log.js';
|
|
4
|
+
import type { SessionTimelineItem } from '../session/transcript-outline.js';
|
|
4
5
|
import { type TuiHotkeyExtensionShortcut } from './format-tui-hotkeys.js';
|
|
5
6
|
import type { TuiState } from './tui-types.js';
|
|
6
7
|
import { type ReasoningLevel, type ThinkLevel, type VerboseLevel } from '../agent/transcript/thinking-types.js';
|
|
@@ -37,6 +38,7 @@ export type CommandHandlerDeps = {
|
|
|
37
38
|
openSessionPicker: () => void;
|
|
38
39
|
openSessionTree: () => void;
|
|
39
40
|
openTranscriptTree: () => void;
|
|
41
|
+
openTimeline: (initialSearch?: string) => void;
|
|
40
42
|
openUserMessageFork: () => void;
|
|
41
43
|
openScopedModels: () => void;
|
|
42
44
|
openThinkingSelector: () => void;
|
|
@@ -63,6 +65,13 @@ export type CommandHandlerDeps = {
|
|
|
63
65
|
getSessionStats?: () => TuiSessionStats | Promise<TuiSessionStats>;
|
|
64
66
|
getStartupResources?: () => TuiStartupResources | undefined;
|
|
65
67
|
loadTranscriptTree?: () => TuiTranscriptTreeEntry[] | Promise<TuiTranscriptTreeEntry[]>;
|
|
68
|
+
loadTimeline?: () => SessionTimelineItem[] | Promise<SessionTimelineItem[]>;
|
|
69
|
+
loadHistoryWindow?: (opts: {
|
|
70
|
+
rowNumber: number;
|
|
71
|
+
before?: number;
|
|
72
|
+
after?: number;
|
|
73
|
+
}) => boolean | Promise<boolean>;
|
|
74
|
+
loadSessionHistory?: () => void | Promise<void>;
|
|
66
75
|
exportSession?: (request: TuiExportRequest) => void | Promise<void>;
|
|
67
76
|
importSession?: (request: TuiImportRequest) => void | Promise<void>;
|
|
68
77
|
createShare?: (request: TuiShareRequest) => void | Promise<void>;
|
|
@@ -1,24 +1,26 @@
|
|
|
1
|
+
import { closeXopcDatabase, isXopcDatabaseOpen, openXopcDatabase } from "../storage/sqlite/connection.js";
|
|
1
2
|
import { parseAgentSessionKey } from "../routing/session-key-utils.js";
|
|
2
3
|
import { init_agent_session_key, isValidAgentId, normalizeAgentId } from "../routing/agent-session-key.js";
|
|
4
|
+
import { getSessionMetadata } from "../storage/sqlite/session-repository.js";
|
|
5
|
+
import "../storage/sqlite/index.js";
|
|
3
6
|
import { resolveConfigPath } from "../config/paths.js";
|
|
4
7
|
import { loadConfig } from "../config/loader.js";
|
|
5
8
|
import { init_providers, providerSupportsOAuth } from "../providers/index.js";
|
|
6
|
-
import { closeXopcDatabase, isXopcDatabaseOpen, openXopcDatabase } from "../storage/sqlite/connection.js";
|
|
7
9
|
import { GoalService } from "../goals/goal-service.js";
|
|
8
10
|
import "../goals/index.js";
|
|
9
|
-
import { getSessionMetadata } from "../storage/sqlite/session-repository.js";
|
|
10
|
-
import "../storage/sqlite/index.js";
|
|
11
11
|
import { createWorkflowCatalog } from "../agent/workflow/catalog.js";
|
|
12
|
-
import { normalizeReasoningLevel, normalizeThinkLevel, normalizeVerboseLevel } from "../agent/transcript/thinking-types.js";
|
|
13
|
-
import { provenanceTracker } from "../extensions/security.js";
|
|
14
|
-
import "../config/index.js";
|
|
15
12
|
import { ProjectService } from "../projects/project-service.js";
|
|
16
13
|
import { isValidProjectAgentId, normalizeProjectAgentId } from "../projects/project-agent.js";
|
|
17
14
|
import { inferSuggestedProjectDefaultAgentId } from "../projects/project-agent-suggestion.js";
|
|
18
15
|
import "../projects/index.js";
|
|
16
|
+
import { normalizeReasoningLevel, normalizeThinkLevel, normalizeVerboseLevel } from "../agent/transcript/thinking-types.js";
|
|
17
|
+
import { provenanceTracker } from "../extensions/security.js";
|
|
18
|
+
import "../config/index.js";
|
|
19
|
+
import { theme } from "./theme.js";
|
|
19
20
|
import { getTuiKeybindingsPath } from "./tui-keybindings-file.js";
|
|
20
21
|
import { formatKeyIds, formatXopcTuiHotkeys } from "./format-tui-hotkeys.js";
|
|
21
22
|
import { formatTuiConfigInfo, formatTuiContextInfo, formatTuiLoginInfo, formatTuiModelsInfo, formatTuiSessionInfo, formatTuiSessionListInfo, formatTuiSessionTreeInfo, formatTuiStoredAuthProfilesInfo, formatTuiTranscriptTreeInfo, formatTuiTrustInfo, formatTuiUsageInfo, formatTuiWorkflowDetail, formatTuiWorkflowsInfo, loadTuiChangelogInfo, nextVerboseLevel, parseTuiExportRequest, parseTuiImportRequest, parseTuiShareRequest, writeTuiDebugInfo } from "./tui-command-formatters.js";
|
|
23
|
+
import { buildTuiTimelineTurns, findNearestTimelineTurnByDisplayIndex, findTimelineTurnByNumber } from "./tui-timeline.js";
|
|
22
24
|
import { getAuthStorePath, listAllProfiles, listProfilesForProvider, removeAuthProfile } from "../auth/profiles/profiles.js";
|
|
23
25
|
import { rewriteUnknownSlashAsWorkflow } from "./tui-workflow-slash.js";
|
|
24
26
|
import { formatTuiStartupText } from "./tui-startup-text.js";
|
|
@@ -160,6 +162,10 @@ function getSlashCommands(_isLocal, keybindings) {
|
|
|
160
162
|
name: "tree",
|
|
161
163
|
description: "Show grouped session tree"
|
|
162
164
|
},
|
|
165
|
+
{
|
|
166
|
+
name: "timeline",
|
|
167
|
+
description: "Jump to a previous turn in the current session"
|
|
168
|
+
},
|
|
163
169
|
{
|
|
164
170
|
name: "scoped-models",
|
|
165
171
|
description: `Choose models for ${modelCycleKey} cycling`
|
|
@@ -332,6 +338,82 @@ function defaultAuthProfiles() {
|
|
|
332
338
|
getStorePath: () => getAuthStorePath()
|
|
333
339
|
};
|
|
334
340
|
}
|
|
341
|
+
function timelineUsage() {
|
|
342
|
+
return ["Usage: /timeline [turn|latest|prev|next|search <text>]", "Examples: /timeline, /timeline 12, /timeline prev, /timeline search deploy"].join("\n");
|
|
343
|
+
}
|
|
344
|
+
function currentTimelineTurnIndex(turns, chatLog) {
|
|
345
|
+
const viewState = chatLog.getTimelineViewportState();
|
|
346
|
+
if (viewState.mode === "history") {
|
|
347
|
+
const current = findNearestTimelineTurnByDisplayIndex(turns, viewState.displayIndex);
|
|
348
|
+
const index = current ? turns.findIndex((turn) => turn.id === current.id) : -1;
|
|
349
|
+
return index >= 0 ? index : turns.length - 1;
|
|
350
|
+
}
|
|
351
|
+
return turns.length - 1;
|
|
352
|
+
}
|
|
353
|
+
async function runTimelineCommand(commandArgs, deps) {
|
|
354
|
+
const raw = commandArgs.trim();
|
|
355
|
+
if (!raw) {
|
|
356
|
+
if (deps.uiOverlays?.openTimeline) deps.uiOverlays.openTimeline();
|
|
357
|
+
else {
|
|
358
|
+
deps.chatLog.addSystem("Timeline picker is not available in this mode.");
|
|
359
|
+
deps.tui.requestRender();
|
|
360
|
+
}
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
const [subcommandRaw, ...rest] = raw.split(/\s+/);
|
|
364
|
+
const subcommand = (subcommandRaw ?? "").toLowerCase();
|
|
365
|
+
if (subcommand === "search" || subcommand === "find") {
|
|
366
|
+
if (deps.uiOverlays?.openTimeline) deps.uiOverlays.openTimeline(rest.join(" ").trim());
|
|
367
|
+
else {
|
|
368
|
+
deps.chatLog.addSystem("Timeline picker is not available in this mode.");
|
|
369
|
+
deps.tui.requestRender();
|
|
370
|
+
}
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
if (subcommand === "latest" || subcommand === "live" || subcommand === "end") {
|
|
374
|
+
await deps.loadSessionHistory?.();
|
|
375
|
+
deps.chatLog.jumpToLatest();
|
|
376
|
+
deps.chatLog.addSystem(theme.dim("Returned to latest transcript view."));
|
|
377
|
+
deps.tui.requestRender();
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
if (!deps.loadTimeline) {
|
|
381
|
+
deps.chatLog.addSystem("Timeline is not available in this mode.");
|
|
382
|
+
deps.tui.requestRender();
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
const turns = buildTuiTimelineTurns(await Promise.resolve(deps.loadTimeline()));
|
|
386
|
+
if (turns.length === 0) {
|
|
387
|
+
deps.chatLog.addSystem("No timeline turns found.");
|
|
388
|
+
deps.tui.requestRender();
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
let target;
|
|
392
|
+
if (subcommand === "prev" || subcommand === "previous") target = turns[Math.max(0, currentTimelineTurnIndex(turns, deps.chatLog) - 1)];
|
|
393
|
+
else if (subcommand === "next") target = turns[Math.min(turns.length - 1, currentTimelineTurnIndex(turns, deps.chatLog) + 1)];
|
|
394
|
+
else {
|
|
395
|
+
const turnNumber = Number.parseInt(subcommand, 10);
|
|
396
|
+
if (!Number.isFinite(turnNumber) || String(turnNumber) !== subcommand) {
|
|
397
|
+
deps.chatLog.addSystem(timelineUsage());
|
|
398
|
+
deps.tui.requestRender();
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
target = findTimelineTurnByNumber(turns, turnNumber);
|
|
402
|
+
}
|
|
403
|
+
if (!target) {
|
|
404
|
+
deps.chatLog.addSystem(`Timeline turn not found: ${raw}`);
|
|
405
|
+
deps.tui.requestRender();
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if (!deps.chatLog.jumpToDisplayIndex(target.displayIndex)) {
|
|
409
|
+
if ((target.rowNumber !== void 0 && deps.loadHistoryWindow ? await deps.loadHistoryWindow({ rowNumber: target.rowNumber }) : false) && deps.chatLog.jumpToDisplayIndex(target.displayIndex)) {
|
|
410
|
+
deps.tui.requestRender();
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
deps.chatLog.addSystem(`Turn ${target.turn} is outside loaded history.`);
|
|
414
|
+
}
|
|
415
|
+
deps.tui.requestRender();
|
|
416
|
+
}
|
|
335
417
|
function formatAgentsList(agents, currentAgentId) {
|
|
336
418
|
if (agents.length === 0) return "No agents available.";
|
|
337
419
|
const current = currentAgentId?.trim().toLowerCase();
|
|
@@ -910,6 +992,13 @@ function createTuiCommandHandler(deps) {
|
|
|
910
992
|
tui.requestRender();
|
|
911
993
|
});
|
|
912
994
|
return;
|
|
995
|
+
case "timeline":
|
|
996
|
+
runTimelineCommand(commandArgs, deps).catch((err) => {
|
|
997
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
998
|
+
chatLog.addSystem(`Timeline failed: ${errorMessage}`);
|
|
999
|
+
tui.requestRender();
|
|
1000
|
+
});
|
|
1001
|
+
return;
|
|
913
1002
|
case "switch": {
|
|
914
1003
|
const modelRef = commandArgs.trim();
|
|
915
1004
|
if (!modelRef) {
|