@aragon-agent/cli 0.6.46 → 0.6.48

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 (775) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +80 -12
  3. package/dist/agent/coalesce.d.ts +5 -1
  4. package/dist/agent/coalesce.js +13 -0
  5. package/dist/agent/controller.d.ts +41 -20
  6. package/dist/agent/controller.js +68 -15
  7. package/dist/agent/conversation-reset.d.ts +1 -1
  8. package/dist/agent/governance-wiring.d.ts +6 -6
  9. package/dist/agent/governance-wiring.js +4 -4
  10. package/dist/agent/headless.d.ts +5 -5
  11. package/dist/agent/headless.js +4 -4
  12. package/dist/agent/job-notices.d.ts +1 -1
  13. package/dist/agent/job-notices.js +1 -1
  14. package/dist/agent/kit-apply.d.ts +3 -3
  15. package/dist/agent/kit-apply.js +3 -3
  16. package/dist/agent/model-profile-settings.d.ts +2 -2
  17. package/dist/agent/model-profile-settings.js +6 -6
  18. package/dist/agent/prompt-options.d.ts +1 -1
  19. package/dist/agent/system-prompt.d.ts +1 -1
  20. package/dist/agent/user-attention.d.ts +17 -0
  21. package/dist/agent/user-attention.js +32 -0
  22. package/dist/{ui → app}/App.d.ts +9 -9
  23. package/dist/{ui → app}/App.js +113 -79
  24. package/dist/{ui → app}/use-startup-notices.d.ts +1 -1
  25. package/dist/{ui → app}/use-startup-notices.js +2 -2
  26. package/dist/cli.js +31 -32
  27. package/dist/commands/agents-command.js +1 -1
  28. package/dist/commands/builtins.js +9 -9
  29. package/dist/commands/governance-command.js +2 -2
  30. package/dist/commands/governance-runs-table.js +1 -1
  31. package/dist/commands/kit-command.js +1 -1
  32. package/dist/commands/perf.d.ts +3 -3
  33. package/dist/commands/perf.js +1 -1
  34. package/dist/commands/registry.d.ts +8 -8
  35. package/dist/commands/skills.js +2 -2
  36. package/dist/commands/team-command.js +1 -1
  37. package/dist/compaction/archive.d.ts +1 -1
  38. package/dist/compaction/archive.js +1 -1
  39. package/dist/compaction/child.d.ts +3 -3
  40. package/dist/compaction/child.js +4 -4
  41. package/dist/compaction/command.js +5 -5
  42. package/dist/compaction/compactor.d.ts +6 -6
  43. package/dist/compaction/compactor.js +6 -6
  44. package/dist/compaction/context-command.js +1 -1
  45. package/dist/compaction/digest.js +1 -1
  46. package/dist/compaction/memory-input.js +1 -1
  47. package/dist/compaction/memory-validation.js +1 -1
  48. package/dist/compaction/memory.js +1 -1
  49. package/dist/compaction/summarize-call.js +1 -1
  50. package/dist/compaction/summary-prompt.js +1 -1
  51. package/dist/compaction/tail-budget.js +2 -2
  52. package/dist/compaction/wiring.d.ts +5 -5
  53. package/dist/compaction/wiring.js +2 -2
  54. package/dist/config/cli-commands.d.ts +1 -1
  55. package/dist/config/cli-commands.js +3 -3
  56. package/dist/config/env.d.ts +1 -1
  57. package/dist/config/env.js +4 -4
  58. package/dist/config/load.d.ts +2 -2
  59. package/dist/config/load.js +10 -31
  60. package/dist/config/migrate-state-out-of-config.js +1 -1
  61. package/dist/config/model-profile-store.d.ts +4 -54
  62. package/dist/config/model-profile-store.js +3 -3
  63. package/dist/config/prompt-history.js +1 -1
  64. package/dist/config/store.d.ts +2 -2
  65. package/dist/config/store.js +3 -3
  66. package/dist/diagnostics/doctor.js +4 -4
  67. package/dist/exec/bridge/decisions.d.ts +1 -1
  68. package/dist/exec/bridge/human-answers.d.ts +1 -1
  69. package/dist/exec/bridge/human-answers.js +1 -1
  70. package/dist/exec/bridge/protocol.d.ts +1 -1
  71. package/dist/exec/bridge/server.js +1 -1
  72. package/dist/exec/events.d.ts +2 -2
  73. package/dist/exec/index.d.ts +1 -1
  74. package/dist/exec/index.js +1 -1
  75. package/dist/exec/permission.js +1 -1
  76. package/dist/exec/runner.d.ts +3 -3
  77. package/dist/exec/runner.js +2 -2
  78. package/dist/exec/threads/runtime.js +1 -1
  79. package/dist/fast/digest.d.ts +1 -1
  80. package/dist/fast/digest.js +1 -1
  81. package/dist/fast/frames.d.ts +1 -1
  82. package/dist/fast/frames.js +1 -1
  83. package/dist/fast/prompt.d.ts +1 -1
  84. package/dist/fast/prompt.js +1 -1
  85. package/dist/fast/review-call.js +1 -1
  86. package/dist/fast/reviewer.d.ts +3 -3
  87. package/dist/fast/reviewer.js +1 -1
  88. package/dist/fast/summary-call.d.ts +3 -3
  89. package/dist/fast/summary-call.js +2 -2
  90. package/dist/fast/summary-prompt.d.ts +1 -1
  91. package/dist/fast/summary-prompt.js +1 -1
  92. package/dist/fast/wiring.d.ts +4 -4
  93. package/dist/fast/wiring.js +1 -1
  94. package/dist/governance/card-normalize.d.ts +1 -1
  95. package/dist/governance/copy.d.ts +1 -1
  96. package/dist/governance/copy.js +2 -2
  97. package/dist/governance/engine/artifact-persist.d.ts +1 -1
  98. package/dist/governance/engine/budget.d.ts +1 -1
  99. package/dist/governance/engine/budget.js +1 -1
  100. package/dist/governance/engine/cards.d.ts +1 -1
  101. package/dist/governance/engine/digest.js +1 -1
  102. package/dist/governance/engine/engine-core.d.ts +5 -5
  103. package/dist/governance/engine/engine-core.js +1 -1
  104. package/dist/governance/engine/engine.d.ts +1 -1
  105. package/dist/governance/engine/engine.js +1 -1
  106. package/dist/governance/engine/estimate.d.ts +1 -1
  107. package/dist/governance/engine/estimate.js +1 -1
  108. package/dist/governance/engine/inspector.js +2 -2
  109. package/dist/governance/engine/integration.d.ts +1 -1
  110. package/dist/governance/engine/lifecycle.d.ts +1 -1
  111. package/dist/governance/engine/lifecycle.js +1 -1
  112. package/dist/governance/engine/phase-members.d.ts +1 -1
  113. package/dist/governance/engine/phase-planner.d.ts +1 -1
  114. package/dist/governance/engine/phase-planner.js +1 -1
  115. package/dist/governance/engine/rebuild.d.ts +1 -1
  116. package/dist/governance/engine/report.d.ts +1 -1
  117. package/dist/governance/engine/report.js +1 -1
  118. package/dist/governance/engine/run-digest.d.ts +1 -1
  119. package/dist/governance/engine/spec-builder.d.ts +2 -2
  120. package/dist/governance/engine/spec-builder.js +2 -2
  121. package/dist/governance/engine/stage-runner.js +2 -2
  122. package/dist/governance/engine/start-input.d.ts +1 -1
  123. package/dist/governance/engine/start-input.js +1 -1
  124. package/dist/governance/engine/state-machine.d.ts +1 -1
  125. package/dist/governance/engine/state-machine.js +3 -3
  126. package/dist/governance/engine/submission-queries.d.ts +1 -1
  127. package/dist/governance/engine/submission-render.d.ts +1 -1
  128. package/dist/governance/engine/submissions.d.ts +1 -1
  129. package/dist/governance/engine/submissions.js +1 -1
  130. package/dist/governance/engine/visibility.d.ts +1 -1
  131. package/dist/governance/engine/visibility.js +1 -1
  132. package/dist/governance/posture-transition.d.ts +2 -2
  133. package/dist/governance/posture-transition.js +1 -1
  134. package/dist/governance/profiles.d.ts +1 -1
  135. package/dist/governance/prompts/orchestrator-block.d.ts +2 -2
  136. package/dist/governance/prompts/orchestrator-block.js +2 -2
  137. package/dist/governance/prompts/plan-addendum.d.ts +1 -1
  138. package/dist/governance/prompts/plan-addendum.js +1 -1
  139. package/dist/governance/prompts/role-blocks.d.ts +2 -2
  140. package/dist/governance/prompts/role-blocks.js +1 -1
  141. package/dist/governance/report-reader.js +1 -1
  142. package/dist/governance/roles.d.ts +1 -1
  143. package/dist/governance/rules/claims.d.ts +1 -1
  144. package/dist/governance/rules/claims.js +1 -1
  145. package/dist/governance/rules/elimination.d.ts +1 -1
  146. package/dist/governance/rules/elimination.js +1 -1
  147. package/dist/governance/rules/failure-analysis.d.ts +2 -2
  148. package/dist/governance/rules/failure-analysis.js +1 -1
  149. package/dist/governance/rules/ledger-replay.d.ts +1 -1
  150. package/dist/governance/rules/ledger-state.d.ts +1 -1
  151. package/dist/governance/rules/ledger-state.js +1 -1
  152. package/dist/governance/rules/ledger.d.ts +2 -2
  153. package/dist/governance/rules/ledger.js +2 -2
  154. package/dist/governance/rules/rca.d.ts +1 -1
  155. package/dist/governance/rules/rca.js +1 -1
  156. package/dist/governance/rules/settlement.d.ts +2 -2
  157. package/dist/governance/rules/settlement.js +2 -2
  158. package/dist/governance/rules/suspicion.d.ts +1 -1
  159. package/dist/governance/store/artifacts.d.ts +1 -1
  160. package/dist/governance/store/artifacts.js +1 -1
  161. package/dist/governance/store/events-log.d.ts +1 -1
  162. package/dist/governance/store/run-store.d.ts +1 -1
  163. package/dist/governance/store/run-store.js +1 -1
  164. package/dist/governance/store/scoreboard-export.d.ts +1 -1
  165. package/dist/governance/tools/child-tools.d.ts +1 -1
  166. package/dist/governance/tools/guard.d.ts +1 -1
  167. package/dist/governance/tools/guard.js +1 -1
  168. package/dist/governance/tools/inspector-tools.d.ts +2 -2
  169. package/dist/governance/tools/inspector-tools.js +2 -2
  170. package/dist/governance/tools/lead-tools.d.ts +1 -1
  171. package/dist/governance/tools/lead-tools.js +1 -1
  172. package/dist/governance/tools/normalize-util.js +1 -1
  173. package/dist/governance/tools/scan-incomplete.js +1 -1
  174. package/dist/governance/tools/shared-tools.d.ts +1 -1
  175. package/dist/governance/tools/shared-tools.js +1 -1
  176. package/dist/governance/tools/submit-normalizers.d.ts +1 -1
  177. package/dist/governance/tools/submit-normalizers.js +1 -1
  178. package/dist/governance/tools/submit-tools.d.ts +1 -1
  179. package/dist/logging/cli-commands.js +1 -1
  180. package/dist/logging/install.d.ts +1 -1
  181. package/dist/logging/install.js +3 -3
  182. package/dist/logging/logger.d.ts +2 -2
  183. package/dist/logging/logger.js +31 -2
  184. package/dist/proc/kill-tree.js +1 -1
  185. package/dist/proc/log-mirror.js +1 -1
  186. package/dist/proc/log-ring.js +2 -2
  187. package/dist/proc/notices.d.ts +1 -1
  188. package/dist/proc/notices.js +2 -2
  189. package/dist/proc/prompt.d.ts +1 -1
  190. package/dist/proc/prompt.js +8 -5
  191. package/dist/proc/readiness.js +1 -1
  192. package/dist/proc/supervisor.d.ts +1 -1
  193. package/dist/proc/supervisor.js +10 -4
  194. package/dist/proc/wait-plan.d.ts +39 -0
  195. package/dist/proc/wait-plan.js +77 -0
  196. package/dist/proc/wait.d.ts +37 -4
  197. package/dist/proc/wait.js +68 -5
  198. package/dist/prompts/command.d.ts +1 -1
  199. package/dist/prompts/command.js +1 -1
  200. package/dist/prompts/normalize.d.ts +1 -1
  201. package/dist/prompts/normalize.js +1 -1
  202. package/dist/prompts/resolve.d.ts +1 -1
  203. package/dist/prompts/store.d.ts +2 -12
  204. package/dist/prompts/store.js +6 -60
  205. package/dist/session/checkpoint.d.ts +2 -2
  206. package/dist/session/checkpoint.js +2 -0
  207. package/dist/session/clear-archive.d.ts +2 -2
  208. package/dist/session/persist.d.ts +2 -2
  209. package/dist/session/persist.js +20 -3
  210. package/dist/session/startup-session.d.ts +2 -2
  211. package/dist/session/validate-session.js +6 -3
  212. package/dist/skills/service.d.ts +2 -2
  213. package/dist/team/bus.d.ts +1 -1
  214. package/dist/team/bus.js +1 -1
  215. package/dist/team/child-reviewer.d.ts +2 -2
  216. package/dist/team/child-reviewer.js +1 -1
  217. package/dist/team/comm-tools.js +1 -1
  218. package/dist/team/dispatch-gate.js +1 -1
  219. package/dist/team/forced-dispatch.js +1 -1
  220. package/dist/team/forced-mode.d.ts +1 -1
  221. package/dist/team/forced-prompt.d.ts +1 -1
  222. package/dist/team/forced-prompt.js +1 -1
  223. package/dist/team/normalize.d.ts +1 -1
  224. package/dist/team/normalize.js +1 -1
  225. package/dist/team/overseer.d.ts +3 -3
  226. package/dist/team/overseer.js +3 -3
  227. package/dist/team/prompt.d.ts +1 -1
  228. package/dist/team/prompt.js +1 -1
  229. package/dist/team/report.d.ts +2 -2
  230. package/dist/team/report.js +2 -2
  231. package/dist/team/retry.d.ts +1 -1
  232. package/dist/team/retry.js +1 -1
  233. package/dist/team/runtime.d.ts +4 -4
  234. package/dist/team/runtime.js +2 -2
  235. package/dist/team/settled.d.ts +2 -2
  236. package/dist/team/subagent.d.ts +4 -4
  237. package/dist/team/subagent.js +5 -5
  238. package/dist/team/task-tool.d.ts +1 -1
  239. package/dist/team/task-tool.js +1 -1
  240. package/dist/todo/normalize.d.ts +1 -1
  241. package/dist/todo/normalize.js +1 -1
  242. package/dist/todo/prompt.d.ts +1 -1
  243. package/dist/todo/prompt.js +1 -1
  244. package/dist/todo/store.d.ts +1 -1
  245. package/dist/todo/store.js +2 -2
  246. package/dist/todo/todo-tool.d.ts +1 -1
  247. package/dist/todo/todo-tool.js +2 -2
  248. package/dist/tools/bash-tool.d.ts +1 -1
  249. package/dist/tools/bash-tool.js +2 -2
  250. package/dist/tools/diff.d.ts +1 -1
  251. package/dist/tools/diff.js +1 -1
  252. package/dist/tools/file-change-store.d.ts +1 -1
  253. package/dist/tools/fs-tools.d.ts +2 -2
  254. package/dist/tools/fs-tools.js +1 -1
  255. package/dist/tools/index.d.ts +3 -3
  256. package/dist/tools/index.js +1 -1
  257. package/dist/tools/job-tools.d.ts +14 -3
  258. package/dist/tools/job-tools.js +158 -35
  259. package/dist/tools/plan-tools.d.ts +1 -1
  260. package/dist/tools/plan-tools.js +1 -1
  261. package/dist/tools/proc-tools.d.ts +1 -1
  262. package/dist/tools/proc-tools.js +2 -2
  263. package/dist/update/classify-failure.d.ts +1 -1
  264. package/dist/update/install-lock.js +1 -1
  265. package/dist/update/install-source.d.ts +1 -1
  266. package/dist/update/installer.js +2 -2
  267. package/dist/update/npm-view.d.ts +1 -1
  268. package/dist/update/npm-view.js +1 -1
  269. package/dist/update/registry.d.ts +1 -1
  270. package/dist/update/registry.js +1 -1
  271. package/dist/update/service.d.ts +2 -2
  272. package/dist/update/service.js +2 -2
  273. package/package.json +7 -7
  274. package/dist/agent/agent-mode.d.ts +0 -108
  275. package/dist/agent/agent-mode.js +0 -121
  276. package/dist/agent/entry-limits.d.ts +0 -65
  277. package/dist/agent/entry-limits.js +0 -133
  278. package/dist/agent/governance-view.d.ts +0 -40
  279. package/dist/agent/governance-view.js +0 -40
  280. package/dist/agent/invocation-card.d.ts +0 -77
  281. package/dist/agent/invocation-card.js +0 -169
  282. package/dist/agent/model-probe-limits.d.ts +0 -39
  283. package/dist/agent/model-probe-limits.js +0 -25
  284. package/dist/agent/model-probe.d.ts +0 -104
  285. package/dist/agent/model-probe.js +0 -391
  286. package/dist/agent/queued-messages.d.ts +0 -23
  287. package/dist/agent/queued-messages.js +0 -49
  288. package/dist/agent/reducer.d.ts +0 -837
  289. package/dist/agent/reducer.js +0 -1617
  290. package/dist/agent/retry-view.d.ts +0 -68
  291. package/dist/agent/retry-view.js +0 -95
  292. package/dist/agent/usage.d.ts +0 -47
  293. package/dist/agent/usage.js +0 -84
  294. package/dist/compaction/limits.d.ts +0 -61
  295. package/dist/compaction/limits.js +0 -64
  296. package/dist/compaction/meter.d.ts +0 -276
  297. package/dist/compaction/meter.js +0 -512
  298. package/dist/compaction/pressure.d.ts +0 -163
  299. package/dist/compaction/pressure.js +0 -199
  300. package/dist/compaction/reason-text.d.ts +0 -36
  301. package/dist/compaction/reason-text.js +0 -78
  302. package/dist/compaction/types.d.ts +0 -360
  303. package/dist/compaction/types.js +0 -22
  304. package/dist/config/governance-config.d.ts +0 -125
  305. package/dist/config/governance-config.js +0 -164
  306. package/dist/config/kit-resolution.d.ts +0 -93
  307. package/dist/config/kit-resolution.js +0 -226
  308. package/dist/config/model-kits.d.ts +0 -225
  309. package/dist/config/model-kits.js +0 -302
  310. package/dist/config/model-profile-resolution.d.ts +0 -28
  311. package/dist/config/model-profile-resolution.js +0 -88
  312. package/dist/config/model-profiles.d.ts +0 -103
  313. package/dist/config/model-profiles.js +0 -188
  314. package/dist/config/schema.d.ts +0 -1645
  315. package/dist/config/schema.js +0 -1377
  316. package/dist/fast/limits.d.ts +0 -152
  317. package/dist/fast/limits.js +0 -152
  318. package/dist/fast/resolve.d.ts +0 -44
  319. package/dist/fast/resolve.js +0 -107
  320. package/dist/fast/task-summary-types.d.ts +0 -66
  321. package/dist/fast/task-summary-types.js +0 -17
  322. package/dist/fast/types.d.ts +0 -141
  323. package/dist/fast/types.js +0 -14
  324. package/dist/governance/governed-dispatch.d.ts +0 -19
  325. package/dist/governance/governed-dispatch.js +0 -17
  326. package/dist/governance/limits.d.ts +0 -107
  327. package/dist/governance/limits.js +0 -131
  328. package/dist/governance/posture.d.ts +0 -35
  329. package/dist/governance/posture.js +0 -59
  330. package/dist/governance/rules/events-table.d.ts +0 -46
  331. package/dist/governance/rules/events-table.js +0 -94
  332. package/dist/governance/types.d.ts +0 -661
  333. package/dist/governance/types.js +0 -27
  334. package/dist/input/control-sequences.d.ts +0 -71
  335. package/dist/input/control-sequences.js +0 -222
  336. package/dist/input/csiu-keys.d.ts +0 -66
  337. package/dist/input/csiu-keys.js +0 -181
  338. package/dist/input/cursor-report.d.ts +0 -61
  339. package/dist/input/cursor-report.js +0 -97
  340. package/dist/input/enter-sequences.d.ts +0 -64
  341. package/dist/input/enter-sequences.js +0 -153
  342. package/dist/input/interrupt-gesture.d.ts +0 -18
  343. package/dist/input/interrupt-gesture.js +0 -19
  344. package/dist/input/keyboard-enhancement.d.ts +0 -42
  345. package/dist/input/keyboard-enhancement.js +0 -65
  346. package/dist/input/keymap.d.ts +0 -20
  347. package/dist/input/keymap.js +0 -99
  348. package/dist/input/limits.d.ts +0 -118
  349. package/dist/input/limits.js +0 -109
  350. package/dist/input/mouse-events.d.ts +0 -87
  351. package/dist/input/mouse-events.js +0 -212
  352. package/dist/input/paste-parse.d.ts +0 -83
  353. package/dist/input/paste-parse.js +0 -107
  354. package/dist/input/pointer-router.d.ts +0 -11
  355. package/dist/input/pointer-router.js +0 -14
  356. package/dist/input/stdin-filter.d.ts +0 -112
  357. package/dist/input/stdin-filter.js +0 -657
  358. package/dist/input/win32-input-mode.d.ts +0 -61
  359. package/dist/input/win32-input-mode.js +0 -269
  360. package/dist/logging/levels.d.ts +0 -40
  361. package/dist/logging/levels.js +0 -59
  362. package/dist/logging/secret-registry.d.ts +0 -32
  363. package/dist/logging/secret-registry.js +0 -73
  364. package/dist/proc/limits.d.ts +0 -200
  365. package/dist/proc/limits.js +0 -207
  366. package/dist/proc/progress.d.ts +0 -40
  367. package/dist/proc/progress.js +0 -135
  368. package/dist/proc/types.d.ts +0 -263
  369. package/dist/proc/types.js +0 -15
  370. package/dist/prompts/copy.d.ts +0 -89
  371. package/dist/prompts/copy.js +0 -131
  372. package/dist/prompts/fill.d.ts +0 -51
  373. package/dist/prompts/fill.js +0 -46
  374. package/dist/prompts/limits.d.ts +0 -53
  375. package/dist/prompts/limits.js +0 -53
  376. package/dist/prompts/search.d.ts +0 -58
  377. package/dist/prompts/search.js +0 -146
  378. package/dist/prompts/types.d.ts +0 -204
  379. package/dist/prompts/types.js +0 -13
  380. package/dist/team/activity.d.ts +0 -67
  381. package/dist/team/activity.js +0 -130
  382. package/dist/team/limits.d.ts +0 -308
  383. package/dist/team/limits.js +0 -330
  384. package/dist/team/model.d.ts +0 -104
  385. package/dist/team/model.js +0 -150
  386. package/dist/team/panel-rows.d.ts +0 -48
  387. package/dist/team/panel-rows.js +0 -75
  388. package/dist/team/timeline.d.ts +0 -74
  389. package/dist/team/timeline.js +0 -101
  390. package/dist/team/types.d.ts +0 -354
  391. package/dist/team/types.js +0 -13
  392. package/dist/todo/acceptance.d.ts +0 -120
  393. package/dist/todo/acceptance.js +0 -399
  394. package/dist/todo/follow-through.d.ts +0 -138
  395. package/dist/todo/follow-through.js +0 -248
  396. package/dist/todo/limits.d.ts +0 -152
  397. package/dist/todo/limits.js +0 -152
  398. package/dist/todo/panel-rows.d.ts +0 -45
  399. package/dist/todo/panel-rows.js +0 -70
  400. package/dist/todo/plan-sections.d.ts +0 -60
  401. package/dist/todo/plan-sections.js +0 -108
  402. package/dist/todo/row-window.d.ts +0 -51
  403. package/dist/todo/row-window.js +0 -107
  404. package/dist/todo/types.d.ts +0 -124
  405. package/dist/todo/types.js +0 -12
  406. package/dist/tools/human-input.d.ts +0 -212
  407. package/dist/tools/human-input.js +0 -265
  408. package/dist/tools/patch.d.ts +0 -115
  409. package/dist/tools/patch.js +0 -453
  410. package/dist/tools/terminal-output.d.ts +0 -115
  411. package/dist/tools/terminal-output.js +0 -201
  412. package/dist/tools/tool-output-store.d.ts +0 -68
  413. package/dist/tools/tool-output-store.js +0 -102
  414. package/dist/ui/ActivityLine.d.ts +0 -26
  415. package/dist/ui/ActivityLine.js +0 -48
  416. package/dist/ui/AutocompletePopup.d.ts +0 -23
  417. package/dist/ui/AutocompletePopup.js +0 -17
  418. package/dist/ui/BottomStatusRow.d.ts +0 -10
  419. package/dist/ui/BottomStatusRow.js +0 -9
  420. package/dist/ui/Composer.d.ts +0 -115
  421. package/dist/ui/Composer.js +0 -64
  422. package/dist/ui/GovernancePanel.d.ts +0 -50
  423. package/dist/ui/GovernancePanel.js +0 -77
  424. package/dist/ui/GovernanceRun.d.ts +0 -18
  425. package/dist/ui/GovernanceRun.js +0 -11
  426. package/dist/ui/Header.d.ts +0 -48
  427. package/dist/ui/Header.js +0 -27
  428. package/dist/ui/Logo.d.ts +0 -32
  429. package/dist/ui/Logo.js +0 -65
  430. package/dist/ui/Markdown.d.ts +0 -29
  431. package/dist/ui/Markdown.js +0 -116
  432. package/dist/ui/PromptCaret.d.ts +0 -11
  433. package/dist/ui/PromptCaret.js +0 -31
  434. package/dist/ui/PromptInput.d.ts +0 -192
  435. package/dist/ui/PromptInput.js +0 -689
  436. package/dist/ui/QueuePanel.d.ts +0 -8
  437. package/dist/ui/QueuePanel.js +0 -9
  438. package/dist/ui/QueueStatusRow.d.ts +0 -24
  439. package/dist/ui/QueueStatusRow.js +0 -51
  440. package/dist/ui/ScrollbackShell.d.ts +0 -132
  441. package/dist/ui/ScrollbackShell.js +0 -26
  442. package/dist/ui/SessionOpener.d.ts +0 -30
  443. package/dist/ui/SessionOpener.js +0 -12
  444. package/dist/ui/StatusBar.d.ts +0 -129
  445. package/dist/ui/StatusBar.js +0 -61
  446. package/dist/ui/TeamPanel.d.ts +0 -76
  447. package/dist/ui/TeamPanel.js +0 -103
  448. package/dist/ui/ToastStack.d.ts +0 -8
  449. package/dist/ui/ToastStack.js +0 -31
  450. package/dist/ui/TodoPanel.d.ts +0 -52
  451. package/dist/ui/TodoPanel.js +0 -214
  452. package/dist/ui/Transcript.d.ts +0 -105
  453. package/dist/ui/Transcript.js +0 -251
  454. package/dist/ui/UpdateLine.d.ts +0 -44
  455. package/dist/ui/UpdateLine.js +0 -129
  456. package/dist/ui/activity-phrases.d.ts +0 -33
  457. package/dist/ui/activity-phrases.js +0 -50
  458. package/dist/ui/capabilities.d.ts +0 -27
  459. package/dist/ui/capabilities.js +0 -65
  460. package/dist/ui/clipboard-task.d.ts +0 -29
  461. package/dist/ui/clipboard-task.js +0 -66
  462. package/dist/ui/clipboard.d.ts +0 -31
  463. package/dist/ui/clipboard.js +0 -157
  464. package/dist/ui/color-runtime.d.ts +0 -5
  465. package/dist/ui/color-runtime.js +0 -29
  466. package/dist/ui/composer-input.d.ts +0 -38
  467. package/dist/ui/composer-input.js +0 -79
  468. package/dist/ui/composer-limits.d.ts +0 -30
  469. package/dist/ui/composer-limits.js +0 -45
  470. package/dist/ui/composer-rows.d.ts +0 -73
  471. package/dist/ui/composer-rows.js +0 -129
  472. package/dist/ui/console-bridge.d.ts +0 -19
  473. package/dist/ui/console-bridge.js +0 -52
  474. package/dist/ui/density.d.ts +0 -26
  475. package/dist/ui/density.js +0 -34
  476. package/dist/ui/display-tab.d.ts +0 -51
  477. package/dist/ui/display-tab.js +0 -82
  478. package/dist/ui/editor-navigation.d.ts +0 -55
  479. package/dist/ui/editor-navigation.js +0 -96
  480. package/dist/ui/editor-reducer.d.ts +0 -108
  481. package/dist/ui/editor-reducer.js +0 -187
  482. package/dist/ui/enter-frames.d.ts +0 -47
  483. package/dist/ui/enter-frames.js +0 -117
  484. package/dist/ui/entries/AssistantEntry.d.ts +0 -37
  485. package/dist/ui/entries/AssistantEntry.js +0 -43
  486. package/dist/ui/entries/CompactionCard.d.ts +0 -88
  487. package/dist/ui/entries/CompactionCard.js +0 -222
  488. package/dist/ui/entries/DiffView.d.ts +0 -61
  489. package/dist/ui/entries/DiffView.js +0 -103
  490. package/dist/ui/entries/EntryFrame.d.ts +0 -23
  491. package/dist/ui/entries/EntryFrame.js +0 -6
  492. package/dist/ui/entries/FastCard.d.ts +0 -53
  493. package/dist/ui/entries/FastCard.js +0 -105
  494. package/dist/ui/entries/GovernanceCard.d.ts +0 -30
  495. package/dist/ui/entries/GovernanceCard.js +0 -32
  496. package/dist/ui/entries/InvocationCard.d.ts +0 -20
  497. package/dist/ui/entries/InvocationCard.js +0 -32
  498. package/dist/ui/entries/QueuedEntry.d.ts +0 -27
  499. package/dist/ui/entries/QueuedEntry.js +0 -33
  500. package/dist/ui/entries/RetryCard.d.ts +0 -56
  501. package/dist/ui/entries/RetryCard.js +0 -60
  502. package/dist/ui/entries/ServiceCard.d.ts +0 -82
  503. package/dist/ui/entries/ServiceCard.js +0 -151
  504. package/dist/ui/entries/TeamCard.d.ts +0 -55
  505. package/dist/ui/entries/TeamCard.js +0 -94
  506. package/dist/ui/entries/TodoCard.d.ts +0 -54
  507. package/dist/ui/entries/TodoCard.js +0 -98
  508. package/dist/ui/entries/ToolCard.d.ts +0 -81
  509. package/dist/ui/entries/ToolCard.js +0 -160
  510. package/dist/ui/entries/ToolPreview.d.ts +0 -59
  511. package/dist/ui/entries/ToolPreview.js +0 -208
  512. package/dist/ui/entries/UserEntry.d.ts +0 -36
  513. package/dist/ui/entries/UserEntry.js +0 -57
  514. package/dist/ui/exit-snapshot.d.ts +0 -43
  515. package/dist/ui/exit-snapshot.js +0 -26
  516. package/dist/ui/frame-differ.d.ts +0 -166
  517. package/dist/ui/frame-differ.js +0 -354
  518. package/dist/ui/frame-observer.d.ts +0 -17
  519. package/dist/ui/frame-observer.js +0 -94
  520. package/dist/ui/frame-parser.d.ts +0 -7
  521. package/dist/ui/frame-parser.js +0 -18
  522. package/dist/ui/gauge.d.ts +0 -39
  523. package/dist/ui/gauge.js +0 -55
  524. package/dist/ui/glyphs.d.ts +0 -178
  525. package/dist/ui/glyphs.js +0 -165
  526. package/dist/ui/governance-copy.d.ts +0 -69
  527. package/dist/ui/governance-copy.js +0 -104
  528. package/dist/ui/governance-status.d.ts +0 -145
  529. package/dist/ui/governance-status.js +0 -326
  530. package/dist/ui/gradient.d.ts +0 -11
  531. package/dist/ui/gradient.js +0 -50
  532. package/dist/ui/ink-runtime.d.ts +0 -4
  533. package/dist/ui/ink-runtime.js +0 -51
  534. package/dist/ui/interaction-copy.d.ts +0 -82
  535. package/dist/ui/interaction-copy.js +0 -38
  536. package/dist/ui/interaction-hints.d.ts +0 -44
  537. package/dist/ui/interaction-hints.js +0 -97
  538. package/dist/ui/layout/AppShell.d.ts +0 -17
  539. package/dist/ui/layout/AppShell.js +0 -6
  540. package/dist/ui/layout/Gutter.d.ts +0 -67
  541. package/dist/ui/layout/Gutter.js +0 -42
  542. package/dist/ui/layout/MeasuredEntry.d.ts +0 -21
  543. package/dist/ui/layout/MeasuredEntry.js +0 -30
  544. package/dist/ui/layout/OverlayFrame.d.ts +0 -73
  545. package/dist/ui/layout/OverlayFrame.js +0 -110
  546. package/dist/ui/layout/ScrollIndicator.d.ts +0 -32
  547. package/dist/ui/layout/ScrollIndicator.js +0 -22
  548. package/dist/ui/layout/ScrollViewport.d.ts +0 -40
  549. package/dist/ui/layout/ScrollViewport.js +0 -222
  550. package/dist/ui/layout/agents-board.d.ts +0 -102
  551. package/dist/ui/layout/agents-board.js +0 -389
  552. package/dist/ui/layout/autocomplete.d.ts +0 -18
  553. package/dist/ui/layout/autocomplete.js +0 -26
  554. package/dist/ui/layout/budget.d.ts +0 -43
  555. package/dist/ui/layout/budget.js +0 -52
  556. package/dist/ui/layout/cells.d.ts +0 -61
  557. package/dist/ui/layout/cells.js +0 -156
  558. package/dist/ui/layout/document-layout.d.ts +0 -13
  559. package/dist/ui/layout/document-layout.js +0 -10
  560. package/dist/ui/layout/follow-state.d.ts +0 -138
  561. package/dist/ui/layout/follow-state.js +0 -148
  562. package/dist/ui/layout/frame.d.ts +0 -36
  563. package/dist/ui/layout/frame.js +0 -39
  564. package/dist/ui/layout/governance-board.d.ts +0 -121
  565. package/dist/ui/layout/governance-board.js +0 -382
  566. package/dist/ui/layout/governance-card.d.ts +0 -53
  567. package/dist/ui/layout/governance-card.js +0 -134
  568. package/dist/ui/layout/governance-chip.d.ts +0 -38
  569. package/dist/ui/layout/governance-chip.js +0 -64
  570. package/dist/ui/layout/governance-panel.d.ts +0 -85
  571. package/dist/ui/layout/governance-panel.js +0 -358
  572. package/dist/ui/layout/governance-roster.d.ts +0 -65
  573. package/dist/ui/layout/governance-roster.js +0 -275
  574. package/dist/ui/layout/header-hints.d.ts +0 -90
  575. package/dist/ui/layout/header-hints.js +0 -110
  576. package/dist/ui/layout/header-left.d.ts +0 -115
  577. package/dist/ui/layout/header-left.js +0 -206
  578. package/dist/ui/layout/invocation-card.d.ts +0 -41
  579. package/dist/ui/layout/invocation-card.js +0 -91
  580. package/dist/ui/layout/kit-chip.d.ts +0 -50
  581. package/dist/ui/layout/kit-chip.js +0 -81
  582. package/dist/ui/layout/overlay-window.d.ts +0 -43
  583. package/dist/ui/layout/overlay-window.js +0 -51
  584. package/dist/ui/layout/queue-layout.d.ts +0 -19
  585. package/dist/ui/layout/queue-layout.js +0 -26
  586. package/dist/ui/layout/rail.d.ts +0 -7
  587. package/dist/ui/layout/rail.js +0 -16
  588. package/dist/ui/layout/scroll-indicator.d.ts +0 -27
  589. package/dist/ui/layout/scroll-indicator.js +0 -36
  590. package/dist/ui/layout/scroll.d.ts +0 -37
  591. package/dist/ui/layout/scroll.js +0 -99
  592. package/dist/ui/layout/scrollbar-geometry.d.ts +0 -17
  593. package/dist/ui/layout/scrollbar-geometry.js +0 -13
  594. package/dist/ui/layout/session-chip.d.ts +0 -52
  595. package/dist/ui/layout/session-chip.js +0 -64
  596. package/dist/ui/layout/shortcut-panel-layout.d.ts +0 -191
  597. package/dist/ui/layout/shortcut-panel-layout.js +0 -321
  598. package/dist/ui/layout/status-detail-layout.d.ts +0 -9
  599. package/dist/ui/layout/status-detail-layout.js +0 -79
  600. package/dist/ui/layout/status-layout.d.ts +0 -139
  601. package/dist/ui/layout/status-layout.js +0 -253
  602. package/dist/ui/layout/task-summary-cell.d.ts +0 -61
  603. package/dist/ui/layout/task-summary-cell.js +0 -65
  604. package/dist/ui/layout/team-panel.d.ts +0 -18
  605. package/dist/ui/layout/team-panel.js +0 -25
  606. package/dist/ui/layout/team-row.d.ts +0 -139
  607. package/dist/ui/layout/team-row.js +0 -246
  608. package/dist/ui/layout/todo-layout.d.ts +0 -62
  609. package/dist/ui/layout/todo-layout.js +0 -102
  610. package/dist/ui/layout/useTerminalSize.d.ts +0 -13
  611. package/dist/ui/layout/useTerminalSize.js +0 -50
  612. package/dist/ui/layout/viewport-geometry.d.ts +0 -29
  613. package/dist/ui/layout/viewport-geometry.js +0 -28
  614. package/dist/ui/layout/virtual-window.d.ts +0 -112
  615. package/dist/ui/layout/virtual-window.js +0 -488
  616. package/dist/ui/layout/wrap-rows.d.ts +0 -26
  617. package/dist/ui/layout/wrap-rows.js +0 -88
  618. package/dist/ui/live-clamp.d.ts +0 -14
  619. package/dist/ui/live-clamp.js +0 -46
  620. package/dist/ui/markdown-blocks.d.ts +0 -107
  621. package/dist/ui/markdown-blocks.js +0 -240
  622. package/dist/ui/overlays/AgentsBoardOverlay.d.ts +0 -57
  623. package/dist/ui/overlays/AgentsBoardOverlay.js +0 -183
  624. package/dist/ui/overlays/ConfirmDialog.d.ts +0 -31
  625. package/dist/ui/overlays/ConfirmDialog.js +0 -44
  626. package/dist/ui/overlays/GovernanceBoardOverlay.d.ts +0 -41
  627. package/dist/ui/overlays/GovernanceBoardOverlay.js +0 -76
  628. package/dist/ui/overlays/GovernanceSettingsPage.d.ts +0 -48
  629. package/dist/ui/overlays/GovernanceSettingsPage.js +0 -93
  630. package/dist/ui/overlays/HelpOverlay.d.ts +0 -29
  631. package/dist/ui/overlays/HelpOverlay.js +0 -232
  632. package/dist/ui/overlays/KitEditor.d.ts +0 -23
  633. package/dist/ui/overlays/KitEditor.js +0 -101
  634. package/dist/ui/overlays/KitManager.d.ts +0 -23
  635. package/dist/ui/overlays/KitManager.js +0 -104
  636. package/dist/ui/overlays/KitPicker.d.ts +0 -49
  637. package/dist/ui/overlays/KitPicker.js +0 -58
  638. package/dist/ui/overlays/ModelDiscoveryList.d.ts +0 -23
  639. package/dist/ui/overlays/ModelDiscoveryList.js +0 -161
  640. package/dist/ui/overlays/ModelPicker.d.ts +0 -26
  641. package/dist/ui/overlays/ModelPicker.js +0 -63
  642. package/dist/ui/overlays/ModelProfileEditor.d.ts +0 -29
  643. package/dist/ui/overlays/ModelProfileEditor.js +0 -168
  644. package/dist/ui/overlays/ModelProfilePicker.d.ts +0 -48
  645. package/dist/ui/overlays/ModelProfilePicker.js +0 -231
  646. package/dist/ui/overlays/PlanReviewOverlay.d.ts +0 -51
  647. package/dist/ui/overlays/PlanReviewOverlay.js +0 -132
  648. package/dist/ui/overlays/PromptEditorPage.d.ts +0 -48
  649. package/dist/ui/overlays/PromptEditorPage.js +0 -227
  650. package/dist/ui/overlays/PromptLibraryOverlay.d.ts +0 -37
  651. package/dist/ui/overlays/PromptLibraryOverlay.js +0 -191
  652. package/dist/ui/overlays/PromptPicker.d.ts +0 -36
  653. package/dist/ui/overlays/PromptPicker.js +0 -129
  654. package/dist/ui/overlays/PromptTextArea.d.ts +0 -86
  655. package/dist/ui/overlays/PromptTextArea.js +0 -141
  656. package/dist/ui/overlays/QuestionOverlay.d.ts +0 -39
  657. package/dist/ui/overlays/QuestionOverlay.js +0 -258
  658. package/dist/ui/overlays/QueueOverlay.d.ts +0 -22
  659. package/dist/ui/overlays/QueueOverlay.js +0 -79
  660. package/dist/ui/overlays/SettingsScreen.d.ts +0 -228
  661. package/dist/ui/overlays/SettingsScreen.js +0 -1037
  662. package/dist/ui/overlays/ShortcutPanel.d.ts +0 -39
  663. package/dist/ui/overlays/ShortcutPanel.js +0 -106
  664. package/dist/ui/overlays/TeamFanoutPage.d.ts +0 -51
  665. package/dist/ui/overlays/TeamFanoutPage.js +0 -90
  666. package/dist/ui/overlays/governance-settings.d.ts +0 -79
  667. package/dist/ui/overlays/governance-settings.js +0 -140
  668. package/dist/ui/overlays/kit-picker-state.d.ts +0 -87
  669. package/dist/ui/overlays/kit-picker-state.js +0 -136
  670. package/dist/ui/overlays/kit-settings-state.d.ts +0 -129
  671. package/dist/ui/overlays/kit-settings-state.js +0 -268
  672. package/dist/ui/overlays/model-probe-view.d.ts +0 -128
  673. package/dist/ui/overlays/model-probe-view.js +0 -225
  674. package/dist/ui/overlays/model-profile-state.d.ts +0 -177
  675. package/dist/ui/overlays/model-profile-state.js +0 -301
  676. package/dist/ui/overlays/prompt-library-state.d.ts +0 -162
  677. package/dist/ui/overlays/prompt-library-state.js +0 -335
  678. package/dist/ui/overlays/prompt-picker-state.d.ts +0 -71
  679. package/dist/ui/overlays/prompt-picker-state.js +0 -98
  680. package/dist/ui/overlays/team-fanout-state.d.ts +0 -106
  681. package/dist/ui/overlays/team-fanout-state.js +0 -155
  682. package/dist/ui/overlays/use-model-probe.d.ts +0 -30
  683. package/dist/ui/overlays/use-model-probe.js +0 -109
  684. package/dist/ui/palettes.d.ts +0 -112
  685. package/dist/ui/palettes.js +0 -130
  686. package/dist/ui/paste-frames.d.ts +0 -91
  687. package/dist/ui/paste-frames.js +0 -117
  688. package/dist/ui/paste-tokens.d.ts +0 -90
  689. package/dist/ui/paste-tokens.js +0 -147
  690. package/dist/ui/render-cache.d.ts +0 -81
  691. package/dist/ui/render-cache.js +0 -196
  692. package/dist/ui/render-governor.d.ts +0 -54
  693. package/dist/ui/render-governor.js +0 -78
  694. package/dist/ui/run-metrics.d.ts +0 -23
  695. package/dist/ui/run-metrics.js +0 -27
  696. package/dist/ui/run-status-row.d.ts +0 -61
  697. package/dist/ui/run-status-row.js +0 -54
  698. package/dist/ui/screen.d.ts +0 -107
  699. package/dist/ui/screen.js +0 -234
  700. package/dist/ui/scrollback/LiveTail.d.ts +0 -115
  701. package/dist/ui/scrollback/LiveTail.js +0 -48
  702. package/dist/ui/scrollback/band.d.ts +0 -114
  703. package/dist/ui/scrollback/band.js +0 -143
  704. package/dist/ui/scrollback/budget.d.ts +0 -90
  705. package/dist/ui/scrollback/budget.js +0 -100
  706. package/dist/ui/scrollback/canvas.d.ts +0 -100
  707. package/dist/ui/scrollback/canvas.js +0 -114
  708. package/dist/ui/scrollback/cursor-probe.d.ts +0 -71
  709. package/dist/ui/scrollback/cursor-probe.js +0 -133
  710. package/dist/ui/scrollback/drain.d.ts +0 -32
  711. package/dist/ui/scrollback/drain.js +0 -64
  712. package/dist/ui/scrollback/exit-summary.d.ts +0 -23
  713. package/dist/ui/scrollback/exit-summary.js +0 -25
  714. package/dist/ui/scrollback/limits.d.ts +0 -98
  715. package/dist/ui/scrollback/limits.js +0 -98
  716. package/dist/ui/scrollback/live-preview.d.ts +0 -34
  717. package/dist/ui/scrollback/live-preview.js +0 -118
  718. package/dist/ui/scrollback/overflow-print.d.ts +0 -108
  719. package/dist/ui/scrollback/overflow-print.js +0 -120
  720. package/dist/ui/scrollback/renderer.d.ts +0 -48
  721. package/dist/ui/scrollback/renderer.js +0 -186
  722. package/dist/ui/scrollback/scrollback-writer.d.ts +0 -174
  723. package/dist/ui/scrollback/scrollback-writer.js +0 -648
  724. package/dist/ui/scrollback/settled-boundary.d.ts +0 -42
  725. package/dist/ui/scrollback/settled-boundary.js +0 -109
  726. package/dist/ui/scrollback/tail-anchor.d.ts +0 -71
  727. package/dist/ui/scrollback/tail-anchor.js +0 -79
  728. package/dist/ui/scrollback/tail-window.d.ts +0 -73
  729. package/dist/ui/scrollback/tail-window.js +0 -89
  730. package/dist/ui/scrollback/use-scrollback-view.d.ts +0 -139
  731. package/dist/ui/scrollback/use-scrollback-view.js +0 -601
  732. package/dist/ui/scrollback/writer-shapes.d.ts +0 -127
  733. package/dist/ui/scrollback/writer-shapes.js +0 -159
  734. package/dist/ui/scrollbar-controller.d.ts +0 -30
  735. package/dist/ui/scrollbar-controller.js +0 -124
  736. package/dist/ui/selection/highlight.d.ts +0 -39
  737. package/dist/ui/selection/highlight.js +0 -64
  738. package/dist/ui/selection/screen-mirror.d.ts +0 -24
  739. package/dist/ui/selection/screen-mirror.js +0 -35
  740. package/dist/ui/selection/selection-controller.d.ts +0 -104
  741. package/dist/ui/selection/selection-controller.js +0 -372
  742. package/dist/ui/selection/selection.d.ts +0 -90
  743. package/dist/ui/selection/selection.js +0 -223
  744. package/dist/ui/shortcuts.d.ts +0 -81
  745. package/dist/ui/shortcuts.js +0 -221
  746. package/dist/ui/status-feedback.d.ts +0 -35
  747. package/dist/ui/status-feedback.js +0 -38
  748. package/dist/ui/stdout-frame-writer.d.ts +0 -74
  749. package/dist/ui/stdout-frame-writer.js +0 -155
  750. package/dist/ui/team-status.d.ts +0 -166
  751. package/dist/ui/team-status.js +0 -252
  752. package/dist/ui/terminal-plan.d.ts +0 -52
  753. package/dist/ui/terminal-plan.js +0 -49
  754. package/dist/ui/theme.d.ts +0 -96
  755. package/dist/ui/theme.js +0 -130
  756. package/dist/ui/transcript-text.d.ts +0 -41
  757. package/dist/ui/transcript-text.js +0 -282
  758. package/dist/ui/use-height-store.d.ts +0 -31
  759. package/dist/ui/use-height-store.js +0 -76
  760. package/dist/ui/use-render-governor.d.ts +0 -39
  761. package/dist/ui/use-render-governor.js +0 -57
  762. package/dist/ui/use-wheel-routing.d.ts +0 -57
  763. package/dist/ui/use-wheel-routing.js +0 -152
  764. package/dist/ui/win-vt-force.d.ts +0 -136
  765. package/dist/ui/win-vt-force.js +0 -237
  766. package/dist/ui/win-vt-input.d.ts +0 -57
  767. package/dist/ui/win-vt-input.js +0 -62
  768. package/dist/update/limits.d.ts +0 -111
  769. package/dist/update/limits.js +0 -111
  770. package/dist/update/semver.d.ts +0 -89
  771. package/dist/update/semver.js +0 -295
  772. package/dist/update/types.d.ts +0 -169
  773. package/dist/update/types.js +0 -68
  774. /package/dist/{ui → app}/session-bridge.d.ts +0 -0
  775. /package/dist/{ui → app}/session-bridge.js +0 -0
