praxis-agent 0.7.0 → 0.9.0

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.
Files changed (301) hide show
  1. package/README.md +8 -0
  2. package/dist/application/background-agent-manager.d.ts +5 -0
  3. package/dist/application/background-agent-manager.js +21 -0
  4. package/dist/application/background-bash-manager.d.ts +14 -0
  5. package/dist/application/background-bash-manager.js +42 -4
  6. package/dist/application/background-task-runtime.d.ts +34 -0
  7. package/dist/application/background-task-runtime.js +59 -0
  8. package/dist/application/session-service.d.ts +21 -1
  9. package/dist/application/session-service.js +188 -17
  10. package/dist/application/session-worktree.d.ts +1 -0
  11. package/dist/application/session-worktree.js +13 -2
  12. package/dist/application/subagent-service.d.ts +3 -0
  13. package/dist/application/subagent-service.js +6 -0
  14. package/dist/application/workflow-manager.d.ts +70 -2
  15. package/dist/application/workflow-manager.js +21 -4
  16. package/dist/cli/agents-dashboard.d.ts +9 -0
  17. package/dist/cli/agents-dashboard.js +16 -5
  18. package/dist/cli/interactive.d.ts +41 -3
  19. package/dist/cli/interactive.js +1281 -183
  20. package/dist/cli/tui/claude-style.d.ts +31 -3
  21. package/dist/cli/tui/claude-style.js +171 -54
  22. package/dist/cli/tui/config-dashboard.d.ts +63 -0
  23. package/dist/cli/tui/config-dashboard.js +150 -0
  24. package/dist/cli/tui/config-settings.d.ts +32 -0
  25. package/dist/cli/tui/config-settings.js +276 -0
  26. package/dist/cli/tui/custom-themes.d.ts +21 -0
  27. package/dist/cli/tui/custom-themes.js +284 -0
  28. package/dist/cli/tui/file-picker.d.ts +3 -1
  29. package/dist/cli/tui/file-picker.js +8 -2
  30. package/dist/cli/tui/keybindings.js +0 -1
  31. package/dist/cli/tui/mcp-panel-controller.d.ts +32 -0
  32. package/dist/cli/tui/mcp-panel-controller.js +80 -0
  33. package/dist/cli/tui/mcp-panel-projector.d.ts +79 -0
  34. package/dist/cli/tui/mcp-panel-projector.js +181 -0
  35. package/dist/cli/tui/mcp-panel.d.ts +8 -0
  36. package/dist/cli/tui/mcp-panel.js +99 -0
  37. package/dist/cli/tui/recently-denied.d.ts +15 -0
  38. package/dist/cli/tui/recently-denied.js +19 -0
  39. package/dist/cli/tui/runtime-interactions.d.ts +17 -0
  40. package/dist/cli/tui/runtime-interactions.js +100 -0
  41. package/dist/cli/tui/runtime-settings.d.ts +40 -0
  42. package/dist/cli/tui/runtime-settings.js +84 -0
  43. package/dist/cli/tui/slash-commands.js +10 -0
  44. package/dist/cli/tui/task-panel.d.ts +53 -0
  45. package/dist/cli/tui/task-panel.js +204 -0
  46. package/dist/cli/tui/terminal-notifications.d.ts +10 -0
  47. package/dist/cli/tui/terminal-notifications.js +48 -0
  48. package/dist/cli/tui/terminal-setup.d.ts +24 -0
  49. package/dist/cli/tui/terminal-setup.js +618 -0
  50. package/dist/cli/tui/theme-settings.d.ts +8 -0
  51. package/dist/cli/tui/theme-settings.js +132 -0
  52. package/dist/cli/tui/theme.d.ts +53 -0
  53. package/dist/cli/tui/theme.js +265 -0
  54. package/dist/cli.d.ts +9 -0
  55. package/dist/cli.js +97 -17
  56. package/dist/compatibility/claude/schema.js +2 -0
  57. package/dist/core/runtime.d.ts +12 -0
  58. package/dist/core/runtime.js +24 -0
  59. package/dist/maintenance/self-update.js +1 -1
  60. package/dist/mcp/claude-mcp-management.d.ts +6 -1
  61. package/dist/mcp/claude-mcp-management.js +191 -44
  62. package/dist/mcp/claude-mcp-oauth.js +2 -0
  63. package/dist/mcp/claude-mcp-tools.d.ts +31 -3
  64. package/dist/mcp/claude-mcp-tools.js +116 -34
  65. package/dist/permissions/claude-permission-resolver.d.ts +3 -0
  66. package/dist/permissions/claude-permission-resolver.js +42 -20
  67. package/dist/platform/claude-version.js +2 -1
  68. package/dist/plugins/claude-plugin-runtime.js +11 -3
  69. package/dist/tools/claude-interactive-tools.d.ts +7 -0
  70. package/dist/tools/claude-interactive-tools.js +21 -8
  71. package/dist/tools/claude-task-tools.d.ts +4 -0
  72. package/dist/tools/claude-task-tools.js +7 -0
  73. package/package.json +2 -1
  74. package/dist/application/background-agent-manager.d.ts.map +0 -1
  75. package/dist/application/background-agent-manager.js.map +0 -1
  76. package/dist/application/background-bash-manager.d.ts.map +0 -1
  77. package/dist/application/background-bash-manager.js.map +0 -1
  78. package/dist/application/background-task-id.d.ts.map +0 -1
  79. package/dist/application/background-task-id.js.map +0 -1
  80. package/dist/application/claude-project-purge.d.ts.map +0 -1
  81. package/dist/application/claude-project-purge.js.map +0 -1
  82. package/dist/application/managed-worktree.d.ts.map +0 -1
  83. package/dist/application/managed-worktree.js.map +0 -1
  84. package/dist/application/model-compactor.d.ts.map +0 -1
  85. package/dist/application/model-compactor.js.map +0 -1
  86. package/dist/application/scheduled-prompt-manager.d.ts.map +0 -1
  87. package/dist/application/scheduled-prompt-manager.js.map +0 -1
  88. package/dist/application/session-service.d.ts.map +0 -1
  89. package/dist/application/session-service.js.map +0 -1
  90. package/dist/application/session-worktree.d.ts.map +0 -1
  91. package/dist/application/session-worktree.js.map +0 -1
  92. package/dist/application/subagent-service.d.ts.map +0 -1
  93. package/dist/application/subagent-service.js.map +0 -1
  94. package/dist/application/tool-use-summary.d.ts.map +0 -1
  95. package/dist/application/tool-use-summary.js.map +0 -1
  96. package/dist/application/top-level-agent-manager.d.ts.map +0 -1
  97. package/dist/application/top-level-agent-manager.js.map +0 -1
  98. package/dist/application/workflow-manager.d.ts.map +0 -1
  99. package/dist/application/workflow-manager.js.map +0 -1
  100. package/dist/application/workflow-meta.d.ts.map +0 -1
  101. package/dist/application/workflow-meta.js.map +0 -1
  102. package/dist/application/workflow-runtime.d.ts.map +0 -1
  103. package/dist/application/workflow-runtime.js.map +0 -1
  104. package/dist/application/workflow-worktree.d.ts.map +0 -1
  105. package/dist/application/workflow-worktree.js.map +0 -1
  106. package/dist/cli/agents-dashboard.d.ts.map +0 -1
  107. package/dist/cli/agents-dashboard.js.map +0 -1
  108. package/dist/cli/controls.d.ts.map +0 -1
  109. package/dist/cli/controls.js.map +0 -1
  110. package/dist/cli/debug.d.ts.map +0 -1
  111. package/dist/cli/debug.js.map +0 -1
  112. package/dist/cli/interactive.d.ts.map +0 -1
  113. package/dist/cli/interactive.js.map +0 -1
  114. package/dist/cli/protocol.d.ts.map +0 -1
  115. package/dist/cli/protocol.js.map +0 -1
  116. package/dist/cli/tui/claude-style.d.ts.map +0 -1
  117. package/dist/cli/tui/claude-style.js.map +0 -1
  118. package/dist/cli/tui/clipboard.d.ts.map +0 -1
  119. package/dist/cli/tui/clipboard.js.map +0 -1
  120. package/dist/cli/tui/composer-editor.d.ts.map +0 -1
  121. package/dist/cli/tui/composer-editor.js.map +0 -1
  122. package/dist/cli/tui/composer-images.d.ts.map +0 -1
  123. package/dist/cli/tui/composer-images.js.map +0 -1
  124. package/dist/cli/tui/conversation-export.d.ts.map +0 -1
  125. package/dist/cli/tui/conversation-export.js.map +0 -1
  126. package/dist/cli/tui/external-editor.d.ts.map +0 -1
  127. package/dist/cli/tui/external-editor.js.map +0 -1
  128. package/dist/cli/tui/file-picker.d.ts.map +0 -1
  129. package/dist/cli/tui/file-picker.js.map +0 -1
  130. package/dist/cli/tui/git-diff.d.ts.map +0 -1
  131. package/dist/cli/tui/git-diff.js.map +0 -1
  132. package/dist/cli/tui/hook-settings.d.ts.map +0 -1
  133. package/dist/cli/tui/hook-settings.js.map +0 -1
  134. package/dist/cli/tui/keybindings.d.ts.map +0 -1
  135. package/dist/cli/tui/keybindings.js.map +0 -1
  136. package/dist/cli/tui/memory-files.d.ts.map +0 -1
  137. package/dist/cli/tui/memory-files.js.map +0 -1
  138. package/dist/cli/tui/permission-settings.d.ts.map +0 -1
  139. package/dist/cli/tui/permission-settings.js.map +0 -1
  140. package/dist/cli/tui/slash-commands.d.ts.map +0 -1
  141. package/dist/cli/tui/slash-commands.js.map +0 -1
  142. package/dist/cli/tui/terminal-suspend.d.ts.map +0 -1
  143. package/dist/cli/tui/terminal-suspend.js.map +0 -1
  144. package/dist/cli/tui/workspace-directories.d.ts.map +0 -1
  145. package/dist/cli/tui/workspace-directories.js.map +0 -1
  146. package/dist/cli.d.ts.map +0 -1
  147. package/dist/cli.js.map +0 -1
  148. package/dist/compatibility/claude/compaction.d.ts.map +0 -1
  149. package/dist/compatibility/claude/compaction.js.map +0 -1
  150. package/dist/compatibility/claude/context.d.ts.map +0 -1
  151. package/dist/compatibility/claude/context.js.map +0 -1
  152. package/dist/compatibility/claude/dynamic-context.d.ts.map +0 -1
  153. package/dist/compatibility/claude/dynamic-context.js.map +0 -1
  154. package/dist/compatibility/claude/file-history.d.ts.map +0 -1
  155. package/dist/compatibility/claude/file-history.js.map +0 -1
  156. package/dist/compatibility/claude/file-resources.d.ts.map +0 -1
  157. package/dist/compatibility/claude/file-resources.js.map +0 -1
  158. package/dist/compatibility/claude/fork.d.ts.map +0 -1
  159. package/dist/compatibility/claude/fork.js.map +0 -1
  160. package/dist/compatibility/claude/history.d.ts.map +0 -1
  161. package/dist/compatibility/claude/history.js.map +0 -1
  162. package/dist/compatibility/claude/ownership.d.ts.map +0 -1
  163. package/dist/compatibility/claude/ownership.js.map +0 -1
  164. package/dist/compatibility/claude/paths.d.ts.map +0 -1
  165. package/dist/compatibility/claude/paths.js.map +0 -1
  166. package/dist/compatibility/claude/pr-links.d.ts.map +0 -1
  167. package/dist/compatibility/claude/pr-links.js.map +0 -1
  168. package/dist/compatibility/claude/projection.d.ts.map +0 -1
  169. package/dist/compatibility/claude/projection.js.map +0 -1
  170. package/dist/compatibility/claude/schema.d.ts.map +0 -1
  171. package/dist/compatibility/claude/schema.js.map +0 -1
  172. package/dist/compatibility/claude/shared-resources.d.ts.map +0 -1
  173. package/dist/compatibility/claude/shared-resources.js.map +0 -1
  174. package/dist/compatibility/claude/sidechain.d.ts.map +0 -1
  175. package/dist/compatibility/claude/sidechain.js.map +0 -1
  176. package/dist/compatibility/claude/tool-links.d.ts.map +0 -1
  177. package/dist/compatibility/claude/tool-links.js.map +0 -1
  178. package/dist/compatibility/claude/translation.d.ts.map +0 -1
  179. package/dist/compatibility/claude/translation.js.map +0 -1
  180. package/dist/compatibility/claude/workflow-replay.d.ts.map +0 -1
  181. package/dist/compatibility/claude/workflow-replay.js.map +0 -1
  182. package/dist/compatibility/claude/workflow.d.ts.map +0 -1
  183. package/dist/compatibility/claude/workflow.js.map +0 -1
  184. package/dist/core/compaction.d.ts.map +0 -1
  185. package/dist/core/compaction.js.map +0 -1
  186. package/dist/core/context-budget.d.ts.map +0 -1
  187. package/dist/core/context-budget.js.map +0 -1
  188. package/dist/core/context.d.ts.map +0 -1
  189. package/dist/core/context.js.map +0 -1
  190. package/dist/core/runtime.d.ts.map +0 -1
  191. package/dist/core/runtime.js.map +0 -1
  192. package/dist/core/usage.d.ts.map +0 -1
  193. package/dist/core/usage.js.map +0 -1
  194. package/dist/extensions/claude-extension-tools.d.ts.map +0 -1
  195. package/dist/extensions/claude-extension-tools.js.map +0 -1
  196. package/dist/extensions/claude-extensions.d.ts.map +0 -1
  197. package/dist/extensions/claude-extensions.js.map +0 -1
  198. package/dist/hooks/claude-hook-tools.d.ts.map +0 -1
  199. package/dist/hooks/claude-hook-tools.js.map +0 -1
  200. package/dist/hooks/claude-hooks.d.ts.map +0 -1
  201. package/dist/hooks/claude-hooks.js.map +0 -1
  202. package/dist/maintenance/doctor.d.ts.map +0 -1
  203. package/dist/maintenance/doctor.js.map +0 -1
  204. package/dist/maintenance/self-update.d.ts.map +0 -1
  205. package/dist/maintenance/self-update.js.map +0 -1
  206. package/dist/mcp/claude-mcp-management.d.ts.map +0 -1
  207. package/dist/mcp/claude-mcp-management.js.map +0 -1
  208. package/dist/mcp/claude-mcp-oauth.d.ts.map +0 -1
  209. package/dist/mcp/claude-mcp-oauth.js.map +0 -1
  210. package/dist/mcp/claude-mcp-tools.d.ts.map +0 -1
  211. package/dist/mcp/claude-mcp-tools.js.map +0 -1
  212. package/dist/mcp/praxis-mcp-server.d.ts.map +0 -1
  213. package/dist/mcp/praxis-mcp-server.js.map +0 -1
  214. package/dist/permissions/claude-auto-classifier.d.ts.map +0 -1
  215. package/dist/permissions/claude-auto-classifier.js.map +0 -1
  216. package/dist/permissions/claude-permission-resolver.d.ts.map +0 -1
  217. package/dist/permissions/claude-permission-resolver.js.map +0 -1
  218. package/dist/persistence/claude-job-store.d.ts.map +0 -1
  219. package/dist/persistence/claude-job-store.js.map +0 -1
  220. package/dist/persistence/claude-scheduled-task-store.d.ts.map +0 -1
  221. package/dist/persistence/claude-scheduled-task-store.js.map +0 -1
  222. package/dist/persistence/claude-sidechain-store.d.ts.map +0 -1
  223. package/dist/persistence/claude-sidechain-store.js.map +0 -1
  224. package/dist/persistence/claude-task-store.d.ts.map +0 -1
  225. package/dist/persistence/claude-task-store.js.map +0 -1
  226. package/dist/persistence/claude-transcript-store.d.ts.map +0 -1
  227. package/dist/persistence/claude-transcript-store.js.map +0 -1
  228. package/dist/persistence/claude-workflow-store.d.ts.map +0 -1
  229. package/dist/persistence/claude-workflow-store.js.map +0 -1
  230. package/dist/persistence/in-memory-sidechain-store.d.ts.map +0 -1
  231. package/dist/persistence/in-memory-sidechain-store.js.map +0 -1
  232. package/dist/persistence/in-memory-transcript-store.d.ts.map +0 -1
  233. package/dist/persistence/in-memory-transcript-store.js.map +0 -1
  234. package/dist/platform/atomic-write.d.ts.map +0 -1
  235. package/dist/platform/atomic-write.js.map +0 -1
  236. package/dist/platform/bounded-process-runner.d.ts.map +0 -1
  237. package/dist/platform/bounded-process-runner.js.map +0 -1
  238. package/dist/platform/claude-version.d.ts.map +0 -1
  239. package/dist/platform/claude-version.js.map +0 -1
  240. package/dist/platform/command-shell.d.ts.map +0 -1
  241. package/dist/platform/command-shell.js.map +0 -1
  242. package/dist/platform/exclusive-file-lease.d.ts.map +0 -1
  243. package/dist/platform/exclusive-file-lease.js.map +0 -1
  244. package/dist/platform/sensitive-data.d.ts.map +0 -1
  245. package/dist/platform/sensitive-data.js.map +0 -1
  246. package/dist/platform/tmux-worktree.d.ts.map +0 -1
  247. package/dist/platform/tmux-worktree.js.map +0 -1
  248. package/dist/plugins/claude-plugin-eval-discovery.d.ts.map +0 -1
  249. package/dist/plugins/claude-plugin-eval-discovery.js.map +0 -1
  250. package/dist/plugins/claude-plugin-eval-graders.d.ts.map +0 -1
  251. package/dist/plugins/claude-plugin-eval-graders.js.map +0 -1
  252. package/dist/plugins/claude-plugin-eval-runner.d.ts.map +0 -1
  253. package/dist/plugins/claude-plugin-eval-runner.js.map +0 -1
  254. package/dist/plugins/claude-plugin-eval-schema.d.ts.map +0 -1
  255. package/dist/plugins/claude-plugin-eval-schema.js.map +0 -1
  256. package/dist/plugins/claude-plugin-eval.d.ts.map +0 -1
  257. package/dist/plugins/claude-plugin-eval.js.map +0 -1
  258. package/dist/plugins/claude-plugin-maintenance.d.ts.map +0 -1
  259. package/dist/plugins/claude-plugin-maintenance.js.map +0 -1
  260. package/dist/plugins/claude-plugin-marketplace.d.ts.map +0 -1
  261. package/dist/plugins/claude-plugin-marketplace.js.map +0 -1
  262. package/dist/plugins/claude-plugin-mcpb.d.ts.map +0 -1
  263. package/dist/plugins/claude-plugin-mcpb.js.map +0 -1
  264. package/dist/plugins/claude-plugin-runtime.d.ts.map +0 -1
  265. package/dist/plugins/claude-plugin-runtime.js.map +0 -1
  266. package/dist/providers/anthropic-compatible.d.ts.map +0 -1
  267. package/dist/providers/anthropic-compatible.js.map +0 -1
  268. package/dist/providers/environment.d.ts.map +0 -1
  269. package/dist/providers/environment.js.map +0 -1
  270. package/dist/providers/fallback-provider.d.ts.map +0 -1
  271. package/dist/providers/fallback-provider.js.map +0 -1
  272. package/dist/providers/openai-compatible.d.ts.map +0 -1
  273. package/dist/providers/openai-compatible.js.map +0 -1
  274. package/dist/tools/claude-interactive-tools.d.ts.map +0 -1
  275. package/dist/tools/claude-interactive-tools.js.map +0 -1
  276. package/dist/tools/claude-lsp-formatters.d.ts.map +0 -1
  277. package/dist/tools/claude-lsp-formatters.js.map +0 -1
  278. package/dist/tools/claude-lsp-tool.d.ts.map +0 -1
  279. package/dist/tools/claude-lsp-tool.js.map +0 -1
  280. package/dist/tools/claude-scheduled-tools.d.ts.map +0 -1
  281. package/dist/tools/claude-scheduled-tools.js.map +0 -1
  282. package/dist/tools/claude-task-tools.d.ts.map +0 -1
  283. package/dist/tools/claude-task-tools.js.map +0 -1
  284. package/dist/tools/claude-user-message.d.ts.map +0 -1
  285. package/dist/tools/claude-user-message.js.map +0 -1
  286. package/dist/tools/claude-workflow-tools.d.ts.map +0 -1
  287. package/dist/tools/claude-workflow-tools.js.map +0 -1
  288. package/dist/tools/claude-worktree-tools.d.ts.map +0 -1
  289. package/dist/tools/claude-worktree-tools.js.map +0 -1
  290. package/dist/tools/filtered-tool-registry.d.ts.map +0 -1
  291. package/dist/tools/filtered-tool-registry.js.map +0 -1
  292. package/dist/tools/glob.d.ts.map +0 -1
  293. package/dist/tools/glob.js.map +0 -1
  294. package/dist/tools/local-tools.d.ts.map +0 -1
  295. package/dist/tools/local-tools.js.map +0 -1
  296. package/dist/tools/notebook.d.ts.map +0 -1
  297. package/dist/tools/notebook.js.map +0 -1
  298. package/dist/tools/pdf.d.ts.map +0 -1
  299. package/dist/tools/pdf.js.map +0 -1
  300. package/dist/tools/web.d.ts.map +0 -1
  301. package/dist/tools/web.js.map +0 -1
