praxis-agent 0.7.0 → 0.8.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 +165 -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
@@ -0,0 +1,132 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { setTimeout } from 'node:timers/promises';
6
+ import { writeFileAtomically } from '../../platform/atomic-write.js';
7
+ import { ExclusiveFileLease, } from '../../platform/exclusive-file-lease.js';
8
+ import { DEFAULT_TUI_THEME_SETTINGS, TUI_THEMES, } from './theme.js';
9
+ import { loadTuiCustomThemes } from './custom-themes.js';
10
+ function isRecord(value) {
11
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
12
+ }
13
+ function configRootPath() {
14
+ return process.env.CLAUDE_CONFIG_DIR ?? join(homedir(), '.claude');
15
+ }
16
+ async function readSettings(path) {
17
+ try {
18
+ const source = await readFile(path, 'utf8');
19
+ const value = JSON.parse(source);
20
+ if (!isRecord(value))
21
+ throw new Error(`JSON root must be an object: ${path}`);
22
+ return { value, fingerprint: fingerprint(source) };
23
+ }
24
+ catch (error) {
25
+ if (error.code === 'ENOENT')
26
+ return { value: {}, fingerprint: fingerprint() };
27
+ if (error instanceof SyntaxError)
28
+ throw new Error(`Invalid JSON: ${path}`, { cause: error });
29
+ throw error;
30
+ }
31
+ }
32
+ function fingerprint(source) {
33
+ return source === undefined
34
+ ? 'missing'
35
+ : createHash('sha256').update(source).digest('hex');
36
+ }
37
+ async function fingerprintUnchanged(path, expected) {
38
+ try {
39
+ return fingerprint(await readFile(path, 'utf8')) === expected;
40
+ }
41
+ catch (error) {
42
+ if (error.code === 'ENOENT')
43
+ return expected === fingerprint();
44
+ throw error;
45
+ }
46
+ }
47
+ function settingsFromRecord(value, customTheme) {
48
+ const configuredTheme = value.theme;
49
+ const theme = TUI_THEMES.includes(configuredTheme)
50
+ ? configuredTheme
51
+ : typeof configuredTheme === 'string' &&
52
+ /^custom:[a-z0-9]+(?:-[a-z0-9]+)*$/u.test(configuredTheme) &&
53
+ customTheme?.slug === configuredTheme.slice('custom:'.length)
54
+ ? configuredTheme
55
+ : DEFAULT_TUI_THEME_SETTINGS.theme;
56
+ return {
57
+ theme,
58
+ syntaxHighlightingDisabled: typeof value.syntaxHighlightingDisabled === 'boolean'
59
+ ? value.syntaxHighlightingDisabled
60
+ : DEFAULT_TUI_THEME_SETTINGS.syntaxHighlightingDisabled,
61
+ ...(customTheme === undefined ? {} : { customTheme }),
62
+ };
63
+ }
64
+ export function themeSettingsWithCustomTheme(settings, customThemes) {
65
+ if (!settings.theme.startsWith('custom:'))
66
+ return settings;
67
+ const customTheme = customThemes.find((theme) => `custom:${theme.slug}` === settings.theme);
68
+ return customTheme === undefined ? settings : { ...settings, customTheme };
69
+ }
70
+ export async function loadTuiThemeSettings(configRoot = configRootPath()) {
71
+ const { value } = await readSettings(join(configRoot, 'settings.json'));
72
+ const configured = value.theme;
73
+ const customSlug = typeof configured === 'string' && configured.startsWith('custom:')
74
+ ? configured.slice('custom:'.length)
75
+ : undefined;
76
+ const customTheme = customSlug
77
+ ? (await loadTuiCustomThemes(configRoot)).find((theme) => theme.slug === customSlug)
78
+ : undefined;
79
+ return settingsFromRecord(value, customTheme);
80
+ }
81
+ export async function saveTuiThemeSettings(update, configRoot = configRootPath(), hooks = {}) {
82
+ const path = join(configRoot, 'settings.json');
83
+ const lease = new ExclusiveFileLease(join(configRoot, '.praxis-settings.lock'));
84
+ let handle = null;
85
+ for (let attempt = 0; attempt < 400; attempt += 1) {
86
+ handle = await lease.tryAcquire();
87
+ if (handle)
88
+ break;
89
+ await setTimeout(5);
90
+ }
91
+ if (!handle)
92
+ throw new Error(`Settings write lock timed out: ${path}`);
93
+ try {
94
+ for (let attempt = 0; attempt < 3; attempt += 1) {
95
+ const { value, fingerprint: expectedFingerprint } = await readSettings(path);
96
+ const selectedTheme = update.theme ?? value.theme;
97
+ const customTheme = typeof selectedTheme === 'string' && selectedTheme.startsWith('custom:')
98
+ ? (await loadTuiCustomThemes(configRoot)).find((theme) => theme.slug === selectedTheme.slice('custom:'.length))
99
+ : undefined;
100
+ if (typeof selectedTheme === 'string' &&
101
+ selectedTheme.startsWith('custom:') &&
102
+ customTheme === undefined) {
103
+ throw new Error(`Custom theme is not available: ${selectedTheme}`);
104
+ }
105
+ const next = {
106
+ ...settingsFromRecord(value, customTheme),
107
+ ...update,
108
+ ...(customTheme === undefined ? {} : { customTheme }),
109
+ };
110
+ const persisted = { ...value };
111
+ if (update.theme !== undefined)
112
+ persisted.theme = update.theme;
113
+ if (update.syntaxHighlightingDisabled !== undefined)
114
+ persisted.syntaxHighlightingDisabled = update.syntaxHighlightingDisabled;
115
+ const committed = await writeFileAtomically(path, `${JSON.stringify(persisted, null, 2)}\n`, {
116
+ beforeCommit: async () => {
117
+ if (!(await fingerprintUnchanged(path, expectedFingerprint)))
118
+ return false;
119
+ await hooks.afterValidation?.();
120
+ return fingerprintUnchanged(path, expectedFingerprint);
121
+ },
122
+ });
123
+ if (committed)
124
+ return next;
125
+ }
126
+ throw new Error(`Settings changed concurrently: ${path}`);
127
+ }
128
+ finally {
129
+ await handle.release();
130
+ }
131
+ }
132
+ //# sourceMappingURL=theme-settings.js.map
@@ -0,0 +1,53 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { TuiCustomTheme } from './custom-themes.js';
3
+ export declare const TUI_THEMES: readonly ["auto", "dark", "light", "dark-daltonized", "light-daltonized", "dark-ansi", "light-ansi"];
4
+ export type TuiTheme = (typeof TUI_THEMES)[number];
5
+ export type TuiThemeSetting = TuiTheme | `custom:${string}`;
6
+ export interface TuiThemeSettings {
7
+ theme: TuiThemeSetting;
8
+ syntaxHighlightingDisabled: boolean;
9
+ customTheme?: TuiCustomTheme;
10
+ }
11
+ export interface TuiSyntaxPalette {
12
+ text: string;
13
+ keyword: string;
14
+ identifier: string;
15
+ string: string;
16
+ removedBackground?: string;
17
+ addedBackground?: string;
18
+ addedHighlight?: string;
19
+ }
20
+ export interface TuiPalette {
21
+ profile: TuiTheme;
22
+ dark: boolean;
23
+ ansiOnly: boolean;
24
+ syntaxHighlightingDisabled: boolean;
25
+ brand: string;
26
+ accent: string;
27
+ info: string;
28
+ link: string;
29
+ error: string;
30
+ success: string;
31
+ warning: string;
32
+ muted: string;
33
+ selectionText: string;
34
+ syntaxTheme: 'Monokai Extended' | 'GitHub' | 'ansi';
35
+ syntax: TuiSyntaxPalette;
36
+ }
37
+ export type TuiSyntaxToken = 'text' | 'keyword' | 'identifier' | 'string';
38
+ export type TerminalColorCapability = 'ansi16' | 'ansi256' | 'truecolor';
39
+ type TerminalEnvironment = Readonly<Record<string, string | undefined>>;
40
+ export declare function tuiSyntaxStyle(palette: TuiPalette, token: TuiSyntaxToken, change?: 'added' | 'removed'): {
41
+ color?: string;
42
+ backgroundColor?: string;
43
+ };
44
+ export declare const DEFAULT_TUI_THEME_SETTINGS: TuiThemeSettings;
45
+ export declare function terminalColorCapability(environment?: TerminalEnvironment): TerminalColorCapability;
46
+ export declare function tuiPalette(profile: TuiTheme, syntaxHighlightingDisabled?: boolean, environment?: TerminalEnvironment, customTheme?: TuiCustomTheme): TuiPalette;
47
+ export declare function TuiThemeProvider({ settings, children, }: {
48
+ settings: TuiThemeSettings;
49
+ children: ReactNode;
50
+ }): import("react").JSX.Element;
51
+ export declare function useTuiPalette(): TuiPalette;
52
+ export {};
53
+ //# sourceMappingURL=theme.d.ts.map
@@ -0,0 +1,265 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext } from 'react';
3
+ export const TUI_THEMES = [
4
+ 'auto',
5
+ 'dark',
6
+ 'light',
7
+ 'dark-daltonized',
8
+ 'light-daltonized',
9
+ 'dark-ansi',
10
+ 'light-ansi',
11
+ ];
12
+ export function tuiSyntaxStyle(palette, token, change) {
13
+ if (palette.syntaxHighlightingDisabled)
14
+ return {};
15
+ const backgroundColor = change === 'added'
16
+ ? palette.syntax.addedBackground
17
+ : change === 'removed'
18
+ ? palette.syntax.removedBackground
19
+ : undefined;
20
+ return {
21
+ color: palette.syntax[token],
22
+ ...(backgroundColor === undefined ? {} : { backgroundColor }),
23
+ };
24
+ }
25
+ export const DEFAULT_TUI_THEME_SETTINGS = {
26
+ theme: 'auto',
27
+ syntaxHighlightingDisabled: false,
28
+ };
29
+ const DARK_SYNTAX = {
30
+ text: '#ffffff',
31
+ keyword: '#5fd7ff',
32
+ identifier: '#afd700',
33
+ string: '#d7d787',
34
+ removedBackground: '#5f0000',
35
+ addedBackground: '#005f00',
36
+ addedHighlight: '#008700',
37
+ };
38
+ const LIGHT_SYNTAX = {
39
+ text: '#303030',
40
+ keyword: '#af005f',
41
+ identifier: '#875faf',
42
+ string: '#005f87',
43
+ removedBackground: '#ffd7d7',
44
+ addedBackground: '#d7ffd7',
45
+ addedHighlight: '#afffaf',
46
+ };
47
+ function automaticDark(environment) {
48
+ const background = environment.COLORFGBG?.split(';').at(-1);
49
+ return background === undefined || Number(background) < 8;
50
+ }
51
+ export function terminalColorCapability(environment = process.env) {
52
+ if (environment.FORCE_COLOR === '3')
53
+ return 'truecolor';
54
+ if (environment.FORCE_COLOR === '2')
55
+ return 'ansi256';
56
+ if (environment.FORCE_COLOR === '1')
57
+ return 'ansi16';
58
+ if (/^(?:truecolor|24bit)$/iu.test(environment.COLORTERM ?? ''))
59
+ return 'truecolor';
60
+ if (/(?:direct|truecolor|24bit)/iu.test(environment.TERM ?? ''))
61
+ return 'truecolor';
62
+ if (/(?:iTerm\.app|WezTerm|ghostty|vscode|Hyper)/iu.test(environment.TERM_PROGRAM ?? ''))
63
+ return 'truecolor';
64
+ return /256color/iu.test(environment.TERM ?? '') ? 'ansi256' : 'ansi16';
65
+ }
66
+ const ANSI_256_LEVELS = [0, 95, 135, 175, 215, 255];
67
+ const ansi256ColorCache = new Map();
68
+ const ANSI_16_COLORS = {
69
+ '#ffffff': 'whiteBright',
70
+ '#5fd7ff': 'cyanBright',
71
+ '#afd700': 'yellowBright',
72
+ '#d7d787': 'whiteBright',
73
+ '#5f0000': 'black',
74
+ '#005f00': 'black',
75
+ '#008700': 'green',
76
+ '#d97757': 'redBright',
77
+ '#b8a1ff': 'whiteBright',
78
+ '#5fafff': 'cyanBright',
79
+ '#ff5f5f': 'redBright',
80
+ '#5fd75f': 'greenBright',
81
+ '#ffd75f': 'yellowBright',
82
+ '#a8a8a8': 'white',
83
+ '#303030': 'black',
84
+ '#af005f': 'red',
85
+ '#875faf': 'magenta',
86
+ '#005f87': 'blue',
87
+ '#ffd7d7': 'whiteBright',
88
+ '#d7ffd7': 'whiteBright',
89
+ '#afffaf': 'whiteBright',
90
+ '#005faf': 'blue',
91
+ '#af0000': 'red',
92
+ '#875f00': 'red',
93
+ '#585858': 'black',
94
+ };
95
+ function ansi16Color(hex) {
96
+ return ANSI_16_COLORS[hex.toLowerCase()] ?? hex;
97
+ }
98
+ function ansi256Color(hex) {
99
+ const cached = ansi256ColorCache.get(hex);
100
+ if (cached)
101
+ return cached;
102
+ const match = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/iu.exec(hex);
103
+ if (!match)
104
+ return hex;
105
+ const rgb = [
106
+ Number.parseInt(match[1] ?? '', 16),
107
+ Number.parseInt(match[2] ?? '', 16),
108
+ Number.parseInt(match[3] ?? '', 16),
109
+ ];
110
+ let bestIndex = 0;
111
+ let bestDistance = Number.POSITIVE_INFINITY;
112
+ for (const [red, redLevel] of ANSI_256_LEVELS.entries()) {
113
+ for (const [green, greenLevel] of ANSI_256_LEVELS.entries()) {
114
+ for (const [blue, blueLevel] of ANSI_256_LEVELS.entries()) {
115
+ const distance = (rgb[0] - redLevel) ** 2 +
116
+ (rgb[1] - greenLevel) ** 2 +
117
+ (rgb[2] - blueLevel) ** 2;
118
+ if (distance < bestDistance) {
119
+ bestDistance = distance;
120
+ bestIndex = 16 + red * 36 + green * 6 + blue;
121
+ }
122
+ }
123
+ }
124
+ }
125
+ for (let index = 232; index <= 255; index += 1) {
126
+ const level = 8 + (index - 232) * 10;
127
+ const distance = rgb.reduce((total, component) => total + (component - level) ** 2, 0);
128
+ if (distance < bestDistance) {
129
+ bestDistance = distance;
130
+ bestIndex = index;
131
+ }
132
+ }
133
+ const color = `ansi256(${bestIndex})`;
134
+ ansi256ColorCache.set(hex, color);
135
+ return color;
136
+ }
137
+ function adaptSyntaxColors(syntax, adapt) {
138
+ return {
139
+ text: adapt(syntax.text),
140
+ keyword: adapt(syntax.keyword),
141
+ identifier: adapt(syntax.identifier),
142
+ string: adapt(syntax.string),
143
+ ...(syntax.removedBackground === undefined
144
+ ? {}
145
+ : { removedBackground: adapt(syntax.removedBackground) }),
146
+ ...(syntax.addedBackground === undefined
147
+ ? {}
148
+ : { addedBackground: adapt(syntax.addedBackground) }),
149
+ ...(syntax.addedHighlight === undefined
150
+ ? {}
151
+ : { addedHighlight: adapt(syntax.addedHighlight) }),
152
+ };
153
+ }
154
+ export function tuiPalette(profile, syntaxHighlightingDisabled = false, environment = process.env, customTheme) {
155
+ const dark = profile === 'auto'
156
+ ? automaticDark(environment)
157
+ : profile === 'dark' ||
158
+ profile === 'dark-daltonized' ||
159
+ profile === 'dark-ansi';
160
+ const ansiOnly = profile.endsWith('-ansi');
161
+ const daltonized = profile.endsWith('-daltonized');
162
+ const syntaxBase = ansiOnly
163
+ ? {
164
+ text: dark ? 'white' : 'black',
165
+ keyword: 'cyanBright',
166
+ identifier: 'yellowBright',
167
+ string: 'greenBright',
168
+ }
169
+ : dark
170
+ ? {
171
+ ...DARK_SYNTAX,
172
+ ...(daltonized
173
+ ? {
174
+ addedBackground: '#00005f',
175
+ addedHighlight: '#005f87',
176
+ }
177
+ : {}),
178
+ }
179
+ : {
180
+ ...LIGHT_SYNTAX,
181
+ ...(daltonized
182
+ ? {
183
+ addedBackground: '#d7ffff',
184
+ addedHighlight: '#afd7ff',
185
+ }
186
+ : {}),
187
+ };
188
+ const terminalCapability = terminalColorCapability(environment);
189
+ const adaptAutoColor = terminalCapability === 'ansi16'
190
+ ? ansi16Color
191
+ : terminalCapability === 'ansi256'
192
+ ? ansi256Color
193
+ : (color) => color;
194
+ const syntax = profile === 'auto'
195
+ ? adaptSyntaxColors(syntaxBase, adaptAutoColor)
196
+ : syntaxBase;
197
+ const autoColor = (color) => profile === 'auto' ? adaptAutoColor(color) : color;
198
+ const palette = {
199
+ profile,
200
+ dark,
201
+ ansiOnly,
202
+ syntaxHighlightingDisabled,
203
+ brand: ansiOnly ? 'redBright' : autoColor('#D97757'),
204
+ accent: ansiOnly
205
+ ? 'magentaBright'
206
+ : daltonized
207
+ ? dark
208
+ ? '#5fd7ff'
209
+ : '#005f87'
210
+ : dark
211
+ ? autoColor('#B8A1FF')
212
+ : autoColor('#875faf'),
213
+ info: ansiOnly ? 'cyanBright' : autoColor(dark ? '#5fd7ff' : '#005f87'),
214
+ link: ansiOnly ? 'blueBright' : autoColor(dark ? '#5fafff' : '#005faf'),
215
+ error: ansiOnly ? 'redBright' : autoColor(dark ? '#ff5f5f' : '#af0000'),
216
+ success: ansiOnly ? 'greenBright' : autoColor(dark ? '#5fd75f' : '#008700'),
217
+ warning: ansiOnly
218
+ ? 'yellowBright'
219
+ : autoColor(dark ? '#ffd75f' : '#875f00'),
220
+ muted: ansiOnly
221
+ ? dark
222
+ ? 'white'
223
+ : 'black'
224
+ : autoColor(dark ? '#a8a8a8' : '#585858'),
225
+ selectionText: dark ? 'black' : 'white',
226
+ syntaxTheme: ansiOnly ? 'ansi' : dark ? 'Monokai Extended' : 'GitHub',
227
+ syntax,
228
+ };
229
+ if (customTheme) {
230
+ const overrides = customTheme.overrides;
231
+ const override = (token, fallback) => overrides[token] ?? fallback;
232
+ palette.brand = override('claude', palette.brand);
233
+ palette.accent = override('suggestion', palette.accent);
234
+ palette.info = override('professionalBlue', palette.info);
235
+ palette.link = override('ide', palette.link);
236
+ palette.error = override('error', palette.error);
237
+ palette.success = override('success', palette.success);
238
+ palette.warning = override('warning', palette.warning);
239
+ palette.muted = override('inactive', palette.muted);
240
+ palette.selectionText = override('inverseText', palette.selectionText);
241
+ palette.syntax = {
242
+ ...palette.syntax,
243
+ text: override('text', palette.syntax.text),
244
+ keyword: override('claudeBlue_FOR_SYSTEM_SPINNER', palette.syntax.keyword),
245
+ identifier: override('suggestion', palette.syntax.identifier),
246
+ string: override('success', palette.syntax.string),
247
+ removedBackground: override('diffRemoved', palette.syntax.removedBackground ?? ''),
248
+ addedBackground: override('diffAdded', palette.syntax.addedBackground ?? ''),
249
+ addedHighlight: override('diffAddedWord', palette.syntax.addedHighlight ?? ''),
250
+ };
251
+ palette.profile = customTheme.base;
252
+ }
253
+ return palette;
254
+ }
255
+ const TuiPaletteContext = createContext(tuiPalette('auto'));
256
+ export function TuiThemeProvider({ settings, children, }) {
257
+ const baseTheme = TUI_THEMES.includes(settings.theme)
258
+ ? settings.theme
259
+ : 'dark';
260
+ return (_jsx(TuiPaletteContext.Provider, { value: tuiPalette(baseTheme, settings.syntaxHighlightingDisabled, process.env, settings.customTheme), children: children }));
261
+ }
262
+ export function useTuiPalette() {
263
+ return useContext(TuiPaletteContext);
264
+ }
265
+ //# sourceMappingURL=theme.js.map
package/dist/cli.d.ts CHANGED
@@ -6,6 +6,7 @@ import type { InteractiveResumeOptions, InteractiveServiceFactory } from './cli/
6
6
  import type { TuiSlashCommand } from './cli/tui/slash-commands.js';
