praxis-agent 0.6.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 (303) hide show
  1. package/README.md +10 -1
  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 +44 -3
  19. package/dist/cli/interactive.js +1431 -189
  20. package/dist/cli/tui/claude-style.d.ts +41 -3
  21. package/dist/cli/tui/claude-style.js +227 -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/hook-settings.d.ts +33 -0
  31. package/dist/cli/tui/hook-settings.js +200 -0
  32. package/dist/cli/tui/keybindings.js +0 -1
  33. package/dist/cli/tui/mcp-panel-controller.d.ts +32 -0
  34. package/dist/cli/tui/mcp-panel-controller.js +80 -0
  35. package/dist/cli/tui/mcp-panel-projector.d.ts +79 -0
  36. package/dist/cli/tui/mcp-panel-projector.js +181 -0
  37. package/dist/cli/tui/mcp-panel.d.ts +8 -0
  38. package/dist/cli/tui/mcp-panel.js +99 -0
  39. package/dist/cli/tui/recently-denied.d.ts +15 -0
  40. package/dist/cli/tui/recently-denied.js +19 -0
  41. package/dist/cli/tui/runtime-interactions.d.ts +17 -0
  42. package/dist/cli/tui/runtime-interactions.js +100 -0
  43. package/dist/cli/tui/runtime-settings.d.ts +40 -0
  44. package/dist/cli/tui/runtime-settings.js +84 -0
  45. package/dist/cli/tui/slash-commands.js +15 -0
  46. package/dist/cli/tui/task-panel.d.ts +53 -0
  47. package/dist/cli/tui/task-panel.js +204 -0
  48. package/dist/cli/tui/terminal-notifications.d.ts +10 -0
  49. package/dist/cli/tui/terminal-notifications.js +48 -0
  50. package/dist/cli/tui/terminal-setup.d.ts +24 -0
  51. package/dist/cli/tui/terminal-setup.js +618 -0
  52. package/dist/cli/tui/theme-settings.d.ts +8 -0
  53. package/dist/cli/tui/theme-settings.js +132 -0
  54. package/dist/cli/tui/theme.d.ts +53 -0
  55. package/dist/cli/tui/theme.js +265 -0
  56. package/dist/cli.d.ts +12 -0
  57. package/dist/cli.js +140 -21
  58. package/dist/compatibility/claude/schema.js +2 -0
  59. package/dist/compatibility/claude/shared-resources.d.ts +2 -0
  60. package/dist/core/runtime.d.ts +12 -0
  61. package/dist/core/runtime.js +24 -0
  62. package/dist/maintenance/self-update.js +1 -1
  63. package/dist/mcp/claude-mcp-management.d.ts +6 -1
  64. package/dist/mcp/claude-mcp-management.js +191 -44
  65. package/dist/mcp/claude-mcp-oauth.js +2 -0
  66. package/dist/mcp/claude-mcp-tools.d.ts +31 -3
  67. package/dist/mcp/claude-mcp-tools.js +116 -34
  68. package/dist/permissions/claude-permission-resolver.d.ts +3 -0
  69. package/dist/permissions/claude-permission-resolver.js +42 -20
  70. package/dist/platform/claude-version.js +2 -1
  71. package/dist/plugins/claude-plugin-runtime.d.ts +1 -0
  72. package/dist/plugins/claude-plugin-runtime.js +60 -24
  73. package/dist/tools/claude-interactive-tools.d.ts +7 -0
  74. package/dist/tools/claude-interactive-tools.js +21 -8
  75. package/dist/tools/claude-task-tools.d.ts +4 -0
  76. package/dist/tools/claude-task-tools.js +7 -0
  77. package/package.json +2 -1
  78. package/dist/application/background-agent-manager.d.ts.map +0 -1
  79. package/dist/application/background-agent-manager.js.map +0 -1
  80. package/dist/application/background-bash-manager.d.ts.map +0 -1
  81. package/dist/application/background-bash-manager.js.map +0 -1
  82. package/dist/application/background-task-id.d.ts.map +0 -1
  83. package/dist/application/background-task-id.js.map +0 -1
  84. package/dist/application/claude-project-purge.d.ts.map +0 -1
  85. package/dist/application/claude-project-purge.js.map +0 -1
  86. package/dist/application/managed-worktree.d.ts.map +0 -1
  87. package/dist/application/managed-worktree.js.map +0 -1
  88. package/dist/application/model-compactor.d.ts.map +0 -1
  89. package/dist/application/model-compactor.js.map +0 -1
  90. package/dist/application/scheduled-prompt-manager.d.ts.map +0 -1
  91. package/dist/application/scheduled-prompt-manager.js.map +0 -1
  92. package/dist/application/session-service.d.ts.map +0 -1
  93. package/dist/application/session-service.js.map +0 -1
  94. package/dist/application/session-worktree.d.ts.map +0 -1
  95. package/dist/application/session-worktree.js.map +0 -1
  96. package/dist/application/subagent-service.d.ts.map +0 -1
  97. package/dist/application/subagent-service.js.map +0 -1
  98. package/dist/application/tool-use-summary.d.ts.map +0 -1
  99. package/dist/application/tool-use-summary.js.map +0 -1
  100. package/dist/application/top-level-agent-manager.d.ts.map +0 -1
  101. package/dist/application/top-level-agent-manager.js.map +0 -1
  102. package/dist/application/workflow-manager.d.ts.map +0 -1
  103. package/dist/application/workflow-manager.js.map +0 -1
  104. package/dist/application/workflow-meta.d.ts.map +0 -1
  105. package/dist/application/workflow-meta.js.map +0 -1
  106. package/dist/application/workflow-runtime.d.ts.map +0 -1
  107. package/dist/application/workflow-runtime.js.map +0 -1
  108. package/dist/application/workflow-worktree.d.ts.map +0 -1
  109. package/dist/application/workflow-worktree.js.map +0 -1
  110. package/dist/cli/agents-dashboard.d.ts.map +0 -1
  111. package/dist/cli/agents-dashboard.js.map +0 -1
  112. package/dist/cli/controls.d.ts.map +0 -1
  113. package/dist/cli/controls.js.map +0 -1
  114. package/dist/cli/debug.d.ts.map +0 -1
  115. package/dist/cli/debug.js.map +0 -1
  116. package/dist/cli/interactive.d.ts.map +0 -1
  117. package/dist/cli/interactive.js.map +0 -1
  118. package/dist/cli/protocol.d.ts.map +0 -1
  119. package/dist/cli/protocol.js.map +0 -1
  120. package/dist/cli/tui/claude-style.d.ts.map +0 -1
  121. package/dist/cli/tui/claude-style.js.map +0 -1
  122. package/dist/cli/tui/clipboard.d.ts.map +0 -1
  123. package/dist/cli/tui/clipboard.js.map +0 -1
  124. package/dist/cli/tui/composer-editor.d.ts.map +0 -1
  125. package/dist/cli/tui/composer-editor.js.map +0 -1
  126. package/dist/cli/tui/composer-images.d.ts.map +0 -1
  127. package/dist/cli/tui/composer-images.js.map +0 -1
  128. package/dist/cli/tui/conversation-export.d.ts.map +0 -1
  129. package/dist/cli/tui/conversation-export.js.map +0 -1
  130. package/dist/cli/tui/external-editor.d.ts.map +0 -1
  131. package/dist/cli/tui/external-editor.js.map +0 -1
  132. package/dist/cli/tui/file-picker.d.ts.map +0 -1
  133. package/dist/cli/tui/file-picker.js.map +0 -1
  134. package/dist/cli/tui/git-diff.d.ts.map +0 -1
  135. package/dist/cli/tui/git-diff.js.map +0 -1
  136. package/dist/cli/tui/keybindings.d.ts.map +0 -1
  137. package/dist/cli/tui/keybindings.js.map +0 -1
  138. package/dist/cli/tui/memory-files.d.ts.map +0 -1
  139. package/dist/cli/tui/memory-files.js.map +0 -1
  140. package/dist/cli/tui/permission-settings.d.ts.map +0 -1
  141. package/dist/cli/tui/permission-settings.js.map +0 -1
  142. package/dist/cli/tui/slash-commands.d.ts.map +0 -1
  143. package/dist/cli/tui/slash-commands.js.map +0 -1
  144. package/dist/cli/tui/terminal-suspend.d.ts.map +0 -1
  145. package/dist/cli/tui/terminal-suspend.js.map +0 -1
  146. package/dist/cli/tui/workspace-directories.d.ts.map +0 -1
  147. package/dist/cli/tui/workspace-directories.js.map +0 -1
  148. package/dist/cli.d.ts.map +0 -1
  149. package/dist/cli.js.map +0 -1
  150. package/dist/compatibility/claude/compaction.d.ts.map +0 -1
  151. package/dist/compatibility/claude/compaction.js.map +0 -1
  152. package/dist/compatibility/claude/context.d.ts.map +0 -1
  153. package/dist/compatibility/claude/context.js.map +0 -1
  154. package/dist/compatibility/claude/dynamic-context.d.ts.map +0 -1
  155. package/dist/compatibility/claude/dynamic-context.js.map +0 -1
  156. package/dist/compatibility/claude/file-history.d.ts.map +0 -1
  157. package/dist/compatibility/claude/file-history.js.map +0 -1
  158. package/dist/compatibility/claude/file-resources.d.ts.map +0 -1
  159. package/dist/compatibility/claude/file-resources.js.map +0 -1
  160. package/dist/compatibility/claude/fork.d.ts.map +0 -1
  161. package/dist/compatibility/claude/fork.js.map +0 -1
  162. package/dist/compatibility/claude/history.d.ts.map +0 -1
  163. package/dist/compatibility/claude/history.js.map +0 -1
  164. package/dist/compatibility/claude/ownership.d.ts.map +0 -1
  165. package/dist/compatibility/claude/ownership.js.map +0 -1
  166. package/dist/compatibility/claude/paths.d.ts.map +0 -1
  167. package/dist/compatibility/claude/paths.js.map +0 -1
  168. package/dist/compatibility/claude/pr-links.d.ts.map +0 -1
  169. package/dist/compatibility/claude/pr-links.js.map +0 -1
  170. package/dist/compatibility/claude/projection.d.ts.map +0 -1
  171. package/dist/compatibility/claude/projection.js.map +0 -1
  172. package/dist/compatibility/claude/schema.d.ts.map +0 -1
  173. package/dist/compatibility/claude/schema.js.map +0 -1
  174. package/dist/compatibility/claude/shared-resources.d.ts.map +0 -1
  175. package/dist/compatibility/claude/shared-resources.js.map +0 -1
  176. package/dist/compatibility/claude/sidechain.d.ts.map +0 -1
  177. package/dist/compatibility/claude/sidechain.js.map +0 -1
  178. package/dist/compatibility/claude/tool-links.d.ts.map +0 -1
  179. package/dist/compatibility/claude/tool-links.js.map +0 -1
  180. package/dist/compatibility/claude/translation.d.ts.map +0 -1
  181. package/dist/compatibility/claude/translation.js.map +0 -1
  182. package/dist/compatibility/claude/workflow-replay.d.ts.map +0 -1
  183. package/dist/compatibility/claude/workflow-replay.js.map +0 -1
  184. package/dist/compatibility/claude/workflow.d.ts.map +0 -1
  185. package/dist/compatibility/claude/workflow.js.map +0 -1
  186. package/dist/core/compaction.d.ts.map +0 -1
  187. package/dist/core/compaction.js.map +0 -1
  188. package/dist/core/context-budget.d.ts.map +0 -1
  189. package/dist/core/context-budget.js.map +0 -1
  190. package/dist/core/context.d.ts.map +0 -1
  191. package/dist/core/context.js.map +0 -1
  192. package/dist/core/runtime.d.ts.map +0 -1
  193. package/dist/core/runtime.js.map +0 -1
  194. package/dist/core/usage.d.ts.map +0 -1
  195. package/dist/core/usage.js.map +0 -1
  196. package/dist/extensions/claude-extension-tools.d.ts.map +0 -1
  197. package/dist/extensions/claude-extension-tools.js.map +0 -1
  198. package/dist/extensions/claude-extensions.d.ts.map +0 -1
  199. package/dist/extensions/claude-extensions.js.map +0 -1
  200. package/dist/hooks/claude-hook-tools.d.ts.map +0 -1
  201. package/dist/hooks/claude-hook-tools.js.map +0 -1
  202. package/dist/hooks/claude-hooks.d.ts.map +0 -1
  203. package/dist/hooks/claude-hooks.js.map +0 -1
  204. package/dist/maintenance/doctor.d.ts.map +0 -1
  205. package/dist/maintenance/doctor.js.map +0 -1
  206. package/dist/maintenance/self-update.d.ts.map +0 -1
  207. package/dist/maintenance/self-update.js.map +0 -1
  208. package/dist/mcp/claude-mcp-management.d.ts.map +0 -1
  209. package/dist/mcp/claude-mcp-management.js.map +0 -1
  210. package/dist/mcp/claude-mcp-oauth.d.ts.map +0 -1
  211. package/dist/mcp/claude-mcp-oauth.js.map +0 -1
  212. package/dist/mcp/claude-mcp-tools.d.ts.map +0 -1
  213. package/dist/mcp/claude-mcp-tools.js.map +0 -1
  214. package/dist/mcp/praxis-mcp-server.d.ts.map +0 -1
  215. package/dist/mcp/praxis-mcp-server.js.map +0 -1
  216. package/dist/permissions/claude-auto-classifier.d.ts.map +0 -1
  217. package/dist/permissions/claude-auto-classifier.js.map +0 -1
  218. package/dist/permissions/claude-permission-resolver.d.ts.map +0 -1
  219. package/dist/permissions/claude-permission-resolver.js.map +0 -1
  220. package/dist/persistence/claude-job-store.d.ts.map +0 -1
  221. package/dist/persistence/claude-job-store.js.map +0 -1
  222. package/dist/persistence/claude-scheduled-task-store.d.ts.map +0 -1
  223. package/dist/persistence/claude-scheduled-task-store.js.map +0 -1
  224. package/dist/persistence/claude-sidechain-store.d.ts.map +0 -1
  225. package/dist/persistence/claude-sidechain-store.js.map +0 -1
  226. package/dist/persistence/claude-task-store.d.ts.map +0 -1
  227. package/dist/persistence/claude-task-store.js.map +0 -1
  228. package/dist/persistence/claude-transcript-store.d.ts.map +0 -1
  229. package/dist/persistence/claude-transcript-store.js.map +0 -1
  230. package/dist/persistence/claude-workflow-store.d.ts.map +0 -1
  231. package/dist/persistence/claude-workflow-store.js.map +0 -1
  232. package/dist/persistence/in-memory-sidechain-store.d.ts.map +0 -1
  233. package/dist/persistence/in-memory-sidechain-store.js.map +0 -1
  234. package/dist/persistence/in-memory-transcript-store.d.ts.map +0 -1
  235. package/dist/persistence/in-memory-transcript-store.js.map +0 -1
  236. package/dist/platform/atomic-write.d.ts.map +0 -1
  237. package/dist/platform/atomic-write.js.map +0 -1
  238. package/dist/platform/bounded-process-runner.d.ts.map +0 -1
  239. package/dist/platform/bounded-process-runner.js.map +0 -1
  240. package/dist/platform/claude-version.d.ts.map +0 -1
  241. package/dist/platform/claude-version.js.map +0 -1
  242. package/dist/platform/command-shell.d.ts.map +0 -1
  243. package/dist/platform/command-shell.js.map +0 -1
  244. package/dist/platform/exclusive-file-lease.d.ts.map +0 -1
  245. package/dist/platform/exclusive-file-lease.js.map +0 -1
  246. package/dist/platform/sensitive-data.d.ts.map +0 -1
  247. package/dist/platform/sensitive-data.js.map +0 -1
  248. package/dist/platform/tmux-worktree.d.ts.map +0 -1
  249. package/dist/platform/tmux-worktree.js.map +0 -1
  250. package/dist/plugins/claude-plugin-eval-discovery.d.ts.map +0 -1
  251. package/dist/plugins/claude-plugin-eval-discovery.js.map +0 -1
  252. package/dist/plugins/claude-plugin-eval-graders.d.ts.map +0 -1
  253. package/dist/plugins/claude-plugin-eval-graders.js.map +0 -1
  254. package/dist/plugins/claude-plugin-eval-runner.d.ts.map +0 -1
  255. package/dist/plugins/claude-plugin-eval-runner.js.map +0 -1
  256. package/dist/plugins/claude-plugin-eval-schema.d.ts.map +0 -1
  257. package/dist/plugins/claude-plugin-eval-schema.js.map +0 -1
  258. package/dist/plugins/claude-plugin-eval.d.ts.map +0 -1
  259. package/dist/plugins/claude-plugin-eval.js.map +0 -1
  260. package/dist/plugins/claude-plugin-maintenance.d.ts.map +0 -1
  261. package/dist/plugins/claude-plugin-maintenance.js.map +0 -1
  262. package/dist/plugins/claude-plugin-marketplace.d.ts.map +0 -1
  263. package/dist/plugins/claude-plugin-marketplace.js.map +0 -1
  264. package/dist/plugins/claude-plugin-mcpb.d.ts.map +0 -1
  265. package/dist/plugins/claude-plugin-mcpb.js.map +0 -1
  266. package/dist/plugins/claude-plugin-runtime.d.ts.map +0 -1
  267. package/dist/plugins/claude-plugin-runtime.js.map +0 -1
  268. package/dist/providers/anthropic-compatible.d.ts.map +0 -1
  269. package/dist/providers/anthropic-compatible.js.map +0 -1
  270. package/dist/providers/environment.d.ts.map +0 -1
  271. package/dist/providers/environment.js.map +0 -1
  272. package/dist/providers/fallback-provider.d.ts.map +0 -1
  273. package/dist/providers/fallback-provider.js.map +0 -1
  274. package/dist/providers/openai-compatible.d.ts.map +0 -1
  275. package/dist/providers/openai-compatible.js.map +0 -1
  276. package/dist/tools/claude-interactive-tools.d.ts.map +0 -1
  277. package/dist/tools/claude-interactive-tools.js.map +0 -1
  278. package/dist/tools/claude-lsp-formatters.d.ts.map +0 -1
  279. package/dist/tools/claude-lsp-formatters.js.map +0 -1
  280. package/dist/tools/claude-lsp-tool.d.ts.map +0 -1
  281. package/dist/tools/claude-lsp-tool.js.map +0 -1
  282. package/dist/tools/claude-scheduled-tools.d.ts.map +0 -1
  283. package/dist/tools/claude-scheduled-tools.js.map +0 -1
  284. package/dist/tools/claude-task-tools.d.ts.map +0 -1
  285. package/dist/tools/claude-task-tools.js.map +0 -1
  286. package/dist/tools/claude-user-message.d.ts.map +0 -1
  287. package/dist/tools/claude-user-message.js.map +0 -1
  288. package/dist/tools/claude-workflow-tools.d.ts.map +0 -1
  289. package/dist/tools/claude-workflow-tools.js.map +0 -1
  290. package/dist/tools/claude-worktree-tools.d.ts.map +0 -1
  291. package/dist/tools/claude-worktree-tools.js.map +0 -1
  292. package/dist/tools/filtered-tool-registry.d.ts.map +0 -1
  293. package/dist/tools/filtered-tool-registry.js.map +0 -1
  294. package/dist/tools/glob.d.ts.map +0 -1
  295. package/dist/tools/glob.js.map +0 -1
  296. package/dist/tools/local-tools.d.ts.map +0 -1
  297. package/dist/tools/local-tools.js.map +0 -1
  298. package/dist/tools/notebook.d.ts.map +0 -1
  299. package/dist/tools/notebook.js.map +0 -1
  300. package/dist/tools/pdf.d.ts.map +0 -1
  301. package/dist/tools/pdf.js.map +0 -1
  302. package/dist/tools/web.d.ts.map +0 -1
  303. package/dist/tools/web.js.map +0 -1
