@xopcai/xopc 0.0.124 → 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/Combination-BzaXOLd9.js +41 -0
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-B5uSVAyJ.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-D9-HW6cy.js +1 -0
- package/dist/gateway/static/root/assets/appearance-settings-BHlahIDL.js +1 -0
- package/dist/gateway/static/root/assets/apps-page-BdJ1eQg3.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-CXUGRp2i.js → archive-plugin-B-aoIt0w.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-Cmiub3Wg.js → attachment-load-BD0G0FD5.js} +1 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-iJRVI7aZ.js +1 -0
- package/dist/gateway/static/root/assets/automations-page-D8hYQbkl.js +4 -0
- package/dist/gateway/static/root/assets/{binary-plugins-0Izz-N3p.js → binary-plugins-B0mNlVSz.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-C1Kv0IkJ.js → block-editor-CJY9Lu5G.js} +3 -3
- package/dist/gateway/static/root/assets/browser-settings-page-CiWEO-Iy.js +8 -0
- package/dist/gateway/static/root/assets/capability-presets-api-Bgc8ag55.js +1 -0
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-B1nIi0TC.js +1 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-BeA2aVor.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/code-editor-gbRgS14t.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-2rjzUu57.js → directory-picker-path-field-CiEc4KmY.js} +1 -1
- package/dist/gateway/static/root/assets/dist-By6Rh2ee.js +1 -0
- package/dist/gateway/static/root/assets/dist-CkobR7mk.js +1 -0
- package/dist/gateway/static/root/assets/dist-DokQNVMQ.js +1 -0
- package/dist/gateway/static/root/assets/dreaming-settings-4bvpk5wr.js +3 -0
- package/dist/gateway/static/root/assets/extension-debug-page-BbyczVZ3.js +1 -0
- package/dist/gateway/static/root/assets/extension-page-DLN1I3DR.js +1 -0
- package/dist/gateway/static/root/assets/extension-settings-page-D9VGHmYJ.js +1 -0
- package/dist/gateway/static/root/assets/{fetch-BU5S0Sn7.js → fetch-5V96dUz3.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-BIPGwrl1.js → gateway-config-api-BtIzObwp.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-KFsGGDhg.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-Cd0Zz30N.js → gateway-startup-retry-DEMad2wt.js} +1 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-4PcF6Sh6.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-B482PSaG.js +1 -0
- package/dist/gateway/static/root/assets/{goals-config-api-B95KdGMj.js → goals-config-api-CVN7-pdM.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-CUdgJuDn.js +2 -0
- package/dist/gateway/static/root/assets/goals-settings-IYCH3-Pi.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-Cf_a2Bmz.js +1 -0
- package/dist/gateway/static/root/assets/{html-workspace-editor-CQLWDiwE.js → html-workspace-editor-DV90ddkE.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-lKTg6St7.js +1 -0
- package/dist/gateway/static/root/assets/logs-page-BCporcNH.js +2 -0
- package/dist/gateway/static/root/assets/{markdown-editor-AssmZFx4.js → markdown-editor-BFOjBBla.js} +2 -2
- package/dist/gateway/static/root/assets/markdown-split-Bv4k6iGJ.js +1 -0
- package/dist/gateway/static/root/assets/{media-plugins-BhIQU5yS.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-Cp395RYD.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-DGzet1d7.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-Cqgb-jqa.js → save-bar-controls-BItmzAzI.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-DVZcI8Yt.js → schedule-field-BQ8IjjCn.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-Bj7sOxC8.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-BmXn-8N6.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-IB1v8i86.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-BxQ384RC.js → system-settings-panel-DKDAojWM.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-BkcpvFYO.js → typed-models-lib-BCCV4Kkp.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-Cd0FaEQ4.js → use-channel-catalog-NBqg3iFY.js} +1 -1
- package/dist/gateway/static/root/assets/{user-profile-settings-panel-DQ7NnRSY.js → user-profile-settings-panel-suQ2x-LB.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-YKhVf7Ka.js → utils-DPGVr3tS.js} +1 -1
- package/dist/gateway/static/root/assets/{vendor-codemirror-CNP1wPe7.js → vendor-codemirror-BvNgyE1Q.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-BrCZpAWh.js +1 -0
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-BTkRVNAh.js +3 -0
- package/dist/gateway/static/root/assets/{workflow-start-dialog-BNJVCWoS.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 +8 -7
- 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 +12 -5
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/child-agent-factory.d.ts +2 -0
- package/dist/src/agent/child-agent-factory.js +2 -0
- package/dist/src/agent/child-agent-factory.js.map +1 -1
- package/dist/src/agent/coding/index.d.ts +1 -0
- package/dist/src/agent/coding/index.js +2 -0
- package/dist/src/agent/coding/turn-diff-tracker.d.ts +67 -0
- package/dist/src/agent/coding/turn-diff-tracker.js +233 -0
- package/dist/src/agent/coding/turn-diff-tracker.js.map +1 -0
- 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/dreaming/config.d.ts +2 -2
- package/dist/src/agent/memory/dreaming/config.js +3 -3
- package/dist/src/agent/memory/dreaming/config.js.map +1 -1
- package/dist/src/agent/memory/dreaming/constants.d.ts +1 -1
- package/dist/src/agent/memory/dreaming/constants.js +1 -1
- package/dist/src/agent/memory/dreaming/constants.js.map +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.d.ts +1 -0
- package/dist/src/agent/memory/dreaming/deep-promotion.js +11 -20
- package/dist/src/agent/memory/dreaming/deep-promotion.js.map +1 -1
- package/dist/src/agent/memory/dreaming/events.d.ts +3 -3
- package/dist/src/agent/memory/dreaming/events.js +6 -6
- package/dist/src/agent/memory/dreaming/events.js.map +1 -1
- package/dist/src/agent/memory/dreaming/last-run.d.ts +2 -2
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js.map +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.d.ts +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +3 -3
- package/dist/src/agent/memory/dreaming/light-sweep.js.map +1 -1
- package/dist/src/agent/memory/dreaming/preview.d.ts +1 -0
- package/dist/src/agent/memory/dreaming/preview.js +2 -2
- package/dist/src/agent/memory/dreaming/preview.js.map +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.d.ts +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +13 -13
- package/dist/src/agent/memory/dreaming/rem-patterns.js.map +1 -1
- package/dist/src/agent/memory/dreaming/scope.d.ts +14 -0
- package/dist/src/agent/memory/dreaming/scope.js +27 -0
- package/dist/src/agent/memory/dreaming/scope.js.map +1 -0
- package/dist/src/agent/memory/dreaming/short-term-store.d.ts +4 -4
- package/dist/src/agent/memory/dreaming/short-term-store.js +17 -17
- package/dist/src/agent/memory/dreaming/short-term-store.js.map +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-event-handler.d.ts +2 -0
- package/dist/src/agent/orchestration/agent-event-handler.js +13 -0
- package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js +22 -12
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/sandbox/command-validator.js +12 -0
- package/dist/src/agent/sandbox/command-validator.js.map +1 -1
- package/dist/src/agent/service.d.ts +2 -1
- package/dist/src/agent/service.js +24 -9
- 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.d.ts +5 -3
- package/dist/src/agent/session/session-inspector.js +17 -8
- package/dist/src/agent/session/session-inspector.js.map +1 -1
- package/dist/src/agent/skills/hub-pull.js +1 -1
- package/dist/src/agent/source-context/types.d.ts +1 -1
- package/dist/src/agent/source-context/types.js +1 -1
- package/dist/src/agent/source-context/types.js.map +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/apply-patch.js +116 -62
- package/dist/src/agent/tools/apply-patch.js.map +1 -1
- package/dist/src/agent/tools/concurrency.d.ts +8 -0
- package/dist/src/agent/tools/concurrency.js +31 -0
- package/dist/src/agent/tools/concurrency.js.map +1 -0
- package/dist/src/agent/tools/dreaming-tool.d.ts +2 -0
- package/dist/src/agent/tools/dreaming-tool.js +13 -10
- package/dist/src/agent/tools/dreaming-tool.js.map +1 -1
- package/dist/src/agent/tools/exec-command.js +4 -0
- package/dist/src/agent/tools/exec-command.js.map +1 -1
- package/dist/src/agent/tools/executor.d.ts +6 -4
- package/dist/src/agent/tools/executor.js +7 -4
- package/dist/src/agent/tools/executor.js.map +1 -1
- package/dist/src/agent/tools/factory.d.ts +10 -0
- package/dist/src/agent/tools/factory.js +16 -1
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/find.js +2 -0
- package/dist/src/agent/tools/find.js.map +1 -1
- package/dist/src/agent/tools/goal-tool.js +2 -2
- package/dist/src/agent/tools/grep.js +2 -0
- package/dist/src/agent/tools/grep.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +3 -0
- package/dist/src/agent/tools/index.js +4 -1
- package/dist/src/agent/tools/list-dir.js +2 -0
- package/dist/src/agent/tools/list-dir.js.map +1 -1
- package/dist/src/agent/tools/memory-tool.d.ts +1 -0
- package/dist/src/agent/tools/memory-tool.js +2 -2
- package/dist/src/agent/tools/memory-tool.js.map +1 -1
- package/dist/src/agent/tools/metadata.d.ts +15 -0
- package/dist/src/agent/tools/metadata.js +26 -0
- package/dist/src/agent/tools/metadata.js.map +1 -0
- package/dist/src/agent/tools/read.js +2 -0
- package/dist/src/agent/tools/read.js.map +1 -1
- package/dist/src/agent/tools/workflow-tool.js +1 -1
- package/dist/src/agent/tools/write.js +6 -0
- package/dist/src/agent/tools/write.js.map +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/workflow/subagent-runner.d.ts +1 -0
- package/dist/src/agent/workflow/subagent-runner.js +5 -1
- package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
- package/dist/src/agent/workflow/workflow-child-tools.js +5 -0
- package/dist/src/agent/workflow/workflow-child-tools.js.map +1 -1
- 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/connectors/health.d.ts +2 -1
- package/dist/src/connectors/health.js +59 -1
- package/dist/src/connectors/health.js.map +1 -1
- package/dist/src/connectors/install.d.ts +1 -0
- package/dist/src/connectors/install.js +28 -1
- package/dist/src/connectors/install.js.map +1 -1
- package/dist/src/connectors/instances.js +7 -0
- package/dist/src/connectors/instances.js.map +1 -1
- package/dist/src/connectors/materialize.js +2 -1
- package/dist/src/connectors/materialize.js.map +1 -1
- package/dist/src/connectors/registries/modelscope.js +38 -13
- package/dist/src/connectors/registries/modelscope.js.map +1 -1
- package/dist/src/connectors/types.d.ts +2 -0
- 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/dreaming-automation-reconciler.d.ts +1 -0
- package/dist/src/gateway/dreaming-automation-reconciler.js +62 -42
- package/dist/src/gateway/dreaming-automation-reconciler.js.map +1 -1
- package/dist/src/gateway/hono/app.js +7 -1
- package/dist/src/gateway/hono/app.js.map +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/connectors.js +46 -2
- package/dist/src/gateway/hono/routes/connectors.js.map +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +111 -66
- package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
- 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 +903 -50
- package/dist/src/gateway/hono/routes/projects.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +102 -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 +28 -16
- 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/media/store.js +1 -1
- package/dist/src/media/store.js.map +1 -1
- package/dist/src/media/types.d.ts +1 -1
- package/dist/src/media/uri.js +2 -1
- package/dist/src/media/uri.js.map +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-context-for-llm.d.ts +2 -0
- package/dist/src/session/session-context-for-llm.js +14 -1
- package/dist/src/session/session-context-for-llm.js.map +1 -1
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/store.js +3 -3
- package/dist/src/session/store.js.map +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/022_work_items.sql +61 -0
- package/dist/src/storage/sqlite/migrations/023_work_item_attachments.sql +15 -0
- 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 +141 -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/assistant-message.js +12 -2
- package/dist/src/tui/components/assistant-message.js.map +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/tool-execution.d.ts +8 -0
- package/dist/src/tui/components/tool-execution.js +87 -77
- package/dist/src/tui/components/tool-execution.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/components/visual-truncate.d.ts +1 -0
- package/dist/src/tui/components/visual-truncate.js +28 -1
- package/dist/src/tui/components/visual-truncate.js.map +1 -1
- package/dist/src/tui/tool-summary.d.ts +22 -0
- package/dist/src/tui/tool-summary.js +212 -0
- package/dist/src/tui/tool-summary.js.map +1 -0
- 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-tool-diff.d.ts +15 -0
- package/dist/src/tui/tui-tool-diff.js +178 -7
- package/dist/src/tui/tui-tool-diff.js.map +1 -1
- 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 +7 -0
- package/dist/src/work-items/agent-context.js +75 -0
- package/dist/src/work-items/agent-context.js.map +1 -0
- package/dist/src/work-items/index.d.ts +4 -0
- package/dist/src/work-items/index.js +4 -0
- package/dist/src/work-items/types.d.ts +112 -0
- package/dist/src/work-items/types.js +1 -0
- package/dist/src/work-items/work-item-service.d.ts +35 -0
- package/dist/src/work-items/work-item-service.js +277 -0
- package/dist/src/work-items/work-item-service.js.map +1 -0
- package/dist/src/work-items/work-item-store.d.ts +21 -0
- package/dist/src/work-items/work-item-store.js +302 -0
- package/dist/src/work-items/work-item-store.js.map +1 -0
- package/dist/src/workflows/draft/workflow-draft-service.js +1 -1
- package/dist/src/workflows/service/workflow-run-service.js +4 -3
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-session-bridge.js +4 -1
- package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
- package/package.json +5 -5
- package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +0 -41
- package/dist/gateway/static/root/assets/agents-BjIxt67Z.js +0 -2
- package/dist/gateway/static/root/assets/app-management-settings-panel-CYCONLIL.js +0 -1
- package/dist/gateway/static/root/assets/appearance-settings-Clw3ryKg.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-QICTeGjX.js +0 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-CU0-4nQ-.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-Car-jtiz.js +0 -1
- package/dist/gateway/static/root/assets/browser-settings-page-CMeBJzlS.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-api-BmQTM9Il.js +0 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-DZEJEoCF.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-kkW-xFau.js +0 -1
- package/dist/gateway/static/root/assets/code-editor-dZTY2dRW.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-BvaQvO5F.js +0 -2
- package/dist/gateway/static/root/assets/dist-Mys7eFJ5.js +0 -1
- package/dist/gateway/static/root/assets/dist-wO9a2_ID.js +0 -1
- package/dist/gateway/static/root/assets/dreaming-settings-DnHO686d.js +0 -1
- package/dist/gateway/static/root/assets/extension-debug-page-BGLRuWVN.js +0 -1
- package/dist/gateway/static/root/assets/extension-page-D978ePp9.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-B6Ih4Swx.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-CMEA3r5u.js +0 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-B-KHKeXN.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-BxrSoWdj.js +0 -1
- package/dist/gateway/static/root/assets/goals-page-BTJzIl28.js +0 -2
- package/dist/gateway/static/root/assets/goals-settings-BJyEuLLm.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-wkOjYNQT.js +0 -1
- package/dist/gateway/static/root/assets/index-BLaXr6Ev.css +0 -1
- package/dist/gateway/static/root/assets/index-c_9TVr_C.js +0 -191
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-BT8T4DyC.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-CrxBJUgI.js +0 -2
- package/dist/gateway/static/root/assets/markdown-split-Dv66bO2b.js +0 -1
- package/dist/gateway/static/root/assets/messages-O6TAtdFC.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-DOOpz6y1.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-Br16pK9v.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-PSJAi0ZC.js +0 -2
- package/dist/gateway/static/root/assets/project-detail-page-CIGGgKuw.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-B2grhsBt.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CXMORxBD.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-Bi2wkBzU.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-B1L3G4IA.js +0 -1
- package/dist/gateway/static/root/assets/settings-form-section-BnqYMWHR.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-BfRSHJmO.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-layout-CdWZU1hd.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-CWtPM7RK.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-ngbsBgij.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BIe442Gv.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-BfchZRVa.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-C5Ov8Uk_.js +0 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-BYD9BtOq.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-BYF29ANm.js +0 -18
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SessionTimelineItem } from '../session/transcript-outline.js';
|
|
2
|
+
export interface TuiTimelineTurn {
|
|
3
|
+
id: string;
|
|
4
|
+
turn: number;
|
|
5
|
+
displayIndex: number;
|
|
6
|
+
rowNumber?: number;
|
|
7
|
+
preview: string;
|
|
8
|
+
timestamp?: number;
|
|
9
|
+
toolCount: number;
|
|
10
|
+
running: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function buildTuiTimelineTurns(items: readonly SessionTimelineItem[]): TuiTimelineTurn[];
|
|
13
|
+
export declare function findTimelineTurnByNumber(turns: readonly TuiTimelineTurn[], turnNumber: number): TuiTimelineTurn | undefined;
|
|
14
|
+
export declare function findNearestTimelineTurnByDisplayIndex(turns: readonly TuiTimelineTurn[], displayIndex: number): TuiTimelineTurn | undefined;
|
|
15
|
+
export declare function formatTimelineToolSummary(toolCount: number): string;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
//#region src/tui/tui-timeline.ts
|
|
2
|
+
function compactText(text, max = 72) {
|
|
3
|
+
const normalized = text.replace(/\s+/g, " ").trim();
|
|
4
|
+
if (normalized.length <= max) return normalized;
|
|
5
|
+
return `${normalized.slice(0, Math.max(0, max - 3)).trimEnd()}...`;
|
|
6
|
+
}
|
|
7
|
+
function buildTuiTimelineTurns(items) {
|
|
8
|
+
const turns = [];
|
|
9
|
+
let current = null;
|
|
10
|
+
let currentToolKeys = /* @__PURE__ */ new Set();
|
|
11
|
+
let lastDisplayIndex = 0;
|
|
12
|
+
for (const item of items) {
|
|
13
|
+
if (typeof item.displayIndex === "number" && Number.isFinite(item.displayIndex)) lastDisplayIndex = item.displayIndex;
|
|
14
|
+
if (item.kind === "turn" && item.role === "user") {
|
|
15
|
+
const turn = item.turn || turns.length + 1;
|
|
16
|
+
current = {
|
|
17
|
+
id: item.id,
|
|
18
|
+
turn,
|
|
19
|
+
displayIndex: item.displayIndex ?? lastDisplayIndex,
|
|
20
|
+
preview: compactText(item.preview || item.title || "Message"),
|
|
21
|
+
toolCount: 0,
|
|
22
|
+
running: false,
|
|
23
|
+
...item.rowNumber !== void 0 ? { rowNumber: item.rowNumber } : {},
|
|
24
|
+
...item.timestamp !== void 0 ? { timestamp: item.timestamp } : {}
|
|
25
|
+
};
|
|
26
|
+
turns.push(current);
|
|
27
|
+
currentToolKeys = /* @__PURE__ */ new Set();
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (!current) continue;
|
|
31
|
+
if (item.kind === "tool" || item.kind === "file" || item.kind === "command") {
|
|
32
|
+
const key = `${item.id}:${item.meta?.toolName ?? item.title ?? item.kind}`;
|
|
33
|
+
if (currentToolKeys.has(key)) {
|
|
34
|
+
current.running ||= item.status === "running";
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
currentToolKeys.add(key);
|
|
38
|
+
current.toolCount += 1;
|
|
39
|
+
current.running ||= item.status === "running";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return turns;
|
|
43
|
+
}
|
|
44
|
+
function findTimelineTurnByNumber(turns, turnNumber) {
|
|
45
|
+
return turns.find((turn) => turn.turn === turnNumber);
|
|
46
|
+
}
|
|
47
|
+
function findNearestTimelineTurnByDisplayIndex(turns, displayIndex) {
|
|
48
|
+
let selected = turns[0];
|
|
49
|
+
for (const turn of turns) {
|
|
50
|
+
if (turn.displayIndex <= displayIndex) {
|
|
51
|
+
selected = turn;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
return selected;
|
|
57
|
+
}
|
|
58
|
+
function formatTimelineToolSummary(toolCount) {
|
|
59
|
+
if (toolCount <= 0) return "0 tools";
|
|
60
|
+
return `${toolCount} tool${toolCount === 1 ? "" : "s"}`;
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
export { buildTuiTimelineTurns, findNearestTimelineTurnByDisplayIndex, findTimelineTurnByNumber, formatTimelineToolSummary };
|
|
64
|
+
|
|
65
|
+
//# sourceMappingURL=tui-timeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tui-timeline.js","names":[],"sources":["../../../src/tui/tui-timeline.ts"],"sourcesContent":["import type { SessionTimelineItem } from '../session/transcript-outline.js';\n\nexport interface TuiTimelineTurn {\n id: string;\n turn: number;\n displayIndex: number;\n rowNumber?: number;\n preview: string;\n timestamp?: number;\n toolCount: number;\n running: boolean;\n}\n\nfunction compactText(text: string, max = 72): string {\n const normalized = text.replace(/\\s+/g, ' ').trim();\n if (normalized.length <= max) return normalized;\n return `${normalized.slice(0, Math.max(0, max - 3)).trimEnd()}...`;\n}\n\nexport function buildTuiTimelineTurns(items: readonly SessionTimelineItem[]): TuiTimelineTurn[] {\n const turns: TuiTimelineTurn[] = [];\n let current: TuiTimelineTurn | null = null;\n let currentToolKeys = new Set<string>();\n let lastDisplayIndex = 0;\n\n for (const item of items) {\n if (typeof item.displayIndex === 'number' && Number.isFinite(item.displayIndex)) {\n lastDisplayIndex = item.displayIndex;\n }\n\n if (item.kind === 'turn' && item.role === 'user') {\n const turn = item.turn || turns.length + 1;\n current = {\n id: item.id,\n turn,\n displayIndex: item.displayIndex ?? lastDisplayIndex,\n preview: compactText(item.preview || item.title || 'Message'),\n toolCount: 0,\n running: false,\n ...(item.rowNumber !== undefined ? { rowNumber: item.rowNumber } : {}),\n ...(item.timestamp !== undefined ? { timestamp: item.timestamp } : {}),\n };\n turns.push(current);\n currentToolKeys = new Set();\n continue;\n }\n\n if (!current) continue;\n\n if (item.kind === 'tool' || item.kind === 'file' || item.kind === 'command') {\n const key = `${item.id}:${item.meta?.toolName ?? item.title ?? item.kind}`;\n if (currentToolKeys.has(key)) {\n current.running ||= item.status === 'running';\n continue;\n }\n currentToolKeys.add(key);\n current.toolCount += 1;\n current.running ||= item.status === 'running';\n }\n }\n\n return turns;\n}\n\nexport function findTimelineTurnByNumber(\n turns: readonly TuiTimelineTurn[],\n turnNumber: number,\n): TuiTimelineTurn | undefined {\n return turns.find((turn) => turn.turn === turnNumber);\n}\n\nexport function findNearestTimelineTurnByDisplayIndex(\n turns: readonly TuiTimelineTurn[],\n displayIndex: number,\n): TuiTimelineTurn | undefined {\n let selected = turns[0];\n for (const turn of turns) {\n if (turn.displayIndex <= displayIndex) {\n selected = turn;\n continue;\n }\n break;\n }\n return selected;\n}\n\nexport function formatTimelineToolSummary(toolCount: number): string {\n if (toolCount <= 0) return '0 tools';\n return `${toolCount} tool${toolCount === 1 ? '' : 's'}`;\n}\n"],"mappings":";AAaA,SAAS,YAAY,MAAc,MAAM,IAAY;CACnD,MAAM,aAAa,KAAK,QAAQ,QAAQ,IAAI,CAAC,MAAM;AACnD,KAAI,WAAW,UAAU,IAAK,QAAO;AACrC,QAAO,GAAG,WAAW,MAAM,GAAG,KAAK,IAAI,GAAG,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC;;AAGhE,SAAgB,sBAAsB,OAA0D;CAC9F,MAAM,QAA2B,EAAE;CACnC,IAAI,UAAkC;CACtC,IAAI,kCAAkB,IAAI,KAAa;CACvC,IAAI,mBAAmB;AAEvB,MAAK,MAAM,QAAQ,OAAO;AACxB,MAAI,OAAO,KAAK,iBAAiB,YAAY,OAAO,SAAS,KAAK,aAAa,CAC7E,oBAAmB,KAAK;AAG1B,MAAI,KAAK,SAAS,UAAU,KAAK,SAAS,QAAQ;GAChD,MAAM,OAAO,KAAK,QAAQ,MAAM,SAAS;AACzC,aAAU;IACR,IAAI,KAAK;IACT;IACA,cAAc,KAAK,gBAAgB;IACnC,SAAS,YAAY,KAAK,WAAW,KAAK,SAAS,UAAU;IAC7D,WAAW;IACX,SAAS;IACT,GAAI,KAAK,cAAc,KAAA,IAAY,EAAE,WAAW,KAAK,WAAW,GAAG,EAAE;IACrE,GAAI,KAAK,cAAc,KAAA,IAAY,EAAE,WAAW,KAAK,WAAW,GAAG,EAAE;IACtE;AACD,SAAM,KAAK,QAAQ;AACnB,qCAAkB,IAAI,KAAK;AAC3B;;AAGF,MAAI,CAAC,QAAS;AAEd,MAAI,KAAK,SAAS,UAAU,KAAK,SAAS,UAAU,KAAK,SAAS,WAAW;GAC3E,MAAM,MAAM,GAAG,KAAK,GAAG,GAAG,KAAK,MAAM,YAAY,KAAK,SAAS,KAAK;AACpE,OAAI,gBAAgB,IAAI,IAAI,EAAE;AAC5B,YAAQ,YAAY,KAAK,WAAW;AACpC;;AAEF,mBAAgB,IAAI,IAAI;AACxB,WAAQ,aAAa;AACrB,WAAQ,YAAY,KAAK,WAAW;;;AAIxC,QAAO;;AAGT,SAAgB,yBACd,OACA,YAC6B;AAC7B,QAAO,MAAM,MAAM,SAAS,KAAK,SAAS,WAAW;;AAGvD,SAAgB,sCACd,OACA,cAC6B;CAC7B,IAAI,WAAW,MAAM;AACrB,MAAK,MAAM,QAAQ,OAAO;AACxB,MAAI,KAAK,gBAAgB,cAAc;AACrC,cAAW;AACX;;AAEF;;AAEF,QAAO;;AAGT,SAAgB,0BAA0B,WAA2B;AACnE,KAAI,aAAa,EAAG,QAAO;AAC3B,QAAO,GAAG,UAAU,OAAO,cAAc,IAAI,KAAK"}
|
|
@@ -1,4 +1,19 @@
|
|
|
1
|
+
export type TuiFileChange = {
|
|
2
|
+
kind: 'add' | 'delete' | 'update';
|
|
3
|
+
path: string;
|
|
4
|
+
movePath?: string;
|
|
5
|
+
unifiedDiff: string;
|
|
6
|
+
added: number;
|
|
7
|
+
removed: number;
|
|
8
|
+
};
|
|
9
|
+
export type TuiPatchSummary = {
|
|
10
|
+
files: TuiFileChange[];
|
|
11
|
+
added: number;
|
|
12
|
+
removed: number;
|
|
13
|
+
};
|
|
1
14
|
export declare function isDiffFriendlyTool(toolName: string): boolean;
|
|
2
15
|
export declare function looksLikeUnifiedDiff(text: string): boolean;
|
|
3
16
|
/** Colorize unified diff lines for terminal display. */
|
|
4
17
|
export declare function renderUnifiedDiff(text: string, maxLines?: number): string;
|
|
18
|
+
export declare function parseUnifiedPatch(text: string): TuiPatchSummary | null;
|
|
19
|
+
export declare function renderPatchSummary(text: string, maxLines?: number): string | null;
|
|
@@ -31,26 +31,145 @@ function renderUnifiedDiff(text, maxLines = 80) {
|
|
|
31
31
|
const inverse = (value) => `\x1b[7m${value}\x1b[27m`;
|
|
32
32
|
const lines = text.split("\n");
|
|
33
33
|
const capped = lines.length > maxLines ? [...lines.slice(0, maxLines), "…"] : lines;
|
|
34
|
+
const lineNumberWidth = getLineNumberWidth(lines);
|
|
34
35
|
const rendered = [];
|
|
36
|
+
let oldLine = 0;
|
|
37
|
+
let newLine = 0;
|
|
35
38
|
for (let index = 0; index < capped.length; index += 1) {
|
|
36
39
|
const line = capped[index] ?? "";
|
|
37
40
|
const next = capped[index + 1] ?? "";
|
|
41
|
+
const hunk = parseHunkHeader(line);
|
|
42
|
+
if (hunk) {
|
|
43
|
+
oldLine = hunk.oldStart;
|
|
44
|
+
newLine = hunk.newStart;
|
|
45
|
+
rendered.push(header(line));
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
38
48
|
if (isRemovedDiffLine(line) && isAddedDiffLine(next)) {
|
|
39
49
|
const pair = renderReplacementPair(line, next, inverse);
|
|
40
|
-
rendered.push(removed(pair.removedLine));
|
|
41
|
-
rendered.push(added(pair.addedLine));
|
|
50
|
+
rendered.push(removed(renderDiffBodyLine(oldLine, "delete", pair.removedLine, lineNumberWidth)));
|
|
51
|
+
rendered.push(added(renderDiffBodyLine(newLine, "add", pair.addedLine, lineNumberWidth)));
|
|
52
|
+
oldLine += 1;
|
|
53
|
+
newLine += 1;
|
|
42
54
|
index += 1;
|
|
43
55
|
continue;
|
|
44
56
|
}
|
|
45
57
|
if (isDiffHeaderLine(line)) rendered.push(header(line));
|
|
46
|
-
else if (line.startsWith("+"))
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
else if (line.startsWith("+")) {
|
|
59
|
+
rendered.push(added(renderDiffBodyLine(newLine, "add", replaceTabs(line), lineNumberWidth)));
|
|
60
|
+
newLine += 1;
|
|
61
|
+
} else if (line.startsWith("-")) {
|
|
62
|
+
rendered.push(removed(renderDiffBodyLine(oldLine, "delete", replaceTabs(line), lineNumberWidth)));
|
|
63
|
+
oldLine += 1;
|
|
64
|
+
} else if (line === "…") rendered.push(context(line));
|
|
65
|
+
else {
|
|
66
|
+
rendered.push(context(renderDiffBodyLine(newLine, "context", replaceTabs(line), lineNumberWidth)));
|
|
67
|
+
oldLine += 1;
|
|
68
|
+
newLine += 1;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return rendered.join("\n");
|
|
72
|
+
}
|
|
73
|
+
function parseUnifiedPatch(text) {
|
|
74
|
+
if (!looksLikeUnifiedDiff(text)) return null;
|
|
75
|
+
const files = [];
|
|
76
|
+
let current = null;
|
|
77
|
+
const finish = () => {
|
|
78
|
+
if (!current || current.hunks.length === 0) return;
|
|
79
|
+
const oldPath = normalizeDiffPath(current.oldPath);
|
|
80
|
+
const newPath = normalizeDiffPath(current.newPath);
|
|
81
|
+
const path = newPath && newPath !== "/dev/null" ? newPath : oldPath && oldPath !== "/dev/null" ? oldPath : "unknown";
|
|
82
|
+
const kind = oldPath === "/dev/null" ? "add" : newPath === "/dev/null" ? "delete" : "update";
|
|
83
|
+
files.push({
|
|
84
|
+
kind,
|
|
85
|
+
path,
|
|
86
|
+
unifiedDiff: current.hunks.join("\n"),
|
|
87
|
+
added: current.added,
|
|
88
|
+
removed: current.removed
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
for (const rawLine of text.split("\n")) {
|
|
92
|
+
const gitMatch = rawLine.match(/^diff --git a\/(.+?) b\/(.+)$/);
|
|
93
|
+
if (gitMatch) {
|
|
94
|
+
finish();
|
|
95
|
+
current = {
|
|
96
|
+
oldPath: gitMatch[1],
|
|
97
|
+
newPath: gitMatch[2],
|
|
98
|
+
hunks: [rawLine],
|
|
99
|
+
added: 0,
|
|
100
|
+
removed: 0
|
|
101
|
+
};
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (rawLine.startsWith("--- ")) {
|
|
105
|
+
if (!current) current = {
|
|
106
|
+
hunks: [],
|
|
107
|
+
added: 0,
|
|
108
|
+
removed: 0
|
|
109
|
+
};
|
|
110
|
+
current.oldPath = rawLine.slice(4).trim();
|
|
111
|
+
current.hunks.push(rawLine);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (rawLine.startsWith("+++ ")) {
|
|
115
|
+
if (!current) current = {
|
|
116
|
+
hunks: [],
|
|
117
|
+
added: 0,
|
|
118
|
+
removed: 0
|
|
119
|
+
};
|
|
120
|
+
current.newPath = rawLine.slice(4).trim();
|
|
121
|
+
current.hunks.push(rawLine);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (!current && rawLine.startsWith("@@")) current = {
|
|
125
|
+
hunks: [],
|
|
126
|
+
added: 0,
|
|
127
|
+
removed: 0
|
|
128
|
+
};
|
|
129
|
+
if (!current) continue;
|
|
130
|
+
current.hunks.push(rawLine);
|
|
131
|
+
if (isAddedDiffLine(rawLine)) current.added += 1;
|
|
132
|
+
else if (isRemovedDiffLine(rawLine)) current.removed += 1;
|
|
133
|
+
}
|
|
134
|
+
finish();
|
|
135
|
+
if (files.length === 0) return null;
|
|
136
|
+
return {
|
|
137
|
+
files,
|
|
138
|
+
added: files.reduce((sum, file) => sum + file.added, 0),
|
|
139
|
+
removed: files.reduce((sum, file) => sum + file.removed, 0)
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function renderPatchSummary(text, maxLines = 120) {
|
|
143
|
+
const summary = parseUnifiedPatch(text);
|
|
144
|
+
if (!summary) return null;
|
|
145
|
+
const { theme } = getThemeExports();
|
|
146
|
+
const fileCount = summary.files.length;
|
|
147
|
+
const header = fileCount === 1 ? `${changeVerb(summary.files[0])} ${summary.files[0].path} ${lineCountSummary(summary.files[0])}` : `Edited ${fileCount} files ${lineCountSummary(summary)}`;
|
|
148
|
+
const rendered = [theme.accentSoft("• ") + theme.bold(header)];
|
|
149
|
+
let remainingLines = Math.max(1, maxLines - 1);
|
|
150
|
+
let omitted = false;
|
|
151
|
+
for (const [index, file] of summary.files.entries()) {
|
|
152
|
+
if (remainingLines <= 0) {
|
|
153
|
+
omitted = true;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
if (index > 0) {
|
|
157
|
+
rendered.push("");
|
|
158
|
+
remainingLines -= 1;
|
|
159
|
+
}
|
|
160
|
+
if (fileCount > 1) {
|
|
161
|
+
rendered.push(theme.dim(` ${changeVerb(file)} ${file.path} ${lineCountSummary(file)}`));
|
|
162
|
+
remainingLines -= 1;
|
|
163
|
+
}
|
|
164
|
+
const diff = renderUnifiedDiff(file.unifiedDiff, Math.max(1, remainingLines)).split("\n").map((line) => ` ${line}`).join("\n");
|
|
165
|
+
rendered.push(diff);
|
|
166
|
+
remainingLines -= diff.split("\n").length;
|
|
49
167
|
}
|
|
168
|
+
if (omitted) rendered.push(theme.dim(" …"));
|
|
50
169
|
return rendered.join("\n");
|
|
51
170
|
}
|
|
52
171
|
function isDiffHeaderLine(line) {
|
|
53
|
-
return line.startsWith("+++") || line.startsWith("---") || line.startsWith("@@") || line.startsWith("diff --git");
|
|
172
|
+
return line.startsWith("+++") || line.startsWith("---") || line.startsWith("@@") || line.startsWith("diff --git") || line.startsWith("index ") || line.startsWith("new file mode ") || line.startsWith("deleted file mode ") || line.startsWith("similarity index ") || line.startsWith("rename from ") || line.startsWith("rename to ");
|
|
54
173
|
}
|
|
55
174
|
function isRemovedDiffLine(line) {
|
|
56
175
|
return line.startsWith("-") && !line.startsWith("---");
|
|
@@ -61,6 +180,9 @@ function isAddedDiffLine(line) {
|
|
|
61
180
|
function replaceTabs(text) {
|
|
62
181
|
return text.replace(/\t/g, " ");
|
|
63
182
|
}
|
|
183
|
+
function renderDiffBodyLine(lineNumber, kind, line, lineNumberWidth) {
|
|
184
|
+
return `${lineNumber > 0 ? String(lineNumber).padStart(lineNumberWidth, " ") : "".padStart(lineNumberWidth, " ")} ${kind === "add" ? "+" : kind === "delete" ? "-" : " "}${kind === "context" ? line.startsWith(" ") ? line.slice(1) : line : line.slice(1)}`;
|
|
185
|
+
}
|
|
64
186
|
function renderReplacementPair(removedLine, addedLine, inverse) {
|
|
65
187
|
const removedContent = replaceTabs(removedLine.slice(1));
|
|
66
188
|
const addedContent = replaceTabs(addedLine.slice(1));
|
|
@@ -79,6 +201,55 @@ function highlightChangedSpan(text, start, end, inverse) {
|
|
|
79
201
|
if (highlightStart >= end) return text;
|
|
80
202
|
return `${text.slice(0, highlightStart)}${inverse(text.slice(highlightStart, end))}${text.slice(end)}`;
|
|
81
203
|
}
|
|
204
|
+
function parseHunkHeader(line) {
|
|
205
|
+
const match = line.match(/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/);
|
|
206
|
+
if (!match) return null;
|
|
207
|
+
return {
|
|
208
|
+
oldStart: Number(match[1]),
|
|
209
|
+
newStart: Number(match[2])
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
function getLineNumberWidth(lines) {
|
|
213
|
+
let oldLine = 0;
|
|
214
|
+
let newLine = 0;
|
|
215
|
+
let maxLine = 0;
|
|
216
|
+
for (const line of lines) {
|
|
217
|
+
const hunk = parseHunkHeader(line);
|
|
218
|
+
if (hunk) {
|
|
219
|
+
oldLine = hunk.oldStart;
|
|
220
|
+
newLine = hunk.newStart;
|
|
221
|
+
maxLine = Math.max(maxLine, oldLine, newLine);
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if (isAddedDiffLine(line)) {
|
|
225
|
+
maxLine = Math.max(maxLine, newLine);
|
|
226
|
+
newLine += 1;
|
|
227
|
+
} else if (isRemovedDiffLine(line)) {
|
|
228
|
+
maxLine = Math.max(maxLine, oldLine);
|
|
229
|
+
oldLine += 1;
|
|
230
|
+
} else if (!isDiffHeaderLine(line)) {
|
|
231
|
+
maxLine = Math.max(maxLine, newLine);
|
|
232
|
+
oldLine += 1;
|
|
233
|
+
newLine += 1;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return Math.max(1, String(maxLine).length);
|
|
237
|
+
}
|
|
238
|
+
function normalizeDiffPath(path) {
|
|
239
|
+
if (!path) return void 0;
|
|
240
|
+
const [first] = path.split(/\s+/);
|
|
241
|
+
if (!first) return void 0;
|
|
242
|
+
if (first === "/dev/null") return first;
|
|
243
|
+
return first.replace(/^[ab]\//, "");
|
|
244
|
+
}
|
|
245
|
+
function changeVerb(file) {
|
|
246
|
+
if (file.kind === "add") return "Added";
|
|
247
|
+
if (file.kind === "delete") return "Deleted";
|
|
248
|
+
return "Edited";
|
|
249
|
+
}
|
|
250
|
+
function lineCountSummary(change) {
|
|
251
|
+
return `(+${change.added} -${change.removed})`;
|
|
252
|
+
}
|
|
82
253
|
function commonPrefixLength(a, b) {
|
|
83
254
|
const max = Math.min(a.length, b.length);
|
|
84
255
|
let index = 0;
|
|
@@ -96,6 +267,6 @@ function hexToRgb(hex) {
|
|
|
96
267
|
return `${Number.parseInt(h.slice(0, 2), 16)};${Number.parseInt(h.slice(2, 4), 16)};${Number.parseInt(h.slice(4, 6), 16)}`;
|
|
97
268
|
}
|
|
98
269
|
//#endregion
|
|
99
|
-
export { isDiffFriendlyTool, looksLikeUnifiedDiff, renderUnifiedDiff };
|
|
270
|
+
export { isDiffFriendlyTool, looksLikeUnifiedDiff, parseUnifiedPatch, renderPatchSummary, renderUnifiedDiff };
|
|
100
271
|
|
|
101
272
|
//# sourceMappingURL=tui-tool-diff.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui-tool-diff.js","names":[],"sources":["../../../src/tui/tui-tool-diff.ts"],"sourcesContent":["import { getThemeExports } from './theme-manager.js';\n\nconst DIFF_TOOLS = new Set([\n 'edit',\n 'write',\n 'apply_patch',\n 'patch',\n 'search_replace',\n 'str_replace',\n]);\n\nexport function isDiffFriendlyTool(toolName: string): boolean {\n const base = toolName.split('__').pop()?.toLowerCase() ?? toolName.toLowerCase();\n return DIFF_TOOLS.has(base);\n}\n\nexport function looksLikeUnifiedDiff(text: string): boolean {\n const sample = text.trimStart();\n if (sample.startsWith('@@')) return true;\n const lines = sample.split('\\n').slice(0, 20);\n let diffLines = 0;\n for (const line of lines) {\n if (/^(\\+\\+\\+|---|@@|[+-] |diff --git)/.test(line)) diffLines += 1;\n }\n return diffLines >= 2;\n}\n\n/** Colorize unified diff lines for terminal display. */\nexport function renderUnifiedDiff(text: string, maxLines = 80): string {\n const palette = getThemeExports().palette;\n const fg = (hex: string) => (line: string) => `\\x1b[38;2;${hexToRgb(hex)}m${line}\\x1b[0m`;\n const added = fg(palette.success);\n const removed = fg(palette.error);\n const context = fg(palette.dim);\n const header = fg(palette.accentSoft);\n const inverse = (value: string) => `\\x1b[7m${value}\\x1b[27m`;\n\n const lines = text.split('\\n');\n const capped = lines.length > maxLines ? [...lines.slice(0, maxLines), '…'] : lines;\n\n const rendered: string[] = [];\n for (let index = 0; index < capped.length; index += 1) {\n const line = capped[index] ?? '';\n const next = capped[index + 1] ?? '';\n\n if (isRemovedDiffLine(line) && isAddedDiffLine(next)) {\n const pair = renderReplacementPair(line, next, inverse);\n rendered.push(removed(pair.removedLine));\n rendered.push(added(pair.addedLine));\n index += 1;\n continue;\n }\n\n if (isDiffHeaderLine(line)) {\n rendered.push(header(line));\n } else if (line.startsWith('+')) {\n rendered.push(added(replaceTabs(line)));\n } else if (line.startsWith('-')) {\n rendered.push(removed(replaceTabs(line)));\n } else {\n rendered.push(context(replaceTabs(line)));\n }\n }\n\n return rendered.join('\\n');\n}\n\nfunction isDiffHeaderLine(line: string): boolean {\n return line.startsWith('+++') || line.startsWith('---') || line.startsWith('@@') || line.startsWith('diff --git');\n}\n\nfunction isRemovedDiffLine(line: string): boolean {\n return line.startsWith('-') && !line.startsWith('---');\n}\n\nfunction isAddedDiffLine(line: string): boolean {\n return line.startsWith('+') && !line.startsWith('+++');\n}\n\nfunction replaceTabs(text: string): string {\n return text.replace(/\\t/g, ' ');\n}\n\nfunction renderReplacementPair(\n removedLine: string,\n addedLine: string,\n inverse: (value: string) => string,\n): { removedLine: string; addedLine: string } {\n const removedContent = replaceTabs(removedLine.slice(1));\n const addedContent = replaceTabs(addedLine.slice(1));\n const commonPrefix = commonPrefixLength(removedContent, addedContent);\n const commonSuffix = commonSuffixLength(\n removedContent.slice(commonPrefix),\n addedContent.slice(commonPrefix),\n );\n\n const removedChangedEnd = removedContent.length - commonSuffix;\n const addedChangedEnd = addedContent.length - commonSuffix;\n return {\n removedLine: `-${highlightChangedSpan(removedContent, commonPrefix, removedChangedEnd, inverse)}`,\n addedLine: `+${highlightChangedSpan(addedContent, commonPrefix, addedChangedEnd, inverse)}`,\n };\n}\n\nfunction highlightChangedSpan(\n text: string,\n start: number,\n end: number,\n inverse: (value: string) => string,\n): string {\n if (end <= start) return text;\n const changed = text.slice(start, end);\n const leadingWhitespace = changed.match(/^\\s*/)?.[0] ?? '';\n const highlightStart = start + leadingWhitespace.length;\n if (highlightStart >= end) return text;\n return `${text.slice(0, highlightStart)}${inverse(text.slice(highlightStart, end))}${text.slice(end)}`;\n}\n\nfunction commonPrefixLength(a: string, b: string): number {\n const max = Math.min(a.length, b.length);\n let index = 0;\n while (index < max && a[index] === b[index]) {\n index += 1;\n }\n return index;\n}\n\nfunction commonSuffixLength(a: string, b: string): number {\n const max = Math.min(a.length, b.length);\n let index = 0;\n while (index < max && a[a.length - index - 1] === b[b.length - index - 1]) {\n index += 1;\n }\n return index;\n}\n\nfunction hexToRgb(hex: string): string {\n const h = hex.replace('#', '');\n const r = Number.parseInt(h.slice(0, 2), 16);\n const g = Number.parseInt(h.slice(2, 4), 16);\n const b = Number.parseInt(h.slice(4, 6), 16);\n return `${r};${g};${b}`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tui-tool-diff.js","names":[],"sources":["../../../src/tui/tui-tool-diff.ts"],"sourcesContent":["import { getThemeExports } from './theme-manager.js';\n\ntype DiffLineKind = 'context' | 'add' | 'delete';\n\ntype HunkHeader = {\n oldStart: number;\n newStart: number;\n};\n\nexport type TuiFileChange = {\n kind: 'add' | 'delete' | 'update';\n path: string;\n movePath?: string;\n unifiedDiff: string;\n added: number;\n removed: number;\n};\n\nexport type TuiPatchSummary = {\n files: TuiFileChange[];\n added: number;\n removed: number;\n};\n\nconst DIFF_TOOLS = new Set([\n 'edit',\n 'write',\n 'apply_patch',\n 'patch',\n 'search_replace',\n 'str_replace',\n]);\n\nexport function isDiffFriendlyTool(toolName: string): boolean {\n const base = toolName.split('__').pop()?.toLowerCase() ?? toolName.toLowerCase();\n return DIFF_TOOLS.has(base);\n}\n\nexport function looksLikeUnifiedDiff(text: string): boolean {\n const sample = text.trimStart();\n if (sample.startsWith('@@')) return true;\n const lines = sample.split('\\n').slice(0, 20);\n let diffLines = 0;\n for (const line of lines) {\n if (/^(\\+\\+\\+|---|@@|[+-] |diff --git)/.test(line)) diffLines += 1;\n }\n return diffLines >= 2;\n}\n\n/** Colorize unified diff lines for terminal display. */\nexport function renderUnifiedDiff(text: string, maxLines = 80): string {\n const palette = getThemeExports().palette;\n const fg = (hex: string) => (line: string) => `\\x1b[38;2;${hexToRgb(hex)}m${line}\\x1b[0m`;\n const added = fg(palette.success);\n const removed = fg(palette.error);\n const context = fg(palette.dim);\n const header = fg(palette.accentSoft);\n const inverse = (value: string) => `\\x1b[7m${value}\\x1b[27m`;\n\n const lines = text.split('\\n');\n const capped = lines.length > maxLines ? [...lines.slice(0, maxLines), '…'] : lines;\n const lineNumberWidth = getLineNumberWidth(lines);\n\n const rendered: string[] = [];\n let oldLine = 0;\n let newLine = 0;\n for (let index = 0; index < capped.length; index += 1) {\n const line = capped[index] ?? '';\n const next = capped[index + 1] ?? '';\n\n const hunk = parseHunkHeader(line);\n if (hunk) {\n oldLine = hunk.oldStart;\n newLine = hunk.newStart;\n rendered.push(header(line));\n continue;\n }\n\n if (isRemovedDiffLine(line) && isAddedDiffLine(next)) {\n const pair = renderReplacementPair(line, next, inverse);\n rendered.push(removed(renderDiffBodyLine(oldLine, 'delete', pair.removedLine, lineNumberWidth)));\n rendered.push(added(renderDiffBodyLine(newLine, 'add', pair.addedLine, lineNumberWidth)));\n oldLine += 1;\n newLine += 1;\n index += 1;\n continue;\n }\n\n if (isDiffHeaderLine(line)) {\n rendered.push(header(line));\n } else if (line.startsWith('+')) {\n rendered.push(added(renderDiffBodyLine(newLine, 'add', replaceTabs(line), lineNumberWidth)));\n newLine += 1;\n } else if (line.startsWith('-')) {\n rendered.push(removed(renderDiffBodyLine(oldLine, 'delete', replaceTabs(line), lineNumberWidth)));\n oldLine += 1;\n } else if (line === '…') {\n rendered.push(context(line));\n } else {\n rendered.push(context(renderDiffBodyLine(newLine, 'context', replaceTabs(line), lineNumberWidth)));\n oldLine += 1;\n newLine += 1;\n }\n }\n\n return rendered.join('\\n');\n}\n\nexport function parseUnifiedPatch(text: string): TuiPatchSummary | null {\n if (!looksLikeUnifiedDiff(text)) return null;\n\n const files: TuiFileChange[] = [];\n let current: {\n oldPath?: string;\n newPath?: string;\n hunks: string[];\n added: number;\n removed: number;\n } | null = null;\n\n const finish = () => {\n if (!current || current.hunks.length === 0) return;\n const oldPath = normalizeDiffPath(current.oldPath);\n const newPath = normalizeDiffPath(current.newPath);\n const path = newPath && newPath !== '/dev/null'\n ? newPath\n : oldPath && oldPath !== '/dev/null'\n ? oldPath\n : 'unknown';\n const kind = oldPath === '/dev/null'\n ? 'add'\n : newPath === '/dev/null'\n ? 'delete'\n : 'update';\n files.push({\n kind,\n path,\n unifiedDiff: current.hunks.join('\\n'),\n added: current.added,\n removed: current.removed,\n });\n };\n\n for (const rawLine of text.split('\\n')) {\n const gitMatch = rawLine.match(/^diff --git a\\/(.+?) b\\/(.+)$/);\n if (gitMatch) {\n finish();\n current = {\n oldPath: gitMatch[1],\n newPath: gitMatch[2],\n hunks: [rawLine],\n added: 0,\n removed: 0,\n };\n continue;\n }\n\n if (rawLine.startsWith('--- ')) {\n if (!current) {\n current = { hunks: [], added: 0, removed: 0 };\n }\n current.oldPath = rawLine.slice(4).trim();\n current.hunks.push(rawLine);\n continue;\n }\n\n if (rawLine.startsWith('+++ ')) {\n if (!current) {\n current = { hunks: [], added: 0, removed: 0 };\n }\n current.newPath = rawLine.slice(4).trim();\n current.hunks.push(rawLine);\n continue;\n }\n\n if (!current && rawLine.startsWith('@@')) {\n current = { hunks: [], added: 0, removed: 0 };\n }\n if (!current) continue;\n\n current.hunks.push(rawLine);\n if (isAddedDiffLine(rawLine)) {\n current.added += 1;\n } else if (isRemovedDiffLine(rawLine)) {\n current.removed += 1;\n }\n }\n finish();\n\n if (files.length === 0) return null;\n return {\n files,\n added: files.reduce((sum, file) => sum + file.added, 0),\n removed: files.reduce((sum, file) => sum + file.removed, 0),\n };\n}\n\nexport function renderPatchSummary(text: string, maxLines = 120): string | null {\n const summary = parseUnifiedPatch(text);\n if (!summary) return null;\n\n const { theme } = getThemeExports();\n const fileCount = summary.files.length;\n const header = fileCount === 1\n ? `${changeVerb(summary.files[0]!)} ${summary.files[0]!.path} ${lineCountSummary(summary.files[0]!)}`\n : `Edited ${fileCount} files ${lineCountSummary(summary)}`;\n const rendered: string[] = [theme.accentSoft('• ') + theme.bold(header)];\n\n let remainingLines = Math.max(1, maxLines - 1);\n let omitted = false;\n for (const [index, file] of summary.files.entries()) {\n if (remainingLines <= 0) {\n omitted = true;\n break;\n }\n if (index > 0) {\n rendered.push('');\n remainingLines -= 1;\n }\n if (fileCount > 1) {\n rendered.push(theme.dim(` ${changeVerb(file)} ${file.path} ${lineCountSummary(file)}`));\n remainingLines -= 1;\n }\n\n const diff = renderUnifiedDiff(file.unifiedDiff, Math.max(1, remainingLines))\n .split('\\n')\n .map((line) => ` ${line}`)\n .join('\\n');\n rendered.push(diff);\n remainingLines -= diff.split('\\n').length;\n }\n\n if (omitted) {\n rendered.push(theme.dim(' …'));\n }\n\n return rendered.join('\\n');\n}\n\nfunction isDiffHeaderLine(line: string): boolean {\n return (\n line.startsWith('+++') ||\n line.startsWith('---') ||\n line.startsWith('@@') ||\n line.startsWith('diff --git') ||\n line.startsWith('index ') ||\n line.startsWith('new file mode ') ||\n line.startsWith('deleted file mode ') ||\n line.startsWith('similarity index ') ||\n line.startsWith('rename from ') ||\n line.startsWith('rename to ')\n );\n}\n\nfunction isRemovedDiffLine(line: string): boolean {\n return line.startsWith('-') && !line.startsWith('---');\n}\n\nfunction isAddedDiffLine(line: string): boolean {\n return line.startsWith('+') && !line.startsWith('+++');\n}\n\nfunction replaceTabs(text: string): string {\n return text.replace(/\\t/g, ' ');\n}\n\nfunction renderDiffBodyLine(\n lineNumber: number,\n kind: DiffLineKind,\n line: string,\n lineNumberWidth: number,\n): string {\n const gutter = lineNumber > 0 ? String(lineNumber).padStart(lineNumberWidth, ' ') : ''.padStart(lineNumberWidth, ' ');\n const marker = kind === 'add' ? '+' : kind === 'delete' ? '-' : ' ';\n const content = kind === 'context'\n ? line.startsWith(' ') ? line.slice(1) : line\n : line.slice(1);\n return `${gutter} ${marker}${content}`;\n}\n\nfunction renderReplacementPair(\n removedLine: string,\n addedLine: string,\n inverse: (value: string) => string,\n): { removedLine: string; addedLine: string } {\n const removedContent = replaceTabs(removedLine.slice(1));\n const addedContent = replaceTabs(addedLine.slice(1));\n const commonPrefix = commonPrefixLength(removedContent, addedContent);\n const commonSuffix = commonSuffixLength(\n removedContent.slice(commonPrefix),\n addedContent.slice(commonPrefix),\n );\n\n const removedChangedEnd = removedContent.length - commonSuffix;\n const addedChangedEnd = addedContent.length - commonSuffix;\n return {\n removedLine: `-${highlightChangedSpan(removedContent, commonPrefix, removedChangedEnd, inverse)}`,\n addedLine: `+${highlightChangedSpan(addedContent, commonPrefix, addedChangedEnd, inverse)}`,\n };\n}\n\nfunction highlightChangedSpan(\n text: string,\n start: number,\n end: number,\n inverse: (value: string) => string,\n): string {\n if (end <= start) return text;\n const changed = text.slice(start, end);\n const leadingWhitespace = changed.match(/^\\s*/)?.[0] ?? '';\n const highlightStart = start + leadingWhitespace.length;\n if (highlightStart >= end) return text;\n return `${text.slice(0, highlightStart)}${inverse(text.slice(highlightStart, end))}${text.slice(end)}`;\n}\n\nfunction parseHunkHeader(line: string): HunkHeader | null {\n const match = line.match(/^@@ -(\\d+)(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/);\n if (!match) return null;\n return {\n oldStart: Number(match[1]),\n newStart: Number(match[2]),\n };\n}\n\nfunction getLineNumberWidth(lines: string[]): number {\n let oldLine = 0;\n let newLine = 0;\n let maxLine = 0;\n for (const line of lines) {\n const hunk = parseHunkHeader(line);\n if (hunk) {\n oldLine = hunk.oldStart;\n newLine = hunk.newStart;\n maxLine = Math.max(maxLine, oldLine, newLine);\n continue;\n }\n if (isAddedDiffLine(line)) {\n maxLine = Math.max(maxLine, newLine);\n newLine += 1;\n } else if (isRemovedDiffLine(line)) {\n maxLine = Math.max(maxLine, oldLine);\n oldLine += 1;\n } else if (!isDiffHeaderLine(line)) {\n maxLine = Math.max(maxLine, newLine);\n oldLine += 1;\n newLine += 1;\n }\n }\n return Math.max(1, String(maxLine).length);\n}\n\nfunction normalizeDiffPath(path: string | undefined): string | undefined {\n if (!path) return undefined;\n const [first] = path.split(/\\s+/);\n if (!first) return undefined;\n if (first === '/dev/null') return first;\n return first.replace(/^[ab]\\//, '');\n}\n\nfunction changeVerb(file: Pick<TuiFileChange, 'kind'>): string {\n if (file.kind === 'add') return 'Added';\n if (file.kind === 'delete') return 'Deleted';\n return 'Edited';\n}\n\nfunction lineCountSummary(change: Pick<TuiFileChange | TuiPatchSummary, 'added' | 'removed'>): string {\n return `(+${change.added} -${change.removed})`;\n}\n\nfunction commonPrefixLength(a: string, b: string): number {\n const max = Math.min(a.length, b.length);\n let index = 0;\n while (index < max && a[index] === b[index]) {\n index += 1;\n }\n return index;\n}\n\nfunction commonSuffixLength(a: string, b: string): number {\n const max = Math.min(a.length, b.length);\n let index = 0;\n while (index < max && a[a.length - index - 1] === b[b.length - index - 1]) {\n index += 1;\n }\n return index;\n}\n\nfunction hexToRgb(hex: string): string {\n const h = hex.replace('#', '');\n const r = Number.parseInt(h.slice(0, 2), 16);\n const g = Number.parseInt(h.slice(2, 4), 16);\n const b = Number.parseInt(h.slice(4, 6), 16);\n return `${r};${g};${b}`;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui-types.js","names":[],"sources":["../../../src/tui/tui-types.ts"],"sourcesContent":["/** TUI configuration options passed from CLI. */\nexport interface TuiOptions {\n /** Connect to a running gateway instead of embedded mode. */\n url?: string;\n /** Gateway bearer token. */\n token?: string;\n /** Session key to resume. */\n session?: string;\n /** Agent id for a fresh TUI session. */\n agentId?: string;\n /** Thinking level override. */\n thinking?: string;\n /** Single message to send on start, then stay open. */\n message?: string;\n /** Workspace directory for the new TUI session. */\n workdir?: string;\n /** Use the launch directory as the new TUI session workspace when no workdir is set. */\n useStartupCwd?: boolean;\n /** Run in embedded (local) mode — no gateway required. */\n local?: boolean;\n /** Theme id: `auto`, `dark`, `light`, or custom name under `~/.xopc/themes/`. */\n theme?: string;\n}\n\nexport type TuiExitReason = 'exit' | 'signal';\n\nexport interface TuiResult {\n exitReason: TuiExitReason;\n}\n\n/** Parsed SSE event from the stream. */\nexport interface ParsedSSEEvent {\n event: string;\n data: string;\n id?: string;\n}\n\n/** Activity status for the TUI status bar. */\nexport type ActivityStatus =\n | 'idle'\n | 'sending'\n | 'waiting'\n | 'streaming'\n | 'running'\n | 'compacting'\n | 'stalled'\n | 'recovering'\n | 'aborting';\n\nexport type TuiEventSource = 'agent-response' | 'agent-resume' | 'broadcast' | 'embedded' | 'unknown';\n\nexport type TuiRunPhase =\n | 'idle'\n | 'sending'\n | 'waiting'\n | 'streaming'\n | 'tool'\n | 'progress'\n | 'stalled'\n | 'recovering'\n | 'aborting';\n\nexport interface TuiRunStatus {\n phase: TuiRunPhase;\n runId: string | null;\n directStreamRunId: string | null;\n lastCompletedRunId: string | null;\n source: TuiEventSource;\n lastEvent: string | null;\n lastActivityAt: number | null;\n stalledAt: number | null;\n recoveredAt: number | null;\n}\n\n/** Session metadata shown in the TUI footer. */\nexport interface SessionInfo {\n model?: string;\n modelProvider?: string;\n thinkingLevel?: string;\n reasoningLevel?: string;\n verboseLevel?: string;\n contextTokens?: number | null;\n totalTokens?: number | null;\n contextWindow?: number | null;\n contextUsagePercent?: number | null;\n displayName?: string;\n effectiveWorkspacePath?: string;\n workingDirectoryLocked?: boolean;\n}\n\n/** Mutable state bag for the TUI runtime. */\nexport interface TuiState {\n currentSessionKey: string;\n activeRunId: string | null;\n isConnected: boolean;\n activityStatus: ActivityStatus;\n runStatus: TuiRunStatus;\n connectionStatus: string;\n sessionInfo: SessionInfo;\n autoMessageSent: boolean;\n historyLoaded: boolean;\n toolsExpanded: boolean;\n showThinking: boolean;\n /** Last Ctrl+C timestamp for double-press exit (see `resolveCtrlCAction`). */\n lastCtrlCAt: number;\n exitRequested: boolean;\n /** Queued via Alt+Enter while a run is active; flushed FIFO when the run ends. */\n messageFollowUpQueue: string[];\n /** Queued Enter-while-busy steering messages after the first in-flight steer. */\n steeringQueue: string[];\n /** Ctrl+P cycle filter; `null` = all models from catalog. */\n scopedModelRefs: string[] | null;\n /** Last Escape timestamp for double-press actions. */\n lastEscapeAt: number;\n /** Human-readable progress from SSE `progress` events. */\n progressMessage: string | null;\n /** Session compaction in flight (local /compact handler). */\n isCompacting: boolean;\n /** Messages queued while compacting. */\n compactionQueue: string[];\n}\n\nexport function createInitialState(sessionKey: string): TuiState {\n return {\n currentSessionKey: sessionKey,\n activeRunId: null,\n isConnected: false,\n activityStatus: 'idle',\n runStatus: {\n phase: 'idle',\n runId: null,\n directStreamRunId: null,\n lastCompletedRunId: null,\n source: 'unknown',\n lastEvent: null,\n lastActivityAt: null,\n stalledAt: null,\n recoveredAt: null,\n },\n connectionStatus: 'connecting',\n sessionInfo: {},\n autoMessageSent: false,\n historyLoaded: false,\n toolsExpanded: false,\n showThinking: false,\n lastCtrlCAt: 0,\n exitRequested: false,\n messageFollowUpQueue: [],\n steeringQueue: [],\n scopedModelRefs: null,\n lastEscapeAt: 0,\n progressMessage: null,\n isCompacting: false,\n compactionQueue: [],\n };\n}\n"],"mappings":";
|
|
1
|
+
{"version":3,"file":"tui-types.js","names":[],"sources":["../../../src/tui/tui-types.ts"],"sourcesContent":["/** TUI configuration options passed from CLI. */\nexport interface TuiOptions {\n /** Connect to a running gateway instead of embedded mode. */\n url?: string;\n /** Gateway bearer token. */\n token?: string;\n /** Session key to resume. */\n session?: string;\n /** Agent id for a fresh TUI session. */\n agentId?: string;\n /** Thinking level override. */\n thinking?: string;\n /** Single message to send on start, then stay open. */\n message?: string;\n /** Workspace directory for the new TUI session. */\n workdir?: string;\n /** Use the launch directory as the new TUI session workspace when no workdir is set. */\n useStartupCwd?: boolean;\n /** Run in embedded (local) mode — no gateway required. */\n local?: boolean;\n /** Theme id: `auto`, `dark`, `light`, or custom name under `~/.xopc/themes/`. */\n theme?: string;\n}\n\nexport type TuiExitReason = 'exit' | 'signal';\n\nexport interface TuiResult {\n exitReason: TuiExitReason;\n}\n\n/** Parsed SSE event from the stream. */\nexport interface ParsedSSEEvent {\n event: string;\n data: string;\n id?: string;\n}\n\n/** Activity status for the TUI status bar. */\nexport type ActivityStatus =\n | 'idle'\n | 'sending'\n | 'waiting'\n | 'streaming'\n | 'running'\n | 'compacting'\n | 'stalled'\n | 'recovering'\n | 'aborting';\n\nexport type TuiEventSource = 'agent-response' | 'agent-resume' | 'broadcast' | 'embedded' | 'unknown';\n\nexport type TuiRunPhase =\n | 'idle'\n | 'sending'\n | 'waiting'\n | 'streaming'\n | 'tool'\n | 'progress'\n | 'stalled'\n | 'recovering'\n | 'aborting';\n\nexport interface TuiRunStatus {\n phase: TuiRunPhase;\n runId: string | null;\n directStreamRunId: string | null;\n lastCompletedRunId: string | null;\n source: TuiEventSource;\n lastEvent: string | null;\n startedAt: number | null;\n lastActivityAt: number | null;\n stalledAt: number | null;\n recoveredAt: number | null;\n}\n\n/** Session metadata shown in the TUI footer. */\nexport interface SessionInfo {\n model?: string;\n modelProvider?: string;\n thinkingLevel?: string;\n reasoningLevel?: string;\n verboseLevel?: string;\n contextTokens?: number | null;\n totalTokens?: number | null;\n contextWindow?: number | null;\n contextUsagePercent?: number | null;\n displayName?: string;\n effectiveWorkspacePath?: string;\n workingDirectoryLocked?: boolean;\n}\n\n/** Mutable state bag for the TUI runtime. */\nexport interface TuiState {\n currentSessionKey: string;\n activeRunId: string | null;\n isConnected: boolean;\n activityStatus: ActivityStatus;\n runStatus: TuiRunStatus;\n connectionStatus: string;\n sessionInfo: SessionInfo;\n autoMessageSent: boolean;\n historyLoaded: boolean;\n toolsExpanded: boolean;\n showThinking: boolean;\n /** Last Ctrl+C timestamp for double-press exit (see `resolveCtrlCAction`). */\n lastCtrlCAt: number;\n exitRequested: boolean;\n /** Queued via Alt+Enter while a run is active; flushed FIFO when the run ends. */\n messageFollowUpQueue: string[];\n /** Queued Enter-while-busy steering messages after the first in-flight steer. */\n steeringQueue: string[];\n /** Ctrl+P cycle filter; `null` = all models from catalog. */\n scopedModelRefs: string[] | null;\n /** Last Escape timestamp for double-press actions. */\n lastEscapeAt: number;\n /** Human-readable progress from SSE `progress` events. */\n progressMessage: string | null;\n /** Session compaction in flight (local /compact handler). */\n isCompacting: boolean;\n /** Messages queued while compacting. */\n compactionQueue: string[];\n}\n\nexport function createInitialState(sessionKey: string): TuiState {\n return {\n currentSessionKey: sessionKey,\n activeRunId: null,\n isConnected: false,\n activityStatus: 'idle',\n runStatus: {\n phase: 'idle',\n runId: null,\n directStreamRunId: null,\n lastCompletedRunId: null,\n source: 'unknown',\n lastEvent: null,\n startedAt: null,\n lastActivityAt: null,\n stalledAt: null,\n recoveredAt: null,\n },\n connectionStatus: 'connecting',\n sessionInfo: {},\n autoMessageSent: false,\n historyLoaded: false,\n toolsExpanded: false,\n showThinking: false,\n lastCtrlCAt: 0,\n exitRequested: false,\n messageFollowUpQueue: [],\n steeringQueue: [],\n scopedModelRefs: null,\n lastEscapeAt: 0,\n progressMessage: null,\n isCompacting: false,\n compactionQueue: [],\n };\n}\n"],"mappings":";AA2HA,SAAgB,mBAAmB,YAA8B;AAC/D,QAAO;EACL,mBAAmB;EACnB,aAAa;EACb,aAAa;EACb,gBAAgB;EAChB,WAAW;GACT,OAAO;GACP,OAAO;GACP,mBAAmB;GACnB,oBAAoB;GACpB,QAAQ;GACR,WAAW;GACX,WAAW;GACX,gBAAgB;GAChB,WAAW;GACX,aAAa;GACd;EACD,kBAAkB;EAClB,aAAa,EAAE;EACf,iBAAiB;EACjB,eAAe;EACf,eAAe;EACf,cAAc;EACd,aAAa;EACb,eAAe;EACf,sBAAsB,EAAE;EACxB,eAAe,EAAE;EACjB,iBAAiB;EACjB,cAAc;EACd,iBAAiB;EACjB,cAAc;EACd,iBAAiB,EAAE;EACpB"}
|
package/dist/src/tui/tui.js
CHANGED
|
@@ -35,7 +35,8 @@ import { createLocalShellRunner } from "./tui-local-shell.js";
|
|
|
35
35
|
import { filterModelsForCycle, loadScopedModelRefs, saveScopedModelRefs } from "./tui-scoped-models.js";
|
|
36
36
|
import { openModelPickerOverlay } from "./tui-model-picker.js";
|
|
37
37
|
import { runTuiOAuthLogin } from "./tui-oauth-login.js";
|
|
38
|
-
import { openAgentPickerOverlay, openProjectTrustOverlay, openReviewLauncherOverlay, openScopedModelsOverlay, openSessionPickerOverlay, openSessionTreeOverlay, openSettingsOverlay, openThinkingSelectorOverlay, openTranscriptTreeOverlay, openUserMessageForkOverlay } from "./tui-picker-overlay.js";
|
|
38
|
+
import { openAgentPickerOverlay, openProjectTrustOverlay, openReviewLauncherOverlay, openScopedModelsOverlay, openSessionPickerOverlay, openSessionTreeOverlay, openSettingsOverlay, openThinkingSelectorOverlay, openTimelineOverlay, openTranscriptTreeOverlay, openUserMessageForkOverlay } from "./tui-picker-overlay.js";
|
|
39
|
+
import { formatActiveRunStatus, formatRunDuration } from "./tui-run-status-format.js";
|
|
39
40
|
import { formatBusyResponseHint, formatSteerUnavailableHint, formatSuspendUnsupportedHint } from "./tui-runtime-hints.js";
|
|
40
41
|
import { createSessionActions } from "./tui-session-actions.js";
|
|
41
42
|
import { TuiSessionSnapshot } from "./tui-session-snapshot.js";
|
|
@@ -55,8 +56,8 @@ import { createTuiExtensionRuntime } from "./extension-host/runtime.js";
|
|
|
55
56
|
import { tmpdir } from "node:os";
|
|
56
57
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
57
58
|
import { mkdirSync, mkdtempSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
58
|
-
import { randomUUID } from "node:crypto";
|
|
59
59
|
import { spawnSync } from "node:child_process";
|
|
60
|
+
import { randomUUID } from "node:crypto";
|
|
60
61
|
import { Container, Loader, ProcessTerminal, TUI, setKeybindings } from "@earendil-works/pi-tui";
|
|
61
62
|
import { Buffer } from "node:buffer";
|
|
62
63
|
//#region src/tui/tui.ts
|
|
@@ -265,6 +266,7 @@ async function runTui(opts) {
|
|
|
265
266
|
const statusContainer = new Container();
|
|
266
267
|
const bottomBar = new TuiBottomBar(() => state, () => opts.thinking, () => formatKeyIds(keybindings, "app.message.dequeue", { capitalize: true }));
|
|
267
268
|
const chatLog = new ChatLog(keybindings);
|
|
269
|
+
chatLog.setViewportRowsProvider(() => Math.max(8, tui.terminal.rows - 8));
|
|
268
270
|
let startupResources;
|
|
269
271
|
let startupCardShown = false;
|
|
270
272
|
chatLog.setShowThinking(state.showThinking);
|
|
@@ -844,7 +846,9 @@ async function runTui(opts) {
|
|
|
844
846
|
"streaming",
|
|
845
847
|
"running",
|
|
846
848
|
"compacting",
|
|
847
|
-
"
|
|
849
|
+
"stalled",
|
|
850
|
+
"recovering",
|
|
851
|
+
"aborting"
|
|
848
852
|
]);
|
|
849
853
|
const syncTerminalProgress = () => {
|
|
850
854
|
if (!tuiSettings.showTerminalProgress) {
|
|
@@ -860,14 +864,10 @@ async function runTui(opts) {
|
|
|
860
864
|
if (state.activeRunId && state.runStatus.lastActivityAt == null) state.runStatus = {
|
|
861
865
|
...state.runStatus,
|
|
862
866
|
runId: state.activeRunId,
|
|
867
|
+
startedAt: state.runStatus.startedAt ?? lastStreamActivityAt,
|
|
863
868
|
lastActivityAt: lastStreamActivityAt
|
|
864
869
|
};
|
|
865
870
|
};
|
|
866
|
-
const formatElapsed = (startMs) => {
|
|
867
|
-
const totalSeconds = Math.max(0, Math.floor((Date.now() - startMs) / 1e3));
|
|
868
|
-
if (totalSeconds < 60) return `${totalSeconds}s`;
|
|
869
|
-
return `${Math.floor(totalSeconds / 60)}m ${totalSeconds % 60}s`;
|
|
870
|
-
};
|
|
871
871
|
const renderStatus = () => {
|
|
872
872
|
const isBusy = busyStates.has(state.activityStatus);
|
|
873
873
|
if (isBusy && extensionWorkingVisible) {
|
|
@@ -877,15 +877,15 @@ async function runTui(opts) {
|
|
|
877
877
|
statusLoader = new Loader(tui, (spinner) => theme.accent(spinner), (text) => theme.bold(theme.accentSoft(text)), "", extensionWorkingIndicator);
|
|
878
878
|
statusContainer.addChild(statusLoader);
|
|
879
879
|
}
|
|
880
|
-
const
|
|
881
|
-
|
|
882
|
-
|
|
880
|
+
const renderLoaderMessage = () => {
|
|
881
|
+
const activeRunStatus = formatActiveRunStatus(state);
|
|
882
|
+
if (activeRunStatus) return activeRunStatus;
|
|
883
|
+
const elapsed = formatRunDuration(Date.now() - statusStartedAt);
|
|
884
|
+
return `${state.progressMessage ?? extensionWorkingMessage ?? state.activityStatus} (${elapsed})`;
|
|
885
|
+
};
|
|
886
|
+
statusLoader.setMessage(`xopc • ${renderLoaderMessage()} | ${state.connectionStatus}`);
|
|
883
887
|
if (!elapsedTimerId) elapsedTimerId = setInterval(() => {
|
|
884
|
-
if (statusStartedAt && statusLoader) {
|
|
885
|
-
const el = formatElapsed(statusStartedAt);
|
|
886
|
-
const message = state.progressMessage ?? extensionWorkingMessage ?? state.activityStatus;
|
|
887
|
-
statusLoader.setMessage(`${message} • ${el} | ${state.connectionStatus}`);
|
|
888
|
-
}
|
|
888
|
+
if (statusStartedAt && statusLoader) statusLoader.setMessage(`xopc • ${renderLoaderMessage()} | ${state.connectionStatus}`);
|
|
889
889
|
}, 1e3);
|
|
890
890
|
} else {
|
|
891
891
|
if (!isBusy) {
|
|
@@ -955,7 +955,7 @@ async function runTui(opts) {
|
|
|
955
955
|
process.exit(0);
|
|
956
956
|
});
|
|
957
957
|
};
|
|
958
|
-
const { refreshSessionInfo, loadHistory: loadSessionHistory, setSession, abortActive, resetCurrentSession, clearChatForSessionSwitch } = createSessionActions({
|
|
958
|
+
const { refreshSessionInfo, loadHistory: loadSessionHistory, loadHistoryWindow, setSession, abortActive, resetCurrentSession, clearChatForSessionSwitch } = createSessionActions({
|
|
959
959
|
client,
|
|
960
960
|
chatLog,
|
|
961
961
|
tui,
|
|
@@ -1035,7 +1035,7 @@ async function runTui(opts) {
|
|
|
1035
1035
|
if (streamRecoveryPromise) return streamRecoveryPromise;
|
|
1036
1036
|
const runId = state.activeRunId;
|
|
1037
1037
|
markRunRecovering(state, Date.now());
|
|
1038
|
-
state.progressMessage = "
|
|
1038
|
+
state.progressMessage = "Reconnecting output";
|
|
1039
1039
|
setActivityStatus("recovering");
|
|
1040
1040
|
streamRecoveryPromise = (async () => {
|
|
1041
1041
|
try {
|
|
@@ -1049,20 +1049,19 @@ async function runTui(opts) {
|
|
|
1049
1049
|
runId
|
|
1050
1050
|
});
|
|
1051
1051
|
if (resumed.ok) {
|
|
1052
|
-
state.progressMessage = "
|
|
1052
|
+
state.progressMessage = "Reconnecting output";
|
|
1053
1053
|
setActivityStatus("recovering");
|
|
1054
|
-
chatLog.addSystem(theme.dim(`Reattached to active run after ${reason}.`));
|
|
1055
1054
|
} else {
|
|
1056
1055
|
markRunRecoveryComplete(state, Date.now());
|
|
1057
|
-
state.progressMessage = "
|
|
1056
|
+
state.progressMessage = "Output stale";
|
|
1058
1057
|
setActivityStatus("stalled");
|
|
1059
|
-
chatLog.addSystem(theme.dim(`
|
|
1058
|
+
chatLog.addSystem(theme.dim(`Output connection is stale. The task may still be running, but xopc could not reattach to live output: ${resumed.reason ?? "run relay unavailable"}. Press Escape or /abort to stop it.`));
|
|
1060
1059
|
}
|
|
1061
1060
|
} else {
|
|
1062
1061
|
markRunRecoveryComplete(state, Date.now());
|
|
1063
|
-
state.progressMessage = "
|
|
1062
|
+
state.progressMessage = "Output stale";
|
|
1064
1063
|
setActivityStatus("stalled");
|
|
1065
|
-
chatLog.addSystem(theme.dim(
|
|
1064
|
+
chatLog.addSystem(theme.dim("Output connection is stale. The task may still be running. Press Escape or /abort to stop it."));
|
|
1066
1065
|
}
|
|
1067
1066
|
}
|
|
1068
1067
|
} catch (error) {
|
|
@@ -1432,6 +1431,7 @@ async function runTui(opts) {
|
|
|
1432
1431
|
sendSteeringToActiveRun(text);
|
|
1433
1432
|
};
|
|
1434
1433
|
const sendMessage = (text) => {
|
|
1434
|
+
chatLog.jumpToLatest();
|
|
1435
1435
|
if (state.activeRunId && pendingImageAttachments.length > 0) {
|
|
1436
1436
|
chatLog.addSystem(theme.dim("Image attachments cannot be steered into an active run. Wait for this reply to finish, then send."));
|
|
1437
1437
|
tui.requestRender();
|
|
@@ -1582,6 +1582,7 @@ async function runTui(opts) {
|
|
|
1582
1582
|
openReviewLauncher: () => {},
|
|
1583
1583
|
openSessionPicker: () => {},
|
|
1584
1584
|
openSessionTree: () => {},
|
|
1585
|
+
openTimeline: (_initialSearch) => {},
|
|
1585
1586
|
openTranscriptTree: () => {},
|
|
1586
1587
|
openUserMessageFork: () => {},
|
|
1587
1588
|
openScopedModels: () => {},
|
|
@@ -1654,6 +1655,9 @@ async function runTui(opts) {
|
|
|
1654
1655
|
getSessionStats: () => client.getSessionStats(state.currentSessionKey),
|
|
1655
1656
|
getStartupResources: () => startupResources,
|
|
1656
1657
|
loadTranscriptTree: () => client.loadTranscriptTree(state.currentSessionKey),
|
|
1658
|
+
loadTimeline: () => client.loadTimeline(state.currentSessionKey),
|
|
1659
|
+
loadHistoryWindow,
|
|
1660
|
+
loadSessionHistory: () => loadSessionHistory(),
|
|
1657
1661
|
exportSession: exportCurrentSession,
|
|
1658
1662
|
importSession: importSessionExport,
|
|
1659
1663
|
createShare: createShareLink,
|
|
@@ -1827,6 +1831,7 @@ async function runTui(opts) {
|
|
|
1827
1831
|
switchAgentSession,
|
|
1828
1832
|
clearChatForSessionSwitch,
|
|
1829
1833
|
loadSessionHistory,
|
|
1834
|
+
loadHistoryWindow,
|
|
1830
1835
|
setEditorText: (text) => editor.setText(text),
|
|
1831
1836
|
setModelChoices,
|
|
1832
1837
|
getScopedModelRefs: () => state.scopedModelRefs,
|
|
@@ -1852,6 +1857,7 @@ async function runTui(opts) {
|
|
|
1852
1857
|
uiOverlays.openReviewLauncher = () => void openReviewLauncherOverlay(pickerSvc);
|
|
1853
1858
|
uiOverlays.openSessionPicker = () => void openSessionPickerOverlay(pickerSvc);
|
|
1854
1859
|
uiOverlays.openSessionTree = () => void openSessionTreeOverlay(pickerSvc);
|
|
1860
|
+
uiOverlays.openTimeline = (initialSearch) => void openTimelineOverlay(pickerSvc, initialSearch);
|
|
1855
1861
|
uiOverlays.openTranscriptTree = () => void openTranscriptTreeOverlay(pickerSvc);
|
|
1856
1862
|
uiOverlays.openUserMessageFork = () => void openUserMessageForkOverlay(pickerSvc);
|
|
1857
1863
|
uiOverlays.openScopedModels = () => void openScopedModelsOverlay(pickerSvc);
|
|
@@ -1959,7 +1965,7 @@ async function runTui(opts) {
|
|
|
1959
1965
|
const now = Date.now();
|
|
1960
1966
|
if (!isActiveRunStreamStale(state, now, 3e4)) return;
|
|
1961
1967
|
if (!markActiveRunStalled(state, now)) return;
|
|
1962
|
-
|
|
1968
|
+
state.progressMessage = "Reconnecting output";
|
|
1963
1969
|
setActivityStatus("stalled");
|
|
1964
1970
|
recoverActiveRunFromHistory("stream watchdog");
|
|
1965
1971
|
tui.requestRender();
|