@ai-agent-forge/agent-forge 0.88.2 → 0.88.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/README.md +1 -1
- package/bundled-plugins/agent-loop-policy/agent-forge.json +1 -1
- package/bundled-plugins/agent-loop-policy/plugin.json +1 -1
- package/bundled-plugins/coding-tools/agent-forge.json +1 -1
- package/bundled-plugins/coding-tools/plugin.json +1 -1
- package/bundled-plugins/compaction-policy/agent-forge.json +1 -1
- package/bundled-plugins/compaction-policy/plugin.json +1 -1
- package/bundled-plugins/overflow-policy/agent-forge.json +1 -1
- package/bundled-plugins/overflow-policy/plugin.json +1 -1
- package/bundled-plugins/provider-failover/agent-forge.json +1 -1
- package/bundled-plugins/provider-failover/plugin.json +1 -1
- package/bundled-plugins/retry-policy/agent-forge.json +1 -1
- package/bundled-plugins/retry-policy/plugin.json +1 -1
- package/dist/artifacts/paged-read.d.ts +6 -1
- package/dist/artifacts/paged-read.d.ts.map +1 -1
- package/dist/artifacts/paged-read.js.map +1 -1
- package/dist/bundle/.build-manifest.json +240 -230
- package/dist/bundle/chunks/{anthropic-messages-PLAKXR73.js → anthropic-messages-3FJHRAJL.js} +2 -2
- package/dist/bundle/chunks/anthropic.js +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-OUWQ2AZD.js → azure-openai-responses-GCL47IDS.js} +1 -1
- package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
- package/dist/bundle/chunks/{chunk-6F5JWGKE.js → chunk-32YDZI4J.js} +1 -1
- package/dist/bundle/chunks/{chunk-LSP24WNH.js → chunk-755VNWIF.js} +12 -12
- package/dist/bundle/chunks/{chunk-HTC5K5SM.js → chunk-B42Y2VME.js} +94 -89
- package/dist/bundle/chunks/{chunk-DRQDKNXA.js → chunk-BVVSHK6W.js} +1 -1
- package/dist/bundle/chunks/{chunk-6R7UI4IY.js → chunk-QDLOMKF6.js} +1 -1
- package/dist/bundle/chunks/{chunk-44I47ACN.js → chunk-V3ACW7VD.js} +1 -1
- package/dist/bundle/chunks/{google-generative-ai-DLII6DAT.js → google-generative-ai-6BMXWA44.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-G7BZL7GM.js → google-vertex-6H7NLRTK.js} +1 -1
- package/dist/bundle/chunks/image-resize-worker.js +1 -1
- package/dist/bundle/chunks/{mistral-conversations-JXUK24ID.js → mistral-conversations-IXUHSFSJ.js} +1 -1
- package/dist/bundle/chunks/{openai-codex-responses-5GSGFIPG.js → openai-codex-responses-YHUAEVCM.js} +1 -1
- package/dist/bundle/chunks/openai-codex.js +1 -1
- package/dist/bundle/chunks/{openai-completions-EI2I6DTG.js → openai-completions-ULQCFC72.js} +1 -1
- package/dist/bundle/chunks/openai-responses-NLLAJDPS.js +2 -0
- package/dist/bundle/chunks/{openrouter-images-G4GQRUSG.js → openrouter-images-GZZQZXMS.js} +1 -1
- package/dist/bundle/chunks/openrouter.js +1 -1
- package/dist/bundle/chunks/{pi-messages-PWU2VJMR.js → pi-messages-EJTI2EJ3.js} +1 -1
- package/dist/bundle/chunks/virtual-modules-TQWEGNNZ.js +5 -0
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/client.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.d.ts +0 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -4
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/experimental/cli.d.ts +3 -3
- package/dist/cli/experimental/cli.d.ts.map +1 -1
- package/dist/cli/experimental/cli.js +2 -2
- package/dist/cli/experimental/cli.js.map +1 -1
- package/dist/cli/experimental/commands/agent-forge.d.ts +15 -0
- package/dist/cli/experimental/commands/agent-forge.d.ts.map +1 -0
- package/dist/cli/experimental/commands/{pi.js → agent-forge.js} +4 -4
- package/dist/cli/experimental/commands/agent-forge.js.map +1 -0
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +1 -1
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/config.d.ts +4 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +7 -7
- package/dist/config.js.map +1 -1
- package/dist/core/agent-forge-manifest.d.ts +7 -0
- package/dist/core/agent-forge-manifest.d.ts.map +1 -0
- package/dist/core/{pi-manifest.js → agent-forge-manifest.js} +4 -4
- package/dist/core/agent-forge-manifest.js.map +1 -0
- package/dist/core/agent-session-compaction.d.ts +1 -1
- package/dist/core/agent-session-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-compaction.js +3 -3
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/agent-session-lifecycle.d.ts.map +1 -1
- package/dist/core/agent-session-lifecycle.js +12 -1
- package/dist/core/agent-session-lifecycle.js.map +1 -1
- package/dist/core/agent-session-projection.d.ts.map +1 -1
- package/dist/core/agent-session-projection.js +3 -3
- package/dist/core/agent-session-projection.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +1 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +1 -1
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +1 -1
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/experimental.d.ts.map +1 -1
- package/dist/core/experimental.js +1 -3
- package/dist/core/experimental.js.map +1 -1
- package/dist/core/extensions/capability-runtime-store.d.ts +20 -1
- package/dist/core/extensions/capability-runtime-store.d.ts.map +1 -1
- package/dist/core/extensions/capability-runtime-store.js +67 -0
- package/dist/core/extensions/capability-runtime-store.js.map +1 -1
- package/dist/core/extensions/capability-runtime-types.d.ts +14 -0
- package/dist/core/extensions/capability-runtime-types.d.ts.map +1 -1
- package/dist/core/extensions/capability-runtime-types.js +7 -1
- package/dist/core/extensions/capability-runtime-types.js.map +1 -1
- package/dist/core/extensions/capability-runtime.d.ts.map +1 -1
- package/dist/core/extensions/capability-runtime.js +144 -42
- package/dist/core/extensions/capability-runtime.js.map +1 -1
- package/dist/core/extensions/virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/virtual-modules.js +6 -1
- package/dist/core/extensions/virtual-modules.js.map +1 -1
- package/dist/core/facade/coding-agent-facade.d.ts +1 -1
- package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
- package/dist/core/facade/coding-agent-facade.js +1 -1
- package/dist/core/facade/coding-agent-facade.js.map +1 -1
- package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts +1 -1
- package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts.map +1 -1
- package/dist/core/i18n/locales/zh-cn/core-contract-final.js +3 -3
- package/dist/core/i18n/locales/zh-cn/core-contract-final.js.map +1 -1
- package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts.map +1 -1
- package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js +1 -1
- package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js.map +1 -1
- package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -1
- package/dist/core/i18n/locales/zh-cn/core-errors.js +1 -1
- package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -1
- package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts.map +1 -1
- package/dist/core/i18n/locales/zh-cn/tui-components-misc.js +2 -0
- package/dist/core/i18n/locales/zh-cn/tui-components-misc.js.map +1 -1
- package/dist/core/model-resolver.d.ts +2 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +4 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-resource-collection.d.ts.map +1 -1
- package/dist/core/package-resource-collection.js +5 -5
- package/dist/core/package-resource-collection.js.map +1 -1
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +3 -3
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +1 -1
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +6 -7
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +4 -4
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +5 -10
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js +1 -3
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +1 -1
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/tool-definition.d.ts +1 -1
- package/dist/core/tools/tool-definition.d.ts.map +1 -1
- package/dist/core/tools/tool-definition.js.map +1 -1
- package/dist/core/trace-retention.d.ts +16 -1
- package/dist/core/trace-retention.d.ts.map +1 -1
- package/dist/core/trace-retention.js +43 -20
- package/dist/core/trace-retention.js.map +1 -1
- package/dist/export-html/ansi-to-html.d.ts.map +1 -0
- package/dist/export-html/ansi-to-html.js.map +1 -0
- package/dist/{core/export-html → export-html}/index.d.ts +1 -1
- package/dist/export-html/index.d.ts.map +1 -0
- package/dist/{core/export-html → export-html}/index.js +5 -5
- package/dist/export-html/index.js.map +1 -0
- package/dist/{core/export-html → export-html}/tool-renderer.d.ts +2 -2
- package/dist/export-html/tool-renderer.d.ts.map +1 -0
- package/dist/export-html/tool-renderer.js.map +1 -0
- package/dist/{modes/interactive → host}/model-catalog-refresh.d.ts +1 -1
- package/dist/host/model-catalog-refresh.d.ts.map +1 -0
- package/dist/{modes/interactive → host}/model-catalog-refresh.js +1 -1
- package/dist/host/model-catalog-refresh.js.map +1 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -12
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +25 -14
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/agents-view.d.ts.map +1 -1
- package/dist/modes/interactive/components/agents-view.js +1 -1
- package/dist/modes/interactive/components/agents-view.js.map +1 -1
- package/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/dist/modes/interactive/components/armin.js +1 -1
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +3 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +83 -24
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +1 -1
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +1 -1
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-entry.js +1 -1
- package/dist/modes/interactive/components/custom-entry.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +1 -1
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
- package/dist/modes/interactive/components/daxnuts.js +1 -1
- package/dist/modes/interactive/components/daxnuts.js.map +1 -1
- package/dist/modes/interactive/components/dialog-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/dialog-editor.js +1 -1
- package/dist/modes/interactive/components/dialog-editor.js.map +1 -1
- package/dist/modes/interactive/components/dialog-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/dialog-input.js +1 -1
- package/dist/modes/interactive/components/dialog-input.js.map +1 -1
- package/dist/modes/interactive/components/dialog-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/dialog-selector.js +1 -1
- package/dist/modes/interactive/components/dialog-selector.js.map +1 -1
- package/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/dist/modes/interactive/components/diff.js +1 -1
- package/dist/modes/interactive/components/diff.js.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js +1 -1
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts +1 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.js +1 -1
- package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +1 -1
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/mermaid.d.ts +1 -1
- package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
- package/dist/modes/interactive/components/mermaid.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +2 -2
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +1 -1
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/plugin-manager-entry.d.ts.map +1 -1
- package/dist/modes/interactive/components/plugin-manager-entry.js +1 -1
- package/dist/modes/interactive/components/plugin-manager-entry.js.map +1 -1
- package/dist/modes/interactive/components/plugin-selection-entry.d.ts.map +1 -1
- package/dist/modes/interactive/components/plugin-selection-entry.js +1 -1
- package/dist/modes/interactive/components/plugin-selection-entry.js.map +1 -1
- package/dist/modes/interactive/components/queue-manager-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/queue-manager-selector.js +1 -1
- package/dist/modes/interactive/components/queue-manager-selector.js.map +1 -1
- package/dist/modes/interactive/components/render-types.d.ts +1 -1
- package/dist/modes/interactive/components/render-types.d.ts.map +1 -1
- package/dist/modes/interactive/components/render-types.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +2 -2
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +1 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-submenu.js +1 -1
- package/dist/modes/interactive/components/settings-submenu.js.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.js +1 -1
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-indicator.js +1 -1
- package/dist/modes/interactive/components/status-indicator.js.map +1 -1
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/theme-selector.js +1 -1
- package/dist/modes/interactive/components/theme-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +1 -1
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +2 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +96 -4
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tool-run-group.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-run-group.js +1 -1
- package/dist/modes/interactive/components/tool-run-group.js.map +1 -1
- package/dist/modes/interactive/components/tree-list.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-list.js +1 -1
- package/dist/modes/interactive/components/tree-list.js.map +1 -1
- package/dist/modes/interactive/components/tree-render.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-render.js +1 -1
- package/dist/modes/interactive/components/tree-render.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +1 -1
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +1 -1
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +1 -1
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/components/workflow-view.d.ts.map +1 -1
- package/dist/modes/interactive/components/workflow-view.js +1 -1
- package/dist/modes/interactive/components/workflow-view.js.map +1 -1
- package/dist/modes/interactive/interactive-auth.d.ts +1 -1
- package/dist/modes/interactive/interactive-auth.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-auth.js +1 -1
- package/dist/modes/interactive/interactive-auth.js.map +1 -1
- package/dist/modes/interactive/interactive-commands.d.ts +123 -6
- package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-commands.js +691 -4
- package/dist/modes/interactive/interactive-commands.js.map +1 -1
- package/dist/modes/interactive/interactive-events.d.ts +174 -0
- package/dist/modes/interactive/interactive-events.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-events.js +704 -0
- package/dist/modes/interactive/interactive-events.js.map +1 -0
- package/dist/modes/interactive/interactive-format.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-format.js +1 -1
- package/dist/modes/interactive/interactive-format.js.map +1 -1
- package/dist/modes/interactive/interactive-lifecycle.d.ts +94 -0
- package/dist/modes/interactive/interactive-lifecycle.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-lifecycle.js +177 -0
- package/dist/modes/interactive/interactive-lifecycle.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +240 -133
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +251 -2159
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/interactive-queues.d.ts +96 -0
- package/dist/modes/interactive/interactive-queues.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-queues.js +183 -0
- package/dist/modes/interactive/interactive-queues.js.map +1 -0
- package/dist/modes/interactive/interactive-selectors.d.ts +95 -5
- package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-selectors.js +517 -6
- package/dist/modes/interactive/interactive-selectors.js.map +1 -1
- package/dist/modes/interactive/startup-services.d.ts +31 -0
- package/dist/modes/interactive/startup-services.d.ts.map +1 -0
- package/dist/modes/interactive/startup-services.js +123 -0
- package/dist/modes/interactive/startup-services.js.map +1 -0
- package/dist/modes/memory-preheat.d.ts +11 -0
- package/dist/modes/memory-preheat.d.ts.map +1 -0
- package/dist/modes/memory-preheat.js +20 -0
- package/dist/modes/memory-preheat.js.map +1 -0
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +3 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/remote/server-assembly.d.ts.map +1 -1
- package/dist/remote/server-assembly.js +7 -2
- package/dist/remote/server-assembly.js.map +1 -1
- package/dist/suites/builtin-suites.d.ts.map +1 -0
- package/dist/suites/builtin-suites.js.map +1 -0
- package/dist/suites/resolved-agent-profile.d.ts.map +1 -0
- package/dist/suites/resolved-agent-profile.js.map +1 -0
- package/dist/suites/suite-lifecycle.d.ts.map +1 -0
- package/dist/suites/suite-lifecycle.js.map +1 -0
- package/dist/suites/suite-loader.d.ts.map +1 -0
- package/dist/suites/suite-loader.js.map +1 -0
- package/dist/{modes/interactive/theme → theme}/dark.json +1 -1
- package/dist/{modes/interactive/theme → theme}/light.json +1 -1
- package/dist/{modes/interactive/theme → theme}/theme-controller.d.ts +1 -1
- package/dist/theme/theme-controller.d.ts.map +1 -0
- package/dist/{modes/interactive/theme → theme}/theme-controller.js +1 -1
- package/dist/theme/theme-controller.js.map +1 -0
- package/dist/{modes/interactive/theme → theme}/theme.d.ts +1 -1
- package/dist/theme/theme.d.ts.map +1 -0
- package/dist/{modes/interactive/theme → theme}/theme.js +5 -5
- package/dist/theme/theme.js.map +1 -0
- package/docs/compaction.md +7 -7
- package/docs/environment-variables.md +10 -4
- package/docs/keybindings.md +3 -3
- package/docs/models.md +17 -17
- package/docs/packages.md +1 -1
- package/docs/prompt-templates.md +1 -1
- package/docs/rpc.md +2 -2
- package/docs/sdk.md +5 -5
- package/docs/session-format.md +3 -3
- package/docs/settings.md +15 -1
- package/docs/shell-aliases.md +1 -1
- package/docs/skills.md +1 -1
- package/docs/terminal-setup.md +17 -17
- package/docs/themes.md +5 -5
- package/docs/tmux.md +4 -4
- package/docs/tui.md +1 -1
- package/docs/usage.md +292 -292
- package/docs/windows.md +1 -1
- package/examples/extensions/bash-spawn-hook/index.ts +1 -1
- package/examples/extensions/dynamic-resources/dynamic.json +1 -1
- package/examples/extensions/mcp-stdio/index.d.ts +64 -0
- package/examples/extensions/mcp-stdio/index.d.ts.map +1 -0
- package/examples/extensions/mcp-stdio/index.js +292 -0
- package/examples/extensions/mcp-stdio/index.js.map +1 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -6
- package/examples/extensions/with-deps/plugin.json +1 -1
- package/package.json +2 -2
- package/dist/bundle/chunks/openai-responses-AUJQ3NWT.js +0 -2
- package/dist/bundle/chunks/virtual-modules-MRXD3RWG.js +0 -5
- package/dist/cli/experimental/commands/pi.d.ts +0 -15
- package/dist/cli/experimental/commands/pi.d.ts.map +0 -1
- package/dist/cli/experimental/commands/pi.js.map +0 -1
- package/dist/core/export-html/ansi-to-html.d.ts.map +0 -1
- package/dist/core/export-html/ansi-to-html.js.map +0 -1
- package/dist/core/export-html/index.d.ts.map +0 -1
- package/dist/core/export-html/index.js.map +0 -1
- package/dist/core/export-html/tool-renderer.d.ts.map +0 -1
- package/dist/core/export-html/tool-renderer.js.map +0 -1
- package/dist/core/pi-manifest.d.ts +0 -7
- package/dist/core/pi-manifest.d.ts.map +0 -1
- package/dist/core/pi-manifest.js.map +0 -1
- package/dist/modes/interactive/model-catalog-refresh.d.ts.map +0 -1
- package/dist/modes/interactive/model-catalog-refresh.js.map +0 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +0 -1
- package/dist/modes/interactive/theme/theme-controller.js.map +0 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +0 -1
- package/dist/modes/interactive/theme/theme.js.map +0 -1
- package/dist/profiles/builtin-suites.d.ts.map +0 -1
- package/dist/profiles/builtin-suites.js.map +0 -1
- package/dist/profiles/resolved-agent-profile.d.ts.map +0 -1
- package/dist/profiles/resolved-agent-profile.js.map +0 -1
- package/dist/profiles/suite-lifecycle.d.ts.map +0 -1
- package/dist/profiles/suite-lifecycle.js.map +0 -1
- package/dist/profiles/suite-loader.d.ts.map +0 -1
- package/dist/profiles/suite-loader.js.map +0 -1
- package/dist/utils/deprecation.d.ts +0 -4
- package/dist/utils/deprecation.d.ts.map +0 -1
- package/dist/utils/deprecation.js +0 -13
- package/dist/utils/deprecation.js.map +0 -1
- /package/dist/{core/export-html → export-html}/ansi-to-html.d.ts +0 -0
- /package/dist/{core/export-html → export-html}/ansi-to-html.js +0 -0
- /package/dist/{core/export-html → export-html}/template.css +0 -0
- /package/dist/{core/export-html → export-html}/template.html +0 -0
- /package/dist/{core/export-html → export-html}/template.js +0 -0
- /package/dist/{core/export-html → export-html}/tool-renderer.js +0 -0
- /package/dist/{core/export-html → export-html}/vendor/highlight.min.js +0 -0
- /package/dist/{core/export-html → export-html}/vendor/marked.min.js +0 -0
- /package/dist/{profiles → suites}/builtin-suites.d.ts +0 -0
- /package/dist/{profiles → suites}/builtin-suites.js +0 -0
- /package/dist/{profiles → suites}/resolved-agent-profile.d.ts +0 -0
- /package/dist/{profiles → suites}/resolved-agent-profile.js +0 -0
- /package/dist/{profiles → suites}/suite-lifecycle.d.ts +0 -0
- /package/dist/{profiles → suites}/suite-lifecycle.js +0 -0
- /package/dist/{profiles → suites}/suite-loader.d.ts +0 -0
- /package/dist/{profiles → suites}/suite-loader.js +0 -0
- /package/dist/{modes/interactive/theme → theme}/theme-schema.json +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents-view.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/agents-view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAkB,SAAS,EAAyC,MAAM,kBAAkB,CAAC;AACpG,OAAO,KAAK,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAmCtG;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,MAAM,EAAE,CAcxF;AAqBD,MAAM,WAAW,gBAAgB;IAChC,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACpD,sFAAsF;IACtF,QAAQ,CAAC,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;IAC5E,oDAAoD;IACpD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,+BAA+B;IAC/B,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,qBAAa,mBAAoB,SAAQ,SAAS;IAC1C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAE5B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,IAAI,CAA6B;IACzC,OAAO,CAAC,IAAI,CAAgB;IAC5B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,MAAM,CAAK;IACnB,4EAA4E;IAC5E,OAAO,CAAC,MAAM,CAA0E;IACxF,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,YAAY,CAAO;IAC3B,OAAO,CAAC,QAAQ,CAAO;IAEvB,YAAY,MAAM,EAAE,gBAAgB,EAenC;IAED,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,SAAS;IAmBjB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,QAAQ;IAMhB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA2BlC;IAED,OAAO,CAAC,IAAI;IAMZ,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,UAAU;IAUlB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAqBjC;CACD","sourcesContent":["/**\n * Read-only subagent session browser (D-060 §3 /agents overlay).\n *\n * Lists this session's own subagent transcripts from the on-disk store\n * (`sessions/_agents/`, same summary source as the subagent_list model tool)\n * and shows one session's bounded timeline on demand. Everything here is\n * read-only: no steer, no cancel, no resume — operations stay with the\n * conversation and the subagent tools; this module never imports plugin code.\n *\n * Entries load lazily (one `readAgentSession` per session on entering detail);\n * a failed load renders as a detail header state instead of throwing.\n */\n\nimport { type Component, Container, getKeybindings, Text, truncateToWidth } from \"@agent-forge/tui\";\nimport type { AgentSessionReadV1, AgentSessionSummaryV1 } from \"../../../core/agent-session-store.ts\";\nimport { t } from \"../../../core/i18n/index.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, rawKeyHint } from \"./keybinding-hints.ts\";\n\n// ---------------------------------------------------------------------------\n// Entry timeline formatting (pure; exported for tests)\n// ---------------------------------------------------------------------------\n\nconst ENTRY_LINE_MAX_CHARS = 160;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Message text extraction mirrors SessionManager's session-file scan\n * (`extractTextContent` in core/session-manager.ts): string content verbatim,\n * block content joined over its `type: \"text\"` blocks.\n */\nfunction messageText(message: Record<string, unknown>): string | undefined {\n\tconst content = message.content;\n\tif (typeof content === \"string\") return content;\n\tif (!Array.isArray(content)) return undefined;\n\treturn content\n\t\t.filter((block): block is Record<string, unknown> => isRecord(block) && block.type === \"text\")\n\t\t.map((block) => (typeof block.text === \"string\" ? block.text : \"\"))\n\t\t.join(\" \");\n}\n\nfunction truncateLine(text: string): string {\n\treturn text.length > ENTRY_LINE_MAX_CHARS ? `${text.slice(0, ENTRY_LINE_MAX_CHARS - 1)}…` : text;\n}\n\n/**\n * One line per entry: message entries render as `[role] text`; anything else\n * renders as `[<type>] <json>` (or bare `[<type>]` when it has no JSON form),\n * each line capped at ~160 characters.\n */\nexport function formatAgentSessionEntries(entries: readonly unknown[]): readonly string[] {\n\tconst lines: string[] = [];\n\tfor (const entry of entries) {\n\t\tif (isRecord(entry) && entry.type === \"message\" && isRecord(entry.message)) {\n\t\t\tconst role = typeof entry.message.role === \"string\" ? entry.message.role : \"message\";\n\t\t\tconst text = messageText(entry.message);\n\t\t\tlines.push(truncateLine(text === undefined || text.length === 0 ? `[${role}]` : `[${role}] ${text}`));\n\t\t\tcontinue;\n\t\t}\n\t\tconst type = isRecord(entry) && typeof entry.type === \"string\" ? entry.type : \"entry\";\n\t\tconst json = JSON.stringify(entry);\n\t\tlines.push(truncateLine(json === undefined ? `[${type}]` : `[${type}] ${json}`));\n\t}\n\treturn Object.freeze(lines);\n}\n\n// ---------------------------------------------------------------------------\n// Component (list + detail)\n// ---------------------------------------------------------------------------\n\n/** Renders the visible row window; reads live state from the owning component. */\nclass AgentsRowsView implements Component {\n\tprivate view: AgentsViewComponent;\n\n\tconstructor(view: AgentsViewComponent) {\n\t\tthis.view = view;\n\t}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\treturn this.view.renderRows(width);\n\t}\n}\n\nexport interface AgentsViewConfig {\n\t/** Summaries of this session's subagent sessions (newest first, parent-scoped). */\n\treadonly sessions: readonly AgentSessionSummaryV1[];\n\t/** Bounded transcript loader (lazy: called once per session when entering detail). */\n\treadonly loadEntries: (sessionId: string) => AgentSessionReadV1 | undefined;\n\t/** Maximum visible rows before the list scrolls. */\n\treadonly maxRows: number;\n\t/** Request a TUI re-render. */\n\trequestRender?: () => void;\n}\n\nexport class AgentsViewComponent extends Container {\n\tpublic onClose?: () => void;\n\n\tprivate config: AgentsViewConfig;\n\tprivate mode: \"list\" | \"detail\" = \"list\";\n\tprivate rows: string[] = [];\n\tprivate selectedIndex = 0;\n\tprivate offset = 0;\n\t/** Detail state: the loaded view plus the list row to restore on return. */\n\tprivate detail: { view: AgentSessionReadV1 | undefined; listIndex: number } | undefined;\n\tprivate titleText: Text;\n\tprivate modeHintText: Text;\n\tprivate helpText: Text;\n\n\tconstructor(config: AgentsViewConfig) {\n\t\tsuper();\n\n\t\tthis.config = config;\n\t\tthis.titleText = new Text(theme.fg(\"accent\", theme.bold(` ${t(\"Subagent Sessions\")}`)), 1, 0);\n\t\tthis.modeHintText = new Text(\"\", 1, 0);\n\t\tthis.helpText = new Text(\"\", 1, 0);\n\t\tthis.updateModeTexts();\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(this.titleText);\n\t\tthis.addChild(this.modeHintText);\n\t\tthis.addChild(new AgentsRowsView(this));\n\t\tthis.addChild(this.helpText);\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tprivate updateModeTexts(): void {\n\t\tconst label = this.mode === \"list\" ? t(\"this session's subagents (newest first)\") : t(\"transcript (read-only)\");\n\t\tthis.modeHintText.setText(theme.fg(\"dim\", ` ${label}`));\n\t\tthis.helpText.setText(this.buildHelpLine());\n\t}\n\n\tprivate buildHelpLine(): string {\n\t\tconst parts = [rawKeyHint(\"↑↓\", t(\"move\"))];\n\t\tif (this.mode === \"list\") {\n\t\t\tparts.push(rawKeyHint(\"tab/l\", t(\"detail\")), keyHint(\"tui.select.confirm\", t(\"open\")));\n\t\t} else {\n\t\t\tparts.push(rawKeyHint(\"tab/l\", t(\"list\")));\n\t\t}\n\t\tparts.push(keyHint(\"tui.select.cancel\", this.mode === \"list\" ? t(\"close\") : t(\"back\")));\n\t\treturn ` ${parts.join(\" \")}`;\n\t}\n\n\tprivate formatSummaryRow(summary: AgentSessionSummaryV1): string {\n\t\tconst role = summary.agentRole ?? \"-\";\n\t\tconst id = summary.sessionId.slice(0, 8);\n\t\tconst modified = new Date(summary.modifiedAt).toLocaleString();\n\t\treturn ` ${role} ${id} ${modified} ${summary.bytes}B`;\n\t}\n\n\tprivate buildDetailHeader(view: AgentSessionReadV1): string[] {\n\t\tconst identity = [t(\"session {sessionId}\", { sessionId: view.sessionId })];\n\t\tif (view.agentRole !== undefined) identity.push(t(\"role {role}\", { role: view.agentRole }));\n\t\tconst facts: string[] = [];\n\t\tif (view.createdAt !== undefined) {\n\t\t\tfacts.push(t(\"created {createdAt}\", { createdAt: view.createdAt }));\n\t\t}\n\t\tfacts.push(`${view.bytes}B`, t(\"{count} entries\", { count: view.entryCount }));\n\t\tif (view.truncated) facts.push(theme.fg(\"warning\", t(\"truncated\")));\n\t\treturn [` ${identity.join(\" · \")}`, ` ${facts.join(\" · \")}`];\n\t}\n\n\tprivate buildRows(): string[] {\n\t\tif (this.mode === \"detail\") {\n\t\t\tif (this.detail === undefined) return [` ${t(\"no session selected\")}`];\n\t\t\tconst view = this.detail.view;\n\t\t\tif (view === undefined) {\n\t\t\t\tconst sessionId = this.config.sessions[this.detail.listIndex]?.sessionId ?? \"?\";\n\t\t\t\treturn [\n\t\t\t\t\t` ${t(\"session {sessionId}\", { sessionId })} — ${theme.fg(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\tt(\"transcript unavailable (missing or unreadable)\"),\n\t\t\t\t\t)}`,\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn [...this.buildDetailHeader(view), ...formatAgentSessionEntries(view.entries)];\n\t\t}\n\t\tif (this.config.sessions.length === 0) return [` ${t(\"no subagent sessions in this session\")}`];\n\t\treturn this.config.sessions.map((summary) => this.formatSummaryRow(summary));\n\t}\n\n\tprivate clampOffset(): void {\n\t\tconst maxRows = Math.max(1, this.config.maxRows);\n\t\tif (this.selectedIndex < this.offset) this.offset = this.selectedIndex;\n\t\tif (this.selectedIndex >= this.offset + maxRows) this.offset = this.selectedIndex - maxRows + 1;\n\t\tif (this.offset < 0) this.offset = 0;\n\t}\n\n\tprivate syncRows(): void {\n\t\tthis.rows = this.buildRows();\n\t\tif (this.selectedIndex >= this.rows.length) this.selectedIndex = Math.max(0, this.rows.length - 1);\n\t\tthis.clampOffset();\n\t}\n\n\trenderRows(width: number): string[] {\n\t\tthis.syncRows();\n\t\tconst maxRows = Math.max(1, this.config.maxRows);\n\t\tconst lines: string[] = [];\n\t\tfor (let index = this.offset; index < Math.min(this.rows.length, this.offset + maxRows); index++) {\n\t\t\tconst row = this.rows[index];\n\t\t\tif (row === undefined) continue;\n\t\t\tconst selected = index === this.selectedIndex;\n\t\t\tconst prefix = selected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tlines.push(truncateToWidth(`${prefix}${row}`, width));\n\t\t}\n\t\tconst hiddenAbove = this.offset;\n\t\tconst hiddenBelow = this.rows.length - this.offset - maxRows;\n\t\tconst hidden: string[] = [];\n\t\tif (hiddenAbove > 0) hidden.push(`↑${hiddenAbove}`);\n\t\tif (hiddenBelow > 0) hidden.push(`↓${hiddenBelow}`);\n\t\t// Fixed output height (exactly maxRows content rows plus this last\n\t\t// row): the overlay's grid footprint must not shrink with mode\n\t\t// switches or row counts. A height change moves the chat/editor\n\t\t// layout boundary between frames, and every boundary shift now\n\t\t// forces the renderer's geometry guard into a full redraw (see\n\t\t// tui-alt-screen.ts doRender); constant-height output keeps pure\n\t\t// mode switches on the cheap incremental diff path. Padding rows\n\t\t// carry a real space so the indicator row position stays stable.\n\t\twhile (lines.length < maxRows) lines.push(truncateToWidth(\" \", width));\n\t\tlines.push(truncateToWidth(hidden.length > 0 ? theme.fg(\"dim\", ` ${hidden.join(\" \")}`) : \" \", width));\n\t\treturn lines;\n\t}\n\n\tprivate move(delta: number): void {\n\t\tif (this.rows.length === 0) return;\n\t\tthis.selectedIndex = Math.min(this.rows.length - 1, Math.max(0, this.selectedIndex + delta));\n\t\tthis.clampOffset();\n\t}\n\n\tprivate enterDetail(): void {\n\t\tconst summary = this.config.sessions[this.selectedIndex];\n\t\tif (summary === undefined) return;\n\t\tthis.detail = { view: this.config.loadEntries(summary.sessionId), listIndex: this.selectedIndex };\n\t\tthis.mode = \"detail\";\n\t\tthis.selectedIndex = 0;\n\t\tthis.offset = 0;\n\t\tthis.updateModeTexts();\n\t\tthis.config.requestRender?.();\n\t}\n\n\tprivate exitDetail(): void {\n\t\tconst restore = this.detail?.listIndex ?? 0;\n\t\tthis.detail = undefined;\n\t\tthis.mode = \"list\";\n\t\tthis.selectedIndex = restore;\n\t\tthis.clampOffset();\n\t\tthis.updateModeTexts();\n\t\tthis.config.requestRender?.();\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\t// Layered cancel (tree-list style): detail escapes to the list first;\n\t\t\t// only a list-mode cancel closes the overlay.\n\t\t\tif (this.mode === \"detail\") this.exitDetail();\n\t\t\telse this.onClose?.();\n\t\t} else if (kb.matches(keyData, \"tui.input.tab\") || keyData === \"l\") {\n\t\t\tif (this.mode === \"list\") this.enterDetail();\n\t\t\telse this.exitDetail();\n\t\t} else if (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tif (this.mode === \"list\") this.enterDetail();\n\t\t} else if (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n\t\t\tthis.move(-1);\n\t\t} else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n\t\t\tthis.move(1);\n\t\t} else if (kb.matches(keyData, \"tui.select.pageUp\")) {\n\t\t\tthis.move(-Math.max(1, this.config.maxRows));\n\t\t} else if (kb.matches(keyData, \"tui.select.pageDown\")) {\n\t\t\tthis.move(Math.max(1, this.config.maxRows));\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agents-view.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/agents-view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAkB,SAAS,EAAyC,MAAM,kBAAkB,CAAC;AACpG,OAAO,KAAK,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAmCtG;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,SAAS,OAAO,EAAE,GAAG,SAAS,MAAM,EAAE,CAcxF;AAqBD,MAAM,WAAW,gBAAgB;IAChC,mFAAmF;IACnF,QAAQ,CAAC,QAAQ,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACpD,sFAAsF;IACtF,QAAQ,CAAC,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS,CAAC;IAC5E,oDAAoD;IACpD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,+BAA+B;IAC/B,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,qBAAa,mBAAoB,SAAQ,SAAS;IAC1C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAE5B,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,IAAI,CAA6B;IACzC,OAAO,CAAC,IAAI,CAAgB;IAC5B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,MAAM,CAAK;IACnB,4EAA4E;IAC5E,OAAO,CAAC,MAAM,CAA0E;IACxF,OAAO,CAAC,SAAS,CAAO;IACxB,OAAO,CAAC,YAAY,CAAO;IAC3B,OAAO,CAAC,QAAQ,CAAO;IAEvB,YAAY,MAAM,EAAE,gBAAgB,EAenC;IAED,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,SAAS;IAmBjB,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,QAAQ;IAMhB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA2BlC;IAED,OAAO,CAAC,IAAI;IAMZ,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,UAAU;IAUlB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAqBjC;CACD","sourcesContent":["/**\n * Read-only subagent session browser (D-060 §3 /agents overlay).\n *\n * Lists this session's own subagent transcripts from the on-disk store\n * (`sessions/_agents/`, same summary source as the subagent_list model tool)\n * and shows one session's bounded timeline on demand. Everything here is\n * read-only: no steer, no cancel, no resume — operations stay with the\n * conversation and the subagent tools; this module never imports plugin code.\n *\n * Entries load lazily (one `readAgentSession` per session on entering detail);\n * a failed load renders as a detail header state instead of throwing.\n */\n\nimport { type Component, Container, getKeybindings, Text, truncateToWidth } from \"@agent-forge/tui\";\nimport type { AgentSessionReadV1, AgentSessionSummaryV1 } from \"../../../core/agent-session-store.ts\";\nimport { t } from \"../../../core/i18n/index.ts\";\nimport { theme } from \"../../../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, rawKeyHint } from \"./keybinding-hints.ts\";\n\n// ---------------------------------------------------------------------------\n// Entry timeline formatting (pure; exported for tests)\n// ---------------------------------------------------------------------------\n\nconst ENTRY_LINE_MAX_CHARS = 160;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Message text extraction mirrors SessionManager's session-file scan\n * (`extractTextContent` in core/session-manager.ts): string content verbatim,\n * block content joined over its `type: \"text\"` blocks.\n */\nfunction messageText(message: Record<string, unknown>): string | undefined {\n\tconst content = message.content;\n\tif (typeof content === \"string\") return content;\n\tif (!Array.isArray(content)) return undefined;\n\treturn content\n\t\t.filter((block): block is Record<string, unknown> => isRecord(block) && block.type === \"text\")\n\t\t.map((block) => (typeof block.text === \"string\" ? block.text : \"\"))\n\t\t.join(\" \");\n}\n\nfunction truncateLine(text: string): string {\n\treturn text.length > ENTRY_LINE_MAX_CHARS ? `${text.slice(0, ENTRY_LINE_MAX_CHARS - 1)}…` : text;\n}\n\n/**\n * One line per entry: message entries render as `[role] text`; anything else\n * renders as `[<type>] <json>` (or bare `[<type>]` when it has no JSON form),\n * each line capped at ~160 characters.\n */\nexport function formatAgentSessionEntries(entries: readonly unknown[]): readonly string[] {\n\tconst lines: string[] = [];\n\tfor (const entry of entries) {\n\t\tif (isRecord(entry) && entry.type === \"message\" && isRecord(entry.message)) {\n\t\t\tconst role = typeof entry.message.role === \"string\" ? entry.message.role : \"message\";\n\t\t\tconst text = messageText(entry.message);\n\t\t\tlines.push(truncateLine(text === undefined || text.length === 0 ? `[${role}]` : `[${role}] ${text}`));\n\t\t\tcontinue;\n\t\t}\n\t\tconst type = isRecord(entry) && typeof entry.type === \"string\" ? entry.type : \"entry\";\n\t\tconst json = JSON.stringify(entry);\n\t\tlines.push(truncateLine(json === undefined ? `[${type}]` : `[${type}] ${json}`));\n\t}\n\treturn Object.freeze(lines);\n}\n\n// ---------------------------------------------------------------------------\n// Component (list + detail)\n// ---------------------------------------------------------------------------\n\n/** Renders the visible row window; reads live state from the owning component. */\nclass AgentsRowsView implements Component {\n\tprivate view: AgentsViewComponent;\n\n\tconstructor(view: AgentsViewComponent) {\n\t\tthis.view = view;\n\t}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\treturn this.view.renderRows(width);\n\t}\n}\n\nexport interface AgentsViewConfig {\n\t/** Summaries of this session's subagent sessions (newest first, parent-scoped). */\n\treadonly sessions: readonly AgentSessionSummaryV1[];\n\t/** Bounded transcript loader (lazy: called once per session when entering detail). */\n\treadonly loadEntries: (sessionId: string) => AgentSessionReadV1 | undefined;\n\t/** Maximum visible rows before the list scrolls. */\n\treadonly maxRows: number;\n\t/** Request a TUI re-render. */\n\trequestRender?: () => void;\n}\n\nexport class AgentsViewComponent extends Container {\n\tpublic onClose?: () => void;\n\n\tprivate config: AgentsViewConfig;\n\tprivate mode: \"list\" | \"detail\" = \"list\";\n\tprivate rows: string[] = [];\n\tprivate selectedIndex = 0;\n\tprivate offset = 0;\n\t/** Detail state: the loaded view plus the list row to restore on return. */\n\tprivate detail: { view: AgentSessionReadV1 | undefined; listIndex: number } | undefined;\n\tprivate titleText: Text;\n\tprivate modeHintText: Text;\n\tprivate helpText: Text;\n\n\tconstructor(config: AgentsViewConfig) {\n\t\tsuper();\n\n\t\tthis.config = config;\n\t\tthis.titleText = new Text(theme.fg(\"accent\", theme.bold(` ${t(\"Subagent Sessions\")}`)), 1, 0);\n\t\tthis.modeHintText = new Text(\"\", 1, 0);\n\t\tthis.helpText = new Text(\"\", 1, 0);\n\t\tthis.updateModeTexts();\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(this.titleText);\n\t\tthis.addChild(this.modeHintText);\n\t\tthis.addChild(new AgentsRowsView(this));\n\t\tthis.addChild(this.helpText);\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tprivate updateModeTexts(): void {\n\t\tconst label = this.mode === \"list\" ? t(\"this session's subagents (newest first)\") : t(\"transcript (read-only)\");\n\t\tthis.modeHintText.setText(theme.fg(\"dim\", ` ${label}`));\n\t\tthis.helpText.setText(this.buildHelpLine());\n\t}\n\n\tprivate buildHelpLine(): string {\n\t\tconst parts = [rawKeyHint(\"↑↓\", t(\"move\"))];\n\t\tif (this.mode === \"list\") {\n\t\t\tparts.push(rawKeyHint(\"tab/l\", t(\"detail\")), keyHint(\"tui.select.confirm\", t(\"open\")));\n\t\t} else {\n\t\t\tparts.push(rawKeyHint(\"tab/l\", t(\"list\")));\n\t\t}\n\t\tparts.push(keyHint(\"tui.select.cancel\", this.mode === \"list\" ? t(\"close\") : t(\"back\")));\n\t\treturn ` ${parts.join(\" \")}`;\n\t}\n\n\tprivate formatSummaryRow(summary: AgentSessionSummaryV1): string {\n\t\tconst role = summary.agentRole ?? \"-\";\n\t\tconst id = summary.sessionId.slice(0, 8);\n\t\tconst modified = new Date(summary.modifiedAt).toLocaleString();\n\t\treturn ` ${role} ${id} ${modified} ${summary.bytes}B`;\n\t}\n\n\tprivate buildDetailHeader(view: AgentSessionReadV1): string[] {\n\t\tconst identity = [t(\"session {sessionId}\", { sessionId: view.sessionId })];\n\t\tif (view.agentRole !== undefined) identity.push(t(\"role {role}\", { role: view.agentRole }));\n\t\tconst facts: string[] = [];\n\t\tif (view.createdAt !== undefined) {\n\t\t\tfacts.push(t(\"created {createdAt}\", { createdAt: view.createdAt }));\n\t\t}\n\t\tfacts.push(`${view.bytes}B`, t(\"{count} entries\", { count: view.entryCount }));\n\t\tif (view.truncated) facts.push(theme.fg(\"warning\", t(\"truncated\")));\n\t\treturn [` ${identity.join(\" · \")}`, ` ${facts.join(\" · \")}`];\n\t}\n\n\tprivate buildRows(): string[] {\n\t\tif (this.mode === \"detail\") {\n\t\t\tif (this.detail === undefined) return [` ${t(\"no session selected\")}`];\n\t\t\tconst view = this.detail.view;\n\t\t\tif (view === undefined) {\n\t\t\t\tconst sessionId = this.config.sessions[this.detail.listIndex]?.sessionId ?? \"?\";\n\t\t\t\treturn [\n\t\t\t\t\t` ${t(\"session {sessionId}\", { sessionId })} — ${theme.fg(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\tt(\"transcript unavailable (missing or unreadable)\"),\n\t\t\t\t\t)}`,\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn [...this.buildDetailHeader(view), ...formatAgentSessionEntries(view.entries)];\n\t\t}\n\t\tif (this.config.sessions.length === 0) return [` ${t(\"no subagent sessions in this session\")}`];\n\t\treturn this.config.sessions.map((summary) => this.formatSummaryRow(summary));\n\t}\n\n\tprivate clampOffset(): void {\n\t\tconst maxRows = Math.max(1, this.config.maxRows);\n\t\tif (this.selectedIndex < this.offset) this.offset = this.selectedIndex;\n\t\tif (this.selectedIndex >= this.offset + maxRows) this.offset = this.selectedIndex - maxRows + 1;\n\t\tif (this.offset < 0) this.offset = 0;\n\t}\n\n\tprivate syncRows(): void {\n\t\tthis.rows = this.buildRows();\n\t\tif (this.selectedIndex >= this.rows.length) this.selectedIndex = Math.max(0, this.rows.length - 1);\n\t\tthis.clampOffset();\n\t}\n\n\trenderRows(width: number): string[] {\n\t\tthis.syncRows();\n\t\tconst maxRows = Math.max(1, this.config.maxRows);\n\t\tconst lines: string[] = [];\n\t\tfor (let index = this.offset; index < Math.min(this.rows.length, this.offset + maxRows); index++) {\n\t\t\tconst row = this.rows[index];\n\t\t\tif (row === undefined) continue;\n\t\t\tconst selected = index === this.selectedIndex;\n\t\t\tconst prefix = selected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tlines.push(truncateToWidth(`${prefix}${row}`, width));\n\t\t}\n\t\tconst hiddenAbove = this.offset;\n\t\tconst hiddenBelow = this.rows.length - this.offset - maxRows;\n\t\tconst hidden: string[] = [];\n\t\tif (hiddenAbove > 0) hidden.push(`↑${hiddenAbove}`);\n\t\tif (hiddenBelow > 0) hidden.push(`↓${hiddenBelow}`);\n\t\t// Fixed output height (exactly maxRows content rows plus this last\n\t\t// row): the overlay's grid footprint must not shrink with mode\n\t\t// switches or row counts. A height change moves the chat/editor\n\t\t// layout boundary between frames, and every boundary shift now\n\t\t// forces the renderer's geometry guard into a full redraw (see\n\t\t// tui-alt-screen.ts doRender); constant-height output keeps pure\n\t\t// mode switches on the cheap incremental diff path. Padding rows\n\t\t// carry a real space so the indicator row position stays stable.\n\t\twhile (lines.length < maxRows) lines.push(truncateToWidth(\" \", width));\n\t\tlines.push(truncateToWidth(hidden.length > 0 ? theme.fg(\"dim\", ` ${hidden.join(\" \")}`) : \" \", width));\n\t\treturn lines;\n\t}\n\n\tprivate move(delta: number): void {\n\t\tif (this.rows.length === 0) return;\n\t\tthis.selectedIndex = Math.min(this.rows.length - 1, Math.max(0, this.selectedIndex + delta));\n\t\tthis.clampOffset();\n\t}\n\n\tprivate enterDetail(): void {\n\t\tconst summary = this.config.sessions[this.selectedIndex];\n\t\tif (summary === undefined) return;\n\t\tthis.detail = { view: this.config.loadEntries(summary.sessionId), listIndex: this.selectedIndex };\n\t\tthis.mode = \"detail\";\n\t\tthis.selectedIndex = 0;\n\t\tthis.offset = 0;\n\t\tthis.updateModeTexts();\n\t\tthis.config.requestRender?.();\n\t}\n\n\tprivate exitDetail(): void {\n\t\tconst restore = this.detail?.listIndex ?? 0;\n\t\tthis.detail = undefined;\n\t\tthis.mode = \"list\";\n\t\tthis.selectedIndex = restore;\n\t\tthis.clampOffset();\n\t\tthis.updateModeTexts();\n\t\tthis.config.requestRender?.();\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\t// Layered cancel (tree-list style): detail escapes to the list first;\n\t\t\t// only a list-mode cancel closes the overlay.\n\t\t\tif (this.mode === \"detail\") this.exitDetail();\n\t\t\telse this.onClose?.();\n\t\t} else if (kb.matches(keyData, \"tui.input.tab\") || keyData === \"l\") {\n\t\t\tif (this.mode === \"list\") this.enterDetail();\n\t\t\telse this.exitDetail();\n\t\t} else if (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tif (this.mode === \"list\") this.enterDetail();\n\t\t} else if (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n\t\t\tthis.move(-1);\n\t\t} else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n\t\t\tthis.move(1);\n\t\t} else if (kb.matches(keyData, \"tui.select.pageUp\")) {\n\t\t\tthis.move(-Math.max(1, this.config.maxRows));\n\t\t} else if (kb.matches(keyData, \"tui.select.pageDown\")) {\n\t\t\tthis.move(Math.max(1, this.config.maxRows));\n\t\t}\n\t}\n}\n"]}
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { Container, getKeybindings, Text, truncateToWidth } from "@agent-forge/tui";
|
|
14
14
|
import { t } from "../../../core/i18n/index.js";
|
|
15
|
-
import { theme } from "
|
|
15
|
+
import { theme } from "../../../theme/theme.js";
|
|
16
16
|
import { DynamicBorder } from "./dynamic-border.js";
|
|
17
17
|
import { keyHint, rawKeyHint } from "./keybinding-hints.js";
|
|
18
18
|
// ---------------------------------------------------------------------------
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents-view.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/agents-view.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Read-only subagent session browser (D-060 §3 /agents overlay).\n *\n * Lists this session's own subagent transcripts from the on-disk store\n * (`sessions/_agents/`, same summary source as the subagent_list model tool)\n * and shows one session's bounded timeline on demand. Everything here is\n * read-only: no steer, no cancel, no resume — operations stay with the\n * conversation and the subagent tools; this module never imports plugin code.\n *\n * Entries load lazily (one `readAgentSession` per session on entering detail);\n * a failed load renders as a detail header state instead of throwing.\n */\n\nimport { type Component, Container, getKeybindings, Text, truncateToWidth } from \"@agent-forge/tui\";\nimport type { AgentSessionReadV1, AgentSessionSummaryV1 } from \"../../../core/agent-session-store.ts\";\nimport { t } from \"../../../core/i18n/index.ts\";\nimport { theme } from \"../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, rawKeyHint } from \"./keybinding-hints.ts\";\n\n// ---------------------------------------------------------------------------\n// Entry timeline formatting (pure; exported for tests)\n// ---------------------------------------------------------------------------\n\nconst ENTRY_LINE_MAX_CHARS = 160;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Message text extraction mirrors SessionManager's session-file scan\n * (`extractTextContent` in core/session-manager.ts): string content verbatim,\n * block content joined over its `type: \"text\"` blocks.\n */\nfunction messageText(message: Record<string, unknown>): string | undefined {\n\tconst content = message.content;\n\tif (typeof content === \"string\") return content;\n\tif (!Array.isArray(content)) return undefined;\n\treturn content\n\t\t.filter((block): block is Record<string, unknown> => isRecord(block) && block.type === \"text\")\n\t\t.map((block) => (typeof block.text === \"string\" ? block.text : \"\"))\n\t\t.join(\" \");\n}\n\nfunction truncateLine(text: string): string {\n\treturn text.length > ENTRY_LINE_MAX_CHARS ? `${text.slice(0, ENTRY_LINE_MAX_CHARS - 1)}…` : text;\n}\n\n/**\n * One line per entry: message entries render as `[role] text`; anything else\n * renders as `[<type>] <json>` (or bare `[<type>]` when it has no JSON form),\n * each line capped at ~160 characters.\n */\nexport function formatAgentSessionEntries(entries: readonly unknown[]): readonly string[] {\n\tconst lines: string[] = [];\n\tfor (const entry of entries) {\n\t\tif (isRecord(entry) && entry.type === \"message\" && isRecord(entry.message)) {\n\t\t\tconst role = typeof entry.message.role === \"string\" ? entry.message.role : \"message\";\n\t\t\tconst text = messageText(entry.message);\n\t\t\tlines.push(truncateLine(text === undefined || text.length === 0 ? `[${role}]` : `[${role}] ${text}`));\n\t\t\tcontinue;\n\t\t}\n\t\tconst type = isRecord(entry) && typeof entry.type === \"string\" ? entry.type : \"entry\";\n\t\tconst json = JSON.stringify(entry);\n\t\tlines.push(truncateLine(json === undefined ? `[${type}]` : `[${type}] ${json}`));\n\t}\n\treturn Object.freeze(lines);\n}\n\n// ---------------------------------------------------------------------------\n// Component (list + detail)\n// ---------------------------------------------------------------------------\n\n/** Renders the visible row window; reads live state from the owning component. */\nclass AgentsRowsView implements Component {\n\tprivate view: AgentsViewComponent;\n\n\tconstructor(view: AgentsViewComponent) {\n\t\tthis.view = view;\n\t}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\treturn this.view.renderRows(width);\n\t}\n}\n\nexport interface AgentsViewConfig {\n\t/** Summaries of this session's subagent sessions (newest first, parent-scoped). */\n\treadonly sessions: readonly AgentSessionSummaryV1[];\n\t/** Bounded transcript loader (lazy: called once per session when entering detail). */\n\treadonly loadEntries: (sessionId: string) => AgentSessionReadV1 | undefined;\n\t/** Maximum visible rows before the list scrolls. */\n\treadonly maxRows: number;\n\t/** Request a TUI re-render. */\n\trequestRender?: () => void;\n}\n\nexport class AgentsViewComponent extends Container {\n\tpublic onClose?: () => void;\n\n\tprivate config: AgentsViewConfig;\n\tprivate mode: \"list\" | \"detail\" = \"list\";\n\tprivate rows: string[] = [];\n\tprivate selectedIndex = 0;\n\tprivate offset = 0;\n\t/** Detail state: the loaded view plus the list row to restore on return. */\n\tprivate detail: { view: AgentSessionReadV1 | undefined; listIndex: number } | undefined;\n\tprivate titleText: Text;\n\tprivate modeHintText: Text;\n\tprivate helpText: Text;\n\n\tconstructor(config: AgentsViewConfig) {\n\t\tsuper();\n\n\t\tthis.config = config;\n\t\tthis.titleText = new Text(theme.fg(\"accent\", theme.bold(` ${t(\"Subagent Sessions\")}`)), 1, 0);\n\t\tthis.modeHintText = new Text(\"\", 1, 0);\n\t\tthis.helpText = new Text(\"\", 1, 0);\n\t\tthis.updateModeTexts();\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(this.titleText);\n\t\tthis.addChild(this.modeHintText);\n\t\tthis.addChild(new AgentsRowsView(this));\n\t\tthis.addChild(this.helpText);\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tprivate updateModeTexts(): void {\n\t\tconst label = this.mode === \"list\" ? t(\"this session's subagents (newest first)\") : t(\"transcript (read-only)\");\n\t\tthis.modeHintText.setText(theme.fg(\"dim\", ` ${label}`));\n\t\tthis.helpText.setText(this.buildHelpLine());\n\t}\n\n\tprivate buildHelpLine(): string {\n\t\tconst parts = [rawKeyHint(\"↑↓\", t(\"move\"))];\n\t\tif (this.mode === \"list\") {\n\t\t\tparts.push(rawKeyHint(\"tab/l\", t(\"detail\")), keyHint(\"tui.select.confirm\", t(\"open\")));\n\t\t} else {\n\t\t\tparts.push(rawKeyHint(\"tab/l\", t(\"list\")));\n\t\t}\n\t\tparts.push(keyHint(\"tui.select.cancel\", this.mode === \"list\" ? t(\"close\") : t(\"back\")));\n\t\treturn ` ${parts.join(\" \")}`;\n\t}\n\n\tprivate formatSummaryRow(summary: AgentSessionSummaryV1): string {\n\t\tconst role = summary.agentRole ?? \"-\";\n\t\tconst id = summary.sessionId.slice(0, 8);\n\t\tconst modified = new Date(summary.modifiedAt).toLocaleString();\n\t\treturn ` ${role} ${id} ${modified} ${summary.bytes}B`;\n\t}\n\n\tprivate buildDetailHeader(view: AgentSessionReadV1): string[] {\n\t\tconst identity = [t(\"session {sessionId}\", { sessionId: view.sessionId })];\n\t\tif (view.agentRole !== undefined) identity.push(t(\"role {role}\", { role: view.agentRole }));\n\t\tconst facts: string[] = [];\n\t\tif (view.createdAt !== undefined) {\n\t\t\tfacts.push(t(\"created {createdAt}\", { createdAt: view.createdAt }));\n\t\t}\n\t\tfacts.push(`${view.bytes}B`, t(\"{count} entries\", { count: view.entryCount }));\n\t\tif (view.truncated) facts.push(theme.fg(\"warning\", t(\"truncated\")));\n\t\treturn [` ${identity.join(\" · \")}`, ` ${facts.join(\" · \")}`];\n\t}\n\n\tprivate buildRows(): string[] {\n\t\tif (this.mode === \"detail\") {\n\t\t\tif (this.detail === undefined) return [` ${t(\"no session selected\")}`];\n\t\t\tconst view = this.detail.view;\n\t\t\tif (view === undefined) {\n\t\t\t\tconst sessionId = this.config.sessions[this.detail.listIndex]?.sessionId ?? \"?\";\n\t\t\t\treturn [\n\t\t\t\t\t` ${t(\"session {sessionId}\", { sessionId })} — ${theme.fg(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\tt(\"transcript unavailable (missing or unreadable)\"),\n\t\t\t\t\t)}`,\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn [...this.buildDetailHeader(view), ...formatAgentSessionEntries(view.entries)];\n\t\t}\n\t\tif (this.config.sessions.length === 0) return [` ${t(\"no subagent sessions in this session\")}`];\n\t\treturn this.config.sessions.map((summary) => this.formatSummaryRow(summary));\n\t}\n\n\tprivate clampOffset(): void {\n\t\tconst maxRows = Math.max(1, this.config.maxRows);\n\t\tif (this.selectedIndex < this.offset) this.offset = this.selectedIndex;\n\t\tif (this.selectedIndex >= this.offset + maxRows) this.offset = this.selectedIndex - maxRows + 1;\n\t\tif (this.offset < 0) this.offset = 0;\n\t}\n\n\tprivate syncRows(): void {\n\t\tthis.rows = this.buildRows();\n\t\tif (this.selectedIndex >= this.rows.length) this.selectedIndex = Math.max(0, this.rows.length - 1);\n\t\tthis.clampOffset();\n\t}\n\n\trenderRows(width: number): string[] {\n\t\tthis.syncRows();\n\t\tconst maxRows = Math.max(1, this.config.maxRows);\n\t\tconst lines: string[] = [];\n\t\tfor (let index = this.offset; index < Math.min(this.rows.length, this.offset + maxRows); index++) {\n\t\t\tconst row = this.rows[index];\n\t\t\tif (row === undefined) continue;\n\t\t\tconst selected = index === this.selectedIndex;\n\t\t\tconst prefix = selected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tlines.push(truncateToWidth(`${prefix}${row}`, width));\n\t\t}\n\t\tconst hiddenAbove = this.offset;\n\t\tconst hiddenBelow = this.rows.length - this.offset - maxRows;\n\t\tconst hidden: string[] = [];\n\t\tif (hiddenAbove > 0) hidden.push(`↑${hiddenAbove}`);\n\t\tif (hiddenBelow > 0) hidden.push(`↓${hiddenBelow}`);\n\t\t// Fixed output height (exactly maxRows content rows plus this last\n\t\t// row): the overlay's grid footprint must not shrink with mode\n\t\t// switches or row counts. A height change moves the chat/editor\n\t\t// layout boundary between frames, and every boundary shift now\n\t\t// forces the renderer's geometry guard into a full redraw (see\n\t\t// tui-alt-screen.ts doRender); constant-height output keeps pure\n\t\t// mode switches on the cheap incremental diff path. Padding rows\n\t\t// carry a real space so the indicator row position stays stable.\n\t\twhile (lines.length < maxRows) lines.push(truncateToWidth(\" \", width));\n\t\tlines.push(truncateToWidth(hidden.length > 0 ? theme.fg(\"dim\", ` ${hidden.join(\" \")}`) : \" \", width));\n\t\treturn lines;\n\t}\n\n\tprivate move(delta: number): void {\n\t\tif (this.rows.length === 0) return;\n\t\tthis.selectedIndex = Math.min(this.rows.length - 1, Math.max(0, this.selectedIndex + delta));\n\t\tthis.clampOffset();\n\t}\n\n\tprivate enterDetail(): void {\n\t\tconst summary = this.config.sessions[this.selectedIndex];\n\t\tif (summary === undefined) return;\n\t\tthis.detail = { view: this.config.loadEntries(summary.sessionId), listIndex: this.selectedIndex };\n\t\tthis.mode = \"detail\";\n\t\tthis.selectedIndex = 0;\n\t\tthis.offset = 0;\n\t\tthis.updateModeTexts();\n\t\tthis.config.requestRender?.();\n\t}\n\n\tprivate exitDetail(): void {\n\t\tconst restore = this.detail?.listIndex ?? 0;\n\t\tthis.detail = undefined;\n\t\tthis.mode = \"list\";\n\t\tthis.selectedIndex = restore;\n\t\tthis.clampOffset();\n\t\tthis.updateModeTexts();\n\t\tthis.config.requestRender?.();\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\t// Layered cancel (tree-list style): detail escapes to the list first;\n\t\t\t// only a list-mode cancel closes the overlay.\n\t\t\tif (this.mode === \"detail\") this.exitDetail();\n\t\t\telse this.onClose?.();\n\t\t} else if (kb.matches(keyData, \"tui.input.tab\") || keyData === \"l\") {\n\t\t\tif (this.mode === \"list\") this.enterDetail();\n\t\t\telse this.exitDetail();\n\t\t} else if (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tif (this.mode === \"list\") this.enterDetail();\n\t\t} else if (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n\t\t\tthis.move(-1);\n\t\t} else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n\t\t\tthis.move(1);\n\t\t} else if (kb.matches(keyData, \"tui.select.pageUp\")) {\n\t\t\tthis.move(-Math.max(1, this.config.maxRows));\n\t\t} else if (kb.matches(keyData, \"tui.select.pageDown\")) {\n\t\t\tthis.move(Math.max(1, this.config.maxRows));\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agents-view.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/agents-view.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Read-only subagent session browser (D-060 §3 /agents overlay).\n *\n * Lists this session's own subagent transcripts from the on-disk store\n * (`sessions/_agents/`, same summary source as the subagent_list model tool)\n * and shows one session's bounded timeline on demand. Everything here is\n * read-only: no steer, no cancel, no resume — operations stay with the\n * conversation and the subagent tools; this module never imports plugin code.\n *\n * Entries load lazily (one `readAgentSession` per session on entering detail);\n * a failed load renders as a detail header state instead of throwing.\n */\n\nimport { type Component, Container, getKeybindings, Text, truncateToWidth } from \"@agent-forge/tui\";\nimport type { AgentSessionReadV1, AgentSessionSummaryV1 } from \"../../../core/agent-session-store.ts\";\nimport { t } from \"../../../core/i18n/index.ts\";\nimport { theme } from \"../../../theme/theme.ts\";\nimport { DynamicBorder } from \"./dynamic-border.ts\";\nimport { keyHint, rawKeyHint } from \"./keybinding-hints.ts\";\n\n// ---------------------------------------------------------------------------\n// Entry timeline formatting (pure; exported for tests)\n// ---------------------------------------------------------------------------\n\nconst ENTRY_LINE_MAX_CHARS = 160;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Message text extraction mirrors SessionManager's session-file scan\n * (`extractTextContent` in core/session-manager.ts): string content verbatim,\n * block content joined over its `type: \"text\"` blocks.\n */\nfunction messageText(message: Record<string, unknown>): string | undefined {\n\tconst content = message.content;\n\tif (typeof content === \"string\") return content;\n\tif (!Array.isArray(content)) return undefined;\n\treturn content\n\t\t.filter((block): block is Record<string, unknown> => isRecord(block) && block.type === \"text\")\n\t\t.map((block) => (typeof block.text === \"string\" ? block.text : \"\"))\n\t\t.join(\" \");\n}\n\nfunction truncateLine(text: string): string {\n\treturn text.length > ENTRY_LINE_MAX_CHARS ? `${text.slice(0, ENTRY_LINE_MAX_CHARS - 1)}…` : text;\n}\n\n/**\n * One line per entry: message entries render as `[role] text`; anything else\n * renders as `[<type>] <json>` (or bare `[<type>]` when it has no JSON form),\n * each line capped at ~160 characters.\n */\nexport function formatAgentSessionEntries(entries: readonly unknown[]): readonly string[] {\n\tconst lines: string[] = [];\n\tfor (const entry of entries) {\n\t\tif (isRecord(entry) && entry.type === \"message\" && isRecord(entry.message)) {\n\t\t\tconst role = typeof entry.message.role === \"string\" ? entry.message.role : \"message\";\n\t\t\tconst text = messageText(entry.message);\n\t\t\tlines.push(truncateLine(text === undefined || text.length === 0 ? `[${role}]` : `[${role}] ${text}`));\n\t\t\tcontinue;\n\t\t}\n\t\tconst type = isRecord(entry) && typeof entry.type === \"string\" ? entry.type : \"entry\";\n\t\tconst json = JSON.stringify(entry);\n\t\tlines.push(truncateLine(json === undefined ? `[${type}]` : `[${type}] ${json}`));\n\t}\n\treturn Object.freeze(lines);\n}\n\n// ---------------------------------------------------------------------------\n// Component (list + detail)\n// ---------------------------------------------------------------------------\n\n/** Renders the visible row window; reads live state from the owning component. */\nclass AgentsRowsView implements Component {\n\tprivate view: AgentsViewComponent;\n\n\tconstructor(view: AgentsViewComponent) {\n\t\tthis.view = view;\n\t}\n\n\tinvalidate(): void {}\n\n\trender(width: number): string[] {\n\t\treturn this.view.renderRows(width);\n\t}\n}\n\nexport interface AgentsViewConfig {\n\t/** Summaries of this session's subagent sessions (newest first, parent-scoped). */\n\treadonly sessions: readonly AgentSessionSummaryV1[];\n\t/** Bounded transcript loader (lazy: called once per session when entering detail). */\n\treadonly loadEntries: (sessionId: string) => AgentSessionReadV1 | undefined;\n\t/** Maximum visible rows before the list scrolls. */\n\treadonly maxRows: number;\n\t/** Request a TUI re-render. */\n\trequestRender?: () => void;\n}\n\nexport class AgentsViewComponent extends Container {\n\tpublic onClose?: () => void;\n\n\tprivate config: AgentsViewConfig;\n\tprivate mode: \"list\" | \"detail\" = \"list\";\n\tprivate rows: string[] = [];\n\tprivate selectedIndex = 0;\n\tprivate offset = 0;\n\t/** Detail state: the loaded view plus the list row to restore on return. */\n\tprivate detail: { view: AgentSessionReadV1 | undefined; listIndex: number } | undefined;\n\tprivate titleText: Text;\n\tprivate modeHintText: Text;\n\tprivate helpText: Text;\n\n\tconstructor(config: AgentsViewConfig) {\n\t\tsuper();\n\n\t\tthis.config = config;\n\t\tthis.titleText = new Text(theme.fg(\"accent\", theme.bold(` ${t(\"Subagent Sessions\")}`)), 1, 0);\n\t\tthis.modeHintText = new Text(\"\", 1, 0);\n\t\tthis.helpText = new Text(\"\", 1, 0);\n\t\tthis.updateModeTexts();\n\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(this.titleText);\n\t\tthis.addChild(this.modeHintText);\n\t\tthis.addChild(new AgentsRowsView(this));\n\t\tthis.addChild(this.helpText);\n\t\tthis.addChild(new DynamicBorder());\n\t}\n\n\tprivate updateModeTexts(): void {\n\t\tconst label = this.mode === \"list\" ? t(\"this session's subagents (newest first)\") : t(\"transcript (read-only)\");\n\t\tthis.modeHintText.setText(theme.fg(\"dim\", ` ${label}`));\n\t\tthis.helpText.setText(this.buildHelpLine());\n\t}\n\n\tprivate buildHelpLine(): string {\n\t\tconst parts = [rawKeyHint(\"↑↓\", t(\"move\"))];\n\t\tif (this.mode === \"list\") {\n\t\t\tparts.push(rawKeyHint(\"tab/l\", t(\"detail\")), keyHint(\"tui.select.confirm\", t(\"open\")));\n\t\t} else {\n\t\t\tparts.push(rawKeyHint(\"tab/l\", t(\"list\")));\n\t\t}\n\t\tparts.push(keyHint(\"tui.select.cancel\", this.mode === \"list\" ? t(\"close\") : t(\"back\")));\n\t\treturn ` ${parts.join(\" \")}`;\n\t}\n\n\tprivate formatSummaryRow(summary: AgentSessionSummaryV1): string {\n\t\tconst role = summary.agentRole ?? \"-\";\n\t\tconst id = summary.sessionId.slice(0, 8);\n\t\tconst modified = new Date(summary.modifiedAt).toLocaleString();\n\t\treturn ` ${role} ${id} ${modified} ${summary.bytes}B`;\n\t}\n\n\tprivate buildDetailHeader(view: AgentSessionReadV1): string[] {\n\t\tconst identity = [t(\"session {sessionId}\", { sessionId: view.sessionId })];\n\t\tif (view.agentRole !== undefined) identity.push(t(\"role {role}\", { role: view.agentRole }));\n\t\tconst facts: string[] = [];\n\t\tif (view.createdAt !== undefined) {\n\t\t\tfacts.push(t(\"created {createdAt}\", { createdAt: view.createdAt }));\n\t\t}\n\t\tfacts.push(`${view.bytes}B`, t(\"{count} entries\", { count: view.entryCount }));\n\t\tif (view.truncated) facts.push(theme.fg(\"warning\", t(\"truncated\")));\n\t\treturn [` ${identity.join(\" · \")}`, ` ${facts.join(\" · \")}`];\n\t}\n\n\tprivate buildRows(): string[] {\n\t\tif (this.mode === \"detail\") {\n\t\t\tif (this.detail === undefined) return [` ${t(\"no session selected\")}`];\n\t\t\tconst view = this.detail.view;\n\t\t\tif (view === undefined) {\n\t\t\t\tconst sessionId = this.config.sessions[this.detail.listIndex]?.sessionId ?? \"?\";\n\t\t\t\treturn [\n\t\t\t\t\t` ${t(\"session {sessionId}\", { sessionId })} — ${theme.fg(\n\t\t\t\t\t\t\"error\",\n\t\t\t\t\t\tt(\"transcript unavailable (missing or unreadable)\"),\n\t\t\t\t\t)}`,\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn [...this.buildDetailHeader(view), ...formatAgentSessionEntries(view.entries)];\n\t\t}\n\t\tif (this.config.sessions.length === 0) return [` ${t(\"no subagent sessions in this session\")}`];\n\t\treturn this.config.sessions.map((summary) => this.formatSummaryRow(summary));\n\t}\n\n\tprivate clampOffset(): void {\n\t\tconst maxRows = Math.max(1, this.config.maxRows);\n\t\tif (this.selectedIndex < this.offset) this.offset = this.selectedIndex;\n\t\tif (this.selectedIndex >= this.offset + maxRows) this.offset = this.selectedIndex - maxRows + 1;\n\t\tif (this.offset < 0) this.offset = 0;\n\t}\n\n\tprivate syncRows(): void {\n\t\tthis.rows = this.buildRows();\n\t\tif (this.selectedIndex >= this.rows.length) this.selectedIndex = Math.max(0, this.rows.length - 1);\n\t\tthis.clampOffset();\n\t}\n\n\trenderRows(width: number): string[] {\n\t\tthis.syncRows();\n\t\tconst maxRows = Math.max(1, this.config.maxRows);\n\t\tconst lines: string[] = [];\n\t\tfor (let index = this.offset; index < Math.min(this.rows.length, this.offset + maxRows); index++) {\n\t\t\tconst row = this.rows[index];\n\t\t\tif (row === undefined) continue;\n\t\t\tconst selected = index === this.selectedIndex;\n\t\t\tconst prefix = selected ? theme.fg(\"accent\", \"→ \") : \" \";\n\t\t\tlines.push(truncateToWidth(`${prefix}${row}`, width));\n\t\t}\n\t\tconst hiddenAbove = this.offset;\n\t\tconst hiddenBelow = this.rows.length - this.offset - maxRows;\n\t\tconst hidden: string[] = [];\n\t\tif (hiddenAbove > 0) hidden.push(`↑${hiddenAbove}`);\n\t\tif (hiddenBelow > 0) hidden.push(`↓${hiddenBelow}`);\n\t\t// Fixed output height (exactly maxRows content rows plus this last\n\t\t// row): the overlay's grid footprint must not shrink with mode\n\t\t// switches or row counts. A height change moves the chat/editor\n\t\t// layout boundary between frames, and every boundary shift now\n\t\t// forces the renderer's geometry guard into a full redraw (see\n\t\t// tui-alt-screen.ts doRender); constant-height output keeps pure\n\t\t// mode switches on the cheap incremental diff path. Padding rows\n\t\t// carry a real space so the indicator row position stays stable.\n\t\twhile (lines.length < maxRows) lines.push(truncateToWidth(\" \", width));\n\t\tlines.push(truncateToWidth(hidden.length > 0 ? theme.fg(\"dim\", ` ${hidden.join(\" \")}`) : \" \", width));\n\t\treturn lines;\n\t}\n\n\tprivate move(delta: number): void {\n\t\tif (this.rows.length === 0) return;\n\t\tthis.selectedIndex = Math.min(this.rows.length - 1, Math.max(0, this.selectedIndex + delta));\n\t\tthis.clampOffset();\n\t}\n\n\tprivate enterDetail(): void {\n\t\tconst summary = this.config.sessions[this.selectedIndex];\n\t\tif (summary === undefined) return;\n\t\tthis.detail = { view: this.config.loadEntries(summary.sessionId), listIndex: this.selectedIndex };\n\t\tthis.mode = \"detail\";\n\t\tthis.selectedIndex = 0;\n\t\tthis.offset = 0;\n\t\tthis.updateModeTexts();\n\t\tthis.config.requestRender?.();\n\t}\n\n\tprivate exitDetail(): void {\n\t\tconst restore = this.detail?.listIndex ?? 0;\n\t\tthis.detail = undefined;\n\t\tthis.mode = \"list\";\n\t\tthis.selectedIndex = restore;\n\t\tthis.clampOffset();\n\t\tthis.updateModeTexts();\n\t\tthis.config.requestRender?.();\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\t// Layered cancel (tree-list style): detail escapes to the list first;\n\t\t\t// only a list-mode cancel closes the overlay.\n\t\t\tif (this.mode === \"detail\") this.exitDetail();\n\t\t\telse this.onClose?.();\n\t\t} else if (kb.matches(keyData, \"tui.input.tab\") || keyData === \"l\") {\n\t\t\tif (this.mode === \"list\") this.enterDetail();\n\t\t\telse this.exitDetail();\n\t\t} else if (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tif (this.mode === \"list\") this.enterDetail();\n\t\t} else if (kb.matches(keyData, \"tui.select.up\") || keyData === \"k\") {\n\t\t\tthis.move(-1);\n\t\t} else if (kb.matches(keyData, \"tui.select.down\") || keyData === \"j\") {\n\t\t\tthis.move(1);\n\t\t} else if (kb.matches(keyData, \"tui.select.pageUp\")) {\n\t\t\tthis.move(-Math.max(1, this.config.maxRows));\n\t\t} else if (kb.matches(keyData, \"tui.select.pageDown\")) {\n\t\t\tthis.move(Math.max(1, this.config.maxRows));\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"armin.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/armin.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAwDvD,qBAAa,cAAe,YAAW,SAAS;IAC/C,OAAO,CAAC,EAAE,CAAM;IAChB,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,aAAa,CAAM;IAE3B,YAAY,EAAE,EAAE,GAAG,EAQlB;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAwB9B;IAED,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,UAAU;IAgElB,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,UAAU;IAsBlB,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,QAAQ;IAoDhB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,OAAO;IAoBf,OAAO,CAAC,UAAU;IAgClB,OAAO,CAAC,YAAY;IAapB,OAAO,CAAC,aAAa;IAIrB,OAAO,IAAI,IAAI,CAEd;CACD","sourcesContent":["/**\n * Armin says hi! A fun easter egg with animated XBM art.\n */\n\nimport type { Component, TUI } from \"@agent-forge/tui\";\nimport { theme } from \"../theme/theme.ts\";\n\n// XBM image: 31x36 pixels, LSB first, 1=background, 0=foreground\nconst WIDTH = 31;\nconst HEIGHT = 36;\nconst BITS = [\n\t0xff, 0xff, 0xff, 0x7f, 0xff, 0xf0, 0xff, 0x7f, 0xff, 0xed, 0xff, 0x7f, 0xff, 0xdb, 0xff, 0x7f, 0xff, 0xb7, 0xff,\n\t0x7f, 0xff, 0x77, 0xfe, 0x7f, 0x3f, 0xf8, 0xfe, 0x7f, 0xdf, 0xff, 0xfe, 0x7f, 0xdf, 0x3f, 0xfc, 0x7f, 0x9f, 0xc3,\n\t0xfb, 0x7f, 0x6f, 0xfc, 0xf4, 0x7f, 0xf7, 0x0f, 0xf7, 0x7f, 0xf7, 0xff, 0xf7, 0x7f, 0xf7, 0xff, 0xe3, 0x7f, 0xf7,\n\t0x07, 0xe8, 0x7f, 0xef, 0xf8, 0x67, 0x70, 0x0f, 0xff, 0xbb, 0x6f, 0xf1, 0x00, 0xd0, 0x5b, 0xfd, 0x3f, 0xec, 0x53,\n\t0xc1, 0xff, 0xef, 0x57, 0x9f, 0xfd, 0xee, 0x5f, 0x9f, 0xfc, 0xae, 0x5f, 0x1f, 0x78, 0xac, 0x5f, 0x3f, 0x00, 0x50,\n\t0x6c, 0x7f, 0x00, 0xdc, 0x77, 0xff, 0xc0, 0x3f, 0x78, 0xff, 0x01, 0xf8, 0x7f, 0xff, 0x03, 0x9c, 0x78, 0xff, 0x07,\n\t0x8c, 0x7c, 0xff, 0x0f, 0xce, 0x78, 0xff, 0xff, 0xcf, 0x7f, 0xff, 0xff, 0xcf, 0x78, 0xff, 0xff, 0xdf, 0x78, 0xff,\n\t0xff, 0xdf, 0x7d, 0xff, 0xff, 0x3f, 0x7e, 0xff, 0xff, 0xff, 0x7f,\n];\n\nconst BYTES_PER_ROW = Math.ceil(WIDTH / 8);\nconst DISPLAY_HEIGHT = Math.ceil(HEIGHT / 2); // Half-block rendering\n\ntype Effect = \"typewriter\" | \"scanline\" | \"rain\" | \"fade\" | \"crt\" | \"glitch\" | \"dissolve\";\n\nconst EFFECTS: Effect[] = [\"typewriter\", \"scanline\", \"rain\", \"fade\", \"crt\", \"glitch\", \"dissolve\"];\n\n// Get pixel at (x, y): true = foreground, false = background\nfunction getPixel(x: number, y: number): boolean {\n\t// v8 ignore next -- getPixel is never called with y beyond the bitmap height\n\tif (y >= HEIGHT) return false;\n\tconst byteIndex = y * BYTES_PER_ROW + Math.floor(x / 8);\n\tconst bitIndex = x % 8;\n\treturn ((BITS[byteIndex] >> bitIndex) & 1) === 0;\n}\n\n// Get the character for a cell (2 vertical pixels packed)\nfunction getChar(x: number, row: number): string {\n\tconst upper = getPixel(x, row * 2);\n\tconst lower = getPixel(x, row * 2 + 1);\n\tif (upper && lower) return \"█\";\n\tif (upper) return \"▀\";\n\tif (lower) return \"▄\";\n\treturn \" \";\n}\n\n// Build the final image grid\nfunction buildFinalGrid(): string[][] {\n\tconst grid: string[][] = [];\n\tfor (let row = 0; row < DISPLAY_HEIGHT; row++) {\n\t\tconst line: string[] = [];\n\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\tline.push(getChar(x, row));\n\t\t}\n\t\tgrid.push(line);\n\t}\n\treturn grid;\n}\n\nexport class ArminComponent implements Component {\n\tprivate ui: TUI;\n\tprivate interval: ReturnType<typeof setInterval> | null = null;\n\tprivate effect: Effect;\n\tprivate finalGrid: string[][];\n\tprivate currentGrid: string[][];\n\tprivate effectState: Record<string, unknown> = {};\n\tprivate cachedLines: string[] = [];\n\tprivate cachedWidth = 0;\n\tprivate gridVersion = 0;\n\tprivate cachedVersion = -1;\n\n\tconstructor(ui: TUI) {\n\t\tthis.ui = ui;\n\t\tthis.effect = EFFECTS[Math.floor(Math.random() * EFFECTS.length)];\n\t\tthis.finalGrid = buildFinalGrid();\n\t\tthis.currentGrid = this.createEmptyGrid();\n\n\t\tthis.initEffect();\n\t\tthis.startAnimation();\n\t}\n\n\tinvalidate(): void {\n\t\tthis.cachedWidth = 0;\n\t}\n\n\trender(width: number): string[] {\n\t\tif (width === this.cachedWidth && this.cachedVersion === this.gridVersion) {\n\t\t\treturn this.cachedLines;\n\t\t}\n\n\t\tconst padding = 1;\n\t\tconst availableWidth = width - padding;\n\n\t\tthis.cachedLines = this.currentGrid.map((row) => {\n\t\t\t// Clip row to available width before applying color\n\t\t\tconst clipped = row.slice(0, availableWidth).join(\"\");\n\t\t\tconst padRight = Math.max(0, width - padding - clipped.length);\n\t\t\treturn ` ${theme.fg(\"accent\", clipped)}${\" \".repeat(padRight)}`;\n\t\t});\n\n\t\t// Add \"ARMIN SAYS HI\" at the end\n\t\tconst message = \"ARMIN SAYS HI\";\n\t\tconst msgPadRight = Math.max(0, width - padding - message.length);\n\t\tthis.cachedLines.push(` ${theme.fg(\"accent\", message)}${\" \".repeat(msgPadRight)}`);\n\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedVersion = this.gridVersion;\n\n\t\treturn this.cachedLines;\n\t}\n\n\tprivate createEmptyGrid(): string[][] {\n\t\treturn Array.from({ length: DISPLAY_HEIGHT }, () => Array(WIDTH).fill(\" \"));\n\t}\n\n\tprivate initEffect(): void {\n\t\tswitch (this.effect) {\n\t\t\tcase \"typewriter\":\n\t\t\t\tthis.effectState = { pos: 0 };\n\t\t\t\tbreak;\n\t\t\tcase \"scanline\":\n\t\t\t\tthis.effectState = { row: 0 };\n\t\t\t\tbreak;\n\t\t\tcase \"rain\":\n\t\t\t\t// Track falling position for each column\n\t\t\t\tthis.effectState = {\n\t\t\t\t\tdrops: Array.from({ length: WIDTH }, () => ({\n\t\t\t\t\t\ty: -Math.floor(Math.random() * DISPLAY_HEIGHT * 2),\n\t\t\t\t\t\tsettled: 0,\n\t\t\t\t\t})),\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"fade\": {\n\t\t\t\t// Shuffle all pixel positions\n\t\t\t\tconst positions: [number, number][] = [];\n\t\t\t\tfor (let row = 0; row < DISPLAY_HEIGHT; row++) {\n\t\t\t\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\t\t\t\tpositions.push([row, x]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Fisher-Yates shuffle\n\t\t\t\tfor (let i = positions.length - 1; i > 0; i--) {\n\t\t\t\t\tconst j = Math.floor(Math.random() * (i + 1));\n\t\t\t\t\t[positions[i], positions[j]] = [positions[j], positions[i]];\n\t\t\t\t}\n\t\t\t\tthis.effectState = { positions, idx: 0 };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"crt\":\n\t\t\t\tthis.effectState = { expansion: 0 };\n\t\t\t\tbreak;\n\t\t\tcase \"glitch\":\n\t\t\t\tthis.effectState = { phase: 0, glitchFrames: 8 };\n\t\t\t\tbreak;\n\t\t\tcase \"dissolve\": {\n\t\t\t\t// Start with random noise\n\t\t\t\tthis.currentGrid = Array.from({ length: DISPLAY_HEIGHT }, () =>\n\t\t\t\t\tArray.from({ length: WIDTH }, () => {\n\t\t\t\t\t\tconst chars = [\" \", \"░\", \"▒\", \"▓\", \"█\", \"▀\", \"▄\"];\n\t\t\t\t\t\treturn chars[Math.floor(Math.random() * chars.length)];\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\t// Shuffle positions for gradual resolve\n\t\t\t\tconst dissolvePositions: [number, number][] = [];\n\t\t\t\tfor (let row = 0; row < DISPLAY_HEIGHT; row++) {\n\t\t\t\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\t\t\t\tdissolvePositions.push([row, x]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (let i = dissolvePositions.length - 1; i > 0; i--) {\n\t\t\t\t\tconst j = Math.floor(Math.random() * (i + 1));\n\t\t\t\t\t[dissolvePositions[i], dissolvePositions[j]] = [dissolvePositions[j], dissolvePositions[i]];\n\t\t\t\t}\n\t\t\t\tthis.effectState = { positions: dissolvePositions, idx: 0 };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate startAnimation(): void {\n\t\tconst fps = this.effect === \"glitch\" ? 60 : 30;\n\t\tthis.interval = setInterval(() => {\n\t\t\tconst done = this.tickEffect();\n\t\t\tthis.updateDisplay();\n\t\t\tthis.ui.requestRender();\n\t\t\tif (done) {\n\t\t\t\tthis.stopAnimation();\n\t\t\t}\n\t\t}, 1000 / fps);\n\t}\n\n\tprivate stopAnimation(): void {\n\t\tif (this.interval) {\n\t\t\tclearInterval(this.interval);\n\t\t\tthis.interval = null;\n\t\t}\n\t}\n\n\tprivate tickEffect(): boolean {\n\t\tswitch (this.effect) {\n\t\t\tcase \"typewriter\":\n\t\t\t\treturn this.tickTypewriter();\n\t\t\tcase \"scanline\":\n\t\t\t\treturn this.tickScanline();\n\t\t\tcase \"rain\":\n\t\t\t\treturn this.tickRain();\n\t\t\tcase \"fade\":\n\t\t\t\treturn this.tickFade();\n\t\t\tcase \"crt\":\n\t\t\t\treturn this.tickCrt();\n\t\t\tcase \"glitch\":\n\t\t\t\treturn this.tickGlitch();\n\t\t\tcase \"dissolve\":\n\t\t\t\treturn this.tickDissolve();\n\t\t\t// v8 ignore next -- switch is exhaustive over the effect union\n\t\t\tdefault:\n\t\t\t\treturn true;\n\t\t}\n\t}\n\n\tprivate tickTypewriter(): boolean {\n\t\tconst state = this.effectState as { pos: number };\n\t\tconst pixelsPerFrame = 3;\n\n\t\tfor (let i = 0; i < pixelsPerFrame; i++) {\n\t\t\tconst row = Math.floor(state.pos / WIDTH);\n\t\t\tconst x = state.pos % WIDTH;\n\t\t\tif (row >= DISPLAY_HEIGHT) return true;\n\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\tstate.pos++;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate tickScanline(): boolean {\n\t\tconst state = this.effectState as { row: number };\n\t\tif (state.row >= DISPLAY_HEIGHT) return true;\n\n\t\t// Copy row\n\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\tthis.currentGrid[state.row][x] = this.finalGrid[state.row][x];\n\t\t}\n\t\tstate.row++;\n\t\treturn false;\n\t}\n\n\tprivate tickRain(): boolean {\n\t\tconst state = this.effectState as {\n\t\t\tdrops: { y: number; settled: number }[];\n\t\t};\n\n\t\tlet allSettled = true;\n\t\tthis.currentGrid = this.createEmptyGrid();\n\n\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\tconst drop = state.drops[x];\n\n\t\t\t// Draw settled pixels\n\t\t\tfor (let row = DISPLAY_HEIGHT - 1; row >= DISPLAY_HEIGHT - drop.settled; row--) {\n\t\t\t\t// v8 ignore next -- settled height never exceeds the display, so rows stay non-negative\n\t\t\t\tif (row >= 0) {\n\t\t\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check if this column is done\n\t\t\tif (drop.settled >= DISPLAY_HEIGHT) continue;\n\n\t\t\tallSettled = false;\n\n\t\t\t// Find the target row for this column (lowest non-space pixel)\n\t\t\tlet targetRow = -1;\n\t\t\tfor (let row = DISPLAY_HEIGHT - 1 - drop.settled; row >= 0; row--) {\n\t\t\t\tif (this.finalGrid[row][x] !== \" \") {\n\t\t\t\t\ttargetRow = row;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Move drop down\n\t\t\tdrop.y++;\n\n\t\t\t// Draw falling drop\n\t\t\tif (drop.y >= 0 && drop.y < DISPLAY_HEIGHT) {\n\t\t\t\tif (targetRow >= 0 && drop.y >= targetRow) {\n\t\t\t\t\t// Settle\n\t\t\t\t\tdrop.settled = DISPLAY_HEIGHT - targetRow;\n\t\t\t\t\tdrop.y = -Math.floor(Math.random() * 5) - 1;\n\t\t\t\t} else {\n\t\t\t\t\t// Still falling\n\t\t\t\t\tthis.currentGrid[drop.y][x] = \"▓\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn allSettled;\n\t}\n\n\tprivate tickFade(): boolean {\n\t\tconst state = this.effectState as { positions: [number, number][]; idx: number };\n\t\tconst pixelsPerFrame = 15;\n\n\t\tfor (let i = 0; i < pixelsPerFrame; i++) {\n\t\t\tif (state.idx >= state.positions.length) return true;\n\t\t\tconst [row, x] = state.positions[state.idx];\n\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\tstate.idx++;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate tickCrt(): boolean {\n\t\tconst state = this.effectState as { expansion: number };\n\t\tconst midRow = Math.floor(DISPLAY_HEIGHT / 2);\n\n\t\tthis.currentGrid = this.createEmptyGrid();\n\n\t\t// Draw from middle expanding outward\n\t\tconst top = midRow - state.expansion;\n\t\tconst bottom = midRow + state.expansion;\n\n\t\tfor (let row = Math.max(0, top); row <= Math.min(DISPLAY_HEIGHT - 1, bottom); row++) {\n\t\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\t}\n\t\t}\n\n\t\tstate.expansion++;\n\t\treturn state.expansion > DISPLAY_HEIGHT;\n\t}\n\n\tprivate tickGlitch(): boolean {\n\t\tconst state = this.effectState as { phase: number; glitchFrames: number };\n\n\t\tif (state.phase < state.glitchFrames) {\n\t\t\t// Glitch phase: show corrupted version\n\t\t\tthis.currentGrid = this.finalGrid.map((row) => {\n\t\t\t\tconst offset = Math.floor(Math.random() * 7) - 3;\n\t\t\t\tconst glitchRow = [...row];\n\n\t\t\t\t// Random horizontal offset\n\t\t\t\tif (Math.random() < 0.3) {\n\t\t\t\t\tconst shifted = glitchRow.slice(offset).concat(glitchRow.slice(0, offset));\n\t\t\t\t\treturn shifted.slice(0, WIDTH);\n\t\t\t\t}\n\n\t\t\t\t// Random vertical swap\n\t\t\t\tif (Math.random() < 0.2) {\n\t\t\t\t\tconst swapRow = Math.floor(Math.random() * DISPLAY_HEIGHT);\n\t\t\t\t\treturn [...this.finalGrid[swapRow]];\n\t\t\t\t}\n\n\t\t\t\treturn glitchRow;\n\t\t\t});\n\t\t\tstate.phase++;\n\t\t\treturn false;\n\t\t}\n\n\t\t// Final frame: show clean image\n\t\tthis.currentGrid = this.finalGrid.map((row) => [...row]);\n\t\treturn true;\n\t}\n\n\tprivate tickDissolve(): boolean {\n\t\tconst state = this.effectState as { positions: [number, number][]; idx: number };\n\t\tconst pixelsPerFrame = 20;\n\n\t\tfor (let i = 0; i < pixelsPerFrame; i++) {\n\t\t\tif (state.idx >= state.positions.length) return true;\n\t\t\tconst [row, x] = state.positions[state.idx];\n\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\tstate.idx++;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.gridVersion++;\n\t}\n\n\tdispose(): void {\n\t\tthis.stopAnimation();\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"armin.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/armin.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAwDvD,qBAAa,cAAe,YAAW,SAAS;IAC/C,OAAO,CAAC,EAAE,CAAM;IAChB,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,aAAa,CAAM;IAE3B,YAAY,EAAE,EAAE,GAAG,EAQlB;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAwB9B;IAED,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,UAAU;IAgElB,OAAO,CAAC,cAAc;IAYtB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,UAAU;IAsBlB,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,YAAY;IAYpB,OAAO,CAAC,QAAQ;IAoDhB,OAAO,CAAC,QAAQ;IAahB,OAAO,CAAC,OAAO;IAoBf,OAAO,CAAC,UAAU;IAgClB,OAAO,CAAC,YAAY;IAapB,OAAO,CAAC,aAAa;IAIrB,OAAO,IAAI,IAAI,CAEd;CACD","sourcesContent":["/**\n * Armin says hi! A fun easter egg with animated XBM art.\n */\n\nimport type { Component, TUI } from \"@agent-forge/tui\";\nimport { theme } from \"../../../theme/theme.ts\";\n\n// XBM image: 31x36 pixels, LSB first, 1=background, 0=foreground\nconst WIDTH = 31;\nconst HEIGHT = 36;\nconst BITS = [\n\t0xff, 0xff, 0xff, 0x7f, 0xff, 0xf0, 0xff, 0x7f, 0xff, 0xed, 0xff, 0x7f, 0xff, 0xdb, 0xff, 0x7f, 0xff, 0xb7, 0xff,\n\t0x7f, 0xff, 0x77, 0xfe, 0x7f, 0x3f, 0xf8, 0xfe, 0x7f, 0xdf, 0xff, 0xfe, 0x7f, 0xdf, 0x3f, 0xfc, 0x7f, 0x9f, 0xc3,\n\t0xfb, 0x7f, 0x6f, 0xfc, 0xf4, 0x7f, 0xf7, 0x0f, 0xf7, 0x7f, 0xf7, 0xff, 0xf7, 0x7f, 0xf7, 0xff, 0xe3, 0x7f, 0xf7,\n\t0x07, 0xe8, 0x7f, 0xef, 0xf8, 0x67, 0x70, 0x0f, 0xff, 0xbb, 0x6f, 0xf1, 0x00, 0xd0, 0x5b, 0xfd, 0x3f, 0xec, 0x53,\n\t0xc1, 0xff, 0xef, 0x57, 0x9f, 0xfd, 0xee, 0x5f, 0x9f, 0xfc, 0xae, 0x5f, 0x1f, 0x78, 0xac, 0x5f, 0x3f, 0x00, 0x50,\n\t0x6c, 0x7f, 0x00, 0xdc, 0x77, 0xff, 0xc0, 0x3f, 0x78, 0xff, 0x01, 0xf8, 0x7f, 0xff, 0x03, 0x9c, 0x78, 0xff, 0x07,\n\t0x8c, 0x7c, 0xff, 0x0f, 0xce, 0x78, 0xff, 0xff, 0xcf, 0x7f, 0xff, 0xff, 0xcf, 0x78, 0xff, 0xff, 0xdf, 0x78, 0xff,\n\t0xff, 0xdf, 0x7d, 0xff, 0xff, 0x3f, 0x7e, 0xff, 0xff, 0xff, 0x7f,\n];\n\nconst BYTES_PER_ROW = Math.ceil(WIDTH / 8);\nconst DISPLAY_HEIGHT = Math.ceil(HEIGHT / 2); // Half-block rendering\n\ntype Effect = \"typewriter\" | \"scanline\" | \"rain\" | \"fade\" | \"crt\" | \"glitch\" | \"dissolve\";\n\nconst EFFECTS: Effect[] = [\"typewriter\", \"scanline\", \"rain\", \"fade\", \"crt\", \"glitch\", \"dissolve\"];\n\n// Get pixel at (x, y): true = foreground, false = background\nfunction getPixel(x: number, y: number): boolean {\n\t// v8 ignore next -- getPixel is never called with y beyond the bitmap height\n\tif (y >= HEIGHT) return false;\n\tconst byteIndex = y * BYTES_PER_ROW + Math.floor(x / 8);\n\tconst bitIndex = x % 8;\n\treturn ((BITS[byteIndex] >> bitIndex) & 1) === 0;\n}\n\n// Get the character for a cell (2 vertical pixels packed)\nfunction getChar(x: number, row: number): string {\n\tconst upper = getPixel(x, row * 2);\n\tconst lower = getPixel(x, row * 2 + 1);\n\tif (upper && lower) return \"█\";\n\tif (upper) return \"▀\";\n\tif (lower) return \"▄\";\n\treturn \" \";\n}\n\n// Build the final image grid\nfunction buildFinalGrid(): string[][] {\n\tconst grid: string[][] = [];\n\tfor (let row = 0; row < DISPLAY_HEIGHT; row++) {\n\t\tconst line: string[] = [];\n\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\tline.push(getChar(x, row));\n\t\t}\n\t\tgrid.push(line);\n\t}\n\treturn grid;\n}\n\nexport class ArminComponent implements Component {\n\tprivate ui: TUI;\n\tprivate interval: ReturnType<typeof setInterval> | null = null;\n\tprivate effect: Effect;\n\tprivate finalGrid: string[][];\n\tprivate currentGrid: string[][];\n\tprivate effectState: Record<string, unknown> = {};\n\tprivate cachedLines: string[] = [];\n\tprivate cachedWidth = 0;\n\tprivate gridVersion = 0;\n\tprivate cachedVersion = -1;\n\n\tconstructor(ui: TUI) {\n\t\tthis.ui = ui;\n\t\tthis.effect = EFFECTS[Math.floor(Math.random() * EFFECTS.length)];\n\t\tthis.finalGrid = buildFinalGrid();\n\t\tthis.currentGrid = this.createEmptyGrid();\n\n\t\tthis.initEffect();\n\t\tthis.startAnimation();\n\t}\n\n\tinvalidate(): void {\n\t\tthis.cachedWidth = 0;\n\t}\n\n\trender(width: number): string[] {\n\t\tif (width === this.cachedWidth && this.cachedVersion === this.gridVersion) {\n\t\t\treturn this.cachedLines;\n\t\t}\n\n\t\tconst padding = 1;\n\t\tconst availableWidth = width - padding;\n\n\t\tthis.cachedLines = this.currentGrid.map((row) => {\n\t\t\t// Clip row to available width before applying color\n\t\t\tconst clipped = row.slice(0, availableWidth).join(\"\");\n\t\t\tconst padRight = Math.max(0, width - padding - clipped.length);\n\t\t\treturn ` ${theme.fg(\"accent\", clipped)}${\" \".repeat(padRight)}`;\n\t\t});\n\n\t\t// Add \"ARMIN SAYS HI\" at the end\n\t\tconst message = \"ARMIN SAYS HI\";\n\t\tconst msgPadRight = Math.max(0, width - padding - message.length);\n\t\tthis.cachedLines.push(` ${theme.fg(\"accent\", message)}${\" \".repeat(msgPadRight)}`);\n\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedVersion = this.gridVersion;\n\n\t\treturn this.cachedLines;\n\t}\n\n\tprivate createEmptyGrid(): string[][] {\n\t\treturn Array.from({ length: DISPLAY_HEIGHT }, () => Array(WIDTH).fill(\" \"));\n\t}\n\n\tprivate initEffect(): void {\n\t\tswitch (this.effect) {\n\t\t\tcase \"typewriter\":\n\t\t\t\tthis.effectState = { pos: 0 };\n\t\t\t\tbreak;\n\t\t\tcase \"scanline\":\n\t\t\t\tthis.effectState = { row: 0 };\n\t\t\t\tbreak;\n\t\t\tcase \"rain\":\n\t\t\t\t// Track falling position for each column\n\t\t\t\tthis.effectState = {\n\t\t\t\t\tdrops: Array.from({ length: WIDTH }, () => ({\n\t\t\t\t\t\ty: -Math.floor(Math.random() * DISPLAY_HEIGHT * 2),\n\t\t\t\t\t\tsettled: 0,\n\t\t\t\t\t})),\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"fade\": {\n\t\t\t\t// Shuffle all pixel positions\n\t\t\t\tconst positions: [number, number][] = [];\n\t\t\t\tfor (let row = 0; row < DISPLAY_HEIGHT; row++) {\n\t\t\t\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\t\t\t\tpositions.push([row, x]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Fisher-Yates shuffle\n\t\t\t\tfor (let i = positions.length - 1; i > 0; i--) {\n\t\t\t\t\tconst j = Math.floor(Math.random() * (i + 1));\n\t\t\t\t\t[positions[i], positions[j]] = [positions[j], positions[i]];\n\t\t\t\t}\n\t\t\t\tthis.effectState = { positions, idx: 0 };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"crt\":\n\t\t\t\tthis.effectState = { expansion: 0 };\n\t\t\t\tbreak;\n\t\t\tcase \"glitch\":\n\t\t\t\tthis.effectState = { phase: 0, glitchFrames: 8 };\n\t\t\t\tbreak;\n\t\t\tcase \"dissolve\": {\n\t\t\t\t// Start with random noise\n\t\t\t\tthis.currentGrid = Array.from({ length: DISPLAY_HEIGHT }, () =>\n\t\t\t\t\tArray.from({ length: WIDTH }, () => {\n\t\t\t\t\t\tconst chars = [\" \", \"░\", \"▒\", \"▓\", \"█\", \"▀\", \"▄\"];\n\t\t\t\t\t\treturn chars[Math.floor(Math.random() * chars.length)];\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\t// Shuffle positions for gradual resolve\n\t\t\t\tconst dissolvePositions: [number, number][] = [];\n\t\t\t\tfor (let row = 0; row < DISPLAY_HEIGHT; row++) {\n\t\t\t\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\t\t\t\tdissolvePositions.push([row, x]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (let i = dissolvePositions.length - 1; i > 0; i--) {\n\t\t\t\t\tconst j = Math.floor(Math.random() * (i + 1));\n\t\t\t\t\t[dissolvePositions[i], dissolvePositions[j]] = [dissolvePositions[j], dissolvePositions[i]];\n\t\t\t\t}\n\t\t\t\tthis.effectState = { positions: dissolvePositions, idx: 0 };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate startAnimation(): void {\n\t\tconst fps = this.effect === \"glitch\" ? 60 : 30;\n\t\tthis.interval = setInterval(() => {\n\t\t\tconst done = this.tickEffect();\n\t\t\tthis.updateDisplay();\n\t\t\tthis.ui.requestRender();\n\t\t\tif (done) {\n\t\t\t\tthis.stopAnimation();\n\t\t\t}\n\t\t}, 1000 / fps);\n\t}\n\n\tprivate stopAnimation(): void {\n\t\tif (this.interval) {\n\t\t\tclearInterval(this.interval);\n\t\t\tthis.interval = null;\n\t\t}\n\t}\n\n\tprivate tickEffect(): boolean {\n\t\tswitch (this.effect) {\n\t\t\tcase \"typewriter\":\n\t\t\t\treturn this.tickTypewriter();\n\t\t\tcase \"scanline\":\n\t\t\t\treturn this.tickScanline();\n\t\t\tcase \"rain\":\n\t\t\t\treturn this.tickRain();\n\t\t\tcase \"fade\":\n\t\t\t\treturn this.tickFade();\n\t\t\tcase \"crt\":\n\t\t\t\treturn this.tickCrt();\n\t\t\tcase \"glitch\":\n\t\t\t\treturn this.tickGlitch();\n\t\t\tcase \"dissolve\":\n\t\t\t\treturn this.tickDissolve();\n\t\t\t// v8 ignore next -- switch is exhaustive over the effect union\n\t\t\tdefault:\n\t\t\t\treturn true;\n\t\t}\n\t}\n\n\tprivate tickTypewriter(): boolean {\n\t\tconst state = this.effectState as { pos: number };\n\t\tconst pixelsPerFrame = 3;\n\n\t\tfor (let i = 0; i < pixelsPerFrame; i++) {\n\t\t\tconst row = Math.floor(state.pos / WIDTH);\n\t\t\tconst x = state.pos % WIDTH;\n\t\t\tif (row >= DISPLAY_HEIGHT) return true;\n\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\tstate.pos++;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate tickScanline(): boolean {\n\t\tconst state = this.effectState as { row: number };\n\t\tif (state.row >= DISPLAY_HEIGHT) return true;\n\n\t\t// Copy row\n\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\tthis.currentGrid[state.row][x] = this.finalGrid[state.row][x];\n\t\t}\n\t\tstate.row++;\n\t\treturn false;\n\t}\n\n\tprivate tickRain(): boolean {\n\t\tconst state = this.effectState as {\n\t\t\tdrops: { y: number; settled: number }[];\n\t\t};\n\n\t\tlet allSettled = true;\n\t\tthis.currentGrid = this.createEmptyGrid();\n\n\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\tconst drop = state.drops[x];\n\n\t\t\t// Draw settled pixels\n\t\t\tfor (let row = DISPLAY_HEIGHT - 1; row >= DISPLAY_HEIGHT - drop.settled; row--) {\n\t\t\t\t// v8 ignore next -- settled height never exceeds the display, so rows stay non-negative\n\t\t\t\tif (row >= 0) {\n\t\t\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check if this column is done\n\t\t\tif (drop.settled >= DISPLAY_HEIGHT) continue;\n\n\t\t\tallSettled = false;\n\n\t\t\t// Find the target row for this column (lowest non-space pixel)\n\t\t\tlet targetRow = -1;\n\t\t\tfor (let row = DISPLAY_HEIGHT - 1 - drop.settled; row >= 0; row--) {\n\t\t\t\tif (this.finalGrid[row][x] !== \" \") {\n\t\t\t\t\ttargetRow = row;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Move drop down\n\t\t\tdrop.y++;\n\n\t\t\t// Draw falling drop\n\t\t\tif (drop.y >= 0 && drop.y < DISPLAY_HEIGHT) {\n\t\t\t\tif (targetRow >= 0 && drop.y >= targetRow) {\n\t\t\t\t\t// Settle\n\t\t\t\t\tdrop.settled = DISPLAY_HEIGHT - targetRow;\n\t\t\t\t\tdrop.y = -Math.floor(Math.random() * 5) - 1;\n\t\t\t\t} else {\n\t\t\t\t\t// Still falling\n\t\t\t\t\tthis.currentGrid[drop.y][x] = \"▓\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn allSettled;\n\t}\n\n\tprivate tickFade(): boolean {\n\t\tconst state = this.effectState as { positions: [number, number][]; idx: number };\n\t\tconst pixelsPerFrame = 15;\n\n\t\tfor (let i = 0; i < pixelsPerFrame; i++) {\n\t\t\tif (state.idx >= state.positions.length) return true;\n\t\t\tconst [row, x] = state.positions[state.idx];\n\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\tstate.idx++;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate tickCrt(): boolean {\n\t\tconst state = this.effectState as { expansion: number };\n\t\tconst midRow = Math.floor(DISPLAY_HEIGHT / 2);\n\n\t\tthis.currentGrid = this.createEmptyGrid();\n\n\t\t// Draw from middle expanding outward\n\t\tconst top = midRow - state.expansion;\n\t\tconst bottom = midRow + state.expansion;\n\n\t\tfor (let row = Math.max(0, top); row <= Math.min(DISPLAY_HEIGHT - 1, bottom); row++) {\n\t\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\t}\n\t\t}\n\n\t\tstate.expansion++;\n\t\treturn state.expansion > DISPLAY_HEIGHT;\n\t}\n\n\tprivate tickGlitch(): boolean {\n\t\tconst state = this.effectState as { phase: number; glitchFrames: number };\n\n\t\tif (state.phase < state.glitchFrames) {\n\t\t\t// Glitch phase: show corrupted version\n\t\t\tthis.currentGrid = this.finalGrid.map((row) => {\n\t\t\t\tconst offset = Math.floor(Math.random() * 7) - 3;\n\t\t\t\tconst glitchRow = [...row];\n\n\t\t\t\t// Random horizontal offset\n\t\t\t\tif (Math.random() < 0.3) {\n\t\t\t\t\tconst shifted = glitchRow.slice(offset).concat(glitchRow.slice(0, offset));\n\t\t\t\t\treturn shifted.slice(0, WIDTH);\n\t\t\t\t}\n\n\t\t\t\t// Random vertical swap\n\t\t\t\tif (Math.random() < 0.2) {\n\t\t\t\t\tconst swapRow = Math.floor(Math.random() * DISPLAY_HEIGHT);\n\t\t\t\t\treturn [...this.finalGrid[swapRow]];\n\t\t\t\t}\n\n\t\t\t\treturn glitchRow;\n\t\t\t});\n\t\t\tstate.phase++;\n\t\t\treturn false;\n\t\t}\n\n\t\t// Final frame: show clean image\n\t\tthis.currentGrid = this.finalGrid.map((row) => [...row]);\n\t\treturn true;\n\t}\n\n\tprivate tickDissolve(): boolean {\n\t\tconst state = this.effectState as { positions: [number, number][]; idx: number };\n\t\tconst pixelsPerFrame = 20;\n\n\t\tfor (let i = 0; i < pixelsPerFrame; i++) {\n\t\t\tif (state.idx >= state.positions.length) return true;\n\t\t\tconst [row, x] = state.positions[state.idx];\n\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\tstate.idx++;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.gridVersion++;\n\t}\n\n\tdispose(): void {\n\t\tthis.stopAnimation();\n\t}\n}\n"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Armin says hi! A fun easter egg with animated XBM art.
|
|
3
3
|
*/
|
|
4
|
-
import { theme } from "
|
|
4
|
+
import { theme } from "../../../theme/theme.js";
|
|
5
5
|
// XBM image: 31x36 pixels, LSB first, 1=background, 0=foreground
|
|
6
6
|
const WIDTH = 31;
|
|
7
7
|
const HEIGHT = 36;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"armin.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/armin.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Armin says hi! A fun easter egg with animated XBM art.\n */\n\nimport type { Component, TUI } from \"@agent-forge/tui\";\nimport { theme } from \"../theme/theme.ts\";\n\n// XBM image: 31x36 pixels, LSB first, 1=background, 0=foreground\nconst WIDTH = 31;\nconst HEIGHT = 36;\nconst BITS = [\n\t0xff, 0xff, 0xff, 0x7f, 0xff, 0xf0, 0xff, 0x7f, 0xff, 0xed, 0xff, 0x7f, 0xff, 0xdb, 0xff, 0x7f, 0xff, 0xb7, 0xff,\n\t0x7f, 0xff, 0x77, 0xfe, 0x7f, 0x3f, 0xf8, 0xfe, 0x7f, 0xdf, 0xff, 0xfe, 0x7f, 0xdf, 0x3f, 0xfc, 0x7f, 0x9f, 0xc3,\n\t0xfb, 0x7f, 0x6f, 0xfc, 0xf4, 0x7f, 0xf7, 0x0f, 0xf7, 0x7f, 0xf7, 0xff, 0xf7, 0x7f, 0xf7, 0xff, 0xe3, 0x7f, 0xf7,\n\t0x07, 0xe8, 0x7f, 0xef, 0xf8, 0x67, 0x70, 0x0f, 0xff, 0xbb, 0x6f, 0xf1, 0x00, 0xd0, 0x5b, 0xfd, 0x3f, 0xec, 0x53,\n\t0xc1, 0xff, 0xef, 0x57, 0x9f, 0xfd, 0xee, 0x5f, 0x9f, 0xfc, 0xae, 0x5f, 0x1f, 0x78, 0xac, 0x5f, 0x3f, 0x00, 0x50,\n\t0x6c, 0x7f, 0x00, 0xdc, 0x77, 0xff, 0xc0, 0x3f, 0x78, 0xff, 0x01, 0xf8, 0x7f, 0xff, 0x03, 0x9c, 0x78, 0xff, 0x07,\n\t0x8c, 0x7c, 0xff, 0x0f, 0xce, 0x78, 0xff, 0xff, 0xcf, 0x7f, 0xff, 0xff, 0xcf, 0x78, 0xff, 0xff, 0xdf, 0x78, 0xff,\n\t0xff, 0xdf, 0x7d, 0xff, 0xff, 0x3f, 0x7e, 0xff, 0xff, 0xff, 0x7f,\n];\n\nconst BYTES_PER_ROW = Math.ceil(WIDTH / 8);\nconst DISPLAY_HEIGHT = Math.ceil(HEIGHT / 2); // Half-block rendering\n\ntype Effect = \"typewriter\" | \"scanline\" | \"rain\" | \"fade\" | \"crt\" | \"glitch\" | \"dissolve\";\n\nconst EFFECTS: Effect[] = [\"typewriter\", \"scanline\", \"rain\", \"fade\", \"crt\", \"glitch\", \"dissolve\"];\n\n// Get pixel at (x, y): true = foreground, false = background\nfunction getPixel(x: number, y: number): boolean {\n\t// v8 ignore next -- getPixel is never called with y beyond the bitmap height\n\tif (y >= HEIGHT) return false;\n\tconst byteIndex = y * BYTES_PER_ROW + Math.floor(x / 8);\n\tconst bitIndex = x % 8;\n\treturn ((BITS[byteIndex] >> bitIndex) & 1) === 0;\n}\n\n// Get the character for a cell (2 vertical pixels packed)\nfunction getChar(x: number, row: number): string {\n\tconst upper = getPixel(x, row * 2);\n\tconst lower = getPixel(x, row * 2 + 1);\n\tif (upper && lower) return \"█\";\n\tif (upper) return \"▀\";\n\tif (lower) return \"▄\";\n\treturn \" \";\n}\n\n// Build the final image grid\nfunction buildFinalGrid(): string[][] {\n\tconst grid: string[][] = [];\n\tfor (let row = 0; row < DISPLAY_HEIGHT; row++) {\n\t\tconst line: string[] = [];\n\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\tline.push(getChar(x, row));\n\t\t}\n\t\tgrid.push(line);\n\t}\n\treturn grid;\n}\n\nexport class ArminComponent implements Component {\n\tprivate ui: TUI;\n\tprivate interval: ReturnType<typeof setInterval> | null = null;\n\tprivate effect: Effect;\n\tprivate finalGrid: string[][];\n\tprivate currentGrid: string[][];\n\tprivate effectState: Record<string, unknown> = {};\n\tprivate cachedLines: string[] = [];\n\tprivate cachedWidth = 0;\n\tprivate gridVersion = 0;\n\tprivate cachedVersion = -1;\n\n\tconstructor(ui: TUI) {\n\t\tthis.ui = ui;\n\t\tthis.effect = EFFECTS[Math.floor(Math.random() * EFFECTS.length)];\n\t\tthis.finalGrid = buildFinalGrid();\n\t\tthis.currentGrid = this.createEmptyGrid();\n\n\t\tthis.initEffect();\n\t\tthis.startAnimation();\n\t}\n\n\tinvalidate(): void {\n\t\tthis.cachedWidth = 0;\n\t}\n\n\trender(width: number): string[] {\n\t\tif (width === this.cachedWidth && this.cachedVersion === this.gridVersion) {\n\t\t\treturn this.cachedLines;\n\t\t}\n\n\t\tconst padding = 1;\n\t\tconst availableWidth = width - padding;\n\n\t\tthis.cachedLines = this.currentGrid.map((row) => {\n\t\t\t// Clip row to available width before applying color\n\t\t\tconst clipped = row.slice(0, availableWidth).join(\"\");\n\t\t\tconst padRight = Math.max(0, width - padding - clipped.length);\n\t\t\treturn ` ${theme.fg(\"accent\", clipped)}${\" \".repeat(padRight)}`;\n\t\t});\n\n\t\t// Add \"ARMIN SAYS HI\" at the end\n\t\tconst message = \"ARMIN SAYS HI\";\n\t\tconst msgPadRight = Math.max(0, width - padding - message.length);\n\t\tthis.cachedLines.push(` ${theme.fg(\"accent\", message)}${\" \".repeat(msgPadRight)}`);\n\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedVersion = this.gridVersion;\n\n\t\treturn this.cachedLines;\n\t}\n\n\tprivate createEmptyGrid(): string[][] {\n\t\treturn Array.from({ length: DISPLAY_HEIGHT }, () => Array(WIDTH).fill(\" \"));\n\t}\n\n\tprivate initEffect(): void {\n\t\tswitch (this.effect) {\n\t\t\tcase \"typewriter\":\n\t\t\t\tthis.effectState = { pos: 0 };\n\t\t\t\tbreak;\n\t\t\tcase \"scanline\":\n\t\t\t\tthis.effectState = { row: 0 };\n\t\t\t\tbreak;\n\t\t\tcase \"rain\":\n\t\t\t\t// Track falling position for each column\n\t\t\t\tthis.effectState = {\n\t\t\t\t\tdrops: Array.from({ length: WIDTH }, () => ({\n\t\t\t\t\t\ty: -Math.floor(Math.random() * DISPLAY_HEIGHT * 2),\n\t\t\t\t\t\tsettled: 0,\n\t\t\t\t\t})),\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"fade\": {\n\t\t\t\t// Shuffle all pixel positions\n\t\t\t\tconst positions: [number, number][] = [];\n\t\t\t\tfor (let row = 0; row < DISPLAY_HEIGHT; row++) {\n\t\t\t\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\t\t\t\tpositions.push([row, x]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Fisher-Yates shuffle\n\t\t\t\tfor (let i = positions.length - 1; i > 0; i--) {\n\t\t\t\t\tconst j = Math.floor(Math.random() * (i + 1));\n\t\t\t\t\t[positions[i], positions[j]] = [positions[j], positions[i]];\n\t\t\t\t}\n\t\t\t\tthis.effectState = { positions, idx: 0 };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"crt\":\n\t\t\t\tthis.effectState = { expansion: 0 };\n\t\t\t\tbreak;\n\t\t\tcase \"glitch\":\n\t\t\t\tthis.effectState = { phase: 0, glitchFrames: 8 };\n\t\t\t\tbreak;\n\t\t\tcase \"dissolve\": {\n\t\t\t\t// Start with random noise\n\t\t\t\tthis.currentGrid = Array.from({ length: DISPLAY_HEIGHT }, () =>\n\t\t\t\t\tArray.from({ length: WIDTH }, () => {\n\t\t\t\t\t\tconst chars = [\" \", \"░\", \"▒\", \"▓\", \"█\", \"▀\", \"▄\"];\n\t\t\t\t\t\treturn chars[Math.floor(Math.random() * chars.length)];\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\t// Shuffle positions for gradual resolve\n\t\t\t\tconst dissolvePositions: [number, number][] = [];\n\t\t\t\tfor (let row = 0; row < DISPLAY_HEIGHT; row++) {\n\t\t\t\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\t\t\t\tdissolvePositions.push([row, x]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (let i = dissolvePositions.length - 1; i > 0; i--) {\n\t\t\t\t\tconst j = Math.floor(Math.random() * (i + 1));\n\t\t\t\t\t[dissolvePositions[i], dissolvePositions[j]] = [dissolvePositions[j], dissolvePositions[i]];\n\t\t\t\t}\n\t\t\t\tthis.effectState = { positions: dissolvePositions, idx: 0 };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate startAnimation(): void {\n\t\tconst fps = this.effect === \"glitch\" ? 60 : 30;\n\t\tthis.interval = setInterval(() => {\n\t\t\tconst done = this.tickEffect();\n\t\t\tthis.updateDisplay();\n\t\t\tthis.ui.requestRender();\n\t\t\tif (done) {\n\t\t\t\tthis.stopAnimation();\n\t\t\t}\n\t\t}, 1000 / fps);\n\t}\n\n\tprivate stopAnimation(): void {\n\t\tif (this.interval) {\n\t\t\tclearInterval(this.interval);\n\t\t\tthis.interval = null;\n\t\t}\n\t}\n\n\tprivate tickEffect(): boolean {\n\t\tswitch (this.effect) {\n\t\t\tcase \"typewriter\":\n\t\t\t\treturn this.tickTypewriter();\n\t\t\tcase \"scanline\":\n\t\t\t\treturn this.tickScanline();\n\t\t\tcase \"rain\":\n\t\t\t\treturn this.tickRain();\n\t\t\tcase \"fade\":\n\t\t\t\treturn this.tickFade();\n\t\t\tcase \"crt\":\n\t\t\t\treturn this.tickCrt();\n\t\t\tcase \"glitch\":\n\t\t\t\treturn this.tickGlitch();\n\t\t\tcase \"dissolve\":\n\t\t\t\treturn this.tickDissolve();\n\t\t\t// v8 ignore next -- switch is exhaustive over the effect union\n\t\t\tdefault:\n\t\t\t\treturn true;\n\t\t}\n\t}\n\n\tprivate tickTypewriter(): boolean {\n\t\tconst state = this.effectState as { pos: number };\n\t\tconst pixelsPerFrame = 3;\n\n\t\tfor (let i = 0; i < pixelsPerFrame; i++) {\n\t\t\tconst row = Math.floor(state.pos / WIDTH);\n\t\t\tconst x = state.pos % WIDTH;\n\t\t\tif (row >= DISPLAY_HEIGHT) return true;\n\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\tstate.pos++;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate tickScanline(): boolean {\n\t\tconst state = this.effectState as { row: number };\n\t\tif (state.row >= DISPLAY_HEIGHT) return true;\n\n\t\t// Copy row\n\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\tthis.currentGrid[state.row][x] = this.finalGrid[state.row][x];\n\t\t}\n\t\tstate.row++;\n\t\treturn false;\n\t}\n\n\tprivate tickRain(): boolean {\n\t\tconst state = this.effectState as {\n\t\t\tdrops: { y: number; settled: number }[];\n\t\t};\n\n\t\tlet allSettled = true;\n\t\tthis.currentGrid = this.createEmptyGrid();\n\n\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\tconst drop = state.drops[x];\n\n\t\t\t// Draw settled pixels\n\t\t\tfor (let row = DISPLAY_HEIGHT - 1; row >= DISPLAY_HEIGHT - drop.settled; row--) {\n\t\t\t\t// v8 ignore next -- settled height never exceeds the display, so rows stay non-negative\n\t\t\t\tif (row >= 0) {\n\t\t\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check if this column is done\n\t\t\tif (drop.settled >= DISPLAY_HEIGHT) continue;\n\n\t\t\tallSettled = false;\n\n\t\t\t// Find the target row for this column (lowest non-space pixel)\n\t\t\tlet targetRow = -1;\n\t\t\tfor (let row = DISPLAY_HEIGHT - 1 - drop.settled; row >= 0; row--) {\n\t\t\t\tif (this.finalGrid[row][x] !== \" \") {\n\t\t\t\t\ttargetRow = row;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Move drop down\n\t\t\tdrop.y++;\n\n\t\t\t// Draw falling drop\n\t\t\tif (drop.y >= 0 && drop.y < DISPLAY_HEIGHT) {\n\t\t\t\tif (targetRow >= 0 && drop.y >= targetRow) {\n\t\t\t\t\t// Settle\n\t\t\t\t\tdrop.settled = DISPLAY_HEIGHT - targetRow;\n\t\t\t\t\tdrop.y = -Math.floor(Math.random() * 5) - 1;\n\t\t\t\t} else {\n\t\t\t\t\t// Still falling\n\t\t\t\t\tthis.currentGrid[drop.y][x] = \"▓\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn allSettled;\n\t}\n\n\tprivate tickFade(): boolean {\n\t\tconst state = this.effectState as { positions: [number, number][]; idx: number };\n\t\tconst pixelsPerFrame = 15;\n\n\t\tfor (let i = 0; i < pixelsPerFrame; i++) {\n\t\t\tif (state.idx >= state.positions.length) return true;\n\t\t\tconst [row, x] = state.positions[state.idx];\n\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\tstate.idx++;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate tickCrt(): boolean {\n\t\tconst state = this.effectState as { expansion: number };\n\t\tconst midRow = Math.floor(DISPLAY_HEIGHT / 2);\n\n\t\tthis.currentGrid = this.createEmptyGrid();\n\n\t\t// Draw from middle expanding outward\n\t\tconst top = midRow - state.expansion;\n\t\tconst bottom = midRow + state.expansion;\n\n\t\tfor (let row = Math.max(0, top); row <= Math.min(DISPLAY_HEIGHT - 1, bottom); row++) {\n\t\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\t}\n\t\t}\n\n\t\tstate.expansion++;\n\t\treturn state.expansion > DISPLAY_HEIGHT;\n\t}\n\n\tprivate tickGlitch(): boolean {\n\t\tconst state = this.effectState as { phase: number; glitchFrames: number };\n\n\t\tif (state.phase < state.glitchFrames) {\n\t\t\t// Glitch phase: show corrupted version\n\t\t\tthis.currentGrid = this.finalGrid.map((row) => {\n\t\t\t\tconst offset = Math.floor(Math.random() * 7) - 3;\n\t\t\t\tconst glitchRow = [...row];\n\n\t\t\t\t// Random horizontal offset\n\t\t\t\tif (Math.random() < 0.3) {\n\t\t\t\t\tconst shifted = glitchRow.slice(offset).concat(glitchRow.slice(0, offset));\n\t\t\t\t\treturn shifted.slice(0, WIDTH);\n\t\t\t\t}\n\n\t\t\t\t// Random vertical swap\n\t\t\t\tif (Math.random() < 0.2) {\n\t\t\t\t\tconst swapRow = Math.floor(Math.random() * DISPLAY_HEIGHT);\n\t\t\t\t\treturn [...this.finalGrid[swapRow]];\n\t\t\t\t}\n\n\t\t\t\treturn glitchRow;\n\t\t\t});\n\t\t\tstate.phase++;\n\t\t\treturn false;\n\t\t}\n\n\t\t// Final frame: show clean image\n\t\tthis.currentGrid = this.finalGrid.map((row) => [...row]);\n\t\treturn true;\n\t}\n\n\tprivate tickDissolve(): boolean {\n\t\tconst state = this.effectState as { positions: [number, number][]; idx: number };\n\t\tconst pixelsPerFrame = 20;\n\n\t\tfor (let i = 0; i < pixelsPerFrame; i++) {\n\t\t\tif (state.idx >= state.positions.length) return true;\n\t\t\tconst [row, x] = state.positions[state.idx];\n\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\tstate.idx++;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.gridVersion++;\n\t}\n\n\tdispose(): void {\n\t\tthis.stopAnimation();\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"armin.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/armin.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Armin says hi! A fun easter egg with animated XBM art.\n */\n\nimport type { Component, TUI } from \"@agent-forge/tui\";\nimport { theme } from \"../../../theme/theme.ts\";\n\n// XBM image: 31x36 pixels, LSB first, 1=background, 0=foreground\nconst WIDTH = 31;\nconst HEIGHT = 36;\nconst BITS = [\n\t0xff, 0xff, 0xff, 0x7f, 0xff, 0xf0, 0xff, 0x7f, 0xff, 0xed, 0xff, 0x7f, 0xff, 0xdb, 0xff, 0x7f, 0xff, 0xb7, 0xff,\n\t0x7f, 0xff, 0x77, 0xfe, 0x7f, 0x3f, 0xf8, 0xfe, 0x7f, 0xdf, 0xff, 0xfe, 0x7f, 0xdf, 0x3f, 0xfc, 0x7f, 0x9f, 0xc3,\n\t0xfb, 0x7f, 0x6f, 0xfc, 0xf4, 0x7f, 0xf7, 0x0f, 0xf7, 0x7f, 0xf7, 0xff, 0xf7, 0x7f, 0xf7, 0xff, 0xe3, 0x7f, 0xf7,\n\t0x07, 0xe8, 0x7f, 0xef, 0xf8, 0x67, 0x70, 0x0f, 0xff, 0xbb, 0x6f, 0xf1, 0x00, 0xd0, 0x5b, 0xfd, 0x3f, 0xec, 0x53,\n\t0xc1, 0xff, 0xef, 0x57, 0x9f, 0xfd, 0xee, 0x5f, 0x9f, 0xfc, 0xae, 0x5f, 0x1f, 0x78, 0xac, 0x5f, 0x3f, 0x00, 0x50,\n\t0x6c, 0x7f, 0x00, 0xdc, 0x77, 0xff, 0xc0, 0x3f, 0x78, 0xff, 0x01, 0xf8, 0x7f, 0xff, 0x03, 0x9c, 0x78, 0xff, 0x07,\n\t0x8c, 0x7c, 0xff, 0x0f, 0xce, 0x78, 0xff, 0xff, 0xcf, 0x7f, 0xff, 0xff, 0xcf, 0x78, 0xff, 0xff, 0xdf, 0x78, 0xff,\n\t0xff, 0xdf, 0x7d, 0xff, 0xff, 0x3f, 0x7e, 0xff, 0xff, 0xff, 0x7f,\n];\n\nconst BYTES_PER_ROW = Math.ceil(WIDTH / 8);\nconst DISPLAY_HEIGHT = Math.ceil(HEIGHT / 2); // Half-block rendering\n\ntype Effect = \"typewriter\" | \"scanline\" | \"rain\" | \"fade\" | \"crt\" | \"glitch\" | \"dissolve\";\n\nconst EFFECTS: Effect[] = [\"typewriter\", \"scanline\", \"rain\", \"fade\", \"crt\", \"glitch\", \"dissolve\"];\n\n// Get pixel at (x, y): true = foreground, false = background\nfunction getPixel(x: number, y: number): boolean {\n\t// v8 ignore next -- getPixel is never called with y beyond the bitmap height\n\tif (y >= HEIGHT) return false;\n\tconst byteIndex = y * BYTES_PER_ROW + Math.floor(x / 8);\n\tconst bitIndex = x % 8;\n\treturn ((BITS[byteIndex] >> bitIndex) & 1) === 0;\n}\n\n// Get the character for a cell (2 vertical pixels packed)\nfunction getChar(x: number, row: number): string {\n\tconst upper = getPixel(x, row * 2);\n\tconst lower = getPixel(x, row * 2 + 1);\n\tif (upper && lower) return \"█\";\n\tif (upper) return \"▀\";\n\tif (lower) return \"▄\";\n\treturn \" \";\n}\n\n// Build the final image grid\nfunction buildFinalGrid(): string[][] {\n\tconst grid: string[][] = [];\n\tfor (let row = 0; row < DISPLAY_HEIGHT; row++) {\n\t\tconst line: string[] = [];\n\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\tline.push(getChar(x, row));\n\t\t}\n\t\tgrid.push(line);\n\t}\n\treturn grid;\n}\n\nexport class ArminComponent implements Component {\n\tprivate ui: TUI;\n\tprivate interval: ReturnType<typeof setInterval> | null = null;\n\tprivate effect: Effect;\n\tprivate finalGrid: string[][];\n\tprivate currentGrid: string[][];\n\tprivate effectState: Record<string, unknown> = {};\n\tprivate cachedLines: string[] = [];\n\tprivate cachedWidth = 0;\n\tprivate gridVersion = 0;\n\tprivate cachedVersion = -1;\n\n\tconstructor(ui: TUI) {\n\t\tthis.ui = ui;\n\t\tthis.effect = EFFECTS[Math.floor(Math.random() * EFFECTS.length)];\n\t\tthis.finalGrid = buildFinalGrid();\n\t\tthis.currentGrid = this.createEmptyGrid();\n\n\t\tthis.initEffect();\n\t\tthis.startAnimation();\n\t}\n\n\tinvalidate(): void {\n\t\tthis.cachedWidth = 0;\n\t}\n\n\trender(width: number): string[] {\n\t\tif (width === this.cachedWidth && this.cachedVersion === this.gridVersion) {\n\t\t\treturn this.cachedLines;\n\t\t}\n\n\t\tconst padding = 1;\n\t\tconst availableWidth = width - padding;\n\n\t\tthis.cachedLines = this.currentGrid.map((row) => {\n\t\t\t// Clip row to available width before applying color\n\t\t\tconst clipped = row.slice(0, availableWidth).join(\"\");\n\t\t\tconst padRight = Math.max(0, width - padding - clipped.length);\n\t\t\treturn ` ${theme.fg(\"accent\", clipped)}${\" \".repeat(padRight)}`;\n\t\t});\n\n\t\t// Add \"ARMIN SAYS HI\" at the end\n\t\tconst message = \"ARMIN SAYS HI\";\n\t\tconst msgPadRight = Math.max(0, width - padding - message.length);\n\t\tthis.cachedLines.push(` ${theme.fg(\"accent\", message)}${\" \".repeat(msgPadRight)}`);\n\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedVersion = this.gridVersion;\n\n\t\treturn this.cachedLines;\n\t}\n\n\tprivate createEmptyGrid(): string[][] {\n\t\treturn Array.from({ length: DISPLAY_HEIGHT }, () => Array(WIDTH).fill(\" \"));\n\t}\n\n\tprivate initEffect(): void {\n\t\tswitch (this.effect) {\n\t\t\tcase \"typewriter\":\n\t\t\t\tthis.effectState = { pos: 0 };\n\t\t\t\tbreak;\n\t\t\tcase \"scanline\":\n\t\t\t\tthis.effectState = { row: 0 };\n\t\t\t\tbreak;\n\t\t\tcase \"rain\":\n\t\t\t\t// Track falling position for each column\n\t\t\t\tthis.effectState = {\n\t\t\t\t\tdrops: Array.from({ length: WIDTH }, () => ({\n\t\t\t\t\t\ty: -Math.floor(Math.random() * DISPLAY_HEIGHT * 2),\n\t\t\t\t\t\tsettled: 0,\n\t\t\t\t\t})),\n\t\t\t\t};\n\t\t\t\tbreak;\n\t\t\tcase \"fade\": {\n\t\t\t\t// Shuffle all pixel positions\n\t\t\t\tconst positions: [number, number][] = [];\n\t\t\t\tfor (let row = 0; row < DISPLAY_HEIGHT; row++) {\n\t\t\t\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\t\t\t\tpositions.push([row, x]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// Fisher-Yates shuffle\n\t\t\t\tfor (let i = positions.length - 1; i > 0; i--) {\n\t\t\t\t\tconst j = Math.floor(Math.random() * (i + 1));\n\t\t\t\t\t[positions[i], positions[j]] = [positions[j], positions[i]];\n\t\t\t\t}\n\t\t\t\tthis.effectState = { positions, idx: 0 };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"crt\":\n\t\t\t\tthis.effectState = { expansion: 0 };\n\t\t\t\tbreak;\n\t\t\tcase \"glitch\":\n\t\t\t\tthis.effectState = { phase: 0, glitchFrames: 8 };\n\t\t\t\tbreak;\n\t\t\tcase \"dissolve\": {\n\t\t\t\t// Start with random noise\n\t\t\t\tthis.currentGrid = Array.from({ length: DISPLAY_HEIGHT }, () =>\n\t\t\t\t\tArray.from({ length: WIDTH }, () => {\n\t\t\t\t\t\tconst chars = [\" \", \"░\", \"▒\", \"▓\", \"█\", \"▀\", \"▄\"];\n\t\t\t\t\t\treturn chars[Math.floor(Math.random() * chars.length)];\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\t// Shuffle positions for gradual resolve\n\t\t\t\tconst dissolvePositions: [number, number][] = [];\n\t\t\t\tfor (let row = 0; row < DISPLAY_HEIGHT; row++) {\n\t\t\t\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\t\t\t\tdissolvePositions.push([row, x]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (let i = dissolvePositions.length - 1; i > 0; i--) {\n\t\t\t\t\tconst j = Math.floor(Math.random() * (i + 1));\n\t\t\t\t\t[dissolvePositions[i], dissolvePositions[j]] = [dissolvePositions[j], dissolvePositions[i]];\n\t\t\t\t}\n\t\t\t\tthis.effectState = { positions: dissolvePositions, idx: 0 };\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate startAnimation(): void {\n\t\tconst fps = this.effect === \"glitch\" ? 60 : 30;\n\t\tthis.interval = setInterval(() => {\n\t\t\tconst done = this.tickEffect();\n\t\t\tthis.updateDisplay();\n\t\t\tthis.ui.requestRender();\n\t\t\tif (done) {\n\t\t\t\tthis.stopAnimation();\n\t\t\t}\n\t\t}, 1000 / fps);\n\t}\n\n\tprivate stopAnimation(): void {\n\t\tif (this.interval) {\n\t\t\tclearInterval(this.interval);\n\t\t\tthis.interval = null;\n\t\t}\n\t}\n\n\tprivate tickEffect(): boolean {\n\t\tswitch (this.effect) {\n\t\t\tcase \"typewriter\":\n\t\t\t\treturn this.tickTypewriter();\n\t\t\tcase \"scanline\":\n\t\t\t\treturn this.tickScanline();\n\t\t\tcase \"rain\":\n\t\t\t\treturn this.tickRain();\n\t\t\tcase \"fade\":\n\t\t\t\treturn this.tickFade();\n\t\t\tcase \"crt\":\n\t\t\t\treturn this.tickCrt();\n\t\t\tcase \"glitch\":\n\t\t\t\treturn this.tickGlitch();\n\t\t\tcase \"dissolve\":\n\t\t\t\treturn this.tickDissolve();\n\t\t\t// v8 ignore next -- switch is exhaustive over the effect union\n\t\t\tdefault:\n\t\t\t\treturn true;\n\t\t}\n\t}\n\n\tprivate tickTypewriter(): boolean {\n\t\tconst state = this.effectState as { pos: number };\n\t\tconst pixelsPerFrame = 3;\n\n\t\tfor (let i = 0; i < pixelsPerFrame; i++) {\n\t\t\tconst row = Math.floor(state.pos / WIDTH);\n\t\t\tconst x = state.pos % WIDTH;\n\t\t\tif (row >= DISPLAY_HEIGHT) return true;\n\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\tstate.pos++;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate tickScanline(): boolean {\n\t\tconst state = this.effectState as { row: number };\n\t\tif (state.row >= DISPLAY_HEIGHT) return true;\n\n\t\t// Copy row\n\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\tthis.currentGrid[state.row][x] = this.finalGrid[state.row][x];\n\t\t}\n\t\tstate.row++;\n\t\treturn false;\n\t}\n\n\tprivate tickRain(): boolean {\n\t\tconst state = this.effectState as {\n\t\t\tdrops: { y: number; settled: number }[];\n\t\t};\n\n\t\tlet allSettled = true;\n\t\tthis.currentGrid = this.createEmptyGrid();\n\n\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\tconst drop = state.drops[x];\n\n\t\t\t// Draw settled pixels\n\t\t\tfor (let row = DISPLAY_HEIGHT - 1; row >= DISPLAY_HEIGHT - drop.settled; row--) {\n\t\t\t\t// v8 ignore next -- settled height never exceeds the display, so rows stay non-negative\n\t\t\t\tif (row >= 0) {\n\t\t\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check if this column is done\n\t\t\tif (drop.settled >= DISPLAY_HEIGHT) continue;\n\n\t\t\tallSettled = false;\n\n\t\t\t// Find the target row for this column (lowest non-space pixel)\n\t\t\tlet targetRow = -1;\n\t\t\tfor (let row = DISPLAY_HEIGHT - 1 - drop.settled; row >= 0; row--) {\n\t\t\t\tif (this.finalGrid[row][x] !== \" \") {\n\t\t\t\t\ttargetRow = row;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Move drop down\n\t\t\tdrop.y++;\n\n\t\t\t// Draw falling drop\n\t\t\tif (drop.y >= 0 && drop.y < DISPLAY_HEIGHT) {\n\t\t\t\tif (targetRow >= 0 && drop.y >= targetRow) {\n\t\t\t\t\t// Settle\n\t\t\t\t\tdrop.settled = DISPLAY_HEIGHT - targetRow;\n\t\t\t\t\tdrop.y = -Math.floor(Math.random() * 5) - 1;\n\t\t\t\t} else {\n\t\t\t\t\t// Still falling\n\t\t\t\t\tthis.currentGrid[drop.y][x] = \"▓\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn allSettled;\n\t}\n\n\tprivate tickFade(): boolean {\n\t\tconst state = this.effectState as { positions: [number, number][]; idx: number };\n\t\tconst pixelsPerFrame = 15;\n\n\t\tfor (let i = 0; i < pixelsPerFrame; i++) {\n\t\t\tif (state.idx >= state.positions.length) return true;\n\t\t\tconst [row, x] = state.positions[state.idx];\n\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\tstate.idx++;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate tickCrt(): boolean {\n\t\tconst state = this.effectState as { expansion: number };\n\t\tconst midRow = Math.floor(DISPLAY_HEIGHT / 2);\n\n\t\tthis.currentGrid = this.createEmptyGrid();\n\n\t\t// Draw from middle expanding outward\n\t\tconst top = midRow - state.expansion;\n\t\tconst bottom = midRow + state.expansion;\n\n\t\tfor (let row = Math.max(0, top); row <= Math.min(DISPLAY_HEIGHT - 1, bottom); row++) {\n\t\t\tfor (let x = 0; x < WIDTH; x++) {\n\t\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\t}\n\t\t}\n\n\t\tstate.expansion++;\n\t\treturn state.expansion > DISPLAY_HEIGHT;\n\t}\n\n\tprivate tickGlitch(): boolean {\n\t\tconst state = this.effectState as { phase: number; glitchFrames: number };\n\n\t\tif (state.phase < state.glitchFrames) {\n\t\t\t// Glitch phase: show corrupted version\n\t\t\tthis.currentGrid = this.finalGrid.map((row) => {\n\t\t\t\tconst offset = Math.floor(Math.random() * 7) - 3;\n\t\t\t\tconst glitchRow = [...row];\n\n\t\t\t\t// Random horizontal offset\n\t\t\t\tif (Math.random() < 0.3) {\n\t\t\t\t\tconst shifted = glitchRow.slice(offset).concat(glitchRow.slice(0, offset));\n\t\t\t\t\treturn shifted.slice(0, WIDTH);\n\t\t\t\t}\n\n\t\t\t\t// Random vertical swap\n\t\t\t\tif (Math.random() < 0.2) {\n\t\t\t\t\tconst swapRow = Math.floor(Math.random() * DISPLAY_HEIGHT);\n\t\t\t\t\treturn [...this.finalGrid[swapRow]];\n\t\t\t\t}\n\n\t\t\t\treturn glitchRow;\n\t\t\t});\n\t\t\tstate.phase++;\n\t\t\treturn false;\n\t\t}\n\n\t\t// Final frame: show clean image\n\t\tthis.currentGrid = this.finalGrid.map((row) => [...row]);\n\t\treturn true;\n\t}\n\n\tprivate tickDissolve(): boolean {\n\t\tconst state = this.effectState as { positions: [number, number][]; idx: number };\n\t\tconst pixelsPerFrame = 20;\n\n\t\tfor (let i = 0; i < pixelsPerFrame; i++) {\n\t\t\tif (state.idx >= state.positions.length) return true;\n\t\t\tconst [row, x] = state.positions[state.idx];\n\t\t\tthis.currentGrid[row][x] = this.finalGrid[row][x];\n\t\t\tstate.idx++;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate updateDisplay(): void {\n\t\tthis.gridVersion++;\n\t}\n\n\tdispose(): void {\n\t\tthis.stopAnimation();\n\t}\n}\n"]}
|
|
@@ -15,6 +15,7 @@ export declare class AssistantMessageComponent extends Container {
|
|
|
15
15
|
private hasToolCalls;
|
|
16
16
|
private isStreaming;
|
|
17
17
|
private thinkingExpanded;
|
|
18
|
+
private contentSegments?;
|
|
18
19
|
constructor(message?: AssistantMessage, hideThinkingBlock?: boolean, markdownTheme?: MarkdownTheme, hiddenThinkingLabel?: string, outputPad?: number, markdownTransformers?: readonly MarkdownTransformer[]);
|
|
19
20
|
invalidate(): void;
|
|
20
21
|
setHideThinkingBlock(hide: boolean): void;
|
|
@@ -24,5 +25,7 @@ export declare class AssistantMessageComponent extends Container {
|
|
|
24
25
|
setOutputPad(padding: number): void;
|
|
25
26
|
render(width: number): string[];
|
|
26
27
|
updateContent(message: AssistantMessage, isStreaming?: boolean): void;
|
|
28
|
+
private createSegmentComponent;
|
|
29
|
+
private buildContentSegments;
|
|
27
30
|
}
|
|
28
31
|
//# sourceMappingURL=assistant-message.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assistant-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,kBAAkB,CAAC;AAIzF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAM7D;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,iBAAiB,CAAU;IACnC,OAAO,CAAC,aAAa,CAAgB;IAKrC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,oBAAoB,CAAiC;IAC7D,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAS;IAI5B,OAAO,CAAC,gBAAgB,CAAS;IAEjC,YACC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,iBAAiB,UAAQ,EACzB,aAAa,GAAE,aAAkC,EACjD,mBAAmB,SAAmB,EACtC,SAAS,SAAI,EACb,oBAAoB,GAAE,SAAS,mBAAmB,EAAO,EAiBzD;IAEQ,UAAU,IAAI,IAAI,CAK1B;IAED,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAKxC;IAED,oEAAoE;IACpE,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAQnC;IAED,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAK1C;IAED,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAKlC;IAEQ,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CASvC;IAED,aAAa,CAAC,OAAO,EAAE,gBAAgB,EAAE,WAAW,UAAmB,GAAG,IAAI,CAkH7E;CACD","sourcesContent":["import type { AssistantMessage } from \"@agent-forge/ai\";\nimport { Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@agent-forge/tui\";\nimport { t } from \"../../../core/i18n/index.ts\";\nimport { getMarkdownTheme, theme } from \"../theme/theme.ts\";\nimport { createMarkdownTransform } from \"./markdown-transform.ts\";\nimport type { MarkdownTransformer } from \"./render-types.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\tprivate markdownTheme: MarkdownTheme;\n\t// D-083: the finished-thinking render no longer reads this label (the\n\t// summary line is the i18n key \"✻ thinking\"); the field and its setter\n\t// stay for the constructor signature callers pass positionally.\n\t// biome-ignore lint/correctness/noUnusedPrivateClassMembers: kept write-only for the preserved constructor/setter surface (D-083)\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate markdownTransformers: readonly MarkdownTransformer[];\n\tprivate lastMessage?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\tprivate isStreaming = false;\n\t// D-083 quiet transcript: thinking collapses to one dim summary line once\n\t// the turn ends; detail mode (setExpanded(true), driven by the ctrl+o\n\t// setToolsExpanded loop) renders the full thinking text again.\n\tprivate thinkingExpanded = false;\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = t(\"Thinking...\"),\n\t\toutputPad = 1,\n\t\tmarkdownTransformers: readonly MarkdownTransformer[] = [],\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\t\tthis.markdownTransformers = markdownTransformers;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\t/** Expandable face for the ctrl+o setToolsExpanded loop (D-083). */\n\tsetExpanded(expanded: boolean): void {\n\t\tif (expanded === this.thinkingExpanded) {\n\t\t\treturn;\n\t\t}\n\t\tthis.thinkingExpanded = expanded;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst lines = super.render(width);\n\t\tif (this.hasToolCalls || lines.length === 0) {\n\t\t\treturn lines;\n\t\t}\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\t\treturn lines;\n\t}\n\n\tupdateContent(message: AssistantMessage, isStreaming = this.isStreaming): void {\n\t\tthis.lastMessage = message;\n\t\tthis.isStreaming = isStreaming;\n\n\t\t// Clear content container\n\t\tthis.contentContainer.clear();\n\n\t\tconst hasVisibleContent = message.content.some(\n\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\n\t\tif (hasVisibleContent) {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t}\n\n\t\t// Render content in order\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\tnew Markdown(content.text.trim(), this.outputPad, 0, this.markdownTheme, undefined, {\n\t\t\t\t\t\ttransform: createMarkdownTransform(\"assistant\", this.isStreaming, this.markdownTransformers),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tconst thinkingBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tthinkingBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tif (thinkingBlocks.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Add spacing only when another visible assistant content block follows.\n\t\t\t\t// This avoids a superfluous blank line before separately-rendered tool execution blocks.\n\t\t\t\tconst hasVisibleContentAfter = message.content\n\t\t\t\t\t.slice(i + 1)\n\t\t\t\t\t// v8 ignore next -- thinking runs consume all consecutive thinking blocks, none remain after the run\n\t\t\t\t\t.some((c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()));\n\n\t\t\t\t// D-083 quiet transcript: while streaming, thinking stays fully\n\t\t\t\t// visible (process transparency, regardless of hideThinkingBlock).\n\t\t\t\t// After the turn ends: hideThinkingBlock renders nothing at all,\n\t\t\t\t// detail mode (thinkingExpanded) restores the full text, and the\n\t\t\t\t// quiet default collapses to one dim summary line.\n\t\t\t\tif (this.isStreaming || (!this.hideThinkingBlock && this.thinkingExpanded)) {\n\t\t\t\t\t// Render each run of thinking blocks as one Markdown section.\n\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\tnew Markdown(\n\t\t\t\t\t\t\tthinkingBlocks.join(\"\\n\\n\"),\n\t\t\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\tthis.markdownTheme,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\t\t\titalic: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttransform: createMarkdownTransform(\n\t\t\t\t\t\t\t\t\t\"assistant-thinking\",\n\t\t\t\t\t\t\t\t\tthis.isStreaming,\n\t\t\t\t\t\t\t\t\tthis.markdownTransformers,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} else if (!this.hideThinkingBlock) {\n\t\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\t\tnew Text(theme.italic(theme.fg(\"thinkingText\", t(\"✻ thinking\"))), this.outputPad, 0),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tthis.hasToolCalls = hasToolCalls;\n\t\tif (message.stopReason === \"length\") {\n\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\tthis.contentContainer.addChild(\n\t\t\t\tnew Text(theme.fg(\"error\", t(\"Response was truncated before completion.\")), this.outputPad, 0),\n\t\t\t);\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: t(\"Operation aborted\");\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(new Text(theme.fg(\"error\", abortMessage), this.outputPad, 0));\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || t(\"Unknown error\");\n\t\t\t\tthis.contentContainer.addChild(new Spacer(1));\n\t\t\t\tthis.contentContainer.addChild(\n\t\t\t\t\tnew Text(theme.fg(\"error\", t(\"Error: {message}\", { message: errorMsg })), this.outputPad, 0),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"assistant-message.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/assistant-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAkB,SAAS,EAAY,KAAK,aAAa,EAAgB,MAAM,kBAAkB,CAAC;AAIzG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAmB7D;;GAEG;AACH,qBAAa,yBAA0B,SAAQ,SAAS;IACvD,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,iBAAiB,CAAU;IACnC,OAAO,CAAC,aAAa,CAAgB;IAKrC,OAAO,CAAC,mBAAmB,CAAS;IACpC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,oBAAoB,CAAiC;IAC7D,OAAO,CAAC,WAAW,CAAC,CAAmB;IACvC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAS;IAI5B,OAAO,CAAC,gBAAgB,CAAS;IAIjC,OAAO,CAAC,eAAe,CAAC,CAAwD;IAEhF,YACC,OAAO,CAAC,EAAE,gBAAgB,EAC1B,iBAAiB,UAAQ,EACzB,aAAa,GAAE,aAAkC,EACjD,mBAAmB,SAAmB,EACtC,SAAS,SAAI,EACb,oBAAoB,GAAE,SAAS,mBAAmB,EAAO,EAiBzD;IAEQ,UAAU,IAAI,IAAI,CAM1B;IAED,oBAAoB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAMxC;IAED,oEAAoE;IACpE,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CASnC;IAED,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAM1C;IAED,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAMlC;IAEQ,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CASvC;IAED,aAAa,CAAC,OAAO,EAAE,gBAAgB,EAAE,WAAW,UAAmB,GAAG,IAAI,CAwC7E;IAED,OAAO,CAAC,sBAAsB;IA8B9B,OAAO,CAAC,oBAAoB;CAoF5B","sourcesContent":["import type { AssistantMessage } from \"@agent-forge/ai\";\nimport { type Component, Container, Markdown, type MarkdownTheme, Spacer, Text } from \"@agent-forge/tui\";\nimport { t } from \"../../../core/i18n/index.ts\";\nimport { getMarkdownTheme, theme } from \"../../../theme/theme.ts\";\nimport { createMarkdownTransform } from \"./markdown-transform.ts\";\nimport type { MarkdownTransformer } from \"./render-types.ts\";\n\nconst OSC133_ZONE_START = \"\\x1b]133;A\\x07\";\nconst OSC133_ZONE_END = \"\\x1b]133;B\\x07\";\nconst OSC133_ZONE_FINAL = \"\\x1b]133;C\\x07\";\n\n/**\n * One rendered unit of an assistant message in emission order. updateContent\n * diffs consecutive spec lists by kind (structure) and text so unchanged\n * prefix segments reuse their component instances across streaming deltas;\n * a component's render output depends only on (kind, text) plus the fixed\n * padding/theme/transformers, which keeps incremental output identical to a\n * full rebuild.\n */\ninterface ContentSegmentSpec {\n\tkind: \"spacer\" | \"text\" | \"thinking\" | \"thinking-summary\" | \"status\";\n\ttext: string;\n}\n\n/**\n * Component that renders a complete assistant message\n */\nexport class AssistantMessageComponent extends Container {\n\tprivate contentContainer: Container;\n\tprivate hideThinkingBlock: boolean;\n\tprivate markdownTheme: MarkdownTheme;\n\t// D-083: the finished-thinking render no longer reads this label (the\n\t// summary line is the i18n key \"✻ thinking\"); the field and its setter\n\t// stay for the constructor signature callers pass positionally.\n\t// biome-ignore lint/correctness/noUnusedPrivateClassMembers: kept write-only for the preserved constructor/setter surface (D-083)\n\tprivate hiddenThinkingLabel: string;\n\tprivate outputPad: number;\n\tprivate markdownTransformers: readonly MarkdownTransformer[];\n\tprivate lastMessage?: AssistantMessage;\n\tprivate hasToolCalls = false;\n\tprivate isStreaming = false;\n\t// D-083 quiet transcript: thinking collapses to one dim summary line once\n\t// the turn ends; detail mode (setExpanded(true), driven by the ctrl+o\n\t// setToolsExpanded loop) renders the full thinking text again.\n\tprivate thinkingExpanded = false;\n\t// Segment specs of the last updateContent build. Undefined forces a full\n\t// rebuild (first build, setters, invalidate); otherwise the diff reuses\n\t// unchanged prefix components and rebuilds only the changed tail.\n\tprivate contentSegments?: { specs: ContentSegmentSpec[]; isStreaming: boolean };\n\n\tconstructor(\n\t\tmessage?: AssistantMessage,\n\t\thideThinkingBlock = false,\n\t\tmarkdownTheme: MarkdownTheme = getMarkdownTheme(),\n\t\thiddenThinkingLabel = t(\"Thinking...\"),\n\t\toutputPad = 1,\n\t\tmarkdownTransformers: readonly MarkdownTransformer[] = [],\n\t) {\n\t\tsuper();\n\n\t\tthis.hideThinkingBlock = hideThinkingBlock;\n\t\tthis.markdownTheme = markdownTheme;\n\t\tthis.hiddenThinkingLabel = hiddenThinkingLabel;\n\t\tthis.outputPad = outputPad;\n\t\tthis.markdownTransformers = markdownTransformers;\n\n\t\t// Container for text/thinking content\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\tif (message) {\n\t\t\tthis.updateContent(message);\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tif (this.lastMessage) {\n\t\t\tthis.contentSegments = undefined;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHideThinkingBlock(hide: boolean): void {\n\t\tthis.hideThinkingBlock = hide;\n\t\tif (this.lastMessage) {\n\t\t\tthis.contentSegments = undefined;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\t/** Expandable face for the ctrl+o setToolsExpanded loop (D-083). */\n\tsetExpanded(expanded: boolean): void {\n\t\tif (expanded === this.thinkingExpanded) {\n\t\t\treturn;\n\t\t}\n\t\tthis.thinkingExpanded = expanded;\n\t\tif (this.lastMessage) {\n\t\t\tthis.contentSegments = undefined;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetHiddenThinkingLabel(label: string): void {\n\t\tthis.hiddenThinkingLabel = label;\n\t\tif (this.lastMessage) {\n\t\t\tthis.contentSegments = undefined;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\tsetOutputPad(padding: number): void {\n\t\tthis.outputPad = padding;\n\t\tif (this.lastMessage) {\n\t\t\tthis.contentSegments = undefined;\n\t\t\tthis.updateContent(this.lastMessage);\n\t\t}\n\t}\n\n\toverride render(width: number): string[] {\n\t\tconst lines = super.render(width);\n\t\tif (this.hasToolCalls || lines.length === 0) {\n\t\t\treturn lines;\n\t\t}\n\n\t\tlines[0] = OSC133_ZONE_START + lines[0];\n\t\tlines[lines.length - 1] = OSC133_ZONE_END + OSC133_ZONE_FINAL + lines[lines.length - 1];\n\t\treturn lines;\n\t}\n\n\tupdateContent(message: AssistantMessage, isStreaming = this.isStreaming): void {\n\t\tthis.lastMessage = message;\n\t\tthis.isStreaming = isStreaming;\n\n\t\tconst specs = this.buildContentSegments(message, isStreaming);\n\n\t\t// Diff against the previous build: reuse component instances for the\n\t\t// structurally unchanged prefix and update only changed text in place,\n\t\t// so the per-delta cost scales with the changed tail instead of the\n\t\t// whole message. An isStreaming flip changes the transform captured by\n\t\t// every Markdown, so it rebuilds all segments.\n\t\tconst previous = this.contentSegments;\n\t\tlet reuseCount = 0;\n\t\tif (previous && previous.isStreaming === isStreaming) {\n\t\t\tconst shared = Math.min(previous.specs.length, specs.length);\n\t\t\twhile (reuseCount < shared && previous.specs[reuseCount].kind === specs[reuseCount].kind) {\n\t\t\t\treuseCount++;\n\t\t\t}\n\t\t\tfor (let i = 0; i < reuseCount; i++) {\n\t\t\t\tif (specs[i].text === previous.specs[i].text) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst component = this.contentContainer.children[i];\n\t\t\t\tif (component instanceof Markdown || component instanceof Text) {\n\t\t\t\t\tcomponent.setText(specs[i].text);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst reused = this.contentContainer.children.slice(0, reuseCount);\n\t\tthis.contentContainer.clear();\n\t\tfor (const component of reused) {\n\t\t\tthis.contentContainer.addChild(component);\n\t\t}\n\t\tfor (let i = reuseCount; i < specs.length; i++) {\n\t\t\tthis.contentContainer.addChild(this.createSegmentComponent(specs[i], isStreaming));\n\t\t}\n\t\tthis.contentSegments = { specs, isStreaming };\n\n\t\tthis.hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t}\n\n\tprivate createSegmentComponent(spec: ContentSegmentSpec, isStreaming: boolean): Component {\n\t\tswitch (spec.kind) {\n\t\t\tcase \"spacer\":\n\t\t\t\treturn new Spacer(1);\n\t\t\tcase \"text\":\n\t\t\t\t// Assistant text messages with no background - trim the text\n\t\t\t\t// Set paddingY=0 to avoid extra spacing before tool executions\n\t\t\t\treturn new Markdown(spec.text, this.outputPad, 0, this.markdownTheme, undefined, {\n\t\t\t\t\ttransform: createMarkdownTransform(\"assistant\", isStreaming, this.markdownTransformers),\n\t\t\t\t});\n\t\t\tcase \"thinking\":\n\t\t\t\treturn new Markdown(\n\t\t\t\t\tspec.text,\n\t\t\t\t\tthis.outputPad,\n\t\t\t\t\t0,\n\t\t\t\t\tthis.markdownTheme,\n\t\t\t\t\t{\n\t\t\t\t\t\tcolor: (text: string) => theme.fg(\"thinkingText\", text),\n\t\t\t\t\t\titalic: true,\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttransform: createMarkdownTransform(\"assistant-thinking\", isStreaming, this.markdownTransformers),\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\tcase \"thinking-summary\":\n\t\t\tcase \"status\":\n\t\t\t\treturn new Text(spec.text, this.outputPad, 0);\n\t\t}\n\t}\n\n\tprivate buildContentSegments(message: AssistantMessage, isStreaming: boolean): ContentSegmentSpec[] {\n\t\tconst specs: ContentSegmentSpec[] = [];\n\n\t\tconst hasVisibleContent = message.content.some(\n\t\t\t(c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()),\n\t\t);\n\t\tif (hasVisibleContent) {\n\t\t\tspecs.push({ kind: \"spacer\", text: \"\" });\n\t\t}\n\n\t\t// Render content in order\n\t\tfor (let i = 0; i < message.content.length; i++) {\n\t\t\tconst content = message.content[i];\n\t\t\tif (content.type === \"text\" && content.text.trim()) {\n\t\t\t\tspecs.push({ kind: \"text\", text: content.text.trim() });\n\t\t\t} else if (content.type === \"thinking\") {\n\t\t\t\tconst thinkingBlocks: string[] = [];\n\t\t\t\tfor (; i < message.content.length; i++) {\n\t\t\t\t\tconst thinkingContent = message.content[i];\n\t\t\t\t\tif (thinkingContent.type !== \"thinking\") {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst thinking = thinkingContent.thinking.trim();\n\t\t\t\t\tif (thinking) {\n\t\t\t\t\t\tthinkingBlocks.push(thinking);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti--;\n\n\t\t\t\tif (thinkingBlocks.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Add spacing only when another visible assistant content block follows.\n\t\t\t\t// This avoids a superfluous blank line before separately-rendered tool execution blocks.\n\t\t\t\tconst hasVisibleContentAfter = message.content\n\t\t\t\t\t.slice(i + 1)\n\t\t\t\t\t// v8 ignore next -- thinking runs consume all consecutive thinking blocks, none remain after the run\n\t\t\t\t\t.some((c) => (c.type === \"text\" && c.text.trim()) || (c.type === \"thinking\" && c.thinking.trim()));\n\n\t\t\t\t// D-083 quiet transcript: while streaming, thinking stays fully\n\t\t\t\t// visible (process transparency, regardless of hideThinkingBlock).\n\t\t\t\t// After the turn ends: hideThinkingBlock renders nothing at all,\n\t\t\t\t// detail mode (thinkingExpanded) restores the full text, and the\n\t\t\t\t// quiet default collapses to one dim summary line.\n\t\t\t\tif (isStreaming || (!this.hideThinkingBlock && this.thinkingExpanded)) {\n\t\t\t\t\t// Render each run of thinking blocks as one Markdown section.\n\t\t\t\t\tspecs.push({ kind: \"thinking\", text: thinkingBlocks.join(\"\\n\\n\") });\n\t\t\t\t} else if (!this.hideThinkingBlock) {\n\t\t\t\t\tspecs.push({\n\t\t\t\t\t\tkind: \"thinking-summary\",\n\t\t\t\t\t\ttext: theme.italic(theme.fg(\"thinkingText\", t(\"✻ thinking\"))),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tif (hasVisibleContentAfter) {\n\t\t\t\t\tspecs.push({ kind: \"spacer\", text: \"\" });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check if incomplete/failed - show after partial content.\n\t\t// For aborted/error tool calls, tool execution components show the error.\n\t\t// Length stops can happen before a tool call is complete, so surface them here too.\n\t\tconst hasToolCalls = message.content.some((c) => c.type === \"toolCall\");\n\t\tif (message.stopReason === \"length\") {\n\t\t\tspecs.push({ kind: \"spacer\", text: \"\" });\n\t\t\tspecs.push({ kind: \"status\", text: theme.fg(\"error\", t(\"Response was truncated before completion.\")) });\n\t\t} else if (!hasToolCalls) {\n\t\t\tif (message.stopReason === \"aborted\") {\n\t\t\t\tconst abortMessage =\n\t\t\t\t\tmessage.errorMessage && message.errorMessage !== \"Request was aborted\"\n\t\t\t\t\t\t? message.errorMessage\n\t\t\t\t\t\t: t(\"Operation aborted\");\n\t\t\t\tspecs.push({ kind: \"spacer\", text: \"\" });\n\t\t\t\tspecs.push({ kind: \"status\", text: theme.fg(\"error\", abortMessage) });\n\t\t\t} else if (message.stopReason === \"error\") {\n\t\t\t\tconst errorMsg = message.errorMessage || t(\"Unknown error\");\n\t\t\t\tspecs.push({ kind: \"spacer\", text: \"\" });\n\t\t\t\tspecs.push({ kind: \"status\", text: theme.fg(\"error\", t(\"Error: {message}\", { message: errorMsg })) });\n\t\t\t}\n\t\t}\n\n\t\treturn specs;\n\t}\n}\n"]}
|