@chengchenccc/oh-my-agent 0.1.1-rc.2 → 0.2.0-rc.1

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 (324) hide show
  1. package/README.md +5 -4
  2. package/dist/cli/args.d.ts +15 -1
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +81 -3
  5. package/dist/cli/gateway-commands.d.ts +28 -0
  6. package/dist/cli/gateway-commands.d.ts.map +1 -0
  7. package/dist/cli/gateway-commands.js +242 -0
  8. package/dist/cli/initial-input.d.ts +9 -0
  9. package/dist/cli/initial-input.d.ts.map +1 -1
  10. package/dist/cli/initial-input.js +39 -5
  11. package/dist/core/coordination/hub-tool.d.ts +30 -0
  12. package/dist/core/coordination/hub-tool.d.ts.map +1 -0
  13. package/dist/core/coordination/hub-tool.js +251 -0
  14. package/dist/core/coordination/index.d.ts +3 -0
  15. package/dist/core/coordination/index.d.ts.map +1 -0
  16. package/dist/core/coordination/index.js +2 -0
  17. package/dist/core/coordination/registry.d.ts +85 -0
  18. package/dist/core/coordination/registry.d.ts.map +1 -0
  19. package/dist/core/coordination/registry.js +164 -0
  20. package/dist/core/{workflow/workflow-executor.d.ts → delegation/executor.d.ts} +44 -22
  21. package/dist/core/delegation/executor.d.ts.map +1 -0
  22. package/dist/core/delegation/executor.fixture.d.ts +27 -0
  23. package/dist/core/delegation/executor.fixture.d.ts.map +1 -0
  24. package/dist/core/delegation/executor.fixture.js +26 -0
  25. package/dist/core/{workflow/workflow-executor.js → delegation/executor.js} +234 -258
  26. package/dist/core/delegation/pool.d.ts +20 -0
  27. package/dist/core/delegation/pool.d.ts.map +1 -0
  28. package/dist/core/delegation/pool.js +55 -0
  29. package/dist/core/delegation/results.d.ts +22 -0
  30. package/dist/core/delegation/results.d.ts.map +1 -0
  31. package/dist/core/delegation/results.js +138 -0
  32. package/dist/core/{workflow/subagent-registry.d.ts → delegation/roles.d.ts} +4 -4
  33. package/dist/core/delegation/roles.d.ts.map +1 -0
  34. package/dist/core/delegation/tool.d.ts +24 -0
  35. package/dist/core/delegation/tool.d.ts.map +1 -0
  36. package/dist/core/delegation/tool.js +188 -0
  37. package/dist/core/delegation/yield-tool.d.ts +13 -0
  38. package/dist/core/delegation/yield-tool.d.ts.map +1 -0
  39. package/dist/core/delegation/yield-tool.js +34 -0
  40. package/dist/core/gateway/artifact.d.ts +55 -0
  41. package/dist/core/gateway/artifact.d.ts.map +1 -0
  42. package/dist/core/gateway/artifact.js +203 -0
  43. package/dist/core/gateway/daemon.d.ts +43 -0
  44. package/dist/core/gateway/daemon.d.ts.map +1 -0
  45. package/dist/core/gateway/daemon.js +135 -0
  46. package/dist/core/gateway/manifest.d.ts +139 -0
  47. package/dist/core/gateway/manifest.d.ts.map +1 -0
  48. package/dist/core/gateway/manifest.js +105 -0
  49. package/dist/core/gateway/supervisor.d.ts +39 -0
  50. package/dist/core/gateway/supervisor.d.ts.map +1 -0
  51. package/dist/core/gateway/supervisor.js +216 -0
  52. package/dist/core/{agent-runtime.d.ts → index.d.ts} +5 -6
  53. package/dist/core/index.d.ts.map +1 -0
  54. package/dist/core/index.js +20 -0
  55. package/dist/core/memory/autonomous-memory.d.ts +14 -0
  56. package/dist/core/memory/autonomous-memory.d.ts.map +1 -1
  57. package/dist/core/memory/autonomous-memory.js +60 -14
  58. package/dist/core/memory/embeddings.d.ts +50 -0
  59. package/dist/core/memory/embeddings.d.ts.map +1 -0
  60. package/dist/core/memory/embeddings.js +385 -0
  61. package/dist/core/memory/learn.d.ts +10 -0
  62. package/dist/core/memory/learn.d.ts.map +1 -0
  63. package/dist/core/memory/learn.js +147 -0
  64. package/dist/core/memory/manage-skill.d.ts +10 -0
  65. package/dist/core/memory/manage-skill.d.ts.map +1 -0
  66. package/dist/core/memory/manage-skill.js +65 -0
  67. package/dist/core/memory/managed-skills.d.ts +39 -0
  68. package/dist/core/memory/managed-skills.d.ts.map +1 -0
  69. package/dist/core/memory/managed-skills.js +167 -0
  70. package/dist/core/memory/vector-memory.d.ts +33 -0
  71. package/dist/core/memory/vector-memory.d.ts.map +1 -0
  72. package/dist/core/memory/vector-memory.js +98 -0
  73. package/dist/core/memory/vector-recall.d.ts +35 -0
  74. package/dist/core/memory/vector-recall.d.ts.map +1 -0
  75. package/dist/core/memory/vector-recall.js +212 -0
  76. package/dist/core/memory/vector-store.d.ts +56 -0
  77. package/dist/core/memory/vector-store.d.ts.map +1 -0
  78. package/dist/core/memory/vector-store.js +125 -0
  79. package/dist/core/memory/vector-tools.d.ts +8 -0
  80. package/dist/core/memory/vector-tools.d.ts.map +1 -0
  81. package/dist/core/memory/vector-tools.js +75 -0
  82. package/dist/core/{workflow/workflow-evaluator.d.ts → orchestrate/script-runner.d.ts} +4 -4
  83. package/dist/core/orchestrate/script-runner.d.ts.map +1 -0
  84. package/dist/core/{workflow/workflow-evaluator.js → orchestrate/script-runner.js} +1 -1
  85. package/dist/core/orchestrate/tool.d.ts +20 -0
  86. package/dist/core/orchestrate/tool.d.ts.map +1 -0
  87. package/dist/core/orchestrate/tool.js +49 -0
  88. package/dist/core/plugins/plugin-code.d.ts.map +1 -1
  89. package/dist/core/plugins/plugin-code.js +16 -0
  90. package/dist/core/plugins/plugin-marketplace.d.ts.map +1 -1
  91. package/dist/core/plugins/plugin-marketplace.js +22 -5
  92. package/dist/core/plugins/plugin-trust.d.ts +6 -2
  93. package/dist/core/plugins/plugin-trust.d.ts.map +1 -1
  94. package/dist/core/plugins/plugin-trust.js +13 -5
  95. package/dist/core/runtime/agent-event.d.ts +36 -12
  96. package/dist/core/runtime/agent-event.d.ts.map +1 -1
  97. package/dist/core/runtime/agent-loop-messages.d.ts +33 -0
  98. package/dist/core/runtime/agent-loop-messages.d.ts.map +1 -0
  99. package/dist/core/runtime/agent-loop-messages.js +133 -0
  100. package/dist/core/runtime/agent-loop-run.d.ts +35 -0
  101. package/dist/core/runtime/agent-loop-run.d.ts.map +1 -0
  102. package/dist/core/runtime/agent-loop-run.js +345 -0
  103. package/dist/core/runtime/agent-loop-runner.d.ts +60 -0
  104. package/dist/core/runtime/agent-loop-runner.d.ts.map +1 -0
  105. package/dist/core/runtime/agent-loop-runner.js +471 -0
  106. package/dist/core/runtime/agent-loop-types.d.ts +172 -0
  107. package/dist/core/runtime/agent-loop-types.d.ts.map +1 -0
  108. package/dist/core/runtime/agent-loop-utils.d.ts +8 -0
  109. package/dist/core/runtime/agent-loop-utils.d.ts.map +1 -0
  110. package/dist/core/runtime/agent-loop-utils.js +26 -0
  111. package/dist/core/runtime/agent-loop.d.ts +2 -138
  112. package/dist/core/runtime/agent-loop.d.ts.map +1 -1
  113. package/dist/core/runtime/agent-loop.js +45 -927
  114. package/dist/core/runtime/approval.d.ts +7 -2
  115. package/dist/core/runtime/approval.d.ts.map +1 -1
  116. package/dist/core/runtime/coding-agent-harness.fixture.d.ts +52 -0
  117. package/dist/core/runtime/coding-agent-harness.fixture.d.ts.map +1 -0
  118. package/dist/core/runtime/coding-agent-harness.fixture.js +84 -0
  119. package/dist/core/runtime/compaction.d.ts +1 -1
  120. package/dist/core/runtime/compaction.d.ts.map +1 -1
  121. package/dist/core/runtime/create-runtime.d.ts +41 -4
  122. package/dist/core/runtime/create-runtime.d.ts.map +1 -1
  123. package/dist/core/runtime/create-runtime.fixture.d.ts +20 -0
  124. package/dist/core/runtime/create-runtime.fixture.d.ts.map +1 -0
  125. package/dist/core/runtime/create-runtime.fixture.js +79 -0
  126. package/dist/core/runtime/create-runtime.js +67 -20
  127. package/dist/core/runtime/fake-provider.d.ts.map +1 -1
  128. package/dist/core/runtime/fake-provider.js +31 -6
  129. package/dist/core/runtime/loop-input.d.ts +1 -1
  130. package/dist/core/runtime/loop-input.d.ts.map +1 -1
  131. package/dist/core/runtime/model-effort.d.ts +11 -0
  132. package/dist/core/runtime/model-effort.d.ts.map +1 -0
  133. package/dist/core/runtime/model-effort.js +17 -0
  134. package/dist/core/runtime/permission-classifier.d.ts +39 -0
  135. package/dist/core/runtime/permission-classifier.d.ts.map +1 -0
  136. package/dist/core/runtime/permission-classifier.js +136 -0
  137. package/dist/core/runtime/plugin-runtime.d.ts +1 -1
  138. package/dist/core/runtime/plugin-runtime.d.ts.map +1 -1
  139. package/dist/core/runtime/prompt.d.ts.map +1 -1
  140. package/dist/core/runtime/prompt.js +2 -0
  141. package/dist/core/runtime/prompts.d.ts +3 -2
  142. package/dist/core/runtime/prompts.d.ts.map +1 -1
  143. package/dist/core/runtime/prompts.js +29 -5
  144. package/dist/core/runtime/run-runtime.d.ts +35 -45
  145. package/dist/core/runtime/run-runtime.d.ts.map +1 -1
  146. package/dist/core/runtime/run-runtime.js +761 -355
  147. package/dist/core/runtime/runtime-catalog.d.ts.map +1 -1
  148. package/dist/core/runtime/runtime-catalog.js +12 -1
  149. package/dist/core/runtime/stream-rules.d.ts +1 -1
  150. package/dist/core/runtime/stream-rules.d.ts.map +1 -1
  151. package/dist/core/session/session-file.d.ts +4 -0
  152. package/dist/core/session/session-file.d.ts.map +1 -1
  153. package/dist/core/session/session-file.js +32 -1
  154. package/dist/core/settings/project-settings.d.ts +66 -0
  155. package/dist/core/settings/project-settings.d.ts.map +1 -1
  156. package/dist/core/settings/project-settings.js +126 -0
  157. package/dist/core/settings/workspace-context.d.ts +16 -5
  158. package/dist/core/settings/workspace-context.d.ts.map +1 -1
  159. package/dist/core/settings/workspace-context.js +116 -10
  160. package/dist/core/store/in-memory-session-store.d.ts.map +1 -0
  161. package/dist/core/store/session-store.contract.test-helper.d.ts +10 -0
  162. package/dist/core/store/session-store.contract.test-helper.d.ts.map +1 -0
  163. package/dist/core/{persistence/session-store.contract.js → store/session-store.contract.test-helper.js} +13 -26
  164. package/dist/core/{persistence → store}/session-store.d.ts +3 -3
  165. package/dist/core/store/session-store.d.ts.map +1 -0
  166. package/dist/core/{persistence → store}/session-store.js +1 -4
  167. package/dist/core/{persistence → store}/session-tree.d.ts +1 -8
  168. package/dist/core/store/session-tree.d.ts.map +1 -0
  169. package/dist/core/store/session-tree.js +1 -0
  170. package/dist/core/tools/ask-question.d.ts +1 -1
  171. package/dist/core/tools/ask-question.d.ts.map +1 -1
  172. package/dist/core/tools/ask-question.js +14 -1
  173. package/dist/core/tools/bash-pty.d.ts +12 -0
  174. package/dist/core/tools/bash-pty.d.ts.map +1 -0
  175. package/dist/core/tools/bash-pty.js +28 -0
  176. package/dist/core/tools/bash-sandbox.d.ts +76 -0
  177. package/dist/core/tools/bash-sandbox.d.ts.map +1 -0
  178. package/dist/core/tools/bash-sandbox.js +226 -0
  179. package/dist/core/tools/bash.d.ts +27 -0
  180. package/dist/core/tools/bash.d.ts.map +1 -1
  181. package/dist/core/tools/bash.js +214 -33
  182. package/dist/core/tools/browser.d.ts +9 -0
  183. package/dist/core/tools/browser.d.ts.map +1 -0
  184. package/dist/core/tools/browser.js +355 -0
  185. package/dist/core/tools/eval.d.ts +11 -1
  186. package/dist/core/tools/eval.d.ts.map +1 -1
  187. package/dist/core/tools/eval.js +109 -39
  188. package/dist/core/tools/file-tools.d.ts +0 -4
  189. package/dist/core/tools/file-tools.d.ts.map +1 -1
  190. package/dist/core/tools/file-tools.js +36 -16
  191. package/dist/core/tools/glob.d.ts.map +1 -1
  192. package/dist/core/tools/glob.js +13 -1
  193. package/dist/core/tools/grep.d.ts.map +1 -1
  194. package/dist/core/tools/grep.js +4 -1
  195. package/dist/core/tools/index.d.ts +4 -4
  196. package/dist/core/tools/index.d.ts.map +1 -1
  197. package/dist/core/tools/index.js +4 -5
  198. package/dist/core/tools/mcp-mount.d.ts +27 -6
  199. package/dist/core/tools/mcp-mount.d.ts.map +1 -1
  200. package/dist/core/tools/mcp-mount.js +97 -23
  201. package/dist/core/tools/read-image.d.ts +2 -0
  202. package/dist/core/tools/read-image.d.ts.map +1 -1
  203. package/dist/core/tools/read-image.js +1 -1
  204. package/dist/core/tools/skill.d.ts +12 -3
  205. package/dist/core/tools/skill.d.ts.map +1 -1
  206. package/dist/core/tools/skill.js +10 -11
  207. package/dist/core/tools/skills.d.ts +8 -1
  208. package/dist/core/tools/skills.d.ts.map +1 -1
  209. package/dist/core/tools/skills.js +28 -6
  210. package/dist/core/tools/todo-store.d.ts +26 -7
  211. package/dist/core/tools/todo-store.d.ts.map +1 -1
  212. package/dist/core/tools/todo-store.js +53 -81
  213. package/dist/core/tools/todo.d.ts +3 -3
  214. package/dist/core/tools/todo.d.ts.map +1 -1
  215. package/dist/core/tools/todo.js +5 -28
  216. package/dist/core/tools/url-guard.d.ts +5 -1
  217. package/dist/core/tools/url-guard.d.ts.map +1 -1
  218. package/dist/core/tools/url-guard.js +68 -26
  219. package/dist/core/tools/web-ports-std.d.ts.map +1 -1
  220. package/dist/core/tools/web-ports-std.js +2 -2
  221. package/dist/main.d.ts +0 -1
  222. package/dist/main.d.ts.map +1 -1
  223. package/dist/main.js +34 -4
  224. package/dist/modes/json-mode.d.ts.map +1 -1
  225. package/dist/modes/json-mode.js +25 -13
  226. package/dist/modes/print-mode.d.ts +7 -0
  227. package/dist/modes/print-mode.d.ts.map +1 -1
  228. package/dist/modes/print-mode.js +11 -17
  229. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  230. package/dist/modes/rpc/rpc-mode.js +39 -11
  231. package/dist/modes/shared.d.ts +34 -0
  232. package/dist/modes/shared.d.ts.map +1 -0
  233. package/dist/modes/shared.js +47 -0
  234. package/dist/modes/tui/pty-console.d.ts +20 -0
  235. package/dist/modes/tui/pty-console.d.ts.map +1 -0
  236. package/dist/modes/tui/pty-console.js +80 -0
  237. package/dist/modes/tui/settings-overlay.d.ts.map +1 -1
  238. package/dist/modes/tui/settings-overlay.js +2 -0
  239. package/dist/modes/tui/tui-branch-layout.d.ts +10 -0
  240. package/dist/modes/tui/tui-branch-layout.d.ts.map +1 -0
  241. package/dist/modes/tui/tui-branch-layout.js +66 -0
  242. package/dist/modes/tui/tui-commands-session.d.ts.map +1 -1
  243. package/dist/modes/tui/tui-commands-session.js +81 -4
  244. package/dist/modes/tui/tui-commands.d.ts +8 -1
  245. package/dist/modes/tui/tui-commands.d.ts.map +1 -1
  246. package/dist/modes/tui/tui-commands.js +105 -1
  247. package/dist/modes/tui/tui-e2e.fixture.d.ts +11 -0
  248. package/dist/modes/tui/tui-e2e.fixture.d.ts.map +1 -0
  249. package/dist/modes/tui/tui-e2e.fixture.js +37 -0
  250. package/dist/modes/tui/tui-format.d.ts +50 -7
  251. package/dist/modes/tui/tui-format.d.ts.map +1 -1
  252. package/dist/modes/tui/tui-format.js +309 -43
  253. package/dist/modes/tui/tui-frame-provider.d.ts +6 -6
  254. package/dist/modes/tui/tui-frame-provider.d.ts.map +1 -1
  255. package/dist/modes/tui/tui-frame-provider.js +24 -10
  256. package/dist/modes/tui/tui-io.d.ts +7 -9
  257. package/dist/modes/tui/tui-io.d.ts.map +1 -1
  258. package/dist/modes/tui/tui-io.js +170 -115
  259. package/dist/modes/tui/tui-mode.d.ts +1 -113
  260. package/dist/modes/tui/tui-mode.d.ts.map +1 -1
  261. package/dist/modes/tui/tui-mode.fixture.d.ts +21 -0
  262. package/dist/modes/tui/tui-mode.fixture.d.ts.map +1 -0
  263. package/dist/modes/tui/tui-mode.fixture.js +60 -0
  264. package/dist/modes/tui/tui-mode.js +164 -25
  265. package/dist/modes/tui/tui-overlays.d.ts +30 -0
  266. package/dist/modes/tui/tui-overlays.d.ts.map +1 -0
  267. package/dist/modes/tui/tui-overlays.js +66 -0
  268. package/dist/modes/tui/tui-render.d.ts +49 -3
  269. package/dist/modes/tui/tui-render.d.ts.map +1 -1
  270. package/dist/modes/tui/tui-render.js +222 -48
  271. package/dist/modes/tui/tui-seam.d.ts +127 -0
  272. package/dist/modes/tui/tui-seam.d.ts.map +1 -0
  273. package/dist/modes/tui/tui-seam.js +1 -0
  274. package/dist/modes/tui/tui-tool-render.d.ts +32 -4
  275. package/dist/modes/tui/tui-tool-render.d.ts.map +1 -1
  276. package/dist/modes/tui/tui-tool-render.js +419 -65
  277. package/dist/modes/tui/tui-transcript-reconciler.d.ts +9 -0
  278. package/dist/modes/tui/tui-transcript-reconciler.d.ts.map +1 -1
  279. package/dist/modes/tui/tui-transcript-reconciler.js +35 -3
  280. package/dist/modes/tui/view-state.d.ts +38 -1
  281. package/dist/modes/tui/view-state.d.ts.map +1 -1
  282. package/dist/modes/tui/view-state.js +154 -20
  283. package/dist/prompts/agents/subagent.md +8 -1
  284. package/dist/prompts/system/base.md +15 -0
  285. package/dist/prompts/system/memory.md +19 -11
  286. package/dist/protocol/index.d.ts +2 -2
  287. package/dist/protocol/index.d.ts.map +1 -1
  288. package/dist/protocol/index.js +2 -2
  289. package/dist/protocol/mapping.d.ts +1 -13
  290. package/dist/protocol/mapping.d.ts.map +1 -1
  291. package/dist/protocol/mapping.js +17 -37
  292. package/dist/protocol/transport.d.ts +146 -146
  293. package/dist/protocol/transport.d.ts.map +1 -1
  294. package/dist/protocol/transport.js +4 -1
  295. package/dist/testing/test-env.d.ts +2 -0
  296. package/dist/testing/test-env.d.ts.map +1 -0
  297. package/dist/testing/test-env.js +9 -0
  298. package/package.json +18 -12
  299. package/dist/core/agent-runtime.d.ts.map +0 -1
  300. package/dist/core/agent-runtime.js +0 -14
  301. package/dist/core/persistence/in-memory-session-store.d.ts.map +0 -1
  302. package/dist/core/persistence/session-store.contract.d.ts +0 -5
  303. package/dist/core/persistence/session-store.contract.d.ts.map +0 -1
  304. package/dist/core/persistence/session-store.d.ts.map +0 -1
  305. package/dist/core/persistence/session-tree.d.ts.map +0 -1
  306. package/dist/core/runtime/logger.d.ts +0 -13
  307. package/dist/core/runtime/logger.d.ts.map +0 -1
  308. package/dist/core/runtime/logger.js +0 -38
  309. package/dist/core/runtime/todo.d.ts +0 -16
  310. package/dist/core/runtime/todo.d.ts.map +0 -1
  311. package/dist/core/runtime/todo.js +0 -40
  312. package/dist/core/tools/agent-fs-like.d.ts +0 -15
  313. package/dist/core/tools/agent-fs-like.d.ts.map +0 -1
  314. package/dist/core/tools/agent-fs-like.js +0 -4
  315. package/dist/core/workflow/subagent-registry.d.ts.map +0 -1
  316. package/dist/core/workflow/workflow-evaluator.d.ts.map +0 -1
  317. package/dist/core/workflow/workflow-executor.d.ts.map +0 -1
  318. package/dist/core/workflow/workflow-tools.d.ts +0 -50
  319. package/dist/core/workflow/workflow-tools.d.ts.map +0 -1
  320. package/dist/core/workflow/workflow-tools.js +0 -217
  321. /package/dist/core/{workflow/subagent-registry.js → delegation/roles.js} +0 -0
  322. /package/dist/core/{persistence/session-tree.js → runtime/agent-loop-types.js} +0 -0
  323. /package/dist/core/{persistence → store}/in-memory-session-store.d.ts +0 -0
  324. /package/dist/core/{persistence → store}/in-memory-session-store.js +0 -0
