actoviq-agent-sdk 0.4.11 → 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +42 -0
- package/dist/src/computer/hadamardComputerUse.d.ts +15 -0
- package/dist/src/computer/hadamardComputerUse.d.ts.map +1 -1
- package/dist/src/computer/hadamardComputerUse.js +120 -4
- package/dist/src/computer/hadamardComputerUse.js.map +1 -1
- package/dist/src/config/agentDefinitionMigration.d.ts +125 -0
- package/dist/src/config/agentDefinitionMigration.d.ts.map +1 -0
- package/dist/src/config/agentDefinitionMigration.js +540 -0
- package/dist/src/config/agentDefinitionMigration.js.map +1 -0
- package/dist/src/config/agentProfiles.d.ts +23 -0
- package/dist/src/config/agentProfiles.d.ts.map +1 -1
- package/dist/src/config/agentProfiles.js +69 -13
- package/dist/src/config/agentProfiles.js.map +1 -1
- package/dist/src/config/hadamardHome.js +0 -1
- package/dist/src/config/hadamardHome.js.map +1 -1
- package/dist/src/config/modelConfigurationCatalog.d.ts +25 -0
- package/dist/src/config/modelConfigurationCatalog.d.ts.map +1 -0
- package/dist/src/config/modelConfigurationCatalog.js +50 -0
- package/dist/src/config/modelConfigurationCatalog.js.map +1 -0
- package/dist/src/config/projectSettings.d.ts +62 -0
- package/dist/src/config/projectSettings.d.ts.map +1 -0
- package/dist/src/config/projectSettings.js +242 -0
- package/dist/src/config/projectSettings.js.map +1 -0
- package/dist/src/config/resolveRuntimeConfig.d.ts.map +1 -1
- package/dist/src/config/resolveRuntimeConfig.js +97 -4
- package/dist/src/config/resolveRuntimeConfig.js.map +1 -1
- package/dist/src/goal/goalCommandService.d.ts +11 -0
- package/dist/src/goal/goalCommandService.d.ts.map +1 -0
- package/dist/src/goal/goalCommandService.js +138 -0
- package/dist/src/goal/goalCommandService.js.map +1 -0
- package/dist/src/goal/goalContinuation.d.ts +50 -0
- package/dist/src/goal/goalContinuation.d.ts.map +1 -0
- package/dist/src/goal/goalContinuation.js +131 -0
- package/dist/src/goal/goalContinuation.js.map +1 -0
- package/dist/src/goal/goalController.d.ts +42 -0
- package/dist/src/goal/goalController.d.ts.map +1 -0
- package/dist/src/goal/goalController.js +281 -0
- package/dist/src/goal/goalController.js.map +1 -0
- package/dist/src/goal/goalPrompt.d.ts +3 -0
- package/dist/src/goal/goalPrompt.d.ts.map +1 -1
- package/dist/src/goal/goalPrompt.js +28 -2
- package/dist/src/goal/goalPrompt.js.map +1 -1
- package/dist/src/goal/goalService.d.ts +68 -2
- package/dist/src/goal/goalService.d.ts.map +1 -1
- package/dist/src/goal/goalService.js +500 -8
- package/dist/src/goal/goalService.js.map +1 -1
- package/dist/src/goal/goalStore.d.ts.map +1 -1
- package/dist/src/goal/goalStore.js +172 -5
- package/dist/src/goal/goalStore.js.map +1 -1
- package/dist/src/goal/goalTools.d.ts +2 -1
- package/dist/src/goal/goalTools.d.ts.map +1 -1
- package/dist/src/goal/goalTools.js +70 -5
- package/dist/src/goal/goalTools.js.map +1 -1
- package/dist/src/goal/goalWorkCoordinator.d.ts +43 -0
- package/dist/src/goal/goalWorkCoordinator.d.ts.map +1 -0
- package/dist/src/goal/goalWorkCoordinator.js +72 -0
- package/dist/src/goal/goalWorkCoordinator.js.map +1 -0
- package/dist/src/goal/index.d.ts +10 -4
- package/dist/src/goal/index.d.ts.map +1 -1
- package/dist/src/goal/index.js +7 -1
- package/dist/src/goal/index.js.map +1 -1
- package/dist/src/goal/projectGoalApi.d.ts +82 -0
- package/dist/src/goal/projectGoalApi.d.ts.map +1 -0
- package/dist/src/goal/projectGoalApi.js +287 -0
- package/dist/src/goal/projectGoalApi.js.map +1 -0
- package/dist/src/goal/projectGoalStore.d.ts +131 -0
- package/dist/src/goal/projectGoalStore.d.ts.map +1 -0
- package/dist/src/goal/projectGoalStore.js +808 -0
- package/dist/src/goal/projectGoalStore.js.map +1 -0
- package/dist/src/goal/types.d.ts +127 -3
- package/dist/src/goal/types.d.ts.map +1 -1
- package/dist/src/goal/types.js +2 -2
- package/dist/src/goal/types.js.map +1 -1
- package/dist/src/gui/agentTargetPicker.d.ts +32 -0
- package/dist/src/gui/agentTargetPicker.d.ts.map +1 -0
- package/dist/src/gui/agentTargetPicker.js +99 -0
- package/dist/src/gui/agentTargetPicker.js.map +1 -0
- package/dist/src/gui/electronMain.js +10 -3
- package/dist/src/gui/electronMain.js.map +1 -1
- package/dist/src/gui/hadamardGui.d.ts +24 -0
- package/dist/src/gui/hadamardGui.d.ts.map +1 -1
- package/dist/src/gui/hadamardGui.js +6321 -1327
- package/dist/src/gui/hadamardGui.js.map +1 -1
- package/dist/src/gui/projectWorkbench.d.ts +13 -2
- package/dist/src/gui/projectWorkbench.d.ts.map +1 -1
- package/dist/src/gui/projectWorkbench.js +109 -67
- package/dist/src/gui/projectWorkbench.js.map +1 -1
- package/dist/src/gui/promptTemplates.d.ts +18 -0
- package/dist/src/gui/promptTemplates.d.ts.map +1 -0
- package/dist/src/gui/promptTemplates.js +178 -0
- package/dist/src/gui/promptTemplates.js.map +1 -0
- package/dist/src/gui/terminalManager.d.ts +14 -0
- package/dist/src/gui/terminalManager.d.ts.map +1 -1
- package/dist/src/gui/terminalManager.js +25 -5
- package/dist/src/gui/terminalManager.js.map +1 -1
- package/dist/src/gui/transcript/clientBundle.d.ts +6 -1
- package/dist/src/gui/transcript/clientBundle.d.ts.map +1 -1
- package/dist/src/gui/transcript/clientBundle.js +6 -1
- package/dist/src/gui/transcript/clientBundle.js.map +1 -1
- package/dist/src/help/productCapabilities.d.ts +17 -0
- package/dist/src/help/productCapabilities.d.ts.map +1 -0
- package/dist/src/help/productCapabilities.js +146 -0
- package/dist/src/help/productCapabilities.js.map +1 -0
- package/dist/src/index.d.ts +21 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +15 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/issues/issueExecution.d.ts.map +1 -1
- package/dist/src/issues/issueExecution.js +29 -9
- package/dist/src/issues/issueExecution.js.map +1 -1
- package/dist/src/manager/assistantGlobalTools.d.ts +44 -0
- package/dist/src/manager/assistantGlobalTools.d.ts.map +1 -1
- package/dist/src/manager/assistantGlobalTools.js +565 -34
- package/dist/src/manager/assistantGlobalTools.js.map +1 -1
- package/dist/src/manager/assistantProposals.d.ts +87 -0
- package/dist/src/manager/assistantProposals.d.ts.map +1 -0
- package/dist/src/manager/assistantProposals.js +207 -0
- package/dist/src/manager/assistantProposals.js.map +1 -0
- package/dist/src/manager/referenceIndex.d.ts +82 -0
- package/dist/src/manager/referenceIndex.d.ts.map +1 -0
- package/dist/src/manager/referenceIndex.js +167 -0
- package/dist/src/manager/referenceIndex.js.map +1 -0
- package/dist/src/manager/referenceOperations.d.ts +108 -0
- package/dist/src/manager/referenceOperations.d.ts.map +1 -0
- package/dist/src/manager/referenceOperations.js +821 -0
- package/dist/src/manager/referenceOperations.js.map +1 -0
- package/dist/src/manager/resolveTargetRef.d.ts +67 -0
- package/dist/src/manager/resolveTargetRef.d.ts.map +1 -0
- package/dist/src/manager/resolveTargetRef.js +81 -0
- package/dist/src/manager/resolveTargetRef.js.map +1 -0
- package/dist/src/memory/durableMemoryPipeline.d.ts +51 -0
- package/dist/src/memory/durableMemoryPipeline.d.ts.map +1 -0
- package/dist/src/memory/durableMemoryPipeline.js +266 -0
- package/dist/src/memory/durableMemoryPipeline.js.map +1 -0
- package/dist/src/memory/durableMemoryStore.d.ts +59 -0
- package/dist/src/memory/durableMemoryStore.d.ts.map +1 -0
- package/dist/src/memory/durableMemoryStore.js +194 -0
- package/dist/src/memory/durableMemoryStore.js.map +1 -0
- package/dist/src/memory/hadamardDream.d.ts +18 -0
- package/dist/src/memory/hadamardDream.d.ts.map +1 -1
- package/dist/src/memory/hadamardDream.js +119 -39
- package/dist/src/memory/hadamardDream.js.map +1 -1
- package/dist/src/memory/hadamardMemory.d.ts +20 -39
- package/dist/src/memory/hadamardMemory.d.ts.map +1 -1
- package/dist/src/memory/hadamardMemory.js +112 -450
- package/dist/src/memory/hadamardMemory.js.map +1 -1
- package/dist/src/memory/hadamardSessionMemoryState.d.ts +2 -5
- package/dist/src/memory/hadamardSessionMemoryState.d.ts.map +1 -1
- package/dist/src/memory/hadamardSessionMemoryState.js +5 -61
- package/dist/src/memory/hadamardSessionMemoryState.js.map +1 -1
- package/dist/src/memory/memoryCommandService.d.ts +25 -0
- package/dist/src/memory/memoryCommandService.d.ts.map +1 -0
- package/dist/src/memory/memoryCommandService.js +93 -0
- package/dist/src/memory/memoryCommandService.js.map +1 -0
- package/dist/src/memory/memoryProposalCommandService.d.ts.map +1 -1
- package/dist/src/memory/memoryProposalCommandService.js +2 -1
- package/dist/src/memory/memoryProposalCommandService.js.map +1 -1
- package/dist/src/memory/memoryProposalTools.d.ts +1 -0
- package/dist/src/memory/memoryProposalTools.d.ts.map +1 -1
- package/dist/src/memory/memoryProposalTools.js +16 -11
- package/dist/src/memory/memoryProposalTools.js.map +1 -1
- package/dist/src/parity/bridgeConfigs.d.ts +4 -0
- package/dist/src/parity/bridgeConfigs.d.ts.map +1 -1
- package/dist/src/parity/bridgeConfigs.js +30 -1
- package/dist/src/parity/bridgeConfigs.js.map +1 -1
- package/dist/src/router/modelRouter.d.ts +22 -2
- package/dist/src/router/modelRouter.d.ts.map +1 -1
- package/dist/src/router/modelRouter.js +76 -9
- package/dist/src/router/modelRouter.js.map +1 -1
- package/dist/src/runtime/agentClient.d.ts +24 -4
- package/dist/src/runtime/agentClient.d.ts.map +1 -1
- package/dist/src/runtime/agentClient.js +581 -262
- package/dist/src/runtime/agentClient.js.map +1 -1
- package/dist/src/runtime/agentSession.d.ts +8 -3
- package/dist/src/runtime/agentSession.d.ts.map +1 -1
- package/dist/src/runtime/agentSession.js +10 -3
- package/dist/src/runtime/agentSession.js.map +1 -1
- package/dist/src/runtime/agentTemplates.d.ts +28 -0
- package/dist/src/runtime/agentTemplates.d.ts.map +1 -0
- package/dist/src/runtime/agentTemplates.js +73 -0
- package/dist/src/runtime/agentTemplates.js.map +1 -0
- package/dist/src/runtime/conversationEngine.d.ts +4 -0
- package/dist/src/runtime/conversationEngine.d.ts.map +1 -1
- package/dist/src/runtime/conversationEngine.js +52 -3
- package/dist/src/runtime/conversationEngine.js.map +1 -1
- package/dist/src/runtime/defaultHadamardAgents.d.ts.map +1 -1
- package/dist/src/runtime/defaultHadamardAgents.js +9 -47
- package/dist/src/runtime/defaultHadamardAgents.js.map +1 -1
- package/dist/src/runtime/effectiveAgentRunOptions.d.ts +49 -0
- package/dist/src/runtime/effectiveAgentRunOptions.d.ts.map +1 -0
- package/dist/src/runtime/effectiveAgentRunOptions.js +50 -0
- package/dist/src/runtime/effectiveAgentRunOptions.js.map +1 -0
- package/dist/src/runtime/externalAgentRunner.d.ts +25 -0
- package/dist/src/runtime/externalAgentRunner.d.ts.map +1 -0
- package/dist/src/runtime/externalAgentRunner.js +57 -0
- package/dist/src/runtime/externalAgentRunner.js.map +1 -0
- package/dist/src/runtime/hadamardAgentDefinitions.d.ts +15 -0
- package/dist/src/runtime/hadamardAgentDefinitions.d.ts.map +1 -1
- package/dist/src/runtime/hadamardAgentDefinitions.js +42 -2
- package/dist/src/runtime/hadamardAgentDefinitions.js.map +1 -1
- package/dist/src/runtime/hadamardAgents.d.ts +6 -0
- package/dist/src/runtime/hadamardAgents.d.ts.map +1 -1
- package/dist/src/runtime/hadamardAgents.js +52 -1
- package/dist/src/runtime/hadamardAgents.js.map +1 -1
- package/dist/src/runtime/hadamardCompact.d.ts +12 -1
- package/dist/src/runtime/hadamardCompact.d.ts.map +1 -1
- package/dist/src/runtime/hadamardCompact.js +91 -35
- package/dist/src/runtime/hadamardCompact.js.map +1 -1
- package/dist/src/runtime/hadamardPermissions.d.ts +1 -0
- package/dist/src/runtime/hadamardPermissions.d.ts.map +1 -1
- package/dist/src/runtime/hadamardPermissions.js +6 -0
- package/dist/src/runtime/hadamardPermissions.js.map +1 -1
- package/dist/src/runtime/hadamardSlashCommands.d.ts +7 -1
- package/dist/src/runtime/hadamardSlashCommands.d.ts.map +1 -1
- package/dist/src/runtime/hadamardSlashCommands.js +47 -5
- package/dist/src/runtime/hadamardSlashCommands.js.map +1 -1
- package/dist/src/runtime/tools.d.ts.map +1 -1
- package/dist/src/runtime/tools.js +2 -0
- package/dist/src/runtime/tools.js.map +1 -1
- package/dist/src/team/executorTarget.d.ts +26 -0
- package/dist/src/team/executorTarget.d.ts.map +1 -0
- package/dist/src/team/executorTarget.js +15 -0
- package/dist/src/team/executorTarget.js.map +1 -0
- package/dist/src/team/modelTeam.d.ts +5 -1
- package/dist/src/team/modelTeam.d.ts.map +1 -1
- package/dist/src/team/modelTeam.js +157 -41
- package/dist/src/team/modelTeam.js.map +1 -1
- package/dist/src/team/teamComposition.d.ts +20 -0
- package/dist/src/team/teamComposition.d.ts.map +1 -0
- package/dist/src/team/teamComposition.js +78 -0
- package/dist/src/team/teamComposition.js.map +1 -0
- package/dist/src/team/teamDefinitions.d.ts +10 -1
- package/dist/src/team/teamDefinitions.d.ts.map +1 -1
- package/dist/src/team/teamDefinitions.js +123 -16
- package/dist/src/team/teamDefinitions.js.map +1 -1
- package/dist/src/team/teamGraph.d.ts +1 -1
- package/dist/src/team/teamGraph.d.ts.map +1 -1
- package/dist/src/team/teamGraph.js +1 -1
- package/dist/src/team/teamGraph.js.map +1 -1
- package/dist/src/team/teamPrompts.d.ts.map +1 -1
- package/dist/src/team/teamPrompts.js +0 -4
- package/dist/src/team/teamPrompts.js.map +1 -1
- package/dist/src/team/teamProposalService.d.ts +9 -1
- package/dist/src/team/teamProposalService.d.ts.map +1 -1
- package/dist/src/team/teamProposalService.js +66 -6
- package/dist/src/team/teamProposalService.js.map +1 -1
- package/dist/src/team/teamPropose.d.ts +3 -1
- package/dist/src/team/teamPropose.d.ts.map +1 -1
- package/dist/src/team/teamPropose.js +16 -10
- package/dist/src/team/teamPropose.js.map +1 -1
- package/dist/src/team/teamRuntime.d.ts +5 -0
- package/dist/src/team/teamRuntime.d.ts.map +1 -1
- package/dist/src/team/teamRuntime.js +23 -5
- package/dist/src/team/teamRuntime.js.map +1 -1
- package/dist/src/team/workflowSquad.d.ts +10 -2
- package/dist/src/team/workflowSquad.d.ts.map +1 -1
- package/dist/src/team/workflowSquad.js +250 -12
- package/dist/src/team/workflowSquad.js.map +1 -1
- package/dist/src/tools/enterWorktree.d.ts.map +1 -1
- package/dist/src/tools/enterWorktree.js +3 -0
- package/dist/src/tools/enterWorktree.js.map +1 -1
- package/dist/src/tools/exaSearch.d.ts +2 -2
- package/dist/src/tools/exitWorktree.d.ts.map +1 -1
- package/dist/src/tools/exitWorktree.js +3 -1
- package/dist/src/tools/exitWorktree.js.map +1 -1
- package/dist/src/tools/hadamardCoreTools.d.ts +5 -14
- package/dist/src/tools/hadamardCoreTools.d.ts.map +1 -1
- package/dist/src/tools/hadamardCoreTools.js +31 -0
- package/dist/src/tools/hadamardCoreTools.js.map +1 -1
- package/dist/src/tools/hadamardFileTools.d.ts.map +1 -1
- package/dist/src/tools/hadamardFileTools.js +116 -38
- package/dist/src/tools/hadamardFileTools.js.map +1 -1
- package/dist/src/tools/planMode/PlanModeTools.d.ts +22 -0
- package/dist/src/tools/planMode/PlanModeTools.d.ts.map +1 -1
- package/dist/src/tools/planMode/PlanModeTools.js +102 -5
- package/dist/src/tools/planMode/PlanModeTools.js.map +1 -1
- package/dist/src/tools/todo/TodoWriteTool.d.ts +1 -1
- package/dist/src/tui/hadamardTui.d.ts.map +1 -1
- package/dist/src/tui/hadamardTui.js +387 -168
- package/dist/src/tui/hadamardTui.js.map +1 -1
- package/dist/src/tui/pendingInput.d.ts +17 -0
- package/dist/src/tui/pendingInput.d.ts.map +1 -0
- package/dist/src/tui/pendingInput.js +23 -0
- package/dist/src/tui/pendingInput.js.map +1 -0
- package/dist/src/tui/reasoningDisplay.d.ts +13 -0
- package/dist/src/tui/reasoningDisplay.d.ts.map +1 -0
- package/dist/src/tui/reasoningDisplay.js +45 -0
- package/dist/src/tui/reasoningDisplay.js.map +1 -0
- package/dist/src/tui/screen.d.ts +11 -1
- package/dist/src/tui/screen.d.ts.map +1 -1
- package/dist/src/tui/screen.js +64 -34
- package/dist/src/tui/screen.js.map +1 -1
- package/dist/src/types.d.ts +210 -77
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/ui/commandSurface.d.ts +8 -0
- package/dist/src/ui/commandSurface.d.ts.map +1 -1
- package/dist/src/ui/commandSurface.js +78 -13
- package/dist/src/ui/commandSurface.js.map +1 -1
- package/dist/src/update/appUpdateService.d.ts +34 -1
- package/dist/src/update/appUpdateService.d.ts.map +1 -1
- package/dist/src/update/appUpdateService.js +114 -9
- package/dist/src/update/appUpdateService.js.map +1 -1
- package/package.json +3 -2
- package/dist/src/prompts/outputStyles.d.ts +0 -20
- package/dist/src/prompts/outputStyles.d.ts.map +0 -1
- package/dist/src/prompts/outputStyles.js +0 -35
- package/dist/src/prompts/outputStyles.js.map +0 -1
|
@@ -10,7 +10,7 @@ import { createHash, randomUUID } from 'node:crypto';
|
|
|
10
10
|
import fs from 'node:fs';
|
|
11
11
|
import path from 'node:path';
|
|
12
12
|
import * as readline from 'node:readline';
|
|
13
|
-
import { createHadamardCoreTools, createAgentSdk, createHadamardBridgeSdk, detectBridgeProviders, loadDefaultHadamardSettings, loadJsonConfigFile, listWorkflows, loadWorkflow, listTeamDefinitions, loadTeamDefinition, cloneTeamDefinition, instantiateTeamDefinition, listTeamAgentLabels, countTeamAgents,
|
|
13
|
+
import { createHadamardCoreTools, createAgentSdk, createHadamardBridgeSdk, detectBridgeProviders, loadDefaultHadamardSettings, loadJsonConfigFile, listWorkflows, loadWorkflow, saveWorkflow, deleteWorkflow, listTeamDefinitions, loadTeamDefinition, cloneTeamDefinition, deleteTeamDefinition, getBuiltInTeamDefinition, instantiateTeamDefinition, listTeamAgentLabels, countTeamAgents, askTeamDefinition, createTeamTool, readTeamPreferences, createManagerTools, createAssistantTeamTools, buildAssistantTeamSystemPrompt, TeamProposalStore, SessionCatalog, createAssistantGlobalTools, buildAssistantGlobalSystemPrompt, readAssistantConfig, writeAssistantConfig, buildManagerSystemPrompt, buildUpdateProgressPrompt, formatManagerUpdatePreview, resolveGitHubDigestForUpdate, readManagerConfig, writeManagerConfig, readProjectPlanFile, readProgressFile, managerProgressPath, createProjectIssue, executeProjectIssue, isIssueStatus, isIssueStorageMode, listProjectIssues, listScheduledAutomationTasks, upsertScheduledAutomationTask, resolveHadamardHome, externalSkillPreferencesToRuntimeOptions, readHadamardExternalSkillPreferences, createManagedPluginRuntime, patchManagedPluginSettings, readManagedPluginCatalog, listRouterProfiles, loadRouterProfile, resolveRoutedRun, transitionProjectIssue, WorktreeService, } from '../index.js';
|
|
14
14
|
import { adaptBridgeRun } from '../parity/bridgeEventAdapter.js';
|
|
15
15
|
import { ExternalCliRuntimeManager } from '../parity/externalCliRuntimeManager.js';
|
|
16
16
|
import { externalCliSessionMatchesConfig, listExternalCliSessions, readExternalCliSession, } from '../parity/externalCliSessions.js';
|
|
@@ -22,25 +22,27 @@ import { createPreToolUseHookClassifier, readPreToolUseHooks, readPostToolUseHoo
|
|
|
22
22
|
import { parseTypedHooks } from '../hooks/hookConfig.js';
|
|
23
23
|
import { isRecord } from '../runtime/helpers.js';
|
|
24
24
|
import { getLoadedJsonConfig } from '../config/loadJsonConfigFile.js';
|
|
25
|
+
import { buildModelConfigurationCatalog, findModelConfiguration, resolveHadamardConfigurationModel, } from '../config/modelConfigurationCatalog.js';
|
|
25
26
|
import { findBridgeConfig, maskApiKey, readBridgeConfigs, addBridgeConfig, removeBridgeConfig, isManagedExternalCliRuntime, } from '../parity/bridgeConfigs.js';
|
|
26
27
|
import { buildRouteModelApi } from '../router/modelRouter.js';
|
|
27
28
|
import { addMcpServer, readMcpServerConfig, removeMcpServer } from '../mcp/mcpServerConfig.js';
|
|
28
29
|
import { isReadOnlyBashCommand } from '../runtime/bashClassification.js';
|
|
29
30
|
import { estimateCost } from '../team/pricing.js';
|
|
30
31
|
import { applyTeamRunEvent, createTeamRunViewState, formatTeamRunTreeLines } from '../team/teamRunView.js';
|
|
31
|
-
import { applyOutputStyle, OUTPUT_STYLES } from '../prompts/outputStyles.js';
|
|
32
32
|
import { planFilePath, readPlanFile } from '../tools/planMode/PlanModeTools.js';
|
|
33
33
|
import { loadProjectContext } from '../memory/projectContext.js';
|
|
34
34
|
import { LegacySurfaceEventPipeline, } from '../surfaces/index.js';
|
|
35
35
|
import { pathToFileURL } from 'node:url';
|
|
36
|
-
import { HADAMARD_INTERACTIVE_COMMANDS, SUBCOMMAND_DESCRIPTIONS, filterInteractiveCommands, interactiveCommandUsage, selectInteractiveCommand, } from '../ui/commandSurface.js';
|
|
36
|
+
import { HADAMARD_INTERACTIVE_COMMANDS, SUBCOMMAND_DESCRIPTIONS, canRunInteractiveCommand, filterInteractiveCommands, interactiveCommandRunPolicy, interactiveCommandUsage, parseTeamAskArguments, selectInteractiveCommand, } from '../ui/commandSurface.js';
|
|
37
37
|
import { createAgentExecutionProjectView, createAgentExecutionRootView, formatAgentExecutionTreeLines, } from '../ui/agentExecutionView.js';
|
|
38
38
|
import { A, stringWidth, truncateToWidth, wrapToWidth } from './ansi.js';
|
|
39
39
|
import { InputEditor } from './editor.js';
|
|
40
40
|
import { discoverHadamardPlugins } from './pluginCatalog.js';
|
|
41
41
|
import { TuiScreen } from './screen.js';
|
|
42
|
+
import { ReasoningDisplayState } from './reasoningDisplay.js';
|
|
43
|
+
import { recallLatestFollowUp, restoreAbandonedFollowUp, submitActiveInput, } from './pendingInput.js';
|
|
42
44
|
import { filterTuiSelectionItems, moveTuiSelection, } from './selection.js';
|
|
43
|
-
import { StreamFlusher, formatBanner, formatCompactNotice, formatDivider, formatEditCall, formatErrorLine, formatInfoLine, formatQueuedPrompt,
|
|
45
|
+
import { StreamFlusher, formatBanner, formatCompactNotice, formatDivider, formatEditCall, formatErrorLine, formatInfoLine, formatQueuedPrompt, formatToolCall, formatToolResult, formatUserPrompt, } from './transcript.js';
|
|
44
46
|
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
45
47
|
const CTRL_C_EXIT_WINDOW_MS = 600;
|
|
46
48
|
const DYNAMIC_FRAME_MS = 33;
|
|
@@ -356,6 +358,8 @@ export async function runHadamardTui(options = {}) {
|
|
|
356
358
|
let running = false;
|
|
357
359
|
let commandBusy = false;
|
|
358
360
|
let shuttingDown = false;
|
|
361
|
+
/** Follow-up pulled out of the queue into the editor; restored if abandoned. */
|
|
362
|
+
let recalledFollowUp = null;
|
|
359
363
|
// Active team tool the main agent may call (toggled via /team). null = no team.
|
|
360
364
|
// The tool is only injected into runs when preferences.team.autoInvoke is on;
|
|
361
365
|
// otherwise attach is a selection and /team ask stays the manual path.
|
|
@@ -682,13 +686,10 @@ export async function runHadamardTui(options = {}) {
|
|
|
682
686
|
return cost !== null ? `$${cost.toFixed(4)}` : null;
|
|
683
687
|
}
|
|
684
688
|
let statusNote = '';
|
|
685
|
-
// /output-style prompt prefix swap (gap #19). Applied to the base system
|
|
686
|
-
// prompt per turn; 'default' is a no-op.
|
|
687
|
-
let outputStyle = 'default';
|
|
688
689
|
let ctrlCCount = 0;
|
|
689
690
|
let ctrlCTimer = null;
|
|
690
691
|
let streamedTextSeen = false;
|
|
691
|
-
|
|
692
|
+
const reasoningDisplay = new ReasoningDisplayState();
|
|
692
693
|
// Track tool names by callId for PostToolUse hook context.
|
|
693
694
|
const toolCallNames = new Map();
|
|
694
695
|
// Live todo list (captured from TodoWrite tool calls). Rendered as a
|
|
@@ -888,6 +889,16 @@ export async function runHadamardTui(options = {}) {
|
|
|
888
889
|
lines.push(promptDivider());
|
|
889
890
|
return lines;
|
|
890
891
|
}
|
|
892
|
+
function promptCursorPosition(promptStartLine) {
|
|
893
|
+
if (editor.isEmpty()) {
|
|
894
|
+
return { line: promptStartLine + 1, column: 2 };
|
|
895
|
+
}
|
|
896
|
+
const visual = editor.visualLines(Math.max(screen.width - 5, 7));
|
|
897
|
+
return {
|
|
898
|
+
line: promptStartLine + 1 + visual.cursorRow,
|
|
899
|
+
column: 2 + visual.cursorCol,
|
|
900
|
+
};
|
|
901
|
+
}
|
|
891
902
|
// ── @-mention file completion ──────────────────────────────────────
|
|
892
903
|
// Prefer git's view (tracked + untracked, honoring .gitignore) so the list
|
|
893
904
|
// matches what the agent actually sees; fall back to a bounded fs walk for
|
|
@@ -1038,7 +1049,10 @@ export async function runHadamardTui(options = {}) {
|
|
|
1038
1049
|
const selected = index === menuSelected;
|
|
1039
1050
|
const command = `/${name}`.padEnd(commandWidth);
|
|
1040
1051
|
const label = selected ? `${A.inverse}${command}${A.reset}` : command;
|
|
1041
|
-
const
|
|
1052
|
+
const commandName = name.split(/\s/u, 1)[0] ?? name;
|
|
1053
|
+
const unavailable = running && interactiveCommandRunPolicy(commandName) === 'idle-only';
|
|
1054
|
+
const summary = TUI_SLASH_COMMANDS[name] ?? SUBCOMMAND_DESCRIPTIONS[name] ?? '';
|
|
1055
|
+
const description = truncateToWidth(unavailable ? `${summary} · after current run` : summary, descriptionWidth);
|
|
1042
1056
|
return `${label} ${A.dim}${description}${A.reset}`;
|
|
1043
1057
|
});
|
|
1044
1058
|
const hiddenAbove = windowStart;
|
|
@@ -1051,6 +1065,14 @@ export async function runHadamardTui(options = {}) {
|
|
|
1051
1065
|
parts.push(`↓${hiddenBelow}`);
|
|
1052
1066
|
lines.push(`${A.dim} ${parts.join(' ')} more · ${menuSelected + 1}/${matches.length} (↑/↓ to scroll)${A.reset}`);
|
|
1053
1067
|
}
|
|
1068
|
+
const selected = matches[Math.min(menuSelected, matches.length - 1)];
|
|
1069
|
+
if (selected) {
|
|
1070
|
+
const commandName = selected.split(/\s/u, 1)[0] ?? selected;
|
|
1071
|
+
const availability = interactiveCommandRunPolicy(commandName) === 'during-run'
|
|
1072
|
+
? 'available while working'
|
|
1073
|
+
: 'idle session';
|
|
1074
|
+
lines.push(`${A.dim} ${interactiveCommandUsage(commandName)} · ${availability}${A.reset}`);
|
|
1075
|
+
}
|
|
1054
1076
|
return lines;
|
|
1055
1077
|
}
|
|
1056
1078
|
function buildDialog() {
|
|
@@ -1146,7 +1168,9 @@ export async function runHadamardTui(options = {}) {
|
|
|
1146
1168
|
const ctxColor = pct >= 90 ? A.red : pct >= 70 ? A.yellow : A.dim;
|
|
1147
1169
|
const modelLabel = activeRouter
|
|
1148
1170
|
? `router:${activeRouter.name}${routedModelLabel ? ` → ${routedModelLabel}` : ''}`
|
|
1149
|
-
:
|
|
1171
|
+
: !bridgeMode && activeBridgeConfig?.runtime === 'hadamard' && bridgeModelLabel
|
|
1172
|
+
? `${activeBridgeConfig.name}:${bridgeModelLabel}`
|
|
1173
|
+
: session.model;
|
|
1150
1174
|
const bridgeTag = bridgeMode && activeBridgeConfig
|
|
1151
1175
|
? ` · bridge:${activeBridgeConfig.name}${bridgeModelLabel ? ` · ${bridgeModelLabel}` : ''}`
|
|
1152
1176
|
: '';
|
|
@@ -1171,10 +1195,39 @@ export async function runHadamardTui(options = {}) {
|
|
|
1171
1195
|
}
|
|
1172
1196
|
function buildHintLine() {
|
|
1173
1197
|
if (running) {
|
|
1174
|
-
return [`${A.dim} enter
|
|
1198
|
+
return [`${A.dim} enter queue follow-up · shift+enter steer now · ↑ recall queued · esc interrupt${A.reset}`];
|
|
1175
1199
|
}
|
|
1176
1200
|
return [`${A.dim} ? shortcuts · / commands · @ files · \\↵ newline · ↑↓ history · ctrl+c clear/exit${A.reset}`];
|
|
1177
1201
|
}
|
|
1202
|
+
function buildPendingInputPanel() {
|
|
1203
|
+
const pending = session.pendingInputs;
|
|
1204
|
+
const visible = pending.followUps.slice(-3);
|
|
1205
|
+
const hidden = pending.followUps.length - visible.length;
|
|
1206
|
+
const lines = visible.map((text, index) => (`${A.dim} queued ${hidden + index + 1}: ${truncateToWidth(text.replace(/\s+/g, ' '), Math.max(screen.width - 15, 12))}${A.reset}`));
|
|
1207
|
+
if (pending.steering.length > 0) {
|
|
1208
|
+
lines.push(`${A.dim} ${pending.steering.length} immediate steering message${pending.steering.length === 1 ? '' : 's'} pending${A.reset}`);
|
|
1209
|
+
}
|
|
1210
|
+
return lines;
|
|
1211
|
+
}
|
|
1212
|
+
function selectionDialogCursorPosition(startLine) {
|
|
1213
|
+
if (!selectionDialog?.searchable)
|
|
1214
|
+
return undefined;
|
|
1215
|
+
return {
|
|
1216
|
+
line: startLine + 2 + (selectionDialog.subtitle ? 1 : 0),
|
|
1217
|
+
column: 4 + stringWidth(selectionDialog.query),
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
function textInputDialogCursorPosition(startLine) {
|
|
1221
|
+
if (!textInputDialog)
|
|
1222
|
+
return undefined;
|
|
1223
|
+
const valueBeforeCursor = textInputDialog.secret
|
|
1224
|
+
? '•'.repeat(textInputDialog.editor.cursor)
|
|
1225
|
+
: textInputDialog.editor.text.slice(0, textInputDialog.editor.cursor);
|
|
1226
|
+
return {
|
|
1227
|
+
line: startLine + 2 + (textInputDialog.description ? 1 : 0),
|
|
1228
|
+
column: 2 + stringWidth(`${textInputDialog.label}: `) + stringWidth(valueBeforeCursor),
|
|
1229
|
+
};
|
|
1230
|
+
}
|
|
1178
1231
|
function buildTodoPanel() {
|
|
1179
1232
|
if (currentTodos.length === 0)
|
|
1180
1233
|
return [];
|
|
@@ -1210,7 +1263,14 @@ export async function runHadamardTui(options = {}) {
|
|
|
1210
1263
|
}
|
|
1211
1264
|
function renderDynamic() {
|
|
1212
1265
|
const lines = [];
|
|
1266
|
+
let promptCursor;
|
|
1213
1267
|
lines.push(...buildStatusLine());
|
|
1268
|
+
if (running && session.pendingInputCount > 0) {
|
|
1269
|
+
lines.push(...buildPendingInputPanel());
|
|
1270
|
+
}
|
|
1271
|
+
if (reasoningDisplay.hasActive) {
|
|
1272
|
+
lines.push(...reasoningDisplay.liveLines(screen.width));
|
|
1273
|
+
}
|
|
1214
1274
|
const tail = flusher.tail();
|
|
1215
1275
|
if (running && tail) {
|
|
1216
1276
|
lines.push(tail);
|
|
@@ -1224,13 +1284,19 @@ export async function runHadamardTui(options = {}) {
|
|
|
1224
1284
|
lines.push(...buildDialog());
|
|
1225
1285
|
}
|
|
1226
1286
|
else if (selectionDialog) {
|
|
1287
|
+
const dialogStartLine = lines.length;
|
|
1227
1288
|
lines.push(...buildSelectionDialog());
|
|
1289
|
+
promptCursor = selectionDialogCursorPosition(dialogStartLine);
|
|
1228
1290
|
}
|
|
1229
1291
|
else if (textInputDialog) {
|
|
1292
|
+
const dialogStartLine = lines.length;
|
|
1230
1293
|
lines.push(...buildTextInputDialog());
|
|
1294
|
+
promptCursor = textInputDialogCursorPosition(dialogStartLine);
|
|
1231
1295
|
}
|
|
1232
1296
|
else {
|
|
1297
|
+
const promptStartLine = lines.length;
|
|
1233
1298
|
lines.push(...buildPromptBar());
|
|
1299
|
+
promptCursor = promptCursorPosition(promptStartLine);
|
|
1234
1300
|
const atMenu = buildAtMenu();
|
|
1235
1301
|
if (atMenu.length > 0) {
|
|
1236
1302
|
lines.push(...atMenu);
|
|
@@ -1240,7 +1306,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
1240
1306
|
lines.push(...(menu.length > 0 ? menu : buildHintLine()));
|
|
1241
1307
|
}
|
|
1242
1308
|
}
|
|
1243
|
-
screen.setDynamic(lines);
|
|
1309
|
+
screen.setDynamic(lines, promptCursor);
|
|
1244
1310
|
}
|
|
1245
1311
|
function scheduleDynamicRender() {
|
|
1246
1312
|
if (dynamicRenderTimer)
|
|
@@ -1259,6 +1325,11 @@ export async function runHadamardTui(options = {}) {
|
|
|
1259
1325
|
function appendStatic(lines) {
|
|
1260
1326
|
screen.appendStatic(lines);
|
|
1261
1327
|
}
|
|
1328
|
+
function collapseReasoning() {
|
|
1329
|
+
const lines = reasoningDisplay.complete();
|
|
1330
|
+
if (lines.length > 0)
|
|
1331
|
+
appendStatic(lines);
|
|
1332
|
+
}
|
|
1262
1333
|
// Inline CLI spinner for long async operations (probe, reload).
|
|
1263
1334
|
// Writes directly to stdout with \r — independent of the redrawable region.
|
|
1264
1335
|
const SPINNER = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
@@ -1419,7 +1490,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
1419
1490
|
if (activeRouter && !bridgeMode) {
|
|
1420
1491
|
try {
|
|
1421
1492
|
const decision = await resolveRoutedRun(activeRouter, text, abortCtrl.signal);
|
|
1422
|
-
routed = { model: decision.model, modelApi: decision.modelApi };
|
|
1493
|
+
routed = { model: decision.model, modelApi: decision.modelApi, effort: decision.effort };
|
|
1423
1494
|
routedModelLabel = `${decision.label} (${decision.model})`;
|
|
1424
1495
|
appendStatic(formatInfoLine(`router → ${routedModelLabel}`));
|
|
1425
1496
|
}
|
|
@@ -1455,7 +1526,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
1455
1526
|
// session → context intact; switching bridge↔hadamard is seamless.
|
|
1456
1527
|
statusNote = `bridge:${activeBridgeConfig?.name ?? 'bridge'}`;
|
|
1457
1528
|
const stream = session.stream(expandImageRefs(text), {
|
|
1458
|
-
systemPrompt:
|
|
1529
|
+
systemPrompt: systemPrompt + buildAgentContext(),
|
|
1459
1530
|
signal: abortCtrl.signal,
|
|
1460
1531
|
permissionMode: currentPermissionMode(),
|
|
1461
1532
|
effort: currentEffort(),
|
|
@@ -1470,14 +1541,18 @@ export async function runHadamardTui(options = {}) {
|
|
|
1470
1541
|
resultPromise = stream.result;
|
|
1471
1542
|
}
|
|
1472
1543
|
else {
|
|
1544
|
+
const selectedConfigModel = resolveHadamardConfigurationModel(activeBridgeConfig, bridgeMode, bridgeModelLabel);
|
|
1473
1545
|
const stream = session.stream(expandImageRefs(text), {
|
|
1474
|
-
systemPrompt:
|
|
1546
|
+
systemPrompt: systemPrompt + buildAgentContext(),
|
|
1475
1547
|
signal: abortCtrl.signal,
|
|
1476
1548
|
permissionMode: currentPermissionMode(),
|
|
1477
|
-
effort
|
|
1549
|
+
// A matched route's effort overrides the session effort for this turn.
|
|
1550
|
+
effort: routed?.effort ?? currentEffort(),
|
|
1478
1551
|
approver,
|
|
1479
1552
|
classifier: preToolUseHookClassifier,
|
|
1480
|
-
...(routed
|
|
1553
|
+
...(routed
|
|
1554
|
+
? { model: routed.model, modelApi: routed.modelApi }
|
|
1555
|
+
: selectedConfigModel ? { model: selectedConfigModel } : {}),
|
|
1481
1556
|
...(activeTeamTool && teamPrefs.autoInvoke ? { tools: [...tools, activeTeamTool] } : {}),
|
|
1482
1557
|
...(canUseTool ? { canUseTool } : {}),
|
|
1483
1558
|
});
|
|
@@ -1491,6 +1566,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
1491
1566
|
}
|
|
1492
1567
|
}
|
|
1493
1568
|
const result = await resultPromise;
|
|
1569
|
+
collapseReasoning();
|
|
1494
1570
|
// Accumulate token + USD usage for /cost and /usage. The model is the
|
|
1495
1571
|
// routed model (if a router is active) or the session model. Bridge runs
|
|
1496
1572
|
recordUsage(routed?.model ?? activeBridgeModelApi?.model ?? bridgeModelLabel ?? session.model, result.usage);
|
|
@@ -1521,6 +1597,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
1521
1597
|
appendStatic(['']);
|
|
1522
1598
|
}
|
|
1523
1599
|
catch (error) {
|
|
1600
|
+
collapseReasoning();
|
|
1524
1601
|
const rest = flusher.drain();
|
|
1525
1602
|
if (rest.length > 0)
|
|
1526
1603
|
appendStatic(rest);
|
|
@@ -1552,7 +1629,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
1552
1629
|
switch (event.type) {
|
|
1553
1630
|
case 'run.started':
|
|
1554
1631
|
streamedTextSeen = false;
|
|
1555
|
-
|
|
1632
|
+
reasoningDisplay.reset();
|
|
1556
1633
|
return;
|
|
1557
1634
|
case 'request.started':
|
|
1558
1635
|
lastTokenEstimate = typeof data.requestTokenEstimate === 'number'
|
|
@@ -1564,6 +1641,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
1564
1641
|
const delta = typeof data.delta === 'string' ? data.delta : '';
|
|
1565
1642
|
if (!delta)
|
|
1566
1643
|
return;
|
|
1644
|
+
collapseReasoning();
|
|
1567
1645
|
streamedTextSeen = true;
|
|
1568
1646
|
const flushed = flusher.push(delta);
|
|
1569
1647
|
if (flushed.length > 0)
|
|
@@ -1575,10 +1653,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
1575
1653
|
const delta = typeof data.delta === 'string' ? data.delta : '';
|
|
1576
1654
|
if (!delta)
|
|
1577
1655
|
return;
|
|
1578
|
-
|
|
1579
|
-
if (lines.length > 0)
|
|
1580
|
-
appendStatic(lines);
|
|
1581
|
-
streamedThinkingSeen = true;
|
|
1656
|
+
reasoningDisplay.append(delta);
|
|
1582
1657
|
scheduleDynamicRender();
|
|
1583
1658
|
return;
|
|
1584
1659
|
}
|
|
@@ -1594,15 +1669,15 @@ export async function runHadamardTui(options = {}) {
|
|
|
1594
1669
|
}
|
|
1595
1670
|
case 'model.content': {
|
|
1596
1671
|
const content = isRecord(data.content) ? data.content : undefined;
|
|
1597
|
-
if (data.kind === 'content' && content?.type === 'thinking' && !
|
|
1672
|
+
if (data.kind === 'content' && content?.type === 'thinking' && !reasoningDisplay.hasStreamedContent) {
|
|
1598
1673
|
const thinking = typeof content.thinking === 'string' ? content.thinking : '';
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
appendStatic(lines);
|
|
1674
|
+
reasoningDisplay.setCompleteContent(thinking);
|
|
1675
|
+
scheduleDynamicRender();
|
|
1602
1676
|
}
|
|
1603
1677
|
return;
|
|
1604
1678
|
}
|
|
1605
1679
|
case 'tool.started': {
|
|
1680
|
+
collapseReasoning();
|
|
1606
1681
|
const callId = typeof data.callId === 'string' ? data.callId : '';
|
|
1607
1682
|
const publicName = typeof data.publicName === 'string'
|
|
1608
1683
|
? data.publicName
|
|
@@ -1739,35 +1814,37 @@ export async function runHadamardTui(options = {}) {
|
|
|
1739
1814
|
await resumeSession(selected);
|
|
1740
1815
|
}
|
|
1741
1816
|
async function chooseModel() {
|
|
1817
|
+
const catalog = buildModelConfigurationCatalog({
|
|
1818
|
+
model: sdk.config.model,
|
|
1819
|
+
provider: sdk.config.provider,
|
|
1820
|
+
baseURL: sdk.config.baseURL,
|
|
1821
|
+
}, readBridgeConfigs().configs);
|
|
1742
1822
|
const items = [
|
|
1743
|
-
{
|
|
1744
|
-
id:
|
|
1745
|
-
label: '
|
|
1746
|
-
description:
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
.
|
|
1751
|
-
id: `tier:${tier}`,
|
|
1752
|
-
label: tier,
|
|
1753
|
-
description: sdk.config.modelTiers[tier],
|
|
1823
|
+
...catalog.map(config => ({
|
|
1824
|
+
id: config.id,
|
|
1825
|
+
label: config.source === 'default' ? 'default' : config.name,
|
|
1826
|
+
description: [
|
|
1827
|
+
config.execution === 'cli' ? `${config.runtime} CLI` : config.runtime,
|
|
1828
|
+
config.model || 'runtime default',
|
|
1829
|
+
config.models.length > 1 ? `${config.models.length} models` : '',
|
|
1830
|
+
].filter(Boolean).join(' · '),
|
|
1754
1831
|
})),
|
|
1755
1832
|
{
|
|
1756
1833
|
id: 'custom',
|
|
1757
1834
|
label: 'Enter a model ID',
|
|
1758
|
-
description: '
|
|
1835
|
+
description: 'Use the default provider for this session',
|
|
1759
1836
|
},
|
|
1760
1837
|
{
|
|
1761
1838
|
id: 'configure',
|
|
1762
|
-
label: '
|
|
1763
|
-
description: '
|
|
1839
|
+
label: 'Manage configurations',
|
|
1840
|
+
description: 'Default plus named provider configurations',
|
|
1764
1841
|
},
|
|
1765
1842
|
];
|
|
1766
1843
|
const selected = await selectItem({
|
|
1767
1844
|
title: 'Select model',
|
|
1768
1845
|
subtitle: `Current: ${session.model}`,
|
|
1769
1846
|
items,
|
|
1770
|
-
searchable:
|
|
1847
|
+
searchable: true,
|
|
1771
1848
|
});
|
|
1772
1849
|
if (!selected)
|
|
1773
1850
|
return;
|
|
@@ -1783,15 +1860,38 @@ export async function runHadamardTui(options = {}) {
|
|
|
1783
1860
|
});
|
|
1784
1861
|
if (!model?.trim())
|
|
1785
1862
|
return;
|
|
1863
|
+
await disableBridge();
|
|
1786
1864
|
await session.setModel(model.trim());
|
|
1787
1865
|
}
|
|
1788
|
-
else if (selected === 'default') {
|
|
1789
|
-
await session.setModel(sdk.config.model);
|
|
1790
|
-
}
|
|
1791
1866
|
else {
|
|
1792
|
-
|
|
1867
|
+
const config = findModelConfiguration(catalog, selected);
|
|
1868
|
+
if (!config)
|
|
1869
|
+
return;
|
|
1870
|
+
if (config.source === 'default') {
|
|
1871
|
+
await disableBridge();
|
|
1872
|
+
await session.setModel(sdk.config.model);
|
|
1873
|
+
}
|
|
1874
|
+
else if (config.config) {
|
|
1875
|
+
let selectedConfig = { ...config.config, model: config.model };
|
|
1876
|
+
if (config.models.length > 1) {
|
|
1877
|
+
const model = await selectItem({
|
|
1878
|
+
title: config.name,
|
|
1879
|
+
subtitle: 'Select a model from this configuration',
|
|
1880
|
+
searchable: true,
|
|
1881
|
+
items: config.models.map(item => ({
|
|
1882
|
+
id: item.name,
|
|
1883
|
+
label: item.name,
|
|
1884
|
+
description: item.modality ?? 'text',
|
|
1885
|
+
})),
|
|
1886
|
+
});
|
|
1887
|
+
if (!model)
|
|
1888
|
+
return;
|
|
1889
|
+
selectedConfig = { ...selectedConfig, model };
|
|
1890
|
+
}
|
|
1891
|
+
await activateBridgeConfig(selectedConfig);
|
|
1892
|
+
}
|
|
1793
1893
|
}
|
|
1794
|
-
appendStatic([...formatInfoLine(`model
|
|
1894
|
+
appendStatic([...formatInfoLine(`model configuration: ${activeBridgeConfig?.name ?? 'default'} · ${bridgeModelLabel ?? session.model}`), '']);
|
|
1795
1895
|
}
|
|
1796
1896
|
async function configureModelSettings() {
|
|
1797
1897
|
const store = await resolveHadamardSettingsStore({ configPath: options.configPath });
|
|
@@ -1830,11 +1930,16 @@ export async function runHadamardTui(options = {}) {
|
|
|
1830
1930
|
label: 'Base URL',
|
|
1831
1931
|
description: env.HADAMARD_BASE_URL || 'provider default',
|
|
1832
1932
|
},
|
|
1833
|
-
|
|
1834
|
-
id:
|
|
1835
|
-
label:
|
|
1836
|
-
description: env
|
|
1837
|
-
}
|
|
1933
|
+
{
|
|
1934
|
+
id: 'model',
|
|
1935
|
+
label: 'Default model',
|
|
1936
|
+
description: env.HADAMARD_MODEL || sdk.config.model || 'not configured',
|
|
1937
|
+
},
|
|
1938
|
+
{
|
|
1939
|
+
id: 'named',
|
|
1940
|
+
label: 'Named configurations',
|
|
1941
|
+
description: `${readBridgeConfigs().configs.length} configured`,
|
|
1942
|
+
},
|
|
1838
1943
|
{
|
|
1839
1944
|
id: 'save',
|
|
1840
1945
|
label: 'Save and apply',
|
|
@@ -1904,21 +2009,23 @@ export async function runHadamardTui(options = {}) {
|
|
|
1904
2009
|
}
|
|
1905
2010
|
continue;
|
|
1906
2011
|
}
|
|
1907
|
-
if (selected
|
|
1908
|
-
const tier = selected.slice('tier:'.length).toUpperCase();
|
|
1909
|
-
const key = `HADAMARD_DEFAULT_${tier}_MODEL`;
|
|
2012
|
+
if (selected === 'model') {
|
|
1910
2013
|
const model = await promptText({
|
|
1911
|
-
title:
|
|
2014
|
+
title: 'Configure default model',
|
|
1912
2015
|
label: 'Model ID',
|
|
1913
|
-
initial: env
|
|
2016
|
+
initial: env.HADAMARD_MODEL ?? sdk.config.model,
|
|
1914
2017
|
});
|
|
1915
2018
|
if (model !== undefined) {
|
|
1916
2019
|
if (model.trim())
|
|
1917
|
-
env
|
|
2020
|
+
env.HADAMARD_MODEL = model.trim();
|
|
1918
2021
|
else
|
|
1919
|
-
delete env
|
|
2022
|
+
delete env.HADAMARD_MODEL;
|
|
1920
2023
|
dirty = true;
|
|
1921
2024
|
}
|
|
2025
|
+
continue;
|
|
2026
|
+
}
|
|
2027
|
+
if (selected === 'named') {
|
|
2028
|
+
await manageBridgeConfigs();
|
|
1922
2029
|
}
|
|
1923
2030
|
}
|
|
1924
2031
|
}
|
|
@@ -2986,23 +3093,14 @@ export async function runHadamardTui(options = {}) {
|
|
|
2986
3093
|
});
|
|
2987
3094
|
appendStatic([...formatInfoLine(`effort set to: ${currentEffort() ?? 'auto'}`), '']);
|
|
2988
3095
|
}
|
|
2989
|
-
// ── /goal:
|
|
3096
|
+
// ── /goal: project-scoped goal managed by the shared GoalService ─────
|
|
2990
3097
|
// The service is the single authority over goal lifecycle (see plan/13
|
|
2991
3098
|
// P0.2); the TUI only reads and steers it (create/clear/pause/resume).
|
|
2992
3099
|
// Complete/blocked are runtime-only transitions, set via the Goal tools.
|
|
2993
|
-
function goalService() {
|
|
2994
|
-
return GoalService.forSession(session);
|
|
2995
|
-
}
|
|
2996
|
-
async function setGoal(objective) {
|
|
2997
|
-
await goalService().create({ objective });
|
|
2998
|
-
}
|
|
2999
|
-
async function clearGoal() {
|
|
3000
|
-
await goalService().clear();
|
|
3001
|
-
}
|
|
3002
3100
|
function goalContextLine() {
|
|
3003
3101
|
// Normalize through the shared Goal schema while keeping status rendering
|
|
3004
3102
|
// synchronous over the already-cached Session metadata.
|
|
3005
|
-
const goal =
|
|
3103
|
+
const goal = sdk.goals.peek(session.id);
|
|
3006
3104
|
if (!goal)
|
|
3007
3105
|
return '';
|
|
3008
3106
|
const marks = {
|
|
@@ -3014,28 +3112,6 @@ export async function runHadamardTui(options = {}) {
|
|
|
3014
3112
|
const mark = marks[goal.status ?? 'active'] ?? '';
|
|
3015
3113
|
return ` · goal:${mark}${A.dim}${truncateToWidth(goal.objective, 30)}${A.reset}`;
|
|
3016
3114
|
}
|
|
3017
|
-
async function chooseOutputStyle(arg) {
|
|
3018
|
-
const valid = OUTPUT_STYLES.map(s => s.id);
|
|
3019
|
-
if (arg) {
|
|
3020
|
-
if (!valid.includes(arg)) {
|
|
3021
|
-
appendStatic([...formatErrorLine(`unknown output style: ${arg}. Valid: ${valid.join(', ')}`), '']);
|
|
3022
|
-
return;
|
|
3023
|
-
}
|
|
3024
|
-
outputStyle = arg;
|
|
3025
|
-
appendStatic([...formatInfoLine(`output style → ${outputStyle}`), '']);
|
|
3026
|
-
return;
|
|
3027
|
-
}
|
|
3028
|
-
const selected = await selectItem({
|
|
3029
|
-
title: 'Select output style',
|
|
3030
|
-
subtitle: `Current: ${outputStyle}`,
|
|
3031
|
-
searchable: false,
|
|
3032
|
-
items: OUTPUT_STYLES.map(s => ({ id: s.id, label: s.label, description: s.description })),
|
|
3033
|
-
});
|
|
3034
|
-
if (selected) {
|
|
3035
|
-
outputStyle = selected;
|
|
3036
|
-
appendStatic([...formatInfoLine(`output style → ${outputStyle}`), '']);
|
|
3037
|
-
}
|
|
3038
|
-
}
|
|
3039
3115
|
async function showSkills() {
|
|
3040
3116
|
const skills = sdk.skills.listMetadata();
|
|
3041
3117
|
if (skills.length === 0) {
|
|
@@ -3441,6 +3517,10 @@ export async function runHadamardTui(options = {}) {
|
|
|
3441
3517
|
const spaceIndex = raw.indexOf(' ');
|
|
3442
3518
|
const name = (spaceIndex === -1 ? raw.slice(1) : raw.slice(1, spaceIndex)).toLowerCase();
|
|
3443
3519
|
const args = spaceIndex === -1 ? '' : raw.slice(spaceIndex + 1).trim();
|
|
3520
|
+
if (!canRunInteractiveCommand(name, running)) {
|
|
3521
|
+
appendStatic(formatInfoLine(`/${name} requires an idle session; it will be available after this run`));
|
|
3522
|
+
return;
|
|
3523
|
+
}
|
|
3444
3524
|
appendStatic(formatUserPrompt(raw));
|
|
3445
3525
|
commandBusy = true;
|
|
3446
3526
|
renderDynamic();
|
|
@@ -3467,6 +3547,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
3467
3547
|
}
|
|
3468
3548
|
case 'clear':
|
|
3469
3549
|
process.stdout.write('\x1b[2J\x1b[H');
|
|
3550
|
+
screen.setDynamic([]);
|
|
3470
3551
|
renderDynamic();
|
|
3471
3552
|
return;
|
|
3472
3553
|
case 'init': {
|
|
@@ -3493,8 +3574,71 @@ export async function runHadamardTui(options = {}) {
|
|
|
3493
3574
|
await chooseRouter(args.slice('router'.length).trim());
|
|
3494
3575
|
return;
|
|
3495
3576
|
}
|
|
3496
|
-
|
|
3497
|
-
|
|
3577
|
+
if (args === 'custom' || args.startsWith('custom ')) {
|
|
3578
|
+
const customModel = args.slice('custom'.length).trim();
|
|
3579
|
+
if (!customModel) {
|
|
3580
|
+
appendStatic([...formatErrorLine('usage: /model custom <model-id>'), '']);
|
|
3581
|
+
return;
|
|
3582
|
+
}
|
|
3583
|
+
await disableBridge();
|
|
3584
|
+
await session.setModel(customModel);
|
|
3585
|
+
appendStatic([...formatInfoLine(`custom model: ${session.model}`), '']);
|
|
3586
|
+
return;
|
|
3587
|
+
}
|
|
3588
|
+
const catalog = buildModelConfigurationCatalog({ model: sdk.config.model, provider: sdk.config.provider, baseURL: sdk.config.baseURL }, readBridgeConfigs().configs);
|
|
3589
|
+
// `/model <config>` or `/model <config> <model-id>` — match the longest
|
|
3590
|
+
// known configuration name so model ids with spaces still work.
|
|
3591
|
+
let config = findModelConfiguration(catalog, args);
|
|
3592
|
+
let explicitModel;
|
|
3593
|
+
if (!config) {
|
|
3594
|
+
const tokens = args.split(/\s+/u).filter(Boolean);
|
|
3595
|
+
for (let i = tokens.length - 1; i >= 1; i -= 1) {
|
|
3596
|
+
const candidate = tokens.slice(0, i).join(' ');
|
|
3597
|
+
const match = findModelConfiguration(catalog, candidate);
|
|
3598
|
+
if (match) {
|
|
3599
|
+
config = match;
|
|
3600
|
+
explicitModel = tokens.slice(i).join(' ');
|
|
3601
|
+
break;
|
|
3602
|
+
}
|
|
3603
|
+
}
|
|
3604
|
+
}
|
|
3605
|
+
if (!config) {
|
|
3606
|
+
appendStatic([
|
|
3607
|
+
...formatErrorLine(`unknown model configuration: ${args}`),
|
|
3608
|
+
...formatInfoLine('Use /model to choose one, or /model custom <model-id>.'),
|
|
3609
|
+
'',
|
|
3610
|
+
]);
|
|
3611
|
+
return;
|
|
3612
|
+
}
|
|
3613
|
+
if (config.source === 'default') {
|
|
3614
|
+
await disableBridge();
|
|
3615
|
+
await session.setModel(explicitModel || sdk.config.model);
|
|
3616
|
+
appendStatic([...formatInfoLine(`model configuration: default · ${session.model}`), '']);
|
|
3617
|
+
return;
|
|
3618
|
+
}
|
|
3619
|
+
if (!config.config)
|
|
3620
|
+
return;
|
|
3621
|
+
let selectedConfig = { ...config.config, model: config.model };
|
|
3622
|
+
if (explicitModel) {
|
|
3623
|
+
selectedConfig = { ...selectedConfig, model: explicitModel };
|
|
3624
|
+
}
|
|
3625
|
+
else if (config.models.length > 1) {
|
|
3626
|
+
const model = await selectItem({
|
|
3627
|
+
title: config.name,
|
|
3628
|
+
subtitle: 'Select a model from this configuration',
|
|
3629
|
+
searchable: true,
|
|
3630
|
+
items: config.models.map(item => ({
|
|
3631
|
+
id: item.name,
|
|
3632
|
+
label: item.name,
|
|
3633
|
+
description: item.modality ?? 'text',
|
|
3634
|
+
})),
|
|
3635
|
+
});
|
|
3636
|
+
if (!model)
|
|
3637
|
+
return;
|
|
3638
|
+
selectedConfig = { ...selectedConfig, model };
|
|
3639
|
+
}
|
|
3640
|
+
await activateBridgeConfig(selectedConfig);
|
|
3641
|
+
appendStatic([...formatInfoLine(`model configuration: ${activeBridgeConfig?.name ?? config.name} · ${bridgeModelLabel ?? session.model}`), '']);
|
|
3498
3642
|
return;
|
|
3499
3643
|
}
|
|
3500
3644
|
case 'effort':
|
|
@@ -3503,9 +3647,6 @@ export async function runHadamardTui(options = {}) {
|
|
|
3503
3647
|
else
|
|
3504
3648
|
await setEffort(args.toLowerCase());
|
|
3505
3649
|
return;
|
|
3506
|
-
case 'output-style':
|
|
3507
|
-
await chooseOutputStyle(args.toLowerCase());
|
|
3508
|
-
return;
|
|
3509
3650
|
case 'permissions': {
|
|
3510
3651
|
// Three presets, selectable or named directly:
|
|
3511
3652
|
// read-only → deny mutating tools (read / search / web only)
|
|
@@ -3761,27 +3902,27 @@ export async function runHadamardTui(options = {}) {
|
|
|
3761
3902
|
]);
|
|
3762
3903
|
return;
|
|
3763
3904
|
case 'memory': {
|
|
3764
|
-
if (/^(proposals|apply|reject)\b/u.test(args)) {
|
|
3765
|
-
try {
|
|
3766
|
-
const { MemoryProposalCommandService } = await import('../memory/memoryProposalCommandService.js');
|
|
3767
|
-
const result = await new MemoryProposalCommandService(sdk.config.homeDir, sdk.config.workDir).execute(args);
|
|
3768
|
-
appendStatic([
|
|
3769
|
-
...formatInfoLine(result.message),
|
|
3770
|
-
...(result.items ?? []).map(item => ` ${A.bold}${item.label}${A.reset}${item.description ? ` ${A.dim}· ${item.description}${A.reset}` : ''}`),
|
|
3771
|
-
'',
|
|
3772
|
-
]);
|
|
3773
|
-
}
|
|
3774
|
-
catch (error) {
|
|
3775
|
-
appendStatic([...formatErrorLine(error instanceof Error ? error.message : String(error)), '']);
|
|
3776
|
-
}
|
|
3777
|
-
return;
|
|
3778
|
-
}
|
|
3779
3905
|
try {
|
|
3780
|
-
const
|
|
3781
|
-
|
|
3906
|
+
const { HadamardMemoryCommandService } = await import('../memory/memoryCommandService.js');
|
|
3907
|
+
const result = await new HadamardMemoryCommandService({
|
|
3908
|
+
memory: sdk.memory,
|
|
3909
|
+
proposals: sdk.memoryProposals,
|
|
3910
|
+
compactConfig: sdk.config.compact,
|
|
3911
|
+
getState: () => session.compactState(),
|
|
3912
|
+
}).execute(args || 'status');
|
|
3913
|
+
appendStatic([
|
|
3914
|
+
`${A.bold}${result.title}${A.reset}`,
|
|
3915
|
+
...formatInfoLine(result.message),
|
|
3916
|
+
...(result.text ? result.text.split('\n').map(line => `${A.dim}${line}${A.reset}`) : []),
|
|
3917
|
+
...(result.items ?? []).flatMap(item => [
|
|
3918
|
+
` ${A.bold}${item.label}${A.reset}${item.description ? ` ${A.dim}· ${item.description}${A.reset}` : ''}`,
|
|
3919
|
+
...(item.detail ? [` ${A.dim}${item.detail}${A.reset}`] : []),
|
|
3920
|
+
]),
|
|
3921
|
+
'',
|
|
3922
|
+
]);
|
|
3782
3923
|
}
|
|
3783
3924
|
catch (error) {
|
|
3784
|
-
appendStatic([...formatErrorLine(error.message), '']);
|
|
3925
|
+
appendStatic([...formatErrorLine(error instanceof Error ? error.message : String(error)), '']);
|
|
3785
3926
|
}
|
|
3786
3927
|
return;
|
|
3787
3928
|
}
|
|
@@ -3789,7 +3930,9 @@ export async function runHadamardTui(options = {}) {
|
|
|
3789
3930
|
// Break down what is consuming the context window (gap #9 vs
|
|
3790
3931
|
// claude-code's /context) — usage, messages, system prompt, tools,
|
|
3791
3932
|
// the loaded CLAUDE.md sources, and the active config.
|
|
3792
|
-
const
|
|
3933
|
+
const { resolveHadamardCompactBudget } = await import('../runtime/hadamardCompact.js');
|
|
3934
|
+
const compactBudget = resolveHadamardCompactBudget(sdk.config.compact);
|
|
3935
|
+
const window = compactBudget.effectiveContextWindowTokens;
|
|
3793
3936
|
const used = lastTokenEstimate ?? 0;
|
|
3794
3937
|
const pct = window > 0 ? Math.min(100, Math.round((used / window) * 100)) : 0;
|
|
3795
3938
|
const usedK = used >= 1000 ? `${(used / 1000).toFixed(1)}k` : `${used}`;
|
|
@@ -3805,6 +3948,8 @@ export async function runHadamardTui(options = {}) {
|
|
|
3805
3948
|
appendStatic([
|
|
3806
3949
|
`${A.bold}Context window${A.reset}`,
|
|
3807
3950
|
` ${ctxColor}${pct}% used (${usedK} / ${windowK} tokens)${A.reset}`,
|
|
3951
|
+
` ${A.dim}raw window${A.reset} ${compactBudget.rawContextWindowTokens}`,
|
|
3952
|
+
` ${A.dim}compact limit${A.reset} ${compactBudget.autoCompactTokenLimit} (${compactBudget.source})`,
|
|
3808
3953
|
` ${A.dim}messages${A.reset} ${messages}`,
|
|
3809
3954
|
` ${A.dim}system prompt${A.reset} ~${sysChars} chars`,
|
|
3810
3955
|
` ${A.dim}tools${A.reset} ${toolMetadata.length}${mcpCount > 0 ? ` (${mcpCount} MCP)` : ''}`,
|
|
@@ -3911,43 +4056,8 @@ export async function runHadamardTui(options = {}) {
|
|
|
3911
4056
|
return;
|
|
3912
4057
|
}
|
|
3913
4058
|
case 'goal': {
|
|
3914
|
-
const
|
|
3915
|
-
|
|
3916
|
-
if (!arg) {
|
|
3917
|
-
const g = await svc.read();
|
|
3918
|
-
if (!g) {
|
|
3919
|
-
appendStatic([...formatInfoLine('no goal set — use /goal <objective> to set one'), '']);
|
|
3920
|
-
}
|
|
3921
|
-
else {
|
|
3922
|
-
const marks = { active: `${A.green}▶ active${A.reset}`, paused: `${A.yellow}‖ paused${A.reset}`, complete: `${A.dim}✓ complete${A.reset}`, blocked: `${A.red}⊘ blocked${A.reset}` };
|
|
3923
|
-
appendStatic([`${A.bold}Goal${A.reset} ${marks[g.status] ?? ''} ${A.dim}${g.createdAt.slice(0, 10)}${A.reset}`, ` ${g.objective}`, '']);
|
|
3924
|
-
}
|
|
3925
|
-
return;
|
|
3926
|
-
}
|
|
3927
|
-
if (arg === 'clear') {
|
|
3928
|
-
await clearGoal();
|
|
3929
|
-
appendStatic([...formatInfoLine('goal cleared'), '']);
|
|
3930
|
-
return;
|
|
3931
|
-
}
|
|
3932
|
-
if (arg === 'pause') {
|
|
3933
|
-
const r = await svc.transition('paused');
|
|
3934
|
-
appendStatic(r.ok ? [...formatInfoLine('goal paused'), ''] : [...formatInfoLine(r.message), '']);
|
|
3935
|
-
return;
|
|
3936
|
-
}
|
|
3937
|
-
if (arg === 'resume') {
|
|
3938
|
-
const r = await svc.transition('active');
|
|
3939
|
-
appendStatic(r.ok ? [...formatInfoLine('goal resumed'), ''] : [...formatInfoLine(r.message), '']);
|
|
3940
|
-
return;
|
|
3941
|
-
}
|
|
3942
|
-
if (arg === 'complete' || arg === 'done') {
|
|
3943
|
-
// Complete is a runtime-only transition requiring evidence; the UI
|
|
3944
|
-
// cannot mark a goal complete without evidence. Steer the user to
|
|
3945
|
-
// let the agent complete it via UpdateGoal, or clear it instead.
|
|
3946
|
-
appendStatic([...formatInfoLine('goal completion requires runtime evidence — ask the agent to call UpdateGoal with status "complete", or use /goal clear'), '']);
|
|
3947
|
-
return;
|
|
3948
|
-
}
|
|
3949
|
-
await setGoal(arg);
|
|
3950
|
-
appendStatic([...formatInfoLine(`goal set — ${arg}`), '']);
|
|
4059
|
+
const commandResult = await sdk.goals.command(session, args);
|
|
4060
|
+
appendStatic([...formatInfoLine(commandResult.message), '']);
|
|
3951
4061
|
return;
|
|
3952
4062
|
}
|
|
3953
4063
|
case 'review': {
|
|
@@ -3974,7 +4084,6 @@ export async function runHadamardTui(options = {}) {
|
|
|
3974
4084
|
` ${A.dim}tokens${A.reset} ${fmtTok(totalInputTokens)} in · ${fmtTok(totalOutputTokens)} out`,
|
|
3975
4085
|
` ${A.dim}tools${A.reset} ${toolMetadata.length}${toolMetadata.filter(t => t.provider === 'mcp').length ? ` (${toolMetadata.filter(t => t.provider === 'mcp').length} MCP)` : ''}`,
|
|
3976
4086
|
` ${A.dim}model${A.reset} ${session.model}${bridgeMode && activeBridgeConfig ? ` · bridge:${activeBridgeConfig.name}` : ''}`,
|
|
3977
|
-
` ${A.dim}output style${A.reset} ${outputStyle}`,
|
|
3978
4087
|
` ${A.dim}plan mode${A.reset} ${session.permissionContext.mode === 'plan' ? 'on' : 'off'}`,
|
|
3979
4088
|
'',
|
|
3980
4089
|
]);
|
|
@@ -4304,8 +4413,40 @@ export async function runHadamardTui(options = {}) {
|
|
|
4304
4413
|
await runSavedWorkflow(runSpace === -1 ? runRest : runRest.slice(0, runSpace), runSpace === -1 ? undefined : runRest.slice(runSpace + 1).trim());
|
|
4305
4414
|
return;
|
|
4306
4415
|
}
|
|
4416
|
+
if (args.startsWith('delete ')) {
|
|
4417
|
+
const name = args.slice(7).trim();
|
|
4418
|
+
if (!name) {
|
|
4419
|
+
appendStatic([...formatErrorLine('usage: /workflows delete <name>'), '']);
|
|
4420
|
+
return;
|
|
4421
|
+
}
|
|
4422
|
+
const removed = await deleteWorkflow(name, sdk.config.workDir);
|
|
4423
|
+
appendStatic([...formatInfoLine(removed ? `deleted workflow: ${name}` : `workflow not found: ${name}`), '']);
|
|
4424
|
+
return;
|
|
4425
|
+
}
|
|
4426
|
+
if (args.startsWith('save ')) {
|
|
4427
|
+
const rest = args.slice(5).trim();
|
|
4428
|
+
const split = rest.indexOf(' ');
|
|
4429
|
+
if (split === -1) {
|
|
4430
|
+
appendStatic([...formatErrorLine('usage: /workflows save <name> <script-path> [--overwrite]'), '']);
|
|
4431
|
+
return;
|
|
4432
|
+
}
|
|
4433
|
+
const name = rest.slice(0, split).trim();
|
|
4434
|
+
const pathParts = rest.slice(split + 1).trim().split(/\s+/);
|
|
4435
|
+
const overwrite = pathParts.includes('--overwrite');
|
|
4436
|
+
const scriptPath = pathParts.filter((part) => part !== '--overwrite').join(' ');
|
|
4437
|
+
try {
|
|
4438
|
+
const resolved = path.isAbsolute(scriptPath) ? scriptPath : path.resolve(sdk.config.workDir, scriptPath);
|
|
4439
|
+
const script = fs.readFileSync(resolved, 'utf8');
|
|
4440
|
+
const filePath = await saveWorkflow(name, script, { projectDir: sdk.config.workDir, overwrite });
|
|
4441
|
+
appendStatic([...formatInfoLine(`saved workflow: ${name} -> ${filePath}`), '']);
|
|
4442
|
+
}
|
|
4443
|
+
catch (error) {
|
|
4444
|
+
appendStatic([...formatErrorLine(error.message || String(error)), '']);
|
|
4445
|
+
}
|
|
4446
|
+
return;
|
|
4447
|
+
}
|
|
4307
4448
|
if (args && args !== 'list') {
|
|
4308
|
-
appendStatic([...formatErrorLine('usage: /workflows [list|run <name> [task]]'), '']);
|
|
4449
|
+
appendStatic([...formatErrorLine('usage: /workflows [list|run <name> [task]|save <name> <script-path>|delete <name>]'), '']);
|
|
4309
4450
|
return;
|
|
4310
4451
|
}
|
|
4311
4452
|
// No sub-command → selection picker.
|
|
@@ -4525,15 +4666,36 @@ export async function runHadamardTui(options = {}) {
|
|
|
4525
4666
|
}
|
|
4526
4667
|
return;
|
|
4527
4668
|
}
|
|
4669
|
+
if (args.startsWith('delete ')) {
|
|
4670
|
+
const teamName = args.slice(7).trim();
|
|
4671
|
+
if (!teamName) {
|
|
4672
|
+
appendStatic([...formatErrorLine('usage: /team delete <name>'), '']);
|
|
4673
|
+
return;
|
|
4674
|
+
}
|
|
4675
|
+
if (getBuiltInTeamDefinition(teamName)) {
|
|
4676
|
+
appendStatic([...formatErrorLine(`cannot delete built-in team: ${teamName}`), '']);
|
|
4677
|
+
return;
|
|
4678
|
+
}
|
|
4679
|
+
const removed = await deleteTeamDefinition(teamName, sdk.config.workDir);
|
|
4680
|
+
if (!removed) {
|
|
4681
|
+
appendStatic([...formatErrorLine(`team not found: ${teamName}`), '']);
|
|
4682
|
+
return;
|
|
4683
|
+
}
|
|
4684
|
+
if (activeTeamName === teamName) {
|
|
4685
|
+
activeTeamTool = null;
|
|
4686
|
+
activeTeamName = null;
|
|
4687
|
+
}
|
|
4688
|
+
appendStatic([...formatInfoLine(`deleted team: ${teamName}`), '']);
|
|
4689
|
+
return;
|
|
4690
|
+
}
|
|
4528
4691
|
if (args.startsWith('ask ')) {
|
|
4529
4692
|
const rest = args.slice(4).trim();
|
|
4530
|
-
const
|
|
4531
|
-
if (
|
|
4693
|
+
const parsed = parseTeamAskArguments(rest);
|
|
4694
|
+
if (!parsed) {
|
|
4532
4695
|
appendStatic([...formatErrorLine('usage: /team ask <name> <prompt>'), '']);
|
|
4533
4696
|
return;
|
|
4534
4697
|
}
|
|
4535
|
-
const teamName =
|
|
4536
|
-
const prompt = rest.slice(spaceIdx + 1).trim();
|
|
4698
|
+
const { name: teamName, prompt } = parsed;
|
|
4537
4699
|
const loaded = loadTeamDefinition(teamName, sdk.config.workDir);
|
|
4538
4700
|
if (!loaded) {
|
|
4539
4701
|
appendStatic([...formatErrorLine(`team not found: ${teamName}`), '']);
|
|
@@ -4559,7 +4721,6 @@ export async function runHadamardTui(options = {}) {
|
|
|
4559
4721
|
'',
|
|
4560
4722
|
]);
|
|
4561
4723
|
try {
|
|
4562
|
-
const team = createModelTeam(definition);
|
|
4563
4724
|
const teamRunView = createTeamRunViewState(definition.name);
|
|
4564
4725
|
const printTeamRunTree = () => {
|
|
4565
4726
|
const lines = formatTeamRunTreeLines(teamRunView);
|
|
@@ -4567,7 +4728,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
4567
4728
|
return;
|
|
4568
4729
|
appendStatic([...lines.map((line) => `${A.dim}${line}${A.reset}`), '']);
|
|
4569
4730
|
};
|
|
4570
|
-
const result = await
|
|
4731
|
+
const result = await askTeamDefinition(definition, prompt, undefined, {
|
|
4571
4732
|
workDir: sdk.config.workDir,
|
|
4572
4733
|
onEvent: (e) => {
|
|
4573
4734
|
applyTeamRunEvent(teamRunView, e);
|
|
@@ -5235,17 +5396,31 @@ export async function runHadamardTui(options = {}) {
|
|
|
5235
5396
|
}
|
|
5236
5397
|
}
|
|
5237
5398
|
// ── Submit / key handling ──────────────────────────────────────────
|
|
5238
|
-
|
|
5239
|
-
|
|
5399
|
+
/** If the editor was emptied after ↑-recall, put the follow-up back in queue. */
|
|
5400
|
+
function restoreRecalledFollowUpIfAbandoned() {
|
|
5401
|
+
if (!recalledFollowUp || !editor.isEmpty())
|
|
5402
|
+
return;
|
|
5403
|
+
restoreAbandonedFollowUp(session, recalledFollowUp);
|
|
5404
|
+
recalledFollowUp = null;
|
|
5405
|
+
}
|
|
5406
|
+
async function submit(mode = 'follow-up') {
|
|
5407
|
+
if (applyAtCompletion()) {
|
|
5240
5408
|
renderDynamic();
|
|
5241
5409
|
return;
|
|
5242
5410
|
}
|
|
5243
|
-
const selectedCommand =
|
|
5244
|
-
? selectInteractiveCommand(editor.text, menuSelected)
|
|
5245
|
-
: undefined;
|
|
5411
|
+
const selectedCommand = selectInteractiveCommand(editor.text, menuSelected);
|
|
5246
5412
|
if (selectedCommand) {
|
|
5413
|
+
const selectedName = selectedCommand.slice(1).split(/\s/u, 1)[0] ?? '';
|
|
5414
|
+
// Slash completions are not a resubmit of the recalled follow-up.
|
|
5415
|
+
restoreAbandonedFollowUp(session, recalledFollowUp);
|
|
5416
|
+
recalledFollowUp = null;
|
|
5247
5417
|
editor.clear();
|
|
5248
5418
|
menuSelected = 0;
|
|
5419
|
+
if (running && !canRunInteractiveCommand(selectedName, true)) {
|
|
5420
|
+
appendStatic(formatInfoLine(`/${selectedName} requires an idle session; it will be available after this run`));
|
|
5421
|
+
renderDynamic();
|
|
5422
|
+
return;
|
|
5423
|
+
}
|
|
5249
5424
|
// A selected completion already contains its subcommand. Keeping the
|
|
5250
5425
|
// partially typed second word would turn `/agents runs` into
|
|
5251
5426
|
// `/agents runs runs` on Enter.
|
|
@@ -5260,17 +5435,31 @@ export async function runHadamardTui(options = {}) {
|
|
|
5260
5435
|
const text = value.trim();
|
|
5261
5436
|
menuSelected = 0;
|
|
5262
5437
|
if (!text) {
|
|
5438
|
+
restoreRecalledFollowUpIfAbandoned();
|
|
5263
5439
|
renderDynamic();
|
|
5264
5440
|
return;
|
|
5265
5441
|
}
|
|
5266
5442
|
if (running) {
|
|
5267
5443
|
if (text.startsWith('/')) {
|
|
5268
|
-
|
|
5444
|
+
// Slash commands are not a resubmit of the recalled follow-up.
|
|
5445
|
+
restoreAbandonedFollowUp(session, recalledFollowUp);
|
|
5446
|
+
recalledFollowUp = null;
|
|
5447
|
+
const command = text.slice(1).trim().split(/\s/u, 1)[0]?.toLowerCase() ?? '';
|
|
5448
|
+
if (!canRunInteractiveCommand(command, true)) {
|
|
5449
|
+
appendStatic(formatInfoLine(`/${command} requires an idle session; it will be available after this run`));
|
|
5450
|
+
renderDynamic();
|
|
5451
|
+
return;
|
|
5452
|
+
}
|
|
5453
|
+
await runSlashCommand(text);
|
|
5269
5454
|
renderDynamic();
|
|
5270
5455
|
return;
|
|
5271
5456
|
}
|
|
5272
|
-
|
|
5273
|
-
|
|
5457
|
+
// Resubmit consumes the recalled draft (re-queued below).
|
|
5458
|
+
recalledFollowUp = null;
|
|
5459
|
+
submitActiveInput(session, text, mode);
|
|
5460
|
+
appendStatic(mode === 'steer'
|
|
5461
|
+
? formatInfoLine(`steering now: ${text.replace(/\s+/g, ' ')}`)
|
|
5462
|
+
: formatQueuedPrompt(text));
|
|
5274
5463
|
renderDynamic();
|
|
5275
5464
|
return;
|
|
5276
5465
|
}
|
|
@@ -5279,9 +5468,12 @@ export async function runHadamardTui(options = {}) {
|
|
|
5279
5468
|
return;
|
|
5280
5469
|
}
|
|
5281
5470
|
if (text.startsWith('/')) {
|
|
5471
|
+
restoreAbandonedFollowUp(session, recalledFollowUp);
|
|
5472
|
+
recalledFollowUp = null;
|
|
5282
5473
|
await runSlashCommand(text);
|
|
5283
5474
|
return;
|
|
5284
5475
|
}
|
|
5476
|
+
recalledFollowUp = null;
|
|
5285
5477
|
void startRun(text);
|
|
5286
5478
|
}
|
|
5287
5479
|
function handleDialogKey(key) {
|
|
@@ -5462,6 +5654,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
5462
5654
|
else if (!editor.isEmpty()) {
|
|
5463
5655
|
editor.clear();
|
|
5464
5656
|
menuSelected = 0;
|
|
5657
|
+
restoreRecalledFollowUpIfAbandoned();
|
|
5465
5658
|
}
|
|
5466
5659
|
renderDynamic();
|
|
5467
5660
|
return;
|
|
@@ -5472,6 +5665,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
5472
5665
|
return;
|
|
5473
5666
|
}
|
|
5474
5667
|
editor.deleteForward();
|
|
5668
|
+
restoreRecalledFollowUpIfAbandoned();
|
|
5475
5669
|
break;
|
|
5476
5670
|
case 'a':
|
|
5477
5671
|
editor.moveHome();
|
|
@@ -5481,12 +5675,15 @@ export async function runHadamardTui(options = {}) {
|
|
|
5481
5675
|
break;
|
|
5482
5676
|
case 'k':
|
|
5483
5677
|
editor.killToEnd();
|
|
5678
|
+
restoreRecalledFollowUpIfAbandoned();
|
|
5484
5679
|
break;
|
|
5485
5680
|
case 'u':
|
|
5486
5681
|
editor.killToStart();
|
|
5682
|
+
restoreRecalledFollowUpIfAbandoned();
|
|
5487
5683
|
break;
|
|
5488
5684
|
case 'w':
|
|
5489
5685
|
editor.deleteWordLeft();
|
|
5686
|
+
restoreRecalledFollowUpIfAbandoned();
|
|
5490
5687
|
break;
|
|
5491
5688
|
case 'left':
|
|
5492
5689
|
editor.moveWordLeft();
|
|
@@ -5508,6 +5705,13 @@ export async function runHadamardTui(options = {}) {
|
|
|
5508
5705
|
}
|
|
5509
5706
|
switch (name) {
|
|
5510
5707
|
case 'return': {
|
|
5708
|
+
if (key.shift) {
|
|
5709
|
+
if (running)
|
|
5710
|
+
void submit('steer');
|
|
5711
|
+
else
|
|
5712
|
+
editor.insert('\n');
|
|
5713
|
+
return;
|
|
5714
|
+
}
|
|
5511
5715
|
if (key.meta) {
|
|
5512
5716
|
editor.insert('\n');
|
|
5513
5717
|
break;
|
|
@@ -5516,6 +5720,10 @@ export async function runHadamardTui(options = {}) {
|
|
|
5516
5720
|
return;
|
|
5517
5721
|
}
|
|
5518
5722
|
case 'enter':
|
|
5723
|
+
if (key.shift && running) {
|
|
5724
|
+
void submit('steer');
|
|
5725
|
+
return;
|
|
5726
|
+
}
|
|
5519
5727
|
editor.insert('\n');
|
|
5520
5728
|
break;
|
|
5521
5729
|
case 'escape': {
|
|
@@ -5525,6 +5733,7 @@ export async function runHadamardTui(options = {}) {
|
|
|
5525
5733
|
else if (!editor.isEmpty()) {
|
|
5526
5734
|
editor.clear();
|
|
5527
5735
|
menuSelected = 0;
|
|
5736
|
+
restoreRecalledFollowUpIfAbandoned();
|
|
5528
5737
|
}
|
|
5529
5738
|
break;
|
|
5530
5739
|
}
|
|
@@ -5532,9 +5741,11 @@ export async function runHadamardTui(options = {}) {
|
|
|
5532
5741
|
editor.backspace();
|
|
5533
5742
|
menuSelected = 0;
|
|
5534
5743
|
atSelected = 0;
|
|
5744
|
+
restoreRecalledFollowUpIfAbandoned();
|
|
5535
5745
|
break;
|
|
5536
5746
|
case 'delete':
|
|
5537
5747
|
editor.deleteForward();
|
|
5748
|
+
restoreRecalledFollowUpIfAbandoned();
|
|
5538
5749
|
break;
|
|
5539
5750
|
case 'left':
|
|
5540
5751
|
if (key.meta)
|
|
@@ -5555,6 +5766,14 @@ export async function runHadamardTui(options = {}) {
|
|
|
5555
5766
|
editor.moveEnd();
|
|
5556
5767
|
break;
|
|
5557
5768
|
case 'up': {
|
|
5769
|
+
if (running && editor.isEmpty()) {
|
|
5770
|
+
const recalled = recallLatestFollowUp(session);
|
|
5771
|
+
if (recalled) {
|
|
5772
|
+
recalledFollowUp = recalled;
|
|
5773
|
+
editor.setText(recalled);
|
|
5774
|
+
break;
|
|
5775
|
+
}
|
|
5776
|
+
}
|
|
5558
5777
|
const atToken = activeAtToken(editor.text, editor.cursor);
|
|
5559
5778
|
const atCount = atToken ? atCompletions(atToken.token).length : 0;
|
|
5560
5779
|
const menu = filterSlashCommands(editor.text);
|