@orion-agents/orion-code 0.1.4 → 0.1.6

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 (540) hide show
  1. package/README.md +73 -38
  2. package/README.zh-CN.md +32 -10
  3. package/dist/agents/coder.d.ts.map +1 -1
  4. package/dist/agents/coder.js.map +1 -1
  5. package/dist/agents/fork.d.ts +12 -4
  6. package/dist/agents/fork.d.ts.map +1 -1
  7. package/dist/agents/fork.js +28 -32
  8. package/dist/agents/fork.js.map +1 -1
  9. package/dist/agents/leader.d.ts.map +1 -1
  10. package/dist/agents/leader.js.map +1 -1
  11. package/dist/agents/worker-pool.d.ts.map +1 -1
  12. package/dist/agents/worker-pool.js +38 -29
  13. package/dist/agents/worker-pool.js.map +1 -1
  14. package/dist/cli.d.ts +1 -1
  15. package/dist/cli.d.ts.map +1 -1
  16. package/dist/cli.js +4 -1
  17. package/dist/cli.js.map +1 -1
  18. package/dist/commands/context-commands.d.ts +4 -0
  19. package/dist/commands/context-commands.d.ts.map +1 -0
  20. package/dist/commands/context-commands.js +74 -0
  21. package/dist/commands/context-commands.js.map +1 -0
  22. package/dist/commands/context-tool-command-handlers.d.ts +13 -0
  23. package/dist/commands/context-tool-command-handlers.d.ts.map +1 -0
  24. package/dist/commands/context-tool-command-handlers.js +617 -0
  25. package/dist/commands/context-tool-command-handlers.js.map +1 -0
  26. package/dist/commands/core-command-handlers.d.ts +12 -0
  27. package/dist/commands/core-command-handlers.d.ts.map +1 -0
  28. package/dist/commands/core-command-handlers.js +805 -0
  29. package/dist/commands/core-command-handlers.js.map +1 -0
  30. package/dist/commands/diagnostic-command-handlers.d.ts +14 -0
  31. package/dist/commands/diagnostic-command-handlers.d.ts.map +1 -0
  32. package/dist/commands/diagnostic-command-handlers.js +1043 -0
  33. package/dist/commands/diagnostic-command-handlers.js.map +1 -0
  34. package/dist/commands/diagnostic-commands.d.ts +4 -0
  35. package/dist/commands/diagnostic-commands.d.ts.map +1 -0
  36. package/dist/commands/diagnostic-commands.js +175 -0
  37. package/dist/commands/diagnostic-commands.js.map +1 -0
  38. package/dist/commands/index.d.ts +9 -10
  39. package/dist/commands/index.d.ts.map +1 -1
  40. package/dist/commands/index.js +42 -3563
  41. package/dist/commands/index.js.map +1 -1
  42. package/dist/commands/legacy-commands.d.ts +4 -0
  43. package/dist/commands/legacy-commands.d.ts.map +1 -0
  44. package/dist/commands/legacy-commands.js +44 -0
  45. package/dist/commands/legacy-commands.js.map +1 -0
  46. package/dist/commands/model-command-handlers.d.ts +15 -0
  47. package/dist/commands/model-command-handlers.d.ts.map +1 -0
  48. package/dist/commands/model-command-handlers.js +526 -0
  49. package/dist/commands/model-command-handlers.js.map +1 -0
  50. package/dist/commands/model-commands.d.ts +4 -0
  51. package/dist/commands/model-commands.d.ts.map +1 -0
  52. package/dist/commands/model-commands.js +85 -0
  53. package/dist/commands/model-commands.js.map +1 -0
  54. package/dist/commands/parser.d.ts +12 -0
  55. package/dist/commands/parser.d.ts.map +1 -1
  56. package/dist/commands/parser.js +48 -7
  57. package/dist/commands/parser.js.map +1 -1
  58. package/dist/commands/registry.d.ts +4 -0
  59. package/dist/commands/registry.d.ts.map +1 -0
  60. package/dist/commands/registry.js +566 -0
  61. package/dist/commands/registry.js.map +1 -0
  62. package/dist/commands/session-command-handlers.d.ts +10 -0
  63. package/dist/commands/session-command-handlers.d.ts.map +1 -0
  64. package/dist/commands/session-command-handlers.js +626 -0
  65. package/dist/commands/session-command-handlers.js.map +1 -0
  66. package/dist/commands/session-commands.d.ts +4 -0
  67. package/dist/commands/session-commands.d.ts.map +1 -0
  68. package/dist/commands/session-commands.js +102 -0
  69. package/dist/commands/session-commands.js.map +1 -0
  70. package/dist/commands/system-commands.d.ts +4 -0
  71. package/dist/commands/system-commands.d.ts.map +1 -0
  72. package/dist/commands/system-commands.js +80 -0
  73. package/dist/commands/system-commands.js.map +1 -0
  74. package/dist/commands/target-command.d.ts +1 -1
  75. package/dist/commands/target-command.d.ts.map +1 -1
  76. package/dist/commands/target-command.js +42 -6
  77. package/dist/commands/target-command.js.map +1 -1
  78. package/dist/commands/tool-commands.d.ts +4 -0
  79. package/dist/commands/tool-commands.d.ts.map +1 -0
  80. package/dist/commands/tool-commands.js +49 -0
  81. package/dist/commands/tool-commands.js.map +1 -0
  82. package/dist/commands/types.d.ts +69 -5
  83. package/dist/commands/types.d.ts.map +1 -1
  84. package/dist/commands/types.js +3 -4
  85. package/dist/commands/types.js.map +1 -1
  86. package/dist/commands/workflow-command-handlers.d.ts +7 -0
  87. package/dist/commands/workflow-command-handlers.d.ts.map +1 -0
  88. package/dist/commands/workflow-command-handlers.js +32 -0
  89. package/dist/commands/workflow-command-handlers.js.map +1 -0
  90. package/dist/commands/workflow-commands.d.ts +4 -0
  91. package/dist/commands/workflow-commands.d.ts.map +1 -0
  92. package/dist/commands/workflow-commands.js +124 -0
  93. package/dist/commands/workflow-commands.js.map +1 -0
  94. package/dist/core/checkpoint.d.ts +12 -4
  95. package/dist/core/checkpoint.d.ts.map +1 -1
  96. package/dist/core/checkpoint.js +114 -28
  97. package/dist/core/checkpoint.js.map +1 -1
  98. package/dist/core/cost-tracker.d.ts +17 -1
  99. package/dist/core/cost-tracker.d.ts.map +1 -1
  100. package/dist/core/cost-tracker.js +24 -8
  101. package/dist/core/cost-tracker.js.map +1 -1
  102. package/dist/core/warn-dedup.d.ts +3 -0
  103. package/dist/core/warn-dedup.d.ts.map +1 -1
  104. package/dist/core/warn-dedup.js +6 -6
  105. package/dist/core/warn-dedup.js.map +1 -1
  106. package/dist/framework/index.d.ts +1 -1
  107. package/dist/framework/index.d.ts.map +1 -1
  108. package/dist/framework/index.js.map +1 -1
  109. package/dist/framework/prompt.d.ts +2 -2
  110. package/dist/framework/query.d.ts +2 -2
  111. package/dist/framework/query.d.ts.map +1 -1
  112. package/dist/framework/query.js +57 -10
  113. package/dist/framework/query.js.map +1 -1
  114. package/dist/framework/store.d.ts +15 -6
  115. package/dist/framework/store.d.ts.map +1 -1
  116. package/dist/framework/store.js +18 -0
  117. package/dist/framework/store.js.map +1 -1
  118. package/dist/framework/tool-scheduler.d.ts +16 -13
  119. package/dist/framework/tool-scheduler.d.ts.map +1 -1
  120. package/dist/framework/tool-scheduler.js +155 -38
  121. package/dist/framework/tool-scheduler.js.map +1 -1
  122. package/dist/framework/tool.d.ts +39 -2
  123. package/dist/framework/tool.d.ts.map +1 -1
  124. package/dist/framework/tool.js +27 -1
  125. package/dist/framework/tool.js.map +1 -1
  126. package/dist/harness/assembler.d.ts.map +1 -1
  127. package/dist/harness/assembler.js +4 -2
  128. package/dist/harness/assembler.js.map +1 -1
  129. package/dist/harness/drift-guard.d.ts.map +1 -1
  130. package/dist/harness/drift-guard.js +9 -1
  131. package/dist/harness/drift-guard.js.map +1 -1
  132. package/dist/harness/evidence.d.ts.map +1 -1
  133. package/dist/harness/evidence.js +3 -2
  134. package/dist/harness/evidence.js.map +1 -1
  135. package/dist/harness/safety.d.ts +11 -1
  136. package/dist/harness/safety.d.ts.map +1 -1
  137. package/dist/harness/safety.js +112 -16
  138. package/dist/harness/safety.js.map +1 -1
  139. package/dist/index.d.ts +1 -4
  140. package/dist/index.d.ts.map +1 -1
  141. package/dist/index.js.map +1 -1
  142. package/dist/init.d.ts +4 -8
  143. package/dist/init.d.ts.map +1 -1
  144. package/dist/init.js +4 -4
  145. package/dist/init.js.map +1 -1
  146. package/dist/ink-ui/App.d.ts +2 -2
  147. package/dist/ink-ui/components/Markdown.d.ts.map +1 -1
  148. package/dist/ink-ui/components/Markdown.js.map +1 -1
  149. package/dist/ink-ui/components/PixelHorseBanner.d.ts +2 -2
  150. package/dist/ink-ui/components/StatusLine.d.ts +2 -2
  151. package/dist/ink-ui/launch.d.ts +2 -2
  152. package/dist/ink-ui/screens/ReplScreen.d.ts +4 -3
  153. package/dist/ink-ui/screens/ReplScreen.d.ts.map +1 -1
  154. package/dist/ink-ui/screens/ReplScreen.js +103 -31
  155. package/dist/ink-ui/screens/ReplScreen.js.map +1 -1
  156. package/dist/memory/relevant-finder.d.ts +2 -1
  157. package/dist/memory/relevant-finder.d.ts.map +1 -1
  158. package/dist/memory/relevant-finder.js +17 -8
  159. package/dist/memory/relevant-finder.js.map +1 -1
  160. package/dist/memory/semantic-config.d.ts +9 -0
  161. package/dist/memory/semantic-config.d.ts.map +1 -0
  162. package/dist/memory/semantic-config.js +16 -0
  163. package/dist/memory/semantic-config.js.map +1 -0
  164. package/dist/memory/semantic-search.d.ts +1 -6
  165. package/dist/memory/semantic-search.d.ts.map +1 -1
  166. package/dist/memory/semantic-search.js +3 -15
  167. package/dist/memory/semantic-search.js.map +1 -1
  168. package/dist/memory/storage.d.ts +23 -0
  169. package/dist/memory/storage.d.ts.map +1 -1
  170. package/dist/memory/storage.js +116 -9
  171. package/dist/memory/storage.js.map +1 -1
  172. package/dist/memory/validation.d.ts +3 -0
  173. package/dist/memory/validation.d.ts.map +1 -1
  174. package/dist/memory/validation.js +123 -10
  175. package/dist/memory/validation.js.map +1 -1
  176. package/dist/memory/vector-store.d.ts +30 -0
  177. package/dist/memory/vector-store.d.ts.map +1 -1
  178. package/dist/memory/vector-store.js +160 -21
  179. package/dist/memory/vector-store.js.map +1 -1
  180. package/dist/migration/command.d.ts.map +1 -1
  181. package/dist/migration/command.js +0 -1
  182. package/dist/migration/command.js.map +1 -1
  183. package/dist/migration/migrate.d.ts.map +1 -1
  184. package/dist/migration/migrate.js +59 -107
  185. package/dist/migration/migrate.js.map +1 -1
  186. package/dist/migration/types.d.ts +0 -1
  187. package/dist/migration/types.d.ts.map +1 -1
  188. package/dist/print-ui/launch.d.ts +13 -3
  189. package/dist/print-ui/launch.d.ts.map +1 -1
  190. package/dist/print-ui/launch.js +28 -3
  191. package/dist/print-ui/launch.js.map +1 -1
  192. package/dist/product/environment.d.ts +3 -5
  193. package/dist/product/environment.d.ts.map +1 -1
  194. package/dist/product/environment.js +4 -32
  195. package/dist/product/environment.js.map +1 -1
  196. package/dist/product/index.d.ts +1 -1
  197. package/dist/product/index.d.ts.map +1 -1
  198. package/dist/product/index.js +1 -3
  199. package/dist/product/index.js.map +1 -1
  200. package/dist/product/paths.d.ts.map +1 -1
  201. package/dist/product/paths.js +16 -11
  202. package/dist/product/paths.js.map +1 -1
  203. package/dist/runtime/agent-runtime-controller.d.ts +4 -2
  204. package/dist/runtime/agent-runtime-controller.d.ts.map +1 -1
  205. package/dist/runtime/agent-runtime-controller.js +129 -15
  206. package/dist/runtime/agent-runtime-controller.js.map +1 -1
  207. package/dist/runtime/agent-runtime-protocol.d.ts +15 -0
  208. package/dist/runtime/agent-runtime-protocol.d.ts.map +1 -1
  209. package/dist/runtime/agent-runtime-protocol.js +6 -0
  210. package/dist/runtime/agent-runtime-protocol.js.map +1 -1
  211. package/dist/runtime/chat-checkpoint.d.ts +17 -0
  212. package/dist/runtime/chat-checkpoint.d.ts.map +1 -0
  213. package/dist/runtime/chat-checkpoint.js +108 -0
  214. package/dist/runtime/chat-checkpoint.js.map +1 -0
  215. package/dist/runtime/chat-controller.d.ts +10 -51
  216. package/dist/runtime/chat-controller.d.ts.map +1 -1
  217. package/dist/runtime/chat-controller.js +256 -1070
  218. package/dist/runtime/chat-controller.js.map +1 -1
  219. package/dist/runtime/chat-effort.d.ts +5 -0
  220. package/dist/runtime/chat-effort.d.ts.map +1 -0
  221. package/dist/runtime/chat-effort.js +47 -0
  222. package/dist/runtime/chat-effort.js.map +1 -0
  223. package/dist/runtime/chat-presentation.d.ts +60 -0
  224. package/dist/runtime/chat-presentation.d.ts.map +1 -0
  225. package/dist/runtime/chat-presentation.js +537 -0
  226. package/dist/runtime/chat-presentation.js.map +1 -0
  227. package/dist/runtime/chat-trace.d.ts +52 -0
  228. package/dist/runtime/chat-trace.d.ts.map +1 -0
  229. package/dist/runtime/chat-trace.js +234 -0
  230. package/dist/runtime/chat-trace.js.map +1 -0
  231. package/dist/runtime/chat-workspace.d.ts +22 -0
  232. package/dist/runtime/chat-workspace.d.ts.map +1 -0
  233. package/dist/runtime/chat-workspace.js +154 -0
  234. package/dist/runtime/chat-workspace.js.map +1 -0
  235. package/dist/runtime/goals/accounting.js +1 -1
  236. package/dist/runtime/goals/accounting.js.map +1 -1
  237. package/dist/runtime/goals/completion-audit.d.ts.map +1 -1
  238. package/dist/runtime/goals/completion-audit.js +5 -4
  239. package/dist/runtime/goals/completion-audit.js.map +1 -1
  240. package/dist/runtime/goals/coordinator.d.ts +3 -0
  241. package/dist/runtime/goals/coordinator.d.ts.map +1 -1
  242. package/dist/runtime/goals/coordinator.js +56 -2
  243. package/dist/runtime/goals/coordinator.js.map +1 -1
  244. package/dist/runtime/goals/prompt.d.ts +1 -1
  245. package/dist/runtime/goals/prompt.d.ts.map +1 -1
  246. package/dist/runtime/goals/prompt.js +4 -3
  247. package/dist/runtime/goals/prompt.js.map +1 -1
  248. package/dist/runtime/goals/tools.d.ts +32 -8
  249. package/dist/runtime/goals/tools.d.ts.map +1 -1
  250. package/dist/runtime/goals/tools.js +187 -11
  251. package/dist/runtime/goals/tools.js.map +1 -1
  252. package/dist/runtime/goals/types.d.ts +9 -0
  253. package/dist/runtime/goals/types.d.ts.map +1 -1
  254. package/dist/runtime/goals/types.js +1 -0
  255. package/dist/runtime/goals/types.js.map +1 -1
  256. package/dist/runtime/loop-budget.d.ts +2 -2
  257. package/dist/runtime/rich-text/markdown-parser.d.ts +2 -0
  258. package/dist/runtime/rich-text/markdown-parser.d.ts.map +1 -1
  259. package/dist/runtime/rich-text/markdown-parser.js +50 -10
  260. package/dist/runtime/rich-text/markdown-parser.js.map +1 -1
  261. package/dist/runtime/subagents/index.d.ts +2 -2
  262. package/dist/runtime/subagents/index.d.ts.map +1 -1
  263. package/dist/runtime/subagents/index.js +2 -1
  264. package/dist/runtime/subagents/index.js.map +1 -1
  265. package/dist/runtime/subagents/policy.d.ts +1 -1
  266. package/dist/runtime/subagents/policy.d.ts.map +1 -1
  267. package/dist/runtime/subagents/policy.js.map +1 -1
  268. package/dist/runtime/subagents/presets.d.ts +2 -2
  269. package/dist/runtime/subagents/research-artifact.d.ts +7 -0
  270. package/dist/runtime/subagents/research-artifact.d.ts.map +1 -1
  271. package/dist/runtime/subagents/research-artifact.js +73 -27
  272. package/dist/runtime/subagents/research-artifact.js.map +1 -1
  273. package/dist/runtime/subagents/research-contract.d.ts +18 -4
  274. package/dist/runtime/subagents/research-contract.d.ts.map +1 -1
  275. package/dist/runtime/subagents/research-contract.js +122 -17
  276. package/dist/runtime/subagents/research-contract.js.map +1 -1
  277. package/dist/runtime/subagents/research-renderer.d.ts +27 -11
  278. package/dist/runtime/subagents/research-renderer.d.ts.map +1 -1
  279. package/dist/runtime/subagents/research-renderer.js +34 -2
  280. package/dist/runtime/subagents/research-renderer.js.map +1 -1
  281. package/dist/runtime/subagents/result-parser.d.ts +1 -5
  282. package/dist/runtime/subagents/result-parser.d.ts.map +1 -1
  283. package/dist/runtime/subagents/result-parser.js +5 -72
  284. package/dist/runtime/subagents/result-parser.js.map +1 -1
  285. package/dist/runtime/subagents/runtime-integration.d.ts +13 -7
  286. package/dist/runtime/subagents/runtime-integration.d.ts.map +1 -1
  287. package/dist/runtime/subagents/runtime-integration.js +112 -2
  288. package/dist/runtime/subagents/runtime-integration.js.map +1 -1
  289. package/dist/runtime/subagents/supervisor.d.ts +15 -1
  290. package/dist/runtime/subagents/supervisor.d.ts.map +1 -1
  291. package/dist/runtime/subagents/supervisor.js +58 -3
  292. package/dist/runtime/subagents/supervisor.js.map +1 -1
  293. package/dist/runtime/subagents/tool.d.ts +2 -2
  294. package/dist/runtime/subagents/tool.d.ts.map +1 -1
  295. package/dist/runtime/subagents/tool.js +129 -9
  296. package/dist/runtime/subagents/tool.js.map +1 -1
  297. package/dist/runtime/subagents/types.d.ts +20 -0
  298. package/dist/runtime/subagents/types.d.ts.map +1 -1
  299. package/dist/runtime/subagents/types.js.map +1 -1
  300. package/dist/runtime/subagents/web-research-adapter.d.ts +4 -2
  301. package/dist/runtime/subagents/web-research-adapter.d.ts.map +1 -1
  302. package/dist/runtime/subagents/web-research-adapter.js +81 -15
  303. package/dist/runtime/subagents/web-research-adapter.js.map +1 -1
  304. package/dist/runtime/ui-events.d.ts +36 -8
  305. package/dist/runtime/ui-events.d.ts.map +1 -1
  306. package/dist/runtime/ui-events.js.map +1 -1
  307. package/dist/runtime/ui-view-model.d.ts +53 -4
  308. package/dist/runtime/ui-view-model.d.ts.map +1 -1
  309. package/dist/runtime/ui-view-model.js +190 -10
  310. package/dist/runtime/ui-view-model.js.map +1 -1
  311. package/dist/services/agent-runner.d.ts +5 -2
  312. package/dist/services/agent-runner.d.ts.map +1 -1
  313. package/dist/services/agent-runner.js +18 -18
  314. package/dist/services/agent-runner.js.map +1 -1
  315. package/dist/services/atomic-write.d.ts +9 -1
  316. package/dist/services/atomic-write.d.ts.map +1 -1
  317. package/dist/services/atomic-write.js +55 -2
  318. package/dist/services/atomic-write.js.map +1 -1
  319. package/dist/services/auth/auth.d.ts +11 -7
  320. package/dist/services/auth/auth.d.ts.map +1 -1
  321. package/dist/services/auth/auth.js +117 -31
  322. package/dist/services/auth/auth.js.map +1 -1
  323. package/dist/services/auth/aws.d.ts +2 -0
  324. package/dist/services/auth/aws.d.ts.map +1 -1
  325. package/dist/services/auth/aws.js +126 -12
  326. package/dist/services/auth/aws.js.map +1 -1
  327. package/dist/services/auth/index.d.ts +1 -1
  328. package/dist/services/auth/index.d.ts.map +1 -1
  329. package/dist/services/auth/index.js +2 -1
  330. package/dist/services/auth/index.js.map +1 -1
  331. package/dist/services/auto-fix/autoFixConfig.d.ts +0 -3
  332. package/dist/services/auto-fix/autoFixConfig.d.ts.map +1 -1
  333. package/dist/services/auto-fix/autoFixConfig.js +25 -8
  334. package/dist/services/auto-fix/autoFixConfig.js.map +1 -1
  335. package/dist/services/auto-fix/autoFixHook.d.ts +7 -0
  336. package/dist/services/auto-fix/autoFixHook.d.ts.map +1 -1
  337. package/dist/services/auto-fix/autoFixHook.js +10 -1
  338. package/dist/services/auto-fix/autoFixHook.js.map +1 -1
  339. package/dist/services/compact/auto-compact.d.ts +2 -0
  340. package/dist/services/compact/auto-compact.d.ts.map +1 -1
  341. package/dist/services/compact/auto-compact.js +15 -1
  342. package/dist/services/compact/auto-compact.js.map +1 -1
  343. package/dist/services/compact/compact.d.ts.map +1 -1
  344. package/dist/services/compact/compact.js +9 -11
  345. package/dist/services/compact/compact.js.map +1 -1
  346. package/dist/services/compact/summary-generator.d.ts.map +1 -1
  347. package/dist/services/compact/summary-generator.js +28 -4
  348. package/dist/services/compact/summary-generator.js.map +1 -1
  349. package/dist/services/compact/tool-call-groups.d.ts +19 -0
  350. package/dist/services/compact/tool-call-groups.d.ts.map +1 -0
  351. package/dist/services/compact/tool-call-groups.js +105 -0
  352. package/dist/services/compact/tool-call-groups.js.map +1 -0
  353. package/dist/services/concurrent-sessions.d.ts +4 -0
  354. package/dist/services/concurrent-sessions.d.ts.map +1 -1
  355. package/dist/services/concurrent-sessions.js +59 -12
  356. package/dist/services/concurrent-sessions.js.map +1 -1
  357. package/dist/services/config.d.ts +8 -4
  358. package/dist/services/config.d.ts.map +1 -1
  359. package/dist/services/config.js +15 -71
  360. package/dist/services/config.js.map +1 -1
  361. package/dist/services/doctor.d.ts +2 -2
  362. package/dist/services/doctor.js.map +1 -1
  363. package/dist/services/effort.d.ts +40 -0
  364. package/dist/services/effort.d.ts.map +1 -0
  365. package/dist/services/effort.js +88 -0
  366. package/dist/services/effort.js.map +1 -0
  367. package/dist/services/file-glob.d.ts.map +1 -1
  368. package/dist/services/file-glob.js +22 -2
  369. package/dist/services/file-glob.js.map +1 -1
  370. package/dist/services/file-lock.d.ts +7 -0
  371. package/dist/services/file-lock.d.ts.map +1 -0
  372. package/dist/services/file-lock.js +193 -0
  373. package/dist/services/file-lock.js.map +1 -0
  374. package/dist/services/global-config.d.ts +9 -0
  375. package/dist/services/global-config.d.ts.map +1 -1
  376. package/dist/services/global-config.js +79 -4
  377. package/dist/services/global-config.js.map +1 -1
  378. package/dist/services/goal-storage.d.ts.map +1 -1
  379. package/dist/services/goal-storage.js +35 -11
  380. package/dist/services/goal-storage.js.map +1 -1
  381. package/dist/services/llm.d.ts +35 -17
  382. package/dist/services/llm.d.ts.map +1 -1
  383. package/dist/services/llm.js +249 -113
  384. package/dist/services/llm.js.map +1 -1
  385. package/dist/services/mcp/transports.d.ts +0 -1
  386. package/dist/services/mcp/transports.d.ts.map +1 -1
  387. package/dist/services/mcp/transports.js +12 -13
  388. package/dist/services/mcp/transports.js.map +1 -1
  389. package/dist/services/model-context.d.ts +8 -0
  390. package/dist/services/model-context.d.ts.map +1 -1
  391. package/dist/services/model-context.js +111 -7
  392. package/dist/services/model-context.js.map +1 -1
  393. package/dist/services/model-registry.d.ts +3 -0
  394. package/dist/services/model-registry.d.ts.map +1 -1
  395. package/dist/services/model-registry.js +59 -2
  396. package/dist/services/model-registry.js.map +1 -1
  397. package/dist/services/provider-diagnostics.d.ts +1 -1
  398. package/dist/services/provider-diagnostics.d.ts.map +1 -1
  399. package/dist/services/provider-diagnostics.js +30 -16
  400. package/dist/services/provider-diagnostics.js.map +1 -1
  401. package/dist/services/provider-resilience/coordinator.d.ts +8 -3
  402. package/dist/services/provider-resilience/coordinator.d.ts.map +1 -1
  403. package/dist/services/provider-resilience/coordinator.js +86 -19
  404. package/dist/services/provider-resilience/coordinator.js.map +1 -1
  405. package/dist/services/provider-resilience/error-classifier.d.ts +1 -0
  406. package/dist/services/provider-resilience/error-classifier.d.ts.map +1 -1
  407. package/dist/services/provider-resilience/error-classifier.js +50 -26
  408. package/dist/services/provider-resilience/error-classifier.js.map +1 -1
  409. package/dist/services/provider-resilience/index.d.ts +3 -3
  410. package/dist/services/provider-resilience/index.d.ts.map +1 -1
  411. package/dist/services/provider-resilience/index.js +3 -1
  412. package/dist/services/provider-resilience/index.js.map +1 -1
  413. package/dist/services/provider-resilience/request-gate.d.ts +6 -0
  414. package/dist/services/provider-resilience/request-gate.d.ts.map +1 -1
  415. package/dist/services/provider-resilience/request-gate.js +24 -9
  416. package/dist/services/provider-resilience/request-gate.js.map +1 -1
  417. package/dist/services/provider-resilience/types.d.ts +10 -1
  418. package/dist/services/provider-resilience/types.d.ts.map +1 -1
  419. package/dist/services/provider-resilience/types.js.map +1 -1
  420. package/dist/services/redaction.d.ts.map +1 -1
  421. package/dist/services/redaction.js +29 -1
  422. package/dist/services/redaction.js.map +1 -1
  423. package/dist/services/session-index.d.ts.map +1 -1
  424. package/dist/services/session-index.js +75 -44
  425. package/dist/services/session-index.js.map +1 -1
  426. package/dist/services/session-memory/sessionMemory.d.ts.map +1 -1
  427. package/dist/services/session-memory/sessionMemory.js +6 -3
  428. package/dist/services/session-memory/sessionMemory.js.map +1 -1
  429. package/dist/services/session-storage.d.ts +12 -0
  430. package/dist/services/session-storage.d.ts.map +1 -1
  431. package/dist/services/session-storage.js +301 -230
  432. package/dist/services/session-storage.js.map +1 -1
  433. package/dist/services/storage-maintenance.d.ts.map +1 -1
  434. package/dist/services/storage-maintenance.js +25 -7
  435. package/dist/services/storage-maintenance.js.map +1 -1
  436. package/dist/services/task-manager.d.ts +6 -1
  437. package/dist/services/task-manager.d.ts.map +1 -1
  438. package/dist/services/task-manager.js +18 -4
  439. package/dist/services/task-manager.js.map +1 -1
  440. package/dist/services/tool-allowlist.d.ts +20 -10
  441. package/dist/services/tool-allowlist.d.ts.map +1 -1
  442. package/dist/services/tool-allowlist.js +64 -15
  443. package/dist/services/tool-allowlist.js.map +1 -1
  444. package/dist/services/usage-state.d.ts +10 -0
  445. package/dist/services/usage-state.d.ts.map +1 -1
  446. package/dist/services/usage-state.js +116 -45
  447. package/dist/services/usage-state.js.map +1 -1
  448. package/dist/services/verification-profile.d.ts.map +1 -1
  449. package/dist/services/verification-profile.js +23 -3
  450. package/dist/services/verification-profile.js.map +1 -1
  451. package/dist/services/workspace-diff.d.ts +14 -0
  452. package/dist/services/workspace-diff.d.ts.map +1 -1
  453. package/dist/services/workspace-diff.js +60 -11
  454. package/dist/services/workspace-diff.js.map +1 -1
  455. package/dist/services/yaml-config.d.ts.map +1 -1
  456. package/dist/services/yaml-config.js +2 -1
  457. package/dist/services/yaml-config.js.map +1 -1
  458. package/dist/skills/loader.d.ts.map +1 -1
  459. package/dist/skills/loader.js +23 -9
  460. package/dist/skills/loader.js.map +1 -1
  461. package/dist/skills/runtime.d.ts +3 -3
  462. package/dist/skills/runtime.d.ts.map +1 -1
  463. package/dist/skills/runtime.js +37 -4
  464. package/dist/skills/runtime.js.map +1 -1
  465. package/dist/skills/types.d.ts +1 -1
  466. package/dist/skills/types.d.ts.map +1 -1
  467. package/dist/terminal-ui/launch.d.ts +26 -8
  468. package/dist/terminal-ui/launch.d.ts.map +1 -1
  469. package/dist/terminal-ui/launch.js +82 -39
  470. package/dist/terminal-ui/launch.js.map +1 -1
  471. package/dist/tools/bash_security.d.ts +17 -0
  472. package/dist/tools/bash_security.d.ts.map +1 -1
  473. package/dist/tools/bash_security.js +233 -27
  474. package/dist/tools/bash_security.js.map +1 -1
  475. package/dist/tools/git.d.ts +8 -8
  476. package/dist/tools/git.d.ts.map +1 -1
  477. package/dist/tools/git.js +248 -55
  478. package/dist/tools/git.js.map +1 -1
  479. package/dist/tools/index.d.ts +13 -3
  480. package/dist/tools/index.d.ts.map +1 -1
  481. package/dist/tools/index.js +262 -30
  482. package/dist/tools/index.js.map +1 -1
  483. package/dist/tools/lsp.d.ts +74 -6
  484. package/dist/tools/lsp.d.ts.map +1 -1
  485. package/dist/tools/lsp.js +24 -5
  486. package/dist/tools/lsp.js.map +1 -1
  487. package/dist/tools/mcp.d.ts +11 -4
  488. package/dist/tools/mcp.d.ts.map +1 -1
  489. package/dist/tools/mcp.js +99 -3
  490. package/dist/tools/mcp.js.map +1 -1
  491. package/dist/tools/plan.d.ts +4 -4
  492. package/dist/tools/sandbox.d.ts +5 -1
  493. package/dist/tools/sandbox.d.ts.map +1 -1
  494. package/dist/tools/sandbox.js +29 -13
  495. package/dist/tools/sandbox.js.map +1 -1
  496. package/dist/tools/todo.d.ts +3 -3
  497. package/dist/tools/web.d.ts +15 -4
  498. package/dist/tools/web.d.ts.map +1 -1
  499. package/dist/tools/web.js +240 -26
  500. package/dist/tools/web.js.map +1 -1
  501. package/dist/tui-ui/launch.d.ts +3 -3
  502. package/dist/tui-ui/launch.d.ts.map +1 -1
  503. package/dist/tui-ui/launch.js +3 -3
  504. package/dist/tui-ui/launch.js.map +1 -1
  505. package/dist/tui-ui/layout.d.ts.map +1 -1
  506. package/dist/tui-ui/layout.js +19 -5
  507. package/dist/tui-ui/layout.js.map +1 -1
  508. package/dist/tui-ui/pickers.d.ts.map +1 -1
  509. package/dist/tui-ui/pickers.js +1 -0
  510. package/dist/tui-ui/pickers.js.map +1 -1
  511. package/dist/tui-ui/runner.d.ts +2 -1
  512. package/dist/tui-ui/runner.d.ts.map +1 -1
  513. package/dist/tui-ui/runner.js +18 -29
  514. package/dist/tui-ui/runner.js.map +1 -1
  515. package/dist/tui-ui/state.d.ts +13 -1
  516. package/dist/tui-ui/state.d.ts.map +1 -1
  517. package/dist/tui-ui/state.js +28 -1
  518. package/dist/tui-ui/state.js.map +1 -1
  519. package/dist/ui/markdown.js.map +1 -1
  520. package/dist/utils/debug-log.d.ts +3 -3
  521. package/dist/utils/debug-log.d.ts.map +1 -1
  522. package/dist/utils/debug-log.js +7 -4
  523. package/dist/utils/debug-log.js.map +1 -1
  524. package/dist/utils/json.d.ts +6 -0
  525. package/dist/utils/json.d.ts.map +1 -0
  526. package/dist/utils/json.js +66 -0
  527. package/dist/utils/json.js.map +1 -0
  528. package/dist/utils/mask.d.ts +8 -1
  529. package/dist/utils/mask.d.ts.map +1 -1
  530. package/dist/utils/mask.js +10 -12
  531. package/dist/utils/mask.js.map +1 -1
  532. package/dist/utils/observability.d.ts +22 -0
  533. package/dist/utils/observability.d.ts.map +1 -0
  534. package/dist/utils/observability.js +80 -0
  535. package/dist/utils/observability.js.map +1 -0
  536. package/dist/utils/token-estimate.d.ts +8 -0
  537. package/dist/utils/token-estimate.d.ts.map +1 -1
  538. package/dist/utils/token-estimate.js +30 -17
  539. package/dist/utils/token-estimate.js.map +1 -1
  540. package/package.json +9 -8