7
7
  import { type TuiHookConfiguration } from './cli/tui/hook-settings.js';
8
8
  import { type ClaudePermissionMode } from './permissions/claude-permission-resolver.js';
9
+ import { type ClaudeMcpServerStatus, type ClaudeMcpToolInspection } from './mcp/claude-mcp-tools.js';
9
10
  import { authenticateMcpServer } from './mcp/claude-mcp-oauth.js';
10
11
  import { servePraxisMcpStdio } from './mcp/praxis-mcp-server.js';
11
12
  import { parseContextEnvironment, parseProviderEnvironment } from './providers/environment.js';
@@ -35,6 +36,8 @@ interface SessionCommands {
35
36
  rewindPoints?(sessionId: string): Promise<RewindPoint[]>;
36
37
  changeCwd?(sessionId: string | undefined, cwd: string): Promise<string>;
37
38
  recordCdUsage?(sessionId: string): Promise<void>;
39
+ approveRecentlyDenied?(sessionId: string, display: string): Promise<void>;
40
+ retryRecentlyDenied?(sessionId: string, display: string, signal?: AbortSignal): Promise<SessionRunResult>;
38
41
  answerSideQuestion?(sessionId: string | undefined, question: string, signal?: AbortSignal, onDelta?: (delta: string) => void, permissionMode?: ClaudePermissionMode): Promise<SideQuestionResult>;
39
42
  recordBtwUsage?(sessionId: string | undefined, permissionMode?: ClaudePermissionMode): Promise<string>;
40
43
  recordBackgroundUsage?(sessionId: string | undefined, permissionMode?: ClaudePermissionMode): Promise<string>;
@@ -57,6 +60,11 @@ interface SessionCommands {
57
60
  } | null>;
58
61
  slashCommands?(): readonly TuiSlashCommand[];
59
62
  hookConfiguration?(): Promise<TuiHookConfiguration>;
63
+ mcpInspect?(): Promise<readonly ClaudeMcpServerStatus[]>;
64
+ mcpReconnect?(name: string): Promise<void>;
65
+ mcpAuthenticate?(name: string): Promise<void>;
66
+ mcpReload?(): Promise<void>;
67
+ mcpTools?(name: string): Promise<readonly ClaudeMcpToolInspection[]>;
60
68
  close?(): Promise<void>;
61
69
  runtimeInfo?(): CliRuntimeInfo;
62
70
  agentDefinitions?(): readonly {
@@ -98,6 +106,7 @@ export interface CliDependencies extends InteractiveServiceFactory {
98
106
  model?: string;
99
107
  effort?: CliControls['effort'];
100
108
  permissionMode?: ClaudePermissionMode;
109
+ isSessionActionApproved?: (call: ModelToolCall) => boolean;
101
110
  controls?: CliControls;
102
111
  interactive?: boolean;
103
112
  sessionKind?: 'bg';