@yeshwanthyk/coding-agent 0.3.0 → 0.3.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/README.md +8 -6
- package/dist/adapters/acp/index.d.ts +10 -0
- package/dist/adapters/acp/index.d.ts.map +1 -0
- package/dist/adapters/acp/index.js +250 -0
- package/dist/adapters/acp/index.js.map +1 -0
- package/dist/adapters/acp/protocol.d.ts +171 -0
- package/dist/adapters/acp/protocol.d.ts.map +1 -0
- package/dist/adapters/acp/protocol.js +25 -0
- package/dist/adapters/acp/protocol.js.map +1 -0
- package/dist/adapters/acp/session.d.ts +33 -0
- package/dist/adapters/acp/session.d.ts.map +1 -0
- package/dist/adapters/acp/session.js +216 -0
- package/dist/adapters/acp/session.js.map +1 -0
- package/dist/adapters/acp/updates.d.ts +17 -0
- package/dist/adapters/acp/updates.d.ts.map +1 -0
- package/dist/adapters/acp/updates.js +62 -0
- package/dist/adapters/acp/updates.js.map +1 -0
- package/dist/adapters/cli/headless.d.ts +7 -0
- package/dist/adapters/cli/headless.d.ts.map +1 -0
- package/dist/adapters/cli/headless.js +93 -0
- package/dist/adapters/cli/headless.js.map +1 -0
- package/dist/adapters/cli/validate.d.ts +3 -0
- package/dist/adapters/cli/validate.d.ts.map +1 -0
- package/dist/adapters/cli/validate.js +40 -0
- package/dist/adapters/cli/validate.js.map +1 -0
- package/dist/adapters/tui/app.d.ts +8 -0
- package/dist/adapters/tui/app.d.ts.map +1 -0
- package/dist/adapters/tui/app.jsx +25 -0
- package/dist/adapters/tui/app.jsx.map +1 -0
- package/dist/agent-events.d.ts +63 -0
- package/dist/agent-events.d.ts.map +1 -0
- package/dist/agent-events.js +510 -0
- package/dist/agent-events.js.map +1 -0
- package/dist/args.d.ts +18 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +87 -0
- package/dist/args.js.map +1 -0
- package/dist/autocomplete-commands.d.ts +26 -0
- package/dist/autocomplete-commands.d.ts.map +1 -0
- package/dist/autocomplete-commands.js +82 -0
- package/dist/autocomplete-commands.js.map +1 -0
- package/dist/commands.d.ts +10 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +17 -0
- package/dist/commands.js.map +1 -0
- package/dist/compact-handler.d.ts +42 -0
- package/dist/compact-handler.d.ts.map +1 -0
- package/dist/compact-handler.js +211 -0
- package/dist/compact-handler.js.map +1 -0
- package/dist/components/Footer.d.ts +9 -0
- package/dist/components/Footer.d.ts.map +1 -0
- package/dist/components/Footer.jsx +36 -0
- package/dist/components/Footer.jsx.map +1 -0
- package/dist/components/Header.d.ts +23 -0
- package/dist/components/Header.d.ts.map +1 -0
- package/dist/components/Header.jsx +174 -0
- package/dist/components/Header.jsx.map +1 -0
- package/dist/components/MessageList.d.ts +19 -0
- package/dist/components/MessageList.d.ts.map +1 -0
- package/dist/components/MessageList.jsx +237 -0
- package/dist/components/MessageList.jsx.map +1 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -0
- package/dist/domain/commands/builtin/clear.d.ts +3 -0
- package/dist/domain/commands/builtin/clear.d.ts.map +1 -0
- package/dist/domain/commands/builtin/clear.js +13 -0
- package/dist/domain/commands/builtin/clear.js.map +1 -0
- package/dist/domain/commands/builtin/compact.d.ts +3 -0
- package/dist/domain/commands/builtin/compact.d.ts.map +1 -0
- package/dist/domain/commands/builtin/compact.js +84 -0
- package/dist/domain/commands/builtin/compact.js.map +1 -0
- package/dist/domain/commands/builtin/conceal.d.ts +3 -0
- package/dist/domain/commands/builtin/conceal.d.ts.map +1 -0
- package/dist/domain/commands/builtin/conceal.js +8 -0
- package/dist/domain/commands/builtin/conceal.js.map +1 -0
- package/dist/domain/commands/builtin/diffwrap.d.ts +3 -0
- package/dist/domain/commands/builtin/diffwrap.d.ts.map +1 -0
- package/dist/domain/commands/builtin/diffwrap.js +8 -0
- package/dist/domain/commands/builtin/diffwrap.js.map +1 -0
- package/dist/domain/commands/builtin/editor.d.ts +3 -0
- package/dist/domain/commands/builtin/editor.d.ts.map +1 -0
- package/dist/domain/commands/builtin/editor.js +22 -0
- package/dist/domain/commands/builtin/editor.js.map +1 -0
- package/dist/domain/commands/builtin/exit.d.ts +3 -0
- package/dist/domain/commands/builtin/exit.d.ts.map +1 -0
- package/dist/domain/commands/builtin/exit.js +14 -0
- package/dist/domain/commands/builtin/exit.js.map +1 -0
- package/dist/domain/commands/builtin/followup.d.ts +3 -0
- package/dist/domain/commands/builtin/followup.d.ts.map +1 -0
- package/dist/domain/commands/builtin/followup.js +20 -0
- package/dist/domain/commands/builtin/followup.js.map +1 -0
- package/dist/domain/commands/builtin/index.d.ts +2 -0
- package/dist/domain/commands/builtin/index.d.ts.map +1 -0
- package/dist/domain/commands/builtin/index.js +29 -0
- package/dist/domain/commands/builtin/index.js.map +1 -0
- package/dist/domain/commands/builtin/login.d.ts +3 -0
- package/dist/domain/commands/builtin/login.d.ts.map +1 -0
- package/dist/domain/commands/builtin/login.js +92 -0
- package/dist/domain/commands/builtin/login.js.map +1 -0
- package/dist/domain/commands/builtin/model.d.ts +3 -0
- package/dist/domain/commands/builtin/model.d.ts.map +1 -0
- package/dist/domain/commands/builtin/model.js +53 -0
- package/dist/domain/commands/builtin/model.js.map +1 -0
- package/dist/domain/commands/builtin/status.d.ts +3 -0
- package/dist/domain/commands/builtin/status.d.ts.map +1 -0
- package/dist/domain/commands/builtin/status.js +30 -0
- package/dist/domain/commands/builtin/status.js.map +1 -0
- package/dist/domain/commands/builtin/steer.d.ts +3 -0
- package/dist/domain/commands/builtin/steer.d.ts.map +1 -0
- package/dist/domain/commands/builtin/steer.js +20 -0
- package/dist/domain/commands/builtin/steer.js.map +1 -0
- package/dist/domain/commands/builtin/theme.d.ts +3 -0
- package/dist/domain/commands/builtin/theme.d.ts.map +1 -0
- package/dist/domain/commands/builtin/theme.js +19 -0
- package/dist/domain/commands/builtin/theme.js.map +1 -0
- package/dist/domain/commands/builtin/thinking.d.ts +3 -0
- package/dist/domain/commands/builtin/thinking.d.ts.map +1 -0
- package/dist/domain/commands/builtin/thinking.js +16 -0
- package/dist/domain/commands/builtin/thinking.js.map +1 -0
- package/dist/domain/commands/helpers.d.ts +7 -0
- package/dist/domain/commands/helpers.d.ts.map +1 -0
- package/dist/domain/commands/helpers.js +34 -0
- package/dist/domain/commands/helpers.js.map +1 -0
- package/dist/domain/commands/registry.d.ts +10 -0
- package/dist/domain/commands/registry.d.ts.map +1 -0
- package/dist/domain/commands/registry.js +36 -0
- package/dist/domain/commands/registry.js.map +1 -0
- package/dist/domain/commands/types.d.ts +62 -0
- package/dist/domain/commands/types.d.ts.map +1 -0
- package/dist/domain/commands/types.js +2 -0
- package/dist/domain/commands/types.js.map +1 -0
- package/dist/domain/messaging/content.d.ts +37 -0
- package/dist/domain/messaging/content.d.ts.map +1 -0
- package/dist/domain/messaging/content.js +103 -0
- package/dist/domain/messaging/content.js.map +1 -0
- package/dist/editor.d.ts +26 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/editor.js +81 -0
- package/dist/editor.js.map +1 -0
- package/dist/extensibility/schema.d.ts +2 -0
- package/dist/extensibility/schema.d.ts.map +1 -0
- package/{src/extensibility/schema.ts → dist/extensibility/schema.js} +2 -1
- package/dist/extensibility/schema.js.map +1 -0
- package/dist/extensibility/validation.d.ts +2 -0
- package/dist/extensibility/validation.d.ts.map +1 -0
- package/{src/extensibility/validation.ts → dist/extensibility/validation.js} +2 -1
- package/dist/extensibility/validation.js.map +1 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/useAgentEvents.d.ts +8 -0
- package/dist/hooks/useAgentEvents.d.ts.map +1 -0
- package/dist/hooks/useAgentEvents.js +22 -0
- package/dist/hooks/useAgentEvents.js.map +1 -0
- package/dist/hooks/useEditorBridge.d.ts +20 -0
- package/dist/hooks/useEditorBridge.d.ts.map +1 -0
- package/dist/hooks/useEditorBridge.js +80 -0
- package/dist/hooks/useEditorBridge.js.map +1 -0
- package/dist/hooks/useGitStatus.d.ts +2 -0
- package/dist/hooks/useGitStatus.d.ts.map +1 -0
- package/dist/hooks/useGitStatus.js +26 -0
- package/dist/hooks/useGitStatus.js.map +1 -0
- package/dist/hooks/usePromptQueue.d.ts +2 -0
- package/dist/hooks/usePromptQueue.d.ts.map +1 -0
- package/dist/hooks/usePromptQueue.js +2 -0
- package/dist/hooks/usePromptQueue.js.map +1 -0
- package/dist/hooks/useSessionController.d.ts +2 -0
- package/dist/hooks/useSessionController.d.ts.map +1 -0
- package/dist/hooks/useSessionController.js +2 -0
- package/dist/hooks/useSessionController.js.map +1 -0
- package/dist/hooks/useSpinner.d.ts +4 -0
- package/dist/hooks/useSpinner.d.ts.map +1 -0
- package/dist/hooks/useSpinner.js +25 -0
- package/dist/hooks/useSpinner.js.map +1 -0
- package/dist/hooks/useToastManager.d.ts +6 -0
- package/dist/hooks/useToastManager.d.ts.map +1 -0
- package/dist/hooks/useToastManager.js +22 -0
- package/dist/hooks/useToastManager.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +156 -0
- package/dist/index.js.map +1 -0
- package/dist/keyboard-handler.d.ts +30 -0
- package/dist/keyboard-handler.d.ts.map +1 -0
- package/dist/keyboard-handler.js +96 -0
- package/dist/keyboard-handler.js.map +1 -0
- package/dist/profiler.d.ts +2 -0
- package/dist/profiler.d.ts.map +1 -0
- package/dist/profiler.js +41 -0
- package/dist/profiler.js.map +1 -0
- package/dist/runtime/context.d.ts +8 -0
- package/dist/runtime/context.d.ts.map +1 -0
- package/dist/runtime/context.jsx +11 -0
- package/dist/runtime/context.jsx.map +1 -0
- package/dist/runtime/factory.d.ts +12 -0
- package/dist/runtime/factory.d.ts.map +1 -0
- package/dist/runtime/factory.js +37 -0
- package/dist/runtime/factory.js.map +1 -0
- package/dist/runtime/git/git-info.d.ts +3 -0
- package/dist/runtime/git/git-info.d.ts.map +1 -0
- package/dist/runtime/git/git-info.js +29 -0
- package/dist/runtime/git/git-info.js.map +1 -0
- package/dist/runtime/session/session-controller.d.ts +48 -0
- package/dist/runtime/session/session-controller.d.ts.map +1 -0
- package/dist/runtime/session/session-controller.js +159 -0
- package/dist/runtime/session/session-controller.js.map +1 -0
- package/dist/session-manager.d.ts +2 -0
- package/dist/session-manager.d.ts.map +1 -0
- package/dist/session-manager.js +2 -0
- package/dist/session-manager.js.map +1 -0
- package/dist/session-picker.d.ts +6 -0
- package/dist/session-picker.d.ts.map +1 -0
- package/dist/session-picker.jsx +96 -0
- package/dist/session-picker.jsx.map +1 -0
- package/dist/shell-runner.d.ts +21 -0
- package/dist/shell-runner.d.ts.map +1 -0
- package/dist/shell-runner.js +106 -0
- package/dist/shell-runner.js.map +1 -0
- package/dist/syntax-highlighting.d.ts +4 -0
- package/dist/syntax-highlighting.d.ts.map +1 -0
- package/dist/syntax-highlighting.js +108 -0
- package/dist/syntax-highlighting.js.map +1 -0
- package/dist/theme-names.d.ts +7 -0
- package/dist/theme-names.d.ts.map +1 -0
- package/dist/theme-names.js +38 -0
- package/dist/theme-names.js.map +1 -0
- package/dist/tool-ui-contracts.d.ts +30 -0
- package/dist/tool-ui-contracts.d.ts.map +1 -0
- package/dist/tool-ui-contracts.js +53 -0
- package/dist/tool-ui-contracts.js.map +1 -0
- package/dist/tui-open-rendering.d.ts +37 -0
- package/dist/tui-open-rendering.d.ts.map +1 -0
- package/dist/tui-open-rendering.jsx +462 -0
- package/dist/tui-open-rendering.jsx.map +1 -0
- package/dist/types.d.ts +117 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/app-shell/TuiApp.d.ts +6 -0
- package/dist/ui/app-shell/TuiApp.d.ts.map +1 -0
- package/dist/ui/app-shell/TuiApp.jsx +480 -0
- package/dist/ui/app-shell/TuiApp.jsx.map +1 -0
- package/dist/ui/clipboard/osc52.d.ts +2 -0
- package/dist/ui/clipboard/osc52.d.ts.map +1 -0
- package/dist/ui/clipboard/osc52.js +19 -0
- package/dist/ui/clipboard/osc52.js.map +1 -0
- package/dist/ui/components/modals/ConfirmModal.d.ts +8 -0
- package/dist/ui/components/modals/ConfirmModal.d.ts.map +1 -0
- package/dist/ui/components/modals/ConfirmModal.jsx +39 -0
- package/dist/ui/components/modals/ConfirmModal.jsx.map +1 -0
- package/dist/ui/components/modals/EditorModal.d.ts +8 -0
- package/dist/ui/components/modals/EditorModal.d.ts.map +1 -0
- package/dist/ui/components/modals/EditorModal.jsx +23 -0
- package/dist/ui/components/modals/EditorModal.jsx.map +1 -0
- package/dist/ui/components/modals/InputModal.d.ts +8 -0
- package/dist/ui/components/modals/InputModal.d.ts.map +1 -0
- package/dist/ui/components/modals/InputModal.jsx +15 -0
- package/dist/ui/components/modals/InputModal.jsx.map +1 -0
- package/dist/ui/components/modals/ModalContainer.d.ts +8 -0
- package/dist/ui/components/modals/ModalContainer.d.ts.map +1 -0
- package/dist/ui/components/modals/ModalContainer.jsx +34 -0
- package/dist/ui/components/modals/ModalContainer.jsx.map +1 -0
- package/dist/ui/components/modals/SelectModal.d.ts +8 -0
- package/dist/ui/components/modals/SelectModal.d.ts.map +1 -0
- package/dist/ui/components/modals/SelectModal.jsx +32 -0
- package/dist/ui/components/modals/SelectModal.jsx.map +1 -0
- package/{src/ui/components/modals/index.ts → dist/ui/components/modals/index.d.ts} +5 -4
- package/dist/ui/components/modals/index.d.ts.map +1 -0
- package/dist/ui/components/modals/index.js +5 -0
- package/dist/ui/components/modals/index.js.map +1 -0
- package/dist/ui/features/composer/Composer.d.ts +16 -0
- package/dist/ui/features/composer/Composer.d.ts.map +1 -0
- package/dist/ui/features/composer/Composer.jsx +39 -0
- package/dist/ui/features/composer/Composer.jsx.map +1 -0
- package/dist/ui/features/composer/SlashCommandHandler.d.ts +14 -0
- package/dist/ui/features/composer/SlashCommandHandler.d.ts.map +1 -0
- package/dist/ui/features/composer/SlashCommandHandler.js +43 -0
- package/dist/ui/features/composer/SlashCommandHandler.js.map +1 -0
- package/dist/ui/features/composer/keyboard.d.ts +3 -0
- package/dist/ui/features/composer/keyboard.d.ts.map +1 -0
- package/dist/ui/features/composer/keyboard.js +3 -0
- package/dist/ui/features/composer/keyboard.js.map +1 -0
- package/dist/ui/features/main-view/MainView.d.ts +52 -0
- package/dist/ui/features/main-view/MainView.d.ts.map +1 -0
- package/dist/ui/features/main-view/MainView.jsx +269 -0
- package/dist/ui/features/main-view/MainView.jsx.map +1 -0
- package/dist/ui/features/message-pane/MessagePane.d.ts +15 -0
- package/dist/ui/features/message-pane/MessagePane.d.ts.map +1 -0
- package/dist/ui/features/message-pane/MessagePane.jsx +7 -0
- package/dist/ui/features/message-pane/MessagePane.jsx.map +1 -0
- package/dist/ui/hooks/useModals.d.ts +35 -0
- package/dist/ui/hooks/useModals.d.ts.map +1 -0
- package/dist/ui/hooks/useModals.js +36 -0
- package/dist/ui/hooks/useModals.js.map +1 -0
- package/dist/ui/state/app-store.d.ts +42 -0
- package/dist/ui/state/app-store.d.ts.map +1 -0
- package/dist/ui/state/app-store.js +28 -0
- package/dist/ui/state/app-store.js.map +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +3 -0
- package/dist/utils.js.map +1 -0
- package/package.json +20 -7
- package/src/adapters/acp/index.ts +0 -305
- package/src/adapters/acp/protocol.ts +0 -191
- package/src/adapters/acp/session.ts +0 -289
- package/src/adapters/acp/updates.ts +0 -96
- package/src/adapters/cli/headless.ts +0 -112
- package/src/adapters/cli/validate.ts +0 -50
- package/src/adapters/tui/app.tsx +0 -39
- package/src/agent-events.ts +0 -671
- package/src/args.ts +0 -102
- package/src/autocomplete-commands.ts +0 -102
- package/src/commands.ts +0 -23
- package/src/compact-handler.ts +0 -272
- package/src/components/Footer.tsx +0 -49
- package/src/components/Header.tsx +0 -218
- package/src/components/MessageList.tsx +0 -380
- package/src/config.ts +0 -1
- package/src/domain/commands/builtin/clear.ts +0 -14
- package/src/domain/commands/builtin/compact.ts +0 -96
- package/src/domain/commands/builtin/conceal.ts +0 -9
- package/src/domain/commands/builtin/diffwrap.ts +0 -9
- package/src/domain/commands/builtin/editor.ts +0 -24
- package/src/domain/commands/builtin/exit.ts +0 -14
- package/src/domain/commands/builtin/followup.ts +0 -24
- package/src/domain/commands/builtin/index.ts +0 -29
- package/src/domain/commands/builtin/login.ts +0 -118
- package/src/domain/commands/builtin/model.ts +0 -66
- package/src/domain/commands/builtin/status.ts +0 -32
- package/src/domain/commands/builtin/steer.ts +0 -24
- package/src/domain/commands/builtin/theme.ts +0 -23
- package/src/domain/commands/builtin/thinking.ts +0 -16
- package/src/domain/commands/helpers.ts +0 -41
- package/src/domain/commands/registry.ts +0 -42
- package/src/domain/commands/types.ts +0 -69
- package/src/domain/messaging/content.ts +0 -117
- package/src/editor.ts +0 -103
- package/src/hooks/index.ts +0 -1
- package/src/hooks/useAgentEvents.ts +0 -28
- package/src/hooks/useEditorBridge.ts +0 -101
- package/src/hooks/useGitStatus.ts +0 -28
- package/src/hooks/usePromptQueue.ts +0 -7
- package/src/hooks/useSessionController.ts +0 -5
- package/src/hooks/useSpinner.ts +0 -28
- package/src/hooks/useToastManager.ts +0 -26
- package/src/index.ts +0 -188
- package/src/keyboard-handler.ts +0 -134
- package/src/profiler.ts +0 -40
- package/src/runtime/context.tsx +0 -16
- package/src/runtime/factory.ts +0 -63
- package/src/runtime/git/git-info.ts +0 -25
- package/src/runtime/session/session-controller.ts +0 -208
- package/src/session-manager.ts +0 -1
- package/src/session-picker.tsx +0 -134
- package/src/shell-runner.ts +0 -134
- package/src/syntax-highlighting.ts +0 -114
- package/src/theme-names.ts +0 -37
- package/src/tool-ui-contracts.ts +0 -77
- package/src/tui-open-rendering.tsx +0 -565
- package/src/types.ts +0 -89
- package/src/ui/app-shell/TuiApp.tsx +0 -586
- package/src/ui/clipboard/osc52.ts +0 -18
- package/src/ui/components/modals/ConfirmModal.tsx +0 -52
- package/src/ui/components/modals/EditorModal.tsx +0 -39
- package/src/ui/components/modals/InputModal.tsx +0 -30
- package/src/ui/components/modals/ModalContainer.tsx +0 -67
- package/src/ui/components/modals/SelectModal.tsx +0 -48
- package/src/ui/features/composer/Composer.tsx +0 -73
- package/src/ui/features/composer/SlashCommandHandler.ts +0 -58
- package/src/ui/features/composer/keyboard.ts +0 -3
- package/src/ui/features/main-view/MainView.tsx +0 -367
- package/src/ui/features/message-pane/MessagePane.tsx +0 -34
- package/src/ui/hooks/useModals.ts +0 -74
- package/src/ui/state/app-store.ts +0 -67
- package/src/utils.ts +0 -14
|
@@ -1,565 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OpenTUI-native rendering components for tool output.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { CodeBlock, Diff, Image, TextAttributes, useTheme, parseColor, type MouseEvent, type Theme } from "@yeshwanthyk/open-tui"
|
|
6
|
-
import { Show, type JSX } from "solid-js"
|
|
7
|
-
import { getLanguageFromPath, replaceTabs } from "./syntax-highlighting.js"
|
|
8
|
-
import { getToolText, getEditDiffText } from "@domain/messaging/content.js"
|
|
9
|
-
import { getAgentDelegationArgs, getAgentDelegationUi, type AgentDelegationArgs, type AgentDelegationUi, type DelegationStatus } from "./tool-ui-contracts.js"
|
|
10
|
-
|
|
11
|
-
// Re-export for backwards compatibility
|
|
12
|
-
export { getToolText, getEditDiffText }
|
|
13
|
-
|
|
14
|
-
// Design tokens - minimal symbols
|
|
15
|
-
const symbols = {
|
|
16
|
-
running: "·",
|
|
17
|
-
complete: "▸",
|
|
18
|
-
expanded: "▾",
|
|
19
|
-
error: "✕",
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export const shortenPath = (p: string, maxLen = 40): string => {
|
|
23
|
-
const home = process.env.HOME || process.env.USERPROFILE || ""
|
|
24
|
-
let shortened = p
|
|
25
|
-
|
|
26
|
-
// Replace home with ~
|
|
27
|
-
if (home && shortened.startsWith(home)) {
|
|
28
|
-
shortened = "~" + shortened.slice(home.length)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// If still long, show .../{parent}/{file}
|
|
32
|
-
const parts = shortened.split("/")
|
|
33
|
-
if (parts.length > 3) {
|
|
34
|
-
shortened = "…/" + parts.slice(-2).join("/")
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Final truncation if still too long
|
|
38
|
-
if (shortened.length > maxLen) {
|
|
39
|
-
shortened = "…" + shortened.slice(-(maxLen - 1))
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return shortened
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Simple diff preview with manual line coloring (tree-sitter lacks diff grammar)
|
|
46
|
-
const diffAddedColor = parseColor("#98c379")
|
|
47
|
-
const diffRemovedColor = parseColor("#e06c75")
|
|
48
|
-
const diffHunkColor = parseColor("#61afef")
|
|
49
|
-
|
|
50
|
-
function DiffPreview(props: { text: string }): JSX.Element {
|
|
51
|
-
const { theme } = useTheme()
|
|
52
|
-
|
|
53
|
-
const coloredLines = () => props.text.split("\n").map((line) => {
|
|
54
|
-
let fg = theme.text
|
|
55
|
-
if (line.startsWith("+") && !line.startsWith("+++")) fg = diffAddedColor
|
|
56
|
-
else if (line.startsWith("-") && !line.startsWith("---")) fg = diffRemovedColor
|
|
57
|
-
else if (line.startsWith("@@")) fg = diffHunkColor
|
|
58
|
-
return { line, fg }
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<box flexDirection="column" backgroundColor={theme.backgroundElement} paddingLeft={1} paddingRight={1}>
|
|
63
|
-
{coloredLines().map(({ line, fg }) => (
|
|
64
|
-
<text fg={fg}>{line}</text>
|
|
65
|
-
))}
|
|
66
|
-
</box>
|
|
67
|
-
)
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const delegationOkColor = diffAddedColor
|
|
71
|
-
|
|
72
|
-
function firstLine(s: string): string {
|
|
73
|
-
return s.split("\n")[0] || ""
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function truncate(s: string, max: number): string {
|
|
77
|
-
if (s.length <= max) return s
|
|
78
|
-
return s.slice(0, Math.max(0, max - 1)) + "…"
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function delegationSymbol(status: DelegationStatus | "unknown"): string {
|
|
82
|
-
switch (status) {
|
|
83
|
-
case "running":
|
|
84
|
-
return "◌"
|
|
85
|
-
case "pending":
|
|
86
|
-
return "○"
|
|
87
|
-
case "ok":
|
|
88
|
-
return "✓"
|
|
89
|
-
case "error":
|
|
90
|
-
return "✕"
|
|
91
|
-
default:
|
|
92
|
-
return "·"
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function delegationColor(theme: Theme, status: DelegationStatus | "unknown"): ReturnType<typeof parseColor> {
|
|
97
|
-
if (status === "error") return theme.error
|
|
98
|
-
if (status === "ok") return delegationOkColor
|
|
99
|
-
if (status === "running") return theme.accent
|
|
100
|
-
return theme.textMuted
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function formatDelegationSuffix(ui: AgentDelegationUi): string {
|
|
104
|
-
const ok = ui.items.filter((i) => i.status === "ok").length
|
|
105
|
-
const err = ui.items.filter((i) => i.status === "error").length
|
|
106
|
-
const total = ui.items.length
|
|
107
|
-
if (err > 0) return `${ok} ok · ${err} err / ${total}`
|
|
108
|
-
return `${ok} ok / ${total}`
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function AgentDelegationView(props: {
|
|
112
|
-
args: AgentDelegationArgs | null
|
|
113
|
-
ui: AgentDelegationUi | null
|
|
114
|
-
expanded: boolean
|
|
115
|
-
}): JSX.Element {
|
|
116
|
-
const { theme } = useTheme()
|
|
117
|
-
const maxItems = () => props.expanded ? 50 : 8
|
|
118
|
-
|
|
119
|
-
const rows = () => {
|
|
120
|
-
if (props.ui) {
|
|
121
|
-
return props.ui.items.slice(0, maxItems()).map((item) => ({
|
|
122
|
-
id: item.id,
|
|
123
|
-
agent: item.agent,
|
|
124
|
-
task: item.task,
|
|
125
|
-
status: item.status as DelegationStatus | "unknown",
|
|
126
|
-
preview: item.preview,
|
|
127
|
-
active: props.ui?.activeId === item.id,
|
|
128
|
-
}))
|
|
129
|
-
}
|
|
130
|
-
if (props.args?.chain?.length) {
|
|
131
|
-
return props.args.chain.slice(0, maxItems()).map((item, idx) => ({
|
|
132
|
-
id: String(idx + 1),
|
|
133
|
-
agent: item.agent,
|
|
134
|
-
task: item.task,
|
|
135
|
-
status: "unknown" as const,
|
|
136
|
-
preview: undefined,
|
|
137
|
-
active: false,
|
|
138
|
-
}))
|
|
139
|
-
}
|
|
140
|
-
if (props.args?.tasks?.length) {
|
|
141
|
-
return props.args.tasks.slice(0, maxItems()).map((item, idx) => ({
|
|
142
|
-
id: String(idx + 1),
|
|
143
|
-
agent: item.agent,
|
|
144
|
-
task: item.task,
|
|
145
|
-
status: "unknown" as const,
|
|
146
|
-
preview: undefined,
|
|
147
|
-
active: false,
|
|
148
|
-
}))
|
|
149
|
-
}
|
|
150
|
-
if (props.args?.agent && props.args?.task) {
|
|
151
|
-
return [{
|
|
152
|
-
id: "1",
|
|
153
|
-
agent: props.args.agent,
|
|
154
|
-
task: props.args.task,
|
|
155
|
-
status: "unknown" as const,
|
|
156
|
-
preview: undefined,
|
|
157
|
-
active: false,
|
|
158
|
-
}]
|
|
159
|
-
}
|
|
160
|
-
return []
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return (
|
|
164
|
-
<box flexDirection="column" backgroundColor={theme.backgroundElement} paddingLeft={1} paddingRight={1}>
|
|
165
|
-
{rows().map((row) => (
|
|
166
|
-
<box flexDirection="column" gap={0}>
|
|
167
|
-
<box flexDirection="row" gap={1}>
|
|
168
|
-
<text selectable={false} fg={delegationColor(theme, row.status)}>{delegationSymbol(row.status)}</text>
|
|
169
|
-
<text fg={row.active ? theme.accent : theme.text}>{truncate(row.agent, 24)}</text>
|
|
170
|
-
<text fg={theme.textMuted}>{truncate(firstLine(row.task), 80)}</text>
|
|
171
|
-
</box>
|
|
172
|
-
<Show when={props.expanded && row.preview}>
|
|
173
|
-
<box paddingLeft={2}>
|
|
174
|
-
<text fg={theme.textMuted}>{truncate(firstLine(String(row.preview)), 120)}</text>
|
|
175
|
-
</box>
|
|
176
|
-
</Show>
|
|
177
|
-
</box>
|
|
178
|
-
))}
|
|
179
|
-
<Show when={props.ui && props.ui.items.length > maxItems()}>
|
|
180
|
-
<text fg={theme.textMuted}>… {props.ui!.items.length - maxItems()} more …</text>
|
|
181
|
-
</Show>
|
|
182
|
-
<Show when={!props.ui && ((props.args?.chain?.length ?? 0) > maxItems() || (props.args?.tasks?.length ?? 0) > maxItems())}>
|
|
183
|
-
<text fg={theme.textMuted}>… more …</text>
|
|
184
|
-
</Show>
|
|
185
|
-
</box>
|
|
186
|
-
)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function truncateHeadTail(text: string, headCount: number, tailCount: number): { text: string; truncated: boolean; omitted: number } {
|
|
190
|
-
const lines = replaceTabs(text).split("\n")
|
|
191
|
-
if (lines.length <= headCount + tailCount) {
|
|
192
|
-
return { text: lines.join("\n"), truncated: false, omitted: 0 }
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const head = lines.slice(0, headCount)
|
|
196
|
-
const tail = lines.slice(-tailCount)
|
|
197
|
-
return {
|
|
198
|
-
text: [...head, "", `… ${lines.length - (headCount + tailCount)} lines omitted …`, "", ...tail].join("\n"),
|
|
199
|
-
truncated: true,
|
|
200
|
-
omitted: lines.length - (headCount + tailCount),
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
function truncateLines(text: string, maxLines: number): { text: string; truncated: boolean; omitted: number } {
|
|
205
|
-
const lines = replaceTabs(text).split("\n")
|
|
206
|
-
if (lines.length <= maxLines) return { text: lines.join("\n"), truncated: false, omitted: 0 }
|
|
207
|
-
return {
|
|
208
|
-
text: [...lines.slice(0, maxLines), `… ${lines.length - maxLines} more lines …`].join("\n"),
|
|
209
|
-
truncated: true,
|
|
210
|
-
omitted: lines.length - maxLines,
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/** Extract +/- line counts from unified diff */
|
|
215
|
-
function getDiffStats(diffText: string): { added: number; removed: number } {
|
|
216
|
-
let added = 0
|
|
217
|
-
let removed = 0
|
|
218
|
-
for (const line of diffText.split("\n")) {
|
|
219
|
-
if (line.startsWith("+") && !line.startsWith("+++")) added++
|
|
220
|
-
else if (line.startsWith("-") && !line.startsWith("---")) removed++
|
|
221
|
-
}
|
|
222
|
-
return { added, removed }
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
function getDiffStartLine(diffText: string): number | undefined {
|
|
226
|
-
const match = diffText.match(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@/m)
|
|
227
|
-
if (!match) return undefined
|
|
228
|
-
const line = Number.parseInt(match[1], 10)
|
|
229
|
-
if (!Number.isFinite(line) || line <= 0) return undefined
|
|
230
|
-
return line
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function toolTitle(name: string, args: any): string {
|
|
234
|
-
switch (name) {
|
|
235
|
-
case "bash": {
|
|
236
|
-
// Prefer description if available
|
|
237
|
-
if (args?.description) return truncate(String(args.description), 50)
|
|
238
|
-
const cmd = String(args?.command || "…")
|
|
239
|
-
return truncate(cmd.split("\n")[0] || "…", 40)
|
|
240
|
-
}
|
|
241
|
-
case "read":
|
|
242
|
-
return shortenPath(String(args?.path || args?.file_path || "…"), 35)
|
|
243
|
-
case "write":
|
|
244
|
-
return shortenPath(String(args?.path || args?.file_path || "…"), 35)
|
|
245
|
-
case "edit":
|
|
246
|
-
return shortenPath(String(args?.path || args?.file_path || "…"), 35)
|
|
247
|
-
// ask_user_question removed - use interview custom tool
|
|
248
|
-
default: {
|
|
249
|
-
const delegation = getAgentDelegationArgs(args)
|
|
250
|
-
if (delegation?.chain?.length) return `chain ${delegation.chain.length}`
|
|
251
|
-
if (delegation?.tasks?.length) return `${delegation.tasks.length} tasks`
|
|
252
|
-
if (delegation?.agent) return truncate(delegation.agent, 30)
|
|
253
|
-
return ""
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
export function Thinking(props: { summary: string }): JSX.Element {
|
|
259
|
-
const { theme } = useTheme()
|
|
260
|
-
return (
|
|
261
|
-
<text selectable={false} fg={theme.textMuted} attributes={TextAttributes.ITALIC}>
|
|
262
|
-
thinking {props.summary}
|
|
263
|
-
</text>
|
|
264
|
-
)
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
export interface ToolBlockProps {
|
|
268
|
-
name: string
|
|
269
|
-
args: any
|
|
270
|
-
output: string | null
|
|
271
|
-
editDiff: string | null
|
|
272
|
-
isError: boolean
|
|
273
|
-
isComplete: boolean
|
|
274
|
-
expanded?: boolean
|
|
275
|
-
onToggleExpanded?: () => void
|
|
276
|
-
diffWrapMode?: "word" | "none"
|
|
277
|
-
// Edit file callback - opens file in editor for user review
|
|
278
|
-
onEditFile?: (path: string, line?: number) => void
|
|
279
|
-
// Custom tool metadata
|
|
280
|
-
label?: string
|
|
281
|
-
source?: "builtin" | "custom"
|
|
282
|
-
sourcePath?: string
|
|
283
|
-
result?: { content: any[]; details: any }
|
|
284
|
-
renderCall?: (args: any, theme: Theme) => JSX.Element
|
|
285
|
-
renderResult?: (result: any, opts: { expanded: boolean; isPartial: boolean }, theme: Theme) => JSX.Element
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
type ToolRenderMode = "inline" | "block"
|
|
289
|
-
|
|
290
|
-
interface ToolRenderContext {
|
|
291
|
-
name: string
|
|
292
|
-
args: any
|
|
293
|
-
output: string | null
|
|
294
|
-
editDiff: string | null
|
|
295
|
-
result: ToolBlockProps["result"] | null
|
|
296
|
-
isError: boolean
|
|
297
|
-
isComplete: boolean
|
|
298
|
-
expanded: boolean
|
|
299
|
-
diffWrapMode: "word" | "none"
|
|
300
|
-
onEditFile?: (path: string, line?: number) => void
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
interface ToolRenderer {
|
|
304
|
-
mode: (ctx: ToolRenderContext) => ToolRenderMode
|
|
305
|
-
renderHeader?: (ctx: ToolRenderContext) => JSX.Element
|
|
306
|
-
renderBody?: (ctx: ToolRenderContext) => JSX.Element
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
function defaultHeader(ctx: ToolRenderContext): JSX.Element {
|
|
310
|
-
const title = toolTitle(ctx.name, ctx.args)
|
|
311
|
-
const delegationUi = getAgentDelegationUi(ctx.result?.details)
|
|
312
|
-
const suffix = delegationUi ? formatDelegationSuffix(delegationUi) : undefined
|
|
313
|
-
return <ToolHeader label={ctx.name} detail={title} suffix={suffix} isComplete={ctx.isComplete} isError={ctx.isError} expanded={ctx.expanded} />
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// Tool header: compact "▸ label detail" format
|
|
317
|
-
interface ToolHeaderProps {
|
|
318
|
-
label: string
|
|
319
|
-
detail?: string
|
|
320
|
-
suffix?: string
|
|
321
|
-
isComplete: boolean
|
|
322
|
-
isError: boolean
|
|
323
|
-
expanded: boolean
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
function ToolHeader(props: ToolHeaderProps): JSX.Element {
|
|
327
|
-
const { theme } = useTheme()
|
|
328
|
-
|
|
329
|
-
const symbol = () => {
|
|
330
|
-
if (!props.isComplete) return symbols.running
|
|
331
|
-
if (props.isError) return symbols.error
|
|
332
|
-
if (props.expanded) return symbols.expanded
|
|
333
|
-
return symbols.complete
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const symbolColor = () => {
|
|
337
|
-
if (props.isError) return theme.error
|
|
338
|
-
return theme.textMuted
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
// Tool name gets subtle accent, rest muted
|
|
342
|
-
return (
|
|
343
|
-
<text selectable={false}>
|
|
344
|
-
<span style={{ fg: symbolColor() }}>{symbol()}</span>
|
|
345
|
-
<span style={{ fg: theme.accent }}> {props.label}</span>
|
|
346
|
-
<Show when={props.detail}>
|
|
347
|
-
<span style={{ fg: theme.textMuted }}> {props.detail}</span>
|
|
348
|
-
</Show>
|
|
349
|
-
<Show when={props.suffix}>
|
|
350
|
-
<span style={{ fg: theme.textMuted }}> · {props.suffix}</span>
|
|
351
|
-
</Show>
|
|
352
|
-
</text>
|
|
353
|
-
)
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
const registry: Record<string, ToolRenderer> = {
|
|
357
|
-
bash: {
|
|
358
|
-
// Inline when collapsed (just command), block when expanded (show output)
|
|
359
|
-
mode: (ctx) => (ctx.expanded ? "block" : "inline"),
|
|
360
|
-
renderHeader: (ctx) => {
|
|
361
|
-
// Prefer description if available, otherwise truncate command
|
|
362
|
-
let detail: string
|
|
363
|
-
if (ctx.args?.description) {
|
|
364
|
-
detail = truncate(String(ctx.args.description), 60)
|
|
365
|
-
} else {
|
|
366
|
-
const cmd = String(ctx.args?.command || "…").split("\n")[0] || "…"
|
|
367
|
-
detail = truncate(cmd, 50)
|
|
368
|
-
}
|
|
369
|
-
return <ToolHeader label="bash" detail={detail} isComplete={ctx.isComplete} isError={ctx.isError} expanded={ctx.expanded} />
|
|
370
|
-
},
|
|
371
|
-
renderBody: (ctx) => {
|
|
372
|
-
const { theme } = useTheme()
|
|
373
|
-
// Only show body when expanded
|
|
374
|
-
if (!ctx.expanded) return null
|
|
375
|
-
if (!ctx.output) return <text fg={theme.textMuted}>no output</text>
|
|
376
|
-
return <CodeBlock content={replaceTabs(ctx.output)} filetype="text" showLineNumbers={false} wrapMode="none" />
|
|
377
|
-
},
|
|
378
|
-
},
|
|
379
|
-
read: {
|
|
380
|
-
mode: (ctx) => (ctx.expanded ? "block" : "inline"),
|
|
381
|
-
renderHeader: (ctx) => {
|
|
382
|
-
const path = shortenPath(String(ctx.args?.path || ctx.args?.file_path || "…"))
|
|
383
|
-
return <ToolHeader label="read" detail={path} isComplete={ctx.isComplete} isError={ctx.isError} expanded={ctx.expanded} />
|
|
384
|
-
},
|
|
385
|
-
renderBody: (ctx) => {
|
|
386
|
-
const { theme } = useTheme()
|
|
387
|
-
const imageBlocks = (ctx.result?.content ?? []).filter(
|
|
388
|
-
(block) =>
|
|
389
|
-
typeof block === "object" &&
|
|
390
|
-
block !== null &&
|
|
391
|
-
(block as { type?: string }).type === "image" &&
|
|
392
|
-
typeof (block as { data?: string }).data === "string" &&
|
|
393
|
-
typeof (block as { mimeType?: string }).mimeType === "string",
|
|
394
|
-
) as Array<{ data: string; mimeType: string }>
|
|
395
|
-
|
|
396
|
-
if (!ctx.output && imageBlocks.length === 0) return <text fg={theme.textMuted}>reading…</text>
|
|
397
|
-
const rendered = ctx.output ? (ctx.expanded ? replaceTabs(ctx.output) : truncateLines(ctx.output, 20).text) : ""
|
|
398
|
-
const filetype = getLanguageFromPath(String(ctx.args?.path || ctx.args?.file_path || ""))
|
|
399
|
-
const preview = rendered ? <CodeBlock content={rendered} filetype={filetype} title="preview" /> : null
|
|
400
|
-
if (imageBlocks.length === 0) return preview ?? <text fg={theme.textMuted}>no preview</text>
|
|
401
|
-
|
|
402
|
-
return (
|
|
403
|
-
<box flexDirection="column" gap={1}>
|
|
404
|
-
{preview}
|
|
405
|
-
{imageBlocks.map((img) => (
|
|
406
|
-
<Image data={img.data} mimeType={img.mimeType} maxWidth={60} />
|
|
407
|
-
))}
|
|
408
|
-
</box>
|
|
409
|
-
)
|
|
410
|
-
},
|
|
411
|
-
},
|
|
412
|
-
|
|
413
|
-
write: {
|
|
414
|
-
mode: () => "block",
|
|
415
|
-
renderHeader: (ctx) => {
|
|
416
|
-
const path = shortenPath(String(ctx.args?.path || ctx.args?.file_path || "…"))
|
|
417
|
-
return <ToolHeader label="write" detail={path} isComplete={ctx.isComplete} isError={ctx.isError} expanded={ctx.expanded} />
|
|
418
|
-
},
|
|
419
|
-
renderBody: (ctx) => {
|
|
420
|
-
const { theme } = useTheme()
|
|
421
|
-
const content = String(ctx.args?.content || "")
|
|
422
|
-
if (!content && !ctx.isComplete) return <text fg={theme.textMuted}>writing…</text>
|
|
423
|
-
if (!content) return <text fg={theme.textMuted}>no content</text>
|
|
424
|
-
|
|
425
|
-
const filetype = getLanguageFromPath(String(ctx.args?.path || ctx.args?.file_path || ""))
|
|
426
|
-
const rendered = ctx.expanded ? replaceTabs(content) : truncateLines(content, 40).text
|
|
427
|
-
return <CodeBlock content={rendered} filetype={filetype} title="write" />
|
|
428
|
-
},
|
|
429
|
-
},
|
|
430
|
-
edit: {
|
|
431
|
-
mode: (ctx) => (ctx.expanded ? "block" : "inline"),
|
|
432
|
-
renderHeader: (ctx) => {
|
|
433
|
-
const { theme } = useTheme()
|
|
434
|
-
const path = shortenPath(String(ctx.args?.path || ctx.args?.file_path || "…"))
|
|
435
|
-
const fullPath = String(ctx.args?.path || ctx.args?.file_path || "")
|
|
436
|
-
const diffStats = ctx.editDiff ? getDiffStats(ctx.editDiff) : null
|
|
437
|
-
const startLine = ctx.editDiff ? getDiffStartLine(ctx.editDiff) : undefined
|
|
438
|
-
const suffix = ctx.isComplete && !ctx.isError && diffStats ? `+${diffStats.added}/-${diffStats.removed}` : undefined
|
|
439
|
-
const showEditButton = ctx.isComplete && !ctx.isError && ctx.onEditFile && fullPath
|
|
440
|
-
return (
|
|
441
|
-
<box flexDirection="row">
|
|
442
|
-
<ToolHeader label="edit" detail={path} suffix={suffix} isComplete={ctx.isComplete} isError={ctx.isError} expanded={ctx.expanded} />
|
|
443
|
-
{showEditButton && (
|
|
444
|
-
<text
|
|
445
|
-
fg={theme.textMuted}
|
|
446
|
-
onMouseUp={(e: { stopPropagation?: () => void }) => {
|
|
447
|
-
e.stopPropagation?.()
|
|
448
|
-
ctx.onEditFile?.(fullPath, startLine)
|
|
449
|
-
}}
|
|
450
|
-
>
|
|
451
|
-
{" [e]"}
|
|
452
|
-
</text>
|
|
453
|
-
)}
|
|
454
|
-
</box>
|
|
455
|
-
)
|
|
456
|
-
},
|
|
457
|
-
renderBody: (ctx) => {
|
|
458
|
-
const { theme } = useTheme()
|
|
459
|
-
// Only show body when expanded
|
|
460
|
-
if (!ctx.expanded) return null
|
|
461
|
-
if (ctx.editDiff) {
|
|
462
|
-
const filetype = getLanguageFromPath(String(ctx.args?.path || ctx.args?.file_path || ""))
|
|
463
|
-
const diffLines = ctx.editDiff.split("\n").length
|
|
464
|
-
if (diffLines > 150) {
|
|
465
|
-
const truncated = truncateHeadTail(ctx.editDiff, 60, 40)
|
|
466
|
-
return <DiffPreview text={truncated.text} />
|
|
467
|
-
}
|
|
468
|
-
return <Diff diffText={ctx.editDiff} filetype={filetype} wrapMode={ctx.diffWrapMode} />
|
|
469
|
-
}
|
|
470
|
-
if (!ctx.output && !ctx.isComplete) return <text fg={theme.textMuted}>editing…</text>
|
|
471
|
-
return <text fg={ctx.isError ? theme.error : theme.text}>{ctx.output ?? ""}</text>
|
|
472
|
-
},
|
|
473
|
-
},
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
export function ToolBlock(props: ToolBlockProps): JSX.Element {
|
|
477
|
-
const { theme } = useTheme()
|
|
478
|
-
|
|
479
|
-
// Use a getter for expanded to maintain reactivity
|
|
480
|
-
const ctx: ToolRenderContext = {
|
|
481
|
-
name: props.name,
|
|
482
|
-
args: props.args,
|
|
483
|
-
output: props.output,
|
|
484
|
-
editDiff: props.editDiff,
|
|
485
|
-
result: props.result ?? null,
|
|
486
|
-
isError: props.isError,
|
|
487
|
-
isComplete: props.isComplete,
|
|
488
|
-
get expanded() { return props.expanded ?? false },
|
|
489
|
-
get diffWrapMode() { return props.diffWrapMode ?? "word" },
|
|
490
|
-
onEditFile: props.onEditFile,
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
const renderer = registry[props.name] ?? {
|
|
494
|
-
mode: () => "block",
|
|
495
|
-
renderBody: (innerCtx) => {
|
|
496
|
-
const delegationUi = getAgentDelegationUi(innerCtx.result?.details)
|
|
497
|
-
const delegationArgs = getAgentDelegationArgs(innerCtx.args)
|
|
498
|
-
|
|
499
|
-
if (delegationUi || delegationArgs) {
|
|
500
|
-
return <AgentDelegationView args={delegationArgs} ui={delegationUi} expanded={innerCtx.expanded} />
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
const out = innerCtx.output ? innerCtx.output : JSON.stringify(innerCtx.args ?? {}, null, 2)
|
|
504
|
-
const rendered = innerCtx.expanded ? replaceTabs(out) : truncateLines(out, 20).text
|
|
505
|
-
return <CodeBlock content={rendered} filetype="text" title="output" showLineNumbers={false} />
|
|
506
|
-
},
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
// Custom tool rendering: prefer tool-provided renderers, fallback to registry
|
|
510
|
-
const tryCustomRenderCall = (): JSX.Element | null => {
|
|
511
|
-
if (!props.renderCall) return null
|
|
512
|
-
try {
|
|
513
|
-
return props.renderCall(props.args, theme)
|
|
514
|
-
} catch {
|
|
515
|
-
return null // Fallback to default on error
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
const tryCustomRenderResult = (): JSX.Element | null => {
|
|
520
|
-
if (!props.renderResult || !props.result) return null
|
|
521
|
-
try {
|
|
522
|
-
return props.renderResult(props.result, { expanded: props.expanded ?? false, isPartial: !props.isComplete }, theme)
|
|
523
|
-
} catch {
|
|
524
|
-
return null // Fallback to default on error
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
// Use functions to ensure reactivity
|
|
529
|
-
const mode = () => renderer.mode(ctx)
|
|
530
|
-
const header = () => tryCustomRenderCall() ?? renderer.renderHeader?.(ctx) ?? defaultHeader(ctx)
|
|
531
|
-
const body = () => tryCustomRenderResult() ?? renderer.renderBody?.(ctx)
|
|
532
|
-
|
|
533
|
-
return (
|
|
534
|
-
<Show when={mode() === "inline"} fallback={
|
|
535
|
-
// Block layout - entire block is clickable to toggle
|
|
536
|
-
<box
|
|
537
|
-
flexDirection="column"
|
|
538
|
-
gap={0}
|
|
539
|
-
onMouseUp={(e: MouseEvent) => {
|
|
540
|
-
if (e.isSelecting) return
|
|
541
|
-
props.onToggleExpanded?.()
|
|
542
|
-
}}
|
|
543
|
-
>
|
|
544
|
-
{header()}
|
|
545
|
-
<Show when={body()}>
|
|
546
|
-
<box paddingLeft={2} paddingTop={1}>
|
|
547
|
-
{body()}
|
|
548
|
-
</box>
|
|
549
|
-
</Show>
|
|
550
|
-
</box>
|
|
551
|
-
}>
|
|
552
|
-
{/* Inline layout - clickable to expand */}
|
|
553
|
-
<box
|
|
554
|
-
flexDirection="row"
|
|
555
|
-
gap={0}
|
|
556
|
-
onMouseUp={(e: MouseEvent) => {
|
|
557
|
-
if (e.isSelecting) return
|
|
558
|
-
props.onToggleExpanded?.()
|
|
559
|
-
}}
|
|
560
|
-
>
|
|
561
|
-
{header()}
|
|
562
|
-
</box>
|
|
563
|
-
</Show>
|
|
564
|
-
)
|
|
565
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared types for TUI application
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/** Content block that preserves order from API response */
|
|
6
|
-
export type UIContentBlock =
|
|
7
|
-
| { type: "thinking"; id: string; summary: string; preview: string; full: string }
|
|
8
|
-
| { type: "text"; text: string }
|
|
9
|
-
| { type: "tool"; tool: ToolBlock }
|
|
10
|
-
|
|
11
|
-
/** User message */
|
|
12
|
-
export interface UIUserMessage {
|
|
13
|
-
id: string
|
|
14
|
-
role: "user"
|
|
15
|
-
content: string
|
|
16
|
-
timestamp?: number
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/** Assistant message with optional tool calls and thinking */
|
|
20
|
-
export interface UIAssistantMessage {
|
|
21
|
-
id: string
|
|
22
|
-
role: "assistant"
|
|
23
|
-
content: string
|
|
24
|
-
/** Ordered content blocks - preserves interleaving of thinking, text, tools */
|
|
25
|
-
contentBlocks?: UIContentBlock[]
|
|
26
|
-
/** @deprecated Use contentBlocks instead - kept for backward compat */
|
|
27
|
-
thinking?: { summary: string; preview: string; full: string }
|
|
28
|
-
isStreaming?: boolean
|
|
29
|
-
/** @deprecated Use contentBlocks instead - kept for backward compat */
|
|
30
|
-
tools?: ToolBlock[]
|
|
31
|
-
timestamp?: number
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** Shell command execution result (from ! prefix) */
|
|
35
|
-
export interface UIShellMessage {
|
|
36
|
-
id: string
|
|
37
|
-
role: "shell"
|
|
38
|
-
command: string
|
|
39
|
-
output: string
|
|
40
|
-
exitCode: number | null
|
|
41
|
-
truncated: boolean
|
|
42
|
-
tempFilePath?: string
|
|
43
|
-
timestamp?: number
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export type UIMessage = UIUserMessage | UIAssistantMessage | UIShellMessage
|
|
47
|
-
|
|
48
|
-
import type { AgentToolResult } from "@yeshwanthyk/ai"
|
|
49
|
-
import type { Theme } from "@yeshwanthyk/open-tui"
|
|
50
|
-
import type { JSX } from "solid-js"
|
|
51
|
-
import type { RenderResultOptions } from "@yeshwanthyk/runtime-effect/extensibility/custom-tools/types.js"
|
|
52
|
-
|
|
53
|
-
export interface ToolBlock {
|
|
54
|
-
id: string
|
|
55
|
-
name: string
|
|
56
|
-
args: unknown
|
|
57
|
-
/** Monotonic counter to invalidate UI caches on tool updates */
|
|
58
|
-
updateSeq?: number
|
|
59
|
-
output?: string
|
|
60
|
-
editDiff?: string
|
|
61
|
-
isError: boolean
|
|
62
|
-
isComplete: boolean
|
|
63
|
-
// Custom tool metadata
|
|
64
|
-
label?: string
|
|
65
|
-
source?: "builtin" | "custom"
|
|
66
|
-
sourcePath?: string
|
|
67
|
-
result?: AgentToolResult<any>
|
|
68
|
-
renderCall?: (args: any, theme: Theme) => JSX.Element
|
|
69
|
-
renderResult?: (result: AgentToolResult<any>, opts: RenderResultOptions, theme: Theme) => JSX.Element
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export type ActivityState = "idle" | "thinking" | "streaming" | "tool" | "compacting"
|
|
73
|
-
|
|
74
|
-
/** Grouped section for display - thinking header with nested tools */
|
|
75
|
-
export interface SectionItem {
|
|
76
|
-
type: "section"
|
|
77
|
-
id: string
|
|
78
|
-
thinking: { id: string; summary: string; full: string } | null
|
|
79
|
-
tools: ToolBlock[]
|
|
80
|
-
isComplete: boolean // true when all tools complete
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export type ContentItem =
|
|
84
|
-
| { type: "user"; content: string }
|
|
85
|
-
| { type: "thinking"; id: string; summary: string; preview: string; full: string; isStreaming?: boolean }
|
|
86
|
-
| { type: "assistant"; content: string; isStreaming?: boolean }
|
|
87
|
-
| { type: "tool"; tool: ToolBlock }
|
|
88
|
-
| { type: "section"; section: SectionItem }
|
|
89
|
-
| { type: "shell"; command: string; output: string; exitCode: number | null; truncated: boolean; tempFilePath?: string }
|