@@ -14,6 +14,7 @@ import { selectClaudeSchemaAdapter, } from '../compatibility/claude/schema.js';
14
14
  import { findUnresolvedClaudeToolCalls } from '../compatibility/claude/tool-links.js';
15
15
  import { createClaudeAgentSettingEntry, createClaudeHookAttachmentEntries, createClaudeLastPromptEntry, createClaudeRuleAttachmentEntry, translateProviderEvents, } from '../compatibility/claude/translation.js';
16
16
  import { AgentRunCancelledError, AgentRuntime, } from '../core/runtime.js';
17
+ import { BackgroundTaskRuntime, } from './background-task-runtime.js';
17
18
  import { usageCostUsd } from '../core/usage.js';
18
19
  import { ContextBudget, estimateModelRequestTokens, } from '../core/context-budget.js';
19
20
  import { injectFirstUserMessageContext, } from '../core/context.js';
@@ -26,7 +27,7 @@ import { ScheduledPromptManager } from './scheduled-prompt-manager.js';
26
27
  import { ClaudeScheduledToolRegistry } from '../tools/claude-scheduled-tools.js';
27
28
  import { ClaudeTaskToolRegistry } from '../tools/claude-task-tools.js';
28
29
  import { ClaudeWorkflowToolRegistry } from '../tools/claude-workflow-tools.js';