package/README.md CHANGED
@@ -18,6 +18,7 @@ Product Backend → Agent Run → Adapter → spawn oma --mode rpc
18
18
  - mermaid fence 渲染为终端 ASCII 图
19
19
  - `/resume` 列表/恢复 session,`/fork <n>` 分支
20
20
  - 模型选择持久化到项目级 `.oma/settings.json`(standalone TUI 专用;backend→oma 仍以 `agent.yml` 为默认,可被 run 参数覆盖)
21
+ - `.oma/settings.json` 里的 `prune` 块显式开启读侧工具输出裁剪(`protectTokens` / `minimumSavings` / `protectedTools`),不配就不裁
21
22
  - composer loader 实时摘要当前动作(tool intent / thinking 首行)
22
23
 
23
24
  | Real session | Tools | Mermaid |
@@ -33,7 +34,7 @@ Product Backend → Agent Run → Adapter → spawn oma --mode rpc
33
34
  | `json` | 一次 Run;stdout 全部事件 JSONL + 恰好一个 terminal outcome 行 |
34
35
  | `rpc` | 每 Run 一次 `execute` + 可选的 `steer`/`abort`;命令走 stdin,`event`/`outcome`/`response` 走 stdout(严格 LF JSONL,stdout 只承载协议) |
35
36
 
