@mseep/claudian 2.0.25
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/.env.local.example +2 -0
- package/.github/workflows/ci.yml +59 -0
- package/.github/workflows/claude-code-review.yml +57 -0
- package/.github/workflows/claude.yml +50 -0
- package/.github/workflows/duplicate-issues.yml +22 -0
- package/.github/workflows/release.yml +73 -0
- package/.github/workflows/stale.yml +21 -0
- package/.node-version +1 -0
- package/AGENTS.md +3 -0
- package/CLAUDE.md +80 -0
- package/LICENSE +21 -0
- package/README.md +190 -0
- package/assets/Preview.png +0 -0
- package/assets/sponsors/MOMA.png +0 -0
- package/bun.lock +1618 -0
- package/esbuild.config.mjs +195 -0
- package/eslint.config.mjs +143 -0
- package/jest.config.js +41 -0
- package/main.js +104915 -0
- package/manifest.json +10 -0
- package/package.json +65 -0
- package/scripts/build-css.mjs +119 -0
- package/scripts/build.mjs +19 -0
- package/scripts/postinstall.mjs +25 -0
- package/scripts/rendererSafeUnref.js +205 -0
- package/scripts/run-jest.js +19 -0
- package/scripts/sync-version.js +16 -0
- package/src/app/settings/ClaudianSettingsStorage.ts +435 -0
- package/src/app/settings/defaultSettings.ts +54 -0
- package/src/app/storage/SharedStorageService.ts +106 -0
- package/src/core/CLAUDE.md +84 -0
- package/src/core/auxiliary/AuxQueryRunner.ts +11 -0
- package/src/core/auxiliary/QueryBackedInlineEditService.ts +73 -0
- package/src/core/auxiliary/QueryBackedInstructionRefineService.ts +78 -0
- package/src/core/auxiliary/QueryBackedTitleGenerationService.ts +90 -0
- package/src/core/bootstrap/SessionStorage.ts +179 -0
- package/src/core/bootstrap/StoragePaths.ts +7 -0
- package/src/core/bootstrap/storage.ts +20 -0
- package/src/core/commands/builtInCommands.ts +141 -0
- package/src/core/mcp/McpConfigParser.ts +102 -0
- package/src/core/mcp/McpServerManager.ts +119 -0
- package/src/core/mcp/McpTester.ts +310 -0
- package/src/core/prompt/inlineEdit.ts +252 -0
- package/src/core/prompt/instructionRefine.ts +72 -0
- package/src/core/prompt/mainAgent.ts +213 -0
- package/src/core/prompt/titleGeneration.ts +44 -0
- package/src/core/providers/ProviderRegistry.ts +253 -0
- package/src/core/providers/ProviderSettingsCoordinator.ts +434 -0
- package/src/core/providers/ProviderWorkspaceRegistry.ts +119 -0
- package/src/core/providers/commands/ProviderCommandCatalog.ts +21 -0
- package/src/core/providers/commands/ProviderCommandEntry.ts +33 -0
- package/src/core/providers/commands/hiddenCommands.ts +74 -0
- package/src/core/providers/modelRouting.ts +17 -0
- package/src/core/providers/modelSelection.ts +72 -0
- package/src/core/providers/providerConfig.ts +34 -0
- package/src/core/providers/providerEnvironment.ts +364 -0
- package/src/core/providers/types.ts +544 -0
- package/src/core/runtime/ChatRuntime.ts +66 -0
- package/src/core/runtime/QueuedTurn.ts +97 -0
- package/src/core/runtime/types.ts +118 -0
- package/src/core/security/ApprovalManager.ts +142 -0
- package/src/core/storage/HomeFileAdapter.ts +75 -0
- package/src/core/storage/VaultFileAdapter.ts +132 -0
- package/src/core/tools/todo.ts +65 -0
- package/src/core/tools/toolIcons.ts +80 -0
- package/src/core/tools/toolInput.ts +119 -0
- package/src/core/tools/toolNames.ts +149 -0
- package/src/core/tools/toolResultContent.ts +26 -0
- package/src/core/types/agent.ts +28 -0
- package/src/core/types/chat.ts +177 -0
- package/src/core/types/diff.ts +31 -0
- package/src/core/types/index.ts +78 -0
- package/src/core/types/mcp.ts +97 -0
- package/src/core/types/plugins.ts +9 -0
- package/src/core/types/provider.ts +1 -0
- package/src/core/types/settings.ts +152 -0
- package/src/core/types/tools.ts +80 -0
- package/src/features/chat/CLAUDE.md +136 -0
- package/src/features/chat/ClaudianView.ts +762 -0
- package/src/features/chat/constants.ts +114 -0
- package/src/features/chat/controllers/BrowserSelectionController.ts +295 -0
- package/src/features/chat/controllers/CanvasSelectionController.ts +142 -0
- package/src/features/chat/controllers/ConversationController.ts +1103 -0
- package/src/features/chat/controllers/InputController.ts +1707 -0
- package/src/features/chat/controllers/NavigationController.ts +209 -0
- package/src/features/chat/controllers/SelectionController.ts +430 -0
- package/src/features/chat/controllers/StreamController.ts +1560 -0
- package/src/features/chat/controllers/contextRowVisibility.ts +18 -0
- package/src/features/chat/rendering/DiffRenderer.ts +134 -0
- package/src/features/chat/rendering/InlineAskUserQuestion.ts +702 -0
- package/src/features/chat/rendering/InlineExitPlanMode.ts +263 -0
- package/src/features/chat/rendering/InlinePlanApproval.ts +183 -0
- package/src/features/chat/rendering/MessageRenderer.ts +907 -0
- package/src/features/chat/rendering/SubagentRenderer.ts +678 -0
- package/src/features/chat/rendering/ThinkingBlockRenderer.ts +126 -0
- package/src/features/chat/rendering/TodoListRenderer.ts +5 -0
- package/src/features/chat/rendering/ToolCallRenderer.ts +1161 -0
- package/src/features/chat/rendering/WriteEditRenderer.ts +232 -0
- package/src/features/chat/rendering/collapsible.ts +101 -0
- package/src/features/chat/rendering/subagentLifecycleResolution.ts +25 -0
- package/src/features/chat/rendering/todoUtils.ts +29 -0
- package/src/features/chat/rewind.ts +31 -0
- package/src/features/chat/services/BangBashService.ts +56 -0
- package/src/features/chat/services/SubagentManager.ts +1107 -0
- package/src/features/chat/state/ChatState.ts +436 -0
- package/src/features/chat/state/types.ts +138 -0
- package/src/features/chat/tabs/Tab.ts +1886 -0
- package/src/features/chat/tabs/TabBar.ts +179 -0
- package/src/features/chat/tabs/TabManager.ts +1021 -0
- package/src/features/chat/tabs/providerResolution.ts +34 -0
- package/src/features/chat/tabs/types.ts +287 -0
- package/src/features/chat/ui/BangBashModeManager.ts +121 -0
- package/src/features/chat/ui/FileContext.ts +385 -0
- package/src/features/chat/ui/ImageContext.ts +366 -0
- package/src/features/chat/ui/InputToolbar.ts +1244 -0
- package/src/features/chat/ui/InstructionModeManager.ts +158 -0
- package/src/features/chat/ui/NavigationSidebar.ts +126 -0
- package/src/features/chat/ui/StatusPanel.ts +589 -0
- package/src/features/chat/ui/file-context/state/FileContextState.ts +83 -0
- package/src/features/chat/ui/file-context/view/FileChipsView.ts +70 -0
- package/src/features/chat/ui/textareaResize.ts +47 -0
- package/src/features/chat/utils/usageInfo.ts +26 -0
- package/src/features/inline-edit/ui/InlineEditModal.ts +895 -0
- package/src/features/inline-edit/ui/inlineEditMarkdownPreview.ts +55 -0
- package/src/features/settings/ClaudianSettings.ts +672 -0
- package/src/features/settings/keyboardNavigation.ts +60 -0
- package/src/features/settings/ui/EnvSnippetManager.ts +430 -0
- package/src/features/settings/ui/EnvironmentSettingsSection.ts +85 -0
- package/src/features/settings/ui/McpServerModal.ts +335 -0
- package/src/features/settings/ui/McpSettingsManager.ts +400 -0
- package/src/features/settings/ui/McpTestModal.ts +346 -0
- package/src/i18n/constants.ts +58 -0
- package/src/i18n/i18n.ts +140 -0
- package/src/i18n/locales/de.json +322 -0
- package/src/i18n/locales/en.json +322 -0
- package/src/i18n/locales/es.json +322 -0
- package/src/i18n/locales/fr.json +322 -0
- package/src/i18n/locales/ja.json +322 -0
- package/src/i18n/locales/ko.json +322 -0
- package/src/i18n/locales/pt.json +322 -0
- package/src/i18n/locales/ru.json +322 -0
- package/src/i18n/locales/zh-CN.json +322 -0
- package/src/i18n/locales/zh-TW.json +322 -0
- package/src/i18n/types.ts +248 -0
- package/src/main.ts +772 -0
- package/src/providers/acp/AcpClientConnection.ts +361 -0
- package/src/providers/acp/AcpJsonRpcTransport.ts +427 -0
- package/src/providers/acp/AcpSessionConfig.ts +139 -0
- package/src/providers/acp/AcpSessionUpdateNormalizer.ts +371 -0
- package/src/providers/acp/AcpSubprocess.ts +155 -0
- package/src/providers/acp/AcpToolStreamAdapter.ts +132 -0
- package/src/providers/acp/buildAcpUsageInfo.ts +41 -0
- package/src/providers/acp/index.ts +9 -0
- package/src/providers/acp/methodNames.ts +50 -0
- package/src/providers/acp/types.ts +566 -0
- package/src/providers/claude/CLAUDE.md +78 -0
- package/src/providers/claude/agents/AgentManager.ts +225 -0
- package/src/providers/claude/agents/AgentStorage.ts +101 -0
- package/src/providers/claude/app/ClaudeWorkspaceServices.ts +90 -0
- package/src/providers/claude/auxiliary/ClaudeInlineEditService.ts +122 -0
- package/src/providers/claude/auxiliary/ClaudeInstructionRefineService.ts +90 -0
- package/src/providers/claude/auxiliary/ClaudeTitleGenerationService.ts +129 -0
- package/src/providers/claude/auxiliary/extractAssistantText.ts +28 -0
- package/src/providers/claude/capabilities.ts +17 -0
- package/src/providers/claude/cli/findClaudeCLIPath.ts +261 -0
- package/src/providers/claude/commands/ClaudeCommandCatalog.ts +149 -0
- package/src/providers/claude/commands/probeRuntimeCommands.ts +86 -0
- package/src/providers/claude/env/ClaudeSettingsReconciler.ts +90 -0
- package/src/providers/claude/env/claudeModelEnv.ts +86 -0
- package/src/providers/claude/history/ClaudeConversationHistoryService.ts +446 -0
- package/src/providers/claude/history/ClaudeHistoryStore.ts +170 -0
- package/src/providers/claude/history/sdkAsyncSubagent.ts +92 -0
- package/src/providers/claude/history/sdkBranchFilter.ts +271 -0
- package/src/providers/claude/history/sdkHistoryTypes.ts +61 -0
- package/src/providers/claude/history/sdkMessageParsing.ts +413 -0
- package/src/providers/claude/history/sdkSessionPaths.ts +98 -0
- package/src/providers/claude/history/sdkSubagentSidecar.ts +261 -0
- package/src/providers/claude/hooks/SubagentHooks.ts +31 -0
- package/src/providers/claude/modelLabels.ts +77 -0
- package/src/providers/claude/modelOptions.ts +113 -0
- package/src/providers/claude/modelSelection.ts +17 -0
- package/src/providers/claude/plugins/PluginManager.ts +194 -0
- package/src/providers/claude/prompt/ClaudeTurnEncoder.ts +46 -0
- package/src/providers/claude/registration.ts +39 -0
- package/src/providers/claude/runtime/ClaudeApprovalHandler.ts +153 -0
- package/src/providers/claude/runtime/ClaudeChatRuntime.ts +1812 -0
- package/src/providers/claude/runtime/ClaudeCliResolver.ts +94 -0
- package/src/providers/claude/runtime/ClaudeDynamicUpdates.ts +164 -0
- package/src/providers/claude/runtime/ClaudeMessageChannel.ts +209 -0
- package/src/providers/claude/runtime/ClaudeQueryOptionsBuilder.ts +315 -0
- package/src/providers/claude/runtime/ClaudeRewindService.ts +220 -0
- package/src/providers/claude/runtime/ClaudeSessionManager.ts +92 -0
- package/src/providers/claude/runtime/ClaudeTaskResultInterpreter.ts +172 -0
- package/src/providers/claude/runtime/ClaudeUserMessageFactory.ts +83 -0
- package/src/providers/claude/runtime/claudeColdStartQuery.ts +152 -0
- package/src/providers/claude/runtime/customSpawn.ts +87 -0
- package/src/providers/claude/runtime/types.ts +134 -0
- package/src/providers/claude/sdk/messages.ts +17 -0
- package/src/providers/claude/sdk/toolResultContent.ts +4 -0
- package/src/providers/claude/sdk/typeGuards.ts +14 -0
- package/src/providers/claude/sdk/types.ts +15 -0
- package/src/providers/claude/security/ClaudePermissionUpdates.ts +44 -0
- package/src/providers/claude/settings.ts +138 -0
- package/src/providers/claude/storage/AgentVaultStorage.ts +101 -0
- package/src/providers/claude/storage/CCSettingsStorage.ts +153 -0
- package/src/providers/claude/storage/ClaudianSettingsStorage.ts +6 -0
- package/src/providers/claude/storage/McpStorage.ts +139 -0
- package/src/providers/claude/storage/SessionStorage.ts +5 -0
- package/src/providers/claude/storage/SkillStorage.ts +61 -0
- package/src/providers/claude/storage/SlashCommandStorage.ts +96 -0
- package/src/providers/claude/storage/StorageService.ts +185 -0
- package/src/providers/claude/stream/toolInputStreamState.ts +318 -0
- package/src/providers/claude/stream/transformClaudeMessage.ts +586 -0
- package/src/providers/claude/types/agent.ts +2 -0
- package/src/providers/claude/types/models.ts +168 -0
- package/src/providers/claude/types/plugins.ts +14 -0
- package/src/providers/claude/types/providerState.ts +16 -0
- package/src/providers/claude/types/settings.ts +98 -0
- package/src/providers/claude/ui/AgentSettings.ts +389 -0
- package/src/providers/claude/ui/ClaudeChatUIConfig.ts +113 -0
- package/src/providers/claude/ui/ClaudeSettingsTab.ts +407 -0
- package/src/providers/claude/ui/PluginSettingsManager.ts +149 -0
- package/src/providers/claude/ui/SlashCommandSettings.ts +527 -0
- package/src/providers/codex/CLAUDE.md +64 -0
- package/src/providers/codex/agents/CodexAgentMentionProvider.ts +33 -0
- package/src/providers/codex/app/CodexWorkspaceServices.ts +76 -0
- package/src/providers/codex/auxiliary/CodexInlineEditService.ts +9 -0
- package/src/providers/codex/auxiliary/CodexInstructionRefineService.ts +9 -0
- package/src/providers/codex/auxiliary/CodexTaskResultInterpreter.ts +29 -0
- package/src/providers/codex/auxiliary/CodexTitleGenerationService.ts +22 -0
- package/src/providers/codex/capabilities.ts +16 -0
- package/src/providers/codex/commands/CodexSkillCatalog.ts +180 -0
- package/src/providers/codex/env/CodexSettingsReconciler.ts +68 -0
- package/src/providers/codex/history/CodexConversationHistoryService.ts +212 -0
- package/src/providers/codex/history/CodexHistoryStore.ts +1672 -0
- package/src/providers/codex/modelOptions.ts +99 -0
- package/src/providers/codex/modelSelection.ts +17 -0
- package/src/providers/codex/normalization/codexSubagentNormalization.ts +227 -0
- package/src/providers/codex/normalization/codexToolNormalization.ts +390 -0
- package/src/providers/codex/prompt/encodeCodexTurn.ts +57 -0
- package/src/providers/codex/registration.ts +29 -0
- package/src/providers/codex/runtime/CodexAppServerProcess.ts +105 -0
- package/src/providers/codex/runtime/CodexAuxQueryRunner.ts +180 -0
- package/src/providers/codex/runtime/CodexBinaryLocator.ts +49 -0
- package/src/providers/codex/runtime/CodexChatRuntime.ts +1296 -0
- package/src/providers/codex/runtime/CodexCliResolver.ts +65 -0
- package/src/providers/codex/runtime/CodexExecutionTargetResolver.ts +104 -0
- package/src/providers/codex/runtime/CodexLaunchSpecBuilder.ts +85 -0
- package/src/providers/codex/runtime/CodexNotificationRouter.ts +1033 -0
- package/src/providers/codex/runtime/CodexPathMapper.ts +155 -0
- package/src/providers/codex/runtime/CodexRpcTransport.ts +171 -0
- package/src/providers/codex/runtime/CodexRuntimeContext.ts +109 -0
- package/src/providers/codex/runtime/CodexServerRequestRouter.ts +331 -0
- package/src/providers/codex/runtime/CodexSessionFileTail.ts +792 -0
- package/src/providers/codex/runtime/CodexSessionManager.ts +39 -0
- package/src/providers/codex/runtime/codexAppServerSupport.ts +58 -0
- package/src/providers/codex/runtime/codexAppServerTypes.ts +705 -0
- package/src/providers/codex/runtime/codexLaunchTypes.ts +30 -0
- package/src/providers/codex/settings.ts +236 -0
- package/src/providers/codex/skills/CodexSkillListingService.ts +173 -0
- package/src/providers/codex/storage/CodexSkillStorage.ts +250 -0
- package/src/providers/codex/storage/CodexSubagentStorage.ts +212 -0
- package/src/providers/codex/types/index.ts +16 -0
- package/src/providers/codex/types/models.ts +46 -0
- package/src/providers/codex/types/subagent.ts +23 -0
- package/src/providers/codex/ui/CodexChatUIConfig.ts +128 -0
- package/src/providers/codex/ui/CodexSettingsTab.ts +432 -0
- package/src/providers/codex/ui/CodexSkillSettings.ts +275 -0
- package/src/providers/codex/ui/CodexSubagentSettings.ts +400 -0
- package/src/providers/defaultProviderConfigs.ts +14 -0
- package/src/providers/index.ts +30 -0
- package/src/providers/opencode/agents/OpencodeAgentMentionProvider.ts +42 -0
- package/src/providers/opencode/app/OpencodeRuntimeCommandLoader.ts +67 -0
- package/src/providers/opencode/app/OpencodeWorkspaceServices.ts +55 -0
- package/src/providers/opencode/auxiliary/OpencodeInlineEditService.ts +13 -0
- package/src/providers/opencode/auxiliary/OpencodeInstructionRefineService.ts +12 -0
- package/src/providers/opencode/auxiliary/OpencodeTaskResultInterpreter.ts +29 -0
- package/src/providers/opencode/auxiliary/OpencodeTitleGenerationService.ts +27 -0
- package/src/providers/opencode/capabilities.ts +16 -0
- package/src/providers/opencode/commands/OpencodeCommandCatalog.ts +92 -0
- package/src/providers/opencode/discoveryState.ts +135 -0
- package/src/providers/opencode/env/OpencodeSettingsReconciler.ts +178 -0
- package/src/providers/opencode/history/OpencodeConversationHistoryService.ts +84 -0
- package/src/providers/opencode/history/OpencodeHistoryStore.ts +472 -0
- package/src/providers/opencode/history/OpencodeSqliteReader.ts +284 -0
- package/src/providers/opencode/internal/compareCollections.ts +72 -0
- package/src/providers/opencode/internal/providerProjection.ts +15 -0
- package/src/providers/opencode/models.ts +378 -0
- package/src/providers/opencode/modes.ts +150 -0
- package/src/providers/opencode/normalization/opencodeToolNormalization.ts +406 -0
- package/src/providers/opencode/registration.ts +27 -0
- package/src/providers/opencode/runtime/OpencodeAuxQueryRunner.ts +436 -0
- package/src/providers/opencode/runtime/OpencodeChatRuntime.ts +1603 -0
- package/src/providers/opencode/runtime/OpencodeCliResolver.ts +57 -0
- package/src/providers/opencode/runtime/OpencodeLaunchArtifacts.ts +231 -0
- package/src/providers/opencode/runtime/OpencodePaths.ts +113 -0
- package/src/providers/opencode/runtime/OpencodeRuntimeEnvironment.ts +18 -0
- package/src/providers/opencode/runtime/buildOpencodePrompt.ts +66 -0
- package/src/providers/opencode/settings.ts +427 -0
- package/src/providers/opencode/storage/OpencodeAgentStorage.ts +346 -0
- package/src/providers/opencode/types/agent.ts +37 -0
- package/src/providers/opencode/types/index.ts +9 -0
- package/src/providers/opencode/ui/OpencodeAgentSettings.ts +579 -0
- package/src/providers/opencode/ui/OpencodeChatUIConfig.ts +316 -0
- package/src/providers/opencode/ui/OpencodeSettingsTab.ts +674 -0
- package/src/providers/pi/app/PiRuntimeCommandLoader.ts +57 -0
- package/src/providers/pi/app/PiWorkspaceServices.ts +39 -0
- package/src/providers/pi/auxiliary/PiInlineEditService.ts +9 -0
- package/src/providers/pi/auxiliary/PiInstructionRefineService.ts +9 -0
- package/src/providers/pi/auxiliary/PiTaskResultInterpreter.ts +29 -0
- package/src/providers/pi/auxiliary/PiTitleGenerationService.ts +19 -0
- package/src/providers/pi/capabilities.ts +16 -0
- package/src/providers/pi/commands/PiCommandCatalog.ts +92 -0
- package/src/providers/pi/env/PiSettingsReconciler.ts +180 -0
- package/src/providers/pi/history/PiConversationHistoryService.ts +123 -0
- package/src/providers/pi/history/PiHistoryStore.ts +664 -0
- package/src/providers/pi/internal/compareCollections.ts +4 -0
- package/src/providers/pi/internal/providerProjection.ts +18 -0
- package/src/providers/pi/models.ts +302 -0
- package/src/providers/pi/normalizations/piEventNormalization.ts +211 -0
- package/src/providers/pi/normalizations/piToolNormalization.ts +97 -0
- package/src/providers/pi/registration.ts +30 -0
- package/src/providers/pi/runtime/PiAuxQueryRunner.ts +216 -0
- package/src/providers/pi/runtime/PiChatRuntime.ts +1064 -0
- package/src/providers/pi/runtime/PiCliResolver.ts +53 -0
- package/src/providers/pi/runtime/PiExtensionUiBridge.ts +161 -0
- package/src/providers/pi/runtime/PiJsonl.ts +71 -0
- package/src/providers/pi/runtime/PiLaunchSpec.ts +70 -0
- package/src/providers/pi/runtime/PiModelDiscoveryService.ts +92 -0
- package/src/providers/pi/runtime/PiRpcPayloads.ts +18 -0
- package/src/providers/pi/runtime/PiRpcTransport.ts +243 -0
- package/src/providers/pi/runtime/PiSubprocess.ts +159 -0
- package/src/providers/pi/runtime/buildPiPrompt.ts +62 -0
- package/src/providers/pi/runtime/buildPiUsageInfo.ts +69 -0
- package/src/providers/pi/settings.ts +468 -0
- package/src/providers/pi/types.ts +64 -0
- package/src/providers/pi/ui/ObsidianPiExtensionUiRenderer.ts +251 -0
- package/src/providers/pi/ui/PiChatUIConfig.ts +265 -0
- package/src/providers/pi/ui/PiExtensionUiRenderer.ts +12 -0
- package/src/providers/pi/ui/PiSettingsTab.ts +642 -0
- package/src/shared/components/ResumeSessionDropdown.ts +185 -0
- package/src/shared/components/SelectableDropdown.ts +140 -0
- package/src/shared/components/SelectionHighlight.ts +77 -0
- package/src/shared/components/SlashCommandDropdown.ts +421 -0
- package/src/shared/icons.ts +180 -0
- package/src/shared/mention/MentionDropdownController.ts +627 -0
- package/src/shared/mention/VaultMentionCache.ts +106 -0
- package/src/shared/mention/VaultMentionDataProvider.ts +51 -0
- package/src/shared/mention/types.ts +67 -0
- package/src/shared/modals/ConfirmModal.ts +60 -0
- package/src/shared/modals/ForkTargetModal.ts +47 -0
- package/src/shared/modals/InstructionConfirmModal.ts +281 -0
- package/src/style/CLAUDE.md +49 -0
- package/src/style/accessibility.css +40 -0
- package/src/style/base/animations.css +44 -0
- package/src/style/base/container.css +20 -0
- package/src/style/base/variables.css +46 -0
- package/src/style/base/visibility.css +15 -0
- package/src/style/components/code.css +97 -0
- package/src/style/components/context-footer.css +76 -0
- package/src/style/components/header.css +27 -0
- package/src/style/components/history.css +221 -0
- package/src/style/components/input.css +312 -0
- package/src/style/components/messages.css +262 -0
- package/src/style/components/nav-sidebar.css +58 -0
- package/src/style/components/status-panel.css +202 -0
- package/src/style/components/subagent.css +248 -0
- package/src/style/components/tabs.css +112 -0
- package/src/style/components/thinking.css +88 -0
- package/src/style/components/toolcalls.css +278 -0
- package/src/style/features/ask-user-question.css +315 -0
- package/src/style/features/diff.css +197 -0
- package/src/style/features/file-context.css +188 -0
- package/src/style/features/file-link.css +22 -0
- package/src/style/features/image-context.css +179 -0
- package/src/style/features/image-embed.css +40 -0
- package/src/style/features/image-modal.css +52 -0
- package/src/style/features/inline-edit.css +278 -0
- package/src/style/features/plan-mode.css +103 -0
- package/src/style/features/resume-session.css +119 -0
- package/src/style/features/slash-commands.css +91 -0
- package/src/style/index.css +63 -0
- package/src/style/modals/fork-target.css +21 -0
- package/src/style/modals/instruction.css +161 -0
- package/src/style/modals/mcp-modal.css +241 -0
- package/src/style/settings/agent-settings.css +2 -0
- package/src/style/settings/base.css +300 -0
- package/src/style/settings/env-snippets.css +366 -0
- package/src/style/settings/mcp-settings.css +211 -0
- package/src/style/settings/plugin-settings.css +164 -0
- package/src/style/settings/provider-model-picker.css +367 -0
- package/src/style/settings/slash-settings.css +16 -0
- package/src/style/toolbar/external-context.css +177 -0
- package/src/style/toolbar/mcp-selector.css +176 -0
- package/src/style/toolbar/mode-selector.css +19 -0
- package/src/style/toolbar/model-selector.css +99 -0
- package/src/style/toolbar/permission-toggle.css +56 -0
- package/src/style/toolbar/service-tier-toggle.css +39 -0
- package/src/style/toolbar/thinking-selector.css +83 -0
- package/src/types/smol-toml.d.ts +4 -0
- package/src/utils/agent.ts +50 -0
- package/src/utils/animationFrame.ts +46 -0
- package/src/utils/browser.ts +46 -0
- package/src/utils/canvas.ts +14 -0
- package/src/utils/cliBinaryLocator.ts +97 -0
- package/src/utils/context.ts +117 -0
- package/src/utils/contextMentionResolver.ts +154 -0
- package/src/utils/date.ts +31 -0
- package/src/utils/diff.ts +384 -0
- package/src/utils/editor.ts +104 -0
- package/src/utils/electronCompat.ts +53 -0
- package/src/utils/env.ts +465 -0
- package/src/utils/externalContext.ts +143 -0
- package/src/utils/externalContextScanner.ts +135 -0
- package/src/utils/fileLink.ts +263 -0
- package/src/utils/frontmatter.ts +194 -0
- package/src/utils/imageEmbed.ts +139 -0
- package/src/utils/inlineEdit.ts +22 -0
- package/src/utils/interrupt.ts +23 -0
- package/src/utils/markdown.ts +25 -0
- package/src/utils/markdownMath.ts +130 -0
- package/src/utils/mcp.ts +96 -0
- package/src/utils/obsidianCompat.ts +23 -0
- package/src/utils/path.ts +342 -0
- package/src/utils/session.ts +240 -0
- package/src/utils/slashCommand.ts +152 -0
- package/src/utils/subagentJsonl.ts +52 -0
- package/src/utils/windowsCmdShim.ts +98 -0
- package/tests/__mocks__/claude-agent-sdk.ts +317 -0
- package/tests/__mocks__/codex-sdk.ts +88 -0
- package/tests/__mocks__/obsidian.ts +434 -0
- package/tests/helpers/mockElement.ts +403 -0
- package/tests/helpers/sdkMessages.ts +291 -0
- package/tests/integration/core/agent/ClaudianService.test.ts +1845 -0
- package/tests/integration/core/mcp/mcp.test.ts +905 -0
- package/tests/integration/features/chat/imagePersistence.test.ts +38 -0
- package/tests/integration/main.test.ts +1701 -0
- package/tests/setupWindow.ts +26 -0
- package/tests/tsconfig.json +7 -0
- package/tests/unit/core/commands/builtInCommands.test.ts +239 -0
- package/tests/unit/core/mcp/McpServerManager.test.ts +405 -0
- package/tests/unit/core/mcp/McpTester.test.ts +282 -0
- package/tests/unit/core/mcp/createNodeFetch.test.ts +188 -0
- package/tests/unit/core/providers/ProviderRegistry.test.ts +275 -0
- package/tests/unit/core/providers/ProviderSettingsCoordinator.test.ts +490 -0
- package/tests/unit/core/providers/ProviderWorkspaceRegistry.test.ts +84 -0
- package/tests/unit/core/providers/modelRouting.test.ts +91 -0
- package/tests/unit/core/providers/modelSelection.test.ts +155 -0
- package/tests/unit/core/providers/providerEnvironment.test.ts +162 -0
- package/tests/unit/core/providers/tabLifecycle.test.ts +217 -0
- package/tests/unit/core/security/ApprovalManager.test.ts +152 -0
- package/tests/unit/core/storage/VaultFileAdapter.test.ts +535 -0
- package/tests/unit/core/tools/todo.test.ts +227 -0
- package/tests/unit/core/tools/toolIcons.test.ts +75 -0
- package/tests/unit/core/tools/toolInput.test.ts +350 -0
- package/tests/unit/core/tools/toolNames.test.ts +464 -0
- package/tests/unit/core/types/mcp.test.ts +115 -0
- package/tests/unit/features/chat/ClaudianView.test.ts +404 -0
- package/tests/unit/features/chat/controllers/BrowserSelectionController.test.ts +179 -0
- package/tests/unit/features/chat/controllers/CanvasSelectionController.test.ts +216 -0
- package/tests/unit/features/chat/controllers/ConversationController.test.ts +2764 -0
- package/tests/unit/features/chat/controllers/InputController.test.ts +3188 -0
- package/tests/unit/features/chat/controllers/NavigationController.test.ts +640 -0
- package/tests/unit/features/chat/controllers/SelectionController.test.ts +695 -0
- package/tests/unit/features/chat/controllers/StreamController.test.ts +2534 -0
- package/tests/unit/features/chat/controllers/contextRowVisibility.test.ts +46 -0
- package/tests/unit/features/chat/controllers/index.test.ts +16 -0
- package/tests/unit/features/chat/rendering/DiffRenderer.test.ts +355 -0
- package/tests/unit/features/chat/rendering/InlineAskUserQuestion.test.ts +1035 -0
- package/tests/unit/features/chat/rendering/InlineExitPlanMode.test.ts +191 -0
- package/tests/unit/features/chat/rendering/InlinePlanApproval.test.ts +126 -0
- package/tests/unit/features/chat/rendering/MessageRenderer.test.ts +2004 -0
- package/tests/unit/features/chat/rendering/SubagentRenderer.test.ts +917 -0
- package/tests/unit/features/chat/rendering/ThinkingBlockRenderer.test.ts +124 -0
- package/tests/unit/features/chat/rendering/TodoListRenderer.test.ts +173 -0
- package/tests/unit/features/chat/rendering/ToolCallRenderer.test.ts +909 -0
- package/tests/unit/features/chat/rendering/WriteEditRenderer.test.ts +474 -0
- package/tests/unit/features/chat/rendering/collapsible.test.ts +158 -0
- package/tests/unit/features/chat/rendering/todoUtils.test.ts +105 -0
- package/tests/unit/features/chat/rewind.test.ts +56 -0
- package/tests/unit/features/chat/services/BangBashService.test.ts +142 -0
- package/tests/unit/features/chat/services/InstructionRefineService.test.ts +371 -0
- package/tests/unit/features/chat/services/SubagentManager.test.ts +1759 -0
- package/tests/unit/features/chat/services/TitleGenerationService.test.ts +480 -0
- package/tests/unit/features/chat/state/ChatState.test.ts +581 -0
- package/tests/unit/features/chat/tabs/Tab.test.ts +4287 -0
- package/tests/unit/features/chat/tabs/TabBar.test.ts +357 -0
- package/tests/unit/features/chat/tabs/TabManager.test.ts +2962 -0
- package/tests/unit/features/chat/tabs/index.test.ts +11 -0
- package/tests/unit/features/chat/ui/BangBashModeManager.test.ts +321 -0
- package/tests/unit/features/chat/ui/ExternalContextSelector.test.ts +555 -0
- package/tests/unit/features/chat/ui/FileContextManager.test.ts +876 -0
- package/tests/unit/features/chat/ui/ImageContext.test.ts +777 -0
- package/tests/unit/features/chat/ui/InputToolbar.test.ts +1139 -0
- package/tests/unit/features/chat/ui/InstructionModeManager.test.ts +243 -0
- package/tests/unit/features/chat/ui/NavigationSidebar.test.ts +570 -0
- package/tests/unit/features/chat/ui/StatusPanel.test.ts +953 -0
- package/tests/unit/features/chat/ui/file-context/state/FileContextState.test.ts +155 -0
- package/tests/unit/features/chat/ui/textareaResize.test.ts +102 -0
- package/tests/unit/features/chat/utils/usageInfo.test.ts +56 -0
- package/tests/unit/features/inline-edit/InlineEditService.test.ts +1199 -0
- package/tests/unit/features/inline-edit/ui/InlineEditModal.openAndWait.test.ts +1482 -0
- package/tests/unit/features/inline-edit/ui/InlineEditModal.test.ts +495 -0
- package/tests/unit/features/inline-edit/ui/inlineEditMarkdownPreview.test.ts +92 -0
- package/tests/unit/features/settings/AgentSettings.test.ts +82 -0
- package/tests/unit/features/settings/keyboardNavigation.test.ts +73 -0
- package/tests/unit/features/settings/ui/CodexSkillSettings.test.ts +294 -0
- package/tests/unit/features/settings/ui/CodexSubagentSettings.test.ts +207 -0
- package/tests/unit/i18n/constants.test.ts +43 -0
- package/tests/unit/i18n/i18n.test.ts +244 -0
- package/tests/unit/i18n/locales.test.ts +134 -0
- package/tests/unit/providers/acp/AcpClientConnection.test.ts +248 -0
- package/tests/unit/providers/acp/AcpJsonRpcTransport.test.ts +186 -0
- package/tests/unit/providers/acp/AcpSessionConfig.test.ts +247 -0
- package/tests/unit/providers/acp/AcpSessionUpdateNormalizer.test.ts +145 -0
- package/tests/unit/providers/acp/AcpSubprocess.test.ts +105 -0
- package/tests/unit/providers/acp/buildAcpUsageInfo.test.ts +51 -0
- package/tests/unit/providers/claude/agents/AgentManager.test.ts +590 -0
- package/tests/unit/providers/claude/agents/AgentStorage.test.ts +434 -0
- package/tests/unit/providers/claude/agents/index.test.ts +10 -0
- package/tests/unit/providers/claude/commands/ClaudeCommandCatalog.test.ts +396 -0
- package/tests/unit/providers/claude/commands/probeRuntimeCommands.test.ts +92 -0
- package/tests/unit/providers/claude/env/ClaudeSettingsReconciler.test.ts +57 -0
- package/tests/unit/providers/claude/env/claudeModelEnv.test.ts +228 -0
- package/tests/unit/providers/claude/hooks/SubagentHooks.test.ts +83 -0
- package/tests/unit/providers/claude/plugins/PluginManager.test.ts +832 -0
- package/tests/unit/providers/claude/plugins/index.test.ts +7 -0
- package/tests/unit/providers/claude/prompt/ClaudeTurnEncoder.test.ts +145 -0
- package/tests/unit/providers/claude/prompt/instructionRefine.test.ts +185 -0
- package/tests/unit/providers/claude/prompt/systemPrompt.test.ts +163 -0
- package/tests/unit/providers/claude/prompt/titleGeneration.test.ts +20 -0
- package/tests/unit/providers/claude/runtime/ClaudeTaskResultInterpreter.test.ts +28 -0
- package/tests/unit/providers/claude/runtime/ClaudianService.test.ts +3796 -0
- package/tests/unit/providers/claude/runtime/MessageChannel.test.ts +421 -0
- package/tests/unit/providers/claude/runtime/QueryOptionsBuilder.test.ts +775 -0
- package/tests/unit/providers/claude/runtime/SessionManager.test.ts +182 -0
- package/tests/unit/providers/claude/runtime/claudeColdStartQuery.test.ts +331 -0
- package/tests/unit/providers/claude/runtime/customSpawn.test.ts +374 -0
- package/tests/unit/providers/claude/runtime/index.test.ts +13 -0
- package/tests/unit/providers/claude/runtime/types.test.ts +190 -0
- package/tests/unit/providers/claude/sdk/typeGuards.test.ts +50 -0
- package/tests/unit/providers/claude/security/ClaudePermissionUpdates.test.ts +198 -0
- package/tests/unit/providers/claude/storage/AgentVaultStorage.test.ts +413 -0
- package/tests/unit/providers/claude/storage/CCSettingsStorage.test.ts +408 -0
- package/tests/unit/providers/claude/storage/ClaudianSettingsStorage.test.ts +653 -0
- package/tests/unit/providers/claude/storage/McpStorage.test.ts +619 -0
- package/tests/unit/providers/claude/storage/SessionStorage.test.ts +680 -0
- package/tests/unit/providers/claude/storage/SkillStorage.test.ts +275 -0
- package/tests/unit/providers/claude/storage/SlashCommandStorage.test.ts +612 -0
- package/tests/unit/providers/claude/storage/storage.test.ts +360 -0
- package/tests/unit/providers/claude/storage/storageService.convenience.test.ts +447 -0
- package/tests/unit/providers/claude/stream/transformSDKMessage.test.ts +1729 -0
- package/tests/unit/providers/claude/types/types.test.ts +726 -0
- package/tests/unit/providers/claude/ui/ClaudeChatUIConfig.test.ts +173 -0
- package/tests/unit/providers/claude/ui/ClaudeSettingsTab.test.ts +466 -0
- package/tests/unit/providers/codex/agents/CodexAgentMentionProvider.test.ts +89 -0
- package/tests/unit/providers/codex/auxiliary/CodexInstructionRefineService.test.ts +81 -0
- package/tests/unit/providers/codex/capabilities.test.ts +39 -0
- package/tests/unit/providers/codex/commands/CodexSkillCatalog.test.ts +413 -0
- package/tests/unit/providers/codex/env/CodexSettingsReconciler.test.ts +106 -0
- package/tests/unit/providers/codex/fixtures/codex-session-abort.jsonl +9 -0
- package/tests/unit/providers/codex/fixtures/codex-session-agent-lifecycle.jsonl +12 -0
- package/tests/unit/providers/codex/fixtures/codex-session-persisted-tools.jsonl +15 -0
- package/tests/unit/providers/codex/fixtures/codex-session-simple.jsonl +10 -0
- package/tests/unit/providers/codex/fixtures/codex-session-tools.jsonl +12 -0
- package/tests/unit/providers/codex/fixtures/codex-session-websearch-persisted.jsonl +3 -0
- package/tests/unit/providers/codex/fixtures/codex-session-websearch.jsonl +7 -0
- package/tests/unit/providers/codex/history/CodexConversationHistoryService.test.ts +690 -0
- package/tests/unit/providers/codex/history/CodexHistoryStore.test.ts +2202 -0
- package/tests/unit/providers/codex/normalization/codexSubagentNormalization.test.ts +81 -0
- package/tests/unit/providers/codex/normalization/codexToolNormalization.test.ts +322 -0
- package/tests/unit/providers/codex/prompt/encodeCodexTurn.test.ts +168 -0
- package/tests/unit/providers/codex/runtime/CodexAppServerProcess.test.ts +255 -0
- package/tests/unit/providers/codex/runtime/CodexAuxQueryRunner.test.ts +130 -0
- package/tests/unit/providers/codex/runtime/CodexBinaryLocator.test.ts +90 -0
- package/tests/unit/providers/codex/runtime/CodexChatRuntime.test.ts +2445 -0
- package/tests/unit/providers/codex/runtime/CodexCliResolver.test.ts +103 -0
- package/tests/unit/providers/codex/runtime/CodexExecutionTargetResolver.test.ts +105 -0
- package/tests/unit/providers/codex/runtime/CodexLaunchSpecBuilder.test.ts +150 -0
- package/tests/unit/providers/codex/runtime/CodexNotificationRouter.test.ts +1248 -0
- package/tests/unit/providers/codex/runtime/CodexPathMapper.test.ts +51 -0
- package/tests/unit/providers/codex/runtime/CodexRpcTransport.test.ts +220 -0
- package/tests/unit/providers/codex/runtime/CodexRuntimeContext.test.ts +107 -0
- package/tests/unit/providers/codex/runtime/CodexServerRequestRouter.test.ts +537 -0
- package/tests/unit/providers/codex/runtime/CodexSessionFileTail.test.ts +1305 -0
- package/tests/unit/providers/codex/runtime/CodexSessionManager.test.ts +82 -0
- package/tests/unit/providers/codex/runtime/codexAppServerTypes.test.ts +336 -0
- package/tests/unit/providers/codex/settings.test.ts +189 -0
- package/tests/unit/providers/codex/skills/CodexSkillListingService.test.ts +178 -0
- package/tests/unit/providers/codex/storage/CodexSkillStorage.test.ts +342 -0
- package/tests/unit/providers/codex/storage/CodexSubagentStorage.test.ts +376 -0
- package/tests/unit/providers/codex/ui/CodexChatUIConfig.test.ts +211 -0
- package/tests/unit/providers/codex/ui/CodexSettingsTab.test.ts +578 -0
- package/tests/unit/providers/defaultProviderConfigs.test.ts +18 -0
- package/tests/unit/providers/opencode/OpencodeAuxQueryRunner.test.ts +355 -0
- package/tests/unit/providers/opencode/OpencodeChatRuntime.test.ts +808 -0
- package/tests/unit/providers/opencode/OpencodeCliResolver.test.ts +93 -0
- package/tests/unit/providers/opencode/OpencodeCommandCatalog.test.ts +75 -0
- package/tests/unit/providers/opencode/OpencodeConversationHistoryService.test.ts +103 -0
- package/tests/unit/providers/opencode/OpencodeHistoryStore.test.ts +418 -0
- package/tests/unit/providers/opencode/OpencodeLaunchArtifacts.test.ts +268 -0
- package/tests/unit/providers/opencode/OpencodePaths.test.ts +35 -0
- package/tests/unit/providers/opencode/OpencodeRuntimeCommandLoader.test.ts +129 -0
- package/tests/unit/providers/opencode/OpencodeSettingsReconciler.test.ts +96 -0
- package/tests/unit/providers/opencode/OpencodeSettingsTab.test.ts +649 -0
- package/tests/unit/providers/opencode/OpencodeSqliteReader.test.ts +185 -0
- package/tests/unit/providers/opencode/agents/OpencodeAgentMentionProvider.test.ts +56 -0
- package/tests/unit/providers/opencode/buildOpencodePrompt.test.ts +87 -0
- package/tests/unit/providers/opencode/capabilities.test.ts +39 -0
- package/tests/unit/providers/opencode/models.test.ts +273 -0
- package/tests/unit/providers/opencode/modes.test.ts +151 -0
- package/tests/unit/providers/opencode/opencodeToolNormalization.test.ts +197 -0
- package/tests/unit/providers/opencode/settings.test.ts +469 -0
- package/tests/unit/providers/opencode/storage/OpencodeAgentStorage.test.ts +377 -0
- package/tests/unit/providers/opencode/ui/OpencodeAgentSettings.test.ts +91 -0
- package/tests/unit/providers/pi/PiRuntimeCommandLoader.test.ts +149 -0
- package/tests/unit/providers/pi/capabilities.test.ts +20 -0
- package/tests/unit/providers/pi/commands/PiCommandCatalog.test.ts +69 -0
- package/tests/unit/providers/pi/env/PiSettingsReconciler.test.ts +61 -0
- package/tests/unit/providers/pi/history/PiConversationHistoryService.test.ts +147 -0
- package/tests/unit/providers/pi/history/PiHistoryStore.test.ts +523 -0
- package/tests/unit/providers/pi/models.test.ts +96 -0
- package/tests/unit/providers/pi/registration.test.ts +54 -0
- package/tests/unit/providers/pi/runtime/PiAuxQueryRunner.test.ts +172 -0
- package/tests/unit/providers/pi/runtime/PiChatRuntime.test.ts +830 -0
- package/tests/unit/providers/pi/runtime/PiCliResolver.test.ts +105 -0
- package/tests/unit/providers/pi/runtime/PiEventNormalization.test.ts +147 -0
- package/tests/unit/providers/pi/runtime/PiExtensionUiBridge.test.ts +98 -0
- package/tests/unit/providers/pi/runtime/PiJsonl.test.ts +42 -0
- package/tests/unit/providers/pi/runtime/PiLaunchSpec.test.ts +92 -0
- package/tests/unit/providers/pi/runtime/PiModelDiscoveryService.test.ts +135 -0
- package/tests/unit/providers/pi/runtime/PiRpcPayloads.test.ts +15 -0
- package/tests/unit/providers/pi/runtime/PiRpcTransport.test.ts +116 -0
- package/tests/unit/providers/pi/runtime/PiSubprocess.test.ts +151 -0
- package/tests/unit/providers/pi/runtime/buildPiPrompt.test.ts +84 -0
- package/tests/unit/providers/pi/runtime/buildPiUsageInfo.test.ts +69 -0
- package/tests/unit/providers/pi/settings.test.ts +253 -0
- package/tests/unit/providers/pi/ui/PiChatUIConfig.test.ts +161 -0
- package/tests/unit/providers/pi/ui/PiSettingsTab.test.ts +492 -0
- package/tests/unit/scripts/rendererSafeUnref.test.ts +101 -0
- package/tests/unit/shared/components/ResumeSessionDropdown.test.ts +356 -0
- package/tests/unit/shared/components/SelectableDropdown.test.ts +406 -0
- package/tests/unit/shared/components/SlashCommandDropdown.provider.test.ts +354 -0
- package/tests/unit/shared/components/SlashCommandDropdown.test.ts +508 -0
- package/tests/unit/shared/icons.test.ts +56 -0
- package/tests/unit/shared/index.test.ts +46 -0
- package/tests/unit/shared/mention/MentionDropdownController.test.ts +823 -0
- package/tests/unit/shared/mention/VaultFileCache.test.ts +195 -0
- package/tests/unit/shared/mention/VaultFolderCache.test.ts +143 -0
- package/tests/unit/shared/mention/VaultMentionDataProvider.test.ts +87 -0
- package/tests/unit/shared/modals/ConfirmModal.test.ts +111 -0
- package/tests/unit/shared/modals/ForkTargetModal.test.ts +101 -0
- package/tests/unit/shared/modals/InstructionConfirmModal.test.ts +305 -0
- package/tests/unit/utils/agent.test.ts +395 -0
- package/tests/unit/utils/animationFrame.test.ts +59 -0
- package/tests/unit/utils/browser.test.ts +73 -0
- package/tests/unit/utils/canvas.test.ts +54 -0
- package/tests/unit/utils/claudeCli.test.ts +294 -0
- package/tests/unit/utils/cliBinaryLocator.test.ts +33 -0
- package/tests/unit/utils/context.test.ts +288 -0
- package/tests/unit/utils/contextMentionResolver.test.ts +270 -0
- package/tests/unit/utils/date.test.ts +80 -0
- package/tests/unit/utils/diff.test.ts +291 -0
- package/tests/unit/utils/editor.test.ts +249 -0
- package/tests/unit/utils/electronCompat.test.ts +87 -0
- package/tests/unit/utils/env.test.ts +1240 -0
- package/tests/unit/utils/externalContext.test.ts +336 -0
- package/tests/unit/utils/externalContextScanner.test.ts +186 -0
- package/tests/unit/utils/fileLink.dom.test.ts +273 -0
- package/tests/unit/utils/fileLink.handler.test.ts +64 -0
- package/tests/unit/utils/fileLink.test.ts +233 -0
- package/tests/unit/utils/frontmatter.test.ts +434 -0
- package/tests/unit/utils/imageEmbed.test.ts +407 -0
- package/tests/unit/utils/inlineEdit.test.ts +63 -0
- package/tests/unit/utils/interrupt.test.ts +73 -0
- package/tests/unit/utils/markdown.test.ts +35 -0
- package/tests/unit/utils/markdownMath.test.ts +54 -0
- package/tests/unit/utils/mcp.test.ts +256 -0
- package/tests/unit/utils/obsidianCompat.test.ts +18 -0
- package/tests/unit/utils/path.test.ts +677 -0
- package/tests/unit/utils/sdkSession.test.ts +2359 -0
- package/tests/unit/utils/session.test.ts +971 -0
- package/tests/unit/utils/slashCommand.test.ts +778 -0
- package/tests/unit/utils/utils.test.ts +809 -0
- package/tsconfig.jest.json +8 -0
- package/tsconfig.json +26 -0
- package/versions.json +4 -0
|
@@ -0,0 +1,917 @@
|
|
|
1
|
+
import { createMockEl, type MockElement } from '@test/helpers/mockElement';
|
|
2
|
+
import { setIcon } from 'obsidian';
|
|
3
|
+
|
|
4
|
+
import type { SubagentInfo, ToolCallInfo } from '@/core/types';
|
|
5
|
+
import {
|
|
6
|
+
addSubagentToolCall,
|
|
7
|
+
createAsyncSubagentBlock,
|
|
8
|
+
createSubagentBlock,
|
|
9
|
+
finalizeAsyncSubagent,
|
|
10
|
+
finalizeSubagentBlock,
|
|
11
|
+
markAsyncSubagentOrphaned,
|
|
12
|
+
renderStoredAsyncSubagent,
|
|
13
|
+
renderStoredSubagent,
|
|
14
|
+
updateAsyncSubagentRunning,
|
|
15
|
+
updateSubagentToolResult,
|
|
16
|
+
} from '@/features/chat/rendering/SubagentRenderer';
|
|
17
|
+
|
|
18
|
+
const getTextByClass = (el: MockElement, cls: string): string[] => {
|
|
19
|
+
const results: string[] = [];
|
|
20
|
+
const visit = (node: MockElement) => {
|
|
21
|
+
if (node.hasClass(cls)) {
|
|
22
|
+
results.push(node.textContent);
|
|
23
|
+
}
|
|
24
|
+
node.children.forEach(visit);
|
|
25
|
+
};
|
|
26
|
+
visit(el);
|
|
27
|
+
return results;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
describe('Sync Subagent Renderer', () => {
|
|
31
|
+
let parentEl: MockElement;
|
|
32
|
+
|
|
33
|
+
beforeEach(() => {
|
|
34
|
+
jest.clearAllMocks();
|
|
35
|
+
parentEl = createMockEl('div');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe('createSubagentBlock', () => {
|
|
39
|
+
it('should start collapsed by default', () => {
|
|
40
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
41
|
+
|
|
42
|
+
expect(state.info.isExpanded).toBe(false);
|
|
43
|
+
expect((state.wrapperEl as any).hasClass('expanded')).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should set aria-expanded to false by default', () => {
|
|
47
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
48
|
+
|
|
49
|
+
expect(state.headerEl.getAttribute('aria-expanded')).toBe('false');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should hide content by default', () => {
|
|
53
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
54
|
+
|
|
55
|
+
expect((state.contentEl as any).style.display).toBe('none');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should set correct ARIA attributes for accessibility', () => {
|
|
59
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
60
|
+
|
|
61
|
+
expect(state.headerEl.getAttribute('role')).toBe('button');
|
|
62
|
+
expect(state.headerEl.getAttribute('tabindex')).toBe('0');
|
|
63
|
+
expect(state.headerEl.getAttribute('aria-expanded')).toBe('false');
|
|
64
|
+
expect(state.headerEl.getAttribute('aria-label')).toContain('click to expand');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should toggle expand/collapse on header click', () => {
|
|
68
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
69
|
+
|
|
70
|
+
// Initially collapsed
|
|
71
|
+
expect(state.info.isExpanded).toBe(false);
|
|
72
|
+
expect((state.wrapperEl as any).hasClass('expanded')).toBe(false);
|
|
73
|
+
expect((state.contentEl as any).style.display).toBe('none');
|
|
74
|
+
|
|
75
|
+
// Trigger click
|
|
76
|
+
(state.headerEl as any).click();
|
|
77
|
+
|
|
78
|
+
// Should be expanded
|
|
79
|
+
expect(state.info.isExpanded).toBe(true);
|
|
80
|
+
expect((state.wrapperEl as any).hasClass('expanded')).toBe(true);
|
|
81
|
+
expect((state.contentEl as any).hasClass('claudian-hidden')).toBe(false);
|
|
82
|
+
|
|
83
|
+
// Click again to collapse
|
|
84
|
+
(state.headerEl as any).click();
|
|
85
|
+
expect(state.info.isExpanded).toBe(false);
|
|
86
|
+
expect((state.wrapperEl as any).hasClass('expanded')).toBe(false);
|
|
87
|
+
expect((state.contentEl as any).style.display).toBe('none');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should update aria-expanded on toggle', () => {
|
|
91
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
92
|
+
|
|
93
|
+
// Initially collapsed
|
|
94
|
+
expect(state.headerEl.getAttribute('aria-expanded')).toBe('false');
|
|
95
|
+
|
|
96
|
+
// Expand
|
|
97
|
+
(state.headerEl as any).click();
|
|
98
|
+
expect(state.headerEl.getAttribute('aria-expanded')).toBe('true');
|
|
99
|
+
|
|
100
|
+
// Collapse
|
|
101
|
+
(state.headerEl as any).click();
|
|
102
|
+
expect(state.headerEl.getAttribute('aria-expanded')).toBe('false');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should show description in label', () => {
|
|
106
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'My task description' });
|
|
107
|
+
|
|
108
|
+
expect(state.labelEl.textContent).toBe('My task description');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should not show a tool count badge in the header', () => {
|
|
112
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
113
|
+
|
|
114
|
+
expect(getTextByClass(state.wrapperEl as any, 'claudian-subagent-count')).toEqual([]);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe('renderStoredSubagent', () => {
|
|
119
|
+
it('should start collapsed by default', () => {
|
|
120
|
+
const subagent: SubagentInfo = {
|
|
121
|
+
id: 'task-1',
|
|
122
|
+
description: 'Test task',
|
|
123
|
+
status: 'completed',
|
|
124
|
+
toolCalls: [],
|
|
125
|
+
isExpanded: false,
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const wrapperEl = renderStoredSubagent(parentEl as any, subagent);
|
|
129
|
+
|
|
130
|
+
expect((wrapperEl as any).hasClass('expanded')).toBe(false);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should set aria-expanded to false by default', () => {
|
|
134
|
+
const subagent: SubagentInfo = {
|
|
135
|
+
id: 'task-1',
|
|
136
|
+
description: 'Test task',
|
|
137
|
+
status: 'completed',
|
|
138
|
+
toolCalls: [],
|
|
139
|
+
isExpanded: false,
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const wrapperEl = renderStoredSubagent(parentEl as any, subagent);
|
|
143
|
+
|
|
144
|
+
const headerEl = (wrapperEl as any).children[0];
|
|
145
|
+
expect(headerEl.getAttribute('aria-expanded')).toBe('false');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should hide content by default', () => {
|
|
149
|
+
const subagent: SubagentInfo = {
|
|
150
|
+
id: 'task-1',
|
|
151
|
+
description: 'Test task',
|
|
152
|
+
status: 'completed',
|
|
153
|
+
toolCalls: [],
|
|
154
|
+
isExpanded: false,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const wrapperEl = renderStoredSubagent(parentEl as any, subagent);
|
|
158
|
+
|
|
159
|
+
const contentEl = (wrapperEl as any).children[1];
|
|
160
|
+
expect(contentEl.style.display).toBe('none');
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should toggle expand/collapse on click', () => {
|
|
164
|
+
const subagent: SubagentInfo = {
|
|
165
|
+
id: 'task-1',
|
|
166
|
+
description: 'Test task',
|
|
167
|
+
status: 'completed',
|
|
168
|
+
toolCalls: [],
|
|
169
|
+
isExpanded: false,
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const wrapperEl = renderStoredSubagent(parentEl as any, subagent);
|
|
173
|
+
const headerEl = (wrapperEl as any).children[0];
|
|
174
|
+
const contentEl = (wrapperEl as any).children[1];
|
|
175
|
+
|
|
176
|
+
// Initially collapsed
|
|
177
|
+
expect((wrapperEl as any).hasClass('expanded')).toBe(false);
|
|
178
|
+
expect(contentEl.style.display).toBe('none');
|
|
179
|
+
|
|
180
|
+
// Click to expand
|
|
181
|
+
headerEl.click();
|
|
182
|
+
expect((wrapperEl as any).hasClass('expanded')).toBe(true);
|
|
183
|
+
expect(contentEl.hasClass('claudian-hidden')).toBe(false);
|
|
184
|
+
expect(headerEl.getAttribute('aria-expanded')).toBe('true');
|
|
185
|
+
|
|
186
|
+
// Click to collapse
|
|
187
|
+
headerEl.click();
|
|
188
|
+
expect((wrapperEl as any).hasClass('expanded')).toBe(false);
|
|
189
|
+
expect(contentEl.style.display).toBe('none');
|
|
190
|
+
expect(headerEl.getAttribute('aria-expanded')).toBe('false');
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
describe('keyboard navigation', () => {
|
|
196
|
+
let parentEl: MockElement;
|
|
197
|
+
|
|
198
|
+
beforeEach(() => {
|
|
199
|
+
jest.clearAllMocks();
|
|
200
|
+
parentEl = createMockEl('div');
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('should support keyboard navigation (Enter/Space) on createSubagentBlock', () => {
|
|
204
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
205
|
+
|
|
206
|
+
// Simulate keydown event
|
|
207
|
+
const keydownHandlers: Array<(e: any) => void> = [];
|
|
208
|
+
const originalAddEventListener = state.headerEl.addEventListener;
|
|
209
|
+
state.headerEl.addEventListener = (event: string, handler: (e: any) => void) => {
|
|
210
|
+
if (event === 'keydown') {
|
|
211
|
+
keydownHandlers.push(handler);
|
|
212
|
+
}
|
|
213
|
+
originalAddEventListener.call(state.headerEl, event, handler);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// Re-check - the handler should already be registered
|
|
217
|
+
// We need to dispatch a keydown event
|
|
218
|
+
const enterEvent = { key: 'Enter', preventDefault: jest.fn() };
|
|
219
|
+
(state.headerEl as any).dispatchEvent({ type: 'keydown', ...enterEvent });
|
|
220
|
+
|
|
221
|
+
// The handler should have been called and expanded
|
|
222
|
+
expect(state.info.isExpanded).toBe(true);
|
|
223
|
+
expect((state.wrapperEl as any).hasClass('expanded')).toBe(true);
|
|
224
|
+
|
|
225
|
+
// Space to collapse
|
|
226
|
+
const spaceEvent = { key: ' ', preventDefault: jest.fn() };
|
|
227
|
+
(state.headerEl as any).dispatchEvent({ type: 'keydown', ...spaceEvent });
|
|
228
|
+
|
|
229
|
+
expect(state.info.isExpanded).toBe(false);
|
|
230
|
+
expect((state.wrapperEl as any).hasClass('expanded')).toBe(false);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should support keyboard navigation (Enter/Space) on renderStoredSubagent', () => {
|
|
234
|
+
const subagent: SubagentInfo = {
|
|
235
|
+
id: 'task-1',
|
|
236
|
+
description: 'Test task',
|
|
237
|
+
status: 'completed',
|
|
238
|
+
toolCalls: [],
|
|
239
|
+
isExpanded: false,
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const wrapperEl = renderStoredSubagent(parentEl as any, subagent);
|
|
243
|
+
const headerEl = (wrapperEl as any).children[0];
|
|
244
|
+
|
|
245
|
+
// Simulate Enter key
|
|
246
|
+
const enterEvent = { key: 'Enter', preventDefault: jest.fn() };
|
|
247
|
+
headerEl.dispatchEvent({ type: 'keydown', ...enterEvent });
|
|
248
|
+
|
|
249
|
+
expect((wrapperEl as any).hasClass('expanded')).toBe(true);
|
|
250
|
+
|
|
251
|
+
// Simulate Space key to collapse
|
|
252
|
+
const spaceEvent = { key: ' ', preventDefault: jest.fn() };
|
|
253
|
+
headerEl.dispatchEvent({ type: 'keydown', ...spaceEvent });
|
|
254
|
+
|
|
255
|
+
expect((wrapperEl as any).hasClass('expanded')).toBe(false);
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
describe('Async Subagent Renderer', () => {
|
|
260
|
+
let parentEl: MockElement;
|
|
261
|
+
|
|
262
|
+
beforeEach(() => {
|
|
263
|
+
jest.clearAllMocks();
|
|
264
|
+
parentEl = createMockEl('div');
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
describe('inline display behavior', () => {
|
|
268
|
+
it('should start collapsed', () => {
|
|
269
|
+
const state = createAsyncSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
270
|
+
|
|
271
|
+
expect(state.info.isExpanded).toBe(false);
|
|
272
|
+
expect((state.wrapperEl as any).hasClass('expanded')).toBe(false);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('should have aria-label indicating expand action', () => {
|
|
276
|
+
const state = createAsyncSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
277
|
+
|
|
278
|
+
expect(state.headerEl.getAttribute('aria-label')).toContain('click to expand');
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('should expand content when header is clicked', () => {
|
|
282
|
+
const state = createAsyncSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
283
|
+
|
|
284
|
+
// Initially collapsed
|
|
285
|
+
expect(state.info.isExpanded).toBe(false);
|
|
286
|
+
|
|
287
|
+
// Trigger click to expand
|
|
288
|
+
(state.headerEl as any).click();
|
|
289
|
+
|
|
290
|
+
expect(state.info.isExpanded).toBe(true);
|
|
291
|
+
expect((state.wrapperEl as any).hasClass('expanded')).toBe(true);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it('should toggle expansion on repeated clicks', () => {
|
|
295
|
+
const state = createAsyncSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
296
|
+
|
|
297
|
+
// Click to expand
|
|
298
|
+
(state.headerEl as any).click();
|
|
299
|
+
expect(state.info.isExpanded).toBe(true);
|
|
300
|
+
|
|
301
|
+
// Click to collapse
|
|
302
|
+
(state.headerEl as any).click();
|
|
303
|
+
expect(state.info.isExpanded).toBe(false);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
it('should expand when Enter key is pressed', () => {
|
|
307
|
+
const state = createAsyncSubagentBlock(parentEl as any, 'task-1', { description: 'Test' });
|
|
308
|
+
|
|
309
|
+
const enterEvent = { key: 'Enter', preventDefault: jest.fn() };
|
|
310
|
+
(state.headerEl as any).dispatchEvent({ type: 'keydown', ...enterEvent });
|
|
311
|
+
|
|
312
|
+
expect(state.info.isExpanded).toBe(true);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('should expand when Space key is pressed', () => {
|
|
316
|
+
const state = createAsyncSubagentBlock(parentEl as any, 'task-1', { description: 'Test' });
|
|
317
|
+
|
|
318
|
+
const spaceEvent = { key: ' ', preventDefault: jest.fn() };
|
|
319
|
+
(state.headerEl as any).dispatchEvent({ type: 'keydown', ...spaceEvent });
|
|
320
|
+
|
|
321
|
+
expect(state.info.isExpanded).toBe(true);
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it('shows label immediately and initializing status text', () => {
|
|
326
|
+
const state = createAsyncSubagentBlock(parentEl as any, 'task-1', { description: 'Background job' });
|
|
327
|
+
|
|
328
|
+
expect(state.labelEl.textContent).toBe('Background job');
|
|
329
|
+
expect(state.statusTextEl.textContent).toBe('Initializing');
|
|
330
|
+
expect((state.wrapperEl as any).getClasses()).toEqual(expect.arrayContaining(['async', 'pending']));
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('shows prompt in content and keeps label visible while running', () => {
|
|
334
|
+
const state = createAsyncSubagentBlock(parentEl as any, 'task-2', { description: 'Background job', prompt: 'Do the work' });
|
|
335
|
+
|
|
336
|
+
updateAsyncSubagentRunning(state, 'agent-xyz');
|
|
337
|
+
|
|
338
|
+
expect(state.labelEl.textContent).toBe('Background job');
|
|
339
|
+
expect(state.statusTextEl.textContent).toBe('Running in background');
|
|
340
|
+
const contentText = getTextByClass(state.contentEl as any, 'claudian-subagent-prompt-text')[0];
|
|
341
|
+
expect(contentText).toContain('Do the work');
|
|
342
|
+
expect((state.wrapperEl as any).getClasses()).toEqual(expect.arrayContaining(['running', 'async']));
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('finalizes to completed and reveals description', () => {
|
|
346
|
+
const state = createAsyncSubagentBlock(parentEl as any, 'task-3', { description: 'Background job' });
|
|
347
|
+
state.info.toolCalls.push(
|
|
348
|
+
{
|
|
349
|
+
id: 'tool-1',
|
|
350
|
+
name: 'Read',
|
|
351
|
+
input: { file_path: 'a.md' },
|
|
352
|
+
status: 'completed',
|
|
353
|
+
result: 'A',
|
|
354
|
+
isExpanded: false,
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
id: 'tool-2',
|
|
358
|
+
name: 'Grep',
|
|
359
|
+
input: { pattern: 'x' },
|
|
360
|
+
status: 'completed',
|
|
361
|
+
result: 'B',
|
|
362
|
+
isExpanded: false,
|
|
363
|
+
}
|
|
364
|
+
);
|
|
365
|
+
updateAsyncSubagentRunning(state, 'agent-complete');
|
|
366
|
+
|
|
367
|
+
(setIcon as jest.Mock).mockClear();
|
|
368
|
+
finalizeAsyncSubagent(state, 'all done', false);
|
|
369
|
+
|
|
370
|
+
expect(state.labelEl.textContent).toBe('Background job');
|
|
371
|
+
expect(state.statusTextEl.textContent).toBe('');
|
|
372
|
+
expect((state.wrapperEl as any).hasClass('done')).toBe(true);
|
|
373
|
+
const contentText = getTextByClass(state.contentEl as any, 'claudian-subagent-result-output')[0];
|
|
374
|
+
expect(contentText).toBe('all done');
|
|
375
|
+
const lastIcon = (setIcon as jest.Mock).mock.calls.pop();
|
|
376
|
+
expect(lastIcon?.[1]).toBe('check');
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it('finalizes to error and truncates error message', () => {
|
|
380
|
+
const state = createAsyncSubagentBlock(parentEl as any, 'task-4', { description: 'Background job' });
|
|
381
|
+
updateAsyncSubagentRunning(state, 'agent-error');
|
|
382
|
+
|
|
383
|
+
(setIcon as jest.Mock).mockClear();
|
|
384
|
+
finalizeAsyncSubagent(state, 'failure happened', true);
|
|
385
|
+
|
|
386
|
+
expect(state.statusTextEl.textContent).toBe('Error');
|
|
387
|
+
expect((state.wrapperEl as any).hasClass('error')).toBe(true);
|
|
388
|
+
const contentText = getTextByClass(state.contentEl as any, 'claudian-subagent-result-output')[0];
|
|
389
|
+
expect(contentText).toBe('failure happened');
|
|
390
|
+
const lastIcon = (setIcon as jest.Mock).mock.calls.pop();
|
|
391
|
+
expect(lastIcon?.[1]).toBe('x');
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
it('marks async subagent as orphaned', () => {
|
|
395
|
+
const state = createAsyncSubagentBlock(parentEl as any, 'task-5', { description: 'Background job' });
|
|
396
|
+
|
|
397
|
+
markAsyncSubagentOrphaned(state);
|
|
398
|
+
|
|
399
|
+
expect(state.statusTextEl.textContent).toBe('Orphaned');
|
|
400
|
+
expect((state.wrapperEl as any).hasClass('orphaned')).toBe(true);
|
|
401
|
+
const contentText = getTextByClass(state.contentEl as any, 'claudian-subagent-result-output')[0];
|
|
402
|
+
expect(contentText).toContain('Conversation ended before task completed');
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
describe('renderStoredAsyncSubagent', () => {
|
|
406
|
+
it('should return wrapper element', () => {
|
|
407
|
+
const subagent: SubagentInfo = {
|
|
408
|
+
id: 'task-1',
|
|
409
|
+
description: 'Test task',
|
|
410
|
+
status: 'completed',
|
|
411
|
+
toolCalls: [],
|
|
412
|
+
isExpanded: false,
|
|
413
|
+
mode: 'async',
|
|
414
|
+
asyncStatus: 'completed',
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
const wrapperEl = renderStoredAsyncSubagent(parentEl as any, subagent);
|
|
418
|
+
|
|
419
|
+
expect(wrapperEl).toBeDefined();
|
|
420
|
+
expect((wrapperEl as any).hasClass('claudian-subagent-list')).toBe(true);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
it('should expand content when header is clicked', () => {
|
|
424
|
+
const subagent: SubagentInfo = {
|
|
425
|
+
id: 'task-1',
|
|
426
|
+
description: 'Test task',
|
|
427
|
+
status: 'completed',
|
|
428
|
+
toolCalls: [],
|
|
429
|
+
isExpanded: false,
|
|
430
|
+
mode: 'async',
|
|
431
|
+
asyncStatus: 'completed',
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
const wrapperEl = renderStoredAsyncSubagent(parentEl as any, subagent);
|
|
435
|
+
const headerEl = (wrapperEl as any).children[0];
|
|
436
|
+
|
|
437
|
+
// Click to expand
|
|
438
|
+
headerEl.click();
|
|
439
|
+
|
|
440
|
+
expect((wrapperEl as any).hasClass('expanded')).toBe(true);
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
it('should expand on Enter key', () => {
|
|
444
|
+
const subagent: SubagentInfo = {
|
|
445
|
+
id: 'task-1',
|
|
446
|
+
description: 'Test task',
|
|
447
|
+
status: 'completed',
|
|
448
|
+
toolCalls: [],
|
|
449
|
+
isExpanded: false,
|
|
450
|
+
mode: 'async',
|
|
451
|
+
asyncStatus: 'completed',
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
const wrapperEl = renderStoredAsyncSubagent(parentEl as any, subagent);
|
|
455
|
+
const headerEl = (wrapperEl as any).children[0];
|
|
456
|
+
|
|
457
|
+
const enterEvent = { key: 'Enter', preventDefault: jest.fn() };
|
|
458
|
+
headerEl.dispatchEvent({ type: 'keydown', ...enterEvent });
|
|
459
|
+
|
|
460
|
+
expect((wrapperEl as any).hasClass('expanded')).toBe(true);
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
it('should have aria-label indicating expand action', () => {
|
|
464
|
+
const subagent: SubagentInfo = {
|
|
465
|
+
id: 'task-1',
|
|
466
|
+
description: 'Test task',
|
|
467
|
+
status: 'completed',
|
|
468
|
+
toolCalls: [],
|
|
469
|
+
isExpanded: false,
|
|
470
|
+
mode: 'async',
|
|
471
|
+
asyncStatus: 'completed',
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
const wrapperEl = renderStoredAsyncSubagent(parentEl as any, subagent);
|
|
475
|
+
const headerEl = (wrapperEl as any).children[0];
|
|
476
|
+
|
|
477
|
+
expect(headerEl.getAttribute('aria-label')).toContain('click to expand');
|
|
478
|
+
});
|
|
479
|
+
|
|
480
|
+
it('should toggle expansion on repeated clicks', () => {
|
|
481
|
+
const subagent: SubagentInfo = {
|
|
482
|
+
id: 'task-1',
|
|
483
|
+
description: 'Test task',
|
|
484
|
+
status: 'completed',
|
|
485
|
+
toolCalls: [],
|
|
486
|
+
isExpanded: false,
|
|
487
|
+
mode: 'async',
|
|
488
|
+
asyncStatus: 'completed',
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
const wrapperEl = renderStoredAsyncSubagent(parentEl as any, subagent);
|
|
492
|
+
const headerEl = (wrapperEl as any).children[0];
|
|
493
|
+
|
|
494
|
+
// Click to expand
|
|
495
|
+
headerEl.click();
|
|
496
|
+
expect((wrapperEl as any).hasClass('expanded')).toBe(true);
|
|
497
|
+
|
|
498
|
+
// Click to collapse
|
|
499
|
+
headerEl.click();
|
|
500
|
+
expect((wrapperEl as any).hasClass('expanded')).toBe(false);
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
it('renders error status correctly', () => {
|
|
504
|
+
const subagent: SubagentInfo = {
|
|
505
|
+
id: 'task-1',
|
|
506
|
+
description: 'Failed task',
|
|
507
|
+
status: 'error',
|
|
508
|
+
toolCalls: [],
|
|
509
|
+
isExpanded: false,
|
|
510
|
+
mode: 'async',
|
|
511
|
+
asyncStatus: 'error',
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
const wrapperEl = renderStoredAsyncSubagent(parentEl as any, subagent);
|
|
515
|
+
|
|
516
|
+
expect((wrapperEl as any).hasClass('error')).toBe(true);
|
|
517
|
+
const contentText = getTextByClass(wrapperEl as any, 'claudian-subagent-result-output')[0];
|
|
518
|
+
expect(contentText).toBe('ERROR');
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
it('renders orphaned status correctly', () => {
|
|
522
|
+
const subagent: SubagentInfo = {
|
|
523
|
+
id: 'task-1',
|
|
524
|
+
description: 'Lost task',
|
|
525
|
+
status: 'error',
|
|
526
|
+
toolCalls: [],
|
|
527
|
+
isExpanded: false,
|
|
528
|
+
mode: 'async',
|
|
529
|
+
asyncStatus: 'orphaned',
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
(setIcon as jest.Mock).mockClear();
|
|
533
|
+
const wrapperEl = renderStoredAsyncSubagent(parentEl as any, subagent);
|
|
534
|
+
|
|
535
|
+
expect((wrapperEl as any).hasClass('error')).toBe(true);
|
|
536
|
+
expect((wrapperEl as any).hasClass('orphaned')).toBe(true);
|
|
537
|
+
const contentText = getTextByClass(wrapperEl as any, 'claudian-subagent-result-output')[0];
|
|
538
|
+
expect(contentText).toContain('Conversation ended before task completed');
|
|
539
|
+
// Should use alert-circle icon
|
|
540
|
+
expect(setIcon).toHaveBeenCalledWith(expect.anything(), 'alert-circle');
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
it('renders running status with prompt', () => {
|
|
544
|
+
const subagent: SubagentInfo = {
|
|
545
|
+
id: 'task-1',
|
|
546
|
+
description: 'Running task',
|
|
547
|
+
status: 'running',
|
|
548
|
+
toolCalls: [],
|
|
549
|
+
isExpanded: false,
|
|
550
|
+
mode: 'async',
|
|
551
|
+
asyncStatus: 'running',
|
|
552
|
+
prompt: 'Do some work',
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
const wrapperEl = renderStoredAsyncSubagent(parentEl as any, subagent);
|
|
556
|
+
|
|
557
|
+
expect((wrapperEl as any).hasClass('running')).toBe(true);
|
|
558
|
+
const contentText = getTextByClass(wrapperEl as any, 'claudian-subagent-prompt-text')[0];
|
|
559
|
+
expect(contentText).toContain('Do some work');
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
it('renders pending status as running', () => {
|
|
563
|
+
const subagent: SubagentInfo = {
|
|
564
|
+
id: 'task-1',
|
|
565
|
+
description: 'Pending task',
|
|
566
|
+
status: 'running',
|
|
567
|
+
toolCalls: [],
|
|
568
|
+
isExpanded: false,
|
|
569
|
+
mode: 'async',
|
|
570
|
+
asyncStatus: 'pending',
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
const wrapperEl = renderStoredAsyncSubagent(parentEl as any, subagent);
|
|
574
|
+
|
|
575
|
+
// pending maps to running display status
|
|
576
|
+
expect((wrapperEl as any).hasClass('running')).toBe(true);
|
|
577
|
+
});
|
|
578
|
+
});
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
describe('addSubagentToolCall', () => {
|
|
582
|
+
let parentEl: MockElement;
|
|
583
|
+
|
|
584
|
+
beforeEach(() => {
|
|
585
|
+
jest.clearAllMocks();
|
|
586
|
+
parentEl = createMockEl('div');
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
it('adds tool call to state without rendering a header count', () => {
|
|
590
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
591
|
+
|
|
592
|
+
const toolCall: ToolCallInfo = {
|
|
593
|
+
id: 'tool-1',
|
|
594
|
+
name: 'Read',
|
|
595
|
+
input: { file_path: 'test.md' },
|
|
596
|
+
status: 'running',
|
|
597
|
+
isExpanded: false,
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
addSubagentToolCall(state, toolCall);
|
|
601
|
+
|
|
602
|
+
expect(state.info.toolCalls).toHaveLength(1);
|
|
603
|
+
expect(getTextByClass(state.wrapperEl as any, 'claudian-subagent-count')).toEqual([]);
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
it('clears previous content and renders new tool item', () => {
|
|
607
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
608
|
+
|
|
609
|
+
const toolCall1: ToolCallInfo = {
|
|
610
|
+
id: 'tool-1',
|
|
611
|
+
name: 'Read',
|
|
612
|
+
input: { file_path: 'test.md' },
|
|
613
|
+
status: 'running',
|
|
614
|
+
isExpanded: false,
|
|
615
|
+
};
|
|
616
|
+
addSubagentToolCall(state, toolCall1);
|
|
617
|
+
|
|
618
|
+
const toolCall2: ToolCallInfo = {
|
|
619
|
+
id: 'tool-2',
|
|
620
|
+
name: 'Grep',
|
|
621
|
+
input: { pattern: 'test' },
|
|
622
|
+
status: 'running',
|
|
623
|
+
isExpanded: false,
|
|
624
|
+
};
|
|
625
|
+
addSubagentToolCall(state, toolCall2);
|
|
626
|
+
|
|
627
|
+
expect(state.info.toolCalls).toHaveLength(2);
|
|
628
|
+
expect(getTextByClass(state.wrapperEl as any, 'claudian-subagent-count')).toEqual([]);
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
it('merges repeated tool IDs instead of duplicating tool rows', () => {
|
|
632
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
633
|
+
|
|
634
|
+
addSubagentToolCall(state, {
|
|
635
|
+
id: 'tool-1',
|
|
636
|
+
name: 'Write',
|
|
637
|
+
input: {},
|
|
638
|
+
status: 'running',
|
|
639
|
+
isExpanded: false,
|
|
640
|
+
});
|
|
641
|
+
|
|
642
|
+
addSubagentToolCall(state, {
|
|
643
|
+
id: 'tool-1',
|
|
644
|
+
name: 'Write',
|
|
645
|
+
input: { file_path: 'notes.md' },
|
|
646
|
+
status: 'running',
|
|
647
|
+
isExpanded: false,
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
expect(state.info.toolCalls).toHaveLength(1);
|
|
651
|
+
expect(state.info.toolCalls[0]).toEqual(
|
|
652
|
+
expect.objectContaining({
|
|
653
|
+
id: 'tool-1',
|
|
654
|
+
input: { file_path: 'notes.md' },
|
|
655
|
+
})
|
|
656
|
+
);
|
|
657
|
+
expect(getTextByClass(state.wrapperEl as any, 'claudian-subagent-count')).toEqual([]);
|
|
658
|
+
expect(getTextByClass(state.toolsContainerEl as any, 'claudian-subagent-tool-name')).toEqual(['Write']);
|
|
659
|
+
expect(getTextByClass(state.toolsContainerEl as any, 'claudian-subagent-tool-summary')).toEqual(['notes.md']);
|
|
660
|
+
});
|
|
661
|
+
});
|
|
662
|
+
|
|
663
|
+
describe('updateSubagentToolResult', () => {
|
|
664
|
+
let parentEl: MockElement;
|
|
665
|
+
|
|
666
|
+
beforeEach(() => {
|
|
667
|
+
jest.clearAllMocks();
|
|
668
|
+
parentEl = createMockEl('div');
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
it('updates tool call status in state', () => {
|
|
672
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
673
|
+
|
|
674
|
+
const toolCall: ToolCallInfo = {
|
|
675
|
+
id: 'tool-1',
|
|
676
|
+
name: 'Read',
|
|
677
|
+
input: { file_path: 'test.md' },
|
|
678
|
+
status: 'running',
|
|
679
|
+
isExpanded: false,
|
|
680
|
+
};
|
|
681
|
+
addSubagentToolCall(state, toolCall);
|
|
682
|
+
|
|
683
|
+
const updatedToolCall: ToolCallInfo = {
|
|
684
|
+
...toolCall,
|
|
685
|
+
status: 'completed',
|
|
686
|
+
result: 'File contents here',
|
|
687
|
+
};
|
|
688
|
+
updateSubagentToolResult(state, 'tool-1', updatedToolCall);
|
|
689
|
+
|
|
690
|
+
expect(state.info.toolCalls[0].status).toBe('completed');
|
|
691
|
+
});
|
|
692
|
+
|
|
693
|
+
it('does not update tool call for non-matching tool ID', () => {
|
|
694
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
695
|
+
|
|
696
|
+
const toolCall: ToolCallInfo = {
|
|
697
|
+
id: 'tool-1',
|
|
698
|
+
name: 'Read',
|
|
699
|
+
input: { file_path: 'test.md' },
|
|
700
|
+
status: 'running',
|
|
701
|
+
isExpanded: false,
|
|
702
|
+
};
|
|
703
|
+
addSubagentToolCall(state, toolCall);
|
|
704
|
+
|
|
705
|
+
updateSubagentToolResult(state, 'tool-999', { ...toolCall, id: 'tool-999', status: 'completed' });
|
|
706
|
+
|
|
707
|
+
expect(state.info.toolCalls[0].status).toBe('running');
|
|
708
|
+
});
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
describe('finalizeSubagentBlock', () => {
|
|
712
|
+
let parentEl: MockElement;
|
|
713
|
+
|
|
714
|
+
beforeEach(() => {
|
|
715
|
+
jest.clearAllMocks();
|
|
716
|
+
parentEl = createMockEl('div');
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
it('sets status to completed and adds done class', () => {
|
|
720
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
721
|
+
|
|
722
|
+
(setIcon as jest.Mock).mockClear();
|
|
723
|
+
finalizeSubagentBlock(state, 'All done', false);
|
|
724
|
+
|
|
725
|
+
expect(state.info.status).toBe('completed');
|
|
726
|
+
expect(state.info.result).toBe('All done');
|
|
727
|
+
expect((state.wrapperEl as any).hasClass('done')).toBe(true);
|
|
728
|
+
expect(setIcon).toHaveBeenCalledWith(expect.anything(), 'check');
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
it('sets status to error and adds error class', () => {
|
|
732
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
733
|
+
|
|
734
|
+
(setIcon as jest.Mock).mockClear();
|
|
735
|
+
finalizeSubagentBlock(state, 'Something failed', true);
|
|
736
|
+
|
|
737
|
+
expect(state.info.status).toBe('error');
|
|
738
|
+
expect(state.info.result).toBe('Something failed');
|
|
739
|
+
expect((state.wrapperEl as any).hasClass('error')).toBe(true);
|
|
740
|
+
expect(setIcon).toHaveBeenCalledWith(expect.anything(), 'x');
|
|
741
|
+
});
|
|
742
|
+
|
|
743
|
+
it('keeps tool history and shows result section text', () => {
|
|
744
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
745
|
+
|
|
746
|
+
// Add a tool call first to populate content
|
|
747
|
+
addSubagentToolCall(state, {
|
|
748
|
+
id: 'tool-1',
|
|
749
|
+
name: 'Read',
|
|
750
|
+
input: { file_path: 'test.md' },
|
|
751
|
+
status: 'running',
|
|
752
|
+
isExpanded: false,
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
finalizeSubagentBlock(state, 'Done', false);
|
|
756
|
+
|
|
757
|
+
const doneText = getTextByClass(state.contentEl as any, 'claudian-subagent-result-output')[0];
|
|
758
|
+
expect(doneText).toBe('Done');
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
it('shows ERROR text when isError is true', () => {
|
|
762
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
763
|
+
|
|
764
|
+
finalizeSubagentBlock(state, 'Error occurred', true);
|
|
765
|
+
|
|
766
|
+
const errorText = getTextByClass(state.contentEl as any, 'claudian-subagent-result-output')[0];
|
|
767
|
+
expect(errorText).toBe('Error occurred');
|
|
768
|
+
});
|
|
769
|
+
|
|
770
|
+
it('does not restore a tool count badge after finalization', () => {
|
|
771
|
+
const state = createSubagentBlock(parentEl as any, 'task-1', { description: 'Test task' });
|
|
772
|
+
|
|
773
|
+
addSubagentToolCall(state, {
|
|
774
|
+
id: 'tool-1',
|
|
775
|
+
name: 'Read',
|
|
776
|
+
input: {},
|
|
777
|
+
status: 'running',
|
|
778
|
+
isExpanded: false,
|
|
779
|
+
});
|
|
780
|
+
addSubagentToolCall(state, {
|
|
781
|
+
id: 'tool-2',
|
|
782
|
+
name: 'Grep',
|
|
783
|
+
input: {},
|
|
784
|
+
status: 'running',
|
|
785
|
+
isExpanded: false,
|
|
786
|
+
});
|
|
787
|
+
|
|
788
|
+
finalizeSubagentBlock(state, 'Done', false);
|
|
789
|
+
|
|
790
|
+
expect(getTextByClass(state.wrapperEl as any, 'claudian-subagent-count')).toEqual([]);
|
|
791
|
+
});
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
describe('renderStoredSubagent status variants', () => {
|
|
795
|
+
let parentEl: MockElement;
|
|
796
|
+
|
|
797
|
+
beforeEach(() => {
|
|
798
|
+
jest.clearAllMocks();
|
|
799
|
+
parentEl = createMockEl('div');
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
it('renders completed subagent with done class and check icon', () => {
|
|
803
|
+
const subagent: SubagentInfo = {
|
|
804
|
+
id: 'task-1',
|
|
805
|
+
description: 'Completed task',
|
|
806
|
+
status: 'completed',
|
|
807
|
+
toolCalls: [],
|
|
808
|
+
isExpanded: false,
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
(setIcon as jest.Mock).mockClear();
|
|
812
|
+
const wrapperEl = renderStoredSubagent(parentEl as any, subagent);
|
|
813
|
+
|
|
814
|
+
expect((wrapperEl as any).hasClass('done')).toBe(true);
|
|
815
|
+
expect(setIcon).toHaveBeenCalledWith(expect.anything(), 'check');
|
|
816
|
+
const doneText = getTextByClass(wrapperEl as any, 'claudian-subagent-result-output')[0];
|
|
817
|
+
expect(doneText).toBe('DONE');
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
it('renders error subagent with error class and x icon', () => {
|
|
821
|
+
const subagent: SubagentInfo = {
|
|
822
|
+
id: 'task-1',
|
|
823
|
+
description: 'Failed task',
|
|
824
|
+
status: 'error',
|
|
825
|
+
toolCalls: [],
|
|
826
|
+
isExpanded: false,
|
|
827
|
+
};
|
|
828
|
+
|
|
829
|
+
(setIcon as jest.Mock).mockClear();
|
|
830
|
+
const wrapperEl = renderStoredSubagent(parentEl as any, subagent);
|
|
831
|
+
|
|
832
|
+
expect((wrapperEl as any).hasClass('error')).toBe(true);
|
|
833
|
+
expect(setIcon).toHaveBeenCalledWith(expect.anything(), 'x');
|
|
834
|
+
const errorText = getTextByClass(wrapperEl as any, 'claudian-subagent-result-output')[0];
|
|
835
|
+
expect(errorText).toBe('ERROR');
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
it('renders running subagent with tool list', () => {
|
|
839
|
+
const subagent: SubagentInfo = {
|
|
840
|
+
id: 'task-1',
|
|
841
|
+
description: 'Running task',
|
|
842
|
+
status: 'running',
|
|
843
|
+
toolCalls: [
|
|
844
|
+
{ id: 'tool-1', name: 'Read', input: { file_path: 'test.md' }, status: 'completed', isExpanded: false },
|
|
845
|
+
{ id: 'tool-2', name: 'Grep', input: { pattern: 'test' }, status: 'running', isExpanded: false },
|
|
846
|
+
],
|
|
847
|
+
isExpanded: false,
|
|
848
|
+
};
|
|
849
|
+
|
|
850
|
+
const wrapperEl = renderStoredSubagent(parentEl as any, subagent);
|
|
851
|
+
|
|
852
|
+
// Should not have done or error class
|
|
853
|
+
expect((wrapperEl as any).hasClass('done')).toBe(false);
|
|
854
|
+
expect((wrapperEl as any).hasClass('error')).toBe(false);
|
|
855
|
+
});
|
|
856
|
+
|
|
857
|
+
it('renders running subagent tool call with expanded-style result', () => {
|
|
858
|
+
const subagent: SubagentInfo = {
|
|
859
|
+
id: 'task-1',
|
|
860
|
+
description: 'Running task',
|
|
861
|
+
status: 'running',
|
|
862
|
+
toolCalls: [
|
|
863
|
+
{
|
|
864
|
+
id: 'tool-1',
|
|
865
|
+
name: 'Read',
|
|
866
|
+
input: { file_path: 'test.md' },
|
|
867
|
+
status: 'completed',
|
|
868
|
+
result: 'File contents here',
|
|
869
|
+
isExpanded: false,
|
|
870
|
+
},
|
|
871
|
+
],
|
|
872
|
+
isExpanded: false,
|
|
873
|
+
};
|
|
874
|
+
|
|
875
|
+
const wrapperEl = renderStoredSubagent(parentEl as any, subagent);
|
|
876
|
+
const contentEl = (wrapperEl as any).children[1]; // content area
|
|
877
|
+
|
|
878
|
+
// Should show result text
|
|
879
|
+
const resultTexts = getTextByClass(contentEl, 'claudian-tool-line');
|
|
880
|
+
expect(resultTexts.length).toBe(1);
|
|
881
|
+
expect(resultTexts[0]).toContain('File contents here');
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
it('does not render a tool count badge for stored subagents', () => {
|
|
885
|
+
const subagent: SubagentInfo = {
|
|
886
|
+
id: 'task-1',
|
|
887
|
+
description: 'Task with tools',
|
|
888
|
+
status: 'completed',
|
|
889
|
+
toolCalls: [
|
|
890
|
+
{ id: 'tool-1', name: 'Read', input: {}, status: 'completed', isExpanded: false },
|
|
891
|
+
{ id: 'tool-2', name: 'Grep', input: {}, status: 'completed', isExpanded: false },
|
|
892
|
+
{ id: 'tool-3', name: 'Edit', input: {}, status: 'completed', isExpanded: false },
|
|
893
|
+
],
|
|
894
|
+
isExpanded: false,
|
|
895
|
+
};
|
|
896
|
+
|
|
897
|
+
const wrapperEl = renderStoredSubagent(parentEl as any, subagent);
|
|
898
|
+
|
|
899
|
+
expect(getTextByClass(wrapperEl as any, 'claudian-subagent-count')).toEqual([]);
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
it('truncates long descriptions', () => {
|
|
903
|
+
const longDesc = 'A'.repeat(50);
|
|
904
|
+
const subagent: SubagentInfo = {
|
|
905
|
+
id: 'task-1',
|
|
906
|
+
description: longDesc,
|
|
907
|
+
status: 'completed',
|
|
908
|
+
toolCalls: [],
|
|
909
|
+
isExpanded: false,
|
|
910
|
+
};
|
|
911
|
+
|
|
912
|
+
const wrapperEl = renderStoredSubagent(parentEl as any, subagent);
|
|
913
|
+
|
|
914
|
+
const labelTexts = getTextByClass(wrapperEl as any, 'claudian-subagent-label');
|
|
915
|
+
expect(labelTexts[0]).toBe('A'.repeat(40) + '...');
|
|
916
|
+
});
|
|
917
|
+
});
|