@orion-agents/orion-code 0.1.9 → 0.2.2

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 (757) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/README.md +142 -323
  3. package/README.zh-CN.md +118 -578
  4. package/dist/cli.js +65 -84
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands/context-commands.d.ts.map +1 -1
  7. package/dist/commands/context-commands.js +14 -7
  8. package/dist/commands/context-commands.js.map +1 -1
  9. package/dist/commands/context-tool-command-handlers.d.ts +4 -5
  10. package/dist/commands/context-tool-command-handlers.d.ts.map +1 -1
  11. package/dist/commands/context-tool-command-handlers.js +132 -208
  12. package/dist/commands/context-tool-command-handlers.js.map +1 -1
  13. package/dist/commands/core-command-handlers.d.ts +3 -6
  14. package/dist/commands/core-command-handlers.d.ts.map +1 -1
  15. package/dist/commands/core-command-handlers.js +66 -664
  16. package/dist/commands/core-command-handlers.js.map +1 -1
  17. package/dist/commands/diagnostic-command-handlers.d.ts +1 -2
  18. package/dist/commands/diagnostic-command-handlers.d.ts.map +1 -1
  19. package/dist/commands/diagnostic-command-handlers.js +3 -17
  20. package/dist/commands/diagnostic-command-handlers.js.map +1 -1
  21. package/dist/commands/diagnostic-commands.d.ts.map +1 -1
  22. package/dist/commands/diagnostic-commands.js +0 -45
  23. package/dist/commands/diagnostic-commands.js.map +1 -1
  24. package/dist/commands/index.d.ts +1 -1
  25. package/dist/commands/index.d.ts.map +1 -1
  26. package/dist/commands/index.js +2 -7
  27. package/dist/commands/index.js.map +1 -1
  28. package/dist/commands/model-command-handlers.d.ts +1 -1
  29. package/dist/commands/model-command-handlers.js +2 -2
  30. package/dist/commands/model-command-handlers.js.map +1 -1
  31. package/dist/commands/model-commands.d.ts.map +1 -1
  32. package/dist/commands/model-commands.js +0 -11
  33. package/dist/commands/model-commands.js.map +1 -1
  34. package/dist/commands/registry.d.ts.map +1 -1
  35. package/dist/commands/registry.js +1 -139
  36. package/dist/commands/registry.js.map +1 -1
  37. package/dist/commands/session-command-handlers.d.ts +1 -1
  38. package/dist/commands/session-command-handlers.d.ts.map +1 -1
  39. package/dist/commands/session-command-handlers.js +52 -214
  40. package/dist/commands/session-command-handlers.js.map +1 -1
  41. package/dist/commands/session-commands.d.ts.map +1 -1
  42. package/dist/commands/session-commands.js +0 -48
  43. package/dist/commands/session-commands.js.map +1 -1
  44. package/dist/commands/target-command.d.ts +9 -15
  45. package/dist/commands/target-command.d.ts.map +1 -1
  46. package/dist/commands/target-command.js +16 -130
  47. package/dist/commands/target-command.js.map +1 -1
  48. package/dist/commands/tool-commands.d.ts.map +1 -1
  49. package/dist/commands/tool-commands.js +0 -10
  50. package/dist/commands/tool-commands.js.map +1 -1
  51. package/dist/commands/types.d.ts +10 -14
  52. package/dist/commands/types.d.ts.map +1 -1
  53. package/dist/commands/types.js +1 -1
  54. package/dist/commands/types.js.map +1 -1
  55. package/dist/commands/workflow-command-handlers.d.ts.map +1 -1
  56. package/dist/commands/workflow-command-handlers.js +1 -3
  57. package/dist/commands/workflow-command-handlers.js.map +1 -1
  58. package/dist/commands/workflow-commands.d.ts.map +1 -1
  59. package/dist/commands/workflow-commands.js +2 -24
  60. package/dist/commands/workflow-commands.js.map +1 -1
  61. package/dist/framework/agent-mode.d.ts +2 -3
  62. package/dist/framework/agent-mode.d.ts.map +1 -1
  63. package/dist/framework/agent-mode.js +8 -31
  64. package/dist/framework/agent-mode.js.map +1 -1
  65. package/dist/framework/index.d.ts +3 -3
  66. package/dist/framework/index.d.ts.map +1 -1
  67. package/dist/framework/index.js +6 -9
  68. package/dist/framework/index.js.map +1 -1
  69. package/dist/framework/loop-budget-contract.d.ts +20 -0
  70. package/dist/framework/loop-budget-contract.d.ts.map +1 -0
  71. package/dist/framework/loop-budget-contract.js +13 -0
  72. package/dist/framework/loop-budget-contract.js.map +1 -0
  73. package/dist/framework/prompt.d.ts.map +1 -1
  74. package/dist/framework/prompt.js +5 -4
  75. package/dist/framework/prompt.js.map +1 -1
  76. package/dist/framework/query.d.ts +45 -22
  77. package/dist/framework/query.d.ts.map +1 -1
  78. package/dist/framework/query.js +64 -52
  79. package/dist/framework/query.js.map +1 -1
  80. package/dist/framework/store.d.ts +4 -2
  81. package/dist/framework/store.d.ts.map +1 -1
  82. package/dist/framework/store.js +1 -0
  83. package/dist/framework/store.js.map +1 -1
  84. package/dist/framework/tool-call-orchestrator.d.ts +80 -0
  85. package/dist/framework/tool-call-orchestrator.d.ts.map +1 -0
  86. package/dist/framework/tool-call-orchestrator.js +192 -0
  87. package/dist/framework/tool-call-orchestrator.js.map +1 -0
  88. package/dist/framework/tool-state.d.ts +12 -11
  89. package/dist/framework/tool-state.d.ts.map +1 -1
  90. package/dist/framework/tool-state.js +36 -28
  91. package/dist/framework/tool-state.js.map +1 -1
  92. package/dist/framework/tool.d.ts +0 -9
  93. package/dist/framework/tool.d.ts.map +1 -1
  94. package/dist/framework/tool.js.map +1 -1
  95. package/dist/index.d.ts +70 -26
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +64 -65
  98. package/dist/index.js.map +1 -1
  99. package/dist/print-ui/launch.d.ts.map +1 -1
  100. package/dist/print-ui/launch.js +9 -2
  101. package/dist/print-ui/launch.js.map +1 -1
  102. package/dist/product/paths.d.ts +7 -0
  103. package/dist/product/paths.d.ts.map +1 -1
  104. package/dist/product/paths.js +19 -0
  105. package/dist/product/paths.js.map +1 -1
  106. package/dist/runtime/agent-loop.d.ts +80 -0
  107. package/dist/runtime/agent-loop.d.ts.map +1 -0
  108. package/dist/runtime/agent-loop.js +419 -0
  109. package/dist/runtime/agent-loop.js.map +1 -0
  110. package/dist/runtime/agent-runtime-controller.d.ts +10 -57
  111. package/dist/runtime/agent-runtime-controller.d.ts.map +1 -1
  112. package/dist/runtime/agent-runtime-controller.js +270 -1216
  113. package/dist/runtime/agent-runtime-controller.js.map +1 -1
  114. package/dist/runtime/agent-runtime-protocol.d.ts +4 -5
  115. package/dist/runtime/agent-runtime-protocol.d.ts.map +1 -1
  116. package/dist/runtime/agent-runtime-protocol.js.map +1 -1
  117. package/dist/runtime/agent-runtime-runner.d.ts +36 -0
  118. package/dist/runtime/agent-runtime-runner.d.ts.map +1 -0
  119. package/dist/runtime/agent-runtime-runner.js +3 -0
  120. package/dist/runtime/agent-runtime-runner.js.map +1 -0
  121. package/dist/runtime/batch-read-service.d.ts +29 -0
  122. package/dist/runtime/batch-read-service.d.ts.map +1 -0
  123. package/dist/runtime/batch-read-service.js +212 -0
  124. package/dist/runtime/batch-read-service.js.map +1 -0
  125. package/dist/runtime/builtin-tool-provider.d.ts +30 -0
  126. package/dist/runtime/builtin-tool-provider.d.ts.map +1 -0
  127. package/dist/runtime/builtin-tool-provider.js +233 -0
  128. package/dist/runtime/builtin-tool-provider.js.map +1 -0
  129. package/dist/runtime/capabilities/compiler.d.ts +11 -0
  130. package/dist/runtime/capabilities/compiler.d.ts.map +1 -0
  131. package/dist/runtime/capabilities/compiler.js +719 -0
  132. package/dist/runtime/capabilities/compiler.js.map +1 -0
  133. package/dist/runtime/capabilities/index.d.ts +3 -0
  134. package/dist/runtime/capabilities/index.d.ts.map +1 -0
  135. package/dist/runtime/capabilities/index.js +9 -0
  136. package/dist/runtime/capabilities/index.js.map +1 -0
  137. package/dist/runtime/capabilities/types.d.ts +175 -0
  138. package/dist/runtime/capabilities/types.d.ts.map +1 -0
  139. package/dist/runtime/capabilities/types.js +3 -0
  140. package/dist/runtime/capabilities/types.js.map +1 -0
  141. package/dist/runtime/capability-receipt-journal.d.ts +29 -0
  142. package/dist/runtime/capability-receipt-journal.d.ts.map +1 -0
  143. package/dist/runtime/capability-receipt-journal.js +264 -0
  144. package/dist/runtime/capability-receipt-journal.js.map +1 -0
  145. package/dist/runtime/capability-step-factory.d.ts +73 -0
  146. package/dist/runtime/capability-step-factory.d.ts.map +1 -0
  147. package/dist/runtime/capability-step-factory.js +302 -0
  148. package/dist/runtime/capability-step-factory.js.map +1 -0
  149. package/dist/runtime/compact-transaction.d.ts +225 -0
  150. package/dist/runtime/compact-transaction.d.ts.map +1 -0
  151. package/dist/runtime/compact-transaction.js +622 -0
  152. package/dist/runtime/compact-transaction.js.map +1 -0
  153. package/dist/runtime/composer/buffer.d.ts +3 -4
  154. package/dist/runtime/composer/buffer.d.ts.map +1 -1
  155. package/dist/runtime/composer/buffer.js +3 -4
  156. package/dist/runtime/composer/buffer.js.map +1 -1
  157. package/dist/runtime/composer/grapheme.d.ts +2 -4
  158. package/dist/runtime/composer/grapheme.d.ts.map +1 -1
  159. package/dist/runtime/composer/grapheme.js +2 -4
  160. package/dist/runtime/composer/grapheme.js.map +1 -1
  161. package/dist/runtime/composer/layout.d.ts +1 -3
  162. package/dist/runtime/composer/layout.d.ts.map +1 -1
  163. package/dist/runtime/composer/layout.js +1 -3
  164. package/dist/runtime/composer/layout.js.map +1 -1
  165. package/dist/runtime/core-tools/descriptors.d.ts +17 -0
  166. package/dist/runtime/core-tools/descriptors.d.ts.map +1 -0
  167. package/dist/runtime/core-tools/descriptors.js +185 -0
  168. package/dist/runtime/core-tools/descriptors.js.map +1 -0
  169. package/dist/runtime/first-party-core-provider.d.ts +55 -0
  170. package/dist/runtime/first-party-core-provider.d.ts.map +1 -0
  171. package/dist/runtime/first-party-core-provider.js +197 -0
  172. package/dist/runtime/first-party-core-provider.js.map +1 -0
  173. package/dist/runtime/first-party-long-tail-provider.d.ts +57 -0
  174. package/dist/runtime/first-party-long-tail-provider.d.ts.map +1 -0
  175. package/dist/runtime/first-party-long-tail-provider.js +238 -0
  176. package/dist/runtime/first-party-long-tail-provider.js.map +1 -0
  177. package/dist/runtime/first-party-tool-services.d.ts +43 -0
  178. package/dist/runtime/first-party-tool-services.d.ts.map +1 -0
  179. package/dist/runtime/first-party-tool-services.js +200 -0
  180. package/dist/runtime/first-party-tool-services.js.map +1 -0
  181. package/dist/runtime/first-party-tool-universe.d.ts +14 -0
  182. package/dist/runtime/first-party-tool-universe.d.ts.map +1 -0
  183. package/dist/runtime/first-party-tool-universe.js +20 -0
  184. package/dist/runtime/first-party-tool-universe.js.map +1 -0
  185. package/dist/runtime/goal-lifecycle-v2.d.ts +63 -0
  186. package/dist/runtime/goal-lifecycle-v2.d.ts.map +1 -0
  187. package/dist/runtime/goal-lifecycle-v2.js +253 -0
  188. package/dist/runtime/goal-lifecycle-v2.js.map +1 -0
  189. package/dist/runtime/goal-runtime-coordinator.d.ts +111 -0
  190. package/dist/runtime/goal-runtime-coordinator.d.ts.map +1 -0
  191. package/dist/runtime/goal-runtime-coordinator.js +511 -0
  192. package/dist/runtime/goal-runtime-coordinator.js.map +1 -0
  193. package/dist/runtime/harness-confluence.d.ts +165 -0
  194. package/dist/runtime/harness-confluence.d.ts.map +1 -0
  195. package/dist/runtime/harness-confluence.js +807 -0
  196. package/dist/runtime/harness-confluence.js.map +1 -0
  197. package/dist/runtime/harness-eval.d.ts +96 -0
  198. package/dist/runtime/harness-eval.d.ts.map +1 -0
  199. package/dist/runtime/harness-eval.js +181 -0
  200. package/dist/runtime/harness-eval.js.map +1 -0
  201. package/dist/runtime/harness-metrics.d.ts +202 -0
  202. package/dist/runtime/harness-metrics.d.ts.map +1 -0
  203. package/dist/runtime/harness-metrics.js +415 -0
  204. package/dist/runtime/harness-metrics.js.map +1 -0
  205. package/dist/runtime/legacy-session-importer.d.ts +99 -0
  206. package/dist/runtime/legacy-session-importer.d.ts.map +1 -0
  207. package/dist/runtime/legacy-session-importer.js +455 -0
  208. package/dist/runtime/legacy-session-importer.js.map +1 -0
  209. package/dist/runtime/legacy-thread-materializer.d.ts +72 -0
  210. package/dist/runtime/legacy-thread-materializer.d.ts.map +1 -0
  211. package/dist/runtime/legacy-thread-materializer.js +553 -0
  212. package/dist/runtime/legacy-thread-materializer.js.map +1 -0
  213. package/dist/runtime/long-tail-tools/descriptors.d.ts +23 -0
  214. package/dist/runtime/long-tail-tools/descriptors.d.ts.map +1 -0
  215. package/dist/runtime/long-tail-tools/descriptors.js +423 -0
  216. package/dist/runtime/long-tail-tools/descriptors.js.map +1 -0
  217. package/dist/runtime/loop-budget.d.ts +1 -1
  218. package/dist/runtime/loop-budget.d.ts.map +1 -1
  219. package/dist/runtime/loop-budget.js +2 -2
  220. package/dist/runtime/loop-budget.js.map +1 -1
  221. package/dist/runtime/mcp/first-party-mcp-adapter.d.ts +75 -0
  222. package/dist/runtime/mcp/first-party-mcp-adapter.d.ts.map +1 -0
  223. package/dist/runtime/mcp/first-party-mcp-adapter.js +484 -0
  224. package/dist/runtime/mcp/first-party-mcp-adapter.js.map +1 -0
  225. package/dist/runtime/mcp/first-party-mcp-config.d.ts +13 -0
  226. package/dist/runtime/mcp/first-party-mcp-config.d.ts.map +1 -0
  227. package/dist/runtime/mcp/first-party-mcp-config.js +139 -0
  228. package/dist/runtime/mcp/first-party-mcp-config.js.map +1 -0
  229. package/dist/runtime/mcp/index.d.ts +5 -0
  230. package/dist/runtime/mcp/index.d.ts.map +1 -0
  231. package/dist/{skills → runtime/mcp}/index.js +3 -9
  232. package/dist/runtime/mcp/index.js.map +1 -0
  233. package/dist/runtime/mcp/lazy-mcp-runtime.d.ts +95 -0
  234. package/dist/runtime/mcp/lazy-mcp-runtime.d.ts.map +1 -0
  235. package/dist/runtime/mcp/lazy-mcp-runtime.js +854 -0
  236. package/dist/runtime/mcp/lazy-mcp-runtime.js.map +1 -0
  237. package/dist/runtime/mcp/types.d.ts +128 -0
  238. package/dist/runtime/mcp/types.d.ts.map +1 -0
  239. package/dist/runtime/mcp/types.js +5 -0
  240. package/dist/runtime/mcp/types.js.map +1 -0
  241. package/dist/runtime/orion-runtime-v1.d.ts +322 -0
  242. package/dist/runtime/orion-runtime-v1.d.ts.map +1 -0
  243. package/dist/runtime/orion-runtime-v1.js +959 -0
  244. package/dist/runtime/orion-runtime-v1.js.map +1 -0
  245. package/dist/runtime/orion-session-runner.d.ts +38 -0
  246. package/dist/runtime/orion-session-runner.d.ts.map +1 -0
  247. package/dist/runtime/orion-session-runner.js +168 -0
  248. package/dist/runtime/orion-session-runner.js.map +1 -0
  249. package/dist/runtime/product-orion-runtime.d.ts +35 -0
  250. package/dist/runtime/product-orion-runtime.d.ts.map +1 -0
  251. package/dist/runtime/product-orion-runtime.js +1047 -0
  252. package/dist/runtime/product-orion-runtime.js.map +1 -0
  253. package/dist/runtime/prompts/index.d.ts +3 -0
  254. package/dist/runtime/prompts/index.d.ts.map +1 -0
  255. package/dist/{ink-ui/types.js → runtime/prompts/index.js} +3 -2
  256. package/dist/runtime/prompts/index.js.map +1 -0
  257. package/dist/runtime/prompts/prompt-registry.d.ts +22 -0
  258. package/dist/runtime/prompts/prompt-registry.d.ts.map +1 -0
  259. package/dist/runtime/prompts/prompt-registry.js +356 -0
  260. package/dist/runtime/prompts/prompt-registry.js.map +1 -0
  261. package/dist/runtime/prompts/types.d.ts +111 -0
  262. package/dist/runtime/prompts/types.d.ts.map +1 -0
  263. package/dist/runtime/prompts/types.js +5 -0
  264. package/dist/runtime/prompts/types.js.map +1 -0
  265. package/dist/runtime/protocol/canonical.d.ts +3 -0
  266. package/dist/runtime/protocol/canonical.d.ts.map +1 -0
  267. package/dist/runtime/protocol/canonical.js +21 -0
  268. package/dist/runtime/protocol/canonical.js.map +1 -0
  269. package/dist/runtime/protocol/index.d.ts +4 -0
  270. package/dist/runtime/protocol/index.d.ts.map +1 -0
  271. package/dist/runtime/protocol/index.js +16 -0
  272. package/dist/runtime/protocol/index.js.map +1 -0
  273. package/dist/runtime/protocol/runtime-protocol-v1.d.ts +671 -0
  274. package/dist/runtime/protocol/runtime-protocol-v1.d.ts.map +1 -0
  275. package/dist/runtime/protocol/runtime-protocol-v1.js +557 -0
  276. package/dist/runtime/protocol/runtime-protocol-v1.js.map +1 -0
  277. package/dist/runtime/release-receipts.d.ts +110 -0
  278. package/dist/runtime/release-receipts.d.ts.map +1 -0
  279. package/dist/runtime/release-receipts.js +305 -0
  280. package/dist/runtime/release-receipts.js.map +1 -0
  281. package/dist/runtime/resource-scope.d.ts +123 -0
  282. package/dist/runtime/resource-scope.d.ts.map +1 -0
  283. package/dist/runtime/resource-scope.js +363 -0
  284. package/dist/runtime/resource-scope.js.map +1 -0
  285. package/dist/runtime/runtime-event-buffer.d.ts +78 -0
  286. package/dist/runtime/runtime-event-buffer.d.ts.map +1 -0
  287. package/dist/runtime/runtime-event-buffer.js +237 -0
  288. package/dist/runtime/runtime-event-buffer.js.map +1 -0
  289. package/dist/runtime/runtime-services.d.ts +87 -0
  290. package/dist/runtime/runtime-services.d.ts.map +1 -0
  291. package/dist/runtime/runtime-services.js +180 -0
  292. package/dist/runtime/runtime-services.js.map +1 -0
  293. package/dist/runtime/session-history-recovery.d.ts +19 -0
  294. package/dist/runtime/session-history-recovery.d.ts.map +1 -0
  295. package/dist/runtime/session-history-recovery.js +45 -0
  296. package/dist/runtime/session-history-recovery.js.map +1 -0
  297. package/dist/runtime/skills/bounded-lru-cache.d.ts +34 -0
  298. package/dist/runtime/skills/bounded-lru-cache.d.ts.map +1 -0
  299. package/dist/runtime/skills/bounded-lru-cache.js +100 -0
  300. package/dist/runtime/skills/bounded-lru-cache.js.map +1 -0
  301. package/dist/runtime/skills/filesystem-skill-provider.d.ts +96 -0
  302. package/dist/runtime/skills/filesystem-skill-provider.d.ts.map +1 -0
  303. package/dist/runtime/skills/filesystem-skill-provider.js +829 -0
  304. package/dist/runtime/skills/filesystem-skill-provider.js.map +1 -0
  305. package/dist/runtime/skills/index.d.ts +5 -0
  306. package/dist/runtime/skills/index.d.ts.map +1 -0
  307. package/dist/{ink-ui/controllers/chat-controller.js → runtime/skills/index.js} +5 -2
  308. package/dist/runtime/skills/index.js.map +1 -0
  309. package/dist/runtime/skills/lazy-skill-runtime.d.ts +77 -0
  310. package/dist/runtime/skills/lazy-skill-runtime.d.ts.map +1 -0
  311. package/dist/runtime/skills/lazy-skill-runtime.js +673 -0
  312. package/dist/runtime/skills/lazy-skill-runtime.js.map +1 -0
  313. package/dist/runtime/skills/types.d.ts +137 -0
  314. package/dist/runtime/skills/types.d.ts.map +1 -0
  315. package/dist/runtime/skills/types.js +13 -0
  316. package/dist/runtime/skills/types.js.map +1 -0
  317. package/dist/runtime/step-snapshot.d.ts +183 -0
  318. package/dist/runtime/step-snapshot.d.ts.map +1 -0
  319. package/dist/runtime/step-snapshot.js +286 -0
  320. package/dist/runtime/step-snapshot.js.map +1 -0
  321. package/dist/runtime/subagent-thread-runtime.d.ts +239 -0
  322. package/dist/runtime/subagent-thread-runtime.d.ts.map +1 -0
  323. package/dist/runtime/subagent-thread-runtime.js +876 -0
  324. package/dist/runtime/subagent-thread-runtime.js.map +1 -0
  325. package/dist/runtime/subagents/index.d.ts +4 -1
  326. package/dist/runtime/subagents/index.d.ts.map +1 -1
  327. package/dist/runtime/subagents/index.js +10 -2
  328. package/dist/runtime/subagents/index.js.map +1 -1
  329. package/dist/runtime/subagents/parent-step-fork.d.ts +36 -0
  330. package/dist/runtime/subagents/parent-step-fork.d.ts.map +1 -0
  331. package/dist/runtime/subagents/parent-step-fork.js +83 -0
  332. package/dist/runtime/subagents/parent-step-fork.js.map +1 -0
  333. package/dist/runtime/subagents/production.d.ts +65 -46
  334. package/dist/runtime/subagents/production.d.ts.map +1 -1
  335. package/dist/runtime/subagents/production.js +494 -170
  336. package/dist/runtime/subagents/production.js.map +1 -1
  337. package/dist/runtime/subagents/receipt-journal.d.ts +20 -0
  338. package/dist/runtime/subagents/receipt-journal.d.ts.map +1 -0
  339. package/dist/runtime/subagents/receipt-journal.js +74 -0
  340. package/dist/runtime/subagents/receipt-journal.js.map +1 -0
  341. package/dist/runtime/subagents/runtime-contract.d.ts +29 -0
  342. package/dist/runtime/subagents/runtime-contract.d.ts.map +1 -0
  343. package/dist/runtime/subagents/runtime-contract.js +3 -0
  344. package/dist/runtime/subagents/runtime-contract.js.map +1 -0
  345. package/dist/runtime/subagents/runtime-integration.d.ts +41 -56
  346. package/dist/runtime/subagents/runtime-integration.d.ts.map +1 -1
  347. package/dist/runtime/subagents/runtime-integration.js +34 -198
  348. package/dist/runtime/subagents/runtime-integration.js.map +1 -1
  349. package/dist/runtime/subagents/supervisor.d.ts +19 -7
  350. package/dist/runtime/subagents/supervisor.d.ts.map +1 -1
  351. package/dist/runtime/subagents/supervisor.js +83 -40
  352. package/dist/runtime/subagents/supervisor.js.map +1 -1
  353. package/dist/runtime/subagents/types.d.ts +1 -1
  354. package/dist/runtime/subagents/types.js +1 -1
  355. package/dist/runtime/task-context-service.d.ts +91 -0
  356. package/dist/runtime/task-context-service.d.ts.map +1 -0
  357. package/dist/runtime/task-context-service.js +122 -0
  358. package/dist/runtime/task-context-service.js.map +1 -0
  359. package/dist/runtime/thread-admission.d.ts +130 -0
  360. package/dist/runtime/thread-admission.d.ts.map +1 -0
  361. package/dist/runtime/thread-admission.js +276 -0
  362. package/dist/runtime/thread-admission.js.map +1 -0
  363. package/dist/runtime/thread-compact-persistence.d.ts +50 -0
  364. package/dist/runtime/thread-compact-persistence.d.ts.map +1 -0
  365. package/dist/runtime/thread-compact-persistence.js +176 -0
  366. package/dist/runtime/thread-compact-persistence.js.map +1 -0
  367. package/dist/runtime/thread-event-store.d.ts +98 -0
  368. package/dist/runtime/thread-event-store.d.ts.map +1 -0
  369. package/dist/runtime/thread-event-store.js +737 -0
  370. package/dist/runtime/thread-event-store.js.map +1 -0
  371. package/dist/runtime/thread-projection.d.ts +91 -0
  372. package/dist/runtime/thread-projection.d.ts.map +1 -0
  373. package/dist/runtime/thread-projection.js +407 -0
  374. package/dist/runtime/thread-projection.js.map +1 -0
  375. package/dist/runtime/thread-runtime.d.ts +165 -0
  376. package/dist/runtime/thread-runtime.d.ts.map +1 -0
  377. package/dist/runtime/thread-runtime.js +704 -0
  378. package/dist/runtime/thread-runtime.js.map +1 -0
  379. package/dist/runtime/thread-session-view.d.ts +45 -0
  380. package/dist/runtime/thread-session-view.d.ts.map +1 -0
  381. package/dist/runtime/thread-session-view.js +264 -0
  382. package/dist/runtime/thread-session-view.js.map +1 -0
  383. package/dist/runtime/thread-tool-journal.d.ts +11 -0
  384. package/dist/runtime/thread-tool-journal.d.ts.map +1 -0
  385. package/dist/runtime/thread-tool-journal.js +131 -0
  386. package/dist/runtime/thread-tool-journal.js.map +1 -0
  387. package/dist/runtime/thread-ui-adapter.d.ts +87 -0
  388. package/dist/runtime/thread-ui-adapter.d.ts.map +1 -0
  389. package/dist/runtime/thread-ui-adapter.js +580 -0
  390. package/dist/runtime/thread-ui-adapter.js.map +1 -0
  391. package/dist/runtime/tool-gateway.d.ts +159 -0
  392. package/dist/runtime/tool-gateway.d.ts.map +1 -0
  393. package/dist/runtime/tool-gateway.js +311 -0
  394. package/dist/runtime/tool-gateway.js.map +1 -0
  395. package/dist/runtime/turn-commit.d.ts +103 -0
  396. package/dist/runtime/turn-commit.d.ts.map +1 -0
  397. package/dist/runtime/turn-commit.js +321 -0
  398. package/dist/runtime/turn-commit.js.map +1 -0
  399. package/dist/runtime/ui-events.d.ts +15 -5
  400. package/dist/runtime/ui-events.d.ts.map +1 -1
  401. package/dist/runtime/ui-events.js +0 -1
  402. package/dist/runtime/ui-events.js.map +1 -1
  403. package/dist/runtime/ui-view-model.d.ts +2 -1
  404. package/dist/runtime/ui-view-model.d.ts.map +1 -1
  405. package/dist/runtime/ui-view-model.js +6 -5
  406. package/dist/runtime/ui-view-model.js.map +1 -1
  407. package/dist/services/config-dir.d.ts +1 -1
  408. package/dist/services/config-dir.d.ts.map +1 -1
  409. package/dist/services/config-dir.js +2 -1
  410. package/dist/services/config-dir.js.map +1 -1
  411. package/dist/services/config.d.ts +2 -16
  412. package/dist/services/config.d.ts.map +1 -1
  413. package/dist/services/config.js +2 -29
  414. package/dist/services/config.js.map +1 -1
  415. package/dist/services/doctor.d.ts +0 -2
  416. package/dist/services/doctor.d.ts.map +1 -1
  417. package/dist/services/doctor.js +39 -64
  418. package/dist/services/doctor.js.map +1 -1
  419. package/dist/services/file-lock.d.ts.map +1 -1
  420. package/dist/services/file-lock.js +42 -17
  421. package/dist/services/file-lock.js.map +1 -1
  422. package/dist/services/global-config.d.ts +2 -2
  423. package/dist/services/global-config.d.ts.map +1 -1
  424. package/dist/services/session-storage.d.ts +8 -0
  425. package/dist/services/session-storage.d.ts.map +1 -1
  426. package/dist/services/session-storage.js +76 -12
  427. package/dist/services/session-storage.js.map +1 -1
  428. package/dist/skills/builtin/code-review/SKILL.md +51 -0
  429. package/dist/skills/builtin/security-check/SKILL.md +54 -0
  430. package/dist/skills/builtin/test-gen/SKILL.md +49 -0
  431. package/dist/terminal-ui/launch.d.ts +3 -1
  432. package/dist/terminal-ui/launch.d.ts.map +1 -1
  433. package/dist/terminal-ui/launch.js +21 -3
  434. package/dist/terminal-ui/launch.js.map +1 -1
  435. package/dist/tools/core/common.d.ts +34 -0
  436. package/dist/tools/core/common.d.ts.map +1 -0
  437. package/dist/tools/core/common.js +164 -0
  438. package/dist/tools/core/common.js.map +1 -0
  439. package/dist/tools/core/edit-file.d.ts +10 -0
  440. package/dist/tools/core/edit-file.d.ts.map +1 -0
  441. package/dist/tools/core/edit-file.js +301 -0
  442. package/dist/tools/core/edit-file.js.map +1 -0
  443. package/dist/tools/core/exec-command.d.ts +2 -0
  444. package/dist/tools/core/exec-command.d.ts.map +1 -0
  445. package/dist/tools/core/exec-command.js +347 -0
  446. package/dist/tools/core/exec-command.js.map +1 -0
  447. package/dist/tools/core/glob.d.ts +2 -0
  448. package/dist/tools/core/glob.d.ts.map +1 -0
  449. package/dist/tools/core/glob.js +133 -0
  450. package/dist/tools/core/glob.js.map +1 -0
  451. package/dist/tools/core/grep.d.ts +12 -0
  452. package/dist/tools/core/grep.d.ts.map +1 -0
  453. package/dist/tools/core/grep.js +223 -0
  454. package/dist/tools/core/grep.js.map +1 -0
  455. package/dist/tools/core/index.d.ts +15 -0
  456. package/dist/tools/core/index.d.ts.map +1 -0
  457. package/dist/tools/core/index.js +31 -0
  458. package/dist/tools/core/index.js.map +1 -0
  459. package/dist/tools/core/list-files.d.ts +2 -0
  460. package/dist/tools/core/list-files.d.ts.map +1 -0
  461. package/dist/tools/core/list-files.js +87 -0
  462. package/dist/tools/core/list-files.js.map +1 -0
  463. package/dist/tools/core/read-file.d.ts +2 -0
  464. package/dist/tools/core/read-file.d.ts.map +1 -0
  465. package/dist/tools/core/read-file.js +129 -0
  466. package/dist/tools/core/read-file.js.map +1 -0
  467. package/dist/tools/core/write-file.d.ts +2 -0
  468. package/dist/tools/core/write-file.d.ts.map +1 -0
  469. package/dist/tools/core/write-file.js +65 -0
  470. package/dist/tools/core/write-file.js.map +1 -0
  471. package/dist/tools/todo.d.ts +3 -4
  472. package/dist/tools/todo.d.ts.map +1 -1
  473. package/dist/tools/todo.js +80 -79
  474. package/dist/tools/todo.js.map +1 -1
  475. package/dist/tools/web.js +1 -1
  476. package/dist/tools/web.js.map +1 -1
  477. package/dist/tui-ui/chrome-view-model.d.ts.map +1 -1
  478. package/dist/tui-ui/chrome-view-model.js +22 -8
  479. package/dist/tui-ui/chrome-view-model.js.map +1 -1
  480. package/dist/tui-ui/launch.d.ts.map +1 -1
  481. package/dist/tui-ui/launch.js +13 -0
  482. package/dist/tui-ui/launch.js.map +1 -1
  483. package/dist/tui-ui/layout.js +1 -1
  484. package/dist/tui-ui/layout.js.map +1 -1
  485. package/dist/tui-ui/state.d.ts.map +1 -1
  486. package/dist/tui-ui/state.js +2 -0
  487. package/dist/tui-ui/state.js.map +1 -1
  488. package/docs/migration/v0.1.9-to-v0.2.0.md +98 -0
  489. package/docs/orion.example.json +79 -0
  490. package/docs/plan/v0.2.0-dsh-harness-redesign-plan.md +1234 -0
  491. package/docs/plan/v0.2.0-release-checklist.md +91 -0
  492. package/docs/readme.md +8 -8
  493. package/npm-shrinkwrap.json +45 -450
  494. package/package.json +17 -13
  495. package/dist/agents/coder.d.ts +0 -12
  496. package/dist/agents/coder.d.ts.map +0 -1
  497. package/dist/agents/coder.js +0 -48
  498. package/dist/agents/coder.js.map +0 -1
  499. package/dist/agents/coordinator.d.ts +0 -86
  500. package/dist/agents/coordinator.d.ts.map +0 -1
  501. package/dist/agents/coordinator.js +0 -291
  502. package/dist/agents/coordinator.js.map +0 -1
  503. package/dist/agents/fork.d.ts +0 -73
  504. package/dist/agents/fork.d.ts.map +0 -1
  505. package/dist/agents/fork.js +0 -163
  506. package/dist/agents/fork.js.map +0 -1
  507. package/dist/agents/leader.d.ts +0 -12
  508. package/dist/agents/leader.d.ts.map +0 -1
  509. package/dist/agents/leader.js +0 -49
  510. package/dist/agents/leader.js.map +0 -1
  511. package/dist/agents/router.d.ts +0 -59
  512. package/dist/agents/router.d.ts.map +0 -1
  513. package/dist/agents/router.js +0 -193
  514. package/dist/agents/router.js.map +0 -1
  515. package/dist/agents/worker-pool.d.ts +0 -72
  516. package/dist/agents/worker-pool.d.ts.map +0 -1
  517. package/dist/agents/worker-pool.js +0 -229
  518. package/dist/agents/worker-pool.js.map +0 -1
  519. package/dist/commands/legacy-commands.d.ts +0 -4
  520. package/dist/commands/legacy-commands.d.ts.map +0 -1
  521. package/dist/commands/legacy-commands.js +0 -44
  522. package/dist/commands/legacy-commands.js.map +0 -1
  523. package/dist/core/agent.d.ts +0 -84
  524. package/dist/core/agent.d.ts.map +0 -1
  525. package/dist/core/agent.js +0 -58
  526. package/dist/core/agent.js.map +0 -1
  527. package/dist/core/brain.d.ts +0 -50
  528. package/dist/core/brain.d.ts.map +0 -1
  529. package/dist/core/brain.js +0 -95
  530. package/dist/core/brain.js.map +0 -1
  531. package/dist/framework/tool-scheduler.d.ts +0 -191
  532. package/dist/framework/tool-scheduler.d.ts.map +0 -1
  533. package/dist/framework/tool-scheduler.js +0 -573
  534. package/dist/framework/tool-scheduler.js.map +0 -1
  535. package/dist/harness/harness.d.ts +0 -58
  536. package/dist/harness/harness.d.ts.map +0 -1
  537. package/dist/harness/harness.js +0 -195
  538. package/dist/harness/harness.js.map +0 -1
  539. package/dist/harness/safety.d.ts +0 -101
  540. package/dist/harness/safety.d.ts.map +0 -1
  541. package/dist/harness/safety.js +0 -322
  542. package/dist/harness/safety.js.map +0 -1
  543. package/dist/init.d.ts +0 -108
  544. package/dist/init.d.ts.map +0 -1
  545. package/dist/init.js +0 -393
  546. package/dist/init.js.map +0 -1
  547. package/dist/ink-ui/App.d.ts +0 -9
  548. package/dist/ink-ui/App.d.ts.map +0 -1
  549. package/dist/ink-ui/App.js +0 -12
  550. package/dist/ink-ui/App.js.map +0 -1
  551. package/dist/ink-ui/components/Markdown.d.ts +0 -10
  552. package/dist/ink-ui/components/Markdown.d.ts.map +0 -1
  553. package/dist/ink-ui/components/Markdown.js +0 -210
  554. package/dist/ink-ui/components/Markdown.js.map +0 -1
  555. package/dist/ink-ui/components/NativeCursor.d.ts +0 -12
  556. package/dist/ink-ui/components/NativeCursor.d.ts.map +0 -1
  557. package/dist/ink-ui/components/NativeCursor.js +0 -35
  558. package/dist/ink-ui/components/NativeCursor.js.map +0 -1
  559. package/dist/ink-ui/components/PixelHorseBanner.d.ts +0 -8
  560. package/dist/ink-ui/components/PixelHorseBanner.d.ts.map +0 -1
  561. package/dist/ink-ui/components/PixelHorseBanner.js +0 -97
  562. package/dist/ink-ui/components/PixelHorseBanner.js.map +0 -1
  563. package/dist/ink-ui/components/PromptInput.d.ts +0 -13
  564. package/dist/ink-ui/components/PromptInput.d.ts.map +0 -1
  565. package/dist/ink-ui/components/PromptInput.js +0 -30
  566. package/dist/ink-ui/components/PromptInput.js.map +0 -1
  567. package/dist/ink-ui/components/RunningHorseIndicator.d.ts +0 -13
  568. package/dist/ink-ui/components/RunningHorseIndicator.d.ts.map +0 -1
  569. package/dist/ink-ui/components/RunningHorseIndicator.js +0 -53
  570. package/dist/ink-ui/components/RunningHorseIndicator.js.map +0 -1
  571. package/dist/ink-ui/components/SelectList.d.ts +0 -16
  572. package/dist/ink-ui/components/SelectList.d.ts.map +0 -1
  573. package/dist/ink-ui/components/SelectList.js +0 -60
  574. package/dist/ink-ui/components/SelectList.js.map +0 -1
  575. package/dist/ink-ui/components/StatusLine.d.ts +0 -11
  576. package/dist/ink-ui/components/StatusLine.d.ts.map +0 -1
  577. package/dist/ink-ui/components/StatusLine.js +0 -70
  578. package/dist/ink-ui/components/StatusLine.js.map +0 -1
  579. package/dist/ink-ui/components/ToolActivity.d.ts +0 -19
  580. package/dist/ink-ui/components/ToolActivity.d.ts.map +0 -1
  581. package/dist/ink-ui/components/ToolActivity.js +0 -134
  582. package/dist/ink-ui/components/ToolActivity.js.map +0 -1
  583. package/dist/ink-ui/components/Transcript.d.ts +0 -14
  584. package/dist/ink-ui/components/Transcript.d.ts.map +0 -1
  585. package/dist/ink-ui/components/Transcript.js +0 -66
  586. package/dist/ink-ui/components/Transcript.js.map +0 -1
  587. package/dist/ink-ui/controllers/chat-controller.d.ts +0 -2
  588. package/dist/ink-ui/controllers/chat-controller.d.ts.map +0 -1
  589. package/dist/ink-ui/controllers/chat-controller.js.map +0 -1
  590. package/dist/ink-ui/hooks/use-raw-input-bridge.d.ts +0 -6
  591. package/dist/ink-ui/hooks/use-raw-input-bridge.d.ts.map +0 -1
  592. package/dist/ink-ui/hooks/use-raw-input-bridge.js +0 -27
  593. package/dist/ink-ui/hooks/use-raw-input-bridge.js.map +0 -1
  594. package/dist/ink-ui/hooks/use-terminal-size.d.ts +0 -7
  595. package/dist/ink-ui/hooks/use-terminal-size.d.ts.map +0 -1
  596. package/dist/ink-ui/hooks/use-terminal-size.js +0 -34
  597. package/dist/ink-ui/hooks/use-terminal-size.js.map +0 -1
  598. package/dist/ink-ui/launch.d.ts +0 -9
  599. package/dist/ink-ui/launch.d.ts.map +0 -1
  600. package/dist/ink-ui/launch.js +0 -101
  601. package/dist/ink-ui/launch.js.map +0 -1
  602. package/dist/ink-ui/runtime/grapheme.d.ts +0 -10
  603. package/dist/ink-ui/runtime/grapheme.d.ts.map +0 -1
  604. package/dist/ink-ui/runtime/grapheme.js +0 -17
  605. package/dist/ink-ui/runtime/grapheme.js.map +0 -1
  606. package/dist/ink-ui/runtime/input-buffer.d.ts +0 -10
  607. package/dist/ink-ui/runtime/input-buffer.d.ts.map +0 -1
  608. package/dist/ink-ui/runtime/input-buffer.js +0 -18
  609. package/dist/ink-ui/runtime/input-buffer.js.map +0 -1
  610. package/dist/ink-ui/runtime/layout-budget.d.ts +0 -13
  611. package/dist/ink-ui/runtime/layout-budget.d.ts.map +0 -1
  612. package/dist/ink-ui/runtime/layout-budget.js +0 -25
  613. package/dist/ink-ui/runtime/layout-budget.js.map +0 -1
  614. package/dist/ink-ui/runtime/native-cursor.d.ts +0 -62
  615. package/dist/ink-ui/runtime/native-cursor.d.ts.map +0 -1
  616. package/dist/ink-ui/runtime/native-cursor.js +0 -398
  617. package/dist/ink-ui/runtime/native-cursor.js.map +0 -1
  618. package/dist/ink-ui/runtime/prompt-layout.d.ts +0 -10
  619. package/dist/ink-ui/runtime/prompt-layout.d.ts.map +0 -1
  620. package/dist/ink-ui/runtime/prompt-layout.js +0 -21
  621. package/dist/ink-ui/runtime/prompt-layout.js.map +0 -1
  622. package/dist/ink-ui/runtime/raw-input.d.ts +0 -4
  623. package/dist/ink-ui/runtime/raw-input.d.ts.map +0 -1
  624. package/dist/ink-ui/runtime/raw-input.js +0 -15
  625. package/dist/ink-ui/runtime/raw-input.js.map +0 -1
  626. package/dist/ink-ui/runtime/transcript-state.d.ts +0 -37
  627. package/dist/ink-ui/runtime/transcript-state.d.ts.map +0 -1
  628. package/dist/ink-ui/runtime/transcript-state.js +0 -91
  629. package/dist/ink-ui/runtime/transcript-state.js.map +0 -1
  630. package/dist/ink-ui/screens/ReplScreen.d.ts +0 -27
  631. package/dist/ink-ui/screens/ReplScreen.d.ts.map +0 -1
  632. package/dist/ink-ui/screens/ReplScreen.js +0 -781
  633. package/dist/ink-ui/screens/ReplScreen.js.map +0 -1
  634. package/dist/ink-ui/types.d.ts +0 -2
  635. package/dist/ink-ui/types.d.ts.map +0 -1
  636. package/dist/ink-ui/types.js.map +0 -1
  637. package/dist/runtime/chat-checkpoint.d.ts +0 -17
  638. package/dist/runtime/chat-checkpoint.d.ts.map +0 -1
  639. package/dist/runtime/chat-checkpoint.js +0 -105
  640. package/dist/runtime/chat-checkpoint.js.map +0 -1
  641. package/dist/runtime/chat-command-scope.d.ts +0 -5
  642. package/dist/runtime/chat-command-scope.d.ts.map +0 -1
  643. package/dist/runtime/chat-command-scope.js +0 -22
  644. package/dist/runtime/chat-command-scope.js.map +0 -1
  645. package/dist/runtime/chat-compact.d.ts +0 -26
  646. package/dist/runtime/chat-compact.d.ts.map +0 -1
  647. package/dist/runtime/chat-compact.js +0 -132
  648. package/dist/runtime/chat-compact.js.map +0 -1
  649. package/dist/runtime/chat-controller.d.ts +0 -62
  650. package/dist/runtime/chat-controller.d.ts.map +0 -1
  651. package/dist/runtime/chat-controller.js +0 -1620
  652. package/dist/runtime/chat-controller.js.map +0 -1
  653. package/dist/runtime/chat-effort.d.ts +0 -5
  654. package/dist/runtime/chat-effort.d.ts.map +0 -1
  655. package/dist/runtime/chat-effort.js +0 -47
  656. package/dist/runtime/chat-effort.js.map +0 -1
  657. package/dist/runtime/chat-presentation.d.ts +0 -63
  658. package/dist/runtime/chat-presentation.d.ts.map +0 -1
  659. package/dist/runtime/chat-presentation.js +0 -561
  660. package/dist/runtime/chat-presentation.js.map +0 -1
  661. package/dist/runtime/chat-trace.d.ts +0 -52
  662. package/dist/runtime/chat-trace.d.ts.map +0 -1
  663. package/dist/runtime/chat-trace.js +0 -234
  664. package/dist/runtime/chat-trace.js.map +0 -1
  665. package/dist/runtime/chat-workspace.d.ts +0 -22
  666. package/dist/runtime/chat-workspace.d.ts.map +0 -1
  667. package/dist/runtime/chat-workspace.js +0 -154
  668. package/dist/runtime/chat-workspace.js.map +0 -1
  669. package/dist/runtime/goals/accounting.d.ts +0 -45
  670. package/dist/runtime/goals/accounting.d.ts.map +0 -1
  671. package/dist/runtime/goals/accounting.js +0 -114
  672. package/dist/runtime/goals/accounting.js.map +0 -1
  673. package/dist/runtime/goals/coordinator.d.ts +0 -92
  674. package/dist/runtime/goals/coordinator.d.ts.map +0 -1
  675. package/dist/runtime/goals/coordinator.js +0 -1471
  676. package/dist/runtime/goals/coordinator.js.map +0 -1
  677. package/dist/runtime/goals/lifecycle.d.ts +0 -13
  678. package/dist/runtime/goals/lifecycle.d.ts.map +0 -1
  679. package/dist/runtime/goals/lifecycle.js +0 -46
  680. package/dist/runtime/goals/lifecycle.js.map +0 -1
  681. package/dist/runtime/goals/prompt.d.ts +0 -16
  682. package/dist/runtime/goals/prompt.d.ts.map +0 -1
  683. package/dist/runtime/goals/prompt.js +0 -88
  684. package/dist/runtime/goals/prompt.js.map +0 -1
  685. package/dist/runtime/goals/stop-policy.d.ts +0 -9
  686. package/dist/runtime/goals/stop-policy.d.ts.map +0 -1
  687. package/dist/runtime/goals/stop-policy.js +0 -83
  688. package/dist/runtime/goals/stop-policy.js.map +0 -1
  689. package/dist/runtime/goals/tools.d.ts +0 -61
  690. package/dist/runtime/goals/tools.d.ts.map +0 -1
  691. package/dist/runtime/goals/tools.js +0 -568
  692. package/dist/runtime/goals/tools.js.map +0 -1
  693. package/dist/sdk/index.d.ts +0 -10
  694. package/dist/sdk/index.d.ts.map +0 -1
  695. package/dist/sdk/index.js +0 -23
  696. package/dist/sdk/index.js.map +0 -1
  697. package/dist/sdk/init.d.ts +0 -24
  698. package/dist/sdk/init.d.ts.map +0 -1
  699. package/dist/sdk/init.js +0 -48
  700. package/dist/sdk/init.js.map +0 -1
  701. package/dist/sdk/query.d.ts +0 -19
  702. package/dist/sdk/query.d.ts.map +0 -1
  703. package/dist/sdk/query.js +0 -42
  704. package/dist/sdk/query.js.map +0 -1
  705. package/dist/sdk/sessions.d.ts +0 -19
  706. package/dist/sdk/sessions.d.ts.map +0 -1
  707. package/dist/sdk/sessions.js +0 -57
  708. package/dist/sdk/sessions.js.map +0 -1
  709. package/dist/sdk/types.d.ts +0 -47
  710. package/dist/sdk/types.d.ts.map +0 -1
  711. package/dist/sdk/types.js +0 -8
  712. package/dist/sdk/types.js.map +0 -1
  713. package/dist/services/agent-runner.d.ts +0 -71
  714. package/dist/services/agent-runner.d.ts.map +0 -1
  715. package/dist/services/agent-runner.js +0 -185
  716. package/dist/services/agent-runner.js.map +0 -1
  717. package/dist/services/task-manager.d.ts +0 -161
  718. package/dist/services/task-manager.d.ts.map +0 -1
  719. package/dist/services/task-manager.js +0 -315
  720. package/dist/services/task-manager.js.map +0 -1
  721. package/dist/skills/discovery.d.ts +0 -22
  722. package/dist/skills/discovery.d.ts.map +0 -1
  723. package/dist/skills/discovery.js +0 -75
  724. package/dist/skills/discovery.js.map +0 -1
  725. package/dist/skills/index.d.ts +0 -11
  726. package/dist/skills/index.d.ts.map +0 -1
  727. package/dist/skills/index.js.map +0 -1
  728. package/dist/skills/loader.d.ts +0 -53
  729. package/dist/skills/loader.d.ts.map +0 -1
  730. package/dist/skills/loader.js +0 -421
  731. package/dist/skills/loader.js.map +0 -1
  732. package/dist/skills/registry.d.ts +0 -41
  733. package/dist/skills/registry.d.ts.map +0 -1
  734. package/dist/skills/registry.js +0 -157
  735. package/dist/skills/registry.js.map +0 -1
  736. package/dist/skills/runtime.d.ts +0 -46
  737. package/dist/skills/runtime.d.ts.map +0 -1
  738. package/dist/skills/runtime.js +0 -363
  739. package/dist/skills/runtime.js.map +0 -1
  740. package/dist/skills/types.d.ts +0 -112
  741. package/dist/skills/types.d.ts.map +0 -1
  742. package/dist/skills/types.js +0 -24
  743. package/dist/skills/types.js.map +0 -1
  744. package/dist/tools/index.d.ts +0 -52
  745. package/dist/tools/index.d.ts.map +0 -1
  746. package/dist/tools/index.js +0 -2268
  747. package/dist/tools/index.js.map +0 -1
  748. package/dist/tools/mcp.d.ts +0 -99
  749. package/dist/tools/mcp.d.ts.map +0 -1
  750. package/dist/tools/mcp.js +0 -695
  751. package/dist/tools/mcp.js.map +0 -1
  752. package/dist/tools/plan.d.ts +0 -17
  753. package/dist/tools/plan.d.ts.map +0 -1
  754. package/dist/tools/plan.js +0 -84
  755. package/dist/tools/plan.js.map +0 -1
  756. package/docs/migration/v0.1.8-to-v0.1.9.md +0 -60
  757. package/docs/plan/v0.1.9-release-checklist.md +0 -64