@@ -1,1377 +0,0 @@
1
- /**
2
- * Config schema — the persisted config-file shape, the in-memory effective
3
- * config, sane defaults, and small validation/masking helpers.
4
- *
5
- * See spec §3.5 (resolution pipeline), §6.1 (config file), and §3.8 (timeout
6
- * invariant).
7
- */
8
- import { isAbsolute } from 'node:path';
9
- import { ABSOLUTE_MAX_OUTPUT_TOKENS, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_RETRY_POLICY, MIN_MAX_OUTPUT_TOKENS, RETRY_LIMITS, } from '@aragon-agent/core';
10
- import { clampLogLevel } from '../logging/levels.js';
11
- import { TEAM_LIMITS } from '../team/limits.js';
12
- import { DEFAULT_GOVERNANCE_CONFIG } from './governance-config.js';
13
- // Governance mode (governance-mode 11.1): defined in its own file so this one does not grow.
14
- export { clampGovernanceConfig, DEFAULT_GOVERNANCE_CONFIG, } from './governance-config.js';
15
- // ---------------------------------------------------------------------------
16
- // Provider set — only the adapter-backed providers are usable at run time (R5).
17
- // ---------------------------------------------------------------------------
18
- /**
19
- * `ModelRegistry` seeds builtin lists for five providers, but `initProviders()`
20
- * registers only three adapters. Running a model whose provider has no adapter
21
- * throws `Unknown LLM provider`, so the CLI only ever offers these three.
22
- */
23
- export const ADAPTER_PROVIDERS = ['anthropic', 'openai', 'google'];
24
- export function isAdapterProvider(id) {
25
- return ADAPTER_PROVIDERS.includes(id);
26
- }
27
- // ---------------------------------------------------------------------------
28
- // Thinking levels
29
- // ---------------------------------------------------------------------------
30
- export const THINKING_LEVELS = [
31
- 'off',
32
- 'minimal',
33
- 'low',
34
- 'medium',
35
- 'high',
36
- 'xhigh',
37
- ];
38
- export function isThinkingLevel(v) {
39
- return typeof v === 'string' && THINKING_LEVELS.includes(v);
40
- }
41
- export function clampThinkingLevel(v, fallback) {
42
- return isThinkingLevel(v) ? v : fallback;
43
- }
44
- // ---------------------------------------------------------------------------
45
- // Theme
46
- // ---------------------------------------------------------------------------
47
- export const THEME_NAMES = ['auto', 'warm', 'cool', 'light'];
48
- /** The v0.3.0 name for what is now `cool`. Accepted forever as an alias. */
49
- export const LEGACY_DARK_THEME = 'dark';
50
- export function isThemeName(v) {
51
- return typeof v === 'string' && THEME_NAMES.includes(v);
52
- }
53
- /**
54
- * THE single gate for every theme write (spec §4.5 / R-4).
55
- *
56
- * All three write paths funnel through here — config resolution (`load.ts`),
57
- * `aragon config set theme`, and the `/theme` slash command — which is why the
58
- * `dark -> cool` migration lives here and nowhere else. Putting it in a
59
- * `load.ts` normalization step instead would migrate what users *read* but not
60
- * what they *write*, producing the worst kind of bug: "the flag works but the
61
- * setting won't stick."
62
- *
63
- * An unrecognized value still falls back silently (plus a warn toast at the call
64
- * site). Turning that into a hard exit would be an unannounced breaking change
65
- * and would not match `clampThinkingLevel` / `clampTranscriptWindow`.
66
- */
67
- export function clampTheme(v, fallback) {
68
- if (v === LEGACY_DARK_THEME)
69
- return 'cool';
70
- return isThemeName(v) ? v : fallback;
71
- }
72
- // ---------------------------------------------------------------------------
73
- // Density / hints (v0.4.0)
74
- // ---------------------------------------------------------------------------
75
- export const SCROLL_MODES = ['native', 'app'];
76
- export const DEFAULT_SCROLL_MODE = 'native';
77
- export function clampScrollMode(v, fallback) {
78
- if (typeof v !== 'string')
79
- return fallback;
80
- const normalized = v.trim().toLowerCase();
81
- return normalized === 'native' || normalized === 'app' ? normalized : fallback;
82
- }
83
- export const DENSITY_MODES = ['comfortable', 'compact'];
84
- export function clampDensity(v, fallback) {
85
- return v === 'comfortable' || v === 'compact' ? v : fallback;
86
- }
87
- /**
88
- * Submissions after which the composer hint collapses to `? help` (§4.6).
89
- * Only the IDLE hint fades; the running hint carries the abort key and is
90
- * always shown in full.
91
- */
92
- export const HINT_FADE_AFTER = 8;
93
- // ---------------------------------------------------------------------------
94
- // Defaults
95
- // ---------------------------------------------------------------------------
96
- export const CONFIG_VERSION = 1;
97
- export const DEFAULT_MODEL = 'claude-sonnet-4-5-20250929';
98
- /** Per-tool executor ceiling (§3.8). Headroom for typical installs/builds. */
99
- export const DEFAULT_TOOL_TIMEOUT_MS = 180_000;
100
- /** Extra margin so idle timeout is strictly greater than the tool ceiling. */
101
- export const IDLE_TIMEOUT_MARGIN_MS = 30_000;
102
- /** Watchdog idle timeout (§3.8) — must stay ≥ toolTimeout so long tools survive. */
103
- export const DEFAULT_IDLE_TIMEOUT_MS = DEFAULT_TOOL_TIMEOUT_MS + IDLE_TIMEOUT_MARGIN_MS;
104
- /**
105
- * Cap on the recall list.
106
- *
107
- * The list itself now lives in `<home>/prompt-history.jsonl`; this constant is
108
- * consumed by `config/prompt-history.ts`, not by the UI.
109
- */
110
- export const PROMPT_HISTORY_CAP = 100;
111
- /**
112
- * The SCROLL HORIZON: entries older than this are not reachable inside the app
113
- * and render as the "N earlier entries collapsed" line instead (invariant I-3).
114
- *
115
- * It used to be a rendering budget as well, because yoga laid out every child
116
- * even when `overflow: hidden` clipped it. The viewport is virtualised now
117
- * (tui-render-performance L3) — off-screen entries are not mounted at all — so
118
- * the horizon costs O(entries) of arithmetic rather than O(characters) of layout
119
- * and the default rises 300 -> 1000 with a 20000 ceiling. An existing persisted
120
- * `300` is still valid and still clamps; no config migration is required.
121
- */
122
- export const DEFAULT_TRANSCRIPT_WINDOW = 1000;
123
- export const MIN_TRANSCRIPT_WINDOW = 50;
124
- export const MAX_TRANSCRIPT_WINDOW = 20_000;
125
- export function clampTranscriptWindow(v, fallback) {
126
- const n = coercePositiveInt(v, fallback);
127
- return Math.min(MAX_TRANSCRIPT_WINDOW, Math.max(MIN_TRANSCRIPT_WINDOW, n));
128
- }
129
- // ---------------------------------------------------------------------------
130
- // Context window override (context-usage-gauge-accuracy §3.6 / W5)
131
- // ---------------------------------------------------------------------------
132
- /**
133
- * Bounds for a hand-supplied context window.
134
- *
135
- * The floor is roughly the smallest window any current model ships with; the
136
- * ceiling is well above the largest, and both exist to keep a typo (a missing
137
- * or an extra zero) from producing a gauge that is permanently red or
138
- * permanently flat.
139
- */
140
- export const MIN_CONTEXT_WINDOW = 8_000;
141
- export const MAX_CONTEXT_WINDOW = 5_000_000;
142
- /**
143
- * THE single gate for every `contextWindow` read AND write.
144
- *
145
- * TRI-STATE, AND `null` MUST PASS STRAIGHT THROUGH (RV-12). `null` means AUTO -
146
- * take the model table's number, or the 128k placeholder. Clamping it into
147
- * `[8000, ...]` yields 8000, which removes "auto" from the config permanently
148
- * and presents to the user as an 8k denominator with a permanently red bar and
149
- * no visible source. `maxTokens` above is the existing tri-state precedent and
150
- * this deliberately copies its shape rather than inventing a second convention.
151
- */
152
- export function clampContextWindow(v, fallback) {
153
- if (v === null)
154
- return null;
155
- if (v === undefined || v === '')
156
- return fallback;
157
- const n = typeof v === 'number' ? v : Number.parseInt(String(v), 10);
158
- if (!Number.isFinite(n) || n <= 0)
159
- return fallback;
160
- return Math.min(MAX_CONTEXT_WINDOW, Math.max(MIN_CONTEXT_WINDOW, Math.floor(n)));
161
- }
162
- /**
163
- * Parse text typed into the settings screen or the profile editor for a
164
- * context window (profile-context-window §5.3).
165
- *
166
- * THE MIRROR OF `parseMaxTokensInput` BELOW, down to the tri-state shape: it
167
- * distinguishes AUTO from "the user typed nonsense", which `clampContextWindow`
168
- * cannot - a typo must change NOTHING rather than silently discard the number
169
- * the user meant to set. `''` / `'auto'` / `'0'` are AUTO (`isAutoToken`);
170
- * a digit run is clamped through THE single gate; anything else is invalid.
171
- */
172
- export function parseContextWindowInput(raw) {
173
- const trimmed = String(raw ?? '').trim();
174
- if (isAutoToken(trimmed))
175
- return { kind: 'auto' };
176
- if (!/^\d+$/.test(trimmed))
177
- return { kind: 'invalid' };
178
- const value = clampContextWindow(trimmed, null);
179
- if (value === null)
180
- return { kind: 'invalid' };
181
- return { kind: 'value', value, clamped: value !== Number.parseInt(trimmed, 10) };
182
- }
183
- /**
184
- * Entries kept in `ViewState` at all (tui-render-performance L1 / R5).
185
- *
186
- * A DIFFERENT BOUND FROM `transcriptWindow`, and the two must not be merged:
187
- * the window is what the user can scroll to, this is what the process keeps in
188
- * memory and what `/save` can export. Dropped entries are COUNTED and reported
189
- * (`/perf`, and a leading line in the exported transcript) — never silent.
190
- */
191
- export const DEFAULT_TRANSCRIPT_RETAIN = 1000;
192
- export const MIN_TRANSCRIPT_RETAIN = 200;
193
- export const MAX_TRANSCRIPT_RETAIN = 20_000;
194
- export function clampTranscriptRetain(v, fallback) {
195
- const n = coercePositiveInt(v, fallback);
196
- return Math.min(MAX_TRANSCRIPT_RETAIN, Math.max(MIN_TRANSCRIPT_RETAIN, n));
197
- }
198
- // ---------------------------------------------------------------------------
199
- // Adaptive render governor (tui-render-performance L4 / R7)
200
- // ---------------------------------------------------------------------------
201
- /** Adaptive coalescing under load. On by default; `--no-render-governor` kills it. */
202
- export const DEFAULT_RENDER_GOVERNOR = true;
203
- /**
204
- * Ceiling of the governor ladder, in ms. `33` flattens the ladder to a single
205
- * rung, which is the pre-feature behaviour without needing the kill switch.
206
- */
207
- export const DEFAULT_MAX_RENDER_INTERVAL_MS = 320;
208
- const RENDER_INTERVAL_RANGE = { min: 33, max: 1000 };
209
- export function clampMaxRenderInterval(v, fallback) {
210
- return clampInt(v, fallback, RENDER_INTERVAL_RANGE);
211
- }
212
- // ---------------------------------------------------------------------------
213
- // Frame diffing (tui-input-flicker-fix §5.1)
214
- //
215
- // TWO TROUBLESHOOTING SWITCHES, in the same class as `historyEnabled`: neither
216
- // appears on the settings overlay, because a user who needs them is debugging a
217
- // terminal, not adjusting a preference.
218
- // ---------------------------------------------------------------------------
219
- /**
220
- * Repaint only the frame lines that changed (full-screen only).
221
- *
222
- * ON by default, and `--no-diff-render` restores today's byte stream EXACTLY —
223
- * the interposer is not constructed at all, so a regression on an exotic
224
- * terminal is one flag away from being neutralised (§3.5 rung 2).
225
- */
226
- export const DEFAULT_DIFF_RENDER = true;
227
- /**
228
- * Wrap each repaint batch in DEC 2026 begin/end synchronized update.
229
- *
230
- * ON by default with NO capability probe (§3.3): terminals that do not implement
231
- * mode 2026 parse the CSI sequence, find an unknown private mode and discard it,
232
- * so a false positive costs nothing — and a false negative costs nothing either,
233
- * because the frame differ already removes the flicker on its own.
234
- */
235
- export const DEFAULT_SYNC_OUTPUT = true;
236
- // ---------------------------------------------------------------------------
237
- // Selection + scroll follow (tui-selection-and-scroll-follow §6.1)
238
- // ---------------------------------------------------------------------------
239
- /**
240
- * Drag-select + copy, and — because §4.4.1 gates `\x1b[?1002h` on exactly this
241
- * value — whether motion reporting is requested from the terminal at all.
242
- *
243
- * That gating is what makes `false` BYTE-IDENTICAL to a pre-feature session
244
- * rather than merely equivalent (AC-8 / D-15). Ignored when `mouse` is false,
245
- * since there is no capture to select with.
246
- */
247
- export const DEFAULT_MOUSE_SELECT = true;
248
- /**
249
- * Idle delay before a paused viewport returns to the newest line, in ms.
250
- *
251
- * Five seconds is chosen to be LONGER than a glance and SHORTER than a read.
252
- * `0` disables auto-resume entirely, and it is a real value rather than a
253
- * sentinel-shaped default: `shouldArmResume` refuses on it before any timer is
254
- * created (AC-9), so the revert for Rule B is one config key.
255
- *
256
- * NO CLI FLAG (§6.1). It is a comfort preference, set once
257
- * (`aragon config set scrollResumeMs 8000`) and then forgotten — the same
258
- * argument this file already makes for `historyEnabled`. Adding a flag for every
259
- * scalar is how a CLI ends up with sixty of them.
260
- */
261
- export const DEFAULT_SCROLL_RESUME_MS = 5000;
262
- const SCROLL_RESUME_RANGE = { min: 0, max: 120_000 };
263
- /**
264
- * `clampIntAllowingZero`, and the choice is load-bearing: `clampInt` delegates to
265
- * `coercePositiveInt`, which returns the FALLBACK for `n <= 0` — so `0` would
266
- * silently become 5000 and the documented off switch would not be an off switch.
267
- * Exactly the trap `retry.maxRetries` needed this helper for.
268
- */
269
- export function clampScrollResumeMs(v, fallback) {
270
- return clampIntAllowingZero(v, fallback, SCROLL_RESUME_RANGE);
271
- }
272
- // ---------------------------------------------------------------------------
273
- // Plan mode (plan-mode §4.4)
274
- //
275
- // THREE FLAT KEYS, not a nested `planMode` object. `store.ts` documents that its
276
- // nested-object merge is hand-written and capped at one level; three scalars do
277
- // not justify a second `clampXConfig` gate plus two more merge sites, and flat
278
- // keys mean `store.ts` needs ZERO changes.
279
- //
280
- // ONE OF THOSE KEYS IS GONE: `planModeMaxAskRounds` capped `ask_user` at four
281
- // rounds per turn. There is no cap any more, so there is no number to store, no
282
- // range to clamp and nothing to configure. It is retired through
283
- // `RETIRED_CONFIG_KEYS` below rather than defaulted to a large number — a
284
- // ninety-nine in the config file is the same second source of truth as a four.
285
- // ---------------------------------------------------------------------------
286
- /**
287
- * Ceiling on ONE human wait, in ms. Thirty minutes is far outside "the user
288
- * went to get coffee", but a ceiling has to exist: an unattended terminal must
289
- * not wedge a CI job or a stale ssh session forever.
290
- *
291
- * THIS IS NOT A ROUND LIMIT and the distinction matters. It bounds a single wait
292
- * (liveness); it says nothing about how many times the model may ask.
293
- */
294
- export const DEFAULT_PLAN_HUMAN_TIMEOUT_MS = 1_800_000;
295
- const HUMAN_TIMEOUT_RANGE = { min: 60_000, max: 7_200_000 };
296
- export function clampHumanTimeout(v, fallback) {
297
- return clampInt(v, fallback, HUMAN_TIMEOUT_RANGE);
298
- }
299
- export const SKILLS_INTEGRITY_MODES = ['off', 'warn', 'strict'];
300
- export function clampSkillsIntegrity(v, fallback) {
301
- return typeof v === 'string' && SKILLS_INTEGRITY_MODES.includes(v)
302
- ? v
303
- : fallback;
304
- }
305
- export const SKILLS_TOOL_POLICY_MODES = ['off', 'warn', 'enforce'];
306
- export function isSkillsToolPolicyMode(v) {
307
- return typeof v === 'string' && SKILLS_TOOL_POLICY_MODES.includes(v);
308
- }
309
- export function clampSkillsToolPolicy(v, fallback) {
310
- return isSkillsToolPolicyMode(v) ? v : fallback;
311
- }
312
- export const DEFAULT_ALLOWED_SKILL_HOSTS = [
313
- 'github.com',
314
- 'raw.githubusercontent.com',
315
- 'codeload.github.com',
316
- 'gitlab.com',
317
- 'objects.githubusercontent.com',
318
- ];
319
- export const DEFAULT_SKILLS_CONFIG = {
320
- enabled: true,
321
- disabled: [],
322
- requireApproval: true,
323
- allowedHosts: DEFAULT_ALLOWED_SKILL_HOSTS,
324
- projectDirs: ['.aragon/skills', '.claude/skills'],
325
- trustedProjectDirs: [],
326
- catalogMaxBytes: 6000,
327
- bodyMaxBytes: 30_000,
328
- integrity: 'warn',
329
- usageTracking: true,
330
- toolPolicy: 'enforce',
331
- // ON by default: the capability this key controls is the feature's whole point,
332
- // and it costs zero model calls (local matching over in-memory records).
333
- triage: true,
334
- };
335
- const CATALOG_BYTES_RANGE = { min: 500, max: 40_000 };
336
- /**
337
- * Upper bound is 50 000, NOT the 90 000 an earlier draft used.
338
- * `SKILL_RESULT_MAX_BYTES` is 60 000 and must also fit the file list and the
339
- * head/tail guidance; 50 000 leaves that margin. A 90 000-CHARACTER body is
340
- * 270 000 bytes of CJK, which `ToolExecutor` would chop mid-tag (D19).
341
- */
342
- const BODY_BYTES_RANGE = { min: 1000, max: 50_000 };
343
- function clampInt(v, fallback, range) {
344
- const n = coercePositiveInt(v, fallback);
345
- return Math.min(range.max, Math.max(range.min, n));
346
- }
347
- /**
348
- * `clampInt` for a key whose range legitimately includes ZERO.
349
- *
350
- * `clampInt` delegates to `coercePositiveInt`, which returns the FALLBACK for
351
- * `n <= 0` — so a range whose floor is `0` cannot express `0` through it, and the
352
- * value silently becomes the default. That trap is invisible at the call site and
353
- * is what `retry.maxRetries` needs this helper for: `0` is that key's documented
354
- * floor and its kill switch, and four documented controls send it
355
- * (`/retry max 0`, `--retry-max 0`, `ARAGON_RETRY_MAX=0`,
356
- * `aragon config set retry.maxRetries 0`). Through `clampInt` all four would set
357
- * the MAXIMUM instead of the minimum, with no error anywhere.
358
- *
359
- * Own coercion: `Number.parseInt`, reject only non-finite and negative, then
360
- * floor and clamp.
361
- */
362
- function clampIntAllowingZero(v, fallback, range) {
363
- if (v === null || v === undefined || v === '')
364
- return clampToRange(fallback, range);
365
- const n = typeof v === 'number' ? v : Number.parseInt(String(v), 10);
366
- if (!Number.isFinite(n) || n < 0)
367
- return clampToRange(fallback, range);
368
- return clampToRange(Math.floor(n), range);
369
- }
370
- /**
371
- * `clampInt` for a key that is legitimately a FLOAT.
372
- *
373
- * `coercePositiveInt` floors, and `2.5` is a legitimate backoff factor — the same
374
- * coercion trap `clampIntAllowingZero` above closes for `0`, one type over.
375
- */
376
- function clampNumber(v, fallback, range) {
377
- if (v === null || v === undefined || v === '')
378
- return clampToRange(fallback, range);
379
- const n = typeof v === 'number' ? v : Number.parseFloat(String(v));
380
- if (!Number.isFinite(n))
381
- return clampToRange(fallback, range);
382
- return clampToRange(n, range);
383
- }
384
- function clampToRange(n, range) {
385
- return Math.min(range.max, Math.max(range.min, n));
386
- }
387
- function stringArray(v, fallback) {
388
- if (!Array.isArray(v))
389
- return fallback;
390
- const out = v.filter((item) => typeof item === 'string' && item.trim().length > 0);
391
- return out.map((s) => s.trim());
392
- }
393
- function bool(v, fallback) {
394
- return typeof v === 'boolean' ? v : fallback;
395
- }
396
- /**
397
- * THE single gate for every skills-config read AND write (§10.3.1).
398
- *
399
- * Shared by `loadConfig()`, `loadPersistedConfig()` and `updatePersistedConfig()`
400
- * on purpose: hardening only the read path would leave a corrupt value on disk
401
- * that silently reverts to a default on every launch — the failure looks like
402
- * "my setting won't stick" with no error anywhere.
403
- */
404
- export function clampSkillsConfig(raw) {
405
- const src = (raw && typeof raw === 'object' ? raw : {});
406
- return {
407
- enabled: bool(src.enabled, DEFAULT_SKILLS_CONFIG.enabled),
408
- disabled: stringArray(src.disabled, DEFAULT_SKILLS_CONFIG.disabled),
409
- requireApproval: bool(src.requireApproval, DEFAULT_SKILLS_CONFIG.requireApproval),
410
- allowedHosts: stringArray(src.allowedHosts, DEFAULT_SKILLS_CONFIG.allowedHosts),
411
- projectDirs: stringArray(src.projectDirs, DEFAULT_SKILLS_CONFIG.projectDirs),
412
- trustedProjectDirs: stringArray(src.trustedProjectDirs, DEFAULT_SKILLS_CONFIG.trustedProjectDirs),
413
- catalogMaxBytes: clampInt(src.catalogMaxBytes, DEFAULT_SKILLS_CONFIG.catalogMaxBytes, CATALOG_BYTES_RANGE),
414
- bodyMaxBytes: clampInt(src.bodyMaxBytes, DEFAULT_SKILLS_CONFIG.bodyMaxBytes, BODY_BYTES_RANGE),
415
- integrity: clampSkillsIntegrity(src.integrity, DEFAULT_SKILLS_CONFIG.integrity),
416
- usageTracking: bool(src.usageTracking, DEFAULT_SKILLS_CONFIG.usageTracking),
417
- toolPolicy: clampSkillsToolPolicy(src.toolPolicy, DEFAULT_SKILLS_CONFIG.toolPolicy),
418
- triage: bool(src.triage, DEFAULT_SKILLS_CONFIG.triage),
419
- };
420
- }
421
- export const DEFAULT_SKILLS_RUNTIME = { forcedSkills: [], approveAll: false };
422
- const DEFAULT_MAX_LOG_FILE_BYTES = 5 * 1024 * 1024;
423
- const LOG_FILE_BYTES_RANGE = { min: 64 * 1024, max: 256 * 1024 * 1024 };
424
- const LOG_MAX_FILES_RANGE = { min: 1, max: 200 };
425
- const LOG_PREVIEW_CHARS_RANGE = { min: 0, max: 8192 };
426
- export const DEFAULT_LOG_CONFIG = {
427
- level: 'info',
428
- toFile: true,
429
- dir: '',
430
- maxFileBytes: DEFAULT_MAX_LOG_FILE_BYTES,
431
- maxFiles: 10,
432
- redactSecrets: true,
433
- previewChars: 512,
434
- };
435
- /**
436
- * Coerce a log directory. Anything relative is discarded (falling back to
437
- * `<home>/logs`) rather than resolved: a relative path would silently mean a
438
- * different directory for every working directory the CLI is launched from, and
439
- * `debug`-level files carry prompt text (R-13).
440
- */
441
- function logDir(v, fallback) {
442
- if (typeof v !== 'string')
443
- return fallback;
444
- const trimmed = v.trim();
445
- if (trimmed.length === 0)
446
- return '';
447
- return isAbsolute(trimmed) ? trimmed : fallback;
448
- }
449
- /**
450
- * THE single gate for every log-config read AND write, exactly like
451
- * `clampSkillsConfig`: hardening only the read path leaves a bad value on disk
452
- * that reverts on every launch, which presents as "my setting won't stick".
453
- *
454
- * `previewChars` uses its own coercion because `coercePositiveInt` rejects `0`,
455
- * and `0` is a legitimate value here — it means "record that content existed,
456
- * but none of it".
457
- */
458
- export function clampLogConfig(raw) {
459
- const src = (raw && typeof raw === 'object' ? raw : {});
460
- const preview = typeof src.previewChars === 'number' || typeof src.previewChars === 'string'
461
- ? Number.parseInt(String(src.previewChars), 10)
462
- : Number.NaN;
463
- return {
464
- level: clampLogLevel(src.level, DEFAULT_LOG_CONFIG.level),
465
- toFile: bool(src.toFile, DEFAULT_LOG_CONFIG.toFile),
466
- dir: logDir(src.dir, DEFAULT_LOG_CONFIG.dir),
467
- maxFileBytes: clampInt(src.maxFileBytes, DEFAULT_LOG_CONFIG.maxFileBytes, LOG_FILE_BYTES_RANGE),
468
- maxFiles: clampInt(src.maxFiles, DEFAULT_LOG_CONFIG.maxFiles, LOG_MAX_FILES_RANGE),
469
- redactSecrets: bool(src.redactSecrets, DEFAULT_LOG_CONFIG.redactSecrets),
470
- previewChars: Number.isFinite(preview)
471
- ? Math.min(LOG_PREVIEW_CHARS_RANGE.max, Math.max(LOG_PREVIEW_CHARS_RANGE.min, preview))
472
- : DEFAULT_LOG_CONFIG.previewChars,
473
- };
474
- }
475
- /**
476
- * The requirement's ceiling on the fan-out (R-g).
477
- *
478
- * Re-exported from `TEAM_LIMITS` rather than re-spelled, because it is enforced
479
- * in TWO places — here on the config value, and again in
480
- * `normalizeSubagentSpecs` on what the model asked for — and two copies of the
481
- * same 10 is exactly how a hand-edited `config.json` ends up being able to raise
482
- * a ceiling the requirement fixed.
483
- */
484
- export const HARD_MAX_SUBAGENTS = TEAM_LIMITS.hardMaxSubagents;
485
- export const DEFAULT_TEAM_CONFIG = {
486
- enabled: true,
487
- // 8 IS THE DEFAULT, 10 IS THE CEILING, and they are not the same number
488
- // (subagent-fanout D-1 / D-2). `maxConcurrent` moves WITH `maxSubagents`
489
- // because a wider population behind a 3-wide pool shows the user nothing:
490
- // children 4..8 simply queue (`team-bus.test.ts` records the queued phase).
491
- maxSubagents: 8,
492
- maxConcurrent: 8,
493
- // 0 = NO LIMIT. Subagents run under the same regime as the lead: no
494
- // wall clock, no turn cap; only the idle watchdog and the user's Esc.
495
- subagentTimeoutMs: 0,
496
- dispatchTimeoutMs: 0,
497
- maxTurnsPerSubagent: 0,
498
- // The dispatch supervisor, default ON (team-overseer): ceilings become
499
- // inspections; the fast-tier supervisor decides what to do.
500
- overseer: true,
501
- // 0 = the structural cadence default (300 s). See the field docstring.
502
- overseerIntervalMs: 0,
503
- // The parity default: children run the lead's own model until the user
504
- // says otherwise (AC-1 - an upgraded config behaves exactly as before).
505
- model: 'main',
506
- modelProfileId: null,
507
- };
508
- const SUBAGENTS_RANGE = { min: 1, max: HARD_MAX_SUBAGENTS };
509
- const CONCURRENT_RANGE = { min: 1, max: HARD_MAX_SUBAGENTS };
510
- // `min: 0` is the documented OFF SWITCH for each bound, so these MUST use
511
- // `clampIntAllowingZero`: plain `clampInt` folds `0` back to the fallback
512
- // ("my setting won't stick"), the exact trap `scrollResumeMs` records above.
513
- const SUBAGENT_TIMEOUT_RANGE = { min: 0, max: 1_800_000 };
514
- const DISPATCH_TIMEOUT_RANGE = { min: 0, max: 3_600_000 };
515
- const OVERSEER_INTERVAL_RANGE = { min: 0, max: 3_600_000 };
516
- const TURNS_RANGE = { min: 0, max: 100 };
517
- /**
518
- * THE single gate for every team-config read AND write, mirroring
519
- * `clampSkillsConfig` / `clampLogConfig` for the reason those two record:
520
- * hardening only the read path leaves a bad value on disk that reverts to the
521
- * default on every launch, which presents to the user as "my setting won't
522
- * stick".
523
- *
524
- * `maxConcurrent` is additionally capped at `maxSubagents`: a pool wider than
525
- * the population it draws from is not wrong so much as meaningless, and letting
526
- * the two disagree would make the panel's `n/m` readout confusing for no gain.
527
- */
528
- export function clampTeamConfig(raw) {
529
- const src = (raw && typeof raw === 'object' ? raw : {});
530
- const maxSubagents = clampInt(src.maxSubagents, DEFAULT_TEAM_CONFIG.maxSubagents, SUBAGENTS_RANGE);
531
- return {
532
- enabled: bool(src.enabled, DEFAULT_TEAM_CONFIG.enabled),
533
- maxSubagents,
534
- maxConcurrent: Math.min(maxSubagents, clampInt(src.maxConcurrent, DEFAULT_TEAM_CONFIG.maxConcurrent, CONCURRENT_RANGE)),
535
- subagentTimeoutMs: clampIntAllowingZero(src.subagentTimeoutMs, DEFAULT_TEAM_CONFIG.subagentTimeoutMs, SUBAGENT_TIMEOUT_RANGE),
536
- dispatchTimeoutMs: clampIntAllowingZero(src.dispatchTimeoutMs, DEFAULT_TEAM_CONFIG.dispatchTimeoutMs, DISPATCH_TIMEOUT_RANGE),
537
- maxTurnsPerSubagent: clampIntAllowingZero(src.maxTurnsPerSubagent, DEFAULT_TEAM_CONFIG.maxTurnsPerSubagent, TURNS_RANGE),
538
- overseer: bool(src.overseer, DEFAULT_TEAM_CONFIG.overseer),
539
- overseerIntervalMs: clampIntAllowingZero(src.overseerIntervalMs, DEFAULT_TEAM_CONFIG.overseerIntervalMs, OVERSEER_INTERVAL_RANGE),
540
- // typo-changes-nothing, the discipline every enum clamp here follows: a
541
- // hand-edited `model: 'fats'` resolves to 'main' (the parity default)
542
- // rather than invalidating the file or refusing to launch. A bad
543
- // `modelProfileId` (wrong type, or over the 128-codepoint budget
544
- // `model-profiles.ts::validText` defines) is nulled the same way;
545
- // reference EXISTENCE stays a resolution-time concern (D-4).
546
- model: src.model === 'fast' || src.model === 'profile' ? src.model : 'main',
547
- modelProfileId: typeof src.modelProfileId === 'string' && src.modelProfileId.length > 0
548
- && [...src.modelProfileId].length <= 128
549
- ? src.modelProfileId
550
- : null,
551
- // TRANSPARENT, and only ever `true` (subagent-fanout D-3 / R-6). The flag is
552
- // not a setting: it is the one-shot marker the migration leaves behind, so a
553
- // clamp that dropped it would re-migrate the user on every launch. Written
554
- // as a spread rather than `=== true ? true : undefined` so the key stays
555
- // ABSENT (not `undefined`) in the clamped result - `toEqual(DEFAULT_TEAM_CONFIG)`
556
- // and the on-disk shape both depend on that.
557
- ...(src.fanoutMigrated === true ? { fanoutMigrated: true } : {}),
558
- };
559
- }
560
- /**
561
- * The team ceilings cli <= 0.6.16 (7a6bf5630) persisted as its OWN defaults:
562
- * every user who touched team mode back then still carries this exact triple
563
- * in config.json, because `resolveTeamConfig` merges file values verbatim and
564
- * no migration ever rewrote them. They are the kill ceilings behind F-8's
565
- * "first block all failed" dispatches, so loading rewrites them to 0 (= no
566
- * ceiling, the shipped default since 2ff15a9c3).
567
- *
568
- * EXACT-EQUALITY ONLY: a value that differs was a deliberate user choice and
569
- * survives untouched. The price of that test is that a user who hand-types
570
- * 300000 today is migrated to 0 too - the accepted trade, and the safe
571
- * direction (no ceiling, not a cliff).
572
- */
573
- export const LEGACY_TEAM_CEILING_DEFAULTS = {
574
- subagentTimeoutMs: 300_000,
575
- dispatchTimeoutMs: 900_000,
576
- maxTurnsPerSubagent: 24,
577
- };
578
- /**
579
- * The `{ key: 0 }` patch for legacy-default-equal ceilings, or `null` when
580
- * nothing matches. Pure on purpose: `loadConfig` decides WHERE the patch is
581
- * applied and persisted; this function only answers WHICH keys match, so the
582
- * equality test lives beside the constants it reads.
583
- */
584
- export function legacyTeamCeilingPatch(raw) {
585
- if (!raw || typeof raw !== 'object')
586
- return null;
587
- const src = raw;
588
- const patch = {};
589
- let matched = false;
590
- for (const key of Object.keys(LEGACY_TEAM_CEILING_DEFAULTS)) {
591
- if (src[key] === LEGACY_TEAM_CEILING_DEFAULTS[key]) {
592
- patch[key] = 0;
593
- matched = true;
594
- }
595
- }
596
- return matched ? patch : null;
597
- }
598
- /**
599
- * The fan-out defaults cli <= 0.6.x persisted as its OWN defaults
600
- * (subagent-fanout F-2 / R-1).
601
- *
602
- * THE SAME TRAP AS THE CEILINGS ABOVE, ONE SECTION OVER. `mergePersistedConfig`
603
- * writes the WHOLE `team` section on every save, so a user who has ever touched
604
- * any setting carries this exact pair in `config.json` - changing
605
- * `DEFAULT_TEAM_CONFIG` alone would never reach them, and they would keep
606
- * seeing "only 3 subagents at once" for ever.
607
- */
608
- export const LEGACY_TEAM_FANOUT_DEFAULTS = {
609
- maxSubagents: 5,
610
- maxConcurrent: 3,
611
- };
612
- /**
613
- * The `{ maxSubagents, maxConcurrent, fanoutMigrated }` patch for the legacy
614
- * default pair, or `null` when nothing matches (subagent-fanout D-3).
615
- *
616
- * EXACT-EQUALITY ONLY, the rule `legacyTeamCeilingPatch` records: a value that
617
- * differs was a deliberate user choice and survives untouched. Two differences
618
- * from that function, both deliberate:
619
- *
620
- * - `fanoutMigrated: true` short-circuits to `null`. That is what makes "the
621
- * user changed their mind and went back to 5/3" stick: without it the next
622
- * launch would migrate them again, every launch, for ever.
623
- * - `maxConcurrent` is allowed to be ABSENT as well as 3, because a
624
- * hand-written section may name only one key and a half-written pair is
625
- * still the legacy intent, not a user decision.
626
- *
627
- * Pure on purpose: `loadConfig` decides WHERE the patch is applied and
628
- * persisted; this function only answers WHICH keys match, so the equality test
629
- * lives beside the constants it reads.
630
- */
631
- export function legacyTeamFanoutPatch(raw) {
632
- if (!raw || typeof raw !== 'object' || Array.isArray(raw))
633
- return null;
634
- const src = raw;
635
- if (src.fanoutMigrated === true)
636
- return null;
637
- if (src.maxSubagents !== LEGACY_TEAM_FANOUT_DEFAULTS.maxSubagents)
638
- return null;
639
- if (src.maxConcurrent !== undefined
640
- && src.maxConcurrent !== LEGACY_TEAM_FANOUT_DEFAULTS.maxConcurrent)
641
- return null;
642
- return {
643
- maxSubagents: DEFAULT_TEAM_CONFIG.maxSubagents,
644
- maxConcurrent: DEFAULT_TEAM_CONFIG.maxConcurrent,
645
- fanoutMigrated: true,
646
- };
647
- }
648
- export const DEFAULT_TODO_CONFIG = {
649
- enabled: true,
650
- panel: true,
651
- followThrough: 'notify',
652
- acceptance: true,
653
- };
654
- /**
655
- * There is no enum helper in this file, so this follows the `isThinkingLevel`
656
- * shape already here rather than inventing a second idiom.
657
- */
658
- const FOLLOW_THROUGH_MODES = ['notify', 'auto', 'off'];
659
- function followMode(value, fallback) {
660
- return typeof value === 'string' && FOLLOW_THROUGH_MODES.includes(value)
661
- ? value
662
- : fallback;
663
- }
664
- /**
665
- * THE single gate for every todo-config read AND write, mirroring
666
- * `clampSkillsConfig` / `clampLogConfig` / `clampTeamConfig` for the reason
667
- * those record: hardening only the read path leaves a bad value on disk that
668
- * reverts to the default on every launch, which presents to the user as "my
669
- * setting won't stick".
670
- */
671
- export function clampTodoConfig(raw) {
672
- const src = (raw && typeof raw === 'object' ? raw : {});
673
- return {
674
- enabled: bool(src.enabled, DEFAULT_TODO_CONFIG.enabled),
675
- panel: bool(src.panel, DEFAULT_TODO_CONFIG.panel),
676
- // CLAMPED TO THE DEFAULT, NEVER REJECTED — the discipline every other key in
677
- // this file follows, and the trade round 1 already made for `--thinking`.
678
- // `ARAGON_TODO_FOLLOW=garbage` therefore resolves to `'notify'` and throws
679
- // nothing (AC-5).
680
- followThrough: followMode(src.followThrough, DEFAULT_TODO_CONFIG.followThrough),
681
- // The fourth key needs nothing beyond this line: no migration, because
682
- // `CONFIG_VERSION` is only stamped and never branched, and an old file reaches
683
- // the new default through `{ ...DEFAULT, ...partial } + clamp`.
684
- acceptance: bool(src.acceptance, DEFAULT_TODO_CONFIG.acceptance),
685
- };
686
- }
687
- export const DEFAULT_RETRY_CONFIG = {
688
- enabled: true,
689
- maxRetries: DEFAULT_RETRY_POLICY.maxRetries,
690
- initialDelayMs: DEFAULT_RETRY_POLICY.initialDelayMs,
691
- maxDelayMs: DEFAULT_RETRY_POLICY.maxDelayMs,
692
- multiplier: DEFAULT_RETRY_POLICY.multiplier,
693
- jitter: DEFAULT_RETRY_POLICY.jitter,
694
- respectRetryAfter: DEFAULT_RETRY_POLICY.respectRetryAfter,
695
- maxElapsedMs: DEFAULT_RETRY_POLICY.maxElapsedMs,
696
- onPartialStream: DEFAULT_RETRY_POLICY.onPartialStream,
697
- };
698
- /**
699
- * `hardMaxRetries` re-exported rather than re-spelled, for the reason
700
- * `HARD_MAX_SUBAGENTS` records: the ceiling is enforced in TWO places — here on
701
- * the config value, and again by `normalizePolicy` inside the engine — and two
702
- * copies of the same 20 is exactly how a hand-edited `config.json` ends up able
703
- * to raise a ceiling the mechanism fixed.
704
- */
705
- export const HARD_MAX_RETRIES = RETRY_LIMITS.hardMaxRetries;
706
- /** FLOOR 0 — and `clampIntAllowingZero` is what makes that reachable. */
707
- const RETRY_MAX_RANGE = { min: 0, max: HARD_MAX_RETRIES };
708
- const RETRY_INITIAL_DELAY_RANGE = { min: 100, max: 30_000 };
709
- const RETRY_MAX_DELAY_RANGE = { min: 1000, max: RETRY_LIMITS.absoluteMaxDelayMs };
710
- const RETRY_MULTIPLIER_RANGE = { min: 1, max: 5 };
711
- const RETRY_ELAPSED_RANGE = { min: 10_000, max: 1_800_000 };
712
- /**
713
- * THE single gate for every retry-config read AND write, mirroring
714
- * `clampSkillsConfig` / `clampLogConfig` / `clampTeamConfig` / `clampTodoConfig`
715
- * for the reason those record: hardening only the read path leaves a bad value on
716
- * disk that reverts to the default on every launch, which presents to the user as
717
- * "my setting won't stick".
718
- *
719
- * Three invariants live inside the gate:
720
- *
721
- * - `maxDelayMs = max(maxDelayMs, initialDelayMs)` — a ceiling under the floor
722
- * makes the ladder a flat line and the countdown a lie.
723
- * - `multiplier` goes through `clampNumber`, not `clampInt`: `2.5` is a
724
- * legitimate factor and `coercePositiveInt` would floor it to 2.
725
- * - `maxRetries` goes through `clampIntAllowingZero`. THIS IS THE ONE THAT SHIPS
726
- * BROKEN WITHOUT IT (R-16): `clampInt` returns the fallback for `n <= 0`, so
727
- * `clampRetryConfig({ maxRetries: 0 })` would yield 10 — the maximum instead
728
- * of the minimum, silently, for the key that gates the whole feature.
729
- *
730
- * `maxElapsedMs` intentionally keeps plain `clampInt`: its floor is 10 000, so it
731
- * has no `0` to express.
732
- */
733
- export function clampRetryConfig(raw) {
734
- const src = (raw && typeof raw === 'object' ? raw : {});
735
- const initialDelayMs = clampInt(src.initialDelayMs, DEFAULT_RETRY_CONFIG.initialDelayMs, RETRY_INITIAL_DELAY_RANGE);
736
- const maxDelayMs = Math.max(initialDelayMs, clampInt(src.maxDelayMs, DEFAULT_RETRY_CONFIG.maxDelayMs, RETRY_MAX_DELAY_RANGE));
737
- return {
738
- enabled: bool(src.enabled, DEFAULT_RETRY_CONFIG.enabled),
739
- maxRetries: clampIntAllowingZero(src.maxRetries, DEFAULT_RETRY_CONFIG.maxRetries, RETRY_MAX_RANGE),
740
- initialDelayMs,
741
- maxDelayMs,
742
- multiplier: clampNumber(src.multiplier, DEFAULT_RETRY_CONFIG.multiplier, RETRY_MULTIPLIER_RANGE),
743
- jitter: bool(src.jitter, DEFAULT_RETRY_CONFIG.jitter),
744
- respectRetryAfter: bool(src.respectRetryAfter, DEFAULT_RETRY_CONFIG.respectRetryAfter),
745
- maxElapsedMs: clampInt(src.maxElapsedMs, DEFAULT_RETRY_CONFIG.maxElapsedMs, RETRY_ELAPSED_RANGE),
746
- onPartialStream: bool(src.onPartialStream, DEFAULT_RETRY_CONFIG.onPartialStream),
747
- };
748
- }
749
- /**
750
- * `RetryConfig` (user intent) -> `RetryPolicy` (engine policy), or `null` for
751
- * "the user said no".
752
- *
753
- * `null` rather than a policy with `maxRetries: 0` because `ProviderRegistry`
754
- * short-circuits on a null policy and returns the adapter's iterator DIRECTLY —
755
- * an opted-out session is then allocation-identical to a pre-feature build.
756
- *
757
- * TOTAL, AND IT ACCEPTS A MISSING SECTION. `loadConfig` always supplies one, but
758
- * a `CliConfig` built by hand — every controller test in this package does exactly
759
- * that, and so would an embedder — legitimately omits it, and a `TypeError` from a
760
- * pure translation function is the wrong way to find out. Routing through
761
- * `clampRetryConfig` also means an out-of-range hand-built value can never reach
762
- * the engine, which is the same "one gate, both directions" rule every other
763
- * section in this file follows.
764
- */
765
- export function toRetryPolicy(cfg) {
766
- const safe = clampRetryConfig(cfg);
767
- if (!safe.enabled || safe.maxRetries <= 0)
768
- return null;
769
- return {
770
- maxRetries: safe.maxRetries,
771
- initialDelayMs: safe.initialDelayMs,
772
- maxDelayMs: safe.maxDelayMs,
773
- multiplier: safe.multiplier,
774
- jitter: safe.jitter,
775
- respectRetryAfter: safe.respectRetryAfter,
776
- maxElapsedMs: safe.maxElapsedMs,
777
- onPartialStream: safe.onPartialStream,
778
- };
779
- }
780
- export const DEFAULT_FAST_CONFIG = {
781
- // R-d, and the one default in this file that is a REQUIREMENT rather than a
782
- // judgement: a feature that silently spends money on a second provider is not
783
- // a default (D-3).
784
- enabled: false,
785
- provider: '',
786
- model: '',
787
- baseUrl: '',
788
- thinkingLevel: 'off',
789
- review: true,
790
- reviewEveryTurns: 5,
791
- reviewContextTurns: 3,
792
- reviewMaxChars: 280,
793
- // 40 is roughly 200 reviewed turns at the default cadence: comfortably past a
794
- // full working session, short of a runaway (D-H2).
795
- reviewMaxPerSession: 40,
796
- };
797
- const REVIEW_EVERY_RANGE = { min: 1, max: 50 };
798
- const REVIEW_CONTEXT_RANGE = { min: 1, max: 10 };
799
- const REVIEW_CHARS_RANGE = { min: 80, max: 600 };
800
- /** No "unlimited" sentinel: a magic `0` reads as "disabled" to the next person
801
- * who meets it, and 500 is already past any session a human sits through. */
802
- const REVIEW_SESSION_RANGE = { min: 1, max: 500 };
803
- /** Trim a string field, falling back when the value is not a string at all. */
804
- function text(v, fallback) {
805
- return typeof v === 'string' ? v.trim() : fallback;
806
- }
807
- /**
808
- * THE single gate for every fast-config read AND write, mirroring
809
- * `clampSkillsConfig` / `clampLogConfig` / `clampTeamConfig` / `clampTodoConfig`
810
- * for the reason those four record: hardening only the read path leaves a bad
811
- * value on disk that reverts to the default on every launch, which presents to
812
- * the user as "my setting won't stick".
813
- *
814
- * `provider` is CLAMPED TO `''` rather than rejected when it names something
815
- * with no adapter. `''` means "inherit the main provider", which is the safe
816
- * reading of a typo — and `resolveFastTier` reports `no_adapter` for the case a
817
- * user really did configure a dead vendor as the MAIN one.
818
- */
819
- export function clampFastConfig(raw) {
820
- const src = (raw && typeof raw === 'object' ? raw : {});
821
- const provider = text(src.provider, DEFAULT_FAST_CONFIG.provider);
822
- return {
823
- enabled: bool(src.enabled, DEFAULT_FAST_CONFIG.enabled),
824
- provider: provider.length === 0 || isAdapterProvider(provider) ? provider : '',
825
- model: text(src.model, DEFAULT_FAST_CONFIG.model),
826
- baseUrl: text(src.baseUrl, DEFAULT_FAST_CONFIG.baseUrl),
827
- thinkingLevel: clampThinkingLevel(src.thinkingLevel, DEFAULT_FAST_CONFIG.thinkingLevel),
828
- review: bool(src.review, DEFAULT_FAST_CONFIG.review),
829
- reviewEveryTurns: clampInt(src.reviewEveryTurns, DEFAULT_FAST_CONFIG.reviewEveryTurns, REVIEW_EVERY_RANGE),
830
- reviewContextTurns: clampInt(src.reviewContextTurns, DEFAULT_FAST_CONFIG.reviewContextTurns, REVIEW_CONTEXT_RANGE),
831
- reviewMaxChars: clampInt(src.reviewMaxChars, DEFAULT_FAST_CONFIG.reviewMaxChars, REVIEW_CHARS_RANGE),
832
- reviewMaxPerSession: clampInt(src.reviewMaxPerSession, DEFAULT_FAST_CONFIG.reviewMaxPerSession, REVIEW_SESSION_RANGE),
833
- };
834
- }
835
- // ---------------------------------------------------------------------------
836
- // Auto-update (cli-auto-update §4.1)
837
- //
838
- // The EIGHTH nested section in the persisted config, after `apiKeys`, `skills`,
839
- // `log`, `team`, `todo`, `retry` and `fast` — and, like all of them, SCALARS
840
- // ONLY, exactly one level deep. `store.ts` merges these sections BY HAND and
841
- // that merge is only correct while nesting stays flat (C-5).
842
- //
843
- // BOTH OF `store.ts`'s MERGES MUST LEARN ABOUT THIS SECTION, AND THE OMISSION IS
844
- // SILENT (C-4 / R-10). `config set update.mode notify` sends
845
- // `{ update: { mode: 'notify' } }`; without the write merge the shallow
846
- // top-level spread REPLACES the whole section and `checkIntervalMs`, `registry`
847
- // and `distTag` silently revert on disk. This package has paid for that twice
848
- // already — `todo` P0-1 and `fast` R-10 — which is why it is written down a
849
- // third time rather than assumed to be common knowledge.
850
- //
851
- // FOUR KEYS AND NO MORE (D-16). `mode` covers on / notify / off; a fifth key
852
- // (`autoInstall`) would be a second way to say the same thing, and two ways to
853
- // express one setting is how they end up disagreeing.
854
- // ---------------------------------------------------------------------------
855
- /** `auto` installs; `notify` only reports; `off` disables the subsystem. */
856
- export const UPDATE_MODES = ['auto', 'notify', 'off'];
857
- export function isUpdateMode(v) {
858
- return typeof v === 'string' && UPDATE_MODES.includes(v);
859
- }
860
- export const DEFAULT_UPDATE_CONFIG = {
861
- mode: 'auto',
862
- // FOUR HOURS, in ms. `checkIntervalMs` and not `checkIntervalHours` (D-17):
863
- // every other duration in this config is in ms (`toolTimeoutMs`,
864
- // `idleTimeoutMs`, `team.dispatchTimeoutMs`, `retry.initialDelayMs`), and one
865
- // unit per file is worth more than one shorter number.
866
- checkIntervalMs: 14_400_000,
867
- registry: '',
868
- distTag: 'latest',
869
- };
870
- /** 15 minutes to 7 days. The floor is a politeness bound on the registry. */
871
- const UPDATE_INTERVAL_RANGE = { min: 900_000, max: 604_800_000 };
872
- /** npm's own dist-tag grammar, loosely: no slashes, no spaces, no `@`. */
873
- const DIST_TAG_RE = /^[a-z0-9][a-z0-9._-]{0,63}$/i;
874
- /**
875
- * THE single gate for every update-config read AND write, mirroring
876
- * `clampSkillsConfig` / `clampLogConfig` / `clampTeamConfig` / `clampTodoConfig`
877
- * / `clampRetryConfig` / `clampFastConfig` for the reason all six record:
878
- * hardening only the read path leaves a bad value on disk that reverts to the
879
- * default on every launch, which presents to the user as "my setting won't
880
- * stick".
881
- *
882
- * `registry` is CLAMPED TO `''` rather than rejected when it is not an
883
- * `http(s):` URL. `''` means "derive it" (§3.3), which is the safe reading of a
884
- * typo — the alternative is a background timer that throws on a value the user
885
- * cannot see it reading.
886
- */
887
- export function clampUpdateConfig(raw) {
888
- const src = (raw && typeof raw === 'object' ? raw : {});
889
- const registry = text(src.registry, DEFAULT_UPDATE_CONFIG.registry);
890
- const distTag = text(src.distTag, DEFAULT_UPDATE_CONFIG.distTag);
891
- return {
892
- mode: isUpdateMode(src.mode) ? src.mode : DEFAULT_UPDATE_CONFIG.mode,
893
- checkIntervalMs: clampInt(src.checkIntervalMs, DEFAULT_UPDATE_CONFIG.checkIntervalMs, UPDATE_INTERVAL_RANGE),
894
- registry: isRegistryUrl(registry) ? registry : DEFAULT_UPDATE_CONFIG.registry,
895
- distTag: DIST_TAG_RE.test(distTag) ? distTag : DEFAULT_UPDATE_CONFIG.distTag,
896
- };
897
- }
898
- function isRegistryUrl(raw) {
899
- if (raw.length === 0)
900
- return false;
901
- try {
902
- const url = new URL(raw);
903
- // `http:` is accepted for a LAN mirror; nothing else is a registry.
904
- return url.protocol === 'https:' || url.protocol === 'http:';
905
- }
906
- catch {
907
- return false;
908
- }
909
- }
910
- export const DEFAULT_COMPACTION_CONFIG = {
911
- enabled: true,
912
- threshold: 0.9,
913
- warnThreshold: 0.75,
914
- keepRecentTurns: 4,
915
- useFastTier: true,
916
- onFailure: 'stop',
917
- subagents: true,
918
- archive: true,
919
- };
920
- const THRESHOLD_RANGE = { min: 0.5, max: 0.95 };
921
- const WARN_THRESHOLD_FLOOR = 0.4;
922
- /** The gap the warn mark must stay below the trigger by. */
923
- const WARN_THRESHOLD_GAP = 0.05;
924
- const KEEP_RECENT_TURNS_RANGE = { min: 1, max: 20 };
925
- const COMPACTION_FAILURE_MODES = ['truncate', 'stop'];
926
- /**
927
- * Round a ratio to two decimals — the precision a percentage actually has.
928
- *
929
- * BINARY FLOATING POINT MAKES `0.95 - 0.05` EQUAL `0.8999999999999999`, and both
930
- * numbers here are produced by subtraction (`threshold - WARN_THRESHOLD_GAP`) and
931
- * by division (`parseThresholdInput` turning `90` into `90/100`). Without this,
932
- * `aragon config list` shows a seventeen-digit value for a setting the user typed
933
- * as `90%`, and `config.json` records one — which looks like corruption and
934
- * invites a hand-edit that the clamp then has to defend against.
935
- *
936
- * Two decimals is exact for every value the range can hold: the clamp is
937
- * `[0.5, 0.95]` and the UI reads it as a whole percentage.
938
- */
939
- function ratio(value) {
940
- return Math.round(value * 100) / 100;
941
- }
942
- function failureMode(value, fallback) {
943
- return typeof value === 'string' && COMPACTION_FAILURE_MODES.includes(value)
944
- ? value
945
- : fallback;
946
- }
947
- /**
948
- * THE single gate for every compaction-config read AND write, mirroring the six
949
- * clamps above for the reason all of them record: hardening only the read path
950
- * leaves a bad value on disk that reverts to the default on every launch, which
951
- * presents to the user as "my setting won't stick".
952
- *
953
- * THE ORDER IS FIXED AND IT MATTERS (§4.2 / P2-5). `threshold` is clamped to
954
- * `[0.5, 0.95]` FIRST, then `warnThreshold` to
955
- * `[0.4, clampedThreshold - 0.05]`. The other order lets a file holding
956
- * `{threshold: 0.6, warnThreshold: 0.9}` produce a warn mark ABOVE the trigger —
957
- * a gauge that turns amber after it has already gone red. Both bounds of the
958
- * second range stay reachable at the extremes: `threshold` floored at `0.5`
959
- * gives `warnThreshold` a range of `[0.4, 0.45]`.
960
- */
961
- export function clampCompactionConfig(raw) {
962
- const src = (raw && typeof raw === 'object' ? raw : {});
963
- const threshold = ratio(clampNumber(src.threshold, DEFAULT_COMPACTION_CONFIG.threshold, THRESHOLD_RANGE));
964
- const warnCeiling = ratio(threshold - WARN_THRESHOLD_GAP);
965
- return {
966
- enabled: bool(src.enabled, DEFAULT_COMPACTION_CONFIG.enabled),
967
- threshold,
968
- warnThreshold: ratio(clampNumber(src.warnThreshold, DEFAULT_COMPACTION_CONFIG.warnThreshold, {
969
- min: Math.min(WARN_THRESHOLD_FLOOR, warnCeiling),
970
- max: warnCeiling,
971
- })),
972
- keepRecentTurns: clampInt(src.keepRecentTurns, DEFAULT_COMPACTION_CONFIG.keepRecentTurns, KEEP_RECENT_TURNS_RANGE),
973
- useFastTier: bool(src.useFastTier, DEFAULT_COMPACTION_CONFIG.useFastTier),
974
- // CLAMPED TO THE DEFAULT, NEVER REJECTED — the discipline every other key in
975
- // this file follows. `ARAGON_COMPACTION_ON_FAILURE=garbage` resolves to
976
- // `truncate` and throws nothing.
977
- onFailure: failureMode(src.onFailure, DEFAULT_COMPACTION_CONFIG.onFailure),
978
- subagents: bool(src.subagents, DEFAULT_COMPACTION_CONFIG.subagents),
979
- archive: bool(src.archive, DEFAULT_COMPACTION_CONFIG.archive),
980
- };
981
- }
982
- export const DEFAULT_BASH_CONFIG = {
983
- background: true,
984
- autoBackground: true,
985
- startupSettleMs: 4000,
986
- readyTimeoutMs: 60_000,
987
- };
988
- const STARTUP_SETTLE_RANGE = { min: 500, max: 30_000 };
989
- const READY_TIMEOUT_RANGE = { min: 5_000, max: 600_000 };
990
- /**
991
- * THE single gate for every bash-config read AND write, mirroring
992
- * `clampSkillsConfig` / `clampLogConfig` / `clampTeamConfig` / `clampTodoConfig`
993
- * for the reason those record: hardening only the read path leaves a bad value
994
- * on disk that reverts to the default on every launch, which presents to the
995
- * user as "my setting won't stick".
996
- *
997
- * CLAMPED, NEVER REJECTED — the discipline every other key in this file follows.
998
- * A garbage `startupSettleMs` resolves to 4000 and throws nothing.
999
- */
1000
- export function clampBashConfig(raw) {
1001
- const src = (raw && typeof raw === 'object' ? raw : {});
1002
- return {
1003
- background: bool(src.background, DEFAULT_BASH_CONFIG.background),
1004
- autoBackground: bool(src.autoBackground, DEFAULT_BASH_CONFIG.autoBackground),
1005
- startupSettleMs: clampInt(src.startupSettleMs, DEFAULT_BASH_CONFIG.startupSettleMs, STARTUP_SETTLE_RANGE),
1006
- readyTimeoutMs: clampInt(src.readyTimeoutMs, DEFAULT_BASH_CONFIG.readyTimeoutMs, READY_TIMEOUT_RANGE),
1007
- };
1008
- }
1009
- export const DEFAULT_JOBS_CONFIG = {
1010
- enabled: true,
1011
- waitSeconds: 30,
1012
- stallSeconds: 300,
1013
- persistLog: true,
1014
- noticeSteer: true,
1015
- };
1016
- const WAIT_SECONDS_RANGE = { min: 5, max: 60 };
1017
- const STALL_SECONDS_RANGE = { min: 30, max: 3600 };
1018
- /**
1019
- * THE single gate for every `jobs` read AND write, mirroring `clampBashConfig`
1020
- * and the four sections before it.
1021
- *
1022
- * THE ELEVENTH SECTION, AND THE FIRST ONE THAT `config set` CAN REACH BY
1023
- * NESTED KEY (§6.5). Every key is a SCALAR and the section is ONE level deep,
1024
- * because `runConfigGet` splits on a single dot - a `jobs.mirror.enabled` would
1025
- * resolve to `undefined` and the setting would silently never apply.
1026
- */
1027
- export function clampJobsConfig(raw) {
1028
- const src = (raw && typeof raw === 'object' ? raw : {});
1029
- return {
1030
- enabled: bool(src.enabled, DEFAULT_JOBS_CONFIG.enabled),
1031
- waitSeconds: clampInt(src.waitSeconds, DEFAULT_JOBS_CONFIG.waitSeconds, WAIT_SECONDS_RANGE),
1032
- stallSeconds: clampInt(src.stallSeconds, DEFAULT_JOBS_CONFIG.stallSeconds, STALL_SECONDS_RANGE),
1033
- persistLog: bool(src.persistLog, DEFAULT_JOBS_CONFIG.persistLog),
1034
- noticeSteer: bool(src.noticeSteer, DEFAULT_JOBS_CONFIG.noticeSteer),
1035
- };
1036
- }
1037
- export const DEFAULT_PROMPTS_CONFIG = {
1038
- enabled: true,
1039
- insertMode: 'insert',
1040
- };
1041
- const PROMPT_INSERT_MODES = ['insert', 'replace'];
1042
- /**
1043
- * THE single gate for every `prompts` read AND write, like the eleven sections
1044
- * above it.
1045
- *
1046
- * An unrecognized `insertMode` falls back to `insert` rather than to `replace`,
1047
- * and that direction is deliberate: a typo must never silently start DISCARDING
1048
- * what the user has already typed into the composer.
1049
- */
1050
- export function clampPromptsConfig(raw) {
1051
- const src = (raw && typeof raw === 'object' ? raw : {});
1052
- const mode = typeof src.insertMode === 'string' ? src.insertMode.trim().toLowerCase() : '';
1053
- return {
1054
- enabled: bool(src.enabled, DEFAULT_PROMPTS_CONFIG.enabled),
1055
- insertMode: PROMPT_INSERT_MODES.includes(mode)
1056
- ? mode
1057
- : DEFAULT_PROMPTS_CONFIG.insertMode,
1058
- };
1059
- }
1060
- export const DEFAULT_TASK_SUMMARY_CONFIG = {
1061
- enabled: true,
1062
- fallback: true,
1063
- };
1064
- /**
1065
- * THE single gate for every `taskSummary` read AND write, like the twelve sections
1066
- * above it.
1067
- *
1068
- * BOTH DEFAULTS ARE `true`, AND THE DIRECTION MATTERS: a corrupt or hand-edited
1069
- * section must not silently switch off a feature the user asked for, and - more
1070
- * importantly - it must not switch off the FLOOR, which is the only thing standing
1071
- * between a failed call and an empty header cell.
1072
- */
1073
- export function clampTaskSummaryConfig(raw) {
1074
- const src = (raw && typeof raw === 'object' ? raw : {});
1075
- return {
1076
- enabled: bool(src.enabled, DEFAULT_TASK_SUMMARY_CONFIG.enabled),
1077
- fallback: bool(src.fallback, DEFAULT_TASK_SUMMARY_CONFIG.fallback),
1078
- };
1079
- }
1080
- /**
1081
- * Parse `0.9`, `90%` or `90` into a ratio, or `null` when it is neither.
1082
- *
1083
- * `null` RATHER THAN A CLAMPED DEFAULT, because this is a COMMAND argument and
1084
- * not a config value: `/compact threshold banana` must say so rather than
1085
- * silently setting 0.9 and reporting success.
1086
- */
1087
- export function parseThresholdInput(raw) {
1088
- const trimmed = raw.trim().replace(/%$/, '');
1089
- if (trimmed.length === 0)
1090
- return null;
1091
- const n = Number.parseFloat(trimmed);
1092
- if (!Number.isFinite(n))
1093
- return null;
1094
- // `90` means 90 %, `0.9` means 0.9. The ambiguity is only at `1`, which is
1095
- // above the clamp ceiling either way.
1096
- const ratio = n > 1 ? n / 100 : n;
1097
- if (ratio <= 0 || ratio > 1)
1098
- return null;
1099
- return ratio;
1100
- }
1101
- export const DEFAULT_CONFIG = {
1102
- version: CONFIG_VERSION,
1103
- provider: 'anthropic',
1104
- model: DEFAULT_MODEL,
1105
- baseUrl: null,
1106
- thinkingLevel: 'off',
1107
- // Off by default — the product default this whole round exists to establish
1108
- // (D-1). One config key restores the old behaviour permanently.
1109
- showThinking: false,
1110
- // ON by default (D-28), and the OPPOSITE of the key above it on purpose: this
1111
- // one shows work that is otherwise invisible for the whole duration of the
1112
- // most expensive thing the agent does.
1113
- liveToolOutput: true,
1114
- // The engine owns this number; spelling it here again is how the CLI and the
1115
- // provider adapters end up disagreeing about what "the default" is.
1116
- maxTokens: DEFAULT_MAX_OUTPUT_TOKENS,
1117
- // AUTO. The model table is right for every listed model, and a default number
1118
- // here would be the same fabricated denominator this key exists to correct.
1119
- contextWindow: null,
1120
- theme: 'auto',
1121
- reducedMotion: false,
1122
- exitTranscript: true,
1123
- transcriptWindow: DEFAULT_TRANSCRIPT_WINDOW,
1124
- transcriptRetain: DEFAULT_TRANSCRIPT_RETAIN,
1125
- renderGovernor: DEFAULT_RENDER_GOVERNOR,
1126
- maxRenderIntervalMs: DEFAULT_MAX_RENDER_INTERVAL_MS,
1127
- diffRender: DEFAULT_DIFF_RENDER,
1128
- scrollMode: DEFAULT_SCROLL_MODE,
1129
- syncOutput: DEFAULT_SYNC_OUTPUT,
1130
- confirmTools: false,
1131
- toolTimeoutMs: DEFAULT_TOOL_TIMEOUT_MS,
1132
- idleTimeoutMs: DEFAULT_IDLE_TIMEOUT_MS,
1133
- apiKeys: {},
1134
- historyEnabled: true,
1135
- density: 'comfortable',
1136
- hints: true,
1137
- mouse: true,
1138
- mouseSelect: DEFAULT_MOUSE_SELECT,
1139
- paste: true,
1140
- keyboardEnhancement: true,
1141
- scrollResumeMs: DEFAULT_SCROLL_RESUME_MS,
1142
- planModeDefault: false,
1143
- planModeHumanTimeoutMs: DEFAULT_PLAN_HUMAN_TIMEOUT_MS,
1144
- skills: DEFAULT_SKILLS_CONFIG,
1145
- log: DEFAULT_LOG_CONFIG,
1146
- team: DEFAULT_TEAM_CONFIG,
1147
- // The load path's first spread is what supplies the section to a user with no
1148
- // `todo` key at all, so this line is as required as the two merges in
1149
- // `store.ts` (P0-1).
1150
- todo: DEFAULT_TODO_CONFIG,
1151
- // Same requirement one section later: without this line a user with no `retry`
1152
- // key resolves `config.retry` to `undefined` and `toRetryPolicy` throws.
1153
- retry: DEFAULT_RETRY_CONFIG,
1154
- // And one section later again: the load path's first spread is what supplies
1155
- // `fast` to a user whose `config.json` predates this feature, which is every
1156
- // existing user. Without it `config.fast.enabled` reads `undefined`, which is
1157
- // falsy and so LOOKS correct — right up until `/fast on` writes a section that
1158
- // has no other keys in it (P0-1's shape, one feature later).
1159
- fast: DEFAULT_FAST_CONFIG,
1160
- // And one section later again, for the third time. Without this line a user
1161
- // whose `config.json` predates auto-update resolves `config.update.mode` to
1162
- // `undefined`, which is neither `'auto'` nor `'off'` — so the §3.8 gate
1163
- // (`cfg.update.mode !== 'off'`) would read TRUE and the feature would be on
1164
- // for a reason nobody could point at.
1165
- update: DEFAULT_UPDATE_CONFIG,
1166
- // And one section later again, for the fourth time. Without this line a user
1167
- // whose `config.json` predates compaction resolves `config.compaction.enabled`
1168
- // to `undefined`, which is FALSY — so a feature that is `true` by default would
1169
- // arrive OFF for every existing user, which is the one direction this
1170
- // particular default must never fail in.
1171
- compaction: DEFAULT_COMPACTION_CONFIG,
1172
- // And one section later again, for the fifth time. `bash.background` is `true`
1173
- // by default, so a `config.json` predating this feature resolving it to
1174
- // `undefined` would arrive with background services OFF for every existing
1175
- // user — the same direction the compaction line above must never fail in.
1176
- bash: DEFAULT_BASH_CONFIG,
1177
- // And one section later again, for the sixth time, and this one would fail
1178
- // in the WORSE direction: every key in `jobs` is `true` or positive by
1179
- // default, so a `config.json` predating this feature resolving `config.jobs`
1180
- // to `undefined` would throw on `config.jobs.waitSeconds` at construction
1181
- // rather than quietly disabling something.
1182
- jobs: DEFAULT_JOBS_CONFIG,
1183
- // And one section later again, for the seventh time, and this one has BOTH
1184
- // failure directions at once: `prompts.enabled` is `true` by default, so a
1185
- // `config.json` predating this feature would resolve it to `undefined` (falsy)
1186
- // and arrive with the key silently off - while
1187
- // `prompts.insertMode` would be `undefined`, which is neither `'insert'` nor
1188
- // `'replace'` and would make `planPromptFill` fall through to its `replace`
1189
- // branch. That branch discards the user's own words, so the miss would be a data
1190
- // loss rather than a missing hint.
1191
- prompts: DEFAULT_PROMPTS_CONFIG,
1192
- // And one section later again, for the eighth time - and this one has a silent
1193
- // DATA-LOSS-shaped miss: `taskSummary.enabled` and `.fallback` are both `true` by
1194
- // default, and `App` reads `cfg.taskSummary?.fallback !== false` at call time. A
1195
- // `config.json` predating this feature would resolve them to `undefined`, which
1196
- // happens to behave like the defaults in those two readers but NOT in
1197
- // `config list`, so the file would report a section it never wrote. One line
1198
- // here, like the seven above it.
1199
- taskSummary: DEFAULT_TASK_SUMMARY_CONFIG,
1200
- // And one section later again. Without this line a `config.json` predating governance
1201
- // resolves `governance` to `undefined`; every reader would then disagree with `config list`.
1202
- governance: DEFAULT_GOVERNANCE_CONFIG,
1203
- };
1204
- /**
1205
- * Runtime state that used to be stored in `config.json` by mistake
1206
- * (config-state-separation §4.5). Each one now lives in its own file:
1207
- * `promptHistory` → `prompt-history.jsonl`, `submitCount` / `mouseNoticeSeen`
1208
- * → `state.json`, and `recentModels` was dead — nothing ever wrote it.
1209
- */
1210
- export const LEGACY_STATE_KEYS = [
1211
- 'promptHistory',
1212
- 'submitCount',
1213
- 'mouseNoticeSeen',
1214
- 'recentModels',
1215
- ];
1216
- /**
1217
- * THE single gate that keeps those keys out of `config.json`, and the one thing
1218
- * in this change that cannot be skipped.
1219
- *
1220
- * `loadPersistedConfig()` merges `{ ...DEFAULT_CONFIG, ...partial }` where
1221
- * `partial` is the raw parse of whatever is on disk. Removing the fields from
1222
- * the interface therefore removes NOTHING from the file: the keys ride through
1223
- * the spread and `updatePersistedConfig` writes them straight back. The user
1224
- * deletes `promptHistory` by hand and watches it grow back.
1225
- *
1226
- * Applied on the READ side on purpose, which is what makes it self-healing:
1227
- * every write goes read-strip-merge-write, so a hand-edited file, a downgrade
1228
- * to 0.5.x and back, or a half-finished migration all converge on a clean file
1229
- * at the next write. Same shape as `clampSkillsConfig` / `clampLogConfig` —
1230
- * one door for both directions.
1231
- */
1232
- export function stripLegacyStateKeys(raw) {
1233
- const out = { ...raw };
1234
- for (const key of LEGACY_STATE_KEYS)
1235
- delete out[key];
1236
- return out;
1237
- }
1238
- /**
1239
- * Config keys whose MEANING was removed, mapped to the explanation a user gets if
1240
- * they still try to set one.
1241
- *
1242
- * SEPARATE FROM `LEGACY_STATE_KEYS`, because the disposition differs: those keys'
1243
- * values were MOVED somewhere else, while these have nowhere to go — the feature
1244
- * they configured no longer exists. Merging the two lists would erase that
1245
- * difference at exactly the moment someone is reading the file to find out what
1246
- * happened to their setting.
1247
- *
1248
- * Stripped on the READ side for the same reason `stripLegacyStateKeys` is:
1249
- * `loadPersistedConfig()` merges `{ ...DEFAULT_CONFIG, ...partial }`, so a key
1250
- * left on disk rides that spread into memory and `updatePersistedConfig` writes it
1251
- * straight back. The user deletes the line, launches once, and watches it return.
1252
- */
1253
- export const RETIRED_CONFIG_KEYS = {
1254
- planModeMaxAskRounds: 'ask_user has no round limit any more, so this key is gone. Nothing to set; ' +
1255
- 'the next config write removes it from config.json.',
1256
- };
1257
- /**
1258
- * THE single gate that keeps retired keys out of `config.json`. Applied on the
1259
- * read side, so it is self-healing: every write is read-strip-merge-write, and a
1260
- * hand-edited file, a downgrade to an older CLI and back, or a half-finished
1261
- * migration all converge on a clean file at the next write.
1262
- */
1263
- export function stripRetiredConfigKeys(raw) {
1264
- const out = { ...raw };
1265
- for (const key of Object.keys(RETIRED_CONFIG_KEYS))
1266
- delete out[key];
1267
- return out;
1268
- }
1269
- // ---------------------------------------------------------------------------
1270
- // Coercion / validation helpers
1271
- // ---------------------------------------------------------------------------
1272
- /** Coerce an arbitrary value into a positive integer, or `undefined`. */
1273
- function coerceTokenCount(v) {
1274
- if (v === null || v === undefined || v === '')
1275
- return undefined;
1276
- const n = typeof v === 'number' ? v : Number.parseInt(String(v), 10);
1277
- if (!Number.isFinite(n) || n <= 0)
1278
- return undefined;
1279
- return Math.floor(n);
1280
- }
1281
- /**
1282
- * Coerce an arbitrary value into a positive integer, or `undefined`.
1283
- *
1284
- * Kept because callers outside this feature still use it, and deliberately
1285
- * WITHOUT the range clamp so its behaviour for in-range values is byte-identical
1286
- * to what it always was. New code wants `clampMaxTokens`.
1287
- */
1288
- export function coerceMaxTokens(v) {
1289
- return coerceTokenCount(v);
1290
- }
1291
- /**
1292
- * The accepted range for an explicit output cap.
1293
- *
1294
- * The floor is the engine's: below it a turn cannot produce a usable tool call.
1295
- * The ceiling is a sanity bound on a hand-edited file, not a model limit — the
1296
- * real per-model ceiling is applied later, by `resolveOutputTokens`.
1297
- */
1298
- export const MAX_TOKENS_RANGE = {
1299
- min: MIN_MAX_OUTPUT_TOKENS,
1300
- max: ABSOLUTE_MAX_OUTPUT_TOKENS,
1301
- };
1302
- /** `auto`, an empty string and `0` all mean AUTO — "let the model decide". */
1303
- export function isAutoToken(v) {
1304
- if (v === 0)
1305
- return true;
1306
- if (typeof v !== 'string')
1307
- return false;
1308
- const trimmed = v.trim().toLowerCase();
1309
- return trimmed === '' || trimmed === 'auto' || trimmed === '0';
1310
- }
1311
- /**
1312
- * THE single gate for every `maxTokens` read AND write, in the shape
1313
- * `clampSkillsConfig` / `clampLogConfig` / `clampTeamConfig` already use.
1314
- *
1315
- * Both directions on purpose: hardening only the read path leaves a bad value on
1316
- * disk that reverts to a default on every launch, which presents to the user as
1317
- * "my setting won't stick".
1318
- *
1319
- * Returns `undefined` for AUTO and for anything unusable — the caller decides
1320
- * which of the two it was, because they mean different things.
1321
- */
1322
- export function clampMaxTokens(v) {
1323
- const n = coerceTokenCount(v);
1324
- if (n === undefined)
1325
- return undefined;
1326
- return Math.min(MAX_TOKENS_RANGE.max, Math.max(MAX_TOKENS_RANGE.min, n));
1327
- }
1328
- /**
1329
- * Parse text typed into the settings screen, a slash command, or `config set`.
1330
- *
1331
- * Distinguishes AUTO from "the user typed nonsense", which `clampMaxTokens`
1332
- * cannot: both come back as `undefined` there, and treating a typo as AUTO would
1333
- * silently discard the number the user meant to set.
1334
- */
1335
- export function parseMaxTokensInput(raw) {
1336
- const trimmed = String(raw ?? '').trim();
1337
- if (isAutoToken(trimmed))
1338
- return { kind: 'auto' };
1339
- if (!/^\d+$/.test(trimmed))
1340
- return { kind: 'invalid' };
1341
- const parsed = Number.parseInt(trimmed, 10);
1342
- if (!Number.isFinite(parsed) || parsed <= 0)
1343
- return { kind: 'invalid' };
1344
- const value = Math.min(MAX_TOKENS_RANGE.max, Math.max(MAX_TOKENS_RANGE.min, parsed));
1345
- return { kind: 'value', value, clamped: value !== parsed };
1346
- }
1347
- /** The product default, re-exported so the CLI never spells the number itself. */
1348
- export const DEFAULT_MAX_TOKENS = DEFAULT_MAX_OUTPUT_TOKENS;
1349
- /** Coerce a value into a positive integer with a fallback (for timeouts). */
1350
- export function coercePositiveInt(v, fallback) {
1351
- if (v === null || v === undefined || v === '')
1352
- return fallback;
1353
- const n = typeof v === 'number' ? v : Number.parseInt(String(v), 10);
1354
- if (!Number.isFinite(n) || n <= 0)
1355
- return fallback;
1356
- return Math.floor(n);
1357
- }
1358
- /**
1359
- * Mask a secret for display: keep a short prefix + suffix, redact the middle.
1360
- * A short/empty key is fully redacted so the length is not leaked.
1361
- *
1362
- * The glyphs are parameters with ASCII defaults (spec §4.1 tier B). This module
1363
- * has no terminal capabilities to consult, and the result is rendered in the
1364
- * settings screen — which on a legacy `cmd.exe` used to show two question-mark
1365
- * boxes where the redaction dots belonged. The UI passes its resolved glyphs;
1366
- * every other caller gets output that is safe anywhere.
1367
- */
1368
- export function maskSecret(key, opts = {}) {
1369
- const maskChar = opts.maskChar ?? '*';
1370
- const ellipsis = opts.ellipsis ?? '...';
1371
- if (!key)
1372
- return '(not set)';
1373
- const trimmed = key.trim();
1374
- if (trimmed.length <= 8)
1375
- return maskChar.repeat(4);
1376
- return `${trimmed.slice(0, 3)}${ellipsis}${trimmed.slice(-4)}`;
1377
- }