36
- `--mode rpc` 是 Adapter 使用的模式。协议 schema 与事件/outcome mapping 定义在契约包 `@chengchenccc/agent-backend`,两侧共用同一份。
37
+ `--mode rpc` 是 Adapter 使用的模式。wire schema 归**本 app 所有**(`src/protocol/`),Adapter 侧保留一份独立的解析/映射副本(`packages/adapter-oma-agent/src/{protocol,event-mapper}.ts`)——两份靠 fixture + `src/protocol/drift.test.ts` 对齐,不共享包(ADR 0024)。改协议:先改这里,再改 adapter 那份,drift 测试会挡住漏改。
37
38
 
38
39
  ## Runtime
39
40
 
@@ -43,7 +44,7 @@ Product Backend → Agent Run → Adapter → spawn oma --mode rpc
43
44
  - `steer(input)` 注入 live loop;`stop()` 中止;
44
45
  - `close()` 拆除 MCP clients 与 SessionStore。
45
46
 
46
- Runtime 内部由 `packages/agent` 提供:OmaSession(model/tool loop、retry、compaction、插件、todo)与 in-memory SessionStoreseed 时把 **full Product history + meta + input** 原子写入,Run 结束即销毁。
47
+ Runtime 主体就在本 app 的 `src/core/`:OmaSession(model/tool loop、retry、compaction、插件、todo、tool-result pruning)与 in-memory SessionStore(`core/store/`)。seed 时把 **full Product history + meta + input** 原子写入,Run 结束即销毁。
47
48
 