@@ -0,0 +1,63 @@
1
+ import React from 'react';
2
+ import type { ModelUsage } from '../../core/runtime.js';
3
+ import { type ConfigSettingDefinition, type ConfigSettingsSnapshot, type ConfigValue } from './config-settings.js';
4
+ export type ConfigDashboardTab = 'settings' | 'status' | 'config' | 'usage' | 'stats';
5
+ export interface ConfigStatusData {
6
+ version: string;
7
+ sessionName?: string;
8
+ sessionId: string;
9
+ cwd: string;
10
+ authSource?: string;
11
+ baseUrl?: string;
12
+ model: string;
13
+ settingSources: readonly string[];
14
+ }
15
+ export interface ConfigUsageData {
16
+ costUsd: number;
17
+ apiDurationMs: number;
18
+ wallDurationMs: number;
19
+ linesAdded: number;
20
+ linesRemoved: number;
21
+ usage: ModelUsage;
22
+ }
23
+ export interface ContextCategory {
24
+ label: string;
25
+ tokens: number;
26
+ }
27
+ export interface ConfigContextData {
28
+ contextWindowTokens: number;
29
+ categories: readonly ContextCategory[];
30
+ }
31
+ export interface ConfigDashboardValueRow {
32
+ label: string;
33
+ value: string;
34
+ }
35
+ export interface ConfigRow {
36
+ definition: ConfigSettingDefinition;
37
+ value: ConfigValue;
38
+ displayValue: string;
39
+ }
40
+ export type ConfigEffectiveValues = Readonly<Partial<Record<string, ConfigValue>>>;
41
+ export declare function projectConfigRows(snapshot: ConfigSettingsSnapshot, query?: string, effectiveValues?: ConfigEffectiveValues): ConfigRow[];
42
+ export declare function projectContextUsage(data: ConfigContextData): {
43
+ categories: ContextCategory[];
44
+ usedTokens: number;
45
+ freeTokens: number;
46
+ contextWindowTokens: number;
47
+ };
48
+ export declare function ConfigDashboard({ tab, snapshot, query, selectedIndex, searchFocused, status, usage, settings, stats, effectiveValues, width, screenReader, maxRows, }: {
49
+ tab: ConfigDashboardTab;
50
+ snapshot: ConfigSettingsSnapshot;
51
+ query?: string;
52
+ selectedIndex?: number;
53
+ searchFocused?: boolean;
54
+ status?: ConfigStatusData;
55
+ usage?: ConfigUsageData;
56
+ settings?: readonly ConfigDashboardValueRow[];
57
+ stats?: readonly ConfigDashboardValueRow[];
58
+ effectiveValues?: ConfigEffectiveValues;
59
+ width: number;
60
+ screenReader: boolean;
61
+ maxRows?: number;
62
+ }): React.JSX.Element;
63
+ //# sourceMappingURL=config-dashboard.d.ts.map
@@ -0,0 +1,150 @@
1
+ import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Box, Text } from 'ink';
3
+ import { CLAUDE_2_1_208_CONFIG_SETTINGS, configSettingValue, } from './config-settings.js';
4
+ const tabs = [
5
+ { id: 'settings', label: 'Settings' },
6
+ { id: 'status', label: 'Status' },
7
+ { id: 'config', label: 'Config' },
8
+ { id: 'usage', label: 'Usage' },
9
+ { id: 'stats', label: 'Stats' },
10
+ ];
11
+ function displayValue(definition, value) {
12
+ if (definition.id === 'permissionMode') {
13
+ return ({
14
+ default: 'Manual',
15
+ plan: 'Plan',
16
+ acceptEdits: 'Accept edits',
17
+ auto: 'Auto',
18
+ dontAsk: "Don't ask",
19
+ }[String(value)] ?? String(value));
20
+ }
21
+ if (definition.id === 'theme') {
22
+ return ({
23
+ auto: 'Auto',
24
+ dark: 'Dark mode',
25
+ light: 'Light mode',
26
+ 'light-daltonized': 'Light mode (colorblind-friendly)',
27
+ 'dark-daltonized': 'Dark mode (colorblind-friendly)',
28
+ 'light-ansi': 'Light mode (ANSI colors only)',
29
+ 'dark-ansi': 'Dark mode (ANSI colors only)',
30
+ }[String(value)] ?? String(value));
31
+ }
32
+ if (definition.id === 'notifChannel') {
33
+ return ({
34
+ auto: 'Auto',
35
+ iterm2: 'iTerm2 (OSC 9)',
36
+ terminal_bell: 'Terminal bell',
37
+ iterm2_with_bell: 'iTerm2 and terminal bell',
38
+ kitty: 'Kitty',
39
+ ghostty: 'Ghostty',
40
+ notifications_disabled: 'Disabled',
41
+ }[String(value)] ?? String(value));
42
+ }
43
+ if (definition.id === 'language' && value === 'default')
44
+ return 'Default (English)';
45
+ return String(value);
46
+ }
47
+ export function projectConfigRows(snapshot, query = '', effectiveValues = {}) {
48
+ const normalized = query.trim().toLowerCase();
49
+ return CLAUDE_2_1_208_CONFIG_SETTINGS.map((definition) => {
50
+ const value = effectiveValues[definition.id] ?? configSettingValue(snapshot, definition);
51
+ return { definition, value, displayValue: displayValue(definition, value) };
52
+ }).filter((row) => !normalized ||
53
+ row.definition.label.toLowerCase().includes(normalized) ||
54
+ row.definition.nativeKey.toLowerCase().includes(normalized) ||
55
+ row.displayValue.toLowerCase().includes(normalized));
56
+ }
57
+ export function projectContextUsage(data) {
58
+ if (!Number.isSafeInteger(data.contextWindowTokens) ||
59
+ data.contextWindowTokens <= 0)
60
+ throw new Error('Context window must be a positive integer');
61
+ const categories = data.categories.map((category) => {
62
+ if (!Number.isSafeInteger(category.tokens) || category.tokens < 0)
63
+ throw new Error(`Invalid context category tokens: ${category.label}`);
64
+ return category;
65
+ });
66
+ const usedTokens = categories.reduce((total, category) => total + category.tokens, 0);
67
+ if (usedTokens > data.contextWindowTokens)
68
+ throw new Error('Measured context categories exceed the context window');
69
+ return {
70
+ categories,
71
+ usedTokens,
72
+ freeTokens: data.contextWindowTokens - usedTokens,
73
+ contextWindowTokens: data.contextWindowTokens,
74
+ };
75
+ }
76
+ function DashboardTabs({ active, screenReader, }) {
77
+ if (screenReader) {
78
+ return (_jsx(Box, { flexDirection: "column", children: tabs.map((tab) => (_jsxs(Text, { children: [tab.id === active ? 'Selected tab: ' : '', tab.label] }, tab.id))) }));
79
+ }
80
+ return (_jsxs(Text, { children: [' ', tabs.map((tab) => (_jsxs(Text, { inverse: tab.id === active, children: [' ', tab.label, ' '] }, tab.id)))] }));
81
+ }
82
+ function ConfigRows({ rows, query, selectedIndex, searchFocused, maxRows, screenReader, width, }) {
83
+ const bounded = Math.max(1, maxRows);
84
+ const start = Math.max(0, Math.min(selectedIndex - bounded + 1, rows.length - bounded));
85
+ const visible = rows.slice(start, start + bounded);
86
+ return (_jsxs(_Fragment, { children: [_jsx(Box, { borderStyle: screenReader ? undefined : 'round', paddingX: 1, children: _jsxs(Text, { inverse: searchFocused, children: ["\u2315 ", query || 'Search settings…'] }) }), _jsx(Text, { children: " " }), start > 0 ? _jsxs(Text, { children: [" \u2191 ", start, " more above"] }) : null, visible.map((row, offset) => {
87
+ const index = start + offset;
88
+ const selected = index === selectedIndex && !searchFocused;
89
+ const stacked = width < 60;
90
+ return (_jsxs(Box, { flexDirection: stacked ? 'column' : 'row', children: [_jsx(Box, { width: stacked ? undefined : Math.min(46, width - 12), children: _jsxs(Text, { inverse: !screenReader && selected, children: [screenReader && selected
91
+ ? 'Selected: '
92
+ : selected
93
+ ? '❯ '
94
+ : ' ', row.definition.label] }) }), _jsx(Text, { children: stacked ? ` ${row.displayValue}` : row.displayValue })] }, row.definition.id));
95
+ }), start + visible.length < rows.length ? (_jsxs(Text, { children: [" \u2193 ", rows.length - start - visible.length, " more below"] })) : null, _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: searchFocused
96
+ ? 'Type to filter · Enter/↓ to select · ↑ to tabs · Esc to clear'
97
+ : 'Enter/Space to change · / to search · Esc to close' })] }));
98
+ }
99
+ function StatusRows({ status }) {
100
+ const rows = [
101
+ ['Version', status.version],
102
+ ['Session name', status.sessionName ?? '/rename to add a name'],
103
+ ['Session ID', status.sessionId],
104
+ ['cwd', status.cwd],
105
+ ...(status.authSource ? [['Auth token', status.authSource]] : []),
106
+ ...(status.baseUrl ? [['Provider base URL', status.baseUrl]] : []),
107
+ ['Model', status.model],
108
+ ['Setting sources', status.settingSources.join(', ')],
109
+ ];
110
+ return (_jsxs(_Fragment, { children: [rows.map(([label, value]) => (_jsxs(Box, { children: [_jsx(Box, { width: 22, children: _jsxs(Text, { children: [label, ":"] }) }), _jsx(Text, { children: value })] }, label))), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "Esc to cancel" })] }));
111
+ }
112
+ function UsageRows({ usage }) {
113
+ const seconds = (milliseconds) => `${Math.round(milliseconds / 1_000)}s`;
114
+ return (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, children: "Session" }), _jsx(Text, { children: " " }), _jsxs(Text, { children: ["Total cost: $", usage.costUsd.toFixed(4)] }), _jsxs(Text, { children: ["Total duration (API): ", seconds(usage.apiDurationMs)] }), _jsxs(Text, { children: ["Total duration (wall): ", seconds(usage.wallDurationMs)] }), _jsxs(Text, { children: ["Total code changes: ", usage.linesAdded, " lines added, ", usage.linesRemoved, ' ', "lines removed"] }), _jsxs(Text, { children: ["Usage: ", usage.usage.inputTokens, " input, ", usage.usage.outputTokens, ' ', "output, ", usage.usage.cacheReadInputTokens ?? 0, " cache read,", ' ', usage.usage.cacheCreationInputTokens ?? 0, " cache write"] }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "Esc to cancel" })] }));
115
+ }
116
+ function ValueRows({ rows }) {
117
+ return rows.map((row) => (_jsxs(Box, { children: [_jsx(Box, { width: 28, children: _jsxs(Text, { children: [row.label, ":"] }) }), _jsx(Text, { children: row.value })] }, row.label)));
118
+ }
119
+ export function ConfigDashboard({ tab, snapshot, query = '', selectedIndex = 0, searchFocused = true, status, usage, settings, stats, effectiveValues, width, screenReader, maxRows = 18, }) {
120
+ const rows = projectConfigRows(snapshot, query, effectiveValues);
121
+ let content;
122
+ switch (tab) {
123
+ case 'settings':
124
+ if (settings === undefined)
125
+ throw new Error('Settings tab requires measured settings data');
126
+ content = _jsx(ValueRows, { rows: settings });
127
+ break;
128
+ case 'status':
129
+ if (status === undefined)
130
+ throw new Error('Status tab requires measured status data');
131
+ content = _jsx(StatusRows, { status: status });
132
+ break;
133
+ case 'config':
134
+ content = (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, children: "Config" }), _jsx(Text, { children: "Available commands: /config \u00B7 /status \u00B7 /usage" }), _jsx(ConfigRows, { rows: rows, query: query, selectedIndex: Math.max(0, Math.min(selectedIndex, rows.length - 1)), searchFocused: searchFocused, maxRows: maxRows, screenReader: screenReader, width: width })] }));
135
+ break;
136
+ case 'usage':
137
+ if (usage === undefined)
138
+ throw new Error('Usage tab requires measured usage data');
139
+ content = _jsx(UsageRows, { usage: usage });
140
+ break;
141
+ case 'stats':
142
+ if (stats === undefined)
143
+ throw new Error('Stats tab requires measured stats data');
144
+ content =
145
+ stats.length === 0 ? (_jsx(Text, { children: "No stats available yet. Start using Praxis Code!" })) : (_jsx(ValueRows, { rows: stats }));
146
+ break;
147
+ }
148
+ return (_jsxs(Box, { flexDirection: "column", width: Math.min(100, width), children: [!screenReader ? _jsx(Text, { children: '─'.repeat(Math.min(100, width)) }) : null, _jsx(DashboardTabs, { active: tab, screenReader: screenReader }), _jsx(Text, { children: " " }), content] }));
149
+ }
150
+ //# sourceMappingURL=config-dashboard.js.map
@@ -0,0 +1,32 @@
1
+ export type ConfigStorageScope = 'settings' | 'state';
2
+ export type ConfigValue = boolean | string;
3
+ export interface ConfigSettingDefinition {
4
+ id: string;
5
+ nativeKey: string;
6
+ label: string;
7
+ scope: ConfigStorageScope;
8
+ path: readonly string[];
9
+ values: readonly ConfigValue[] | 'language';
10
+ defaultValue: ConfigValue;
11
+ runtimeStatus: 'integrated' | 'interactive-integration' | 'not-applicable';
12
+ runtimeConsumer: string;
13
+ applicabilityReason?: string;
14
+ }
15
+ export interface ConfigSettingsSnapshot {
16
+ settings: Readonly<Record<string, unknown>>;
17
+ state: Readonly<Record<string, unknown>>;
18
+ }
19
+ export interface ConfigSettingsLocation {
20
+ configRoot: string;
21
+ statePath: string;
22
+ }
23
+ export type ConfigSettingsTarget = string | ConfigSettingsLocation;
24
+ export declare const CLAUDE_2_1_208_CONFIG_SETTINGS: readonly [ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition, ConfigSettingDefinition];
25
+ export declare function resolveConfigSettingsLocation(target?: ConfigSettingsTarget): ConfigSettingsLocation;
26
+ export declare function configSettingDefinition(id: string): ConfigSettingDefinition | undefined;
27
+ export declare function configSettingValue(snapshot: ConfigSettingsSnapshot, definition: ConfigSettingDefinition): ConfigValue;
28
+ export declare function loadConfigSettings(target?: ConfigSettingsTarget): Promise<ConfigSettingsSnapshot>;
29
+ export declare function saveConfigSetting(id: string, value: ConfigValue, target?: ConfigSettingsTarget, hooks?: {
30
+ afterValidation?: () => Promise<void>;
31
+ }): Promise<ConfigSettingsSnapshot>;
32
+ //# sourceMappingURL=config-settings.d.ts.map
@@ -0,0 +1,276 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { constants } from 'node:fs';
3
+ import { open, realpath } from 'node:fs/promises';
4
+ import { homedir } from 'node:os';
5
+ import { dirname, join } from 'node:path';
6
+ import { setTimeout } from 'node:timers/promises';
7
+ import { writeFileAtomically } from '../../platform/atomic-write.js';
8
+ import { ExclusiveFileLease, } from '../../platform/exclusive-file-lease.js';
9
+ const booleanValues = [true, false];
10
+ export const CLAUDE_2_1_208_CONFIG_SETTINGS = [
11
+ setting('autoCompact', 'Auto-compact', 'settings', ['autoCompactEnabled'], booleanValues, true, 'compaction threshold policy'),
12
+ setting('switchModelsOnFlag', 'Switch models when a message is flagged', 'settings', ['switchModelsOnFlag'], booleanValues, true, 'provider capability-aware model fallback'),
13
+ setting('tips', 'Show tips', 'settings', ['spinnerTipsEnabled'], booleanValues, true, 'interactive spinner tips'),
14
+ setting('reduceMotion', 'Reduce motion', 'settings', ['prefersReducedMotion'], booleanValues, false, 'all animated TUI surfaces'),
15
+ setting('thinking', 'Thinking mode', 'settings', ['alwaysThinkingEnabled'], booleanValues, true, 'interactive thinking controls and provider adapter'),
16
+ setting('recap', 'Session recap', 'settings', ['awaySummaryEnabled'], booleanValues, true, 'interactive session resume recap'),
17
+ setting('checkpoints', 'Rewind code (checkpoints)', 'settings', ['fileCheckpointingEnabled'], booleanValues, true, 'file-history snapshot and rewind runtime'),
18
+ setting('workflows', 'Dynamic workflows', 'settings', ['enableWorkflows'], booleanValues, true, 'workflow tool exposure and SessionService'),
19
+ setting('workflowKeywordTriggerEnabled', 'Ultracode keyword trigger', 'settings', ['workflowKeywordTriggerEnabled'], booleanValues, true, 'workflow keyword dispatcher'),
20
+ setting('workflowSizeGuideline', 'Dynamic workflow size', 'state', ['workflowSizeGuideline'], ['unrestricted', 'small', 'medium', 'large'], 'unrestricted', 'workflow planner sizing guidance'),
21
+ setting('verbose', 'Verbose output', 'settings', ['verbose'], booleanValues, false, 'interactive transcript detail and protocol diagnostics'),
22
+ setting('progressBar', 'Terminal progress bar', 'settings', ['terminalProgressBarEnabled'], booleanValues, true, 'terminal progress renderer'),
23
+ setting('turnDuration', 'Show turn duration', 'settings', ['showTurnDuration'], booleanValues, true, 'interactive turn footer'),
24
+ setting('permissionMode', 'Default permission mode', 'settings', ['permissions', 'defaultMode'], ['default', 'plan', 'acceptEdits', 'auto', 'dontAsk'], 'default', 'startup permission mode selection'),
25
+ setting('worktreeBaseRef', 'Worktree base ref', 'settings', ['worktree', 'baseRef'], ['fresh', 'head'], 'fresh', 'worktree creation runtime'),
26
+ setting('useAutoModeDuringPlan', 'Use auto mode during plan', 'settings', ['useAutoModeDuringPlan'], booleanValues, true, 'plan approval permission transition'),
27
+ setting('gitignore', 'Respect .gitignore in file picker', 'state', ['respectGitignore'], booleanValues, true, 'interactive file picker'),
28
+ setting('copyFullResponse', 'Skip the /copy picker', 'state', ['copyFullResponse'], booleanValues, false, '/copy local command'),
29
+ setting('defaultToAgentsView', 'Open agents view by default', 'state', ['defaultToAgentsView'], booleanValues, false, 'interactive agents dashboard'),
30
+ setting('leftArrowOpensAgents', '← opens agents', 'state', ['leftArrowOpensAgents'], booleanValues, true, 'global interactive key dispatcher'),
31
+ setting('autoUpdatesChannel', 'Auto-update channel', 'settings', ['autoUpdatesChannel'], ['latest', 'stable'], 'latest', 'self-update policy'),
32
+ setting('theme', 'Theme', 'settings', ['theme'], [
33
+ 'auto',
34
+ 'dark',
35
+ 'light',
36
+ 'light-daltonized',
37
+ 'dark-daltonized',
38
+ 'light-ansi',
39
+ 'dark-ansi',
40
+ ], 'auto', 'Stage 109 theme runtime'),
41
+ setting('notifChannel', 'Local notifications', 'settings', ['preferredNotifChannel'], [
42
+ 'auto',
43
+ 'iterm2',
44
+ 'terminal_bell',
45
+ 'iterm2_with_bell',
46
+ 'kitty',
47
+ 'ghostty',
48
+ 'notifications_disabled',
49
+ ], 'auto', 'task and permission notification dispatcher'),
50
+ setting('outputStyle', 'Output style', 'settings', ['outputStyle'], ['default', 'Proactive', 'Explanatory', 'Learning'], 'default', 'system-prompt output-style projection'),
51
+ setting('language', 'Language', 'settings', ['language'], 'language', 'default', 'system-prompt language projection'),
52
+ setting('editor', 'Editor mode', 'settings', ['editorMode'], ['normal', 'vim'], 'normal', 'interactive composer editor mode'),
53
+ setting('askUserQuestionTimeout', 'Question auto-continue timeout', 'settings', ['askUserQuestionTimeout'], ['never', '60s', '5m', '10m'], 'never', 'AskUserQuestion decision timer'),
54
+ setting('externalEditorContext', 'Show last response in external editor', 'state', ['externalEditorContext'], booleanValues, false, 'external editor prompt projection'),
55
+ setting('prStatus', 'Show PR status footer', 'state', ['prStatusFooterEnabled'], booleanValues, true, 'interactive repository footer'),
56
+ setting('model', 'Model', 'settings', ['model'], [
57
+ 'default',
58
+ 'sonnet',
59
+ 'opus',
60
+ 'haiku',
61
+ 'best',
62
+ 'sonnet[1m]',
63
+ 'opus[1m]',
64
+ 'opusplan',
65
+ ], 'default', 'startup provider model selection'),
66
+ setting('tui', 'TUI renderer', 'settings', ['tui'], ['default', 'fullscreen'], 'default', 'interactive renderer mode'),
67
+ ];
68
+ function setting(nativeKey, label, scope, path, values, defaultValue, runtimeConsumer) {
69
+ const integrated = new Set([
70
+ 'autoCompact',
71
+ 'thinking',
72
+ 'checkpoints',
73
+ 'workflows',
74
+ 'permissionMode',
75
+ 'worktreeBaseRef',
76
+ 'gitignore',
77
+ 'theme',
78
+ 'outputStyle',
79
+ 'language',
80
+ 'model',
81
+ ]).has(nativeKey);
82
+ const notApplicable = nativeKey === 'switchModelsOnFlag';
83
+ return {
84
+ id: nativeKey,
85
+ nativeKey,
86
+ label,
87
+ scope,
88
+ path,
89
+ values,
90
+ defaultValue,
91
+ runtimeStatus: integrated
92
+ ? 'integrated'
93
+ : notApplicable
94
+ ? 'not-applicable'
95
+ : 'interactive-integration',
96
+ runtimeConsumer,
97
+ ...(notApplicable
98
+ ? {
99
+ applicabilityReason: 'Claude subscription flag fallback is outside the API-provider, subscription-auth-free Praxis boundary',
100
+ }
101
+ : {}),
102
+ };
103
+ }
104
+ function isRecord(value) {
105
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
106
+ }
107
+ export function resolveConfigSettingsLocation(target) {
108
+ if (typeof target === 'object')
109
+ return target;
110
+ if (typeof target === 'string')
111
+ return { configRoot: target, statePath: join(target, '.claude.json') };
112
+ const configuredRoot = process.env.CLAUDE_CONFIG_DIR;
113
+ return configuredRoot
114
+ ? {
115
+ configRoot: configuredRoot,
116
+ statePath: join(configuredRoot, '.claude.json'),
117
+ }
118
+ : {
119
+ configRoot: join(homedir(), '.claude'),
120
+ statePath: join(homedir(), '.claude.json'),
121
+ };
122
+ }
123
+ function configPath(location, scope) {
124
+ return scope === 'settings'
125
+ ? join(location.configRoot, 'settings.json')
126
+ : location.statePath;
127
+ }
128
+ async function readObject(path) {
129
+ try {
130
+ const source = await readRegularSource(path);
131
+ if (source === undefined)
132
+ return { value: {}, fingerprint: sourceFingerprint() };
133
+ const value = JSON.parse(source);
134
+ if (!isRecord(value))
135
+ throw new Error(`JSON root must be an object: ${path}`);
136
+ return { value, fingerprint: sourceFingerprint(source) };
137
+ }
138
+ catch (error) {
139
+ if (error instanceof SyntaxError)
140
+ throw new Error(`Invalid JSON: ${path}`, { cause: error });
141
+ throw error;
142
+ }
143
+ }
144
+ async function readRegularSource(path) {
145
+ let handle;
146
+ try {
147
+ handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
148
+ }
149
+ catch (error) {
150
+ const code = error.code;
151
+ if (code === 'ENOENT')
152
+ return undefined;
153
+ if (code === 'ELOOP')
154
+ throw new Error(`Config path must be a regular file: ${path}`);
155
+ throw error;
156
+ }
157
+ try {
158
+ if (!(await handle.stat()).isFile())
159
+ throw new Error(`Config path must be a regular file: ${path}`);
160
+ return handle.readFile('utf8');
161
+ }
162
+ finally {
163
+ await handle.close();
164
+ }
165
+ }
166
+ function sourceFingerprint(source) {
167
+ return source === undefined
168
+ ? 'missing'
169
+ : createHash('sha256').update(source).digest('hex');
170
+ }
171
+ async function fingerprintUnchanged(path, expected) {
172
+ const source = await readRegularSource(path);
173
+ return sourceFingerprint(source) === expected;
174
+ }
175
+ function valueAtPath(source, path) {
176
+ let current = source;
177
+ for (const segment of path) {
178
+ if (!isRecord(current))
179
+ return undefined;
180
+ current = current[segment];
181
+ }
182
+ return current;
183
+ }
184
+ function withValueAtPath(source, path, value) {
185
+ const [head, ...tail] = path;
186
+ if (!head)
187
+ throw new Error('Config setting path cannot be empty');
188
+ if (tail.length === 0)
189
+ return { ...source, [head]: value };
190
+ const storedChild = source[head];
191
+ if (storedChild !== undefined && !isRecord(storedChild)) {
192
+ throw new Error(`Config setting path ${path.join('.')} crosses a non-object`);
193
+ }
194
+ const child = storedChild ?? {};
195
+ return { ...source, [head]: withValueAtPath(child, tail, value) };
196
+ }
197
+ function validValue(definition, value) {
198
+ if (definition.values === 'language')
199
+ return (typeof value === 'string' &&
200
+ value.trim().length > 0 &&
201
+ value.length <= 256);
202
+ return definition.values.includes(value);
203
+ }
204
+ export function configSettingDefinition(id) {
205
+ return CLAUDE_2_1_208_CONFIG_SETTINGS.find((definition) => definition.id === id || definition.nativeKey === id);
206
+ }
207
+ export function configSettingValue(snapshot, definition) {
208
+ const source = definition.scope === 'settings' ? snapshot.settings : snapshot.state;
209
+ const stored = valueAtPath(source, definition.path);
210
+ return validValue(definition, stored) ? stored : definition.defaultValue;
211
+ }
212
+ export async function loadConfigSettings(target) {
213
+ const location = resolveConfigSettingsLocation(target);
214
+ const [settings, state] = await Promise.all([
215
+ readObject(configPath(location, 'settings')),
216
+ readObject(configPath(location, 'state')),
217
+ ]);
218
+ return { settings: settings.value, state: state.value };
219
+ }
220
+ async function acquireLease(location, scope) {
221
+ const path = configPath(location, scope);
222
+ const lockParent = await realpath(dirname(path)).catch((error) => {
223
+ if (error.code === 'ENOENT')
224
+ return dirname(path);
225
+ throw error;
226
+ });
227
+ const lease = new ExclusiveFileLease(scope === 'settings'
228
+ ? join(lockParent, '.praxis-settings.lock')
229
+ : join(lockParent, '.praxis-claude-state.lock'));
230
+ for (let attempt = 0; attempt < 400; attempt += 1) {
231
+ const handle = await lease.tryAcquire();
232
+ if (handle)
233
+ return handle;
234
+ await setTimeout(5);
235
+ }
236
+ throw new Error(`Config write lock timed out: ${path}`);
237
+ }
238
+ export async function saveConfigSetting(id, value, target, hooks = {}) {
239
+ const definition = configSettingDefinition(id);
240
+ if (!definition)
241
+ throw new Error(`Unknown Claude config setting: ${id}`);
242
+ if (!validValue(definition, value))
243
+ throw new Error(`Invalid value for Claude config setting ${id}: ${String(value)}`);
244
+ const location = resolveConfigSettingsLocation(target);
245
+ await loadConfigSettings(location);
246
+ const path = configPath(location, definition.scope);
247
+ const handle = await acquireLease(location, definition.scope);
248
+ try {
249
+ for (let attempt = 0; attempt < 3; attempt += 1) {
250
+ const settingsPath = configPath(location, 'settings');
251
+ const statePath = configPath(location, 'state');
252
+ const [settings, state] = await Promise.all([
253
+ readObject(settingsPath),
254
+ readObject(statePath),
255
+ ]);
256
+ const current = definition.scope === 'settings' ? settings : state;
257
+ const next = withValueAtPath(current.value, definition.path, value);
258
+ const committed = await writeFileAtomically(path, `${JSON.stringify(next, null, 2)}\n`, {
259
+ beforeCommit: async () => {
260
+ const unchanged = (await fingerprintUnchanged(settingsPath, settings.fingerprint)) && (await fingerprintUnchanged(statePath, state.fingerprint));
261
+ if (!unchanged)
262
+ return false;
263
+ await hooks.afterValidation?.();
264
+ return ((await fingerprintUnchanged(settingsPath, settings.fingerprint)) && (await fingerprintUnchanged(statePath, state.fingerprint)));
265
+ },
266
+ });
267
+ if (committed)
268
+ return loadConfigSettings(location);
269
+ }
270
+ throw new Error(`Config changed concurrently: ${path}`);
271
+ }
272
+ finally {
273
+ await handle.release();
274
+ }
275
+ }
276
+ //# sourceMappingURL=config-settings.js.map
@@ -0,0 +1,21 @@
1
+ import { type TuiTheme } from './theme.js';
2
+ export declare const CUSTOM_THEME_TOKENS: readonly ["autoAccept", "autoAcceptShimmer", "background", "bashBorder", "bashMessageBackgroundColor", "blue_FOR_SUBAGENTS_ONLY", "briefLabelClaude", "briefLabelYou", "chromeYellow", "claude", "claudeBlueShimmer_FOR_SYSTEM_SPINNER", "claudeBlue_FOR_SYSTEM_SPINNER", "claudeShimmer", "clawd_background", "clawd_body", "cyan_FOR_SUBAGENTS_ONLY", "diffAdded", "diffAddedDimmed", "diffAddedWord", "diffRemoved", "diffRemovedDimmed", "diffRemovedWord", "error", "fastMode", "fastModeShimmer", "green_FOR_SUBAGENTS_ONLY", "ide", "inactive", "inactiveShimmer", "inverseText", "memoryBackgroundColor", "merged", "messageActionsBackground", "orange_FOR_SUBAGENTS_ONLY", "pink_FOR_SUBAGENTS_ONLY", "planMode", "professionalBlue", "promptBorder", "promptBorderShimmer", "purple_FOR_SUBAGENTS_ONLY", "rainbow_blue", "rainbow_blue_shimmer", "rainbow_green", "rainbow_green_shimmer", "rainbow_indigo", "rainbow_indigo_shimmer", "rainbow_orange", "rainbow_orange_shimmer", "rainbow_red", "rainbow_red_shimmer", "rainbow_violet", "rainbow_violet_shimmer", "rainbow_yellow", "rainbow_yellow_shimmer", "rate_limit_empty", "rate_limit_fill", "red_FOR_SUBAGENTS_ONLY", "remember", "selectionBg", "success", "subtle", "suggestion", "text", "userMessageBackground", "userMessageBackgroundHover", "warning", "warningShimmer", "yellow_FOR_SUBAGENTS_ONLY"];
3
+ export type CustomThemeToken = (typeof CUSTOM_THEME_TOKENS)[number];
4
+ export type CustomThemeBase = Exclude<TuiTheme, 'auto'>;
5
+ export interface TuiCustomTheme {
6
+ name: string;
7
+ slug: string;
8
+ base: CustomThemeBase;
9
+ overrides: Readonly<Partial<Record<CustomThemeToken, string>>>;
10
+ }
11
+ export declare function customThemeDirectory(configRoot?: string): string;
12
+ export declare function validateCustomThemeName(name: string): string;
13
+ export declare function loadTuiCustomThemes(configRoot?: string): Promise<readonly TuiCustomTheme[]>;
14
+ export declare function createTuiCustomTheme({ name, base, configRoot, }: {
15
+ name: string;
16
+ base: CustomThemeBase;
17
+ configRoot?: string;
18
+ }): Promise<TuiCustomTheme>;
19
+ export declare function updateTuiCustomTheme(theme: TuiCustomTheme, token: CustomThemeToken, value: string | undefined, configRoot?: string): Promise<TuiCustomTheme>;
20
+ export declare function deleteTuiCustomTheme(theme: TuiCustomTheme, configRoot?: string): Promise<void>;
21
+ //# sourceMappingURL=custom-themes.d.ts.map