@@ -1,3580 +1,59 @@
1
1
  "use strict";
2
2
  /**
3
- * orion code - Command Registry
3
+ * Orion Code slash-command registry.
4
4
  *
5
- * 注册所有 slash 命令,提供查找和列表功能。
5
+ * Command definitions are grouped by product domain while handler implementations
6
+ * remain isolated from registry lookup. Keep the concatenation order stable: aliases
7
+ * and duplicate detection use first-registration semantics.
6
8
  */
7
- var __importDefault = (this && this.__importDefault) || function (mod) {
8
- return (mod && mod.__esModule) ? mod : { "default": mod };
9
- };
10
9
  Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.getCommandCategoryLabel = getCommandCategoryLabel;
12
- exports.sortCommands = sortCommands;
13
- exports.getCommands = getCommands;
10
+ exports.sortCommands = exports.getCommandCategoryLabel = exports.executeChat = void 0;
14
11
  exports.getVisibleCommands = getVisibleCommands;
12
+ exports.getCommands = getCommands;
15
13
  exports.findCommand = findCommand;
16
14
  exports.getCommandNames = getCommandNames;
17
- exports.executeChat = handleChat;
18
- const chalk_1 = __importDefault(require("chalk"));
19
- const types_1 = require("./types");
20
- const ui_view_model_1 = require("../runtime/ui-view-model");
21
- const task_manager_1 = require("../services/task-manager");
22
- const agent_runner_1 = require("../services/agent-runner");
23
- const config_1 = require("../services/config");
24
- const tool_allowlist_1 = require("../services/tool-allowlist");
25
- const box_1 = require("../ui/box");
26
- const stream_markdown_1 = require("../ui/stream-markdown");
27
- const progress_1 = require("../ui/progress");
28
- const format_1 = require("../services/format");
29
- const framework_1 = require("../framework");
30
- const tools_1 = require("../tools");
31
- const mcp_1 = require("../tools/mcp");
32
- const session_storage_1 = require("../services/session-storage");
33
- const session_index_1 = require("../services/session-index");
34
- const auto_compact_1 = require("../services/compact/auto-compact");
35
- const coordinator_1 = require("../services/compact/coordinator");
36
- const harness_1 = require("../harness");
37
- const skills_1 = require("../skills");
38
- const file_context_1 = require("../services/file-context");
39
- const project_instructions_1 = require("../services/project-instructions");
40
- const prompt_context_1 = require("../services/prompt-context");
41
- const doctor_1 = require("../services/doctor");
42
- const model_context_1 = require("../services/model-context");
43
- const token_estimate_1 = require("../utils/token-estimate");
44
- const mask_1 = require("../utils/mask");
45
- const model_catalog_1 = require("../services/model-catalog");
46
- const model_registry_1 = require("../services/model-registry");
47
- const workspace_diff_1 = require("../services/workspace-diff");
48
- const commit_plan_1 = require("../services/commit-plan");
49
- const tool_artifacts_1 = require("../core/tool-artifacts");
50
- const checkpoint_1 = require("../core/checkpoint");
51
- const storage_maintenance_1 = require("../services/storage-maintenance");
52
- const agent_status_1 = require("../runtime/agent-status");
53
- const loop_budget_1 = require("../runtime/loop-budget");
54
- const usage_state_1 = require("../services/usage-state");
55
- const command_1 = require("../migration/command");
56
- // ============================================================================
57
- // 颜色常量
58
- // ============================================================================
59
- const BRAND = chalk_1.default.hex('#FF6B35');
60
- const ACCENT = chalk_1.default.hex('#00D4AA');
61
- const DIM = chalk_1.default.dim;
62
- const ERROR = chalk_1.default.red;
63
- const WARN = chalk_1.default.yellow;
64
- const SUCCESS = chalk_1.default.green;
65
- const HEADER = chalk_1.default.cyan.bold;
66
- const CATEGORY_ORDER = [
67
- 'workflow',
68
- 'session',
69
- 'context',
70
- 'tools',
71
- 'model',
72
- 'system',
73
- 'diagnostics',
74
- 'legacy',
75
- ];
76
- function commandUICapabilities(ctx) {
77
- return (0, ui_view_model_1.createStatusSnapshot)({
78
- renderer: ctx.uiRenderer ?? ctx.config.ui?.renderer ?? 'terminal',
79
- capabilities: ctx.uiCapabilities,
80
- }).renderer.capabilities;
81
- }
82
- function formatTokenCount(tokens) {
83
- if (tokens >= 1000000)
84
- return `${(tokens / 1000000).toFixed(1)}M`;
85
- if (tokens >= 1000)
86
- return `${Math.round(tokens / 1000)}K`;
87
- return String(tokens);
88
- }
89
- function formatThreshold(value) {
90
- return `${Math.round(value * 100)}%`;
91
- }
92
- function formatDurationMs(ms) {
93
- if (ms >= 1000)
94
- return `${(ms / 1000).toFixed(1)}s`;
95
- return `${Math.round(ms)}ms`;
96
- }
97
- function formatRendererStatus(ctx) {
98
- const snapshot = (0, ui_view_model_1.createStatusSnapshot)({
99
- renderer: ctx.uiRenderer ?? ctx.config.ui?.renderer ?? 'terminal',
100
- capabilities: ctx.uiCapabilities,
101
- });
102
- const status = snapshot.renderer.status === 'deprecated'
103
- ? WARN('deprecated')
104
- : snapshot.renderer.status === 'product'
105
- ? SUCCESS('product')
106
- : snapshot.renderer.status === 'technical'
107
- ? DIM('technical')
108
- : snapshot.renderer.status === 'non-interactive'
109
- ? DIM('non-interactive')
110
- : DIM('custom');
111
- return `${BRAND(snapshot.renderer.name)} ${status} ${DIM(snapshot.renderer.capabilityLabels.join(', '))}`;
112
- }
113
- function getProfileByModelId(registry, modelId) {
114
- if (!registry)
115
- return undefined;
116
- const normalized = modelId.trim();
117
- if (!normalized)
118
- return undefined;
119
- if (registry.profiles.has(normalized))
120
- return registry.profiles.get(normalized);
121
- for (const profile of registry.profiles.values()) {
122
- if (modelId === profile.model)
123
- return profile;
124
- }
125
- return undefined;
126
- }
127
- function resolveModelFromRegistry(config, selector) {
128
- if (!config.modelRegistry)
129
- return undefined;
130
- const trimmed = selector.trim();
131
- if (!trimmed)
132
- return undefined;
133
- return (0, model_registry_1.lookupProfile)(config.modelRegistry, trimmed) ?? undefined;
134
- }
135
- function listConfiguredModelCatalogEntries(registry) {
136
- if (!registry)
137
- return [];
138
- return registry.enabledProfiles.map(profile => {
139
- const provider = registry.providers.get(profile.provider);
140
- return {
141
- name: profile.id,
142
- alias: profile.aliases?.[0],
143
- provider: provider?.displayName ?? profile.provider,
144
- contextWindow: profile.resolvedContextWindow,
145
- maxOutputTokens: profile.resolvedMaxOutputTokens,
146
- source: `${profile.contextSource}/${profile.outputSource}`,
147
- };
148
- });
149
- }
150
- function formatLoopBudgetSource(stats) {
151
- const source = stats.loopBudgetSource ?? 'unknown';
152
- if (source === 'config' && stats.loopBudgetBaseProfile) {
153
- return `config over ${stats.loopBudgetBaseProfile}`;
154
- }
155
- return source;
156
- }
157
- function formatLoopStatsLines(stats, detail = false) {
158
- const lines = [
159
- `Finish ${stats.finishReason}`,
160
- `Requests ${stats.llmRequests} LLM / ${stats.turnsStarted} turns`,
161
- `Tools ${stats.toolCalls} total (${stats.readOnlyToolCalls} read-only, ${stats.unsafeToolCalls} unsafe)`,
162
- `Tool bytes ${(0, format_1.formatBytes)(stats.modelVisibleToolBytes)} model-visible / ${(0, format_1.formatBytes)(stats.toolResultBytes)} total`,
163
- ];
164
- if (stats.summarizedBytes > 0) {
165
- lines.push(`Saved ${(0, format_1.formatBytes)(stats.summarizedBytes)} from model context`);
166
- }
167
- if (stats.compactTrigger) {
168
- lines.push(`Compact ${stats.compactTrigger}`);
169
- }
170
- if (stats.localFastPathUsed) {
171
- lines.push('Fast path yes');
172
- }
173
- if (stats.budgetExceededReason) {
174
- lines.push(`Budget ${stats.budgetExceededReason}`);
175
- }
176
- if (stats.continuationActions && stats.continuationActions.length > 0) {
177
- lines.push(`Next ${stats.continuationActions.join(', ')}`);
178
- }
179
- if ((stats.providerRetryCount ?? 0) > 0) {
180
- const retryParts = [
181
- `${stats.providerRetryCount} retries`,
182
- `delay ${formatDurationMs(stats.providerRetryDelayMs ?? 0)}`,
183
- stats.providerLastRetryErrorType
184
- ? `last ${stats.providerLastRetryErrorType}${stats.providerLastRetryStatus ? `/${stats.providerLastRetryStatus}` : ''}`
185
- : undefined,
186
- ].filter(Boolean);
187
- lines.push(`Provider ${retryParts.join(', ')}`);
188
- }
189
- if ((stats.providerFallbackCount ?? 0) > 0 || stats.providerUsingFallback) {
190
- const fallbackPath = stats.providerFallbackFromModel && stats.providerFallbackToModel
191
- ? `${stats.providerFallbackFromModel} -> ${stats.providerFallbackToModel}`
192
- : stats.providerFinalModel
193
- ? `final ${stats.providerFinalModel}`
194
- : 'active';
195
- lines.push(`Fallback ${fallbackPath}`);
196
- }
197
- if (typeof stats.verificationClaimAllowed === 'boolean') {
198
- const verificationParts = [
199
- stats.verificationProfile ?? 'unknown',
200
- `required=${stats.verificationRequired ? 'yes' : 'no'}`,
201
- `passed=${stats.verificationPassedCommands?.length ?? 0}`,
202
- `failed=${stats.verificationFailedCommands?.length ?? 0}`,
203
- `missing=${stats.verificationMissingCommands?.length ?? 0}`,
204
- `claim=${stats.verificationClaimAllowed ? 'yes' : 'no'}`,
205
- ];
206
- lines.push(`Verify ${verificationParts.join(' ')}`);
207
- }
208
- if (typeof stats.loopBudgetMaxLlmRequests === 'number' ||
209
- typeof stats.loopBudgetMaxToolCalls === 'number' ||
210
- typeof stats.loopBudgetMaxModelVisibleBytes === 'number') {
211
- const caps = [
212
- typeof stats.loopBudgetMaxLlmRequests === 'number'
213
- ? `${stats.llmRequests}/${stats.loopBudgetMaxLlmRequests} LLM`
214
- : undefined,
215
- typeof stats.loopBudgetMaxToolCalls === 'number'
216
- ? `${stats.toolCalls}/${stats.loopBudgetMaxToolCalls} tools`
217
- : undefined,
218
- typeof stats.loopBudgetMaxModelVisibleBytes === 'number'
219
- ? `${(0, format_1.formatBytes)(stats.modelVisibleToolBytes)}/${(0, format_1.formatBytes)(stats.loopBudgetMaxModelVisibleBytes)} visible`
220
- : undefined,
221
- typeof stats.loopBudgetMaxReadOnlyFragmentation === 'number'
222
- ? `fragment ${stats.singleReadOnlyStreak}/${stats.loopBudgetMaxReadOnlyFragmentation}`
223
- : undefined,
224
- ].filter(Boolean);
225
- lines.push(`Budget cap ${caps.join(', ')} (${formatLoopBudgetSource(stats)})`);
226
- }
227
- if (stats.singleReadOnlyStreak > 0 || stats.batchReadSuggestionCount > 0) {
228
- lines.push(`Read-only streak ${stats.singleReadOnlyStreak}, batch_read hints ${stats.batchReadSuggestionCount}`);
229
- }
230
- if (detail) {
231
- lines.push(`Unsafe ${stats.unsafeToolCalls}`);
232
- if (stats.providerRetryErrorTypes && stats.providerRetryErrorTypes.length > 0) {
233
- lines.push(`Retry type ${stats.providerRetryErrorTypes.join(', ')}`);
234
- }
235
- if (stats.verificationFailedCommands && stats.verificationFailedCommands.length > 0) {
236
- lines.push(`Failed ${stats.verificationFailedCommands.join(' && ')}`);
237
- }
238
- if (stats.verificationMissingCommands && stats.verificationMissingCommands.length > 0) {
239
- lines.push(`Missing ${stats.verificationMissingCommands.join(' && ')}`);
240
- }
241
- if (stats.verificationSkippedReason) {
242
- lines.push(`Verify why ${stats.verificationSkippedReason}`);
243
- }
244
- if (stats.continuationHint) {
245
- lines.push(`Next why ${stats.continuationHint}`);
246
- }
247
- lines.push(`Budget hit ${stats.finishReason === 'budget_exceeded' ? 'yes' : 'no'}`);
248
- }
249
- return lines;
250
- }
251
- const CATEGORY_LABELS = {
252
- workflow: 'Workflow',
253
- session: 'Session',
254
- context: 'Context',
255
- tools: 'Tools',
256
- model: 'Model',
257
- system: 'System',
258
- diagnostics: 'Diagnostics',
259
- legacy: 'Legacy',
260
- };
261
- function commandCategory(command) {
262
- return command.category ?? 'system';
263
- }
264
- function getCommandCategoryLabel(category) {
265
- return CATEGORY_LABELS[category ?? 'system'];
266
- }
267
- function sortCommands(commands) {
268
- return [...commands].sort((a, b) => {
269
- const categoryDelta = CATEGORY_ORDER.indexOf(commandCategory(a)) - CATEGORY_ORDER.indexOf(commandCategory(b));
270
- if (categoryDelta !== 0)
271
- return categoryDelta;
272
- const priorityDelta = (a.priority ?? 100) - (b.priority ?? 100);
273
- if (priorityDelta !== 0)
274
- return priorityDelta;
275
- return a.name.localeCompare(b.name);
276
- });
277
- }
278
- function isAbortError(error, abortSignal) {
279
- if (abortSignal?.aborted)
280
- return true;
281
- if (error instanceof Error) {
282
- return error.name === 'AbortError' || error.message.toLowerCase().includes('aborted');
283
- }
284
- return false;
285
- }
286
- function hasCommandFlag(args, flag) {
287
- return args.trim().split(/\s+/u).includes(flag);
288
- }
289
- // ============================================================================
290
- // 工具参数摘要
291
- // ============================================================================
292
- // ============================================================================
293
- // 命令实现
294
- // ============================================================================
295
- let taskManager = null;
296
- function showHelp(ctx) {
297
- console.log();
298
- console.log(HEADER('Commands:'));
299
- console.log();
300
- const visible = getVisibleCommands(ctx.uiRenderer);
301
- for (const category of CATEGORY_ORDER) {
302
- const items = visible.filter(cmd => commandCategory(cmd) === category);
303
- if (items.length === 0)
304
- continue;
305
- console.log(DIM(getCommandCategoryLabel(category)));
306
- for (const cmd of items) {
307
- const aliases = cmd.aliases ? ` (${cmd.aliases.join(', ')})` : '';
308
- const params = cmd.argumentHint || cmd.params?.map(p => `<${p.name}>`).join(' ') || '';
309
- const lifecycle = cmd.deprecated
310
- ? ` deprecated since ${cmd.deprecated.since}${cmd.deprecated.replacement ? `; use ${cmd.deprecated.replacement}` : ''}`
311
- : '';
312
- const risk = cmd.risk === 'destructive' ? ' destructive' : '';
313
- const availability = cmd.availability?.(ctx);
314
- const unavailable = availability && !availability.available
315
- ? ` unavailable: ${availability.reason ?? 'requirements not met'}`
316
- : '';
317
- console.log(` ${ACCENT(`/${cmd.name}`)}${aliases} ${DIM(params)}`);
318
- console.log(` ${DIM(`${cmd.description}${lifecycle}${risk}${unavailable}`)}`);
319
- }
320
- console.log();
321
- }
322
- console.log(DIM('Type any text without / prefix to chat with the LLM.'));
323
- console.log();
324
- return { success: true };
325
- }
326
- function showStatus(ctx) {
327
- console.log();
328
- console.log(HEADER('System Status'));
329
- console.log(DIM('─'.repeat(40)));
330
- const brainStatus = ctx.runtime.brain.getStatus();
331
- const memStatus = ctx.runtime.memory.getStatus();
332
- const storeStats = ctx.runtime.store.getStats();
333
- console.log(` Mode ${BRAND(ctx.config.mode)}`);
334
- console.log(` Log level ${DIM(ctx.config.logLevel)}`);
335
- const modelId = ctx.llm?.getModel() ?? snapshotCurrentModel(ctx);
336
- const modelContext = (0, model_context_1.resolveModelContext)(modelId);
337
- const compactStats = getCommandAutoCompact(ctx, modelId).getStats();
338
- console.log(` Model ${BRAND(modelId)}`);
339
- console.log(` Context ${DIM(`${formatTokenCount(modelContext.contextWindow)} tokens (${modelContext.source}${modelContext.source === 'fuzzy' ? `:${modelContext.matchedId}` : ''})`)}`);
340
- console.log(` Compact ${compactStats.enabled ? SUCCESS('auto') : WARN('off')} ${DIM(`predict ${formatThreshold(compactStats.predictiveCompactThreshold)}, hard ${formatThreshold(compactStats.threshold)}, used ${compactStats.ctxPercent}%`)}`);
341
- console.log(` Renderer ${formatRendererStatus(ctx)}`);
342
- console.log();
343
- console.log(` Agents ${SUCCESS(brainStatus.agents.length)} registered`);
344
- console.log(` Tasks ${brainStatus.pendingTasks} pending (${brainStatus.strategy} strategy)`);
345
- console.log();
346
- console.log(` Memory (inline):`);
347
- console.log(` Working ${memStatus.working} entries`);
348
- console.log(` Short-term ${memStatus['short-term']} entries`);
349
- console.log(` Long-term ${memStatus['long-term']} entries`);
350
- console.log();
351
- console.log(` Memory (store):`);
352
- console.log(` Working ${storeStats.working} entries`);
353
- console.log(` Short-term ${storeStats['short-term']} entries`);
354
- console.log(` Long-term ${storeStats['long-term']} entries`);
355
- (0, prompt_context_1.refreshProjectInstructions)(ctx.store, ctx.cwd);
356
- const snapshot = ctx.store.getSnapshot();
357
- const instructionFiles = (0, project_instructions_1.loadProjectInstructionFiles)(ctx.cwd);
358
- console.log();
359
- console.log(` Context:`);
360
- console.log(` Project rules ${instructionFiles.length > 0 ? SUCCESS(`${instructionFiles.length} files`) : DIM('none')}`);
361
- for (const file of instructionFiles.slice(0, 8)) {
362
- console.log(` ${DIM(file.path)}${file.truncated ? ` ${WARN('(truncated)')}` : ''}`);
363
- }
364
- if (instructionFiles.length > 8) {
365
- console.log(` ${DIM(`... ${instructionFiles.length - 8} more`)}`);
366
- }
367
- console.log(` Prompt rules ${snapshot.projectInstructionsContent ? SUCCESS(`${snapshot.projectInstructionsContent.length} chars`) : DIM('none')}`);
368
- console.log(` Project memory ${snapshot.memoryContent ? SUCCESS(`${snapshot.memoryContent.length} chars`) : DIM('none')}`);
369
- console.log(` Skills index ${snapshot.skillsContent ? SUCCESS(`${snapshot.skillsContent.length} chars`) : DIM('none')}`);
370
- if (snapshot.lastLoopStats) {
371
- const stats = snapshot.lastLoopStats;
372
- console.log();
373
- console.log(` Last loop:`);
374
- for (const line of formatLoopStatsLines(stats)) {
375
- console.log(` ${line}`);
376
- }
377
- }
378
- const harnessState = snapshot.harnessState;
379
- if (harnessState?.contract || harnessState?.capsule) {
380
- console.log();
381
- console.log(` Harness:`);
382
- if (harnessState.contract) {
383
- console.log(` Objective ${ACCENT(harnessState.contract.objective)}`);
384
- }
385
- console.log(` Ledger ${DIM(`${harnessState.ledger.length} entries`)}`);
386
- if (harnessState.capsule) {
387
- console.log(` Next ${DIM(harnessState.capsule.nextAction)}`);
388
- const passed = harnessState.capsule.verification.passed.length;
389
- const failed = harnessState.capsule.verification.failed.length;
390
- console.log(` Verify ${SUCCESS(`${passed} passed`)} / ${failed > 0 ? ERROR(`${failed} failed`) : DIM('0 failed')}`);
391
- }
392
- }
393
- console.log();
394
- return { success: true };
395
- }
396
- function handleLoopStats(ctx) {
397
- const stats = ctx.store.getSnapshot().lastLoopStats;
398
- if (!stats) {
399
- console.log('No agent-loop stats recorded yet.');
400
- return { success: true };
401
- }
402
- console.log(HEADER('Agent Loop Stats'));
403
- console.log();
404
- for (const line of formatLoopStatsLines(stats, true)) {
405
- console.log(` ${line}`);
406
- }
407
- console.log();
408
- console.log(DIM('Use this to spot excessive LLM requests, fragmented read-only tool calls, and local fast-path hits.'));
409
- return { success: true };
410
- }
411
- function formatTraceEventLine(event) {
412
- const time = new Date(event.timestamp).toLocaleTimeString();
413
- const prefix = `${DIM(time)} ${ACCENT(event.type)}`;
414
- switch (event.type) {
415
- case 'turn_start':
416
- return `${prefix} input=${(0, format_1.formatBytes)(event.inputBytes ?? 0)}${event.localFastPathUsed ? ' fast-path' : ''}${event.note ? ` ${DIM(event.note)}` : ''}`;
417
- case 'request_start':
418
- return `${prefix} model=${event.model ?? 'unknown'} iteration=${event.turn ?? '?'}`;
419
- case 'provider_retry': {
420
- const parts = [
421
- `count=${event.providerRetryCount ?? 0}`,
422
- `delay=${formatDurationMs(event.providerRetryDelayMs ?? 0)}`,
423
- event.providerLastRetryErrorType
424
- ? `last=${event.providerLastRetryErrorType}${event.providerLastRetryStatus ? `/${event.providerLastRetryStatus}` : ''}`
425
- : '',
426
- event.providerRetryErrorTypes?.length
427
- ? `types=${event.providerRetryErrorTypes.join(',')}`
428
- : '',
429
- event.providerFinalModel ? `final=${event.providerFinalModel}` : '',
430
- ].filter(Boolean);
431
- return `${prefix} ${parts.join(' ')}`;
432
- }
433
- case 'provider_fallback': {
434
- const path = event.providerFallbackFromModel && event.providerFallbackToModel
435
- ? `${event.providerFallbackFromModel}->${event.providerFallbackToModel}`
436
- : (event.providerFinalModel ?? 'active');
437
- const parts = [
438
- `count=${event.providerFallbackCount ?? 0}`,
439
- `path=${path}`,
440
- `using=${event.providerUsingFallback ? 'yes' : 'no'}`,
441
- ];
442
- return `${prefix} ${parts.join(' ')}`;
443
- }
444
- case 'prompt_assembly': {
445
- const parts = [
446
- `model=${event.promptModelId ?? 'unknown'}`,
447
- `tokens=${event.promptEstimatedTokens ?? 0}/${event.promptBudgetTokens ?? 0}`,
448
- `core=${event.promptCoreTokens ?? 0}`,
449
- `evidenceBudget=${event.promptEvidenceBudgetTokens ?? 0}`,
450
- `recentBudget=${event.promptRecentTurnBudgetTokens ?? 0}`,
451
- `included=${event.promptIncludedEvidenceCount ?? 0}`,
452
- `omitted=${event.promptOmittedEvidenceCount ?? 0}`,
453
- ];
454
- const sections = event.promptSections?.length
455
- ? ` sections=${event.promptSections.join(',')}`
456
- : '';
457
- const evidence = event.promptIncludedEvidence?.length
458
- ? ` evidence=${event.promptIncludedEvidence.slice(0, 6).join(', ')}${event.promptIncludedEvidence.length > 6 ? ', ...' : ''}`
459
- : '';
460
- return `${prefix} ${parts.join(' ')}${sections ? DIM(sections) : ''}${evidence ? ` ${DIM(evidence)}` : ''}`;
461
- }
462
- case 'assistant_tool_calls':
463
- return `${prefix} calls=${event.toolCallCount ?? 0} assistant=${(0, format_1.formatBytes)(event.contentBytes ?? 0)}`;
464
- case 'checkpoint': {
465
- const files = event.checkpointFiles?.length
466
- ? ` files=${event.checkpointFiles.slice(0, 6).join(', ')}${event.checkpointFiles.length > 6 ? ', ...' : ''}`
467
- : '';
468
- const targets = event.workspaceFiles?.length && !files
469
- ? ` targets=${event.workspaceFiles.slice(0, 6).join(', ')}${event.workspaceFiles.length > 6 ? ', ...' : ''}`
470
- : '';
471
- return `${prefix} id=${event.checkpointId ?? 'unknown'} saved=${event.checkpointFileCount ?? 0}${files}${targets}${event.note ? ` ${DIM(event.note)}` : ''}`;
472
- }
473
- case 'tool_call':
474
- return `${prefix} ${event.name ?? 'tool'}${event.argsSummary ? ` ${DIM(event.argsSummary)}` : ''}${event.argsArtifactId ? ` ${DIM(`args=/artifacts show ${event.argsArtifactId} --full${event.argsBytes ? ` (${(0, format_1.formatBytes)(event.argsBytes)})` : ''}`)}` : ''}${event.callId ? ` ${DIM(event.callId)}` : ''}`;
475
- case 'permission_decision': {
476
- const status = event.permissionApproved ? SUCCESS('approved') : ERROR('denied');
477
- const parts = [
478
- `source=${event.permissionSource ?? 'unknown'}`,
479
- `behavior=${event.permissionBehavior ?? 'unknown'}`,
480
- ];
481
- if (typeof event.permissionDuration === 'number') {
482
- parts.push(`${event.permissionDuration}ms`);
483
- }
484
- return `${prefix} ${status} ${event.name ?? 'tool'} ${DIM(parts.join(' '))}${event.permissionReason ? ` ${DIM(event.permissionReason)}` : ''}`;
485
- }
486
- case 'tool_result': {
487
- const status = event.success === false ? ERROR('error') : SUCCESS('ok');
488
- const bytes = [
489
- `output=${(0, format_1.formatBytes)(event.outputBytes ?? 0)}`,
490
- `model=${(0, format_1.formatBytes)(event.modelVisibleBytes ?? 0)}`,
491
- ];
492
- if (event.artifactId)
493
- bytes.push(`artifact=${event.artifactId}`);
494
- return `${prefix} ${status} ${event.name ?? 'tool'} ${DIM(`${event.duration ?? 0}ms`)} ${DIM(bytes.join(' '))}${event.error ? ` ${ERROR(event.error)}` : ''}`;
495
- }
496
- case 'message':
497
- return `${prefix} assistant=${(0, format_1.formatBytes)(event.contentBytes ?? 0)}`;
498
- case 'strategy_exhausted':
499
- return `${prefix}${event.note ? ` ${WARN(event.note)}` : ''}`;
500
- case 'complete': {
501
- const stats = [
502
- `finish=${event.finishReason ?? 'unknown'}`,
503
- `llm=${typeof event.llmRequests === 'number' ? event.llmRequests : 'unknown'}`,
504
- `tools=${typeof event.toolCalls === 'number' ? event.toolCalls : 'unknown'}`,
505
- ];
506
- if (event.loopBudgetSource ||
507
- typeof event.loopBudgetMaxLlmRequests === 'number' ||
508
- typeof event.loopBudgetMaxToolCalls === 'number' ||
509
- typeof event.loopBudgetMaxModelVisibleBytes === 'number') {
510
- const source = event.loopBudgetSource === 'config' && event.loopBudgetBaseProfile
511
- ? `config/${event.loopBudgetBaseProfile}`
512
- : (event.loopBudgetSource ?? 'unknown');
513
- const caps = [
514
- typeof event.loopBudgetMaxLlmRequests === 'number'
515
- ? `${typeof event.llmRequests === 'number' ? event.llmRequests : '?'}/${event.loopBudgetMaxLlmRequests}llm`
516
- : undefined,
517
- typeof event.loopBudgetMaxToolCalls === 'number'
518
- ? `${typeof event.toolCalls === 'number' ? event.toolCalls : '?'}/${event.loopBudgetMaxToolCalls}tools`
519
- : undefined,
520
- typeof event.loopBudgetMaxModelVisibleBytes === 'number'
521
- ? `${(0, format_1.formatBytes)(event.loopBudgetMaxModelVisibleBytes)}visible`
522
- : undefined,
523
- typeof event.loopBudgetMaxReadOnlyFragmentation === 'number'
524
- ? `frag=${event.loopBudgetMaxReadOnlyFragmentation}`
525
- : undefined,
526
- event.loopBudgetConfigOverride ? 'override=yes' : undefined,
527
- ].filter(Boolean);
528
- stats.push(`budgetProfile=${source}${caps.length ? `(${caps.join(',')})` : ''}`);
529
- }
530
- if (event.budgetExceededReason)
531
- stats.push(`budget=${event.budgetExceededReason}`);
532
- if (event.continuationActions?.length)
533
- stats.push(`next=${event.continuationActions.join(',')}`);
534
- if (event.continuationHint)
535
- stats.push(`hint=${event.continuationHint}`);
536
- if (event.localFastPathUsed)
537
- stats.push('fast-path=yes');
538
- return `${prefix} ${stats.join(' ')}`;
539
- }
540
- case 'local_fast_path':
541
- return `${prefix} ${event.name ?? 'tool'}${event.argsSummary ? ` ${DIM(event.argsSummary)}` : ''}${event.argsArtifactId ? ` ${DIM(`args=/artifacts show ${event.argsArtifactId} --full${event.argsBytes ? ` (${(0, format_1.formatBytes)(event.argsBytes)})` : ''}`)}` : ''}${event.note ? ` ${DIM(event.note)}` : ''}`;
542
- case 'workspace_snapshot': {
543
- const state = event.workspaceGitAvailable === false
544
- ? WARN('not-git')
545
- : event.workspaceDirty
546
- ? WARN('dirty')
547
- : SUCCESS('clean');
548
- const files = event.workspaceFiles?.length
549
- ? ` files=${event.workspaceFiles.slice(0, 6).join(', ')}${event.workspaceFiles.length > 6 ? ', ...' : ''}`
550
- : '';
551
- return `${prefix} ${event.workspacePhase ?? 'unknown'} ${state} count=${event.workspaceFileCount ?? 0}${event.workspaceBranch ? ` branch=${event.workspaceBranch}` : ''}${files}${event.error ? ` ${ERROR(event.error)}` : ''}`;
552
- }
553
- case 'workspace_delta': {
554
- const added = event.workspaceNewByTurn ?? [];
555
- const changed = event.workspaceChangedByTurn ?? [];
556
- const modifiedPreExisting = event.workspaceModifiedPreExistingByTurn ?? [];
557
- const resolved = event.workspaceResolvedByTurn ?? [];
558
- const parts = [
559
- `after=${event.workspaceFileCount ?? 0}`,
560
- `new=${added.length}`,
561
- `changed=${changed.length}`,
562
- `pre-existing-modified=${modifiedPreExisting.length}`,
563
- `resolved=${resolved.length}`,
564
- ];
565
- const details = [
566
- added.length
567
- ? `new: ${added.slice(0, 6).join(', ')}${added.length > 6 ? ', ...' : ''}`
568
- : '',
569
- changed.length
570
- ? `changed: ${changed.slice(0, 6).join(', ')}${changed.length > 6 ? ', ...' : ''}`
571
- : '',
572
- modifiedPreExisting.length
573
- ? `pre-existing modified: ${modifiedPreExisting.slice(0, 6).join(', ')}${modifiedPreExisting.length > 6 ? ', ...' : ''}`
574
- : '',
575
- resolved.length
576
- ? `resolved: ${resolved.slice(0, 6).join(', ')}${resolved.length > 6 ? ', ...' : ''}`
577
- : '',
578
- ]
579
- .filter(Boolean)
580
- .join(' | ');
581
- return `${prefix} ${parts.join(' ')}${details ? ` ${DIM(details)}` : ''}${event.note ? ` ${DIM(event.note)}` : ''}`;
582
- }
583
- case 'verification_profile': {
584
- const commands = event.verificationCommands ?? [];
585
- const files = event.verificationChangedFiles ?? [];
586
- const details = [
587
- `profile=${event.verificationProfile ?? 'unknown'}`,
588
- `required=${event.verificationRequired === false ? 'no' : 'yes'}`,
589
- `commands=${commands.length}`,
590
- `files=${files.length}`,
591
- ];
592
- if (event.verificationRisky) {
593
- details.push(`risk=${WARN('high')}(${files.length} files)`);
594
- }
595
- const commandPreview = commands.length
596
- ? ` cmds: ${commands.slice(0, 4).join(' && ')}${commands.length > 4 ? ' && ...' : ''}`
597
- : '';
598
- return `${prefix} ${details.join(' ')}${commandPreview ? ` ${DIM(commandPreview)}` : ''}${event.note ? ` ${DIM(event.note)}` : ''}`;
599
- }
600
- case 'verification_result': {
601
- const status = event.verificationPassed === true ? SUCCESS('passed') : ERROR('failed');
602
- const command = event.verificationCommand ?? 'unknown';
603
- return `${prefix} ${status} ${command}${typeof event.outputBytes === 'number' ? ` ${DIM((0, format_1.formatBytes)(event.outputBytes))}` : ''}${event.error ? ` ${ERROR(event.error)}` : ''}`;
604
- }
605
- case 'verification_summary': {
606
- const passed = event.verificationPassedCommands?.length ?? 0;
607
- const failed = event.verificationFailedCommands?.length ?? 0;
608
- const missing = event.verificationMissingCommands?.length ?? 0;
609
- const parts = [
610
- `profile=${event.verificationProfile ?? 'unknown'}`,
611
- `required=${event.verificationRequired === false ? 'no' : 'yes'}`,
612
- `passed=${passed}`,
613
- `failed=${failed}`,
614
- `missing=${missing}`,
615
- `claimAllowed=${event.verificationClaimAllowed ? 'yes' : 'no'}`,
616
- ];
617
- const missingPreview = missing > 0
618
- ? ` missing: ${(event.verificationMissingCommands ?? []).slice(0, 4).join(' && ')}${missing > 4 ? ' && ...' : ''}`
619
- : '';
620
- return `${prefix} ${parts.join(' ')}${missingPreview ? ` ${DIM(missingPreview)}` : ''}${event.note ? ` ${DIM(event.note)}` : ''}`;
621
- }
622
- case 'aborted':
623
- return `${prefix}${event.note ? ` ${WARN(event.note)}` : ''}`;
624
- case 'error':
625
- return `${prefix} ${ERROR(event.error ?? 'unknown error')}`;
626
- default:
627
- return prefix;
628
- }
629
- }
630
- function handleTrace(ctx, args = '') {
631
- const session = ctx.getSession?.() ?? (ctx.sessionId ? (0, session_storage_1.loadSessionMeta)(ctx.sessionId) : null);
632
- if (!session) {
633
- console.log(ERROR('No active session.'));
634
- console.log(DIM('Use /resume <session-id> first, or start a chat turn to create a session.'));
635
- return { success: false };
636
- }
637
- const events = (0, session_storage_1.readSessionTraceEvents)(session.id);
638
- if (events.length === 0) {
639
- console.log(DIM(`No trace events recorded for session ${session.id.slice(0, 8)} yet.`));
640
- return { success: true };
641
- }
642
- const ref = args.trim();
643
- const requestedTurnId = ref && ref !== 'latest' ? ref : events[events.length - 1].turnId;
644
- const turnEvents = events.filter(event => event.turnId === requestedTurnId);
645
- if (turnEvents.length === 0) {
646
- const recentTurnIds = [...new Set(events.map(event => event.turnId))].slice(-8).reverse();
647
- console.log(ERROR(`Trace turn not found: ${requestedTurnId}`));
648
- console.log(DIM(`Recent turns: ${recentTurnIds.join(', ')}`));
649
- return { success: false };
650
- }
651
- console.log(HEADER(`Trace ${requestedTurnId}`));
652
- console.log(DIM(`Session ${session.id} Events ${turnEvents.length}`));
653
- console.log(DIM('─'.repeat(40)));
654
- for (const event of turnEvents) {
655
- console.log(` ${formatTraceEventLine(event)}`);
656
- }
657
- console.log();
658
- console.log(DIM('Trace stores metadata only; full transcript and tool output stay in session/artifacts.'));
659
- return { success: true };
660
- }
661
- function latestToolTrace(events) {
662
- for (let index = events.length - 1; index >= 0; index--) {
663
- const event = events[index];
664
- if (event.type !== 'tool_result' && event.type !== 'tool_call')
665
- continue;
666
- const callId = event.callId;
667
- const result = event.type === 'tool_result' ? event : undefined;
668
- const call = event.type === 'tool_call'
669
- ? event
670
- : callId
671
- ? events
672
- .slice(0, index)
673
- .reverse()
674
- .find(candidate => candidate.type === 'tool_call' && candidate.callId === callId)
675
- : undefined;
676
- return { call, result };
677
- }
678
- return null;
679
- }
680
- /** Find tool trace by 1-based sequence number across all tool events. */
681
- function toolTraceBySeq(events, seq) {
682
- let counter = 0;
683
- const toolEvents = new Map();
684
- for (const event of events) {
685
- if (event.type !== 'tool_call' && event.type !== 'tool_result')
686
- continue;
687
- if (!event.callId)
688
- continue;
689
- const entry = toolEvents.get(event.callId) ?? {};
690
- if (event.type === 'tool_call') {
691
- counter++;
692
- entry.call = event;
693
- }
694
- else {
695
- if (!entry.call)
696
- counter++;
697
- entry.result = event;
698
- }
699
- toolEvents.set(event.callId, entry);
700
- if (counter === seq) {
701
- return toolEvents.get(event.callId) ?? null;
702
- }
703
- }
704
- return null;
705
- }
706
- /** Find tool trace by callId prefix. */
707
- function toolTraceByCallId(events, callIdPrefix) {
708
- let call;
709
- let result;
710
- for (const event of events) {
711
- if (event.type !== 'tool_call' && event.type !== 'tool_result')
712
- continue;
713
- if (!event.callId?.startsWith(callIdPrefix))
714
- continue;
715
- if (event.type === 'tool_call')
716
- call = event;
717
- else
718
- result = event;
719
- }
720
- if (!call && !result)
721
- return null;
722
- return { call, result };
723
- }
724
- /** Collect all tool trace pairs ordered by appearance (1-based sequence). */
725
- function collectToolTracePairs(events) {
726
- const pairs = [];
727
- const seen = new Map();
728
- let counter = 0;
729
- for (const event of events) {
730
- if (event.type !== 'tool_call' && event.type !== 'tool_result')
731
- continue;
732
- if (!event.callId)
733
- continue;
734
- let entry = seen.get(event.callId);
735
- if (!entry) {
736
- counter++;
737
- entry = { seq: counter };
738
- seen.set(event.callId, entry);
739
- pairs.push(entry);
740
- }
741
- if (event.type === 'tool_call')
742
- entry.call = event;
743
- else
744
- entry.result = event;
745
- }
746
- return pairs;
747
- }
748
- function parseLastToolArgs(args = '') {
749
- const parts = args.trim().split(/\s+/).filter(Boolean);
750
- const ref = parts.length > 0 && !parts[0].startsWith('--') ? parts[0] : undefined;
751
- return {
752
- full: parts.includes('--full'),
753
- preview: !parts.includes('--no-preview'),
754
- ref,
755
- };
756
- }
757
- function printLastToolArtifactPreview(projectPath, label, artifactId, full) {
758
- if (!artifactId)
759
- return;
760
- const artifact = (0, tool_artifacts_1.findArtifact)(projectPath, artifactId);
761
- if (!artifact) {
762
- console.log(` ${label} preview ${DIM(`artifact not found or ambiguous: ${artifactId}`)}`);
763
- return;
764
- }
765
- const content = (0, tool_artifacts_1.retrieveArtifact)(artifact.path);
766
- if (content == null) {
767
- console.log(` ${label} preview ${DIM(`artifact cannot be read: ${artifact.id}`)}`);
768
- return;
769
- }
770
- const redacted = (0, session_storage_1.redactTraceText)(content);
771
- const maxPreviewBytes = 4 * 1024;
772
- const shouldTruncate = !full && Buffer.byteLength(redacted, 'utf8') > maxPreviewBytes;
773
- const preview = shouldTruncate
774
- ? Buffer.from(redacted, 'utf8').subarray(0, maxPreviewBytes).toString('utf8')
775
- : redacted;
776
- console.log(` ${label} preview`);
777
- console.log(` ${DIM('─'.repeat(40))}`);
778
- for (const line of preview.split('\n')) {
779
- console.log(` ${line}`);
780
- }
781
- if (shouldTruncate) {
782
- console.log(` ${DIM(`... preview truncated at ${(0, format_1.formatBytes)(maxPreviewBytes)}. Use /last-tool --full or /artifacts show ${artifact.id} --full.`)}`);
783
- }
784
- }
785
- function lastToolInputLabel(toolName) {
786
- return toolName === 'exec_command' ? 'Command' : 'Args';
787
- }
788
- function lastToolField(label) {
789
- return label.padEnd(13, ' ');
790
- }
791
- function handleLastTool(ctx, args = '') {
792
- const options = parseLastToolArgs(args);
793
- const session = ctx.getSession?.() ?? (ctx.sessionId ? (0, session_storage_1.loadSessionMeta)(ctx.sessionId) : null);
794
- if (!session) {
795
- console.log(ERROR('No active session.'));
796
- console.log(DIM('Use /resume <session-id> first, or start a chat turn to create a session.'));
797
- return { success: false };
798
- }
799
- const events = (0, session_storage_1.readSessionTraceEvents)(session.id);
800
- // Resolve reference: latest (default), #N, or callId prefix
801
- let trace = null;
802
- let listMode = false;
803
- if (!options.ref || options.ref === 'latest') {
804
- trace = latestToolTrace(events);
805
- }
806
- else if (/^#?\d+$/.test(options.ref)) {
807
- const seq = parseInt(options.ref.replace('#', ''), 10);
808
- trace = toolTraceBySeq(events, seq);
809
- if (!trace) {
810
- console.log(ERROR(`Tool #${seq} not found in session trace.`));
811
- // Fall back to listing available tools
812
- listMode = true;
813
- }
814
- }
815
- else {
816
- trace = toolTraceByCallId(events, options.ref);
817
- if (!trace) {
818
- console.log(ERROR(`Tool with callId prefix "${options.ref}" not found in session trace.`));
819
- listMode = true;
820
- }
821
- }
822
- if (listMode || !trace) {
823
- const pairs = collectToolTracePairs(events);
824
- if (pairs.length === 0) {
825
- console.log(DIM(`No tool trace events recorded for session ${session.id.slice(0, 8)} yet.`));
826
- return { success: true };
827
- }
828
- console.log(HEADER(`Tools (${pairs.length})`));
829
- console.log(DIM('─'.repeat(60)));
830
- for (const pair of pairs.slice(-30)) {
831
- const source = pair.result ?? pair.call;
832
- const name = source?.name ?? 'tool';
833
- const status = pair.result ? (pair.result.success === false ? '✗' : '✓') : '…';
834
- const duration = typeof pair.result?.duration === 'number'
835
- ? ` (${formatDurationMs(pair.result.duration)})`
836
- : '';
837
- const argsShort = (pair.call?.argsSummary ?? '').slice(0, 40);
838
- console.log(` #${pair.seq} ${status} ${ACCENT(name)}${duration} ${DIM(argsShort)}`);
839
- }
840
- console.log();
841
- console.log(DIM('Use /last-tool #N or /last-tool <callId> for details.'));
842
- return { success: true };
843
- }
844
- const call = trace.call;
845
- const result = trace.result;
846
- const source = result ?? call;
847
- const argsSource = call ?? result;
848
- const name = source?.name ?? 'tool';
849
- const inputLabel = lastToolInputLabel(name);
850
- const callId = source?.callId ?? call?.callId;
851
- const status = result
852
- ? result.success === false
853
- ? ERROR('error')
854
- : SUCCESS('ok')
855
- : WARN('running');
856
- // Resolve sequence number from the trace events
857
- let seqLabel = '';
858
- if (options.ref && /^#?\d+$/.test(options.ref)) {
859
- seqLabel = `#${parseInt(options.ref.replace('#', ''), 10)} `;
860
- }
861
- else if (result || call) {
862
- const allPairs = collectToolTracePairs(events);
863
- const matchingPair = allPairs.find(p => p.call?.callId === callId || p.result?.callId === callId);
864
- if (matchingPair)
865
- seqLabel = `#${matchingPair.seq} `;
866
- }
867
- console.log(HEADER(`Last Tool ${seqLabel}`.trimEnd()));
868
- console.log(DIM('─'.repeat(40)));
869
- console.log(` Tool ${ACCENT(name)}`);
870
- console.log(` Turn ${DIM(source?.turnId ?? 'unknown')}`);
871
- if (callId)
872
- console.log(` Call ${DIM(callId)}`);
873
- console.log(` Status ${status}`);
874
- if (typeof result?.duration === 'number') {
875
- console.log(` Time ${DIM(formatDurationMs(result.duration))}`);
876
- }
877
- if (argsSource?.argsSummary) {
878
- console.log(` ${lastToolField(inputLabel)}${DIM((0, session_storage_1.redactTraceText)(argsSource.argsSummary))}`);
879
- }
880
- if (argsSource?.argsArtifactId) {
881
- const size = typeof argsSource.argsBytes === 'number' ? ` (${(0, format_1.formatBytes)(argsSource.argsBytes)})` : '';
882
- console.log(` ${lastToolField(`${inputLabel} full`)}${DIM(`/artifacts show ${argsSource.argsArtifactId} --full${size}`)}`);
883
- }
884
- if (typeof result?.outputBytes === 'number') {
885
- const modelVisible = typeof result.modelVisibleBytes === 'number'
886
- ? `, model-visible ${(0, format_1.formatBytes)(result.modelVisibleBytes)}`
887
- : '';
888
- console.log(` Output ${DIM(`${(0, format_1.formatBytes)(result.outputBytes)}${modelVisible}`)}`);
889
- }
890
- if (result?.artifactId) {
891
- console.log(` Output full ${DIM(`/artifacts show ${result.artifactId} --full`)}`);
892
- }
893
- if (result?.error) {
894
- console.log(` Error ${ERROR((0, session_storage_1.redactTraceText)(result.error))}`);
895
- }
896
- if (options.preview) {
897
- const projectPath = session.projectPath || ctx.cwd;
898
- printLastToolArtifactPreview(projectPath, inputLabel, argsSource?.argsArtifactId, options.full);
899
- printLastToolArtifactPreview(projectPath, 'Output', result?.artifactId, options.full);
900
- }
901
- console.log();
902
- console.log(DIM('Use /last-tool --full for redacted full previews, --no-preview for metadata only, or /trace latest for the ordered turn timeline.'));
903
- return { success: true };
904
- }
905
- function formatDateTime(timestamp) {
906
- return new Date(timestamp).toLocaleString();
907
- }
908
- function parseArtifactArgs(args) {
909
- const parts = args.trim().split(/\s+/).filter(Boolean);
910
- let full = false;
911
- let limit = 20;
912
- const positional = [];
913
- for (let i = 0; i < parts.length; i++) {
914
- const part = parts[i];
915
- if (part === '--full') {
916
- full = true;
917
- continue;
918
- }
919
- if ((part === '--limit' || part === '-n') && parts[i + 1]) {
920
- const parsed = Number(parts[i + 1]);
921
- if (Number.isInteger(parsed) && parsed > 0) {
922
- limit = Math.min(parsed, 200);
923
- }
924
- i++;
925
- continue;
926
- }
927
- positional.push(part);
928
- }
929
- if (positional[0] === 'show' || positional[0] === 'cat') {
930
- return { action: 'show', ref: positional[1], full, limit };
931
- }
932
- if (positional[0]) {
933
- return { action: 'show', ref: positional[0], full, limit };
934
- }
935
- return { action: 'list', full, limit };
936
- }
937
- function printArtifactPreview(content, full) {
938
- const maxPreviewBytes = 16 * 1024;
939
- if (full || Buffer.byteLength(content, 'utf8') <= maxPreviewBytes) {
940
- console.log(content);
941
- return;
942
- }
943
- const preview = Buffer.from(content, 'utf8').subarray(0, maxPreviewBytes).toString('utf8');
944
- console.log(preview);
945
- console.log();
946
- console.log(DIM(`... preview truncated at ${(0, format_1.formatBytes)(maxPreviewBytes)}. Use /artifacts show <id> --full for full output.`));
947
- }
948
- function formatArtifactPathForDisplay(artifactPath) {
949
- return (0, session_storage_1.redactTraceText)(artifactPath);
950
- }
951
- function handleArtifacts(ctx, args = '') {
952
- const parsed = parseArtifactArgs(args);
953
- if (parsed.action === 'list') {
954
- const artifacts = (0, tool_artifacts_1.listArtifacts)(ctx.cwd, parsed.limit);
955
- console.log(HEADER('Artifacts'));
956
- console.log(DIM('─'.repeat(40)));
957
- if (artifacts.length === 0) {
958
- console.log(DIM('No artifacts found for this project.'));
959
- return { success: true };
960
- }
961
- for (const artifact of artifacts) {
962
- console.log(`${ACCENT(artifact.id)} ${DIM(artifact.toolName)} ${(0, format_1.formatBytes)(artifact.outputBytes)}`);
963
- console.log(` ${DIM(formatDateTime(artifact.modifiedAt))}`);
964
- console.log(` ${DIM(formatArtifactPathForDisplay(artifact.path))}`);
965
- }
966
- console.log();
967
- console.log(DIM('Use /artifacts show <id|prefix> to preview, or add --full for full output.'));
968
- return { success: true };
969
- }
970
- if (!parsed.ref) {
971
- console.log(ERROR('Usage: /artifacts show <id|prefix> [--full]'));
972
- return { success: false };
973
- }
974
- const artifact = (0, tool_artifacts_1.findArtifact)(ctx.cwd, parsed.ref);
975
- if (!artifact) {
976
- console.log(ERROR(`Artifact not found or ambiguous: ${parsed.ref}`));
977
- console.log(DIM('Run /artifacts to list available artifact ids.'));
978
- return { success: false };
979
- }
980
- const content = (0, tool_artifacts_1.retrieveArtifact)(artifact.path);
981
- if (content == null) {
982
- console.log(ERROR(`Artifact exists but cannot be read: ${artifact.id}`));
983
- console.log(DIM(formatArtifactPathForDisplay(artifact.path)));
984
- return { success: false };
985
- }
986
- console.log(HEADER(`Artifact ${artifact.id}`));
987
- console.log(DIM(`Tool ${artifact.toolName} Size ${(0, format_1.formatBytes)(artifact.outputBytes)} Modified ${formatDateTime(artifact.modifiedAt)}`));
988
- console.log(DIM(formatArtifactPathForDisplay(artifact.path)));
989
- console.log(DIM('─'.repeat(40)));
990
- printArtifactPreview(content, parsed.full);
991
- return { success: true };
992
- }
993
- function findCheckpointByRef(ctx, ref) {
994
- const checkpoints = (0, checkpoint_1.listCheckpoints)(ctx.cwd);
995
- const exact = checkpoints.find(checkpoint => checkpoint.turnId === ref);
996
- if (exact)
997
- return { checkpoint: exact, ambiguous: false };
998
- const matches = checkpoints.filter(checkpoint => checkpoint.turnId.startsWith(ref));
999
- return {
1000
- checkpoint: matches.length === 1 ? matches[0] : undefined,
1001
- ambiguous: matches.length > 1,
1002
- };
1003
- }
1004
- function handleCheckpoint(ctx, args = '') {
1005
- const tokens = args.trim().split(/\s+/).filter(Boolean);
1006
- const action = tokens[0] ?? 'list';
1007
- if (action === 'list') {
1008
- const checkpoints = (0, checkpoint_1.listCheckpoints)(ctx.cwd);
1009
- console.log(HEADER('Checkpoints'));
1010
- console.log(DIM('─'.repeat(40)));
1011
- if (checkpoints.length === 0) {
1012
- console.log(DIM('No checkpoints found for this project.'));
1013
- return { success: true };
1014
- }
1015
- for (const checkpoint of checkpoints.slice(0, 20)) {
1016
- console.log(`${ACCENT(checkpoint.turnId)} ${DIM(formatDateTime(checkpoint.createdAt))}`);
1017
- const files = checkpoint.files
1018
- .map(file => file.path)
1019
- .slice(0, 8)
1020
- .join(', ');
1021
- console.log(` ${DIM(`${checkpoint.files.length} file(s)${files ? `: ${files}` : ''}`)}`);
1022
- }
1023
- console.log();
1024
- console.log(DIM('Use /checkpoint restore <turn-id|prefix> to preview, then add --yes to restore.'));
1025
- return { success: true };
1026
- }
1027
- if (action !== 'restore') {
1028
- console.log(ERROR('Usage: /checkpoint [list|restore <turn-id|prefix> [--yes]]'));
1029
- return { success: false };
1030
- }
1031
- const ref = tokens.find(token => token !== 'restore' && token !== '--yes');
1032
- const confirmed = tokens.includes('--yes');
1033
- if (!ref) {
1034
- console.log(ERROR('Usage: /checkpoint restore <turn-id|prefix> [--yes]'));
1035
- return { success: false };
1036
- }
1037
- const { checkpoint, ambiguous } = findCheckpointByRef(ctx, ref);
1038
- if (!checkpoint) {
1039
- console.log(ERROR(ambiguous ? `Checkpoint prefix is ambiguous: ${ref}` : `Checkpoint not found: ${ref}`));
1040
- console.log(DIM('Run /checkpoint to list available checkpoint ids.'));
1041
- return { success: false };
1042
- }
1043
- if (!confirmed) {
1044
- console.log(HEADER(`Checkpoint ${checkpoint.turnId}`));
1045
- console.log(DIM(`${formatDateTime(checkpoint.createdAt)} ${checkpoint.files.length} file(s)`));
1046
- for (const file of checkpoint.files.slice(0, 20)) {
1047
- console.log(` ${file.path} ${DIM((0, format_1.formatBytes)(file.sizeBytes))}`);
1048
- }
1049
- console.log();
1050
- console.log(WARN(`This will overwrite current files from checkpoint ${checkpoint.turnId}.`));
1051
- console.log(DIM(`Run /checkpoint restore ${checkpoint.turnId} --yes to restore.`));
1052
- return { success: true };
1053
- }
1054
- const result = (0, checkpoint_1.restoreCheckpoint)(ctx.cwd, checkpoint.turnId);
1055
- if (result.error) {
1056
- console.log(ERROR(result.error));
1057
- return { success: false, error: result.error };
1058
- }
1059
- console.log(SUCCESS(`Restored ${result.restored.length} file(s) from checkpoint ${checkpoint.turnId}.`));
1060
- for (const file of result.restored.slice(0, 20)) {
1061
- console.log(` ${file}`);
1062
- }
1063
- return { success: true, output: result.restored.join('\n') };
1064
- }
1065
- function snapshotCurrentModel(ctx) {
1066
- return ctx.store.getSnapshot().currentModel || ctx.config.model;
1067
- }
1068
- function getCommandAutoCompact(ctx, modelId) {
1069
- if (ctx.compactCoordinator) {
1070
- ctx.compactCoordinator.configure({
1071
- modelId,
1072
- llm: ctx.llm,
1073
- outputReserveTokens: ctx.llm?.getMaxTokens?.(),
1074
- });
1075
- return ctx.compactCoordinator.getAutomatic();
1076
- }
1077
- return (0, auto_compact_1.getAutoCompact)({ modelId });
1078
- }
1079
- function showAgents(ctx) {
1080
- console.log();
1081
- console.log(HEADER('Registered Agents'));
1082
- console.log(DIM('─'.repeat(40)));
1083
- for (const agent of ctx.runtime.agents) {
1084
- const status = agent.getStatus();
1085
- const statusColor = status.status === 'idle' ? SUCCESS : WARN;
1086
- console.log();
1087
- console.log(` ${ACCENT(status.name)} ${DIM(`(${status.id})`)}`);
1088
- console.log(` Status: ${statusColor(status.status)}`);
1089
- console.log(` Capabilities: ${status.capabilities.join(', ')}`);
1090
- }
1091
- console.log();
1092
- return { success: true };
1093
- }
1094
- function showMemory(ctx) {
1095
- console.log();
1096
- console.log(HEADER('Memory Status'));
1097
- console.log(DIM('─'.repeat(40)));
1098
- const memStatus = ctx.runtime.memory.getStatus();
1099
- const storeStats = ctx.runtime.store.getStats();
1100
- console.log();
1101
- console.log(HEADER(' Inline MemorySystem:'));
1102
- console.log(` Working ${memStatus.working} / ${ctx.runtime.config.memory.workingCapacity}`);
1103
- console.log(` Short-term ${memStatus['short-term']} / ${ctx.runtime.config.memory.shortTermCapacity}`);
1104
- console.log(` Long-term ${memStatus['long-term']} entries`);
1105
- console.log();
1106
- console.log(HEADER(' Modular MemoryStore:'));
1107
- console.log(` Working ${storeStats.working}`);
1108
- console.log(` Short-term ${storeStats['short-term']}`);
1109
- console.log(` Long-term ${storeStats['long-term']} entries`);
1110
- console.log();
1111
- return { success: true };
1112
- }
1113
- async function handleMemoryReindex(_ctx) {
1114
- const { isSemanticEnabled, getSemanticSearchService } = require('../memory/semantic-search');
1115
- if (!isSemanticEnabled()) {
1116
- console.log();
1117
- console.log(WARN('⚠ Semantic search is not enabled.'));
1118
- console.log(DIM(' Set ORION_CODE_EMBEDDING_PROVIDER=ollama or openai to enable.'));
1119
- console.log();
1120
- return { success: false };
1121
- }
1122
- console.log();
1123
- console.log(HEADER('Reindexing project memories...'));
1124
- try {
1125
- const service = getSemanticSearchService();
1126
- const count = await service.indexExistingMemories(process.cwd());
1127
- console.log(SUCCESS(`✔ Indexed ${count} memories`));
1128
- }
1129
- catch (err) {
1130
- console.log(ERROR(`✗ Reindex failed: ${err.message}`));
1131
- return { success: false };
1132
- }
1133
- console.log();
1134
- return { success: true };
1135
- }
1136
- async function handleMemory(ctx, args) {
1137
- const sub = args.trim().toLowerCase();
1138
- if (sub === 'reindex') {
1139
- return handleMemoryReindex(ctx);
1140
- }
1141
- return showMemory(ctx);
1142
- }
1143
- function showSafety(ctx) {
1144
- console.log();
1145
- console.log(HEADER('Safety Checker'));
1146
- console.log(DIM('─'.repeat(40)));
1147
- const policy = ctx.runtime.safety.getPolicy();
1148
- const summary = ctx.runtime.safety.getAuditSummary();
1149
- console.log();
1150
- console.log(` Enabled ${policy.enabled ? SUCCESS('yes') : ERROR('no')}`);
1151
- console.log(` Sandbox ${policy.sandboxMode ? WARN('on') : DIM('off')}`);
1152
- console.log();
1153
- console.log(` Blocked patterns:`);
1154
- for (const pattern of policy.blocked) {
1155
- console.log(` ${ERROR('✗')} ${DIM(pattern)}`);
1156
- }
1157
- console.log();
1158
- console.log(` Dangerous patterns:`);
1159
- for (const pattern of policy.dangerousPatterns) {
1160
- console.log(` ${WARN('⚠')} ${DIM(pattern)}`);
1161
- }
1162
- console.log();
1163
- console.log(` Audit summary: ${summary.total} checks | ${SUCCESS(`${summary.passed} passed`)} | ${ERROR(`${summary.blocked} blocked`)}`);
1164
- console.log();
1165
- return { success: true };
1166
- }
1167
- function showHarness(ctx, args = '') {
1168
- const explain = args.trim().toLowerCase() === 'explain';
1169
- console.log();
1170
- console.log(HEADER(explain ? 'Harness Explain' : 'Harness'));
1171
- console.log(DIM('─'.repeat(40)));
1172
- const cfg = ctx.runtime.harness.getConfig();
1173
- console.log();
1174
- if (!explain) {
1175
- console.log(` Max steps ${cfg.maxSteps}`);
1176
- console.log(` Boundary check ${cfg.boundaryCheck ? SUCCESS('on') : ERROR('off')}`);
1177
- console.log(` Goal constraint ${cfg.goalConstraint ? SUCCESS('on') : ERROR('off')}`);
1178
- console.log(` Result validate ${cfg.resultValidation ? SUCCESS('on') : ERROR('off')}`);
1179
- console.log(` Sandbox ${cfg.sandbox ? WARN('on') : DIM('off')}`);
1180
- console.log(` Timeout ${cfg.timeout}ms`);
1181
- console.log(` Blocked actions ${DIM(cfg.blockedActions.join(', ') || 'none')}`);
1182
- }
1183
- const state = ctx.store.getSnapshot().harnessState;
1184
- if (!state) {
1185
- console.log();
1186
- console.log(DIM(' No Context Harness state for this session yet.'));
1187
- console.log();
1188
- return { success: true };
1189
- }
1190
- if (explain) {
1191
- // Build explain output from harnessState in store
1192
- const contract = state.contract;
1193
- // Contract section
1194
- console.log(HEADER(' Contract'));
1195
- if (contract) {
1196
- console.log(` Objective ${ACCENT(contract.objective || '(none)')}`);
1197
- if (contract.requirements?.length) {
1198
- console.log(` Requires ${DIM(contract.requirements.slice(0, 3).join(' | '))}`);
1199
- }
1200
- if (contract.prohibitions?.length) {
1201
- console.log(` Prohibits ${WARN(contract.prohibitions.slice(0, 3).join(' | '))}`);
1202
- }
1203
- if (contract.successCriteria?.length) {
1204
- console.log(` Success ${DIM(contract.successCriteria.slice(0, 3).join(' | '))}`);
1205
- }
1206
- }
1207
- else {
1208
- console.log(DIM(' (no contract established)'));
1209
- }
1210
- console.log();
1211
- // Context source
1212
- console.log(HEADER(' Context Source'));
1213
- const session = ctx.getSession?.() ?? (ctx.sessionId ? (0, session_storage_1.loadSessionMeta)(ctx.sessionId) : null);
1214
- const isRestored = session?.transcriptDisplayStartTime != null;
1215
- const isCompactActive = Boolean(state.promptAssemblyStats);
1216
- console.log(` Root ${ACCENT(state.rootObjective || contract?.objective || '(none)')}`);
1217
- console.log(` Active ${DIM(state.activeInstruction || contract?.userIntent || '(none)')}`);
1218
- console.log(` Source ${isRestored ? WARN('restored session') : DIM('live turn')}`);
1219
- if (isRestored && session) {
1220
- const restoredTime = session.transcriptDisplayStartTime
1221
- ? new Date(session.transcriptDisplayStartTime).toLocaleString()
1222
- : 'unknown';
1223
- console.log(` Restored ${DIM(restoredTime)}`);
1224
- }
1225
- if (isCompactActive) {
1226
- console.log(` Compact ${SUCCESS('active')}`);
1227
- }
1228
- console.log();
1229
- // Evidence index summary
1230
- console.log(HEADER(' Evidence Index'));
1231
- const evidenceItems = state.evidenceIndex?.length ?? 0;
1232
- const evidenceKinds = new Map();
1233
- if (state.evidenceIndex) {
1234
- for (const item of state.evidenceIndex) {
1235
- const kind = item.kind || 'unknown';
1236
- evidenceKinds.set(kind, (evidenceKinds.get(kind) || 0) + 1);
1237
- }
1238
- }
1239
- console.log(` Total ${ACCENT(String(evidenceItems))} items`);
1240
- if (evidenceKinds.size > 0) {
1241
- const kinds = Array.from(evidenceKinds.entries())
1242
- .sort((a, b) => b[1] - a[1])
1243
- .slice(0, 10);
1244
- for (const [kind, count] of kinds) {
1245
- console.log(` ${DIM(kind.padEnd(16))} ${count}`);
1246
- }
1247
- }
1248
- else {
1249
- console.log(DIM(' (no evidence records yet)'));
1250
- }
1251
- console.log();
1252
- // Intent history
1253
- console.log(HEADER(' Recent Intents'));
1254
- const intents = state.intentHistory?.slice(-5) ?? [];
1255
- if (intents.length > 0) {
1256
- for (const intent of intents) {
1257
- const conf = intent.confidence != null ? ` (${Math.round(intent.confidence * 100)}%)` : '';
1258
- console.log(` ${ACCENT(intent.kind)}${DIM(conf)} ${DIM(intent.summary?.slice(0, 50) || '')}`);
1259
- }
1260
- }
1261
- else {
1262
- console.log(DIM(' (no intents recorded)'));
1263
- }
1264
- console.log();
1265
- // Capsule snapshot
1266
- console.log(HEADER(' Capsule'));
1267
- const capsule = state.capsule;
1268
- if (capsule) {
1269
- console.log(` Next ${DIM(capsule.nextAction)}`);
1270
- if (capsule.completed?.length) {
1271
- console.log(` Done ${SUCCESS(`${capsule.completed.length} steps`)}`);
1272
- }
1273
- if (capsule.openTodos?.length) {
1274
- console.log(` Open ${WARN(`${capsule.openTodos.length} todos`)}`);
1275
- }
1276
- if (capsule.changedFiles?.length) {
1277
- console.log(` Files ${DIM(capsule.changedFiles.slice(0, 5).join(', '))}`);
1278
- }
1279
- const passed = capsule.verification?.passed?.length ?? 0;
1280
- const failed = capsule.verification?.failed?.length ?? 0;
1281
- console.log(` Verify ${SUCCESS(`${passed} passed`)} / ${failed > 0 ? ERROR(`${failed} failed`) : DIM('0 failed')}`);
1282
- }
1283
- else {
1284
- console.log(DIM(' (no capsule yet)'));
1285
- }
1286
- console.log();
1287
- // Prompt assembly stats
1288
- const stats = state.promptAssemblyStats;
1289
- console.log(HEADER(' Prompt Assembly'));
1290
- if (stats) {
1291
- console.log(` Model ${ACCENT(stats.modelId)}`);
1292
- console.log(` Budget ${DIM(`${stats.estimatedTokens}/${stats.budgetTokens} tokens`)}`);
1293
- console.log(` Sections ${DIM(stats.sections.join(', ') || 'none')}`);
1294
- console.log(` Ledger ${DIM(`${state.ledger?.length ?? 0} entries`)}`);
1295
- console.log(` Evidence ${DIM(`${state.evidenceIndex?.length ?? 0} records`)}`);
1296
- console.log(` Turns ${DIM(`${state.turnSummaries?.length ?? 0} summaries`)}`);
1297
- console.log();
1298
- console.log(HEADER(' Included Evidence'));
1299
- for (const item of stats.includedEvidence.slice(0, 10)) {
1300
- console.log(` ${ACCENT(item.id)} ${DIM(`[${item.kind}] score=${item.score} tokens=${item.tokens}`)}`);
1301
- console.log(` ${DIM(item.reason)}`);
1302
- }
1303
- if (stats.includedEvidence.length === 0) {
1304
- console.log(DIM(' none'));
1305
- }
1306
- if (stats.omittedEvidence.length > 0) {
1307
- console.log();
1308
- console.log(HEADER(' Omitted Evidence'));
1309
- for (const item of stats.omittedEvidence.slice(0, 8)) {
1310
- console.log(` ${DIM(item.id)} ${DIM(`[${item.kind}] score=${item.score} tokens=${item.tokens}`)}`);
1311
- console.log(` ${DIM(item.reason)}`);
1312
- }
1313
- }
1314
- }
1315
- else {
1316
- console.log(DIM(' No prompt assembly stats recorded yet. Run a chat turn first.'));
1317
- }
1318
- console.log();
1319
- console.log(HEADER(' Auto Compact'));
1320
- const compactStats = getCommandAutoCompact(ctx, state.promptAssemblyStats?.modelId ?? snapshotCurrentModel(ctx)).getStats();
1321
- const contextInfo = (0, model_context_1.resolveModelContext)(compactStats.modelId);
1322
- console.log(` Model ${ACCENT(compactStats.modelId)}`);
1323
- console.log(` Window ${DIM(`${formatTokenCount(contextInfo.contextWindow)} tokens (${contextInfo.source}${contextInfo.source === 'fuzzy' ? `:${contextInfo.matchedId}` : ''})`)}`);
1324
- console.log(` Thresholds ${DIM(`predict ${formatThreshold(compactStats.predictiveCompactThreshold)}, hard ${formatThreshold(compactStats.threshold)}, prewarm ${formatThreshold(compactStats.preCompactThreshold)}`)}`);
1325
- console.log(` Usage ${DIM(`${compactStats.lastTokenCount} tokens, ${compactStats.ctxPercent}%`)}`);
1326
- console.log(` Armed ${compactStats.preCompactArmed ? SUCCESS('yes') : DIM('no')}`);
1327
- console.log(` Last mode ${DIM(compactStats.lastCompactMode ?? 'none')}`);
1328
- console.log();
1329
- return { success: true };
1330
- }
1331
- console.log();
1332
- console.log(HEADER(' Context State'));
1333
- console.log(` Version ${ACCENT(String(state.version ?? 1))}`);
1334
- console.log(` Epoch ${ACCENT(String(state.taskEpoch ?? 1))}`);
1335
- console.log(` Objective ${ACCENT(state.rootObjective ?? state.contract?.objective ?? '(none)')}`);
1336
- console.log(` Active ${DIM(state.activeInstruction ?? state.contract?.userIntent ?? '(none)')}`);
1337
- console.log(` Ledger ${DIM(`${state.ledger.length} entries`)}`);
1338
- console.log(` Evidence ${DIM(`${state.evidenceIndex?.length ?? 0} records`)}`);
1339
- console.log(` Turns ${DIM(`${state.turnSummaries?.length ?? 0} summaries`)}`);
1340
- if (state.activeConstraints && state.activeConstraints.length > 0) {
1341
- console.log(` Constraints ${DIM(state.activeConstraints.slice(0, 3).join(' | '))}`);
1342
- }
1343
- if (state.capsule) {
1344
- console.log(` Next ${DIM(state.capsule.nextAction)}`);
1345
- const passed = state.capsule.verification.passed.length;
1346
- const failed = state.capsule.verification.failed.length;
1347
- console.log(` Verify ${SUCCESS(`${passed} passed`)} / ${failed > 0 ? ERROR(`${failed} failed`) : DIM('0 failed')}`);
1348
- }
1349
- if (state.diagnostics && state.diagnostics.length > 0) {
1350
- console.log(` Diagnostics ${WARN(state.diagnostics.slice(-2).join(' | '))}`);
1351
- }
1352
- console.log();
1353
- return { success: true };
1354
- }
1355
- function showConfig(ctx) {
1356
- console.log();
1357
- console.log(HEADER('Configuration'));
1358
- console.log(DIM('─'.repeat(40)));
1359
- const allowlist = (0, tool_allowlist_1.resolveProjectToolAllowlist)(ctx.cwd);
1360
- const allowlistSummary = allowlist.rules.length === 0 && allowlist.invalid.length === 0
1361
- ? '(none)'
1362
- : `${allowlist.rules.length} rule(s)` +
1363
- (allowlist.invalid.length > 0 ? `, ${allowlist.invalid.length} invalid (ignored)` : '');
1364
- const summary = {
1365
- name: ctx.config.name,
1366
- model: ctx.config.model,
1367
- apiBaseUrl: ctx.config.apiBaseUrl || '(default OpenAI)',
1368
- apiKey: (0, mask_1.maskSecret)(ctx.config.apiKey),
1369
- mode: ctx.config.mode,
1370
- logLevel: ctx.config.logLevel,
1371
- toolConfirmation: ctx.config.toolConfirmation,
1372
- allowedTools: allowlistSummary,
1373
- };
1374
- const llmSummary = ctx.llm?.getConfigSummary() ?? {};
1375
- for (const [key, val] of Object.entries(summary)) {
1376
- console.log(` ${ACCENT(key.padEnd(16))} ${DIM(val)}`);
1377
- }
1378
- if (allowlist.rules.length > 0 || allowlist.invalid.length > 0) {
1379
- console.log();
1380
- console.log(HEADER(' Project allowedTools:'));
1381
- for (const rule of allowlist.rules) {
1382
- console.log(` ${ACCENT(rule.effect.padEnd(6))} ${DIM(rule.tool)}${DIM(rule.pattern ? `(${rule.pattern})` : '')}`);
1383
- }
1384
- for (const entry of allowlist.invalid) {
1385
- console.log(` ${WARN('invalid')} ${DIM(entry)}`);
1386
- }
1387
- }
1388
- console.log();
1389
- console.log(HEADER(' LLM Settings:'));
1390
- for (const [key, val] of Object.entries(llmSummary)) {
1391
- console.log(` ${ACCENT(key.padEnd(16))} ${DIM(val)}`);
1392
- }
1393
- console.log();
1394
- return { success: true };
1395
- }
1396
- function handleModel(ctx, args) {
1397
- const trimmedArgs = args.trim().toLowerCase();
1398
- // 显示当前模型
1399
- if (!args || trimmedArgs === '?' || trimmedArgs === 'info') {
1400
- console.log();
1401
- if (ctx.llm) {
1402
- const currentModel = ctx.store.getSnapshot().currentModel || ctx.llm.getModel();
1403
- const profile = getProfileByModelId(ctx.config.modelRegistry, currentModel);
1404
- const aliasEntry = (0, model_catalog_1.getModelCatalogEntry)(currentModel);
1405
- const contextInfo = profile
1406
- ? {
1407
- id: profile.model,
1408
- label: profile.displayName || profile.id,
1409
- contextWindow: profile.resolvedContextWindow,
1410
- maxOutputTokens: profile.resolvedMaxOutputTokens,
1411
- source: 'config',
1412
- matchedId: profile.model,
1413
- }
1414
- : (0, model_context_1.resolveModelContext)(currentModel);
1415
- const compactStats = getCommandAutoCompact(ctx, currentModel).getStats();
1416
- console.log(HEADER('Current Model'));
1417
- console.log(DIM('─'.repeat(40)));
1418
- console.log(` Model ${BRAND(currentModel)}`);
1419
- if (profile) {
1420
- console.log(` Alias ${ACCENT(profile.aliases?.[0] ? `(${profile.aliases[0]})` : 'none')}`);
1421
- const provider = ctx.config.modelRegistry?.providers.get(profile.provider);
1422
- console.log(` Provider ${DIM(provider?.displayName || profile.provider)}`);
1423
- }
1424
- else if (aliasEntry) {
1425
- console.log(` Alias ${ACCENT(aliasEntry.alias)}`);
1426
- console.log(` Provider ${DIM(aliasEntry.provider)}`);
1427
- }
1428
- console.log(` Context ${DIM(`${formatTokenCount(contextInfo.contextWindow)} tokens`)}`);
1429
- if (contextInfo.maxOutputTokens) {
1430
- console.log(` Output ${DIM(`${formatTokenCount(contextInfo.maxOutputTokens)} tokens`)}`);
1431
- }
1432
- console.log(` Source ${DIM(`${contextInfo.source}${contextInfo.source === 'fuzzy' ? `:${contextInfo.matchedId}` : ''}`)}`);
1433
- console.log(` Compact ${compactStats.enabled ? SUCCESS('auto') : WARN('off')} ${DIM(`predict ${formatThreshold(compactStats.predictiveCompactThreshold)}, hard ${formatThreshold(compactStats.threshold)}`)}`);
1434
- }
1435
- else {
1436
- console.log(ERROR('LLM not initialized. Set ORION_CODE_API_KEY first.'));
1437
- }
1438
- console.log();
1439
- return { success: true };
1440
- }
1441
- // /model list|ls|help 已移除,统一由 /models 承接(交互式选择切换)
1442
- if (trimmedArgs === 'list' || trimmedArgs === 'ls' || trimmedArgs === 'help') {
1443
- console.log();
1444
- console.log(WARN(`/model ${trimmedArgs} was removed.`));
1445
- console.log(DIM('Use /models to switch models interactively,'));
1446
- console.log(DIM('or /model <name|alias> to switch directly, e.g. /model sonnet'));
1447
- console.log();
1448
- return { success: true };
1449
- }
1450
- // 设置模型
1451
- if (!ctx.llm) {
1452
- console.log(ERROR('LLM not initialized. Set ORION_CODE_API_KEY first.'));
1453
- console.log();
1454
- return { success: false };
1455
- }
1456
- // 解析别名
1457
- const registryProfile = resolveModelFromRegistry(ctx.config, args);
1458
- const resolvedModel = registryProfile ? registryProfile.model : (0, model_catalog_1.resolveModelAlias)(args);
1459
- const resolvedProfileId = registryProfile ? registryProfile.id : resolvedModel;
1460
- ctx.llm.setModel(resolvedModel);
1461
- getCommandAutoCompact(ctx, resolvedModel);
1462
- ctx.store.setState({ currentModel: resolvedProfileId });
1463
- console.log(SUCCESS(`✔ Model changed to ${BRAND(resolvedProfileId)}`));
1464
- const contextInfo = registryProfile
1465
- ? {
1466
- contextWindow: registryProfile.resolvedContextWindow,
1467
- maxOutputTokens: registryProfile.resolvedMaxOutputTokens,
1468
- source: 'resolved',
1469
- }
1470
- : (0, model_context_1.resolveModelContext)(resolvedModel);
1471
- console.log(DIM(` Context window ${formatTokenCount(contextInfo.contextWindow)} tokens (${contextInfo.source})`));
1472
- console.log();
1473
- return { success: true };
1474
- }
1475
- /**
1476
- * /models — 交互式选择切换模型。
1477
- * 交互式渲染器返回结构化 modelPicker 请求(渲染器弹出选择层,选中即 /model <id>);
1478
- * 非交互式渲染器直接打印候选列表并提示 /model <name|alias>。
1479
- */
1480
- function handleModels(ctx, _args) {
1481
- console.log();
1482
- const currentModel = ctx.store.getSnapshot().currentModel || ctx.llm?.getModel() || '';
1483
- const configuredModels = listConfiguredModelCatalogEntries(ctx.config.modelRegistry);
1484
- const candidates = configuredModels.length > 0
1485
- ? configuredModels
1486
- : (0, model_catalog_1.listModelCatalogEntries)().map(model => {
1487
- const contextInfo = (0, model_context_1.resolveModelContext)(model.name);
1488
- return {
1489
- name: model.name,
1490
- alias: model.alias,
1491
- provider: model.provider,
1492
- contextWindow: contextInfo.contextWindow,
1493
- maxOutputTokens: contextInfo.maxOutputTokens,
1494
- source: contextInfo.source,
1495
- };
1496
- });
1497
- const ui = commandUICapabilities(ctx);
1498
- if (ui.structuredPickers) {
1499
- return {
1500
- success: true,
1501
- modelPicker: {
1502
- models: candidates,
1503
- currentModel,
1504
- title: 'Switch Model',
1505
- maxVisibleItems: 12,
1506
- },
1507
- };
1508
- }
1509
- // 非交互式渲染器:打印候选列表
1510
- console.log(HEADER('Available Models'));
1511
- console.log(DIM('─'.repeat(40)));
1512
- const modelPicker = (0, ui_view_model_1.createModelPickerState)({ currentModel, models: candidates });
1513
- for (const item of modelPicker.visibleItems) {
1514
- const marker = item.isCurrent ? SUCCESS('●') : DIM('○');
1515
- const alias = item.alias ? `(${item.alias})` : '';
1516
- const context = `${formatTokenCount(item.contextWindow ?? 0)} ctx`;
1517
- const current = item.isCurrent ? BRAND('(current)') : '';
1518
- console.log(` ${marker} ${ACCENT(item.name)} ${DIM(alias)} ${DIM(context)} ${current}`);
1519
- console.log(` ${DIM(item.provider ?? 'unknown')}`);
1520
- }
1521
- console.log();
1522
- console.log(DIM('Use /model <name|alias> to switch, e.g. /model sonnet'));
1523
- console.log();
1524
- return { success: true };
1525
- }
1526
- function normalizePermissionMode(raw) {
1527
- const value = raw.trim().toLowerCase();
1528
- if (!value)
1529
- return null;
1530
- if (value === 'accept' ||
1531
- value === 'acceptedits' ||
1532
- value === 'accept-edits' ||
1533
- value === 'edit') {
1534
- return 'acceptEdits';
1535
- }
1536
- if (value === 'default' || value === 'ask')
1537
- return 'default';
1538
- if (value === 'plan' || value === 'readonly' || value === 'read-only')
1539
- return 'plan';
1540
- if (value === 'auto' || value === 'full-auto')
1541
- return 'auto';
1542
- return null;
1543
- }
1544
- function handleMode(ctx, args) {
1545
- const current = ctx.store.getSnapshot().permissionMode;
1546
- const trimmed = args.trim();
1547
- if (!trimmed || trimmed === '?' || trimmed === 'help') {
1548
- console.log();
1549
- console.log(HEADER('Permission Mode'));
1550
- console.log(DIM('─'.repeat(40)));
1551
- console.log(` Current ${ACCENT(current)} ${DIM((0, types_1.getModeDisplayText)(current) || 'ask before sensitive actions')}`);
1552
- console.log();
1553
- console.log(` ${ACCENT('/mode next')} Cycle to the next mode`);
1554
- console.log(` ${ACCENT('/mode default')} Ask before sensitive actions`);
1555
- console.log(` ${ACCENT('/mode accept-edits')} Auto-accept file edits`);
1556
- console.log(` ${ACCENT('/mode plan')} Plan first, avoid executing edits`);
1557
- console.log(` ${ACCENT('/mode auto')} Auto-run allowed actions`);
1558
- console.log();
1559
- return { success: true };
1560
- }
1561
- const next = trimmed === 'next' ? (0, types_1.getNextPermissionMode)(current) : normalizePermissionMode(trimmed);
1562
- if (!next || !types_1.PERMISSION_MODES.includes(next)) {
1563
- return {
1564
- success: false,
1565
- error: `Unknown mode: ${trimmed}. Use one of: default, accept-edits, plan, auto, next.`,
1566
- };
1567
- }
1568
- ctx.store.setPermissionMode(next);
1569
- const display = (0, types_1.getModeDisplayText)(next);
1570
- return {
1571
- success: true,
1572
- output: `Mode changed to ${next}${display ? ` (${display})` : ''}.`,
1573
- };
1574
- }
1575
- function handleTask(ctx, args) {
1576
- const [sub] = args.trim().split(/\s+/);
1577
- if (sub === 'list' || sub === 'ls') {
1578
- if (!taskManager) {
1579
- taskManager = new task_manager_1.TaskManager();
1580
- }
1581
- console.log();
1582
- console.log(HEADER('Task List'));
1583
- console.log(DIM('─'.repeat(40)));
1584
- const stats = taskManager.getStats();
1585
- console.log(` Total ${stats.total}`);
1586
- console.log(` Pending ${stats.pending}`);
1587
- console.log(` Running ${stats.running}`);
1588
- console.log(` Completed ${SUCCESS(stats.completed)}`);
1589
- console.log(` Failed ${ERROR(stats.failed)}`);
1590
- console.log(` Cancelled ${DIM(stats.cancelled)}`);
1591
- const tasks = taskManager.list();
1592
- if (tasks.length > 0) {
1593
- console.log();
1594
- for (const t of tasks) {
1595
- const statusIcon = t.status === 'completed'
1596
- ? SUCCESS('✓')
1597
- : t.status === 'failed'
1598
- ? ERROR('✗')
1599
- : t.status === 'running'
1600
- ? WARN('◌')
1601
- : t.status === 'cancelled'
1602
- ? DIM('⊘')
1603
- : DIM('○');
1604
- console.log(` ${statusIcon} ${ACCENT(t.name)} ${DIM(`(${t.id.slice(0, 8)})`)}`);
1605
- console.log(` ${DIM(`[${t.priority}]`)} ${t.description.slice(0, 60)}`);
1606
- }
1607
- }
1608
- console.log();
1609
- return { success: true };
1610
- }
1611
- // 默认行为: 作为任务名提交
1612
- const taskName = args.trim() || 'demo-task';
1613
- const task = {
1614
- id: `cli-${Date.now()}`,
1615
- name: taskName,
1616
- description: `Task submitted from CLI: ${taskName}`,
1617
- priority: 'P1',
1618
- assignedTo: 'leader',
1619
- status: 'pending',
1620
- };
1621
- console.log();
1622
- ctx.runtime.brain.submitTask(task);
1623
- console.log(SUCCESS(`✔ Task "${taskName}" submitted`));
1624
- console.log();
1625
- return { success: true };
1626
- }
1627
- async function handleRun(ctx, args) {
1628
- if (!args.trim()) {
1629
- console.log(ERROR('Usage: /run <task description>'));
1630
- console.log(DIM(' Creates a task and executes it through the Agent + LLM pipeline.'));
1631
- console.log();
1632
- return { success: false };
1633
- }
1634
- if (!ctx.llm || !(0, config_1.isConfigured)(ctx.config)) {
1635
- console.log(WARN('⚠ LLM not configured. Set ORION_CODE_API_KEY in .env to enable run mode.'));
1636
- console.log();
1637
- return { success: false };
1638
- }
1639
- if (!taskManager) {
1640
- taskManager = new task_manager_1.TaskManager();
1641
- }
1642
- const taskOptions = {
1643
- name: args.slice(0, 80),
1644
- description: args,
1645
- priority: 'P1',
1646
- assignedTo: 'leader',
1647
- tags: ['cli', 'interactive'],
1648
- };
1649
- const record = taskManager.create(taskOptions);
1650
- console.log();
1651
- console.log(SUCCESS(`✔ Task created: ${ACCENT(record.name)}`));
1652
- console.log(DIM(` ID: ${record.id} | Tags: ${record.tags.join(', ')}`));
1653
- taskManager.start(record.id);
1654
- console.log(WARN('◌ Running task through Agent + LLM...'));
1655
- try {
1656
- const agent = ctx.runtime.agents[0];
1657
- if (!agent) {
1658
- throw new Error('No agents registered');
1659
- }
1660
- const runner = new agent_runner_1.AgentRunner(agent, ctx.llm);
1661
- const task = taskManager.toTask(record);
1662
- const result = await runner.run(task);
1663
- if (result.success) {
1664
- taskManager.complete(record.id, result);
1665
- console.log(SUCCESS(`✓ Task completed in ${result.duration}ms`));
1666
- if (result.tokenUsage) {
1667
- console.log(DIM(` Tokens: ${result.tokenUsage.promptTokens} in / ${result.tokenUsage.completionTokens} out`));
1668
- }
1669
- if (result.data?.summary) {
1670
- console.log();
1671
- console.log(ACCENT(' Summary:'));
1672
- console.log(` ${result.data.summary}`);
1673
- }
1674
- }
1675
- else {
1676
- taskManager.fail(record.id, result.error, result);
1677
- console.log(ERROR(`✗ Task failed: ${result.error}`));
1678
- }
1679
- }
1680
- catch (error) {
1681
- taskManager.fail(record.id, error.message);
1682
- console.log(ERROR(`✗ Task error: ${error.message}`));
1683
- }
1684
- console.log();
1685
- return { success: true };
1686
- }
1687
- async function handleChat(ctx, input) {
1688
- const ui = commandUICapabilities(ctx);
1689
- const writeOutput = ctx.writeOutput ?? ((text) => process.stdout.write(text));
1690
- const writeLine = ctx.writeLine ?? ((text = '') => console.log(text));
1691
- if (!input) {
1692
- console.log(ERROR('Usage: /chat <message>'));
1693
- console.log();
1694
- return { success: false };
1695
- }
1696
- if (!ctx.llm || !(0, config_1.isConfigured)(ctx.config)) {
1697
- console.log(WARN('⚠ LLM not configured. Set ORION_CODE_API_KEY in .env to enable chat.'));
1698
- console.log();
1699
- return { success: false };
1700
- }
1701
- const activeSession = ctx.getSession?.() ??
1702
- ctx.ensureSession?.() ??
1703
- (ctx.sessionId ? (0, session_storage_1.loadSessionMeta)(ctx.sessionId) : null);
1704
- const sessionId = activeSession?.id ?? ctx.sessionId;
1705
- const runtimeTools = (0, tools_1.getRuntimeTools)();
1706
- const skillResolution = (0, skills_1.resolveSkillsForTurn)({
1707
- cwd: ctx.cwd,
1708
- input,
1709
- tools: runtimeTools,
1710
- projectPath: activeSession?.projectPath,
1711
- sessionId,
1712
- });
1713
- const appliedSkillNames = skillResolution.skills.map(skill => skill.name);
1714
- // Record user message to session
1715
- if (sessionId) {
1716
- (0, session_storage_1.appendSessionMessage)(sessionId, {
1717
- role: 'user',
1718
- content: input,
1719
- timestamp: Date.now(),
1720
- appliedSkills: appliedSkillNames.length > 0 ? appliedSkillNames : undefined,
1721
- });
1722
- }
1723
- ctx.store.addMessage({ role: 'user', content: input });
1724
- (0, prompt_context_1.refreshProjectInstructions)(ctx.store, ctx.cwd);
1725
- const snapshot = ctx.store.getSnapshot();
1726
- const harness = (0, harness_1.createContextHarness)({
1727
- cwd: ctx.cwd,
1728
- modelId: ctx.llm.getModel(),
1729
- state: snapshot.harnessState,
1730
- config: {
1731
- enabled: true,
1732
- driftGuard: 'warn',
1733
- completionGate: true,
1734
- },
1735
- });
1736
- const intent = harness.updateContractFromUserInput(input);
1737
- harness.recordAppliedSkills(skillResolution.skills);
1738
- const promptCtx = {
1739
- cwd: ctx.cwd,
1740
- platform: process.platform,
1741
- nodeVersion: process.version,
1742
- tools: skillResolution.tools,
1743
- memoryContent: snapshot.memoryContent,
1744
- skillsContent: snapshot.skillsContent,
1745
- projectInstructionsContent: snapshot.projectInstructionsContent,
1746
- activeSkillsContent: skillResolution.promptInjection,
1747
- referencedFilesContent: (0, file_context_1.buildReferencedFilesPrompt)(input, ctx.cwd),
1748
- };
1749
- const systemPrompt = (0, framework_1.getSystemPrompt)(promptCtx);
1750
- const spinner = (0, box_1.createSpinner)();
1751
- const useSpinner = !ui.inlineProgress;
1752
- if (useSpinner) {
1753
- spinner.start('Thinking');
1754
- }
1755
- let finalContent = '';
1756
- let finalModel = '';
1757
- let finalUsage;
1758
- let responseStarted = false;
1759
- const sessionMessagesToRecord = [];
1760
- // Issue #22: 批量工具调用进度显示
1761
- let toolCallCount = 0;
1762
- let lastProgressUpdate = 0;
1763
- // 流式 Markdown 渲染器
1764
- let streamRenderer = null;
1765
- // Issue #32 #3.2: toolExecutor 支持 abortSignal
1766
- const toolExecutor = async (name, args, abortSignal) => {
1767
- if (!skillResolution.tools.some(tool => tool.name === name)) {
1768
- return JSON.stringify({
1769
- success: false,
1770
- error: skillResolution.toolScopeActive
1771
- ? `Tool ${name} is not available for the active skill scope. Available tools: ${skillResolution.tools.map(tool => tool.name).join(', ') || 'none'}`
1772
- : `Tool ${name} is not available.`,
1773
- });
1774
- }
1775
- const result = await (0, tools_1.executeTool)(name, args, abortSignal, {
1776
- cwd: ctx.cwd,
1777
- config: {
1778
- name: ctx.config.name,
1779
- mode: ctx.config.mode,
1780
- },
1781
- sessionId,
1782
- turnId: ctx.turnId,
1783
- });
1784
- // 不在这里打印,让 tool_result 事件处理
1785
- return result;
1786
- };
1787
- const streamCallbacks = {
1788
- onChunk: (chunk) => {
1789
- if (ctx.abortSignal?.aborted) {
1790
- return;
1791
- }
1792
- if (!responseStarted) {
1793
- responseStarted = true;
1794
- spinner.stop();
1795
- // 打印换行,让流式输出在新行开始
1796
- writeLine();
1797
- // 初始化流式渲染器
1798
- streamRenderer = (0, stream_markdown_1.createStreamRenderer)();
1799
- }
1800
- // 使用流式渲染器处理 chunk
1801
- if (streamRenderer) {
1802
- const rendered = streamRenderer.feed(chunk);
1803
- if (rendered) {
1804
- writeOutput(rendered);
1805
- }
1806
- }
1807
- else {
1808
- writeOutput(chunk);
1809
- }
1810
- },
1811
- };
1812
- try {
1813
- const messages = [
1814
- { role: 'system', content: systemPrompt },
1815
- ...snapshot.conversationHistory,
1816
- ];
1817
- for await (const event of (0, framework_1.query)({
1818
- messages,
1819
- tools: skillResolution.tools,
1820
- toolExecutor,
1821
- llm: ctx.llm,
1822
- streamCallbacks,
1823
- costTracker: snapshot.costTracker,
1824
- permissionMode: snapshot.permissionMode,
1825
- toolConfirmation: ctx.config.toolConfirmation,
1826
- toolAllowlist: (0, tool_allowlist_1.resolveProjectToolAllowlist)(ctx.cwd).evaluator,
1827
- toolContext: {
1828
- cwd: ctx.cwd,
1829
- config: {
1830
- name: ctx.config.name,
1831
- mode: ctx.config.mode,
1832
- },
1833
- sessionId,
1834
- turnId: ctx.turnId,
1835
- },
1836
- abortSignal: ctx.abortSignal,
1837
- harness,
1838
- input,
1839
- loopBudget: (0, loop_budget_1.resolveRuntimeLoopBudget)(input, ctx.config, harness.toJSON()),
1840
- })) {
1841
- switch (event.type) {
1842
- case 'request_start':
1843
- // 停止 spinner,等待 LLM 响应
1844
- spinner.stop();
1845
- writeLine();
1846
- writeLine(DIM((0, agent_status_1.agentStepStatus)(event.turn)));
1847
- // 重置流式渲染器
1848
- streamRenderer = (0, stream_markdown_1.createStreamRenderer)();
1849
- // Issue #22: 重置工具调用计数器
1850
- toolCallCount = 0;
1851
- lastProgressUpdate = 0;
1852
- break;
1853
- case 'assistant_tool_calls':
1854
- if (event.toolCalls.length > 1) {
1855
- writeLine(DIM((0, agent_status_1.runningToolsStatus)(event.toolCalls.length)));
1856
- }
1857
- sessionMessagesToRecord.push({
1858
- role: 'assistant',
1859
- content: event.content || '',
1860
- timestamp: Date.now(),
1861
- tool_calls: event.toolCalls,
1862
- });
1863
- break;
1864
- case 'tool_call':
1865
- // Issue #22: 批量工具调用进度显示
1866
- toolCallCount++;
1867
- if (toolCallCount >= 3 && Date.now() - lastProgressUpdate > 1000) {
1868
- (0, progress_1.showToolProgress)(toolCallCount, event.name);
1869
- lastProgressUpdate = Date.now();
1870
- }
1871
- break;
1872
- case 'tool_result':
1873
- // Issue #22: 隐藏进度指示
1874
- (0, progress_1.hideProgress)();
1875
- // 显示工具结果后,准备下一轮(不启动 spinner)
1876
- writeLine(event.summary || (0, box_1.toolLine)(event.name, event.args, event.success, event.duration));
1877
- // 显示错误详情
1878
- if (!event.success && event.error) {
1879
- writeLine(ERROR(` Error: ${event.error}`));
1880
- }
1881
- // Debug: 显示接收到的参数
1882
- if (!event.success && Object.keys(event.args).length === 0) {
1883
- writeLine(WARN(` ⚠ Tool received empty arguments - LLM may not be providing parameters correctly`));
1884
- writeLine(DIM(` Try using /model qwen or /model gpt4o for better tool calling support`));
1885
- }
1886
- // Record tool result for session
1887
- sessionMessagesToRecord.push({
1888
- role: 'tool',
1889
- content: event.result,
1890
- modelVisibleContent: event.modelVisibleResult,
1891
- timestamp: Date.now(),
1892
- toolCallId: event.callId,
1893
- });
1894
- break;
1895
- case 'message':
1896
- if (event.content) {
1897
- sessionMessagesToRecord.push({
1898
- role: 'assistant',
1899
- content: event.content,
1900
- timestamp: Date.now(),
1901
- });
1902
- }
1903
- break;
1904
- case 'strategy_exhausted':
1905
- writeLine(WARN(`⚠ ${event.suggestion}`));
1906
- break;
1907
- case 'complete':
1908
- finalContent = event.content;
1909
- finalModel = event.model;
1910
- finalUsage = event.usage;
1911
- if (event.stats) {
1912
- ctx.store.setLastLoopStats(event.stats);
1913
- }
1914
- break;
1915
- }
1916
- }
1917
- // 刷新流式渲染器,输出剩余内容
1918
- if (streamRenderer) {
1919
- const remaining = streamRenderer.flush();
1920
- if (remaining) {
1921
- writeOutput(remaining);
1922
- }
1923
- streamRenderer = null;
1924
- }
1925
- const wasAborted = ctx.abortSignal?.aborted === true;
1926
- if (finalContent && !wasAborted) {
1927
- ctx.store.addMessage({ role: 'assistant', content: finalContent });
1928
- }
1929
- if (sessionId && sessionMessagesToRecord.length > 0 && !wasAborted) {
1930
- (0, session_storage_1.appendSessionMessages)(sessionId, sessionMessagesToRecord);
1931
- }
1932
- if (finalUsage && !wasAborted) {
1933
- ctx.store.setTokenUsage(finalUsage);
1934
- }
1935
- if (!wasAborted) {
1936
- harness.ingestTurn({
1937
- userInput: input,
1938
- assistantContent: finalContent,
1939
- sessionMessages: sessionMessagesToRecord,
1940
- intent,
1941
- });
1942
- const harnessState = harness.toJSON();
1943
- ctx.store.setState({ harnessState });
1944
- if (sessionId) {
1945
- (0, session_storage_1.updateSessionSkills)(sessionId, appliedSkillNames);
1946
- (0, session_storage_1.updateSessionHarnessState)(sessionId, harnessState);
1947
- const recordedMessages = (0, session_storage_1.readSessionMessages)(sessionId);
1948
- if (recordedMessages.length > 0) {
1949
- (0, session_storage_1.updateSessionSummary)(sessionId, recordedMessages);
1950
- }
1951
- }
1952
- }
1953
- if (responseStarted) {
1954
- writeLine();
1955
- if (ui.extraAssistantSpacing) {
1956
- writeLine();
1957
- }
1958
- }
1959
- if (!ui.suppressLegacyTokenMeta) {
1960
- const stats = [
1961
- finalUsage ? `tokens: ${finalUsage.promptTokens}+${finalUsage.completionTokens}` : '',
1962
- finalModel ? finalModel : '',
1963
- ]
1964
- .filter(Boolean)
1965
- .join(' ');
1966
- if (stats) {
1967
- writeLine(DIM(stats));
1968
- }
1969
- }
1970
- }
1971
- catch (error) {
1972
- spinner.stop();
1973
- writeLine();
1974
- if (isAbortError(error, ctx.abortSignal)) {
1975
- (0, progress_1.hideProgress)();
1976
- if (!ui.suppressAbortNotice) {
1977
- writeLine(DIM('Interrupted.'));
1978
- }
1979
- }
1980
- else {
1981
- writeLine(ERROR(`✗ ${error.message || String(error)}`));
1982
- const hist = ctx.store.getSnapshot().conversationHistory;
1983
- if (hist.length > 0) {
1984
- ctx.store.setState({ conversationHistory: hist.slice(0, -1) });
1985
- }
1986
- }
1987
- }
1988
- return { success: true };
1989
- }
1990
- async function handleExit(ctx) {
1991
- console.log();
1992
- console.log(DIM('Shutting down...'));
1993
- // Update session summary before exit
1994
- if (ctx.sessionId) {
1995
- const messages = (0, session_storage_1.readSessionMessages)(ctx.sessionId);
1996
- if (messages.length > 0) {
1997
- (0, session_storage_1.updateSessionSummary)(ctx.sessionId, messages);
1998
- }
1999
- (0, session_storage_1.endSession)(ctx.sessionId);
2000
- }
2001
- ctx.requestShutdown?.('user request');
2002
- await ctx.runtime.shutdown();
2003
- console.log(SUCCESS('Goodbye.'));
2004
- return { success: true };
2005
- }
2006
- function handleCost(ctx) {
2007
- console.log();
2008
- console.log(HEADER('Lifetime Cost'));
2009
- console.log(DIM('─'.repeat(40)));
2010
- const costTracker = ctx.store.getSnapshot().costTracker;
2011
- const state = (0, usage_state_1.loadUsageState)();
2012
- const ledger = (0, usage_state_1.summarizeUsageLedger)();
2013
- if (state.totalTokens === 0 && state.totalCost === 0) {
2014
- console.log(DIM(' No usage recorded yet.'));
2015
- console.log(DIM(' Use /run or /chat to interact with LLM.'));
2016
- console.log();
2017
- return { success: true };
2018
- }
2019
- // Summary
2020
- console.log();
2021
- console.log(` ${ACCENT('Total Tokens')} ${state.totalTokens.toLocaleString()}`);
2022
- console.log(` ${ACCENT('Tracked Cost')} ${costTracker.formatCost(state.totalCost)}`);
2023
- console.log(` ${ACCENT('Provider Cost')} ${costTracker.formatCost(state.providerCost)}`);
2024
- console.log(` ${ACCENT('Estimated Cost')} ${costTracker.formatCost(state.estimatedCost)}`);
2025
- console.log(` ${ACCENT('Requests')} ${state.usageRecords.toLocaleString()}`);
2026
- console.log(` ${ACCENT('Sessions')} ${state.totalSessions.toLocaleString()}`);
2027
- // By Model
2028
- if (Object.keys(ledger.byModel).length > 0) {
2029
- console.log();
2030
- console.log(HEADER(' By Model:'));
2031
- for (const [model, data] of Object.entries(ledger.byModel)) {
2032
- console.log(` ${BRAND(model.padEnd(20))} ${data.tokens} tokens, ${costTracker.formatCost(data.cost)}`);
2033
- }
2034
- }
2035
- console.log();
2036
- console.log(HEADER(' Cost Sources:'));
2037
- for (const source of ['provider', 'configured', 'builtin', 'fallback']) {
2038
- const data = ledger.bySource[source];
2039
- if (data.count === 0)
2040
- continue;
2041
- console.log(` ${source.padEnd(12)} ${data.count} requests, ${costTracker.formatCost(data.cost)}`);
2042
- }
2043
- if (state.baselineCost > 0 || state.baselineTokens > 0) {
2044
- console.log(DIM(` legacy ${state.baselineTokens.toLocaleString()} tokens, ${costTracker.formatCost(state.baselineCost)}`));
2045
- }
2046
- if (ledger.bySource.fallback.count > 0) {
2047
- console.log();
2048
- console.log(WARN(' Unknown-model fallback pricing is an estimate.'));
2049
- console.log(DIM(' Configure cost.modelPricing in ~/.orion-code/orion.json for accuracy.'));
2050
- }
2051
- // Budget
2052
- const budget = costTracker.getBudget();
2053
- if (budget !== null) {
2054
- const check = costTracker.checkBudget();
2055
- console.log();
2056
- console.log(HEADER(' Budget:'));
2057
- console.log(` ${ACCENT('Limit')} ${costTracker.formatCost(budget)}`);
2058
- console.log(` ${ACCENT('Used this run')} ${costTracker.formatCost(check.used)}`);
2059
- console.log(` ${check.ok ? SUCCESS('✓ Within budget') : WARN('⚠ Budget exceeded')}`);
2060
- }
2061
- console.log();
2062
- return { success: true };
2063
- }
2064
- function handleSkills(_ctx) {
2065
- console.log();
2066
- console.log(HEADER('Loaded Skills'));
2067
- console.log(DIM('─'.repeat(40)));
2068
- try {
2069
- const registry = (0, skills_1.getSkillsRegistry)();
2070
- const summary = registry.getSummary();
2071
- if (summary.count === 0) {
2072
- console.log();
2073
- console.log(DIM(' No skills loaded.'));
2074
- console.log(DIM(' Place SKILL.md files in ~/.orion-code/skills/<name>/ or .orion-code/skills/<name>/'));
2075
- console.log();
2076
- return { success: true };
2077
- }
2078
- console.log();
2079
- console.log(` Total ${SUCCESS(summary.count)} skills (${WARN(summary.autoCount)} auto-trigger)`);
2080
- console.log();
2081
- for (const skill of registry.getAllSkills()) {
2082
- const source = registry.getSource(skill.name);
2083
- const sourceType = source?.type || 'unknown';
2084
- const resourceRoot = skill.resourceRoot || skill.source || source?.path;
2085
- const skillFile = resourceRoot
2086
- ? `${resourceRoot.replace(/\/SKILL\.md$/i, '')}/SKILL.md`
2087
- : source?.skillFile;
2088
- console.log(` ${ACCENT(skill.name)} ${DIM(`(${sourceType})`)}`);
2089
- console.log(` ${DIM(skill.description || '(no description)')}`);
2090
- if (skillFile)
2091
- console.log(` ${DIM(`SKILL.md ${skillFile}`)}`);
2092
- if (resourceRoot)
2093
- console.log(` ${DIM(`Root ${resourceRoot}`)}`);
2094
- }
2095
- console.log();
2096
- }
2097
- catch (err) {
2098
- console.log(ERROR(`✗ ${err.message}`));
2099
- return { success: false };
2100
- }
2101
- return { success: true };
2102
- }
2103
- function handleSkill(ctx, args) {
2104
- const trimmed = args.trim();
2105
- const registry = (0, skills_1.getSkillsRegistry)();
2106
- registry.initialize();
2107
- if (!trimmed) {
2108
- const names = registry
2109
- .getAllSkills()
2110
- .map(skill => skill.name)
2111
- .sort();
2112
- return {
2113
- success: false,
2114
- error: ['Usage: /skill <name> <task>', `Loaded skills: ${names.join(', ') || 'none'}`].join('\n'),
2115
- };
2116
- }
2117
- const parsed = (0, skills_1.parseSkillCommandInput)(`/skill ${trimmed}`);
2118
- const rawName = trimmed.split(/\s+/, 1)[0] || '';
2119
- const requestedName = parsed.skillName || (0, skills_1.normalizeRequestedSkillName)(rawName);
2120
- const referencedSkill = (0, skills_1.loadExplicitSkillReference)(`/skill ${trimmed}`, ctx.cwd);
2121
- if (parsed.skillPath && !referencedSkill) {
2122
- return {
2123
- success: false,
2124
- error: `Invalid skill reference: ${parsed.skillPath}`,
2125
- };
2126
- }
2127
- const skill = referencedSkill ||
2128
- registry
2129
- .getAllSkills()
2130
- .find(candidate => (0, skills_1.skillActivationNames)(candidate).some(name => (0, skills_1.normalizeRequestedSkillName)(name) === requestedName));
2131
- if (!skill) {
2132
- const suggestions = registry
2133
- .getAllSkills()
2134
- .map(candidate => candidate.name)
2135
- .filter(name => name.includes(requestedName) || requestedName.includes(name))
2136
- .slice(0, 5);
2137
- return {
2138
- success: false,
2139
- error: suggestions.length > 0
2140
- ? `Unknown skill: ${rawName}\nDid you mean: ${suggestions.join(', ')}?`
2141
- : `Unknown skill: ${rawName}`,
2142
- };
2143
- }
2144
- const task = parsed.task;
2145
- const source = registry.getSource(skill.name);
2146
- const resourceRoot = skill.resourceRoot || skill.source || source?.path;
2147
- const skillFile = resourceRoot
2148
- ? `${resourceRoot.replace(/\/SKILL\.md$/i, '')}/SKILL.md`
2149
- : source?.skillFile;
2150
- if (!task) {
2151
- const usageSelector = parsed.skillPath
2152
- ? `[$${skill.name}](${formatSkillReferencePath(parsed.skillPath)})`
2153
- : skill.name;
2154
- return {
2155
- success: true,
2156
- output: [
2157
- parsed.skillPath
2158
- ? `Skill reference ${skill.name} is valid for one turn.`
2159
- : `Skill ${skill.name} is loaded.`,
2160
- skillFile ? `SKILL.md ${skillFile}` : '',
2161
- resourceRoot ? `Root ${resourceRoot}` : '',
2162
- `Use: /skill ${usageSelector} <task>`,
2163
- ]
2164
- .filter(Boolean)
2165
- .join('\n'),
2166
- };
2167
- }
2168
- return {
2169
- success: true,
2170
- continueAsChat: true,
2171
- chatInput: parsed.skillPath
2172
- ? `/skill [$${skill.name}](${formatSkillReferencePath(parsed.skillPath)}) ${task}`
2173
- : `/skill ${skill.name} ${task}`,
2174
- };
2175
- }
2176
- function formatSkillReferencePath(path) {
2177
- return /[\s()]/u.test(path) ? `<${path}>` : path;
2178
- }
2179
- function handleMcp(_ctx) {
2180
- console.log();
2181
- console.log(HEADER('MCP Servers'));
2182
- console.log(DIM('─'.repeat(40)));
2183
- const status = mcp_1.mcpManager.getStatus();
2184
- if (status.length === 0) {
2185
- console.log();
2186
- console.log(DIM(' No servers configured. Add to ~/.orion-code/mcp.json'));
2187
- console.log();
2188
- return { success: true };
2189
- }
2190
- console.log();
2191
- for (const s of status) {
2192
- const stateLabel = s.dead
2193
- ? ERROR('dead')
2194
- : s.connected
2195
- ? SUCCESS('connected')
2196
- : WARN('disconnected');
2197
- console.log(` ${ACCENT(s.name.padEnd(20))} ${stateLabel} ${DIM(`${s.toolCount} tools`)}`);
2198
- }
2199
- console.log();
2200
- return { success: true };
2201
- }
2202
- function handleDoctor(ctx) {
2203
- const report = (0, doctor_1.collectDoctorReport)(ctx);
2204
- console.log();
2205
- console.log((0, doctor_1.formatDoctorReport)(report));
2206
- console.log();
2207
- return { success: !(0, doctor_1.hasDoctorFailures)(report) };
2208
- }
2209
- function handleStorage(_ctx, args) {
2210
- const usage = '/storage [doctor|status|repair [--dry-run|--yes] [--plan=<token>]|cleanup [--dry-run|--yes] [--plan=<token>]]';
2211
- const trimmed = args.trim();
2212
- const tokens = trimmed ? trimmed.split(/\s+/u) : [];
2213
- const action = tokens[0] ?? 'doctor';
2214
- const flags = tokens.slice(1);
2215
- const acceptsMutationFlags = action === 'cleanup' || action === 'repair';
2216
- const planFlags = flags.filter(flag => flag.startsWith('--plan='));
2217
- const invalidTokens = flags.filter(flag => !acceptsMutationFlags ||
2218
- (flag !== '--dry-run' && flag !== '--yes' && !flag.startsWith('--plan=')) ||
2219
- (flag.startsWith('--plan=') && flag.length === '--plan='.length));
2220
- if (planFlags.length > 1)
2221
- invalidTokens.push(...planFlags.slice(1));
2222
- if (invalidTokens.length > 0) {
2223
- return {
2224
- success: false,
2225
- error: `Unknown /storage option: ${invalidTokens.join(', ')}. Usage: ${usage}`,
2226
- };
2227
- }
2228
- const confirmed = flags.includes('--yes');
2229
- const explicitDryRun = flags.includes('--dry-run');
2230
- const planToken = planFlags[0]?.slice('--plan='.length);
2231
- const decodedPlan = planToken ? (0, storage_maintenance_1.deserializeStorageMaintenancePlan)(planToken) : undefined;
2232
- if (planToken && !decodedPlan) {
2233
- return { success: false, error: `Invalid or corrupted storage plan token. Usage: ${usage}` };
2234
- }
2235
- if (action === 'cleanup') {
2236
- if (decodedPlan && decodedPlan.kind !== 'cleanup') {
2237
- return { success: false, error: 'The supplied storage plan is not a cleanup plan.' };
2238
- }
2239
- const dryRun = explicitDryRun || !confirmed;
2240
- if (!dryRun && !decodedPlan) {
2241
- return {
2242
- success: false,
2243
- error: 'Cleanup requires the exact preview plan. Run /storage cleanup first.',
2244
- };
2245
- }
2246
- const consumedPlan = !dryRun && planToken ? (0, storage_maintenance_1.consumeStorageMaintenancePlan)(planToken) : undefined;
2247
- if (!dryRun && (!consumedPlan || consumedPlan.kind !== 'cleanup')) {
2248
- return {
2249
- success: false,
2250
- error: 'The storage cleanup plan expired, was already used, or is not valid in this process.',
2251
- };
2252
- }
2253
- const plan = dryRun
2254
- ? decodedPlan?.kind === 'cleanup'
2255
- ? decodedPlan.plan
2256
- : (0, storage_maintenance_1.collectStorageCleanupPlan)()
2257
- : consumedPlan
2258
- .plan;
2259
- const result = (0, storage_maintenance_1.cleanupStorage)({ dryRun }, plan);
2260
- console.log();
2261
- console.log((0, storage_maintenance_1.formatStorageCleanupResult)(result));
2262
- if (dryRun) {
2263
- const portablePlan = planToken ?? (0, storage_maintenance_1.serializeStorageMaintenancePlan)({ kind: 'cleanup', plan });
2264
- console.log(DIM(`Preview only. Run /storage cleanup --plan=${portablePlan} --yes to apply this plan.`));
2265
- }
2266
- console.log();
2267
- return { success: true };
2268
- }
2269
- if (action === 'repair') {
2270
- if (decodedPlan && decodedPlan.kind !== 'repair') {
2271
- return { success: false, error: 'The supplied storage plan is not a repair plan.' };
2272
- }
2273
- const plan = decodedPlan?.kind === 'repair' ? decodedPlan.plan : (0, storage_maintenance_1.collectProjectMetadataRepairPlan)();
2274
- if (explicitDryRun || !confirmed) {
2275
- console.log();
2276
- console.log(HEADER('Orion Code Storage Repair Preview'));
2277
- console.log(DIM('─'.repeat(40)));
2278
- console.log(` Repairable metadata entries ${ACCENT(String(plan.actions.length))}`);
2279
- for (const action of plan.actions.slice(0, 12)) {
2280
- console.log(` ${DIM('•')} ${DIM(action.metadataPath)}`);
2281
- }
2282
- const portablePlan = planToken ?? (0, storage_maintenance_1.serializeStorageMaintenancePlan)({ kind: 'repair', plan });
2283
- console.log(DIM(` Preview only. Writable repair is disabled; /storage repair --plan=${portablePlan} --yes will fail closed.`));
2284
- console.log();
2285
- return { success: true };
2286
- }
2287
- if (!decodedPlan) {
2288
- return {
2289
- success: false,
2290
- error: 'Repair requires the exact preview plan. Run /storage repair first.',
2291
- };
2292
- }
2293
- const consumedPlan = planToken ? (0, storage_maintenance_1.consumeStorageMaintenancePlan)(planToken) : undefined;
2294
- if (!consumedPlan || consumedPlan.kind !== 'repair') {
2295
- return {
2296
- success: false,
2297
- error: 'The storage repair plan expired, was already used, or is not valid in this process.',
2298
- };
2299
- }
2300
- const result = (0, storage_maintenance_1.repairProjectMetadata)(consumedPlan.plan);
2301
- return { success: false, error: result.blockedReason };
2302
- }
2303
- if (action !== 'doctor' && action !== 'status') {
2304
- return {
2305
- success: false,
2306
- error: `Usage: ${usage}`,
2307
- };
2308
- }
2309
- const report = (0, storage_maintenance_1.collectStorageReport)();
2310
- console.log();
2311
- console.log((0, storage_maintenance_1.formatStorageReport)(report));
2312
- console.log();
2313
- return { success: true };
2314
- }
2315
- function handleDiff(ctx, args) {
2316
- const maxFilesMatch = args.match(/--max-files(?:=|\s+)(\d+)/);
2317
- const maxFiles = maxFilesMatch ? Number(maxFilesMatch[1]) : 40;
2318
- const report = (0, workspace_diff_1.collectWorkspaceDiff)({ cwd: ctx.cwd, maxFiles });
2319
- console.log();
2320
- console.log((0, workspace_diff_1.formatWorkspaceDiff)(report, { maxFiles }));
2321
- console.log();
2322
- return { success: report.isGitRepo };
2323
- }
2324
- function handleCommitPlan(ctx, args) {
2325
- const maxFilesMatch = args.match(/--max-files(?:=|\s+)(\d+)/);
2326
- const maxFiles = maxFilesMatch ? Number(maxFilesMatch[1]) : 20;
2327
- const plan = (0, commit_plan_1.createCommitPlan)({ cwd: ctx.cwd, maxFiles });
2328
- console.log();
2329
- console.log((0, commit_plan_1.formatCommitPlan)(plan));
2330
- console.log();
2331
- return { success: plan.diff.isGitRepo };
2332
- }
2333
- function handleTools(ctx) {
2334
- const tools = ctx.store.getSnapshot().tools.length > 0 ? ctx.store.getSnapshot().tools : (0, tools_1.getRuntimeTools)();
2335
- const staticTools = tools.filter(tool => !tool.name.startsWith('mcp__'));
2336
- const mcpTools = tools.filter(tool => tool.name.startsWith('mcp__'));
2337
- console.log();
2338
- console.log(HEADER('Available Tools'));
2339
- console.log(DIM('─'.repeat(40)));
2340
- console.log(` Static tools ${ACCENT(String(staticTools.length))}`);
2341
- console.log(` MCP tools ${ACCENT(String(mcpTools.length))}`);
2342
- console.log();
2343
- const visible = [...staticTools, ...mcpTools].slice(0, 28);
2344
- for (const tool of visible) {
2345
- const label = tool.name.startsWith('mcp__') ? 'mcp' : 'tool';
2346
- console.log(` ${ACCENT(tool.name)} ${DIM(`[${label}]`)}`);
2347
- console.log(` ${DIM(tool.description.slice(0, 96))}`);
2348
- }
2349
- if (tools.length > visible.length) {
2350
- console.log();
2351
- console.log(DIM(` ... ${tools.length - visible.length} more tools hidden`));
2352
- }
2353
- console.log();
2354
- return { success: true };
2355
- }
2356
- function handleTodos(ctx) {
2357
- const todos = ctx.store.getSnapshot().todos;
2358
- console.log();
2359
- console.log(HEADER('Todos'));
2360
- console.log(DIM('─'.repeat(40)));
2361
- if (todos.length === 0) {
2362
- console.log(DIM(' No active todos yet.'));
2363
- console.log();
2364
- return { success: true };
2365
- }
2366
- for (const todo of todos) {
2367
- const marker = todo.status === 'completed'
2368
- ? SUCCESS('✓')
2369
- : todo.status === 'in_progress'
2370
- ? WARN('›')
2371
- : DIM('○');
2372
- console.log(` ${marker} ${todo.content}`);
2373
- if (todo.activeForm && todo.activeForm !== todo.content) {
2374
- console.log(` ${DIM(todo.activeForm)}`);
2375
- }
2376
- }
2377
- console.log();
2378
- return { success: true };
2379
- }
2380
- function handleContextClear(ctx, args) {
2381
- const history = ctx.store.getSnapshot().conversationHistory;
2382
- if (history.length === 0) {
2383
- console.log(DIM('Current in-memory model context is already empty.'));
2384
- console.log();
2385
- return { success: true };
2386
- }
2387
- if (!hasCommandFlag(args, '--yes')) {
2388
- return {
2389
- success: false,
2390
- error: [
2391
- `This will clear ${history.length} message(s) from the current in-memory model context.`,
2392
- 'Saved session history will not be deleted and can still be restored with /resume.',
2393
- 'Run /context-clear --yes to continue.',
2394
- ].join('\n'),
2395
- };
2396
- }
2397
- ctx.store.resetConversation();
2398
- (0, framework_1.resetToolState)();
2399
- console.log(SUCCESS(`✔ Cleared ${history.length} messages from current model context`));
2400
- console.log(DIM(' Saved session history, configuration, and system state were preserved.'));
2401
- console.log();
2402
- return { success: true };
2403
- }
2404
- async function handleCompact(ctx, args) {
2405
- const history = ctx.store.getSnapshot().conversationHistory;
2406
- if (history.length === 0) {
2407
- console.log(DIM('Conversation history is empty, nothing to compact'));
2408
- console.log();
2409
- return { success: true };
2410
- }
2411
- // 解析参数
2412
- const thresholdArg = parseInt(args.trim(), 10);
2413
- const threshold = thresholdArg > 0 ? thresholdArg : 50;
2414
- console.log();
2415
- console.log(HEADER('Compacting Conversation'));
2416
- console.log(DIM('─'.repeat(40)));
2417
- console.log(` Current messages: ${history.length}`);
2418
- console.log(` Threshold: ${threshold}`);
2419
- console.log();
2420
- if (history.length <= threshold) {
2421
- console.log(DIM(`Conversation has ${history.length} messages, below compact threshold ${threshold}.`));
2422
- console.log(DIM('Nothing compacted.'));
2423
- console.log();
2424
- return { success: true };
2425
- }
2426
- console.log(DIM((0, agent_status_1.compactStatus)()));
2427
- try {
2428
- const modelId = ctx.llm?.getModel() ?? ctx.store.getSnapshot().currentModel;
2429
- const coordinator = ctx.compactCoordinator ??
2430
- new coordinator_1.CompactCoordinator({
2431
- modelId,
2432
- llm: ctx.llm,
2433
- outputReserveTokens: ctx.llm?.getMaxTokens?.(),
2434
- getContextCapsule: () => ctx.store.getSnapshot().harnessState?.capsule,
2435
- getHarnessState: () => ctx.store.getSnapshot().harnessState,
2436
- });
2437
- coordinator.configure({
2438
- modelId,
2439
- llm: ctx.llm,
2440
- outputReserveTokens: ctx.llm?.getMaxTokens?.(),
2441
- getContextCapsule: () => ctx.store.getSnapshot().harnessState?.capsule,
2442
- getHarnessState: () => ctx.store.getSnapshot().harnessState,
2443
- });
2444
- const beforeTokens = (0, token_estimate_1.estimateMessagesTokens)(history);
2445
- const automaticStats = coordinator.getAutomatic().getStats();
2446
- const beforeUsage = (0, model_context_1.createContextUsageSnapshot)({
2447
- modelId,
2448
- usedTokens: beforeTokens,
2449
- source: 'estimated',
2450
- outputReserveTokens: ctx.llm?.getMaxTokens?.(),
2451
- warningThreshold: automaticStats.preCompactThreshold,
2452
- autoCompactThreshold: automaticStats.threshold,
2453
- autoCompactEnabled: automaticStats.enabled,
2454
- });
2455
- const result = await coordinator.compactManual(history, threshold);
2456
- const compacted = result.messages;
2457
- const compactedTokens = (0, token_estimate_1.estimateMessagesTokens)(compacted);
2458
- const afterUsage = (0, model_context_1.createContextUsageSnapshot)({
2459
- modelId,
2460
- usedTokens: compactedTokens,
2461
- source: 'estimated',
2462
- outputReserveTokens: ctx.llm?.getMaxTokens?.(),
2463
- warningThreshold: automaticStats.preCompactThreshold,
2464
- autoCompactThreshold: automaticStats.threshold,
2465
- autoCompactEnabled: automaticStats.enabled,
2466
- });
2467
- const reduction = history.length - compacted.length;
2468
- const percent = Math.round((reduction / history.length) * 100);
2469
- const sessionId = ctx.getSession?.()?.id ?? ctx.sessionId;
2470
- if (sessionId) {
2471
- const sourceMessageCount = (0, session_storage_1.readSessionMessages)(sessionId).length;
2472
- const checkpoint = (0, session_storage_1.commitSessionCompactCheckpoint)({
2473
- sessionId,
2474
- mode: 'manual',
2475
- modelId,
2476
- sourceMessageCount,
2477
- transcriptStartMessageIndex: Math.max(0, sourceMessageCount - threshold),
2478
- modelHistory: compacted,
2479
- summary: {
2480
- text: result.summary,
2481
- generatedAt: result.summaryGeneratedAt,
2482
- source: result.summarySource,
2483
- },
2484
- beforeUsage,
2485
- afterUsage,
2486
- });
2487
- ctx.store.setState({ conversationHistory: checkpoint.modelHistory });
2488
- }
2489
- else {
2490
- ctx.store.setState({ conversationHistory: compacted });
2491
- }
2492
- ctx.store.setContextUsage(afterUsage);
2493
- console.log(SUCCESS(`✔ Compacted ${history.length} → ${compacted.length} messages`));
2494
- console.log(DIM(` Reduced by ${reduction} messages (${percent}%)`));
2495
- console.log();
2496
- return { success: true };
2497
- }
2498
- catch (err) {
2499
- const message = err instanceof Error ? err.message : String(err);
2500
- console.log(ERROR(`✗ Compact failed: ${message}`));
2501
- console.log();
2502
- return { success: false };
2503
- }
2504
- }
2505
- function handleUsage(ctx) {
2506
- console.log();
2507
- console.log(HEADER('Usage Statistics'));
2508
- console.log(DIM('─'.repeat(40)));
2509
- const snapshot = ctx.store.getSnapshot();
2510
- const usage = snapshot.tokenUsage;
2511
- const history = snapshot.conversationHistory;
2512
- console.log();
2513
- // Token usage
2514
- console.log(HEADER(' Tokens:'));
2515
- if (usage) {
2516
- console.log(` Input ${ACCENT(usage.promptTokens.toLocaleString())}`);
2517
- console.log(` Output ${ACCENT(usage.completionTokens.toLocaleString())}`);
2518
- const total = usage.promptTokens + usage.completionTokens;
2519
- console.log(` Total ${DIM(total.toLocaleString())}`);
2520
- const ratio = usage.completionTokens / usage.promptTokens;
2521
- console.log(` Ratio ${DIM(ratio.toFixed(2))} (output/input)`);
2522
- }
2523
- else {
2524
- console.log(DIM(' No token usage recorded'));
2525
- }
2526
- console.log();
2527
- // Conversation stats
2528
- console.log(HEADER(' Conversation:'));
2529
- console.log(` Messages ${DIM(history.length.toString())}`);
2530
- console.log(` Turns ${DIM(Math.floor(history.length / 2).toString())}`);
2531
- // Count by role
2532
- const byRole = { user: 0, assistant: 0, system: 0, tool: 0 };
2533
- for (const msg of history) {
2534
- byRole[msg.role] = (byRole[msg.role] || 0) + 1;
2535
- }
2536
- console.log(` User msgs ${DIM(byRole.user.toString())}`);
2537
- console.log(` Assistant ${DIM(byRole.assistant.toString())}`);
2538
- console.log();
2539
- // Model info
2540
- console.log(HEADER(' Model:'));
2541
- console.log(` Current ${BRAND(snapshot.currentModel)}`);
2542
- if (ctx.llm) {
2543
- console.log(` Active ${ACCENT(ctx.llm.getModel())}`);
2544
- }
2545
- console.log();
2546
- return { success: true };
2547
- }
2548
- // ============================================================================
2549
- // Session 命令
2550
- // ============================================================================
2551
- function parseSessionScopeArgs(args, cwd) {
2552
- const parts = args.trim().split(/\s+/).filter(Boolean);
2553
- let allProjects = false;
2554
- let last = false;
2555
- let projectPath = (0, session_storage_1.resolveProjectPath)(cwd);
2556
- const queryParts = [];
2557
- for (let i = 0; i < parts.length; i++) {
2558
- const part = parts[i];
2559
- if (part === '--all' || part === '-a') {
2560
- allProjects = true;
2561
- continue;
2562
- }
2563
- if (part === '--last' || part === '-l') {
2564
- last = true;
2565
- continue;
2566
- }
2567
- if ((part === '--project' || part === '-p') && parts[i + 1]) {
2568
- projectPath = (0, session_storage_1.resolveProjectPath)(parts[i + 1]);
2569
- i++;
2570
- continue;
2571
- }
2572
- queryParts.push(part);
2573
- }
2574
- return {
2575
- allProjects,
2576
- projectPath,
2577
- last,
2578
- query: queryParts.join(' '),
2579
- };
2580
- }
2581
- function sessionTitle(session) {
2582
- return session.name || session.taskSummary || '(untitled)';
2583
- }
2584
- function truncateText(text, max) {
2585
- return text.length > max ? text.slice(0, max - 3) + '...' : text;
2586
- }
2587
- function printSessionRows(sessions, options = {}) {
2588
- for (let i = 0; i < sessions.length; i++) {
2589
- const session = sessions[i];
2590
- const startTime = new Date(session.startTime).toLocaleString();
2591
- const updatedTime = new Date(session.updatedAt ?? session.startTime).toLocaleString();
2592
- const duration = session.endTime
2593
- ? Math.round((session.endTime - session.startTime) / 1000) + 's'
2594
- : 'active';
2595
- const status = session.endTime ? DIM('completed') : ACCENT('active');
2596
- const index = options.indexed ? `${String(i + 1).padStart(2, ' ')}. ` : ' ';
2597
- const name = session.name ? ` ${ACCENT(`"${session.name}"`)}` : '';
2598
- console.log(`${index}${status} ${BRAND(session.id.slice(0, 8))}${name} ${DIM(session.model)}`);
2599
- console.log(` ${truncateText(sessionTitle(session), 96)}`);
2600
- console.log(` ${DIM(`Started: ${startTime}`)} ${DIM(`Updated: ${updatedTime}`)} ${DIM(`Duration: ${duration}`)}`);
2601
- console.log(` ${DIM(`Messages: ${session.messageCount ?? 0}`)} ${DIM(`Size: ${(0, format_1.formatBytes)(session.historySizeBytes ?? 0)}`)} ${DIM(`Tokens: ${session.tokenCount}`)} ${DIM(`Cost: $${session.cost.toFixed(4)}`)}`);
2602
- if (options.showIndexSummary) {
2603
- const indexSummary = (0, session_index_1.loadSessionIndex)(session.id, session.projectPath);
2604
- if (indexSummary) {
2605
- const toolCount = Object.values(indexSummary.tools).reduce((total, count) => total + count, 0);
2606
- console.log(` ${DIM(`Index: ${indexSummary.files.length} files, ${toolCount} tool calls, ${indexSummary.topics.length} topics`)}`);
2607
- }
2608
- else {
2609
- console.log(` ${DIM('Index: not built')}`);
2610
- }
2611
- }
2612
- if (options.showProject) {
2613
- console.log(` ${DIM(`Project: ${session.projectPath}`)}`);
2614
- }
2615
- console.log();
2616
- }
2617
- }
2618
- function parsePickerIndex(ref, max) {
2619
- const trimmed = ref.trim();
2620
- const match = trimmed.match(/^#?(\d+)$/);
2621
- if (!match)
2622
- return null;
2623
- const index = Number(match[1]);
2624
- if (!Number.isInteger(index) || index < 1 || index > max)
2625
- return null;
2626
- return index - 1;
2627
- }
2628
- function printSessionConflict(ref, matches) {
2629
- console.log(ERROR(`Session reference is ambiguous: ${ref}`));
2630
- console.log(DIM('Use a longer id prefix, exact session name, or pick one of these:'));
2631
- console.log();
2632
- printSessionRows(matches.slice(0, 10), { indexed: true, showProject: true });
2633
- console.log(DIM('Example: /resume <longer-session-id>'));
2634
- console.log();
2635
- }
2636
- function printSessionPicker(sessions, options) {
2637
- console.log(HEADER(options.title));
2638
- console.log(DIM('─'.repeat(Math.min(process.stdout.columns || 80, 96))));
2639
- printSessionRows(sessions, { indexed: true, showProject: options.showProject });
2640
- if (options.moreCount && options.moreCount > 0) {
2641
- console.log(DIM(`... ${options.moreCount} more sessions. Use /sessions to list them, or /resume <session-id>.`));
2642
- }
2643
- console.log(DIM('Use /resume <number|session-id|name> or /resume --last.'));
2644
- }
2645
- function handleSessions(ctx, args = '') {
2646
- const scope = parseSessionScopeArgs(args, ctx.cwd);
2647
- const query = scope.query?.trim();
2648
- // If there's a search query, use the session index
2649
- if (query && !query.startsWith('--')) {
2650
- const allSessions = scope.allProjects ? (0, session_storage_1.listSessions)() : (0, session_storage_1.listProjectSessions)(scope.projectPath);
2651
- const matchedIds = (0, session_index_1.searchSessions)(query, allSessions.map(session => ({
2652
- id: session.id,
2653
- projectPath: session.projectPath,
2654
- })));
2655
- if (matchedIds.length === 0) {
2656
- console.log();
2657
- console.log(HEADER(`Sessions (search: "${query}")`));
2658
- console.log(DIM('─'.repeat(40)));
2659
- console.log(DIM(' No matching sessions found'));
2660
- console.log();
2661
- console.log(DIM('Tip: search by file path, tool name, or topic keyword'));
2662
- console.log();
2663
- return { success: true };
2664
- }
2665
- // Rebuild session list in matched order
2666
- const sessionMap = new Map(allSessions.map(s => [s.id, s]));
2667
- const matchedSessions = matchedIds
2668
- .map(id => sessionMap.get(id))
2669
- .filter(Boolean);
2670
- console.log();
2671
- console.log(HEADER(`Sessions (search: "${query}") — ${matchedSessions.length} matches`));
2672
- console.log(DIM('─'.repeat(40)));
2673
- console.log();
2674
- printSessionRows(matchedSessions, {
2675
- indexed: true,
2676
- showProject: scope.allProjects,
2677
- showIndexSummary: true,
2678
- });
2679
- console.log();
2680
- console.log(DIM(`Searched ${allSessions.length} sessions, found ${matchedSessions.length} matches`));
2681
- console.log(DIM('Use /resume <number|session-id|name> to restore a session'));
2682
- console.log();
2683
- return { success: true };
2684
- }
2685
- console.log();
2686
- console.log(HEADER(scope.allProjects ? 'Sessions (all projects)' : 'Sessions'));
2687
- console.log(DIM('─'.repeat(40)));
2688
- const sessions = scope.allProjects
2689
- ? (0, session_storage_1.listSessions)(10)
2690
- : (0, session_storage_1.listProjectSessions)(scope.projectPath, 10);
2691
- if (sessions.length === 0) {
2692
- console.log(DIM(scope.allProjects ? ' No sessions found' : ' No sessions found for this project'));
2693
- console.log();
2694
- return { success: true };
2695
- }
2696
- console.log();
2697
- printSessionRows(sessions, { indexed: true, showProject: scope.allProjects });
2698
- console.log(DIM('Use /resume <number|session-id|name> to restore a session'));
2699
- console.log(DIM('Use /session-rename <number|session-id|name> <new name> to rename'));
2700
- console.log(DIM('Use /sessions --all to list sessions from every project'));
2701
- console.log(DIM('Use /sessions <query> to search by file, tool, or keyword'));
2702
- console.log();
2703
- return { success: true };
2704
- }
2705
- function handleResume(ctx, args) {
2706
- const ui = commandUICapabilities(ctx);
2707
- const scope = parseSessionScopeArgs(args, ctx.cwd);
2708
- const sessionRef = scope.query;
2709
- const scopedSessions = (scope.allProjects ? (0, session_storage_1.listSessions)() : (0, session_storage_1.listProjectSessions)(scope.projectPath)).filter(session => (session.messageCount ?? 0) > 0);
2710
- if (!sessionRef) {
2711
- const lastSession = scopedSessions[0];
2712
- if (!lastSession) {
2713
- console.log(ERROR('No previous session found for this project'));
2714
- console.log(DIM('Use /sessions --all to list all sessions'));
2715
- console.log();
2716
- return { success: false };
2717
- }
2718
- if (scope.last || scopedSessions.length === 1) {
2719
- return restoreSession(ctx, lastSession, true);
2720
- }
2721
- const picker = {
2722
- title: scope.allProjects ? 'Pick a Session (all projects)' : 'Pick a Session',
2723
- showProject: scope.allProjects,
2724
- moreCount: 0,
2725
- sessions: scopedSessions,
2726
- allProjects: scope.allProjects,
2727
- maxVisibleItems: 10,
2728
- };
2729
- if (ui.structuredPickers) {
2730
- return { success: true, sessionPicker: picker };
2731
- }
2732
- const visibleSessions = scopedSessions.slice(0, 10);
2733
- console.log();
2734
- printSessionPicker(visibleSessions, {
2735
- title: picker.title,
2736
- showProject: picker.showProject,
2737
- moreCount: Math.max(0, scopedSessions.length - visibleSessions.length),
2738
- });
2739
- console.log();
2740
- return { success: true };
2741
- }
2742
- const pickerIndex = parsePickerIndex(sessionRef, scopedSessions.length);
2743
- if (pickerIndex !== null) {
2744
- return restoreSession(ctx, scopedSessions[pickerIndex], false);
2745
- }
2746
- // Resume specific session
2747
- const result = (0, session_storage_1.lookupSessionRef)(sessionRef, scope.projectPath, {
2748
- allProjects: scope.allProjects,
2749
- });
2750
- if (result.status === 'ambiguous') {
2751
- printSessionConflict(sessionRef, result.matches);
2752
- return { success: false };
2753
- }
2754
- if (result.status === 'not_found') {
2755
- console.log(ERROR(`Session not found: ${sessionRef}`));
2756
- console.log(DIM(scope.allProjects
2757
- ? 'Use /sessions --all to list sessions'
2758
- : 'Use /sessions to list project sessions, or /resume <id> --all'));
2759
- console.log();
2760
- return { success: false };
2761
- }
2762
- return restoreSession(ctx, result.session, false);
2763
- }
2764
- function restoreSession(ctx, session, isLast) {
2765
- const resumed = (0, session_storage_1.resumeSession)(session.id) ?? session;
2766
- // Swap in the resumed session's transcript BEFORE emitting any command output,
2767
- // so the output is appended after the history rather than wiped by the
2768
- // transcript replacement below.
2769
- ctx.setSession?.(resumed);
2770
- // Load history and notify runtime/TUI consumers.
2771
- const history = (0, session_storage_1.loadSessionHistory)(resumed.id);
2772
- const transcriptMessages = (0, session_storage_1.loadSessionTranscriptMessages)(resumed.id);
2773
- const rawMessages = (0, session_storage_1.readSessionMessages)(resumed.id);
2774
- const checkpoint = (0, session_storage_1.loadSessionCompactCheckpoint)(resumed.id);
2775
- const resumeGeneratedAt = Date.now();
2776
- const summary = checkpoint?.summary.text ?? (history.length > 0 ? generateHistorySummary(history) : '');
2777
- const summaryGeneratedAt = checkpoint?.summary.generatedAt ?? resumeGeneratedAt;
2778
- const summarySource = checkpoint?.summary.source ?? 'resume_heuristic';
2779
- const summaryCoveredMessages = checkpoint?.summary.sourceMessageCount ?? rawMessages.length;
2780
- if (history.length > 0) {
2781
- const eventSummary = checkpoint?.summary.text ?? generateRestoredSessionEventSummary(history);
2782
- ctx.store.setState({ conversationHistory: history });
2783
- ctx.store.setState({
2784
- harnessState: (0, session_storage_1.loadSessionHarnessState)(resumed.id) ?? resumed.harnessState,
2785
- });
2786
- (0, framework_1.resetToolState)();
2787
- ctx.sessionRestored?.({
2788
- sessionId: resumed.id,
2789
- projectPath: resumed.projectPath,
2790
- model: resumed.model,
2791
- restoredMessages: history.length,
2792
- messageCount: resumed.messageCount,
2793
- summary: eventSummary,
2794
- summaryGeneratedAt,
2795
- summarySource,
2796
- summaryCoveredMessages,
2797
- checkpointId: checkpoint?.checkpointId,
2798
- transcriptMessages: transcriptMessages.length,
2799
- });
2800
- }
2801
- else {
2802
- ctx.sessionRestored?.({
2803
- sessionId: resumed.id,
2804
- projectPath: resumed.projectPath,
2805
- model: resumed.model,
2806
- restoredMessages: 0,
2807
- messageCount: resumed.messageCount,
2808
- summaryGeneratedAt,
2809
- summarySource,
2810
- summaryCoveredMessages,
2811
- checkpointId: checkpoint?.checkpointId,
2812
- transcriptMessages: transcriptMessages.length,
2813
- });
2814
- }
2815
- // Emit the resume summary. In TUI (inline-surface) mode, route through the
2816
- // command-output sink instead of raw console.log: a bare console.log writes
2817
- // directly to stdout and desyncs the surface's cursor tracking, leaving the
2818
- // live region mis-positioned (blank lower screen, content stuck at top).
2819
- // Plain text is used so no raw ANSI escapes leak into the TUI frame.
2820
- const bannerLines = [
2821
- isLast ? 'Resuming last session' : `Resuming session ${resumed.id.slice(0, 8)}`,
2822
- ` ID: ${resumed.id}`,
2823
- ` Model: ${resumed.model}`,
2824
- ` Project: ${resumed.projectPath}`,
2825
- ` Started: ${new Date(resumed.startTime).toLocaleString()}`,
2826
- ];
2827
- if (history.length > 0) {
2828
- bannerLines.push(` Summary: ${summary}`);
2829
- bannerLines.push(` Generated: ${new Date(summaryGeneratedAt).toLocaleString()} (${checkpoint ? 'compact checkpoint' : 'generated on resume'})`);
2830
- bannerLines.push(` Covers: ${summaryCoveredMessages} source messages`);
2831
- bannerLines.push(`✔ Restored ${history.length} model-context messages / ${transcriptMessages.length} transcript messages`);
2832
- }
2833
- else {
2834
- bannerLines.push(' No messages in session');
2835
- }
2836
- if (ctx.uiRenderer === 'tui' || ctx.uiRenderer === 'ink') {
2837
- if (!ctx.sessionRestored) {
2838
- for (const line of bannerLines)
2839
- ctx.writeLine?.(line);
2840
- }
2841
- }
2842
- else {
2843
- console.log();
2844
- console.log(HEADER(bannerLines[0]));
2845
- for (const line of bannerLines.slice(1)) {
2846
- console.log(line.startsWith('✔') ? SUCCESS(line) : DIM(line));
2847
- }
2848
- console.log();
2849
- }
2850
- return { success: true };
2851
- }
2852
- function handleSessionRename(ctx, args) {
2853
- const scope = parseSessionScopeArgs(args, ctx.cwd);
2854
- const parts = scope.query.split(/\s+/).filter(Boolean);
2855
- const ref = parts.shift();
2856
- const newName = parts.join(' ').trim();
2857
- if (!ref || !newName) {
2858
- console.log(ERROR('Usage: /session-rename <number|session-id|name> <new name>'));
2859
- console.log(DIM('Run /sessions first to see picker numbers for this project.'));
2860
- console.log();
2861
- return { success: false };
2862
- }
2863
- const scopedSessions = scope.allProjects
2864
- ? (0, session_storage_1.listSessions)()
2865
- : (0, session_storage_1.listProjectSessions)(scope.projectPath);
2866
- const pickerIndex = parsePickerIndex(ref, scopedSessions.length);
2867
- let session = pickerIndex !== null ? scopedSessions[pickerIndex] : null;
2868
- if (!session) {
2869
- const result = (0, session_storage_1.lookupSessionRef)(ref, scope.projectPath, { allProjects: scope.allProjects });
2870
- if (result.status === 'ambiguous') {
2871
- printSessionConflict(ref, result.matches);
2872
- return { success: false };
2873
- }
2874
- if (result.status === 'not_found') {
2875
- console.log(ERROR(`Session not found: ${ref}`));
2876
- console.log(DIM(scope.allProjects
2877
- ? 'Use /sessions --all to list sessions'
2878
- : 'Use /sessions to list project sessions'));
2879
- console.log();
2880
- return { success: false };
2881
- }
2882
- session = result.session;
2883
- }
2884
- const duplicate = scopedSessions.find(s => s.id !== session.id && s.name === newName);
2885
- const renamed = (0, session_storage_1.renameSession)(session.id, newName);
2886
- if (!renamed) {
2887
- console.log(ERROR(`Session not found: ${ref}`));
2888
- console.log();
2889
- return { success: false };
2890
- }
2891
- if (ctx.getSession?.()?.id === renamed.id) {
2892
- ctx.setSession?.(renamed);
2893
- }
2894
- console.log();
2895
- console.log(SUCCESS(`✔ Renamed session ${renamed.id.slice(0, 8)} to "${newName}"`));
2896
- if (duplicate) {
2897
- console.log(WARN(` Name already exists on ${duplicate.id.slice(0, 8)}; /resume "${newName}" will be ambiguous.`));
2898
- }
2899
- console.log();
2900
- return { success: true };
2901
- }
2902
- async function handleEditPreview(ctx) {
2903
- const lastEdit = (0, framework_1.getToolState)().lastEditFileArgs;
2904
- if (!lastEdit) {
2905
- console.log(ERROR('No previous edit_file call found for preview'));
2906
- console.log(DIM('Run an edit_file tool call first, then use /edit-preview to inspect the match candidates.'));
2907
- console.log();
2908
- return { success: false };
2909
- }
2910
- const hasMetadata = Boolean(lastEdit.sessionId || lastEdit.turnId);
2911
- if (!hasMetadata) {
2912
- console.log(WARN('Using legacy edit-preview state without session/turn tags. Running preview as best-effort.'));
2913
- }
2914
- const staleBySession = Boolean(lastEdit.sessionId && ctx.sessionId && lastEdit.sessionId !== ctx.sessionId);
2915
- const staleByTurn = Boolean(lastEdit.turnId != null && ctx.turnId != null && String(lastEdit.turnId) !== String(ctx.turnId));
2916
- if (staleBySession || staleByTurn) {
2917
- const mismatch = [];
2918
- if (staleBySession)
2919
- mismatch.push(`session ${lastEdit.sessionId} vs ${ctx.sessionId}`);
2920
- if (staleByTurn)
2921
- mismatch.push(`turn ${String(lastEdit.turnId)} vs ${String(ctx.turnId)}`);
2922
- console.log(ERROR('Edit preview target does not match current context.'));
2923
- console.log(DIM(`Stale edit target: ${mismatch.join(', ')}.`));
2924
- console.log();
2925
- return { success: false };
2926
- }
2927
- if (hasMetadata && !(ctx.sessionId || ctx.turnId)) {
2928
- console.log(WARN('Edit preview context is available, but current command context is missing session/turn metadata.'));
2929
- console.log(DIM('Preview is allowed, but stale checks cannot be fully validated.'));
2930
- }
2931
- const rawResult = await (0, tools_1.executeTool)('edit_file', {
2932
- ...lastEdit,
2933
- preview: true,
2934
- }, ctx.abortSignal, {
2935
- cwd: ctx.cwd,
2936
- config: {
2937
- name: ctx.config.name,
2938
- mode: ctx.config.mode,
2939
- },
2940
- sessionId: ctx.sessionId,
2941
- turnId: ctx.turnId,
2942
- });
2943
- let parsed;
2944
- try {
2945
- parsed = JSON.parse(rawResult);
2946
- }
2947
- catch {
2948
- parsed = { success: false, error: rawResult };
2949
- }
2950
- console.log();
2951
- console.log(HEADER('Edit Preview'));
2952
- console.log(DIM('─'.repeat(40)));
2953
- if (parsed.success) {
2954
- console.log(parsed.output || DIM('No preview output'));
2955
- }
2956
- else {
2957
- console.log(ERROR(parsed.error || 'Preview failed'));
2958
- }
2959
- console.log();
2960
- // Return structured data for terminal/TUI/Ink picker rendering.
2961
- if (parsed.success && parsed.metadata?.candidates && Array.isArray(parsed.metadata.candidates)) {
2962
- return {
2963
- success: true,
2964
- editPreview: {
2965
- path: lastEdit.path,
2966
- newString: lastEdit.new_string,
2967
- kind: (lastEdit.fuzzy_match ? 'fuzzy' : 'exact'),
2968
- candidates: parsed.metadata.candidates,
2969
- },
2970
- };
2971
- }
2972
- return { success: parsed.success === true };
2973
- }
2974
- /** Generate a brief summary of conversation history */
2975
- function truncateRedactedSummary(text, maxLength) {
2976
- const redacted = (0, session_storage_1.redactTraceText)(text);
2977
- if (redacted.length <= maxLength)
2978
- return redacted;
2979
- let truncated = redacted.slice(0, maxLength);
2980
- for (const marker of ['[REDACTED_SECRET]']) {
2981
- const markerStart = truncated.indexOf(marker.slice(0, 6));
2982
- if (markerStart >= 0 && !truncated.includes(marker)) {
2983
- truncated = `${truncated.slice(0, markerStart)}${marker}`;
2984
- break;
2985
- }
2986
- }
2987
- return `${truncated}...`;
2988
- }
2989
- function generateHistorySummary(messages) {
2990
- const userMsgs = messages.filter(m => m.role === 'user' && m.content);
2991
- const assistantMsgsWithTools = messages.filter(m => m.role === 'assistant' && m.tool_calls && m.tool_calls.length > 0);
2992
- // Extract topics from first few user messages
2993
- const topics = userMsgs.slice(0, 3).map(m => {
2994
- return truncateRedactedSummary(m.content || '', 40);
2995
- });
2996
- // Extract tools used
2997
- const toolsUsed = assistantMsgsWithTools.flatMap(m => m.tool_calls?.map(tc => tc.function.name) || []);
2998
- const uniqueTools = [...new Set(toolsUsed)];
2999
- // Build summary
3000
- const parts = [];
3001
- if (topics.length > 0) {
3002
- parts.push(`Topics: ${topics.join('; ')}`);
3003
- }
3004
- if (uniqueTools.length > 0) {
3005
- parts.push(`Tools: ${uniqueTools.join(', ')}`);
3006
- }
3007
- if (parts.length === 0) {
3008
- return 'No significant activity';
3009
- }
3010
- return parts.join('. ');
3011
- }
3012
- function generateRestoredSessionEventSummary(messages) {
3013
- const assistantMsgsWithTools = messages.filter(m => m.role === 'assistant' && m.tool_calls && m.tool_calls.length > 0);
3014
- const toolsUsed = assistantMsgsWithTools.flatMap(m => m.tool_calls?.map(tc => tc.function.name) || []);
3015
- const uniqueTools = [...new Set(toolsUsed)].slice(0, 8);
3016
- if (uniqueTools.length === 0)
3017
- return undefined;
3018
- return `Tools: ${uniqueTools.join(', ')}`;
3019
- }
3020
- function continueAsSlashChat(name, args) {
3021
- const trimmed = args.trim();
3022
- return {
3023
- success: true,
3024
- continueAsChat: true,
3025
- chatInput: `/${name}${trimmed ? ` ${trimmed}` : ''}`,
3026
- };
15
+ const registry_1 = require("./registry");
16
+ const core_command_handlers_1 = require("./core-command-handlers");
17
+ const workflow_commands_1 = require("./workflow-commands");
18
+ const session_commands_1 = require("./session-commands");
19
+ const context_commands_1 = require("./context-commands");
20
+ const tool_commands_1 = require("./tool-commands");
21
+ const model_commands_1 = require("./model-commands");
22
+ const system_commands_1 = require("./system-commands");
23
+ const diagnostic_commands_1 = require("./diagnostic-commands");
24
+ const legacy_commands_1 = require("./legacy-commands");
25
+ function getVisibleCommands(renderer) {
26
+ return (0, core_command_handlers_1.sortCommands)(COMMANDS.filter(command => !command.isHidden &&
27
+ command.audience !== 'compatibility' &&
28
+ command.audience !== 'internal' &&
29
+ (!renderer || !command.rendererScope || command.rendererScope.includes(renderer))));
3027
30
  }
3028
- // ============================================================================
3029
- // 命令注册表
3030
- // ============================================================================
3031
- const COMMANDS = [
3032
- // Coding workflows
3033
- {
3034
- name: 'target',
3035
- aliases: ['goal'],
3036
- description: 'Create, view, pause, resume, or clear a persistent goal target',
3037
- argumentHint: '[objective | pause | resume | clear --yes | status | edit <text> | replace <text> | confirm <criterion-id> | budget <tokens>]',
3038
- category: 'workflow',
3039
- priority: 3,
3040
- type: 'builtin',
3041
- execution: 'builtin',
3042
- risk: 'state-write',
3043
- execute: () => ({
3044
- success: false,
3045
- error: '/target must be routed through the shared AgentRuntimeController.',
3046
- }),
3047
- },
3048
- {
3049
- name: 'diff',
3050
- description: 'Summarize current git workspace changes and touched files',
3051
- argumentHint: '[--max-files N]',
3052
- category: 'workflow',
3053
- priority: 5,
3054
- type: 'builtin',
3055
- execution: 'builtin',
3056
- risk: 'read-only',
3057
- execute: (ctx, args) => handleDiff(ctx, args),
3058
- },
3059
- {
3060
- name: 'commit',
3061
- description: 'Create a read-only commit plan and suggested message for current changes',
3062
- argumentHint: '[--max-files N]',
3063
- category: 'workflow',
3064
- priority: 8,
3065
- type: 'builtin',
3066
- execution: 'builtin',
3067
- risk: 'read-only',
3068
- execute: (ctx, args) => handleCommitPlan(ctx, args),
3069
- },
3070
- {
3071
- name: 'review',
3072
- description: 'Review the current change or requested files',
3073
- argumentHint: '[scope]',
3074
- category: 'workflow',
3075
- priority: 10,
3076
- type: 'chat',
3077
- execution: 'agent-workflow',
3078
- risk: 'read-only',
3079
- execute: (_ctx, args) => continueAsSlashChat('review', args),
3080
- },
3081
- {
3082
- name: 'security',
3083
- aliases: ['audit'],
3084
- description: 'Review code or dependencies for security risks',
3085
- argumentHint: '[scope]',
3086
- category: 'workflow',
3087
- priority: 20,
3088
- type: 'chat',
3089
- execution: 'agent-workflow',
3090
- risk: 'read-only',
3091
- execute: (_ctx, args) => continueAsSlashChat('security', args),
3092
- },
3093
- {
3094
- name: 'test-gen',
3095
- aliases: ['tests'],
3096
- description: 'Generate or improve tests for a target area',
3097
- argumentHint: '[scope]',
3098
- category: 'workflow',
3099
- priority: 30,
3100
- type: 'chat',
3101
- execution: 'agent-workflow',
3102
- risk: 'state-write',
3103
- execute: (_ctx, args) => continueAsSlashChat('test-gen', args),
3104
- },
3105
- {
3106
- name: 'todos',
3107
- aliases: ['todo'],
3108
- description: 'Show current agent todo state',
3109
- category: 'workflow',
3110
- priority: 40,
3111
- type: 'builtin',
3112
- execution: 'builtin',
3113
- risk: 'read-only',
3114
- execute: ctx => handleTodos(ctx),
3115
- },
3116
- // Sessions and context lifecycle
3117
- {
3118
- name: 'resume',
3119
- description: 'Resume a previous session',
3120
- argumentHint: '[number|session-id|name]',
3121
- category: 'session',
3122
- priority: 10,
3123
- type: 'builtin',
3124
- execution: 'builtin',
3125
- risk: 'state-write',
3126
- execute: (ctx, args) => handleResume(ctx, args),
3127
- },
3128
- {
3129
- name: 'sessions',
3130
- description: 'List recent sessions, or search by file/tool/keyword',
3131
- argumentHint: '[<query>|--all]',
3132
- category: 'session',
3133
- priority: 20,
3134
- type: 'builtin',
3135
- execution: 'builtin',
3136
- risk: 'read-only',
3137
- execute: (ctx, args) => handleSessions(ctx, args),
3138
- },
3139
- {
3140
- name: 'session-rename',
3141
- aliases: ['rename-session'],
3142
- description: 'Rename a saved session',
3143
- argumentHint: '<number|session-id|name> <new name>',
3144
- category: 'session',
3145
- priority: 30,
3146
- type: 'builtin',
3147
- execution: 'builtin',
3148
- risk: 'state-write',
3149
- execute: (ctx, args) => handleSessionRename(ctx, args),
3150
- },
3151
- {
3152
- name: 'compact',
3153
- description: 'Compact conversation history to reduce context size',
3154
- argumentHint: '[threshold]',
3155
- category: 'session',
3156
- priority: 40,
3157
- type: 'builtin',
3158
- execution: 'builtin',
3159
- risk: 'state-write',
3160
- execute: (ctx, args) => handleCompact(ctx, args),
3161
- },
3162
- {
3163
- name: 'context-clear',
3164
- description: 'Clear current in-memory model context; preserve saved session history',
3165
- argumentHint: '--yes',
3166
- category: 'session',
3167
- priority: 50,
3168
- type: 'builtin',
3169
- execution: 'builtin',
3170
- risk: 'destructive',
3171
- execute: (ctx, args) => handleContextClear(ctx, args),
3172
- },
3173
- {
3174
- name: 'clear-history',
3175
- aliases: ['reset'],
3176
- description: 'Deprecated alias for clearing only the current in-memory model context',
3177
- argumentHint: '--yes',
3178
- category: 'legacy',
3179
- priority: 50,
3180
- type: 'builtin',
3181
- isHidden: true,
3182
- execution: 'builtin',
3183
- risk: 'destructive',
3184
- deprecated: { since: 'v0.1.1', replacement: '/context-clear', removeIn: 'v0.3.0' },
3185
- execute: (ctx, args) => handleContextClear(ctx, args),
3186
- },
3187
- // Harness, memory, and skills
3188
- {
3189
- name: 'harness',
3190
- description: 'Show Context Harness state, or `/harness explain` for prompt assembly details',
3191
- argumentHint: '[explain]',
3192
- category: 'context',
3193
- priority: 10,
3194
- type: 'builtin',
3195
- execution: 'builtin',
3196
- risk: 'read-only',
3197
- execute: (ctx, args) => showHarness(ctx, args),
3198
- },
3199
- {
3200
- name: 'skills',
3201
- description: 'List loaded skills (built-in / user / project)',
3202
- category: 'context',
3203
- priority: 20,
3204
- type: 'builtin',
3205
- execution: 'builtin',
3206
- risk: 'read-only',
3207
- execute: ctx => handleSkills(ctx),
3208
- },
3209
- {
3210
- name: 'skill',
3211
- aliases: ['use-skill', 'activate-skill'],
3212
- description: 'Activate a loaded skill for one chat turn',
3213
- argumentHint: '<name> <task>',
3214
- category: 'context',
3215
- priority: 21,
3216
- type: 'chat',
3217
- execution: 'agent-workflow',
3218
- risk: 'state-write',
3219
- execute: (ctx, args) => handleSkill(ctx, args),
3220
- },
3221
- {
3222
- name: 'memory',
3223
- description: 'Show memory status, or `/memory reindex` to rebuild semantic index',
3224
- argumentHint: '[reindex]',
3225
- category: 'context',
3226
- priority: 30,
3227
- type: 'builtin',
3228
- execution: 'builtin',
3229
- risk: 'state-write',
3230
- execute: (ctx, args) => handleMemory(ctx, args),
3231
- },
3232
- // Tools and safety
3233
- {
3234
- name: 'tools',
3235
- aliases: ['tool'],
3236
- description: 'List available built-in and MCP tools',
3237
- category: 'tools',
3238
- priority: 10,
3239
- type: 'builtin',
3240
- execution: 'builtin',
3241
- risk: 'read-only',
3242
- execute: ctx => handleTools(ctx),
3243
- },
3244
- {
3245
- name: 'edit-preview',
3246
- description: 'Preview the last edit_file match candidates without writing',
3247
- category: 'tools',
3248
- priority: 15,
3249
- type: 'builtin',
3250
- execution: 'builtin',
3251
- risk: 'read-only',
3252
- execute: ctx => handleEditPreview(ctx),
3253
- },
3254
- {
3255
- name: 'mcp',
3256
- description: 'Show connected MCP servers and their status',
3257
- category: 'tools',
3258
- priority: 20,
3259
- type: 'builtin',
3260
- execution: 'builtin',
3261
- risk: 'read-only',
3262
- execute: ctx => handleMcp(ctx),
3263
- },
3264
- {
3265
- name: 'safety',
3266
- description: 'Show safety checker status and audit summary',
3267
- category: 'tools',
3268
- priority: 30,
3269
- type: 'builtin',
3270
- execution: 'builtin',
3271
- risk: 'read-only',
3272
- execute: ctx => showSafety(ctx),
3273
- },
3274
- // Model and runtime configuration
3275
- {
3276
- name: 'model',
3277
- description: 'Show or change the current model',
3278
- argumentHint: '[model|info]',
3279
- category: 'model',
3280
- priority: 10,
3281
- type: 'builtin',
3282
- execution: 'builtin',
3283
- risk: 'state-write',
3284
- execute: (ctx, args) => handleModel(ctx, args),
3285
- },
3286
- {
3287
- name: 'models',
3288
- description: 'Switch the current model interactively',
3289
- argumentHint: '',
3290
- category: 'model',
3291
- priority: 10,
3292
- type: 'builtin',
3293
- execution: 'builtin',
3294
- risk: 'state-write',
3295
- execute: (ctx, args) => handleModels(ctx, args),
3296
- },
3297
- {
3298
- name: 'mode',
3299
- aliases: ['perm'],
3300
- description: 'Show or change tool permission mode',
3301
- argumentHint: '[default|accept-edits|plan|auto|next]',
3302
- category: 'model',
3303
- priority: 20,
3304
- type: 'builtin',
3305
- execution: 'builtin',
3306
- risk: 'state-write',
3307
- execute: (ctx, args) => handleMode(ctx, args),
3308
- },
3309
- {
3310
- name: 'config',
3311
- description: 'Show current configuration',
3312
- category: 'model',
3313
- priority: 30,
3314
- type: 'builtin',
3315
- execution: 'builtin',
3316
- risk: 'read-only',
3317
- execute: ctx => showConfig(ctx),
3318
- },
3319
- // System commands
3320
- {
3321
- name: 'help',
3322
- aliases: ['h'],
3323
- description: 'Show available commands',
3324
- category: 'system',
3325
- priority: 10,
3326
- type: 'builtin',
3327
- execution: 'builtin',
3328
- risk: 'read-only',
3329
- execute: ctx => showHelp(ctx),
3330
- },
3331
- {
3332
- name: 'status',
3333
- aliases: ['s'],
3334
- description: 'Show system status overview',
3335
- category: 'system',
3336
- priority: 20,
3337
- type: 'builtin',
3338
- execution: 'builtin',
3339
- risk: 'read-only',
3340
- execute: ctx => showStatus(ctx),
3341
- },
3342
- {
3343
- name: 'clear',
3344
- description: 'Clear the current view without deleting session data',
3345
- category: 'system',
3346
- priority: 30,
3347
- type: 'builtin',
3348
- execution: 'renderer-local',
3349
- risk: 'read-only',
3350
- rendererScope: ['tui', 'terminal'],
3351
- execute: ctx => {
3352
- ctx.clearView?.();
3353
- return { success: true };
3354
- },
3355
- },
3356
- {
3357
- name: 'tool-output',
3358
- description: 'Set the TUI tool output presentation mode',
3359
- argumentHint: '[adaptive|collapsed|full]',
3360
- category: 'system',
3361
- priority: 32,
3362
- type: 'builtin',
3363
- execution: 'renderer-local',
3364
- risk: 'read-only',
3365
- rendererScope: ['tui'],
3366
- execute: () => ({ success: true }),
3367
- },
3368
- {
3369
- name: 'permissions',
3370
- description: 'Set the tool confirmation policy (TUI). No argument opens a picker; with an argument applies immediately.',
3371
- argumentHint: '[allow|ask|deny]',
3372
- category: 'system',
3373
- priority: 33,
3374
- type: 'builtin',
3375
- execution: 'renderer-local',
3376
- risk: 'state-write',
3377
- rendererScope: ['tui'],
3378
- execute: () => ({ success: true }),
3379
- },
3380
- {
3381
- name: 'redraw',
3382
- description: 'Redraw the TUI-owned live region',
3383
- category: 'system',
3384
- priority: 34,
3385
- type: 'builtin',
3386
- execution: 'renderer-local',
3387
- risk: 'read-only',
3388
- rendererScope: ['tui'],
3389
- execute: () => ({ success: true }),
3390
- },
3391
- {
3392
- name: 'exit',
3393
- aliases: ['quit', 'q'],
3394
- description: 'Shutdown and exit',
3395
- category: 'system',
3396
- priority: 40,
3397
- type: 'builtin',
3398
- execution: 'builtin',
3399
- risk: 'state-write',
3400
- execute: ctx => handleExit(ctx),
3401
- },
3402
- // Diagnostics
3403
- {
3404
- name: 'doctor',
3405
- aliases: ['diag', 'diagnose'],
3406
- description: 'Run configuration, tools, MCP, skills, session, and harness diagnostics',
3407
- category: 'diagnostics',
3408
- priority: 5,
3409
- type: 'builtin',
3410
- execution: 'builtin',
3411
- risk: 'read-only',
3412
- execute: ctx => handleDoctor(ctx),
3413
- },
3414
- {
3415
- name: 'storage',
3416
- description: 'Inspect, repair, or clean Orion Code storage layout',
3417
- argumentHint: '[doctor|repair [--dry-run|--yes] [--plan=<token>]|cleanup [--dry-run|--yes] [--plan=<token>]]',
3418
- category: 'diagnostics',
3419
- priority: 8,
3420
- type: 'builtin',
3421
- execution: 'builtin',
3422
- risk: 'destructive',
3423
- execute: (ctx, args) => handleStorage(ctx, args),
3424
- },
3425
- {
3426
- name: 'usage',
3427
- aliases: ['stats'],
3428
- description: 'Show detailed usage statistics',
3429
- category: 'diagnostics',
3430
- priority: 10,
3431
- type: 'builtin',
3432
- execution: 'builtin',
3433
- risk: 'read-only',
3434
- execute: ctx => handleUsage(ctx),
3435
- },
3436
- {
3437
- name: 'loop-stats',
3438
- aliases: ['loop'],
3439
- description: 'Show detailed agent-loop budget and efficiency diagnostics',
3440
- category: 'diagnostics',
3441
- priority: 12,
3442
- type: 'builtin',
3443
- execution: 'builtin',
3444
- risk: 'read-only',
3445
- execute: ctx => handleLoopStats(ctx),
3446
- },
3447
- {
3448
- name: 'trace',
3449
- description: 'Show structured event timeline for the latest or selected turn',
3450
- argumentHint: '[latest|turn-id]',
3451
- category: 'diagnostics',
3452
- priority: 14,
3453
- type: 'builtin',
3454
- execution: 'builtin',
3455
- risk: 'read-only',
3456
- execute: (ctx, args) => handleTrace(ctx, args),
3457
- },
3458
- {
3459
- name: 'last-tool',
3460
- aliases: ['tool-last'],
3461
- description: 'Show the latest tool call/result with full inspection hints',
3462
- category: 'diagnostics',
3463
- priority: 15,
3464
- type: 'builtin',
3465
- execution: 'builtin',
3466
- risk: 'read-only',
3467
- execute: (ctx, args) => handleLastTool(ctx, args),
3468
- },
3469
- {
3470
- name: 'artifacts',
3471
- aliases: ['artifact'],
3472
- description: 'List or inspect saved full tool outputs for this project',
3473
- argumentHint: '[show <id|prefix> --full]',
3474
- category: 'diagnostics',
3475
- priority: 16,
3476
- type: 'builtin',
3477
- execution: 'builtin',
3478
- risk: 'read-only',
3479
- execute: (ctx, args) => handleArtifacts(ctx, args),
3480
- },
3481
- {
3482
- name: 'checkpoint',
3483
- aliases: ['checkpoints'],
3484
- description: 'List or restore file checkpoints created before agent edits',
3485
- argumentHint: '[list|restore <turn-id|prefix> --yes]',
3486
- category: 'diagnostics',
3487
- priority: 18,
3488
- type: 'builtin',
3489
- execution: 'builtin',
3490
- risk: 'destructive',
3491
- execute: (ctx, args) => handleCheckpoint(ctx, args),
3492
- },
3493
- {
3494
- name: 'cost',
3495
- description: 'Show session token usage',
3496
- category: 'diagnostics',
3497
- priority: 20,
3498
- type: 'builtin',
3499
- execution: 'builtin',
3500
- risk: 'read-only',
3501
- deprecated: { since: 'v0.1.1', replacement: '/usage', removeIn: 'v0.3.0' },
3502
- execute: ctx => handleCost(ctx),
3503
- },
3504
- {
3505
- name: 'agents',
3506
- description: 'List registered agents and their status',
3507
- category: 'diagnostics',
3508
- priority: 30,
3509
- type: 'builtin',
3510
- execution: 'builtin',
3511
- risk: 'read-only',
3512
- isHidden: true,
3513
- execute: ctx => showAgents(ctx),
3514
- },
3515
- {
3516
- name: 'migrate',
3517
- description: 'Migrate data from OpenHorse to Orion Code',
3518
- argumentHint: 'openhorse [--dry-run | --yes] [--include-env] [--include-project-files]',
3519
- category: 'diagnostics',
3520
- priority: 32,
3521
- type: 'builtin',
3522
- execution: 'builtin',
3523
- risk: 'destructive',
3524
- execute: (ctx, args) => (0, command_1.handleMigrateCommand)(ctx, args),
3525
- },
3526
- // Legacy commands kept executable for compatibility, but not shown in help/palette.
3527
- {
3528
- name: 'task',
3529
- description: 'Submit or list tasks',
3530
- params: [{ name: 'action', description: 'list | <task-name>', required: false }],
3531
- category: 'legacy',
3532
- type: 'builtin',
3533
- isHidden: true,
3534
- execution: 'builtin',
3535
- risk: 'state-write',
3536
- deprecated: { since: 'v0.1.1', replacement: '/target', removeIn: 'v0.3.0' },
3537
- execute: (ctx, args) => handleTask(ctx, args),
3538
- },
3539
- {
3540
- name: 'run',
3541
- description: 'Create and run a task through Agent + LLM',
3542
- params: [{ name: 'description', description: 'Task description', required: true }],
3543
- category: 'legacy',
3544
- type: 'builtin',
3545
- isHidden: true,
3546
- execution: 'agent-workflow',
3547
- risk: 'state-write',
3548
- deprecated: { since: 'v0.1.1', replacement: '/target', removeIn: 'v0.3.0' },
3549
- execute: (ctx, args) => handleRun(ctx, args),
3550
- },
3551
- {
3552
- name: 'chat',
3553
- description: 'Send a message to the LLM',
3554
- params: [{ name: 'message', description: 'Message to send', required: true }],
3555
- category: 'legacy',
3556
- type: 'chat',
3557
- isHidden: true,
3558
- execution: 'agent-workflow',
3559
- risk: 'state-write',
3560
- deprecated: { since: 'v0.1.1', removeIn: 'v0.3.0' },
3561
- execute: (ctx, args) => ({ success: true, continueAsChat: true, chatInput: args }),
3562
- },
31
+ const SYSTEM_COMMANDS = (0, system_commands_1.createSystemCommands)(getVisibleCommands);
32
+ const COMMAND_DEFINITIONS = [
33
+ ...workflow_commands_1.WORKFLOW_COMMANDS,
34
+ ...session_commands_1.SESSION_COMMANDS,
35
+ ...context_commands_1.CONTEXT_COMMANDS,
36
+ ...tool_commands_1.TOOL_COMMANDS,
37
+ ...model_commands_1.MODEL_COMMANDS,
38
+ ...SYSTEM_COMMANDS,
39
+ ...diagnostic_commands_1.DIAGNOSTIC_COMMANDS,
40
+ ...legacy_commands_1.LEGACY_COMMANDS,
3563
41
  ];
3564
- // ============================================================================
3565
- // 导出
3566
- // ============================================================================
42
+ const COMMANDS = (0, registry_1.registerBuiltinCommands)(COMMAND_DEFINITIONS);
3567
43
  function getCommands() {
3568
- return sortCommands(COMMANDS);
3569
- }
3570
- function getVisibleCommands(renderer) {
3571
- return sortCommands(COMMANDS.filter(command => !command.isHidden &&
3572
- (!renderer || !command.rendererScope || command.rendererScope.includes(renderer))));
44
+ return (0, core_command_handlers_1.sortCommands)(COMMANDS);
3573
45
  }
3574
46
  function findCommand(name) {
3575
- return COMMANDS.find(c => c.name === name || c.aliases?.includes(name));
47
+ const normalized = name.toLowerCase();
48
+ return COMMANDS.find(command => command.name.toLowerCase() === normalized ||
49
+ command.aliases?.some(alias => alias.toLowerCase() === normalized) ||
50
+ command.compatibilityAliases?.some(alias => alias.name.toLowerCase() === normalized));
3576
51
  }
3577
52
  function getCommandNames() {
3578
- return getVisibleCommands().map(c => c.name);
53
+ return getVisibleCommands().map(command => command.name);
3579
54
  }
55
+ var core_command_handlers_2 = require("./core-command-handlers");
56
+ Object.defineProperty(exports, "executeChat", { enumerable: true, get: function () { return core_command_handlers_2.handleChat; } });
57
+ Object.defineProperty(exports, "getCommandCategoryLabel", { enumerable: true, get: function () { return core_command_handlers_2.getCommandCategoryLabel; } });
58
+ Object.defineProperty(exports, "sortCommands", { enumerable: true, get: function () { return core_command_handlers_2.sortCommands; } });
3580
59
  //# sourceMappingURL=index.js.map