48
49
  ## 运行
49
50
 
@@ -75,5 +76,5 @@ src/
75
76
 
76
77
  ## 相关文档
77
78
 
78
- - [架构 Wiki — Oma](docs/architecture/runtime/oma.md)
79
- - [Agent Backend 协议](docs/architecture/execution/agent-backend.md)
79
+ - [架构 Wiki — Oma](../../docs/architecture/runtime/oma.md)
80
+ - [Agent Backend 协议](../../docs/architecture/execution/agent-backend.md)
@@ -1,4 +1,6 @@
1
+ import { type GatewayCommand } from "./gateway-commands.js";
1
2
  export type CliMode = "print" | "json" | "rpc" | "tui";
3
+ export type PermissionFlag = "ask" | "auto" | "deny" | "off";
2
4
  export interface CliArgs {
3
5
  mode: CliMode;
4
6
  /** True when -p/--mode was given explicitly; a bare positional prompt
@@ -8,8 +10,20 @@ export interface CliArgs {
8
10
  listModels: boolean;
9
11
  /** Canonical `<provider>/<model>` id; undefined = first available model. */
10
12
  model?: string;
11
- /** Resume a session file by id (TUI mode). */
13
+ /** Resume a session file by id (all modes; TUI and one-shot). */
12
14
  session?: string;
15
+ /** --continue: resume the workspace's most recent session. */
16
+ continueLast?: boolean;
17
+ /** Standalone permission gate; undefined = .oma/settings.json decides. */
18
+ permission?: PermissionFlag;
19
+ /** --read-only: run with no write/edit/bash/eval tools. */
20
+ readOnly?: boolean;
21
+ /** `oma gateway <command>`: the gateway domain (backend + web) verbs. */
22
+ gateway?: GatewayCommand;
23
+ /** `oma gateway up|fetch --version <v>`: pin the artifact version. */
24
+ gatewayVersion?: string;
25
+ /** `oma gateway up -d`: run detached. */
26
+ gatewayDetach?: boolean;
13
27
  /** Tool filter: comma-separated tool names or groups. Plain names form a
14
28
  * whitelist (ONLY those tools run); `!name` entries form a blacklist
15
29
  * (all but those). Applied to the FINAL tool table (native + MCP +
@@ -1 +1 @@
1
- {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;AAEvD,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,OAAO,CAAC;IACd;yEACqE;IACrE,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;mCAG+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,UAAW,SAAQ,KAAK;CAAG;AA0BxC;6DAC6D;AAC7D,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CA6E1D"}
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,cAAc,EAAoB,MAAM,uBAAuB,CAAC;AAE7F,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAE7D,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,OAAO,CAAC;IACd;yEACqE;IACrE,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,yEAAyE;IACzE,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,sEAAsE;IACtE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yCAAyC;IACzC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;mCAG+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,UAAW,SAAQ,KAAK;CAAG;AAkCxC;6DAC6D;AAC7D,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAuG1D"}
package/dist/cli/args.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { GATEWAY_USAGE, isGatewayCommand } from "./gateway-commands.js";
1
2
  export class UsageError extends Error {
2
3
  }
3
4
  const USAGE = `oma - Oma coding agent
@@ -10,11 +11,18 @@ Usage:
10
11
  oma --mode json "<prompt>" json mode: all events + one outcome as JSONL
11
12
  oma --mode rpc rpc mode: stdin/stdout JSONL protocol
12
13
  oma --list-models print the model catalog as JSON
14
+ oma gateway up start backend + web (foreground, Ctrl-C stops)
15
+ oma gateway up -d same, detached (returns once healthy)
16
+ oma gateway down stop a detached gateway
17
+ oma gateway status installed version, running state, health
18
+ oma gateway fetch download + verify the gateway artifact
19
+ oma --continue resume the most recent session
20
+ oma --session <id> -p "..." one-shot follow-up on a session
21
+ oma --permission ask -p "..." gate bash/write/mcp behind approval cards
22
+ oma --read-only -p "..." research-only run (no mutating tools)
13
23
  oma --model <provider/model> -p "<prompt>"
14
24
  pick a model by canonical id
15
25
  (default: first available model)
16
- oma --tools todo_write,read -p "..." only these tools enter the Run
17
- oma --tools '!todo_write' -p "..." all tools except todo_write
18
26
 
19
27
  Piped stdin (print/json modes):
20
28
  cat file | oma -p "Review"
@@ -22,6 +30,7 @@ Piped stdin (print/json modes):
22
30
  cat error.log | oma -p (stdin only)
23
31
  `;
24
32
  const MODES = ["print", "json", "rpc", "tui"];
33
+ const PERMISSIONS = ["ask", "auto", "deny", "off"];
25
34
  /** Parse argv SYNTAX only: whether a run actually has an input (prompt or
26
35
  * piped stdin) is decided in main() after stdin is read. */
27
36
  export function parseArgs(argv) {
@@ -33,11 +42,19 @@ export function parseArgs(argv) {
33
42
  };
34
43
  const positional = [];
35
44
  let modeFlag = null;
45
+ // `oma gateway <verb>` — a reserved first word, because the first positional
46
+ // is otherwise the prompt (`oma "explain this"`). `oma -p "gateway up"` is the
47
+ // escape hatch when the word really is part of a prompt.
48
+ if (argv[0] === "gateway")
49
+ return parseGatewayArgs(argv.slice(1), args);
36
50
  let i = 0;
37
51
  while (i < argv.length) {
38
52
  const arg = argv[i];
39
53
  if (arg === "-p") {
40
- modeFlag = "print";
54
+ // `-p` means "one-shot with this prompt", NOT "force print mode": an
55
+ // explicit --mode (either order) must win, or `--mode json -p x` would
56
+ // silently run print mode and print bare text where JSONL was expected.
57
+ modeFlag ??= "print";
41
58
  args.modeExplicit = true;
42
59
  }
43
60
  else if (arg === "--mode") {
@@ -88,6 +105,27 @@ export function parseArgs(argv) {
88
105
  throw new UsageError("--session requires a session id");
89
106
  args.session = value;
90
107
  }
108
+ else if (arg === "--continue" || arg === "-c") {
109
+ args.continueLast = true;
110
+ }
111
+ else if (arg === "--read-only") {
112
+ args.readOnly = true;
113
+ }
114
+ else if (arg === "--permission") {
115
+ const value = argv[i + 1];
116
+ if (!value || !PERMISSIONS.includes(value)) {
117
+ throw new UsageError(`--permission requires one of: ${PERMISSIONS.join(" | ")}`);
118
+ }
119
+ args.permission = value;
120
+ i++;
121
+ }
122
+ else if (arg.startsWith("--permission=")) {
123
+ const value = arg.slice("--permission=".length);
124
+ if (!PERMISSIONS.includes(value)) {
125
+ throw new UsageError(`--permission requires one of: ${PERMISSIONS.join(" | ")}`);
126
+ }
127
+ args.permission = value;
128
+ }
91
129
  else if (arg === "--tools") {
92
130
  const value = argv[i + 1];
93
131
  if (!value || value.startsWith("-")) {
@@ -118,3 +156,43 @@ export function parseArgs(argv) {
118
156
  args.prompt = positional.join(" ");
119
157
  return args;
120
158
  }
159
+ /** Parse `oma gateway <verb> [--version <v>]`. Kept separate from the main
160
+ * loop: the gateway surface takes no prompt, session or mode. */
161
+ function parseGatewayArgs(rest, args) {
162
+ const verb = rest[0];
163
+ if (verb === undefined || verb.startsWith("-")) {
164
+ throw new UsageError(`oma gateway needs a command\n\n${GATEWAY_USAGE}`);
165
+ }
166
+ if (!isGatewayCommand(verb)) {
167
+ throw new UsageError(`unknown gateway command: ${verb}\n\n${GATEWAY_USAGE}`);
168
+ }
169
+ args.gateway = verb;
170
+ let i = 1;
171
+ while (i < rest.length) {
172
+ const arg = rest[i] ?? "";
173
+ if (arg === "--version") {
174
+ const value = rest[i + 1];
175
+ if (!value || value.startsWith("-")) {
176
+ throw new UsageError("oma gateway --version needs a version like 0.2.0");
177
+ }
178
+ args.gatewayVersion = value;
179
+ i += 2;
180
+ continue;
181
+ }
182
+ if (arg.startsWith("--version=")) {
183
+ const value = arg.slice("--version=".length);
184
+ if (!value)
185
+ throw new UsageError("oma gateway --version needs a version like 0.2.0");
186
+ args.gatewayVersion = value;
187
+ i += 1;
188
+ continue;
189
+ }
190
+ if (arg === "--detach" || arg === "-d") {
191
+ args.gatewayDetach = true;
192
+ i += 1;
193
+ continue;
194
+ }
195
+ throw new UsageError(`unknown gateway option: ${arg}\n\n${GATEWAY_USAGE}`);
196
+ }
197
+ return args;
198
+ }
@@ -0,0 +1,28 @@
1
+ /** The gateway domain's verbs. `oma gateway <verb>` is the CLI surface for
2
+ * backend + web: fetch their artifact, run it, report on it. */
3
+ export declare const GATEWAY_VERBS: readonly ["up", "down", "fetch", "status"];
4
+ export type GatewayCommand = (typeof GATEWAY_VERBS)[number];
5
+ export declare const GATEWAY_USAGE = "oma gateway <command>\n\n up start backend + web; stays in the foreground (Ctrl-C stops it)\n up -d same, but detached: returns once it is healthy\n down stop a detached gateway\n fetch download, verify and unpack the gateway artifact for a version\n status which version is installed, is it running, is it answering\n\n --version <v> artifact version for up/fetch (default: oma's own)\n\nNote: 'gateway' is a reserved first word. To send it as a prompt, use\n'oma -p \"gateway ...\"'.";
6
+ export declare function isGatewayCommand(value: string): value is GatewayCommand;
7
+ export interface GatewayCommandOptions {
8
+ home?: string;
9
+ version?: string;
10
+ /** `up -d`: run detached, with a pidfile and a log file. */
11
+ detach?: boolean;
12
+ quiet?: boolean;
13
+ log?: (line: string) => void;
14
+ }
15
+ /** `oma gateway fetch`: download, verify and unpack the artifact for one
16
+ * version (default: oma's own) so `up` can start it. Idempotent. */
17
+ export declare function runGatewayFetch(opts?: GatewayCommandOptions): Promise<number>;
18
+ /** `oma gateway status`: what is installed, which version is current, and
19
+ * whether the gateway answers right now. Never mutates anything. */
20
+ export declare function runGatewayStatus(opts?: GatewayCommandOptions): Promise<number>;
21
+ /** `oma gateway up`: fetch the version if it is missing, then run the whole gateway in
22
+ * the foreground (Ctrl-C stops it, children are signalled in reverse order). */
23
+ export declare function runGatewayUp(opts?: GatewayCommandOptions): Promise<number>;
24
+ /** `oma gateway down`: stop whatever `up -d` started. */
25
+ export declare function runGatewayDown(opts?: GatewayCommandOptions): Promise<number>;
26
+ /** `oma gateway <verb>`: single entry point so the CLI owns one code path. */
27
+ export declare function runGatewayCommand(verb: GatewayCommand, opts?: GatewayCommandOptions): Promise<number>;
28
+ //# sourceMappingURL=gateway-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gateway-commands.d.ts","sourceRoot":"","sources":["../../src/cli/gateway-commands.ts"],"names":[],"mappings":"AAqBA;iEACiE;AACjE,eAAO,MAAM,aAAa,4CAA6C,CAAC;AACxE,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5D,eAAO,MAAM,aAAa,ygBAWF,CAAC;AAEzB,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,cAAc,CAKvE;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAyBD;qEACqE;AACrE,wBAAsB,eAAe,CAAC,IAAI,GAAE,qBAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CAmBvF;AAED;qEACqE;AACrE,wBAAsB,gBAAgB,CAAC,IAAI,GAAE,qBAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CAuDxF;AAED;iFACiF;AACjF,wBAAsB,YAAY,CAAC,IAAI,GAAE,qBAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CAkCpF;AAED,yDAAyD;AACzD,wBAAsB,cAAc,CAAC,IAAI,GAAE,qBAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CAUtF;AA0DD,8EAA8E;AAC9E,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,cAAc,EACpB,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,MAAM,CAAC,CAKjB"}
@@ -0,0 +1,242 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join, resolve } from "node:path";
3
+ import { currentVersion, fetchGatewayArtifact, gatewayPaths, installedVersions, omaHome, omaVersion, readSecrets, } from "../core/gateway/artifact.js";
4
+ import { isProcessAlive, readDaemon, startDetachedGateway, stopDetachedGateway, tailDaemonLog, } from "../core/gateway/daemon.js";
5
+ import { readGatewayManifest } from "../core/gateway/manifest.js";
6
+ import { runGateway } from "../core/gateway/supervisor.js";
7
+ /** The gateway domain's verbs. `oma gateway <verb>` is the CLI surface for
8
+ * backend + web: fetch their artifact, run it, report on it. */
9
+ export const GATEWAY_VERBS = ["up", "down", "fetch", "status"];
10
+ export const GATEWAY_USAGE = `oma gateway <command>
11
+
12
+ up start backend + web; stays in the foreground (Ctrl-C stops it)
13
+ up -d same, but detached: returns once it is healthy
14
+ down stop a detached gateway
15
+ fetch download, verify and unpack the gateway artifact for a version
16
+ status which version is installed, is it running, is it answering
17
+
18
+ --version <v> artifact version for up/fetch (default: oma's own)
19
+
20
+ Note: 'gateway' is a reserved first word. To send it as a prompt, use
21
+ 'oma -p "gateway ..."'.`;
22
+ export function isGatewayCommand(value) {
23
+ for (const verb of GATEWAY_VERBS) {
24
+ if (verb === value)
25
+ return true;
26
+ }
27
+ return false;
28
+ }
29
+ /** A source checkout runs the gateway from the repo, so the release artifact it
30
+ * would download is unused. Only stay quiet there: an explicit CLI call still
31
+ * fetches. `npm_lifecycle_event` is set while a package's postinstall runs. */
32
+ function inMonorepoCheckoutPostinstall() {
33
+ if (process.env.npm_lifecycle_event !== "postinstall")
34
+ return false;
35
+ // src/cli (dist/cli) is TWO levels under the package root — unlike
36
+ // core/gateway/*, which sits three. Getting this wrong made the guard a no-op.
37
+ const packageRoot = resolve(import.meta.dirname, "../..");
38
+ return existsSync(join(packageRoot, "..", "..", "turbo.json"));
39
+ }
40
+ function loggerFor(opts, stream) {
41
+ if (opts.log)
42
+ return opts.log;
43
+ if (opts.quiet)
44
+ return () => { };
45
+ const write = (line) => {
46
+ process[stream].write(`${line}\n`);
47
+ };
48
+ return write;
49
+ }
50
+ /** `oma gateway fetch`: download, verify and unpack the artifact for one
51
+ * version (default: oma's own) so `up` can start it. Idempotent. */
52
+ export async function runGatewayFetch(opts = {}) {
53
+ const log = loggerFor(opts, "stderr");
54
+ if (inMonorepoCheckoutPostinstall()) {
55
+ log("gateway fetch skipped: source checkout (the gateway runs from the repo here)");
56
+ return 0;
57
+ }
58
+ try {
59
+ const result = await fetchGatewayArtifact({
60
+ log,
61
+ ...(opts.home ? { home: opts.home } : {}),
62
+ ...(opts.version ? { version: opts.version } : {}),
63
+ });
64
+ log(`gateway ${result.version} ready at ${result.dir}`);
65
+ log("start it with: oma gateway up");
66
+ return 0;
67
+ }
68
+ catch (err) {
69
+ log(`gateway fetch failed: ${err instanceof Error ? err.message : String(err)}`);
70
+ return 1;
71
+ }
72
+ }
73
+ /** `oma gateway status`: what is installed, which version is current, and
74
+ * whether the gateway answers right now. Never mutates anything. */
75
+ export async function runGatewayStatus(opts = {}) {
76
+ const home = opts.home ?? omaHome();
77
+ const paths = gatewayPaths(home);
78
+ const log = loggerFor(opts, "stdout");
79
+ const versions = installedVersions(home);
80
+ const current = currentVersion(home);
81
+ log(`gateway home: ${paths.home}`);
82
+ log(`versions: ${versions.length > 0 ? versions.join(", ") : "(none installed)"}`);
83
+ log(`current: ${current ?? "(none)"}`);
84
+ if (versions.length === 0) {
85
+ log(`install one: oma gateway fetch (oma ${omaVersion()})`);
86
+ return 1;
87
+ }
88
+ const version = opts.version ?? current ?? versions[versions.length - 1] ?? "";
89
+ const dir = join(paths.versions, version);
90
+ const manifestPath = join(dir, "gateway.json");
91
+ if (!existsSync(manifestPath)) {
92
+ log(`version ${version} is incomplete at ${dir} — re-run: oma gateway fetch`);
93
+ return 1;
94
+ }
95
+ const daemon = readDaemon(home);
96
+ if (daemon && isProcessAlive(daemon.pid)) {
97
+ log(`running: detached, pid ${daemon.pid}, since ${daemon.startedAt}`);
98
+ log(`log: ${daemon.logPath}`);
99
+ }
100
+ else if (daemon) {
101
+ log(`running: no (stale pidfile for pid ${daemon.pid}; 'oma gateway down' clears it)`);
102
+ }
103
+ else {
104
+ log("running: no pidfile (started in the foreground, or not started)");
105
+ }
106
+ const manifest = readGatewayManifest(manifestPath);
107
+ let allUp = true;
108
+ for (const component of manifest.components) {
109
+ if (!component.healthUrl)
110
+ continue;
111
+ let state = "down";
112
+ try {
113
+ const res = await fetch(component.healthUrl, { signal: AbortSignal.timeout(2000) });
114
+ if (res.ok)
115
+ state = "up";
116
+ }
117
+ catch {
118
+ // down
119
+ }
120
+ if (state === "down")
121
+ allUp = false;
122
+ log(`${component.name.padEnd(8)} ${state.padEnd(4)} ${component.healthUrl}`);
123
+ }
124
+ const password = readSecrets(home).MOCK_PASSWORD;
125
+ if (allUp) {
126
+ log(`login: http://127.0.0.1:3001/login (user-001 / ${password ?? "?"})`);
127
+ return 0;
128
+ }
129
+ log("start it with: oma gateway up");
130
+ return 1;
131
+ }
132
+ /** `oma gateway up`: fetch the version if it is missing, then run the whole gateway in
133
+ * the foreground (Ctrl-C stops it, children are signalled in reverse order). */
134
+ export async function runGatewayUp(opts = {}) {
135
+ const home = opts.home ?? omaHome();
136
+ const log = loggerFor(opts, "stdout");
137
+ const version = opts.version ?? currentVersion(home) ?? omaVersion();
138
+ const dir = join(gatewayPaths(home).versions, version);
139
+ if (!existsSync(join(dir, "gateway.json"))) {
140
+ log(`gateway ${version} is not installed yet — fetching it`);
141
+ const code = await runGatewayFetch({ ...opts, version, log });
142
+ if (code !== 0)
143
+ return code;
144
+ }
145
+ if (opts.detach)
146
+ return startGatewayDetached({ ...opts, home, version, log });
147
+ try {
148
+ return await runGateway({
149
+ home,
150
+ version,
151
+ log,
152
+ onReady: (handle) => {
153
+ const web = handle.manifest.components.find((component) => component.port === 3001);
154
+ log("");
155
+ log(`gateway ${handle.manifest.version} is up (${handle.manifest.components.length} processes)`);
156
+ log(`open http://127.0.0.1:${web?.port ?? 3001}/login`);
157
+ if (handle.secrets.MOCK_PASSWORD)
158
+ log(`login: user-001 / ${handle.secrets.MOCK_PASSWORD}`);
159
+ log("Ctrl-C stops the gateway");
160
+ },
161
+ });
162
+ }
163
+ catch (err) {
164
+ log(`gateway failed to start: ${err instanceof Error ? err.message : String(err)}`);
165
+ return 1;
166
+ }
167
+ }
168
+ /** `oma gateway down`: stop whatever `up -d` started. */
169
+ export async function runGatewayDown(opts = {}) {
170
+ const home = opts.home ?? omaHome();
171
+ const log = loggerFor(opts, "stdout");
172
+ const result = await stopDetachedGateway(home);
173
+ if (result.stopped) {
174
+ log(`gateway stopped${result.reason ? ` (${result.reason})` : ""}`);
175
+ return 0;
176
+ }
177
+ log(`nothing stopped: ${result.reason ?? "unknown reason"}`);
178
+ return result.reason?.startsWith("stale pidfile") ? 0 : 1;
179
+ }
180
+ /** Relaunch this CLI in the background and wait until it answers, so the command
181
+ * reports the truth instead of "started something, maybe". */
182
+ async function startGatewayDetached(opts) {
183
+ const entry = process.argv[1];
184
+ if (!entry) {
185
+ opts.log("cannot detach: no CLI entry path in argv");
186
+ return 1;
187
+ }
188
+ const command = [process.execPath, entry, "gateway", "up"];
189
+ if (opts.version)
190
+ command.push("--version", opts.version);
191
+ const daemon = await startDetachedGateway({
192
+ home: opts.home,
193
+ version: opts.version,
194
+ command,
195
+ });
196
+ opts.log(`gateway ${opts.version} starting detached (pid ${daemon.pid})`);
197
+ opts.log(`log: ${daemon.logPath}`);
198
+ const manifest = readGatewayManifest(join(gatewayPaths(opts.home).versions, opts.version, "gateway.json"));
199
+ const web = manifest.components.find((component) => component.port === 3001);
200
+ const healthUrl = web?.healthUrl;
201
+ const deadline = Date.now() + 60_000;
202
+ while (Date.now() < deadline) {
203
+ if (!isProcessAlive(daemon.pid))
204
+ break;
205
+ if (healthUrl) {
206
+ try {
207
+ const res = await fetch(healthUrl, { signal: AbortSignal.timeout(2000) });
208
+ if (res.ok) {
209
+ const password = readSecrets(opts.home).MOCK_PASSWORD;
210
+ opts.log("");
211
+ opts.log(`gateway ${opts.version} is up in the background (pid ${daemon.pid})`);
212
+ opts.log(`open http://127.0.0.1:${web?.port ?? 3001}/login`);
213
+ if (password)
214
+ opts.log(`login: user-001 / ${password}`);
215
+ opts.log("stop it with: oma gateway down");
216
+ return 0;
217
+ }
218
+ }
219
+ catch {
220
+ // not listening yet
221
+ }
222
+ }
223
+ await new Promise((res) => {
224
+ setTimeout(res, 500);
225
+ });
226
+ }
227
+ opts.log("gateway did not become healthy in 60s — last log lines:");
228
+ for (const line of tailDaemonLog(opts.home))
229
+ opts.log(` ${line}`);
230
+ opts.log("stop it with: oma gateway down");
231
+ return 1;
232
+ }
233
+ /** `oma gateway <verb>`: single entry point so the CLI owns one code path. */
234
+ export async function runGatewayCommand(verb, opts = {}) {
235
+ if (verb === "up")
236
+ return runGatewayUp(opts);
237
+ if (verb === "down")
238
+ return runGatewayDown(opts);
239
+ if (verb === "fetch")
240
+ return runGatewayFetch(opts);
241
+ return runGatewayStatus(opts);
242
+ }
@@ -28,5 +28,14 @@ export declare function buildCliRunInput(opts: {
28
28
  modelRuntime: ModelRuntime;
29
29
  /** Canonical `<provider>/<model>` id; undefined = first available. */
30
30
  modelId?: string;
31
+ /** Standalone permission gate. undefined = ungated (legacy default). */
32
+ permissionMode?: "ask" | "auto" | "deny";
33
+ /** --read-only: advertise no write/edit/bash/eval to the model. */
34
+ readOnly?: boolean;
35
+ /** Clipboard/pasted images riding this prompt (vision input). */
36
+ images?: ReadonlyArray<{
37
+ mediaType: "image/png" | "image/jpeg" | "image/gif" | "image/webp";
38
+ base64: string;
39
+ }>;
31
40
  }): Promise<BackendRunInput<"oma">>;
32
41
  //# sourceMappingURL=initial-input.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"initial-input.d.ts","sourceRoot":"","sources":["../../src/cli/initial-input.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAQrD;;;;;wDAKwD;AACxD,wBAAgB,2BAA2B,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,CAqC3E;AAMD;;yCAEyC;AACzC,wBAAsB,cAAc,CAClC,MAAM,GAAE,cAAc,CAAC,UAAU,CAAsB,GACtD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAsB7B;AAED;;iDAEiD;AACjD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAKpF;AAED;;;wBAGwB;AACxB,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;IAC3B,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAqClC"}
1
+ {"version":3,"file":"initial-input.d.ts","sourceRoot":"","sources":["../../src/cli/initial-input.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAUrD;;;;;wDAKwD;AACxD,wBAAgB,2BAA2B,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,EAAE,CA+C3E;AAMD;;yCAEyC;AACzC,wBAAsB,cAAc,CAClC,MAAM,GAAE,cAAc,CAAC,UAAU,CAAsB,GACtD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAsB7B;AAED;;iDAEiD;AACjD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAKpF;AA0BD;;;wBAGwB;AAExB,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;IAC3B,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,cAAc,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACzC,mEAAmE;IACnE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iEAAiE;IACjE,MAAM,CAAC,EAAE,aAAa,CAAC;QACrB,SAAS,EAAE,WAAW,GAAG,YAAY,GAAG,WAAW,GAAG,YAAY,CAAC;QACnE,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ,GAAG,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,CAyClC"}
@@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  import { existsSync, statSync } from "node:fs";
3
3
  import { homedir } from "node:os";
4
4
  import { isAbsolute, join } from "node:path";
5
+ import { managedSkillsDir } from "../core/memory/managed-skills.js";
5
6
  import { enabledPluginSkillRoots } from "../core/plugins/plugin-marketplace.js";
6
7
  import { buildSystemPrompt, readMemorySummary } from "../core/runtime/prompts.js";
7
8
  import { agentDir } from "../core/session/session-file.js";
@@ -45,6 +46,18 @@ export function resolveStandaloneSkillRoots(workspaceRoot) {
45
46
  if (!roots.includes(dir))
46
47
  roots.push(dir);
47
48
  }
49
+ // Managed skills (learn-tool minted) resolve DEAD-LAST: any authored skill
50
+ // of the same name shadows them (omp managed-skills semantics).
51
+ const managed = managedSkillsDir();
52
+ if (!roots.includes(managed)) {
53
+ try {
54
+ if (statSync(managed).isDirectory())
55
+ roots.push(managed);
56
+ }
57
+ catch {
58
+ /* absent managed dir */
59
+ }
60
+ }
48
61
  return roots;
49
62
  }
50
63
  /** One-shot CLI stdin bound: a hostile `cat huge-file | oma -p`
@@ -86,6 +99,24 @@ export function mergeInitialInput(input) {
86
99
  const parts = [input.piped?.trim(), input.prompt?.trim()].filter((part) => Boolean(part));
87
100
  return parts.join("\n\n");
88
101
  }
102
+ /** User message with optional vision images: blocks form when images ride
103
+ * along (the providers map user image blocks natively); plain text otherwise. */
104
+ function buildUserMessage(prompt, images) {
105
+ if (!images || images.length === 0)
106
+ return { role: "user", text: prompt };
107
+ return {
108
+ role: "user",
109
+ text: prompt,
110
+ blocks: [
111
+ { type: "text", text: prompt },
112
+ ...images.map((img) => ({
113
+ type: "image",
114
+ mediaType: img.mediaType,
115
+ base64: img.base64,
116
+ })),
117
+ ],
118
+ };
119
+ }
89
120
  /** Build the BackendRunInput for a one-shot CLI run: current cwd as the
90
121
  * workspace, empty Product history, the requested model (canonical
91
122
  * `<provider>/<model>` id) or the first available model, no Product Tools,
@@ -110,7 +141,7 @@ export async function buildCliRunInput(opts) {
110
141
  const input = {
111
142
  input: {
112
143
  inputId: `cli-in-${randomUUID()}`,
113
- message: { role: "user", text: opts.prompt },
144
+ message: buildUserMessage(opts.prompt, opts.images),
114
145
  },
115
146
  run: {
116
147
  runId,
@@ -122,10 +153,13 @@ export async function buildCliRunInput(opts) {
122
153
  }),
123
154
  configRevision: 0,
124
155
  },
125
- workspace: { root: opts.workspaceRoot, access: "read_write" },
156
+ workspace: { root: opts.workspaceRoot, access: opts.readOnly ? "read_only" : "read_write" },
126
157
  // Standalone agent: no product conversation/agent/branch identity.
127
158
  };
128
- if (skillRoots.length === 0)
129
- return input;
130
- return { ...input, run: { ...input.run, skillRoots } };
159
+ const run = {
160
+ ...input.run,
161
+ ...(skillRoots.length > 0 ? { skillRoots } : {}),
162
+ ...(opts.permissionMode ? { permissionMode: opts.permissionMode } : {}),
163
+ };
164
+ return { ...input, run };
131
165
  }
@@ -0,0 +1,30 @@
1
+ import type { PluginTool } from "../index.js";
2
+ import type { EntryRow, RegistryEntry } from "./registry.js";
3
+ export interface HubToolDeps {
4
+ readonly scope: string;
5
+ readonly list: (scope: string) => EntryRow[];
6
+ readonly get: (id: string) => RegistryEntry | undefined;
7
+ readonly wait: (opts: {
8
+ ids?: readonly string[];
9
+ scope: string;
10
+ timeoutMs: number;
11
+ }) => Promise<{
12
+ settled: EntryRow[];
13
+ timedOut: boolean;
14
+ }>;
15
+ readonly stop: (id: string) => {
16
+ ok: boolean;
17
+ error?: string;
18
+ };
19
+ readonly steer: (handle: string, prompt: string) => {
20
+ ok: boolean;
21
+ error?: string;
22
+ };
23
+ /** Delivery suppression: ack settled ids this tool result showed. */
24
+ readonly acknowledge?: (ids: readonly string[]) => void;
25
+ /** True when a job's result already reached the model through an earlier
26
+ * tool result (inline task batch) or a previous hub fetch. */
27
+ readonly isDelivered?: (id: string) => boolean;
28
+ }
29
+ export declare function createHubTool(deps: HubToolDeps): readonly PluginTool[];
30
+ //# sourceMappingURL=hub-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hub-tool.d.ts","sourceRoot":"","sources":["../../../src/core/coordination/hub-tool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE7D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,QAAQ,EAAE,CAAC;IAC7C,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,aAAa,GAAG,SAAS,CAAC;IACxD,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE;QACpB,GAAG,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QACxB,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;KACnB,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC1D,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/D,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACpF,qEAAqE;IACrE,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC;IACxD;mEAC+D;IAC/D,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;CAChD;AAsHD,wBAAgB,aAAa,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS,UAAU,EAAE,CAsItE"}