@@ -1,2268 +0,0 @@
1
- "use strict";
2
- /**
3
- * orion code - 工具集
4
- *
5
- * 定义 Agent 可用的工具(Tool System v2):
6
- * - read_file: 读取文件内容
7
- * - write_file: 写入文件
8
- * - list_files: 列出目录
9
- * - exec_command: 执行 shell 命令
10
- *
11
- * 使用 buildTool() 工厂模式。
12
- */
13
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
- if (k2 === undefined) k2 = k;
15
- var desc = Object.getOwnPropertyDescriptor(m, k);
16
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
17
- desc = { enumerable: true, get: function() { return m[k]; } };
18
- }
19
- Object.defineProperty(o, k2, desc);
20
- }) : (function(o, m, k, k2) {
21
- if (k2 === undefined) k2 = k;
22
- o[k2] = m[k];
23
- }));
24
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
25
- Object.defineProperty(o, "default", { enumerable: true, value: v });
26
- }) : function(o, v) {
27
- o["default"] = v;
28
- });
29
- var __importStar = (this && this.__importStar) || (function () {
30
- var ownKeys = function(o) {
31
- ownKeys = Object.getOwnPropertyNames || function (o) {
32
- var ar = [];
33
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
34
- return ar;
35
- };
36
- return ownKeys(o);
37
- };
38
- return function (mod) {
39
- if (mod && mod.__esModule) return mod;
40
- var result = {};
41
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
42
- __setModuleDefault(result, mod);
43
- return result;
44
- };
45
- })();
46
- Object.defineProperty(exports, "__esModule", { value: true });
47
- exports.findDestructiveRmTarget = exports.assessCommandSecurity = exports.isPotentiallyDestructive = exports.checkDangerousCommand = exports.isReadOnlyCommand = exports.POTENTIALLY_DESTRUCTIVE_PATTERNS = exports.DANGEROUS_PATTERNS = exports.READ_ONLY_COMMANDS = exports.TOOLS = exports.BATCH_READ_MAX_STEPS = exports.BATCH_READ_ALLOWED_TOOLS = void 0;
48
- exports.getRuntimeTools = getRuntimeTools;
49
- exports.validateRegexPattern = validateRegexPattern;
50
- exports.executeTool = executeTool;
51
- exports.getToolNames = getToolNames;
52
- const child_process_1 = require("child_process");
53
- const fs_1 = require("fs");
54
- const path_1 = require("path");
55
- const readline_1 = require("readline");
56
- const tool_1 = require("../framework/tool");
57
- const tool_scheduler_1 = require("../framework/tool-scheduler");
58
- const external_assertion_1 = require("../framework/external-assertion");
59
- const tool_state_1 = require("../framework/tool-state");
60
- const tool_artifacts_1 = require("../core/tool-artifacts");
61
- const environment_1 = require("../product/environment");
62
- const storage_1 = require("../memory/storage");
63
- const semantic_config_1 = require("../memory/semantic-config");
64
- const session_storage_1 = require("../services/session-storage");
65
- const workspace_containment_1 = require("../services/workspace-containment");
66
- const web_1 = require("./web");
67
- const mcp_1 = require("./mcp");
68
- const todo_1 = require("./todo");
69
- const plan_1 = require("./plan");
70
- const git_1 = require("./git");
71
- const lsp_1 = require("./lsp");
72
- const tools_1 = require("../runtime/goals/tools");
73
- const bash_security_1 = require("./bash_security");
74
- const debug_log_1 = require("../utils/debug-log");
75
- const errors_1 = require("../utils/errors");
76
- const sandbox_1 = require("./sandbox");
77
- exports.BATCH_READ_ALLOWED_TOOLS = new Set([
78
- 'git_status',
79
- 'list_files',
80
- 'glob',
81
- 'grep',
82
- 'read_file',
83
- ]);
84
- exports.BATCH_READ_MAX_STEPS = 8;
85
- const BATCH_READ_STEP_OUTPUT_MAX_BYTES = 1600;
86
- const LIST_FILES_MAX_DEPTH = 8;
87
- const EXEC_COMMAND_MIN_TIMEOUT_MS = 1;
88
- const EXEC_COMMAND_MAX_TIMEOUT_MS = 600000;
89
- const EXEC_COMMAND_MIN_OUTPUT_BYTES = 1024;
90
- const EXEC_COMMAND_MAX_OUTPUT_BYTES = 10 * 1024 * 1024;
91
- function validateOptionalSafeInteger(args, toolName, field, minimum, maximum) {
92
- const value = args[field];
93
- if (value === undefined)
94
- return undefined;
95
- if (typeof value !== 'number' ||
96
- !Number.isFinite(value) ||
97
- !Number.isSafeInteger(value) ||
98
- value < minimum ||
99
- value > maximum) {
100
- return `${toolName} ${field} must be a safe integer between ${minimum} and ${maximum}`;
101
- }
102
- return undefined;
103
- }
104
- function compactOneLine(text, maxLength) {
105
- const compact = text.replace(/\s+/g, ' ').trim();
106
- if (compact.length <= maxLength)
107
- return compact;
108
- if (maxLength <= 3)
109
- return compact.slice(0, maxLength);
110
- const headLength = Math.ceil((maxLength - 3) * 0.55);
111
- const tailLength = Math.floor((maxLength - 3) * 0.45);
112
- return `${compact.slice(0, headLength)}...${compact.slice(-tailLength)}`;
113
- }
114
- function summarizeFailedToolResult(result) {
115
- const details = [];
116
- if (result.error) {
117
- details.push(compactOneLine(result.error, 80));
118
- }
119
- const output = result.output ? compactOneLine(result.output, 120) : '';
120
- if (output && output !== result.error) {
121
- details.push(`output: ${output}`);
122
- }
123
- return details.join('; ');
124
- }
125
- // ============================================================================
126
- // 工具集
127
- // ============================================================================
128
- exports.TOOLS = [
129
- // Web tools (P0)
130
- ...web_1.WEB_TOOLS,
131
- // MCP tools (P0)
132
- ...mcp_1.MCP_TOOLS,
133
- // Git tools (P0 - Issue #18/#23)
134
- ...git_1.GIT_TOOLS,
135
- // LSP tools (P0 - Phase 6)
136
- ...lsp_1.lspTools,
137
- // Todo tools (P1)
138
- ...todo_1.TODO_TOOLS,
139
- // Plan mode tools (P1)
140
- ...plan_1.PLAN_TOOLS,
141
- // Goal tools (P0 - v0.2.24)
142
- ...tools_1.GOAL_TOOLS,
143
- // File tools
144
- (0, tool_1.buildTool)({
145
- name: 'read_file',
146
- description: '读取文件内容,支持从指定行开始分页。返回文件内容字符串。',
147
- parameters: {
148
- type: 'object',
149
- properties: {
150
- path: {
151
- type: 'string',
152
- description: '文件路径(绝对路径或相对路径)',
153
- },
154
- maxLines: {
155
- type: 'number',
156
- description: '最大读取行数(可选,默认 500 行)',
157
- },
158
- offset: {
159
- type: 'number',
160
- description: '开始读取的行号(可选,1-based,默认第 1 行)',
161
- },
162
- },
163
- required: ['path'],
164
- },
165
- execute: async (args, context) => {
166
- // Ensure path is a valid string
167
- const path = args.path;
168
- if (!path || typeof path !== 'string') {
169
- return { success: false, output: '', error: 'read_file requires a path parameter' };
170
- }
171
- const maxLines = readPositiveInteger(args.maxLines, 'maxLines', 500);
172
- if (typeof maxLines === 'string') {
173
- return { success: false, output: '', error: maxLines };
174
- }
175
- const offset = readPositiveInteger(args.offset, 'offset', 1);
176
- if (typeof offset === 'string') {
177
- return { success: false, output: '', error: offset };
178
- }
179
- return readFileSync_(path, maxLines, offset, context.cwd);
180
- },
181
- isReadOnly: () => true,
182
- isConcurrencySafe: () => true,
183
- userFacingName: args => `Read ${args.path}`,
184
- getSummary: (args, result) => {
185
- const path = args.path;
186
- if (!result.success)
187
- return `📄 read ${path} → error`;
188
- const lines = result.output.split('\n').length;
189
- const bytes = Buffer.byteLength(result.output, 'utf8');
190
- return `📄 read ${path} (${lines}L, ${bytes}B)`;
191
- },
192
- }),
193
- (0, tool_1.buildTool)({
194
- name: 'write_file',
195
- description: '将内容写入文件。如果文件不存在则创建,存在则覆盖。',
196
- parameters: {
197
- type: 'object',
198
- properties: {
199
- path: {
200
- type: 'string',
201
- description: '文件路径(绝对路径或相对路径)',
202
- },
203
- content: {
204
- type: 'string',
205
- description: '要写入的文件内容',
206
- },
207
- },
208
- required: ['path', 'content'],
209
- },
210
- execute: async (args, context) => {
211
- // Ensure path and content are valid strings
212
- const path = args.path;
213
- const content = args.content;
214
- if (!path || typeof path !== 'string') {
215
- return { success: false, output: '', error: 'write_file requires a path parameter' };
216
- }
217
- if (typeof content !== 'string') {
218
- return { success: false, output: '', error: 'write_file requires a content parameter' };
219
- }
220
- return writeFileSync_(path, content, context.cwd);
221
- },
222
- isDestructive: () => true,
223
- isFileEdit: () => true,
224
- checkPermissions: (_args, _context) => {
225
- return { behavior: 'ask', reason: 'Write operation may modify existing files' };
226
- },
227
- userFacingName: args => `Write ${args.path}`,
228
- getSummary: (args, result) => {
229
- const path = args.path;
230
- if (!result.success)
231
- return `💾 write ${path} → error`;
232
- const bytes = Buffer.byteLength(args.content || '', 'utf8');
233
- return `💾 write ${path} (${bytes}B)`;
234
- },
235
- }),
236
- (0, tool_1.buildTool)({
237
- name: 'list_files',
238
- description: '列出指定目录中的文件和子目录。支持控制递归深度。',
239
- parameters: {
240
- type: 'object',
241
- properties: {
242
- path: {
243
- type: 'string',
244
- description: '目录路径(绝对路径或相对路径)',
245
- },
246
- maxDepth: {
247
- type: 'number',
248
- description: '最大递归深度(可选,默认 2,范围 0-8)',
249
- minimum: 0,
250
- maximum: LIST_FILES_MAX_DEPTH,
251
- },
252
- },
253
- required: ['path'],
254
- },
255
- execute: async (args, context) => {
256
- // Ensure path is a valid string
257
- const path = args.path;
258
- if (!path || typeof path !== 'string') {
259
- return { success: false, output: '', error: 'list_files requires a path parameter' };
260
- }
261
- return listFiles_(path, args.maxDepth, context.cwd);
262
- },
263
- validateInput: args => validateOptionalSafeInteger(args, 'list_files', 'maxDepth', 0, LIST_FILES_MAX_DEPTH),
264
- isReadOnly: () => true,
265
- isConcurrencySafe: () => true,
266
- userFacingName: args => `List ${args.path}`,
267
- getSummary: (args, result) => {
268
- const path = args.path;
269
- if (!result.success)
270
- return `📁 list ${path} → error`;
271
- const count = result.output.split('\n').filter(Boolean).length;
272
- return `📁 list ${path} (${count} entries)`;
273
- },
274
- }),
275
- (0, tool_1.buildTool)({
276
- name: 'exec_command',
277
- description: '执行一个 shell 命令。返回 stdout 和 stderr。输出超过 maxOutput 会自动截断。',
278
- parameters: {
279
- type: 'object',
280
- properties: {
281
- command: {
282
- type: 'string',
283
- description: '要执行的 shell 命令',
284
- },
285
- cwd: {
286
- type: 'string',
287
- description: '工作目录(可选,默认当前目录)',
288
- },
289
- timeout: {
290
- type: 'number',
291
- description: '超时时间 ms(可选,默认 30000,范围 1-600000)',
292
- minimum: EXEC_COMMAND_MIN_TIMEOUT_MS,
293
- maximum: EXEC_COMMAND_MAX_TIMEOUT_MS,
294
- },
295
- maxOutput: {
296
- type: 'number',
297
- description: '最大输出字节数(可选,默认 51200,范围 1024-10485760,超出截断)',
298
- minimum: EXEC_COMMAND_MIN_OUTPUT_BYTES,
299
- maximum: EXEC_COMMAND_MAX_OUTPUT_BYTES,
300
- },
301
- },
302
- required: ['command'],
303
- },
304
- execute: async (args, context) => {
305
- // Ensure command is a valid string
306
- const command = args.command;
307
- if (!command || typeof command !== 'string') {
308
- return { success: false, output: '', error: 'exec_command requires a command parameter' };
309
- }
310
- // Issue #32 #3.2: 传递 abortSignal
311
- return execCommand_(command, args.cwd, args.timeout, args.maxOutput, context.abortSignal, context.cwd);
312
- },
313
- validateInput: args => validateOptionalSafeInteger(args, 'exec_command', 'timeout', EXEC_COMMAND_MIN_TIMEOUT_MS, EXEC_COMMAND_MAX_TIMEOUT_MS) ??
314
- validateOptionalSafeInteger(args, 'exec_command', 'maxOutput', EXEC_COMMAND_MIN_OUTPUT_BYTES, EXEC_COMMAND_MAX_OUTPUT_BYTES),
315
- isDestructive: args => {
316
- const cmd = args.command || '';
317
- return (0, bash_security_1.containsRecursiveRm)(cmd) || /(?:^|[;&|]\s*)(?:[^\s]+\/)?(?:mkfs|dd)(?:\s|$)/.test(cmd);
318
- },
319
- checkPermissions: (args, context) => {
320
- const cmd = args.command || '';
321
- // Use the bash_security module for comprehensive checks
322
- const security = (0, bash_security_1.assessCommandSecurity)(cmd);
323
- if (security.level === 'blocked') {
324
- return {
325
- behavior: 'deny',
326
- reason: security.reason || `Command blocked by safety policy: ${cmd.slice(0, 50)}`,
327
- };
328
- }
329
- // v0.1.3-2 §1.2: a configured-but-unusable sandbox is a hard deny, decided
330
- // here so the user sees the reason instead of an opaque execution failure.
331
- let paths;
332
- try {
333
- paths = resolveExecCommandPaths(args.cwd, context?.cwd);
334
- }
335
- catch (error) {
336
- return {
337
- behavior: 'deny',
338
- reason: error instanceof Error ? error.message : 'exec_command cwd is outside workspace',
339
- };
340
- }
341
- const { workdir, projectRoot } = paths;
342
- const sandboxSettings = (0, sandbox_1.resolveSandboxSettings)(projectRoot);
343
- let sandboxNote = '';
344
- if ((sandboxSettings.profile ?? 'none') !== 'none') {
345
- const plan = (0, sandbox_1.planSandboxedCommand)(cmd, {
346
- cwd: workdir,
347
- projectRoot,
348
- settings: sandboxSettings,
349
- });
350
- if (!plan.ok) {
351
- return {
352
- behavior: 'deny',
353
- reason: `sandbox profile "${plan.profile}" is configured but cannot be applied — ${plan.reason}`,
354
- };
355
- }
356
- sandboxNote = ` [${(0, sandbox_1.describeSandboxPlan)(plan)}]`;
357
- }
358
- if (security.level === 'safe' && security.isReadOnly) {
359
- return { behavior: 'allow' };
360
- }
361
- if (security.level === 'caution') {
362
- return {
363
- behavior: 'ask',
364
- reason: (security.reason || 'Command requires confirmation') + sandboxNote,
365
- };
366
- }
367
- // Default: ask for confirmation
368
- return { behavior: 'ask', reason: 'Command requires confirmation' + sandboxNote };
369
- },
370
- isReadOnly: args => {
371
- const cmd = args.command || '';
372
- return (0, bash_security_1.isReadOnlyCommand)(cmd);
373
- },
374
- isConcurrencySafe: args => {
375
- const cmd = args.command || '';
376
- return (0, bash_security_1.isReadOnlyCommand)(cmd);
377
- },
378
- userFacingName: args => `Exec ${compactOneLine(args.command || '', 80)}`,
379
- getSummary: (args, result) => {
380
- const command = args.command || '';
381
- const commandSummary = command ? `\n $ ${compactOneLine(command, 160)}` : '';
382
- if (!result.success) {
383
- const detail = summarizeFailedToolResult(result);
384
- return `🔧 exec → error${detail ? ` (${detail})` : ''}${commandSummary}`;
385
- }
386
- const bytes = Buffer.byteLength(result.output, 'utf8');
387
- return `🔧 exec (${bytes}B output)${commandSummary}`;
388
- },
389
- }),
390
- (0, tool_1.buildTool)({
391
- name: 'edit_file',
392
- description: '对文件进行精确字符串替换。old_string 必须在文件中唯一匹配,否则拒绝执行。使用 replace_all 可替换所有精确匹配;只有显式 fuzzy_match=true 时才尝试宽松空白匹配。',
393
- parameters: {
394
- type: 'object',
395
- properties: {
396
- path: {
397
- type: 'string',
398
- description: '文件路径(绝对路径或相对路径)',
399
- },
400
- old_string: {
401
- type: 'string',
402
- description: '要替换的字符串(必须精确匹配)',
403
- },
404
- new_string: {
405
- type: 'string',
406
- description: '替换后的字符串',
407
- },
408
- replace_all: {
409
- type: 'boolean',
410
- description: '是否替换所有匹配(可选,默认 false)',
411
- },
412
- fuzzy_match: {
413
- type: 'boolean',
414
- description: '精确匹配失败时是否允许宽松空白匹配(可选,默认 false;多候选时总是拒绝)',
415
- },
416
- preview: {
417
- type: 'boolean',
418
- description: '预览匹配结果而不写入文件(可选,默认 false)',
419
- },
420
- },
421
- required: ['path', 'old_string', 'new_string'],
422
- },
423
- execute: async (args, context) => {
424
- // Ensure required parameters are valid strings
425
- const path = args.path;
426
- const old_string = args.old_string;
427
- const new_string = args.new_string;
428
- if (!path || typeof path !== 'string') {
429
- return { success: false, output: '', error: 'edit_file requires a path parameter' };
430
- }
431
- if (!old_string || typeof old_string !== 'string') {
432
- return { success: false, output: '', error: 'edit_file requires an old_string parameter' };
433
- }
434
- if (typeof new_string !== 'string') {
435
- return { success: false, output: '', error: 'edit_file requires a new_string parameter' };
436
- }
437
- const lastEditFileArgs = { path, old_string, new_string, updatedAt: Date.now() };
438
- if (typeof args.replace_all === 'boolean')
439
- lastEditFileArgs.replace_all = args.replace_all;
440
- if (typeof args.fuzzy_match === 'boolean')
441
- lastEditFileArgs.fuzzy_match = args.fuzzy_match;
442
- if (context?.sessionId)
443
- lastEditFileArgs.sessionId = context.sessionId;
444
- if (context?.turnId)
445
- lastEditFileArgs.turnId = context.turnId;
446
- lastEditFileArgs.updatedAt = Date.now();
447
- (0, tool_state_1.setToolState)({ lastEditFileArgs });
448
- return editFile_(path, old_string, new_string, args.replace_all, args.fuzzy_match, args.preview, context.cwd);
449
- },
450
- isDestructive: () => true,
451
- isFileEdit: () => true,
452
- checkPermissions: (_args, _context) => {
453
- return { behavior: 'ask', reason: 'Edit operation modifies file contents' };
454
- },
455
- userFacingName: args => `Edit ${args.path}`,
456
- getSummary: (args, result) => {
457
- const path = args.path;
458
- if (!result.success)
459
- return `✏️ edit ${path} → error`;
460
- const replaceAll = args.replace_all ? ' (all)' : '';
461
- return `✏️ edit ${path}${replaceAll}`;
462
- },
463
- }),
464
- (0, tool_1.buildTool)({
465
- name: 'glob',
466
- description: '使用 glob 模式搜索文件。支持 **(递归)、*(任意字符)、?(单个字符)等通配符。',
467
- parameters: {
468
- type: 'object',
469
- properties: {
470
- pattern: {
471
- type: 'string',
472
- description: 'Glob 模式(如 **/*.ts, src/**/*.js)',
473
- },
474
- path: {
475
- type: 'string',
476
- description: '搜索起始目录(可选,默认当前目录)',
477
- },
478
- },
479
- required: ['pattern'],
480
- },
481
- execute: async (args, context) => {
482
- // Ensure pattern is a valid string
483
- const pattern = args.pattern;
484
- if (!pattern || typeof pattern !== 'string') {
485
- return { success: false, output: '', error: 'glob requires a pattern parameter' };
486
- }
487
- return glob_(pattern, args.path, context.cwd);
488
- },
489
- isReadOnly: () => true,
490
- isConcurrencySafe: () => true,
491
- userFacingName: args => `Glob ${args.pattern}`,
492
- getSummary: (args, result) => {
493
- const pattern = args.pattern;
494
- if (!result.success)
495
- return `🔍 glob ${pattern} → error`;
496
- const count = result.output.split('\n').filter(Boolean).length;
497
- return `🔍 glob ${pattern} → ${count} matches`;
498
- },
499
- }),
500
- (0, tool_1.buildTool)({
501
- name: 'grep',
502
- description: '在文件中搜索正则表达式模式。返回匹配的文件路径和行内容。',
503
- parameters: {
504
- type: 'object',
505
- properties: {
506
- pattern: {
507
- type: 'string',
508
- description: '正则表达式模式',
509
- },
510
- path: {
511
- type: 'string',
512
- description: '搜索路径(可选,默认当前目录)',
513
- },
514
- glob: {
515
- type: 'string',
516
- description: '文件过滤模式(可选,如 *.ts)',
517
- },
518
- context: {
519
- type: 'number',
520
- description: '上下文行数(可选,默认 0)',
521
- },
522
- },
523
- required: ['pattern'],
524
- },
525
- execute: async (args, context) => {
526
- // Ensure pattern is a valid string
527
- const pattern = args.pattern;
528
- if (!pattern || typeof pattern !== 'string') {
529
- return { success: false, output: '', error: 'grep requires a pattern parameter' };
530
- }
531
- return grep_(pattern, args.path, args.glob, args.context, context.cwd);
532
- },
533
- isReadOnly: () => true,
534
- isConcurrencySafe: () => true,
535
- userFacingName: args => `Grep ${args.pattern}`,
536
- getSummary: (args, result) => {
537
- const pattern = args.pattern;
538
- if (!result.success)
539
- return `🔎 grep /${pattern}/ → error`;
540
- const count = result.output.split('\n').filter(l => l && !l.startsWith('--')).length;
541
- return `🔎 grep /${pattern}/ → ${count} matches`;
542
- },
543
- }),
544
- (0, tool_1.buildTool)({
545
- name: 'batch_read',
546
- description: 'Run up to 8 read-only exploration tool calls in one ordered batch. Allowed tools: git_status, list_files, glob, grep, read_file.',
547
- parameters: {
548
- type: 'object',
549
- properties: {
550
- steps: {
551
- type: 'array',
552
- description: 'Array of steps: [{ "tool": "read_file", "args": { "path": "package.json" } }]. Max 8 steps.',
553
- items: {
554
- type: 'object',
555
- properties: {
556
- tool: { type: 'string', description: 'Allowed read-only tool name' },
557
- args: { type: 'object', description: 'Arguments for the tool' },
558
- },
559
- required: ['tool', 'args'],
560
- },
561
- maxItems: exports.BATCH_READ_MAX_STEPS,
562
- },
563
- reason: {
564
- type: 'string',
565
- description: 'Optional reason for this read-only batch.',
566
- },
567
- },
568
- required: ['steps'],
569
- },
570
- execute: async (args, context) => executeBatchRead(args, context),
571
- isReadOnly: () => true,
572
- isConcurrencySafe: () => true,
573
- userFacingName: args => {
574
- const count = Array.isArray(args.steps) ? args.steps.length : 0;
575
- return `Batch read ${count} steps`;
576
- },
577
- getSummary: (args, result) => {
578
- if (!result.success)
579
- return '📚 batch_read → error';
580
- const count = Array.isArray(args.steps) ? args.steps.length : 0;
581
- return `📚 batch_read → ${count} steps`;
582
- },
583
- }),
584
- // Memory tools
585
- (0, tool_1.buildTool)({
586
- name: 'memory_save',
587
- description: 'Save a memory entry to the persistent memory system. Memories help tailor behavior to user preferences.',
588
- parameters: {
589
- type: 'object',
590
- properties: {
591
- name: {
592
- type: 'string',
593
- description: 'Memory name (kebab-case, e.g., "user-role", "feedback-style")',
594
- },
595
- type: {
596
- type: 'string',
597
- enum: ['user', 'feedback', 'project', 'reference'],
598
- description: 'Memory type',
599
- },
600
- description: {
601
- type: 'string',
602
- description: 'One-line description for memory index',
603
- },
604
- content: {
605
- type: 'string',
606
- description: 'Memory content. For feedback/project: use rule + Why + How to apply structure',
607
- },
608
- },
609
- required: ['name', 'type', 'content'],
610
- },
611
- execute: async (args, context) => {
612
- const name = args.name;
613
- const type = args.type;
614
- const content = args.content;
615
- if (!name || typeof name !== 'string') {
616
- return { success: false, output: '', error: 'memory_save requires a name parameter' };
617
- }
618
- if (!type || !['user', 'feedback', 'project', 'reference'].includes(type)) {
619
- return {
620
- success: false,
621
- output: '',
622
- error: 'memory_save requires a valid type: user, feedback, project, or reference',
623
- };
624
- }
625
- if (!content || typeof content !== 'string') {
626
- return { success: false, output: '', error: 'memory_save requires a content parameter' };
627
- }
628
- const description = args.description || content.slice(0, 80);
629
- try {
630
- const projectPath = context?.cwd || process.cwd();
631
- const entry = {
632
- name,
633
- type,
634
- description,
635
- content,
636
- createdAt: Date.now(),
637
- updatedAt: Date.now(),
638
- };
639
- if ((0, semantic_config_1.isSemanticEnabled)()) {
640
- // saveAndIndex internally calls saveMemory + vectorStore.upsert
641
- const { getSemanticSearchService } = await Promise.resolve().then(() => __importStar(require('../memory/semantic-search')));
642
- await getSemanticSearchService().saveAndIndex(entry, projectPath);
643
- }
644
- else {
645
- (0, storage_1.saveMemory)(entry, projectPath);
646
- }
647
- return { success: true, output: `Saved memory: ${name} (${type})` };
648
- }
649
- catch (err) {
650
- return { success: false, output: '', error: (0, errors_1.errorMessage)(err) };
651
- }
652
- },
653
- isReadOnly: () => false,
654
- userFacingName: args => `Memory save ${args.name}`,
655
- getSummary: (args, result) => {
656
- const name = args.name;
657
- const type = args.type;
658
- if (!result.success)
659
- return `🧠 save ${name} → error`;
660
- return `🧠 save ${name} (${type})`;
661
- },
662
- }),
663
- (0, tool_1.buildTool)({
664
- name: 'memory_recall',
665
- description: 'Recall memories from the memory system. Returns matching memories or all if no query.',
666
- parameters: {
667
- type: 'object',
668
- properties: {
669
- query: {
670
- type: 'string',
671
- description: 'Search query (optional, returns all if empty)',
672
- },
673
- type: {
674
- type: 'string',
675
- enum: ['user', 'feedback', 'project', 'reference'],
676
- description: 'Filter by memory type (optional)',
677
- },
678
- },
679
- required: [],
680
- },
681
- execute: async (args, context) => {
682
- try {
683
- const projectPath = context?.cwd || process.cwd();
684
- const query = args.query || '';
685
- const type = args.type;
686
- let memories;
687
- if (query && (0, semantic_config_1.isSemanticEnabled)()) {
688
- // Semantic path: ask the vector store, then fall back to keywords if it
689
- // returns nothing (e.g. embedding provider unreachable, empty index)
690
- try {
691
- const { getSemanticSearchService } = await Promise.resolve().then(() => __importStar(require('../memory/semantic-search')));
692
- const result = await getSemanticSearchService().search({
693
- query,
694
- projectPath,
695
- type,
696
- });
697
- memories = result.memories.map(m => ({
698
- name: m.name,
699
- type: m.type,
700
- description: m.description,
701
- content: m.content,
702
- createdAt: m.createdAt,
703
- updatedAt: m.createdAt,
704
- }));
705
- if (memories.length === 0) {
706
- memories = (0, storage_1.searchMemories)(query, projectPath);
707
- if (type)
708
- memories = memories.filter(m => m.type === type);
709
- }
710
- }
711
- catch (error) {
712
- (0, debug_log_1.debugError)('tools.memory.semanticSearch', error, query);
713
- memories = (0, storage_1.searchMemories)(query, projectPath);
714
- if (type)
715
- memories = memories.filter(m => m.type === type);
716
- }
717
- }
718
- else if (type) {
719
- memories = (0, storage_1.loadAllMemories)(projectPath).filter(m => m.type === type);
720
- }
721
- else if (query) {
722
- memories = (0, storage_1.searchMemories)(query, projectPath);
723
- }
724
- else {
725
- memories = (0, storage_1.loadAllMemories)(projectPath);
726
- }
727
- if (memories.length === 0) {
728
- return { success: true, output: 'No memories found' };
729
- }
730
- const lines = [];
731
- for (const mem of memories) {
732
- lines.push(`## ${mem.name} (${mem.type})`);
733
- lines.push(mem.description);
734
- lines.push(mem.content);
735
- lines.push('');
736
- }
737
- return { success: true, output: lines.join('\n') };
738
- }
739
- catch (err) {
740
- return { success: false, output: '', error: (0, errors_1.errorMessage)(err) };
741
- }
742
- },
743
- isReadOnly: () => true,
744
- userFacingName: args => `Memory recall ${args.query || 'all'}`,
745
- getSummary: (args, result) => {
746
- const query = args.query || 'all';
747
- if (!result.success)
748
- return `🧠 recall "${query}" → error`;
749
- if (result.output === 'No memories found')
750
- return `🧠 recall "${query}" → 0 found`;
751
- const count = result.output.split(/^## /m).length - 1;
752
- return `🧠 recall "${query}" → ${count} memories`;
753
- },
754
- }),
755
- (0, tool_1.buildTool)({
756
- name: 'memory_forget',
757
- description: 'Delete a memory entry from the memory system.',
758
- parameters: {
759
- type: 'object',
760
- properties: {
761
- name: {
762
- type: 'string',
763
- description: 'Memory name to delete',
764
- },
765
- },
766
- required: ['name'],
767
- },
768
- execute: async (args, context) => {
769
- const name = args.name;
770
- if (!name || typeof name !== 'string') {
771
- return { success: false, output: '', error: 'memory_forget requires a name parameter' };
772
- }
773
- try {
774
- const projectPath = context?.cwd || process.cwd();
775
- const existing = (0, storage_1.loadMemory)(name, projectPath);
776
- if (!existing) {
777
- return { success: false, output: '', error: `Memory not found: ${name}` };
778
- }
779
- (0, storage_1.deleteMemory)(name, projectPath);
780
- if ((0, semantic_config_1.isSemanticEnabled)()) {
781
- try {
782
- const { getVectorStore } = require('../memory/vector-store');
783
- getVectorStore().delete(name, projectPath);
784
- }
785
- catch (error) {
786
- // Vector store cleanup is best-effort, but a failure leaves an
787
- // orphaned embedding that keeps surfacing a deleted memory.
788
- (0, debug_log_1.debugError)('tools.memory.vectorDelete', error, name);
789
- }
790
- }
791
- return { success: true, output: `Deleted memory: ${name}` };
792
- }
793
- catch (err) {
794
- return { success: false, output: '', error: (0, errors_1.errorMessage)(err) };
795
- }
796
- },
797
- isReadOnly: () => false,
798
- userFacingName: args => `Memory forget ${args.name}`,
799
- getSummary: (args, result) => {
800
- const name = args.name;
801
- if (!result.success)
802
- return `🧠 forget ${name} → error`;
803
- return `🧠 forget ${name}`;
804
- },
805
- }),
806
- // History search tool
807
- (0, tool_1.buildTool)({
808
- name: 'history_search',
809
- description: 'Search previous tool operations in current or past sessions. Helps find what was done before.',
810
- parameters: {
811
- type: 'object',
812
- properties: {
813
- query: {
814
- type: 'string',
815
- description: 'Search query (tool name, file path, keyword)',
816
- },
817
- sessionId: {
818
- type: 'string',
819
- description: 'Session ID to search (optional, defaults to searching recent sessions)',
820
- },
821
- limit: {
822
- type: 'number',
823
- description: 'Max results (optional, default 10)',
824
- },
825
- },
826
- required: ['query'],
827
- },
828
- execute: async (args) => {
829
- const query = args.query;
830
- if (!query || typeof query !== 'string') {
831
- return { success: false, output: '', error: 'history_search requires a query parameter' };
832
- }
833
- try {
834
- const limit = args.limit || 10;
835
- const sessionId = args.sessionId;
836
- // If sessionId provided, search that session; otherwise search all recent sessions
837
- const sessions = sessionId
838
- ? [(0, session_storage_1.loadSessionMeta)(sessionId)].filter(Boolean)
839
- : (0, session_storage_1.listSessions)(5);
840
- const results = [];
841
- for (const session of sessions) {
842
- if (!session)
843
- continue;
844
- const messages = (0, session_storage_1.readSessionMessages)(session.id);
845
- // Search through messages for tool calls matching query
846
- for (let i = 0; i < messages.length; i++) {
847
- const msg = messages[i];
848
- if (msg.role === 'assistant' && msg.tool_calls) {
849
- for (const tc of msg.tool_calls) {
850
- // Match tool name or arguments content
851
- const matchesQuery = tc.function.name.toLowerCase().includes(query.toLowerCase()) ||
852
- tc.function.arguments.toLowerCase().includes(query.toLowerCase());
853
- if (matchesQuery) {
854
- // Find corresponding tool result
855
- const nextMsg = messages[i + 1];
856
- const resultPreview = nextMsg?.role === 'tool' && nextMsg.toolCallId === tc.id
857
- ? nextMsg.content.slice(0, 200)
858
- : '(no result)';
859
- results.push({
860
- sessionId: session.id.slice(0, 8),
861
- tool: tc.function.name,
862
- args: tc.function.arguments.slice(0, 100),
863
- resultPreview,
864
- timestamp: msg.timestamp,
865
- });
866
- }
867
- }
868
- }
869
- }
870
- }
871
- // Sort by timestamp (newest first) and limit
872
- results.sort((a, b) => b.timestamp - a.timestamp);
873
- const limited = results.slice(0, limit);
874
- if (limited.length === 0) {
875
- return { success: true, output: 'No matching tool operations found' };
876
- }
877
- const lines = [];
878
- lines.push(`Found ${limited.length} matching operations:`);
879
- lines.push('');
880
- for (const r of limited) {
881
- lines.push(`Session ${r.sessionId}: ${r.tool}`);
882
- lines.push(` Args: ${r.args}`);
883
- lines.push(` Result: ${r.resultPreview.slice(0, 100)}...`);
884
- lines.push('');
885
- }
886
- return { success: true, output: lines.join('\n') };
887
- }
888
- catch (err) {
889
- return { success: false, output: '', error: (0, errors_1.errorMessage)(err) };
890
- }
891
- },
892
- isReadOnly: () => true,
893
- userFacingName: args => `History search ${args.query}`,
894
- getSummary: (args, result) => {
895
- const query = args.query;
896
- if (!result.success)
897
- return `📜 history "${query}" → error`;
898
- if (result.output.startsWith('No matching'))
899
- return `📜 history "${query}" → 0 found`;
900
- const match = result.output.match(/Found (\d+) matching/);
901
- const count = match ? match[1] : '?';
902
- return `📜 history "${query}" → ${count} found`;
903
- },
904
- }),
905
- ];
906
- /**
907
- * Runtime tool pool.
908
- *
909
- * Static Orion Code tools are always present. Connected MCP server tools are
910
- * exposed as first-class tools named mcp__<server>__<tool>, matching the
911
- * convention used by Claude Code, Codex, and OpenClaude.
912
- */
913
- function getRuntimeTools() {
914
- return [...exports.TOOLS, ...mcp_1.mcpManager.getOrionCodeTools()];
915
- }
916
- // ============================================================================
917
- // 工具实现
918
- // ============================================================================
919
- /** Normalize model/tool path strings before resolving them on disk. */
920
- function normalizeToolPath(input) {
921
- let value = input.trim();
922
- const markdownLink = value.match(/^!?\[[^\]]*\]\(([\s\S]+)\)$/u);
923
- if (markdownLink) {
924
- value = markdownLink[1].trim();
925
- if (value.startsWith('<')) {
926
- const end = value.indexOf('>');
927
- if (end >= 0) {
928
- value = value.slice(1, end);
929
- }
930
- }
931
- else {
932
- value = value.replace(/\s+["'][\s\S]*["']$/u, '');
933
- }
934
- }
935
- if ((value.startsWith('`') && value.endsWith('`')) ||
936
- (value.startsWith('"') && value.endsWith('"')) ||
937
- (value.startsWith("'") && value.endsWith("'"))) {
938
- value = value.slice(1, -1);
939
- }
940
- if (value.startsWith('file://')) {
941
- try {
942
- return decodeURIComponent(new URL(value).pathname);
943
- }
944
- catch (error) {
945
- // Malformed URL or bad percent-encoding: strip the scheme so the path
946
- // still reaches the caller's own validation instead of vanishing.
947
- return value.replace(/^file:\/\//u, '');
948
- }
949
- }
950
- // Plain filesystem paths are not URLs: do NOT percent-decode them, or a
951
- // literal filename like "lit%41.txt" is silently rewritten to "litA.txt".
952
- return value;
953
- }
954
- /** Safely stat a path, returning null for dangling symlinks or missing files
955
- * instead of throwing ENOENT. Uses lstatSync to avoid following symlinks
956
- * when checking existence. */
957
- function safeStatSync(resolved) {
958
- try {
959
- // lstatSync does NOT follow symlinks — safe for dangling ones.
960
- const lst = (0, fs_1.lstatSync)(resolved);
961
- if (lst.isSymbolicLink()) {
962
- // For symlinks, use statSync (follows the link) inside try/catch.
963
- // If the target doesn't exist, statSync throws ENOENT — catch and return null.
964
- try {
965
- return (0, fs_1.statSync)(resolved);
966
- }
967
- catch {
968
- return null; // dangling symlink
969
- }
970
- }
971
- return (0, fs_1.statSync)(resolved);
972
- }
973
- catch {
974
- return null; // path doesn't exist at all
975
- }
976
- }
977
- /** Read a file safely, returning null for dangling symlinks or unreadable files. */
978
- function safeReadFileSync(resolved) {
979
- try {
980
- // Check if it's a dangling symlink before attempting read.
981
- const st = safeStatSync(resolved);
982
- if (!st || st.isDirectory())
983
- return null;
984
- return (0, fs_1.readFileSync)(resolved, 'utf-8');
985
- }
986
- catch (error) {
987
- // Permission denied or a binary that is not valid UTF-8; callers treat null
988
- // as "no content", which otherwise hides a real read failure.
989
- (0, debug_log_1.debugError)('tools.safeReadFile', error, resolved);
990
- return null;
991
- }
992
- }
993
- /** Resolve tool path parameters relative to the current tool cwd. */
994
- function safePath(input, cwd = process.cwd()) {
995
- return (0, path_1.resolve)(cwd, normalizeToolPath(input));
996
- }
997
- /**
998
- * Return true when `p` resolves (after following symlinks) to a location at or
999
- * under `rootReal`. Used to enforce that a realpath is still inside the
1000
- * workspace even when directories along the path are themselves symlinks.
1001
- */
1002
- function isWithinWorkspace(resolved, cwd) {
1003
- return (0, workspace_containment_1.isWorkspacePath)(cwd, resolved);
1004
- }
1005
- function isExecCwdWithinWorkspace(workdir, projectRoot) {
1006
- const root = (0, path_1.resolve)(projectRoot);
1007
- const rel = (0, path_1.relative)(root, workdir);
1008
- if (!(rel === '' || (!rel.startsWith('..') && !(0, path_1.isAbsolute)(rel))))
1009
- return false;
1010
- // A missing synthetic root can only fail at spawn time; lexical containment
1011
- // still prevents it from selecting an external directory. Real workspaces
1012
- // take the shared symlink-aware boundary check.
1013
- return (0, fs_1.existsSync)(root) ? (0, workspace_containment_1.isWorkspacePath)(root, workdir) : true;
1014
- }
1015
- /**
1016
- * Truncate text to at most maxBytes UTF-8 bytes, cutting on a character
1017
- * boundary (never inside a multi-byte sequence or surrogate pair). Returns the
1018
- * truncated text and the byte length it was cut at. String.slice counts UTF-16
1019
- * code units, not bytes, so it is wrong for enforcing a byte budget on CJK or
1020
- * emoji content and can split a surrogate pair.
1021
- */
1022
- function truncateToBytes(text, maxBytes) {
1023
- const buf = Buffer.from(text, 'utf-8');
1024
- if (buf.length <= maxBytes)
1025
- return { text, bytes: buf.length };
1026
- let cut = maxBytes;
1027
- // Walk back past UTF-8 continuation bytes (0x80-0xBF) to a lead-byte boundary.
1028
- while (cut > 0 && (buf[cut] & 0xc0) === 0x80)
1029
- cut--;
1030
- return { text: buf.subarray(0, cut).toString('utf-8'), bytes: cut };
1031
- }
1032
- function readPositiveInteger(value, name, defaultValue) {
1033
- if (value === undefined)
1034
- return defaultValue;
1035
- if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 1) {
1036
- return `read_file ${name} must be a positive integer`;
1037
- }
1038
- return value;
1039
- }
1040
- async function readFileSync_(path, maxLines, offset, cwd) {
1041
- try {
1042
- const normalizedPath = normalizeToolPath(path);
1043
- const resolved = safePath(path, cwd);
1044
- const workspaceRoot = cwd ?? process.cwd();
1045
- if (!isWithinWorkspace(resolved, workspaceRoot)) {
1046
- return {
1047
- success: false,
1048
- output: '',
1049
- error: `Refusing to read outside the workspace: ${normalizedPath}`,
1050
- };
1051
- }
1052
- if (!(0, fs_1.existsSync)(resolved)) {
1053
- return { success: false, output: '', error: `File not found: ${normalizedPath}` };
1054
- }
1055
- const st = safeStatSync(resolved);
1056
- if (!st) {
1057
- return {
1058
- success: false,
1059
- output: '',
1060
- error: `Cannot access file: ${normalizedPath} (may be a dangling symlink or missing)`,
1061
- };
1062
- }
1063
- if (st.isDirectory()) {
1064
- return {
1065
- success: false,
1066
- output: '',
1067
- error: `Path is a directory, not a file: ${normalizedPath}`,
1068
- };
1069
- }
1070
- const content = safeReadFileSync(resolved);
1071
- if (content === null) {
1072
- return {
1073
- success: false,
1074
- output: '',
1075
- error: `Cannot read file: ${normalizedPath}`,
1076
- };
1077
- }
1078
- const lines = content.split('\n');
1079
- const maxBytes = 51200; // 50KB byte limit
1080
- if (offset > lines.length) {
1081
- return {
1082
- success: false,
1083
- output: '',
1084
- error: `read_file offset ${offset} is beyond the file (${lines.length} lines)`,
1085
- };
1086
- }
1087
- const startIndex = offset - 1;
1088
- const selectedLines = lines.slice(startIndex, startIndex + maxLines);
1089
- const selected = selectedLines.join('\n');
1090
- const remainingLines = Math.max(0, lines.length - startIndex - selectedLines.length);
1091
- if (remainingLines > 0) {
1092
- const byteLen = Buffer.byteLength(selected, 'utf8');
1093
- const notice = `\n\n[... truncated, ${remainingLines} more lines; showing lines ${offset}-${offset + selectedLines.length - 1} of ${lines.length}]`;
1094
- if (byteLen > maxBytes) {
1095
- const cut = truncateToBytes(selected, maxBytes);
1096
- return {
1097
- success: true,
1098
- output: cut.text + `\n\n[... truncated at ${cut.bytes}B]`,
1099
- };
1100
- }
1101
- return { success: true, output: selected + notice };
1102
- }
1103
- // Also apply byte limit to the selected page.
1104
- const byteLen = Buffer.byteLength(selected, 'utf8');
1105
- if (byteLen > maxBytes) {
1106
- const cut = truncateToBytes(selected, maxBytes);
1107
- return {
1108
- success: true,
1109
- output: cut.text + `\n\n[... truncated at ${cut.bytes}B of ${byteLen}B]`,
1110
- };
1111
- }
1112
- return { success: true, output: selected };
1113
- }
1114
- catch (err) {
1115
- return { success: false, output: '', error: (0, errors_1.errorMessage)(err) };
1116
- }
1117
- }
1118
- async function writeFileSync_(path, content, cwd) {
1119
- try {
1120
- const normalizedPath = normalizeToolPath(path);
1121
- const resolved = safePath(path, cwd);
1122
- const workspaceRoot = cwd ?? process.cwd();
1123
- if (!isWithinWorkspace(resolved, workspaceRoot)) {
1124
- return {
1125
- success: false,
1126
- output: '',
1127
- error: `Refusing to write outside the workspace: ${normalizedPath}`,
1128
- };
1129
- }
1130
- (0, fs_1.mkdirSync)((0, path_1.dirname)(resolved), { recursive: true });
1131
- (0, fs_1.writeFileSync)(resolved, content, 'utf-8');
1132
- return {
1133
- success: true,
1134
- output: `Wrote ${content.split('\n').length} lines to ${normalizedPath}`,
1135
- };
1136
- }
1137
- catch (err) {
1138
- return { success: false, output: '', error: (0, errors_1.errorMessage)(err) };
1139
- }
1140
- }
1141
- async function listFiles_(path, maxDepth, cwd) {
1142
- const normalizedPath = normalizeToolPath(path);
1143
- const resolved = safePath(path, cwd);
1144
- const workspaceRoot = cwd ?? process.cwd();
1145
- if (!isWithinWorkspace(resolved, workspaceRoot)) {
1146
- return {
1147
- success: false,
1148
- output: '',
1149
- error: `Refusing to list outside the workspace: ${normalizedPath}`,
1150
- };
1151
- }
1152
- if (!(0, fs_1.existsSync)(resolved)) {
1153
- return { success: false, output: '', error: `Path not found: ${normalizedPath}` };
1154
- }
1155
- if (!(0, fs_1.statSync)(resolved).isDirectory()) {
1156
- return { success: true, output: normalizedPath };
1157
- }
1158
- const depth = maxDepth ?? 2;
1159
- const results = [];
1160
- function walk(dir, currentDepth, prefix) {
1161
- if (currentDepth > depth)
1162
- return;
1163
- try {
1164
- const entries = (0, fs_1.readdirSync)(dir, { withFileTypes: true });
1165
- for (const entry of entries) {
1166
- if (entry.name.startsWith('.') && entry.name !== '.')
1167
- continue;
1168
- const fullPath = (0, path_1.join)(dir, entry.name);
1169
- const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
1170
- if (entry.isDirectory()) {
1171
- results.push(`${relPath}/`);
1172
- walk(fullPath, currentDepth + 1, relPath);
1173
- }
1174
- else {
1175
- results.push(relPath);
1176
- }
1177
- }
1178
- }
1179
- catch {
1180
- // skip unreadable directories
1181
- }
1182
- }
1183
- walk(resolved, 1, '');
1184
- // Limit output to 500 entries
1185
- const maxEntries = 500;
1186
- const output = results.length > maxEntries
1187
- ? results.slice(0, maxEntries).join('\n') +
1188
- `\n\n[... truncated, ${results.length - maxEntries} more entries]`
1189
- : results.join('\n');
1190
- return { success: true, output };
1191
- }
1192
- // Issue #32 #3.2: execCommand_ 支持 abortSignal
1193
- function resolveExecCommandPaths(cwd, baseCwd) {
1194
- const projectRoot = (0, path_1.resolve)(baseCwd ?? process.cwd());
1195
- if (!cwd)
1196
- return { workdir: projectRoot, projectRoot };
1197
- const normalizedCwd = normalizeToolPath(cwd);
1198
- if ((0, path_1.isAbsolute)(normalizedCwd)) {
1199
- throw new Error('exec_command cwd must be a workspace-relative path');
1200
- }
1201
- const workdir = safePath(normalizedCwd, projectRoot);
1202
- if (!isExecCwdWithinWorkspace(workdir, projectRoot)) {
1203
- throw new Error('exec_command cwd must stay within the workspace');
1204
- }
1205
- return {
1206
- workdir,
1207
- projectRoot,
1208
- };
1209
- }
1210
- async function execCommand_(command, cwd, timeout, maxOutput, abortSignal, baseCwd, sandbox) {
1211
- let paths;
1212
- try {
1213
- paths = resolveExecCommandPaths(cwd, baseCwd);
1214
- }
1215
- catch (error) {
1216
- return {
1217
- success: false,
1218
- output: '',
1219
- error: error instanceof Error ? error.message : 'exec_command cwd is outside workspace',
1220
- };
1221
- }
1222
- const { workdir, projectRoot } = paths;
1223
- // v0.1.3-2 §1.2: plan the (possibly sandboxed) argv before spawning. A
1224
- // configured sandbox that cannot be honoured must refuse the command rather
1225
- // than silently degrade into an unsandboxed run.
1226
- const plan = (0, sandbox_1.planSandboxedCommand)(command, {
1227
- cwd: workdir,
1228
- projectRoot,
1229
- settings: sandbox ?? (0, sandbox_1.resolveSandboxSettings)(projectRoot),
1230
- });
1231
- if (!plan.ok) {
1232
- return {
1233
- success: false,
1234
- output: '',
1235
- error: `Refusing to run: sandbox profile "${plan.profile}" is configured but cannot be applied — ${plan.reason}. ` +
1236
- 'Set sandbox.profile to "none" to run without isolation.',
1237
- };
1238
- }
1239
- return new Promise(resolve => {
1240
- const timeoutMs = timeout ?? 30000;
1241
- const maxBytes = maxOutput ?? 51200; // Default 50KB, Issue #28 fix
1242
- // The docker backend bind-mounts `workdir` into the container; the host
1243
- // directory must exist at container-creation time or the mount fails with a
1244
- // confusing "nonexistent directory" error. Create it deterministically
1245
- // rather than relying on docker to materialise it.
1246
- if (plan.backend === 'docker') {
1247
- try {
1248
- (0, fs_1.mkdirSync)(workdir, { recursive: true });
1249
- }
1250
- catch {
1251
- // If it cannot be created we let the spawn fail with a clear error.
1252
- }
1253
- }
1254
- // Use spawn for streaming output with truncation support. The user command
1255
- // is a single argv element, so no intermediate shell re-parses it.
1256
- const useProcessGroup = process.platform !== 'win32';
1257
- const child = (0, child_process_1.spawn)(plan.file, plan.args, {
1258
- cwd: workdir,
1259
- detached: useProcessGroup,
1260
- });
1261
- // Issue #53: exec_command runs a complete command as a single argv element
1262
- // and never pipes input into it. If stdin stays open, stdin-reading commands
1263
- // (cat, sort, grep, `python3 -`, ...) block waiting for EOF until the timeout.
1264
- // Close it immediately so the child receives EOF and can proceed.
1265
- child.stdin?.end();
1266
- let stdoutData = '';
1267
- let stderrData = '';
1268
- let stdoutTruncated = false;
1269
- let stderrTruncated = false;
1270
- // Issue #32 修复:使用独立计数器
1271
- let stdoutBytes = 0;
1272
- let stderrBytes = 0;
1273
- let interrupted = null;
1274
- // Issue #32 #3.2: AbortSignal 处理
1275
- // Declared uninitialized on purpose: `finish()` below closes over it before the
1276
- // `timeoutId = setTimeout(...)` assignment. `const` without an initializer is a
1277
- // compile error (TS1155), and inlining the assignment would put it in the closure's TDZ.
1278
- // eslint-disable-next-line prefer-const
1279
- let timeoutId;
1280
- let killTimerId;
1281
- let settled = false;
1282
- const finish = (result) => {
1283
- if (settled)
1284
- return;
1285
- settled = true;
1286
- if (timeoutId)
1287
- clearTimeout(timeoutId);
1288
- if (killTimerId)
1289
- clearTimeout(killTimerId);
1290
- if (abortSignal) {
1291
- abortSignal.removeEventListener('abort', abortHandler);
1292
- }
1293
- resolve(result);
1294
- };
1295
- const terminateChild = () => {
1296
- if (!child.pid || child.killed)
1297
- return;
1298
- try {
1299
- if (useProcessGroup) {
1300
- process.kill(-child.pid, 'SIGTERM');
1301
- }
1302
- else {
1303
- child.kill('SIGTERM');
1304
- }
1305
- }
1306
- catch {
1307
- child.kill('SIGTERM');
1308
- }
1309
- killTimerId = setTimeout(() => {
1310
- if (!child.pid || child.killed || settled)
1311
- return;
1312
- try {
1313
- if (useProcessGroup) {
1314
- process.kill(-child.pid, 'SIGKILL');
1315
- }
1316
- else {
1317
- child.kill('SIGKILL');
1318
- }
1319
- }
1320
- catch {
1321
- child.kill('SIGKILL');
1322
- }
1323
- }, 500);
1324
- killTimerId.unref?.();
1325
- };
1326
- const abortHandler = () => {
1327
- interrupted = 'aborted';
1328
- terminateChild();
1329
- };
1330
- if (abortSignal) {
1331
- abortSignal.addEventListener('abort', abortHandler);
1332
- if (abortSignal.aborted) {
1333
- abortHandler();
1334
- }
1335
- }
1336
- // Timeout handling
1337
- timeoutId = setTimeout(() => {
1338
- if (!interrupted) {
1339
- interrupted = 'timeout';
1340
- terminateChild();
1341
- }
1342
- }, timeoutMs);
1343
- // Stream stdout with truncation
1344
- child.stdout.on('data', (data) => {
1345
- if (!stdoutTruncated) {
1346
- const chunk = data.toString();
1347
- // Issue #30: count UTF-8 bytes, not UTF-16 code units, so CJK/emoji
1348
- // output is bounded by `maxBytes` (a UTF-16 count could exceed it ~2x).
1349
- const chunkBytes = Buffer.byteLength(chunk, 'utf8');
1350
- if (stdoutBytes + chunkBytes > maxBytes) {
1351
- stdoutTruncated = true;
1352
- const room = Math.max(0, maxBytes - stdoutBytes);
1353
- // Byte-accurate truncation that respects multi-byte character boundaries.
1354
- stdoutData += truncateToBytes(chunk, room).text;
1355
- stdoutBytes = maxBytes;
1356
- }
1357
- else {
1358
- stdoutData += chunk;
1359
- stdoutBytes += chunkBytes;
1360
- }
1361
- }
1362
- });
1363
- // Stream stderr with truncation (Issue #32 修复:使用独立计数器)
1364
- child.stderr.on('data', (data) => {
1365
- if (!stderrTruncated) {
1366
- const chunk = data.toString();
1367
- // Issue #30: count UTF-8 bytes, not UTF-16 code units.
1368
- const chunkBytes = Buffer.byteLength(chunk, 'utf8');
1369
- if (stderrBytes + chunkBytes > maxBytes) {
1370
- stderrTruncated = true;
1371
- const room = Math.max(0, maxBytes - stderrBytes);
1372
- stderrData += truncateToBytes(chunk, room).text;
1373
- stderrBytes = maxBytes;
1374
- }
1375
- else {
1376
- stderrData += chunk;
1377
- stderrBytes += chunkBytes;
1378
- }
1379
- }
1380
- });
1381
- child.on('close', code => {
1382
- if (interrupted === 'aborted') {
1383
- finish({
1384
- success: false,
1385
- output: truncateToBytes(stdoutData, maxBytes).text,
1386
- error: 'Command aborted by user',
1387
- });
1388
- return;
1389
- }
1390
- if (interrupted === 'timeout') {
1391
- finish({
1392
- success: false,
1393
- output: truncateToBytes(stdoutData, maxBytes).text,
1394
- error: `Command timed out after ${timeoutMs}ms`,
1395
- });
1396
- return;
1397
- }
1398
- const output = stdoutData.trim();
1399
- const errOutput = stderrData.trim();
1400
- // Add truncation notice if output was truncated
1401
- let finalOutput = output;
1402
- if (stdoutTruncated) {
1403
- finalOutput += '\n\n[... output truncated, exceeded 50KB limit]';
1404
- }
1405
- if (code !== 0) {
1406
- finish({
1407
- success: false,
1408
- output: finalOutput || errOutput,
1409
- error: `Command exited with code ${code}`,
1410
- });
1411
- }
1412
- else {
1413
- finish({
1414
- success: true,
1415
- output: finalOutput || '(no output)',
1416
- error: stderrTruncated
1417
- ? errOutput + '\n\n[... stderr truncated]'
1418
- : errOutput || undefined,
1419
- });
1420
- }
1421
- });
1422
- child.on('error', err => {
1423
- finish({
1424
- success: false,
1425
- output: '',
1426
- error: err.message,
1427
- });
1428
- });
1429
- });
1430
- }
1431
- function lineNumberForIndex(content, index) {
1432
- return content.slice(0, Math.max(0, index)).split('\n').length;
1433
- }
1434
- function findAllMatchIndexes(content, needle, limit = 20) {
1435
- const indexes = [];
1436
- let cursor = 0;
1437
- while (indexes.length < limit) {
1438
- const index = content.indexOf(needle, cursor);
1439
- if (index < 0)
1440
- break;
1441
- indexes.push(index);
1442
- cursor = index + Math.max(needle.length, 1);
1443
- }
1444
- return indexes;
1445
- }
1446
- function previewLine(text) {
1447
- return text.replace(/\s+/g, ' ').trim().slice(0, 120);
1448
- }
1449
- function buildEditCandidates(params) {
1450
- const cursorByMatch = new Map();
1451
- return params.matches.slice(0, 20).map((match, index) => {
1452
- const cursor = cursorByMatch.get(match) ?? 0;
1453
- const matchIndex = params.content.indexOf(match, cursor);
1454
- cursorByMatch.set(match, matchIndex >= 0 ? matchIndex + Math.max(match.length, 1) : cursor);
1455
- const lineNum = matchIndex >= 0 ? lineNumberForIndex(params.content, matchIndex) : 0;
1456
- // Get context lines (3 before, 3 after)
1457
- const allLines = params.content.split('\n');
1458
- const contextBefore = allLines.slice(Math.max(0, lineNum - 4), lineNum).join('\n');
1459
- const contextAfter = allLines.slice(lineNum + 1, lineNum + 4).join('\n');
1460
- return {
1461
- index,
1462
- line: lineNum,
1463
- match,
1464
- contextBefore,
1465
- contextAfter,
1466
- isReplaceAll: (params.count ?? 1) > 1,
1467
- };
1468
- });
1469
- }
1470
- function formatEditPreview(params) {
1471
- const cursorByMatch = new Map();
1472
- const lines = [
1473
- `Preview: ${params.kind === 'fuzzy' ? `Fuzzy ${params.strategy ?? 'match'}` : 'Exact match'} candidates (${params.matches.length})`,
1474
- ];
1475
- params.matches.slice(0, 20).forEach((match, index) => {
1476
- const cursor = cursorByMatch.get(match) ?? 0;
1477
- const matchIndex = params.content.indexOf(match, cursor);
1478
- cursorByMatch.set(match, matchIndex >= 0 ? matchIndex + Math.max(match.length, 1) : cursor);
1479
- const lineNum = matchIndex >= 0 ? lineNumberForIndex(params.content, matchIndex) : '?';
1480
- lines.push(`${index + 1}. line ${lineNum}: "${previewLine(match)}"`);
1481
- });
1482
- if (params.matches.length > 20) {
1483
- lines.push(`... ${params.matches.length - 20} more candidates omitted`);
1484
- }
1485
- lines.push(`Would replace with: "${previewLine(params.newString)}"`);
1486
- return lines.join('\n');
1487
- }
1488
- /**
1489
- * Attempt to find old_string in content using fuzzy matching strategies.
1490
- * Returns null if no match found, or the matched strings.
1491
- */
1492
- function fuzzyMatch(content, oldString) {
1493
- // Strategy 1: Line-by-line matching (allow different indentation)
1494
- const oldLines = oldString
1495
- .split('\n')
1496
- .map(l => l.trim())
1497
- .filter(Boolean);
1498
- const contentLines = content.split('\n');
1499
- const lineMatches = [];
1500
- for (let i = 0; i <= contentLines.length - oldLines.length; i++) {
1501
- let allMatch = true;
1502
- for (let j = 0; j < oldLines.length; j++) {
1503
- if (contentLines[i + j].trim() !== oldLines[j]) {
1504
- allMatch = false;
1505
- break;
1506
- }
1507
- }
1508
- if (allMatch) {
1509
- const matchedStr = contentLines.slice(i, i + oldLines.length).join('\n');
1510
- lineMatches.push(matchedStr);
1511
- }
1512
- }
1513
- if (lineMatches.length > 0) {
1514
- return { matches: lineMatches, strategy: 'line' };
1515
- }
1516
- // Strategy 2: Whitespace-tolerant token match. This preserves the actual
1517
- // matched span without consuming unrelated leading/trailing blank lines.
1518
- const tokens = oldString.trim().split(/\s+/).filter(Boolean);
1519
- if (tokens.length === 0)
1520
- return null;
1521
- const pattern = tokens.map(escapeRegExp).join('\\s+');
1522
- const regex = new RegExp(pattern, 'g');
1523
- const wsMatches = [];
1524
- let match;
1525
- while ((match = regex.exec(content)) !== null) {
1526
- if (match[0]) {
1527
- wsMatches.push(match[0]);
1528
- }
1529
- if (wsMatches.length > 5)
1530
- break; // Safety limit
1531
- if (match.index === regex.lastIndex)
1532
- regex.lastIndex++;
1533
- }
1534
- if (wsMatches.length > 0) {
1535
- return { matches: wsMatches, strategy: 'whitespace' };
1536
- }
1537
- return null;
1538
- }
1539
- async function editFile_(path, old_string, new_string, replace_all, fuzzy_match, preview, cwd) {
1540
- try {
1541
- const normalizedPath = normalizeToolPath(path);
1542
- const resolved = safePath(path, cwd);
1543
- const workspaceRoot = cwd ?? process.cwd();
1544
- if (!isWithinWorkspace(resolved, workspaceRoot)) {
1545
- return {
1546
- success: false,
1547
- output: '',
1548
- error: `Refusing to edit outside the workspace: ${normalizedPath}`,
1549
- };
1550
- }
1551
- if (!(0, fs_1.existsSync)(resolved)) {
1552
- return { success: false, output: '', error: `File not found: ${normalizedPath}` };
1553
- }
1554
- const fileStat = safeStatSync(resolved);
1555
- if (!fileStat) {
1556
- return {
1557
- success: false,
1558
- output: '',
1559
- error: `Cannot access file: ${normalizedPath} (may be a dangling symlink)`,
1560
- };
1561
- }
1562
- if (fileStat.isDirectory()) {
1563
- return {
1564
- success: false,
1565
- output: '',
1566
- error: `Path is a directory, not a file: ${normalizedPath}`,
1567
- };
1568
- }
1569
- const content = safeReadFileSync(resolved);
1570
- if (content === null) {
1571
- return { success: false, output: '', error: `Cannot read file: ${normalizedPath}` };
1572
- }
1573
- // Check if old_string exists exactly
1574
- const count = (content.match(new RegExp(escapeRegExp(old_string), 'g')) || []).length;
1575
- if (count > 0 && preview) {
1576
- const matchIndexes = findAllMatchIndexes(content, old_string);
1577
- const matches = matchIndexes.map(() => old_string);
1578
- return {
1579
- success: true,
1580
- output: formatEditPreview({
1581
- kind: 'exact',
1582
- content,
1583
- matches,
1584
- newString: new_string,
1585
- }),
1586
- metadata: {
1587
- candidates: buildEditCandidates({
1588
- kind: 'exact',
1589
- content,
1590
- matches,
1591
- newString: new_string,
1592
- count,
1593
- }),
1594
- },
1595
- };
1596
- }
1597
- if (count === 0) {
1598
- if (!fuzzy_match) {
1599
- return {
1600
- success: false,
1601
- output: '',
1602
- error: `old_string not found in file: ${old_string.slice(0, 100)}...`,
1603
- };
1604
- }
1605
- // Try fuzzy match strategies
1606
- const fuzzyResult = fuzzyMatch(content, old_string);
1607
- if (fuzzyResult === null) {
1608
- return {
1609
- success: false,
1610
- output: '',
1611
- error: `old_string not found in file: ${old_string.slice(0, 100)}...`,
1612
- };
1613
- }
1614
- if (preview) {
1615
- return {
1616
- success: true,
1617
- output: formatEditPreview({
1618
- kind: 'fuzzy',
1619
- content,
1620
- matches: fuzzyResult.matches,
1621
- newString: new_string,
1622
- strategy: fuzzyResult.strategy,
1623
- }),
1624
- metadata: {
1625
- candidates: buildEditCandidates({
1626
- kind: 'fuzzy',
1627
- content,
1628
- matches: fuzzyResult.matches,
1629
- newString: new_string,
1630
- strategy: fuzzyResult.strategy,
1631
- }),
1632
- },
1633
- };
1634
- }
1635
- if (fuzzyResult.matches.length > 1) {
1636
- return {
1637
- success: false,
1638
- output: '',
1639
- error: `Fuzzy match found ${fuzzyResult.matches.length} candidates. Provide a more specific string. First 3 candidates:\n${fuzzyResult.matches
1640
- .slice(0, 3)
1641
- .map((m, i) => ` ${i + 1}: "${m.slice(0, 80)}..."`)
1642
- .join('\n')}`,
1643
- };
1644
- }
1645
- // Use the single fuzzy match only.
1646
- const match = fuzzyResult.matches[0];
1647
- const idx = content.indexOf(match);
1648
- const newContent = content.slice(0, idx) + new_string + content.slice(idx + match.length);
1649
- (0, fs_1.writeFileSync)(resolved, newContent, 'utf-8');
1650
- return {
1651
- success: true,
1652
- output: `Fuzzy edited ${normalizedPath} (matched by ${fuzzyResult.strategy}, "${match.slice(0, 50)}...")`,
1653
- };
1654
- }
1655
- // If not replace_all, require unique match
1656
- if (!replace_all && count > 1) {
1657
- return {
1658
- success: false,
1659
- output: '',
1660
- error: `old_string found ${count} times in file. Use replace_all=true to replace all occurrences, or provide a more specific string that matches exactly once.`,
1661
- };
1662
- }
1663
- // Perform replacement
1664
- let newContent;
1665
- if (replace_all) {
1666
- newContent = content.split(old_string).join(new_string);
1667
- }
1668
- else {
1669
- // Replace first occurrence only
1670
- const idx = content.indexOf(old_string);
1671
- newContent = content.slice(0, idx) + new_string + content.slice(idx + old_string.length);
1672
- }
1673
- (0, fs_1.writeFileSync)(resolved, newContent, 'utf-8');
1674
- return {
1675
- success: true,
1676
- output: `Replaced ${count} occurrence(s) of old_string with new_string in ${normalizedPath}`,
1677
- };
1678
- }
1679
- catch (err) {
1680
- return { success: false, output: '', error: (0, errors_1.errorMessage)(err) };
1681
- }
1682
- }
1683
- /** Escape special regex characters for literal matching */
1684
- function escapeRegExp(str) {
1685
- return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
1686
- }
1687
- /**
1688
- * Validate a caller-supplied regular expression pattern before compiling it.
1689
- *
1690
- * Issue #79: `grep_` compiles user/model-supplied patterns with `new RegExp`
1691
- * directly. A pathological pattern with a quantified group that itself contains
1692
- * a quantifier (e.g. `(a+)+`, `(\d+)*`) triggers catastrophic backtracking
1693
- * (ReDoS) and can hang the process on adversarial input (prompt injection).
1694
- * Reject empty/oversized patterns and the classic nested-quantifier shapes.
1695
- */
1696
- function validateRegexPattern(pattern) {
1697
- if (!pattern)
1698
- return 'pattern must not be empty';
1699
- if (pattern.length > 2000)
1700
- return 'pattern is too long (max 2000 characters)';
1701
- // A group containing an internal quantifier, then quantified again: the
1702
- // canonical exponential-backtracking construction. Quantifier families
1703
- // include braces; treating only `*+?` as quantifiers lets `(a{1,})+` hang
1704
- // the event loop on a long near miss.
1705
- const quantifier = String.raw `(?:[*+?]|\{\d+(?:,\d*)?\})`;
1706
- if (new RegExp(String.raw `\([^()]*${quantifier}[^()]*\)\s*${quantifier}`).test(pattern)) {
1707
- return 'pattern contains a quantified group with an internal quantifier — this risks catastrophic backtracking (ReDoS)';
1708
- }
1709
- // Reject the common overlapping-alternative form `(a|aa)+`: either branch
1710
- // can consume the same prefix, creating exponentially many partitions.
1711
- const quantifiedGroup = new RegExp(String.raw `\(([^()]*)\)\s*${quantifier}`, 'gu');
1712
- for (const match of pattern.matchAll(quantifiedGroup)) {
1713
- const alternatives = match[1].split('|');
1714
- if (alternatives.length > 1 &&
1715
- alternatives.some((left, index) => alternatives.some((right, otherIndex) => index !== otherIndex && left.length > 0 && right.length > 0 && right.startsWith(left)))) {
1716
- return 'pattern contains overlapping alternatives inside a quantified group — this risks catastrophic backtracking (ReDoS)';
1717
- }
1718
- }
1719
- try {
1720
- new RegExp(pattern);
1721
- }
1722
- catch {
1723
- return 'pattern is not a valid regular expression';
1724
- }
1725
- return null;
1726
- }
1727
- // ============================================================================
1728
- // Glob/Grep 工具实现
1729
- // ============================================================================
1730
- /**
1731
- * Glob 模式匹配 - 简化版实现
1732
- * 支持: **(递归目录)、*(任意字符)、?(单个字符)
1733
- */
1734
- async function glob_(pattern, basePath, cwd) {
1735
- try {
1736
- const normalizedBasePath = basePath ? normalizeToolPath(basePath) : (cwd ?? process.cwd());
1737
- const base = basePath ? safePath(basePath, cwd) : (cwd ?? process.cwd());
1738
- const workspaceRoot = cwd ?? process.cwd();
1739
- if (!isWithinWorkspace(base, workspaceRoot)) {
1740
- return {
1741
- success: false,
1742
- output: '',
1743
- error: `Refusing to search outside the workspace: ${normalizedBasePath}`,
1744
- };
1745
- }
1746
- if (!(0, fs_1.existsSync)(base)) {
1747
- return { success: false, output: '', error: `Path not found: ${normalizedBasePath}` };
1748
- }
1749
- if (!(0, fs_1.statSync)(base).isDirectory()) {
1750
- return {
1751
- success: false,
1752
- output: '',
1753
- error: `Path is not a directory: ${normalizedBasePath}`,
1754
- };
1755
- }
1756
- const results = [];
1757
- // Convert glob pattern to regex.
1758
- // Escape ALL regex metacharacters first, then translate glob wildcards.
1759
- // Escaping only `.` (the old behavior) left parens/brackets/+/^/$/| as
1760
- // regex syntax: a literal "(group)" became a capture group (so the real
1761
- // file stopped matching) and an unbalanced "[" made new RegExp throw.
1762
- function globToRegex(pat) {
1763
- // Use placeholders for glob wildcards so escaping does not touch them.
1764
- let regex = pat;
1765
- // **/ at start - matches optional path (including empty)
1766
- regex = regex.replace(/^\*\*\//, '<<STARSTAR_SLASH_START>>');
1767
- // **/ in middle - matches any number of path segments
1768
- regex = regex.replace(/\*\*\//g, '<<STARSTAR_SLASH>>');
1769
- // standalone ** - matches anything
1770
- regex = regex.replace(/\*\*/g, '<<STARSTAR>>');
1771
- // Escape every regex metacharacter in the remaining literal text.
1772
- // NOTE: * and ? are glob wildcards, handled below - do not escape them.
1773
- regex = regex.replace(/[.+^${}()|[\]\\]/g, '\\$&');
1774
- // * matches anything except /
1775
- regex = regex.replace(/\*/g, '[^/]*');
1776
- // ? matches single char except /
1777
- regex = regex.replace(/\?/g, '[^/]');
1778
- // Now restore ** placeholders
1779
- regex = regex.replace(/<<STARSTAR_SLASH_START>>/g, '(.*\\/)?');
1780
- regex = regex.replace(/<<STARSTAR_SLASH>>/g, '([^/]+\\/)*');
1781
- regex = regex.replace(/<<STARSTAR>>/g, '.*');
1782
- return new RegExp(`^${regex}$`);
1783
- }
1784
- const regex = globToRegex(pattern);
1785
- // Recursive walk with a depth cap so a pathological tree (or symlink loop)
1786
- // cannot hang or OOM the tool.
1787
- const MAX_DEPTH = 16;
1788
- function walk(dir, prefix, depth) {
1789
- if (depth > MAX_DEPTH)
1790
- return;
1791
- try {
1792
- const entries = (0, fs_1.readdirSync)(dir, { withFileTypes: true });
1793
- for (const entry of entries) {
1794
- if (entry.name.startsWith('.'))
1795
- continue;
1796
- const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
1797
- if (entry.isDirectory()) {
1798
- walk((0, path_1.join)(dir, entry.name), relPath, depth + 1);
1799
- }
1800
- else {
1801
- if (regex.test(relPath)) {
1802
- results.push(relPath);
1803
- }
1804
- }
1805
- }
1806
- }
1807
- catch {
1808
- // skip unreadable directories
1809
- }
1810
- }
1811
- walk(base, '', 0);
1812
- if (results.length === 0) {
1813
- return { success: true, output: 'No files found matching pattern' };
1814
- }
1815
- // Limit output to 200 matches
1816
- const maxMatches = 200;
1817
- const sorted = results.sort();
1818
- const output = sorted.length > maxMatches
1819
- ? sorted.slice(0, maxMatches).join('\n') +
1820
- `\n\n[... truncated, ${sorted.length - maxMatches} more matches]`
1821
- : sorted.join('\n');
1822
- return { success: true, output };
1823
- }
1824
- catch (err) {
1825
- return { success: false, output: '', error: (0, errors_1.errorMessage)(err) };
1826
- }
1827
- }
1828
- /**
1829
- * Grep 搜索 - 在文件中搜索正则表达式
1830
- */
1831
- async function grep_(pattern, basePath, globPattern, contextLines, cwd) {
1832
- try {
1833
- const normalizedBasePath = basePath ? normalizeToolPath(basePath) : (cwd ?? process.cwd());
1834
- const base = basePath ? safePath(basePath, cwd) : (cwd ?? process.cwd());
1835
- const workspaceRoot = cwd ?? process.cwd();
1836
- if (!isWithinWorkspace(base, workspaceRoot)) {
1837
- return {
1838
- success: false,
1839
- output: '',
1840
- error: `Refusing to search outside the workspace: ${normalizedBasePath}`,
1841
- };
1842
- }
1843
- if (!(0, fs_1.existsSync)(base)) {
1844
- return { success: false, output: '', error: `Path not found: ${normalizedBasePath}` };
1845
- }
1846
- const patternError = validateRegexPattern(pattern);
1847
- if (patternError) {
1848
- return { success: false, output: '', error: `Invalid grep pattern: ${patternError}` };
1849
- }
1850
- const regex = new RegExp(pattern);
1851
- const context = contextLines ?? 0;
1852
- const results = [];
1853
- const maxResults = 100;
1854
- // Get list of files to search
1855
- const files = [];
1856
- const skippedDangling = [];
1857
- function collectFiles(dir) {
1858
- try {
1859
- const entries = (0, fs_1.readdirSync)(dir, { withFileTypes: true });
1860
- for (const entry of entries) {
1861
- if (entry.name.startsWith('.'))
1862
- continue;
1863
- const fullPath = (0, path_1.join)(dir, entry.name);
1864
- if (entry.isDirectory()) {
1865
- collectFiles(fullPath);
1866
- }
1867
- else {
1868
- // Check glob filter if provided
1869
- if (globPattern) {
1870
- if (!matchGlobSimple(entry.name, globPattern))
1871
- continue;
1872
- }
1873
- // Skip dangling symlinks — collect their paths for a warning.
1874
- if (entry.isSymbolicLink()) {
1875
- try {
1876
- (0, fs_1.statSync)(fullPath);
1877
- }
1878
- catch {
1879
- skippedDangling.push(fullPath);
1880
- continue;
1881
- }
1882
- }
1883
- files.push(fullPath);
1884
- }
1885
- }
1886
- }
1887
- catch {
1888
- // skip unreadable
1889
- }
1890
- }
1891
- function matchGlobSimple(name, pat) {
1892
- const escaped = pat.replace(/[.+^${}()|[\]\\]/g, '\\$&');
1893
- const regex = escaped.replace(/\*/g, '.*').replace(/\?/g, '.');
1894
- return new RegExp(`^${regex}$`).test(name);
1895
- }
1896
- const baseStat = safeStatSync(base);
1897
- if (!baseStat) {
1898
- return {
1899
- success: false,
1900
- output: '',
1901
- error: `Cannot access path: ${base} (may be a dangling symlink or missing)`,
1902
- };
1903
- }
1904
- if (baseStat.isDirectory()) {
1905
- collectFiles(base);
1906
- }
1907
- else {
1908
- // Skip dangling symlinks / unreadable single files early.
1909
- const fileStat = safeStatSync(base);
1910
- if (fileStat && fileStat.isFile()) {
1911
- files.push(base);
1912
- }
1913
- }
1914
- // Search each file
1915
- for (const file of files) {
1916
- if (results.length >= maxResults)
1917
- break;
1918
- try {
1919
- // Skip dangling symlinks and unreadable files before creating the stream.
1920
- const fileStat = safeStatSync(file);
1921
- if (!fileStat || !fileStat.isFile())
1922
- continue;
1923
- const stream = (0, fs_1.createReadStream)(file, { encoding: 'utf-8' });
1924
- const rl = (0, readline_1.createInterface)({
1925
- input: stream,
1926
- crlfDelay: Infinity,
1927
- });
1928
- const lines = [];
1929
- const relPath = (0, path_1.relative)(base, file);
1930
- rl.on('line', line => {
1931
- lines.push(line);
1932
- });
1933
- // Guard against stream errors (dangling symlinks, permission denied, etc.)
1934
- await new Promise((resolve, reject) => {
1935
- stream.on('error', reject);
1936
- rl.on('close', resolve);
1937
- });
1938
- // Search for matches
1939
- for (let i = 0; i < lines.length && results.length < maxResults; i++) {
1940
- if (regex.test(lines[i])) {
1941
- // Format: file:line:content
1942
- const start = Math.max(0, i - context);
1943
- const end = Math.min(lines.length - 1, i + context);
1944
- if (context > 0) {
1945
- results.push(`${relPath}:${i + 1}:`);
1946
- for (let j = start; j <= end; j++) {
1947
- const prefix = j === i ? '>' : ' ';
1948
- results.push(` ${prefix}${j + 1}: ${lines[j]}`);
1949
- }
1950
- results.push('');
1951
- }
1952
- else {
1953
- results.push(`${relPath}:${i + 1}: ${lines[i]}`);
1954
- }
1955
- }
1956
- }
1957
- }
1958
- catch {
1959
- // skip unreadable files
1960
- }
1961
- }
1962
- const symlinkWarning = skippedDangling.length > 0
1963
- ? `\n⚠️ Skipped ${skippedDangling.length} dangling symlink(s): ${skippedDangling.slice(0, 3).join(', ')}${skippedDangling.length > 3 ? '...' : ''}\n`
1964
- : '';
1965
- if (results.length === 0) {
1966
- return { success: true, output: 'No matches found' + symlinkWarning };
1967
- }
1968
- return { success: true, output: results.slice(0, maxResults).join('\n') + symlinkWarning };
1969
- }
1970
- catch (err) {
1971
- return { success: false, output: '', error: (0, errors_1.errorMessage)(err) };
1972
- }
1973
- }
1974
- function isRecord(value) {
1975
- return typeof value === 'object' && value !== null && !Array.isArray(value);
1976
- }
1977
- function parseBatchReadSteps(rawSteps) {
1978
- let value = rawSteps;
1979
- if (typeof value === 'string') {
1980
- try {
1981
- value = JSON.parse(value);
1982
- }
1983
- catch {
1984
- return { error: 'batch_read steps must be an array or a valid JSON array string' };
1985
- }
1986
- }
1987
- if (!Array.isArray(value)) {
1988
- return { error: 'batch_read requires steps to be an array' };
1989
- }
1990
- if (value.length === 0) {
1991
- return { error: 'batch_read requires at least one step' };
1992
- }
1993
- if (value.length > exports.BATCH_READ_MAX_STEPS) {
1994
- return { error: `batch_read supports at most ${exports.BATCH_READ_MAX_STEPS} steps` };
1995
- }
1996
- const steps = [];
1997
- for (let i = 0; i < value.length; i++) {
1998
- const step = value[i];
1999
- if (!isRecord(step)) {
2000
- return { error: `batch_read step ${i + 1} must be an object` };
2001
- }
2002
- if (typeof step.tool !== 'string' || !step.tool) {
2003
- return { error: `batch_read step ${i + 1} requires a tool string` };
2004
- }
2005
- let stepArgs = step.args;
2006
- if (typeof stepArgs === 'string') {
2007
- try {
2008
- stepArgs = JSON.parse(stepArgs);
2009
- }
2010
- catch {
2011
- return {
2012
- error: `batch_read step ${i + 1} args must be an object or valid JSON object string`,
2013
- };
2014
- }
2015
- }
2016
- if (!isRecord(stepArgs)) {
2017
- return { error: `batch_read step ${i + 1} requires args to be an object` };
2018
- }
2019
- steps.push({ tool: step.tool, args: stepArgs });
2020
- }
2021
- return { steps };
2022
- }
2023
- function buildBatchReadPayload(success, summary, steps, error) {
2024
- const payload = {
2025
- success,
2026
- output: steps
2027
- .map(step => `${step.index}. ${step.tool}: ${step.summary || (step.success ? 'ok' : step.error || 'error')}`)
2028
- .join('\n'),
2029
- summary,
2030
- steps,
2031
- };
2032
- if (error) {
2033
- payload.error = error;
2034
- }
2035
- return {
2036
- success,
2037
- output: JSON.stringify(payload, null, 2),
2038
- summary,
2039
- error,
2040
- };
2041
- }
2042
- async function executeBatchRead(args, context) {
2043
- const parsed = parseBatchReadSteps(args.steps);
2044
- if (parsed.error || !parsed.steps) {
2045
- return buildBatchReadPayload(false, parsed.error || 'Invalid batch_read request', [], parsed.error);
2046
- }
2047
- const runtimeTools = getRuntimeTools();
2048
- for (let i = 0; i < parsed.steps.length; i++) {
2049
- const step = parsed.steps[i];
2050
- const tool = runtimeTools.find(t => t.name === step.tool);
2051
- if (!exports.BATCH_READ_ALLOWED_TOOLS.has(step.tool)) {
2052
- const error = `Tool ${step.tool} is not allowed in batch_read`;
2053
- return buildBatchReadPayload(false, error, [
2054
- {
2055
- index: i + 1,
2056
- tool: step.tool,
2057
- args: step.args,
2058
- success: false,
2059
- error,
2060
- output: '',
2061
- },
2062
- ], error);
2063
- }
2064
- if (!tool || tool.isReadOnly?.(step.args) !== true) {
2065
- const error = `Tool ${step.tool} is unavailable or not read-only`;
2066
- return buildBatchReadPayload(false, error, [
2067
- {
2068
- index: i + 1,
2069
- tool: step.tool,
2070
- args: step.args,
2071
- success: false,
2072
- error,
2073
- output: '',
2074
- },
2075
- ], error);
2076
- }
2077
- // The scheduler resolved permissions for `batch_read` itself, not for the
2078
- // tools it fans out to. Without re-running the gate here, a project
2079
- // `deny: read_file(*.env)` rule applies to the flat call and must also apply
2080
- // to the batched one, otherwise the model could read a denied path simply
2081
- // by wrapping it in `batch_read`.
2082
- const stepPermission = (0, tool_1.getToolMetadataPresence)(tool).hasPermissionCheck && tool.checkPermissions
2083
- ? tool.checkPermissions(step.args, context)
2084
- : undefined;
2085
- const effective = (0, tool_scheduler_1.resolveEffectivePermission)({
2086
- toolName: step.tool,
2087
- tool,
2088
- args: step.args,
2089
- permission: stepPermission,
2090
- permissionMode: context.permissionMode,
2091
- allowlist: context.toolAllowlist?.(step.tool, step.args),
2092
- });
2093
- if (effective.outcome === 'deny') {
2094
- const error = effective.reason || `Tool ${step.tool} is not permitted (${effective.source ?? 'policy'})`;
2095
- return buildBatchReadPayload(false, error, [
2096
- {
2097
- index: i + 1,
2098
- tool: step.tool,
2099
- args: step.args,
2100
- success: false,
2101
- error,
2102
- output: '',
2103
- },
2104
- ], error);
2105
- }
2106
- if (effective.outcome === 'confirm') {
2107
- const confirmation = context.toolConfirmation ?? 'ask';
2108
- if (confirmation === 'deny' || !context.confirmToolUse) {
2109
- const error = confirmation === 'deny'
2110
- ? `Tool ${step.tool} requires confirmation and was denied by toolConfirmation=deny.`
2111
- : effective.reason || `Tool ${step.tool} requires user confirmation.`;
2112
- return buildBatchReadPayload(false, error, [
2113
- {
2114
- index: i + 1,
2115
- tool: step.tool,
2116
- args: step.args,
2117
- success: false,
2118
- error,
2119
- output: '',
2120
- },
2121
- ], error);
2122
- }
2123
- const approved = await context.confirmToolUse({
2124
- name: step.tool,
2125
- args: step.args,
2126
- reason: effective.reason,
2127
- abortSignal: context.abortSignal,
2128
- });
2129
- if (!approved) {
2130
- const error = `Tool ${step.tool} requires user confirmation and was denied by user.`;
2131
- return buildBatchReadPayload(false, error, [
2132
- {
2133
- index: i + 1,
2134
- tool: step.tool,
2135
- args: step.args,
2136
- success: false,
2137
- error,
2138
- output: '',
2139
- },
2140
- ], error);
2141
- }
2142
- }
2143
- }
2144
- const stepResults = [];
2145
- for (let i = 0; i < parsed.steps.length; i++) {
2146
- const step = parsed.steps[i];
2147
- try {
2148
- const rawResult = await executeTool(step.tool, step.args, context.abortSignal, context);
2149
- const envelope = JSON.parse(rawResult);
2150
- const output = typeof envelope.output === 'string'
2151
- ? envelope.output
2152
- : JSON.stringify(envelope.output ?? '');
2153
- stepResults.push({
2154
- index: i + 1,
2155
- tool: step.tool,
2156
- args: step.args,
2157
- success: envelope.success === true,
2158
- summary: typeof envelope.summary === 'string' ? envelope.summary : undefined,
2159
- error: typeof envelope.error === 'string' ? envelope.error : undefined,
2160
- output: (0, tool_artifacts_1.truncateForContext)(output, BATCH_READ_STEP_OUTPUT_MAX_BYTES),
2161
- });
2162
- }
2163
- catch (err) {
2164
- stepResults.push({
2165
- index: i + 1,
2166
- tool: step.tool,
2167
- args: step.args,
2168
- success: false,
2169
- error: (0, errors_1.errorMessage)(err),
2170
- output: '',
2171
- });
2172
- }
2173
- }
2174
- const okCount = stepResults.filter(step => step.success).length;
2175
- const success = okCount === stepResults.length;
2176
- const summary = `batch_read completed ${okCount}/${stepResults.length} steps`;
2177
- return buildBatchReadPayload(success, summary, stepResults, success ? undefined : summary);
2178
- }
2179
- // ============================================================================
2180
- // 统一执行入口
2181
- // ============================================================================
2182
- /**
2183
- * 执行一个工具调用,返回结构化结果字符串
2184
- * Issue #32 #3.2: 支持 abortSignal
2185
- */
2186
- async function executeTool(name, args, abortSignal, toolContext) {
2187
- const runtimeTools = getRuntimeTools();
2188
- const tool = runtimeTools.find(t => t.name === name);
2189
- if (!tool) {
2190
- return JSON.stringify({
2191
- success: false,
2192
- error: `Unknown tool: ${name}. Available tools: ${runtimeTools.map(t => t.name).join(', ')}`,
2193
- });
2194
- }
2195
- const context = {
2196
- cwd: toolContext?.cwd || process.cwd(),
2197
- config: toolContext?.config || {
2198
- name: process.env[environment_1.ENV.NAME] || 'orion-code',
2199
- mode: process.env[environment_1.ENV.MODE] || 'development',
2200
- },
2201
- abortSignal, // Issue #32 #3.2: 透传 abortSignal
2202
- sessionId: toolContext?.sessionId,
2203
- turnId: toolContext?.turnId,
2204
- // Must survive the rebuild: batch_read re-runs the permission gate on its
2205
- // sub-steps and reads both of these off the context.
2206
- permissionMode: toolContext?.permissionMode,
2207
- toolAllowlist: toolContext?.toolAllowlist,
2208
- toolConfirmation: toolContext?.toolConfirmation,
2209
- confirmToolUse: toolContext?.confirmToolUse,
2210
- onPlanModeChange: toolContext?.onPlanModeChange,
2211
- };
2212
- const result = await tool.execute(args, context);
2213
- // Assertions are generated by the runtime allowlist, never accepted from a
2214
- // tool's display summary or arbitrary custom ToolResult payload.
2215
- const externalAssertion = (0, external_assertion_1.deriveToolExternalAssertion)({ name, args, result });
2216
- const summary = summarizeToolResult(tool, args, result);
2217
- const outputBytes = Buffer.byteLength(result.output || '', 'utf8');
2218
- let output = result.output || '';
2219
- let artifactRef;
2220
- if (outputBytes > tool_artifacts_1.ARTIFACT_THRESHOLD) {
2221
- const artifact = (0, tool_artifacts_1.storeArtifact)(context.cwd, name, output, outputBytes);
2222
- if (artifact) {
2223
- artifactRef = { id: artifact.id, outputBytes: artifact.outputBytes };
2224
- output = (0, tool_artifacts_1.truncateForContext)(output);
2225
- }
2226
- }
2227
- const payload = {
2228
- success: result.success,
2229
- output,
2230
- summary,
2231
- outputBytes,
2232
- externalAssertion,
2233
- };
2234
- if (!result.success) {
2235
- payload.error = result.error;
2236
- }
2237
- if (artifactRef) {
2238
- payload.artifactRef = artifactRef;
2239
- }
2240
- return JSON.stringify(payload);
2241
- }
2242
- function summarizeToolResult(tool, args, result) {
2243
- try {
2244
- return tool.getSummary?.(args, result);
2245
- }
2246
- catch {
2247
- return undefined;
2248
- }
2249
- }
2250
- /**
2251
- * 获取可用工具名称列表
2252
- */
2253
- function getToolNames() {
2254
- return getRuntimeTools()
2255
- .map(t => t.name)
2256
- .join(', ');
2257
- }
2258
- // Re-export bash_security module
2259
- var bash_security_2 = require("./bash_security");
2260
- Object.defineProperty(exports, "READ_ONLY_COMMANDS", { enumerable: true, get: function () { return bash_security_2.READ_ONLY_COMMANDS; } });
2261
- Object.defineProperty(exports, "DANGEROUS_PATTERNS", { enumerable: true, get: function () { return bash_security_2.DANGEROUS_PATTERNS; } });
2262
- Object.defineProperty(exports, "POTENTIALLY_DESTRUCTIVE_PATTERNS", { enumerable: true, get: function () { return bash_security_2.POTENTIALLY_DESTRUCTIVE_PATTERNS; } });
2263
- Object.defineProperty(exports, "isReadOnlyCommand", { enumerable: true, get: function () { return bash_security_2.isReadOnlyCommand; } });
2264
- Object.defineProperty(exports, "checkDangerousCommand", { enumerable: true, get: function () { return bash_security_2.checkDangerousCommand; } });
2265
- Object.defineProperty(exports, "isPotentiallyDestructive", { enumerable: true, get: function () { return bash_security_2.isPotentiallyDestructive; } });
2266
- Object.defineProperty(exports, "assessCommandSecurity", { enumerable: true, get: function () { return bash_security_2.assessCommandSecurity; } });
2267
- Object.defineProperty(exports, "findDestructiveRmTarget", { enumerable: true, get: function () { return bash_security_2.findDestructiveRmTarget; } });
2268
- //# sourceMappingURL=index.js.map