29
- import { WorkflowManager } from './workflow-manager.js';
30
+ import { WorkflowManager, } from './workflow-manager.js';
30
31
  import { SessionWorktreeManager } from './session-worktree.js';
31
32
  import { ClaudeWorktreeToolRegistry } from '../tools/claude-worktree-tools.js';
32
33
  import { generateToolUseSummary } from './tool-use-summary.js';
@@ -88,12 +89,14 @@ export class ClaudeSessionService {
88
89
  inMemoryStores = new Map();
89
90
  scheduledPrompts;
90
91
  workflowManager;
92
+ backgroundTasks;
91
93
  worktreeManager;
92
94
  sessionCwds = new Map();
93
95
  hostedSubagents = new Set();
94
96
  hostedSubagentsByRegistry = new WeakMap();
95
97
  backgroundNotificationWrites = new Map();
96
98
  downloadedFileResourceSessions = new Set();
99
+ mcpClosePromise;
97
100
  runtimeCwd;
98
101
  constructor(options) {
99
102
  this.options = options;
@@ -112,11 +115,15 @@ export class ClaudeSessionService {
112
115
  this.workflowManager = options.enableWorkflows
113
116
  ? new WorkflowManager(options.configRoot, options.cwd, () => this.activeCwd())
114
117
  : null;
118
+ this.backgroundTasks = new BackgroundTaskRuntime(this.workflowManager);
115
119
  this.worktreeManager =
116
120
  options.enableWorktrees && options.workspace
117
121
  ? new SessionWorktreeManager({
118
122
  workspace: options.workspace,
119
123
  sessionId: '',
124
+ ...(options.worktreeBaseRef
125
+ ? { baseRef: options.worktreeBaseRef }
126
+ : {}),
120
127
  })
121
128
  : null;
122
129
  }
@@ -126,13 +133,42 @@ export class ClaudeSessionService {
126
133
  workflows() {
127
134
  return this.workflowManager?.list() ?? [];
128
135
  }
136
+ mcpInspect() {
137
+ return this.requireMcp().inspect();
138
+ }
139
+ mcpReconnect(name) {
140
+ return this.requireMcp().reconnect(name);
141
+ }
142
+ mcpAuthenticate(name) {
143
+ return this.requireMcp().authenticate(name);
144
+ }
145
+ mcpReload() {
146
+ return this.requireMcp().reload();
147
+ }
148
+ mcpTools(name) {
149
+ return this.requireMcp().tools(name);
150
+ }
151
+ requireMcp() {
152
+ if (!this.options.mcp)
153
+ throw new Error('MCP runtime is not configured');
154
+ return this.options.mcp;
155
+ }
156
+ taskSnapshots(sessionId) {
157
+ return this.backgroundTasks.snapshot(sessionId);
158
+ }
159
+ stopTask(sessionId, taskId) {
160
+ return this.backgroundTasks.stop(sessionId, taskId);
161
+ }
129
162
  async close() {
130
163
  this.scheduledPrompts?.close();
131
164
  await Promise.all([...this.hostedSubagents].map((executor) => executor.close()));
132
165
  await Promise.resolve();
133
166
  await Promise.all([...this.backgroundNotificationWrites.values()]);
134
167
  this.hostedSubagents.clear();
168
+ this.backgroundTasks.clear();
135
169
  await this.workflowManager?.close();
170
+ this.mcpClosePromise ??= this.options.mcp?.close?.() ?? Promise.resolve();
171
+ await this.mcpClosePromise;
136
172
  }
137
173
  createHostedToolRegistry(sessionId) {
138
174
  const baseTools = this.options.tools;
@@ -155,6 +191,8 @@ export class ClaudeSessionService {
155
191
  : {}),
156
192
  })
157
193
  : null;
194
+ if (taskTools)
195
+ this.backgroundTasks.registerBash(sessionId, taskTools);
158
196
  const scheduledTools = this.scheduledPrompts &&
159
197
  (this.options.scheduledToolNames?.length ?? 0) > 0
160
198
  ? new ClaudeScheduledToolRegistry({
@@ -221,6 +259,9 @@ export class ClaudeSessionService {
221
259
  : null;
222
260
  if (subagentExecutor)
223
261
  this.hostedSubagents.add(subagentExecutor);
262
+ if (subagentExecutor) {
263
+ this.backgroundTasks.registerAgents(sessionId, subagentExecutor);
264
+ }
224
265
  const agentTools = subagentExecutor
225
266
  ? subagentExecutor.registry(sessionId, 0, (callId) => callId)
226
267
  : wrappedBase;
@@ -810,6 +851,13 @@ export class ClaudeSessionService {
810
851
  throw new Error(`Claude cd usage conflict: ${result.reason}`);
811
852
  }
812
853
  }
854
+ async approveRecentlyDenied(sessionId, display) {
855
+ await this.appendPermissionGrant(sessionId, display, false);
856
+ }
857
+ async retryRecentlyDenied(sessionId, display, signal) {
858
+ await this.appendPermissionGrant(sessionId, display, true);
859
+ return this.executeTurn(sessionId, '/permissions', true, signal, undefined, [], [], undefined, undefined, true);
860
+ }
813
861
  async recordBtwUsage(sessionId, permissionMode = 'default') {
814
862
  const activeSessionId = await this.ensureLocalSession(sessionId, permissionMode);
815
863
  await this.appendInputHistory('/btw', activeSessionId);
@@ -1188,7 +1236,7 @@ export class ClaudeSessionService {
1188
1236
  throw new Error(`Claude permission mode update conflict: ${result.reason}`);
1189
1237
  }
1190
1238
  }
1191
- async executeTurn(sessionId, prompt, requireExisting, signal, name, images = [], documents = [], resumeSessionAt, shellCommand) {
1239
+ async executeTurn(sessionId, prompt, requireExisting, signal, name, images = [], documents = [], resumeSessionAt, shellCommand, skipUserPrompt = false) {
1192
1240
  this.assertWritable();
1193
1241
  if (prompt.length === 0 && images.length === 0 && documents.length === 0)
1194
1242
  throw new Error('Prompt must not be empty');
@@ -1205,6 +1253,10 @@ export class ClaudeSessionService {
1205
1253
  }
1206
1254
  const pinnedCwd = this.sessionCwds.get(sessionId) ?? this.activeCwd();
1207
1255
  this.sessionCwds.set(sessionId, pinnedCwd);
1256
+ if (this.options.workspace?.cwd() !== pinnedCwd) {
1257
+ this.options.workspace?.setCwd(pinnedCwd);
1258
+ }
1259
+ this.runtimeCwd = pinnedCwd;
1208
1260
  const sessionPaths = this.paths(sessionId);
1209
1261
  const toolResultDirectory = join(sessionPaths.projectRoot, sessionId, 'tool-results');
1210
1262
  const store = this.turnStore(sessionId);
@@ -1470,6 +1522,10 @@ export class ClaudeSessionService {
1470
1522
  if (typeof path !== 'string') {
1471
1523
  return interactiveMessageTools.execute(call, context);
1472
1524
  }
1525
+ if ((call.name === 'Write' || call.name === 'Edit') &&
1526
+ (await this.options.interactiveTools?.isPlanFile(sessionId, path))) {
1527
+ return interactiveMessageTools.execute(call, context);
1528
+ }
1473
1529
  const snapshotMessageId = currentPromptId ??
1474
1530
  this.promptIdForToolCall(snapshot.entries, call.id);
1475
1531
  const assistantMessageId = lastAssistantUuid ??
@@ -1743,13 +1799,15 @@ export class ClaudeSessionService {
1743
1799
  ]
1744
1800
  : []),
1745
1801
  ];
1746
- const expansion = shellCommand === undefined
1747
- ? this.options.extensions
1748
- ? await this.options.extensions.expandPromptAsync(prompt, signal, toolResultDirectory)
1749
- : { userMessages: [prompt] }
1750
- : {
1751
- userMessages: [`<bash-input>${shellCommand}</bash-input>`],
1752
- };
1802
+ const expansion = skipUserPrompt
1803
+ ? { userMessages: [] }
1804
+ : shellCommand === undefined
1805
+ ? this.options.extensions
1806
+ ? await this.options.extensions.expandPromptAsync(prompt, signal, toolResultDirectory)
1807
+ : { userMessages: [prompt] }
1808
+ : {
1809
+ userMessages: [`<bash-input>${shellCommand}</bash-input>`],
1810
+ };
1753
1811
  const expandedMessages = expansion.messages ?? expansion.userMessages.map((text) => ({ text }));
1754
1812
  const attachmentIndex = expansion.messages
1755
1813
  ? expandedMessages.length - 1
@@ -1786,7 +1844,7 @@ export class ClaudeSessionService {
1786
1844
  ? { documents }
1787
1845
  : {}),
1788
1846
  }));
1789
- const agentMentionMessages = shellCommand === undefined
1847
+ const agentMentionMessages = shellCommand === undefined && !skipUserPrompt
1790
1848
  ? (this.options.extensions?.agentMentionMessages(prompt) ?? [])
1791
1849
  : [];
1792
1850
  const injectAgentMentionContext = (messages) => {
@@ -1819,7 +1877,7 @@ export class ClaudeSessionService {
1819
1877
  const injectTurnContext = (messages) => injectAgentMentionContext(injectDynamicContext(messages));
1820
1878
  let compactionAnchorUuid = this.lastMessageUuid(snapshot.entries);
1821
1879
  const compactIfNeeded = async (pendingMessages = [], preservedUserMessages = []) => {
1822
- if (!budget)
1880
+ if (!budget || this.options.autoCompact === false)
1823
1881
  return;
1824
1882
  const historyMessages = projectClaudeModelMessages(snapshot.entries);
1825
1883
  const predicted = budget.evaluate([
@@ -1991,7 +2049,7 @@ export class ClaudeSessionService {
1991
2049
  tail: historyTail,
1992
2050
  };
1993
2051
  }
1994
- if (this.options.hooks) {
2052
+ if (this.options.hooks && !skipUserPrompt) {
1995
2053
  const outcome = await this.options.hooks.run({
1996
2054
  ...hookSession,
1997
2055
  hook_event_name: 'UserPromptSubmit',
@@ -2168,11 +2226,13 @@ export class ClaudeSessionService {
2168
2226
  if (!finalLeafUuid) {
2169
2227
  throw new Error('Could not locate final assistant response');
2170
2228
  }
2171
- await this.append(lease, snapshot.tail, createClaudeLastPromptEntry({
2172
- sessionId,
2173
- lastPrompt: prompt,
2174
- leafUuid: finalLeafUuid,
2175
- }));
2229
+ if (!skipUserPrompt) {
2230
+ await this.append(lease, snapshot.tail, createClaudeLastPromptEntry({
2231
+ sessionId,
2232
+ lastPrompt: prompt,
2233
+ leafUuid: finalLeafUuid,
2234
+ }));
2235
+ }
2176
2236
  const totalUsage = mergeUsage(mergeUsage(mergeUsage(recoveryUsage, compactionUsage), shellUsage), result.usage);
2177
2237
  return {
2178
2238
  sessionId,
@@ -2494,6 +2554,117 @@ export class ClaudeSessionService {
2494
2554
  sessionId,
2495
2555
  })}\n`, 'utf8');
2496
2556
  }
2557
+ async appendPermissionGrant(sessionId, display, retry) {
2558
+ this.assertWritable();
2559
+ const normalized = display.trim();
2560
+ if (!normalized)
2561
+ throw new Error('Permission action must not be empty');
2562
+ while (true) {
2563
+ const result = await this.turnStore(sessionId).withLease(async (lease) => {
2564
+ const snapshot = await lease.load();
2565
+ if (snapshot.entries.length === 0) {
2566
+ throw new Error(`Claude session not found: ${sessionId}`);
2567
+ }
2568
+ const timestamp = new Date().toISOString();
2569
+ const promptId = randomUUID();
2570
+ const commandUuid = randomUUID();
2571
+ const common = {
2572
+ isSidechain: false,
2573
+ promptId,
2574
+ timestamp,
2575
+ userType: 'external',
2576
+ entrypoint: 'cli',
2577
+ cwd: this.activeCwd(),
2578
+ sessionId,
2579
+ version: this.options.claudeVersion,
2580
+ gitBranch: null,
2581
+ };
2582
+ let parentUuid = this.logicalTailUuid(snapshot.tail);
2583
+ const entries = [];
2584
+ if (this.options.fileCheckpointing &&
2585
+ this.options.sessionPersistence !== false) {
2586
+ const fileHistory = new ClaudeFileHistory(this.options.configRoot, sessionId, [this.activeCwd(), ...(this.options.fileRewindRoots ?? [])]);
2587
+ entries.push(await fileHistory.snapshot(snapshot.entries, commandUuid));
2588
+ }
2589
+ if (retry) {
2590
+ const retryUuid = randomUUID();
2591
+ entries.push({
2592
+ parentUuid,
2593
+ isSidechain: false,
2594
+ type: 'system',
2595
+ subtype: 'permission_retry',
2596
+ content: `Allowed ${normalized}`,
2597
+ commands: [normalized],
2598
+ level: 'info',
2599
+ isMeta: false,
2600
+ timestamp,
2601
+ uuid: retryUuid,
2602
+ userType: 'external',
2603
+ entrypoint: 'cli',
2604
+ cwd: this.activeCwd(),
2605
+ sessionId,
2606
+ version: this.options.claudeVersion,
2607
+ gitBranch: null,
2608
+ });
2609
+ parentUuid = retryUuid;
2610
+ }
2611
+ else {
2612
+ const caveatUuid = randomUUID();
2613
+ entries.push({
2614
+ ...common,
2615
+ parentUuid,
2616
+ type: 'user',
2617
+ message: {
2618
+ role: 'user',
2619
+ content: '<local-command-caveat>Caveat: The messages below were generated by the user while running local commands. DO NOT respond to these messages or otherwise consider them in your response unless the user explicitly asks you to.</local-command-caveat>',
2620
+ },
2621
+ isMeta: true,
2622
+ uuid: caveatUuid,
2623
+ });
2624
+ parentUuid = caveatUuid;
2625
+ }
2626
+ entries.push({
2627
+ ...common,
2628
+ parentUuid,
2629
+ type: 'user',
2630
+ message: {
2631
+ role: 'user',
2632
+ content: '<command-name>/permissions</command-name>\n <command-message>permissions</command-message>\n <command-args></command-args>',
2633
+ },
2634
+ uuid: commandUuid,
2635
+ });
2636
+ const outputUuid = randomUUID();
2637
+ entries.push({
2638
+ ...common,
2639
+ parentUuid: commandUuid,
2640
+ type: 'user',
2641
+ message: {
2642
+ role: 'user',
2643
+ content: `<local-command-stdout>${retry ? '(no content)' : `Approved ${normalized}`}</local-command-stdout>`,
2644
+ },
2645
+ uuid: outputUuid,
2646
+ });
2647
+ entries.push({
2648
+ ...common,
2649
+ parentUuid: outputUuid,
2650
+ type: 'user',
2651
+ message: {
2652
+ role: 'user',
2653
+ content: `Permission granted for: ${normalized}. You may now retry this command if you would like.`,
2654
+ },
2655
+ isMeta: true,
2656
+ uuid: randomUUID(),
2657
+ });
2658
+ const appended = await lease.appendMany(snapshot.tail, entries);
2659
+ if (appended.status === 'conflict') {
2660
+ throw new Error(`Claude permission grant append conflict: ${appended.reason}`);
2661
+ }
2662
+ });
2663
+ if (result.status === 'completed')
2664
+ return;
2665
+ await new Promise((resolve) => setTimeout(resolve, 25));
2666
+ }
2667
+ }
2497
2668
  async appendBackgroundNotification(sessionId, content) {
2498
2669
  while (true) {
2499
2670
  const result = await this.turnStore(sessionId).withLease(async (lease) => {
@@ -28,6 +28,7 @@ export declare class SessionWorktreeManager {
28
28
  constructor(options: {
29
29
  workspace: WorkspaceContext;
30
30
  sessionId: string;
31
+ baseRef?: 'fresh' | 'head';
31
32
  });
32
33
  bindSession(sessionId: string): void;
33
34
  current(): WorktreeSessionState | null;
@@ -143,14 +143,25 @@ export class SessionWorktreeManager {
143
143
  }
144
144
  const worktreePath = join(root, '.claude', 'worktrees', name);
145
145
  const branch = `worktree-${nameFromPath(name)}`;
146
+ const baseCommit = this.options.baseRef === 'head'
147
+ ? originalHeadCommit
148
+ : ((await gitOptional(root, ['merge-base', 'HEAD', '@{upstream}'])) ??
149
+ originalHeadCommit);
146
150
  await mkdir(join(root, '.claude', 'worktrees'), { recursive: true });
147
151
  try {
148
- await git(root, ['worktree', 'add', '-b', branch, worktreePath, 'HEAD']);
152
+ await git(root, [
153
+ 'worktree',
154
+ 'add',
155
+ '-b',
156
+ branch,
157
+ worktreePath,
158
+ baseCommit,
159
+ ]);
149
160
  const gitDirectory = await git(worktreePath, ['rev-parse', '--git-dir']);
150
161
  const absoluteGitDirectory = isAbsolute(gitDirectory)
151
162
  ? gitDirectory
152
163
  : resolve(worktreePath, gitDirectory);
153
- await writeFile(join(absoluteGitDirectory, 'CLAUDE_BASE'), `${originalHeadCommit}\n`);
164
+ await writeFile(join(absoluteGitDirectory, 'CLAUDE_BASE'), `${baseCommit}\n`);
154
165
  }
155
166
  catch (error) {
156
167
  await execFileAsync('git', ['-C', root, 'worktree', 'remove', '--force', worktreePath], {
@@ -3,6 +3,7 @@ import { type ContextAssembler } from '../core/context.js';
3
3
  import { type ModelProvider, type ModelToolCall, type ModelToolDefinition, type ModelUsage, type PermissionResolver, type PermissionApproval, type RuntimeEventSink, type ToolExecutionContext, type ToolExecutionResult, type ToolRegistry } from '../core/runtime.js';
4
4
  import type { ClaudeExtensionCatalog } from '../extensions/claude-extensions.js';
5
5
  import type { ClaudeHookRunner } from '../hooks/claude-hooks.js';
6
+ import { type BackgroundAgentSnapshot } from './background-agent-manager.js';
6
7
  export interface WorkflowAgentRunOptions {
7
8
  sessionId: string;
8
9
  promptId: string;
@@ -74,6 +75,8 @@ export declare class ClaudeSubagentExecutor {
74
75
  isEnabled(name: string): boolean;
75
76
  constructor(options: ClaudeSubagentExecutorOptions);
76
77
  close(): Promise<void>;
78
+ backgroundSnapshots(): readonly BackgroundAgentSnapshot[];
79
+ stopBackgroundTask(taskId: string): string;
77
80
  private cwd;
78
81
  registry(sessionId: string, depth: number, promptIdForCall: (callId: string) => string | null): ToolRegistry;
79
82
  definitions(): ModelToolDefinition;
@@ -176,6 +176,12 @@ export class ClaudeSubagentExecutor {
176
176
  await this.background.close();
177
177
  this.ephemeralSidechains.clear();
178
178
  }
179
+ backgroundSnapshots() {
180
+ return this.background.snapshots();
181
+ }
182
+ stopBackgroundTask(taskId) {
183
+ return this.background.stop(taskId);
184
+ }
179
185
  cwd() {
180
186
  return this.options.cwdProvider?.() ?? this.options.cwd;
181
187
  }
@@ -1,5 +1,6 @@
1
+ import { ClaudeWorkflowStore } from '../persistence/claude-workflow-store.js';
1
2
  import type { WorkflowAgentRunOptions, WorkflowAgentRunResult } from './subagent-service.js';
2
- import { parseWorkflowScript, type ParsedWorkflowScript } from './workflow-meta.js';
3
+ import { parseWorkflowScript, type ParsedWorkflowScript, type WorkflowMeta } from './workflow-meta.js';
3
4
  export interface WorkflowSource {
4
5
  script: string;
5
6
  parsed: ParsedWorkflowScript;
@@ -24,6 +25,71 @@ export interface WorkflowLaunchResult {
24
25
  scriptFile: string;
25
26
  transcriptDirectory: string;
26
27
  }
28
+ export interface WorkflowProgress {
29
+ index: number;
30
+ agentId: string;
31
+ label: string;
32
+ phase?: string;
33
+ status: 'running' | 'completed' | 'error';
34
+ cached?: boolean;
35
+ result?: unknown;
36
+ error?: string;
37
+ totalTokens: number;
38
+ toolCalls: number;
39
+ durationMs: number;
40
+ resolvedModel?: string;
41
+ requestedModel?: string;
42
+ requestedAgentType?: string;
43
+ queuedAt: number;
44
+ startedAt?: number;
45
+ promptPreview: string;
46
+ isolationPath?: string;
47
+ isolationRetained?: boolean;
48
+ isolationWarning?: string;
49
+ }
50
+ interface WorkflowTask {
51
+ taskId: string;
52
+ runId: string;
53
+ sessionId: string;
54
+ meta: WorkflowMeta;
55
+ script: string;
56
+ scriptFile: string;
57
+ transcriptDirectory: string;
58
+ store: ClaudeWorkflowStore;
59
+ args: unknown;
60
+ defaultModel: string;
61
+ startTime: number;
62
+ durationMs: number | null;
63
+ status: 'running' | 'completed' | 'failed' | 'killed';
64
+ result: unknown;
65
+ error?: string;
66
+ logs: string[];
67
+ phases: {
68
+ title: string;
69
+ detail?: string;
70
+ model?: string;
71
+ }[];
72
+ progress: WorkflowProgress[];
73
+ agentCount: number;
74
+ totalTokens: number;
75
+ totalInputTokens: number;
76
+ totalToolCalls: number;
77
+ controller: AbortController;
78
+ promise: Promise<void>;
79
+ notificationPending: boolean;
80
+ }
81
+ export interface WorkflowTaskSnapshot {
82
+ task_id: string;
83
+ task_type: 'local_workflow';
84
+ status: WorkflowTask['status'];
85
+ summary: string;
86
+ run_id: string;
87
+ progress: readonly WorkflowProgress[];
88
+ result: unknown;
89
+ startTime: number;
90
+ durationMs: number;
91
+ error?: string;
92
+ }
27
93
  export declare class WorkflowManager {
28
94
  private readonly configRoot;
29
95
  private readonly cwd;
@@ -32,11 +98,13 @@ export declare class WorkflowManager {
32
98
  private readonly activeRuns;
33
99
  launch(options: WorkflowLaunchOptions): Promise<WorkflowLaunchResult>;
34
100
  has(taskId: string): boolean;
101
+ hasForSession(sessionId: string, taskId: string): boolean;
35
102
  output(taskId: string, options: {
36
103
  block: boolean;
37
104
  timeout: number;
38
105
  }): Promise<string>;
39
106
  stop(taskId: string): string;
107
+ stopAndWait(taskId: string): Promise<void>;
40
108
  notifications(waitForRunning: boolean): Promise<{
41
109
  messages: string[];
42
110
  usage: {
@@ -44,7 +112,7 @@ export declare class WorkflowManager {
44
112
  outputTokens: number;
45
113
  };
46
114
  }>;
47
- list(): readonly Record<string, unknown>[];
115
+ list(sessionId?: string): readonly WorkflowTaskSnapshot[];
48
116
  abortAll(): void;
49
117
  close(): Promise<void>;
50
118
  constructor(configRoot: string, cwd: string, cwdProvider?: (() => string) | undefined);
@@ -130,6 +130,7 @@ export class WorkflowManager {
130
130
  args: structuredClone(options.args),
131
131
  defaultModel: options.defaultModel,
132
132
  startTime: Date.now(),
133
+ durationMs: null,
133
134
  status: 'running',
134
135
  result: null,
135
136
  logs: [],
@@ -167,6 +168,9 @@ export class WorkflowManager {
167
168
  has(taskId) {
168
169
  return this.tasks.has(taskId);
169
170
  }
171
+ hasForSession(sessionId, taskId) {
172
+ return this.tasks.get(taskId)?.sessionId === sessionId;
173
+ }
170
174
  async output(taskId, options) {
171
175
  const task = this.task(taskId);
172
176
  if (options.block && task.status === 'running') {
@@ -200,6 +204,14 @@ export class WorkflowManager {
200
204
  command: task.meta.description,
201
205
  });
202
206
  }
207
+ async stopAndWait(taskId) {
208
+ const task = this.task(taskId);
209
+ if (task.status !== 'running') {
210
+ throw new Error(`Task ${taskId} is not running (status: ${task.status})`);
211
+ }
212
+ task.controller.abort('TaskStop');
213
+ await task.promise;
214
+ }
203
215
  async notifications(waitForRunning) {
204
216
  if (waitForRunning) {
205
217
  await Promise.all([...this.tasks.values()]
@@ -222,8 +234,10 @@ export class WorkflowManager {
222
234
  usage: { inputTokens, outputTokens },
223
235
  };
224
236
  }
225
- list() {
226
- return [...this.tasks.values()].map((task) => this.summary(task));
237
+ list(sessionId) {
238
+ return [...this.tasks.values()]
239
+ .filter((task) => sessionId === undefined || task.sessionId === sessionId)
240
+ .map((task) => this.summary(task));
227
241
  }
228
242
  abortAll() {
229
243
  for (const task of this.tasks.values()) {
@@ -444,12 +458,13 @@ export class WorkflowManager {
444
458
  task.error = `${error instanceof Error ? (error.stack ?? error.message) : String(error)}`;
445
459
  }
446
460
  finally {
461
+ task.durationMs = Date.now() - task.startTime;
447
462
  task.notificationPending = true;
448
463
  await task.store.writeRun(this.runRecord(task));
449
464
  }
450
465
  }
451
466
  runRecord(task) {
452
- const durationMs = Date.now() - task.startTime;
467
+ const durationMs = task.durationMs ?? Date.now() - task.startTime;
453
468
  return {
454
469
  runId: task.runId,
455
470
  timestamp: new Date().toISOString(),
@@ -482,6 +497,8 @@ export class WorkflowManager {
482
497
  run_id: task.runId,
483
498
  progress: task.progress,
484
499
  result: task.result,
500
+ startTime: task.startTime,
501
+ durationMs: task.durationMs ?? Date.now() - task.startTime,
485
502
  ...(task.error ? { error: task.error } : {}),
486
503
  };
487
504
  }
@@ -558,7 +575,7 @@ export class WorkflowManager {
558
575
  `agents_empty_result: ${empty}`,
559
576
  `subagent_tokens: ${task.totalTokens}`,
560
577
  `tool_uses: ${task.totalToolCalls}`,
561
- `duration_ms: ${Date.now() - task.startTime}`,
578
+ `duration_ms: ${task.durationMs ?? Date.now() - task.startTime}`,
562
579
  '</usage>',
563
580
  '</task-notification>',
564
581
  ].join('\n');
@@ -1,4 +1,6 @@
1
+ import { type ReactElement } from 'react';
1
2
  import type { TopLevelAgentSummary } from '../application/top-level-agent-manager.js';
3
+ import { type TuiThemeSettings } from './tui/theme.js';
2
4
  export interface AgentsDashboardManager {
3
5
  launch(options: {
4
6
  prompt: string;
@@ -33,5 +35,12 @@ export declare function runAgentsDashboard(options: {
33
35
  manager: AgentsDashboardManager;
34
36
  defaults: AgentsDashboardDefaults;
35
37
  signal?: AbortSignal;
38
+ }, dependencies?: {
39
+ loadThemeSettings?: () => Promise<TuiThemeSettings>;
40
+ renderDashboard?: (element: ReactElement, options: {
41
+ exitOnCtrlC: boolean;
42
+ }) => {
43
+ waitUntilExit(): Promise<void>;
44
+ };
36
45
  }): Promise<number>;
37
46
  //# sourceMappingURL=agents-dashboard.d.ts.map
@@ -1,6 +1,8 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { useCallback, useEffect, useRef, useState, } from 'react';
3
3
  import { Box, Text, render, useApp, useInput } from 'ink';
4
+ import { loadTuiThemeSettings } from './tui/theme-settings.js';
5
+ import { DEFAULT_TUI_THEME_SETTINGS, TuiThemeProvider, useTuiPalette, } from './tui/theme.js';
4
6
  const DASHBOARD_SECTIONS = [
5
7
  'Ready for review',
6
8
  'Needs input',
@@ -72,10 +74,12 @@ function groupAgents(agents) {
72
74
  return DASHBOARD_SECTIONS.flatMap((section) => agents.filter((agent) => sectionFor(agent) === section));
73
75
  }
74
76
  function AgentSection({ title, agents, selected, }) {
75
- return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { bold: true, children: [title, " (", agents.length, ")"] }), agents.length === 0 ? (_jsx(Text, { dimColor: true, children: " None" })) : (agents.map((agent) => (_jsxs(Text, { ...(agent === selected ? { color: 'cyan' } : {}), children: [agent === selected ? '› ' : ' ', agent.name, " \u00B7 ", agentStatus(agent), " \u00B7 ", agentKey(agent)] }, agentKey(agent)))))] }));
77
+ const palette = useTuiPalette();
78
+ return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { bold: true, children: [title, " (", agents.length, ")"] }), agents.length === 0 ? (_jsx(Text, { dimColor: true, children: " None" })) : (agents.map((agent) => (_jsxs(Text, { ...(agent === selected ? { color: palette.accent } : {}), children: [agent === selected ? '› ' : ' ', agent.name, " \u00B7 ", agentStatus(agent), " \u00B7 ", agentKey(agent)] }, agentKey(agent)))))] }));
76
79
  }
77
80
  export function AgentsDashboardApp({ manager, defaults, signal, refreshIntervalMs = 1_000, onCancel, }) {
78
81
  const { exit } = useApp();
82
+ const palette = useTuiPalette();
79
83
  const [agents, setAgents] = useState([]);
80
84
  const [selectedIndex, setSelectedIndex] = useState(0);
81
85
  const selectedIndexRef = useRef(0);
@@ -410,14 +414,21 @@ export function AgentsDashboardApp({ manager, defaults, signal, refreshIntervalM
410
414
  editInput();
411
415
  });
412
416
  const selected = agents[selectedIndex];
413
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, color: "cyan", children: "Praxis agents" }), _jsxs(Text, { dimColor: true, children: [agents.length, " sessions \u00B7 live refresh"] }), DASHBOARD_SECTIONS.map((title) => (_jsx(AgentSection, { title: title, agents: agents.filter((agent) => sectionFor(agent) === title), ...(selected === undefined ? {} : { selected }) }, title))), mode === 'attach' ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["Attached to ", attachedId] }), attachedOutput ? (_jsx(Text, { children: attachedOutput })) : (_jsx(Text, { dimColor: true, children: "Waiting for output\u2026" })), _jsxs(Text, { children: ["\u203A ", input] }), _jsx(Text, { dimColor: true, children: "Enter sends \u00B7 Esc detaches \u00B7 Ctrl+C exits" })] })) : mode === 'review' ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["Reviewing ", reviewAgent ? agentKey(reviewAgent) : ''] }), _jsx(Text, { children: attachedOutput || 'No review output.' }), _jsxs(Text, { children: ["\u203A ", input] }), _jsx(Text, { dimColor: true, children: "Enter resumes with prompt \u00B7 Esc returns to list" })] })) : (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["\u203A ", input || 'describe a task for a new background agent'] }), _jsx(Text, { dimColor: true, children: "Enter dispatches \u00B7 \u2191/\u2193 select \u00B7 Enter empty attaches \u00B7 Ctrl+X stops \u00B7 Ctrl+R refreshes \u00B7 ? help \u00B7 Esc exits" }), selected ? (_jsxs(Text, { dimColor: true, children: ["Selected ", agentKey(selected)] })) : null] })), busy ? _jsx(Text, { dimColor: true, children: "Working\u2026" }) : null, notice ? _jsx(Text, { color: "yellow", children: notice }) : null, showHelp ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { bold: true, children: "Shortcuts" }), _jsx(Text, { children: "Enter dispatches or attaches \u00B7 Esc detaches/exits \u00B7 Ctrl+X stops local background agents \u00B7 Ctrl+R refreshes \u00B7 ? closes help" })] })) : null] }));
417
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, color: palette.accent, children: "Praxis agents" }), _jsxs(Text, { dimColor: true, children: [agents.length, " sessions \u00B7 live refresh"] }), DASHBOARD_SECTIONS.map((title) => (_jsx(AgentSection, { title: title, agents: agents.filter((agent) => sectionFor(agent) === title), ...(selected === undefined ? {} : { selected }) }, title))), mode === 'attach' ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["Attached to ", attachedId] }), attachedOutput ? (_jsx(Text, { children: attachedOutput })) : (_jsx(Text, { dimColor: true, children: "Waiting for output\u2026" })), _jsxs(Text, { children: ["\u203A ", input] }), _jsx(Text, { dimColor: true, children: "Enter sends \u00B7 Esc detaches \u00B7 Ctrl+C exits" })] })) : mode === 'review' ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["Reviewing ", reviewAgent ? agentKey(reviewAgent) : ''] }), _jsx(Text, { children: attachedOutput || 'No review output.' }), _jsxs(Text, { children: ["\u203A ", input] }), _jsx(Text, { dimColor: true, children: "Enter resumes with prompt \u00B7 Esc returns to list" })] })) : (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["\u203A ", input || 'describe a task for a new background agent'] }), _jsx(Text, { dimColor: true, children: "Enter dispatches \u00B7 \u2191/\u2193 select \u00B7 Enter empty attaches \u00B7 Ctrl+X stops \u00B7 Ctrl+R refreshes \u00B7 ? help \u00B7 Esc exits" }), selected ? (_jsxs(Text, { dimColor: true, children: ["Selected ", agentKey(selected)] })) : null] })), busy ? _jsx(Text, { dimColor: true, children: "Working\u2026" }) : null, notice ? _jsx(Text, { color: palette.warning, children: notice }) : null, showHelp ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { bold: true, children: "Shortcuts" }), _jsx(Text, { children: "Enter dispatches or attaches \u00B7 Esc detaches/exits \u00B7 Ctrl+X stops local background agents \u00B7 Ctrl+R refreshes \u00B7 ? closes help" })] })) : null] }));
414
418
  }
415
- export async function runAgentsDashboard(options) {
419
+ export async function runAgentsDashboard(options, dependencies = {}) {
416
420
  const controller = new AbortController();
417
421
  const signal = options.signal
418
422
  ? AbortSignal.any([options.signal, controller.signal])
419
423
  : controller.signal;
420
- const instance = render(_jsx(AgentsDashboardApp, { manager: options.manager, defaults: options.defaults, signal: signal, onCancel: () => controller.abort() }), { exitOnCtrlC: false });
424
+ let settings = DEFAULT_TUI_THEME_SETTINGS;
425
+ try {
426
+ settings = await (dependencies.loadThemeSettings ?? loadTuiThemeSettings)();
427
+ }
428
+ catch {
429
+ // A corrupt shared settings file must not make the standalone dashboard unusable.
430
+ }
431
+ const instance = (dependencies.renderDashboard ?? render)(_jsx(TuiThemeProvider, { settings: settings, children: _jsx(AgentsDashboardApp, { manager: options.manager, defaults: options.defaults, signal: signal, onCancel: () => controller.abort() }) }), { exitOnCtrlC: false });
421
432
  await instance.waitUntilExit();
422
433
  return signal.aborted ? 130 : 0;
423
434
  }