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

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 (215) hide show
  1. package/README.md +11 -6
  2. package/dist/cli/args.d.ts +1 -1
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +9 -2
  5. package/dist/cli/gateway-commands.d.ts +14 -2
  6. package/dist/cli/gateway-commands.d.ts.map +1 -1
  7. package/dist/cli/gateway-commands.js +133 -8
  8. package/dist/cli/initial-input.d.ts +3 -2
  9. package/dist/cli/initial-input.d.ts.map +1 -1
  10. package/dist/core/coordination/registry.d.ts +11 -0
  11. package/dist/core/coordination/registry.d.ts.map +1 -1
  12. package/dist/core/coordination/registry.js +23 -0
  13. package/dist/core/gateway/artifact.d.ts +3 -2
  14. package/dist/core/gateway/artifact.d.ts.map +1 -1
  15. package/dist/core/gateway/artifact.js +62 -10
  16. package/dist/core/gateway/daemon.d.ts.map +1 -1
  17. package/dist/core/gateway/daemon.js +3 -1
  18. package/dist/core/gateway/doctor.d.ts +21 -0
  19. package/dist/core/gateway/doctor.d.ts.map +1 -0
  20. package/dist/core/gateway/doctor.js +405 -0
  21. package/dist/core/goals/index.d.ts +8 -0
  22. package/dist/core/goals/index.d.ts.map +1 -0
  23. package/dist/core/goals/index.js +7 -0
  24. package/dist/core/goals/runtime.d.ts +112 -0
  25. package/dist/core/goals/runtime.d.ts.map +1 -0
  26. package/dist/core/goals/runtime.js +241 -0
  27. package/dist/core/goals/state.d.ts +82 -0
  28. package/dist/core/goals/state.d.ts.map +1 -0
  29. package/dist/core/goals/state.js +225 -0
  30. package/dist/core/goals/tool.d.ts +10 -0
  31. package/dist/core/goals/tool.d.ts.map +1 -0
  32. package/dist/core/goals/tool.js +87 -0
  33. package/dist/core/index.d.ts.map +1 -1
  34. package/dist/core/index.js +4 -3
  35. package/dist/core/loops/condition.d.ts +57 -0
  36. package/dist/core/loops/condition.d.ts.map +1 -0
  37. package/dist/core/loops/condition.js +153 -0
  38. package/dist/core/loops/index.d.ts +9 -0
  39. package/dist/core/loops/index.d.ts.map +1 -0
  40. package/dist/core/loops/index.js +8 -0
  41. package/dist/core/loops/limits.d.ts +43 -0
  42. package/dist/core/loops/limits.d.ts.map +1 -0
  43. package/dist/core/loops/limits.js +219 -0
  44. package/dist/core/loops/ralph.d.ts +37 -0
  45. package/dist/core/loops/ralph.d.ts.map +1 -0
  46. package/dist/core/loops/ralph.js +72 -0
  47. package/dist/core/loops/runtime.d.ts +95 -0
  48. package/dist/core/loops/runtime.d.ts.map +1 -0
  49. package/dist/core/loops/runtime.js +222 -0
  50. package/dist/core/memory/managed-skills.d.ts +0 -11
  51. package/dist/core/memory/managed-skills.d.ts.map +1 -1
  52. package/dist/core/memory/managed-skills.js +2 -2
  53. package/dist/core/memory/vector-store.d.ts +0 -1
  54. package/dist/core/memory/vector-store.d.ts.map +1 -1
  55. package/dist/core/memory/vector-store.js +0 -3
  56. package/dist/core/plans/index.d.ts +7 -0
  57. package/dist/core/plans/index.d.ts.map +1 -0
  58. package/dist/core/plans/index.js +6 -0
  59. package/dist/core/plans/prompts.d.ts +20 -0
  60. package/dist/core/plans/prompts.d.ts.map +1 -0
  61. package/dist/core/plans/prompts.js +72 -0
  62. package/dist/core/plans/runtime.d.ts +89 -0
  63. package/dist/core/plans/runtime.d.ts.map +1 -0
  64. package/dist/core/plans/runtime.js +170 -0
  65. package/dist/core/plans/state.d.ts +55 -0
  66. package/dist/core/plans/state.d.ts.map +1 -0
  67. package/dist/core/plans/state.js +88 -0
  68. package/dist/core/runtime/agent-loop-messages.d.ts +6 -0
  69. package/dist/core/runtime/agent-loop-messages.d.ts.map +1 -1
  70. package/dist/core/runtime/agent-loop-messages.js +40 -15
  71. package/dist/core/runtime/agent-loop-run.d.ts.map +1 -1
  72. package/dist/core/runtime/agent-loop-run.js +18 -27
  73. package/dist/core/runtime/agent-loop-runner.d.ts +1 -23
  74. package/dist/core/runtime/agent-loop-runner.d.ts.map +1 -1
  75. package/dist/core/runtime/agent-loop-runner.js +84 -30
  76. package/dist/core/runtime/agent-loop-types.d.ts +4 -0
  77. package/dist/core/runtime/agent-loop-types.d.ts.map +1 -1
  78. package/dist/core/runtime/compaction.d.ts +9 -0
  79. package/dist/core/runtime/compaction.d.ts.map +1 -1
  80. package/dist/core/runtime/compaction.js +28 -0
  81. package/dist/core/runtime/context-estimate.d.ts +37 -4
  82. package/dist/core/runtime/context-estimate.d.ts.map +1 -1
  83. package/dist/core/runtime/context-estimate.js +70 -0
  84. package/dist/core/runtime/create-runtime.d.ts +27 -5
  85. package/dist/core/runtime/create-runtime.d.ts.map +1 -1
  86. package/dist/core/runtime/create-runtime.js +22 -2
  87. package/dist/core/runtime/permission-classifier.d.ts.map +1 -1
  88. package/dist/core/runtime/permission-classifier.js +83 -12
  89. package/dist/core/runtime/plugin.d.ts +7 -0
  90. package/dist/core/runtime/plugin.d.ts.map +1 -1
  91. package/dist/core/runtime/plugin.js +13 -0
  92. package/dist/core/runtime/process-tree.d.ts +0 -9
  93. package/dist/core/runtime/process-tree.d.ts.map +1 -1
  94. package/dist/core/runtime/process-tree.js +1 -1
  95. package/dist/core/runtime/run-runtime.d.ts.map +1 -1
  96. package/dist/core/runtime/run-runtime.js +88 -49
  97. package/dist/core/runtime/runtime-catalog.d.ts +0 -4
  98. package/dist/core/runtime/runtime-catalog.d.ts.map +1 -1
  99. package/dist/core/runtime/runtime-catalog.js +1 -1
  100. package/dist/core/runtime/stream-rules.d.ts +9 -2
  101. package/dist/core/runtime/stream-rules.d.ts.map +1 -1
  102. package/dist/core/runtime/stream-rules.js +19 -5
  103. package/dist/core/runtime/title.d.ts +13 -1
  104. package/dist/core/runtime/title.d.ts.map +1 -1
  105. package/dist/core/runtime/title.js +51 -17
  106. package/dist/core/runtime/tool-pruning.d.ts.map +1 -1
  107. package/dist/core/runtime/tool-pruning.js +8 -16
  108. package/dist/core/session/session-file.d.ts +91 -5
  109. package/dist/core/session/session-file.d.ts.map +1 -1
  110. package/dist/core/session/session-file.js +206 -24
  111. package/dist/core/session/session-loop.d.ts +3 -1
  112. package/dist/core/session/session-loop.d.ts.map +1 -1
  113. package/dist/core/session/session-loop.js +8 -4
  114. package/dist/core/settings/project-settings.d.ts +63 -9
  115. package/dist/core/settings/project-settings.d.ts.map +1 -1
  116. package/dist/core/settings/project-settings.js +43 -2
  117. package/dist/core/settings/workspace-context.js +4 -4
  118. package/dist/core/store/in-memory-session-store.d.ts.map +1 -1
  119. package/dist/core/store/in-memory-session-store.js +3 -2
  120. package/dist/core/store/session-store.contract.test-helper.d.ts +7 -5
  121. package/dist/core/store/session-store.contract.test-helper.d.ts.map +1 -1
  122. package/dist/core/store/session-store.contract.test-helper.js +7 -5
  123. package/dist/core/store/session-store.d.ts +4 -2
  124. package/dist/core/store/session-store.d.ts.map +1 -1
  125. package/dist/core/store/session-store.js +4 -2
  126. package/dist/core/tools/ask-question.d.ts.map +1 -1
  127. package/dist/core/tools/ask-question.js +51 -5
  128. package/dist/core/tools/bash-pty.d.ts +13 -4
  129. package/dist/core/tools/bash-pty.d.ts.map +1 -1
  130. package/dist/core/tools/bash-pty.js +15 -8
  131. package/dist/core/tools/bash-sandbox.d.ts +1 -1
  132. package/dist/core/tools/bash.d.ts +1 -1
  133. package/dist/core/tools/bash.d.ts.map +1 -1
  134. package/dist/core/tools/bash.js +18 -8
  135. package/dist/core/tools/browser.d.ts +54 -0
  136. package/dist/core/tools/browser.d.ts.map +1 -1
  137. package/dist/core/tools/browser.js +138 -1
  138. package/dist/core/tools/file-fingerprint.d.ts +24 -0
  139. package/dist/core/tools/file-fingerprint.d.ts.map +1 -0
  140. package/dist/core/tools/file-fingerprint.js +61 -0
  141. package/dist/core/tools/file-tools.d.ts +26 -0
  142. package/dist/core/tools/file-tools.d.ts.map +1 -1
  143. package/dist/core/tools/file-tools.js +113 -17
  144. package/dist/core/tools/index.d.ts +2 -0
  145. package/dist/core/tools/index.d.ts.map +1 -1
  146. package/dist/core/tools/index.js +1 -0
  147. package/dist/core/tools/mcp-mount.d.ts +1 -1
  148. package/dist/core/tools/mcp-mount.d.ts.map +1 -1
  149. package/dist/core/tools/mcp-mount.js +72 -26
  150. package/dist/core/tools/url-guard.d.ts +15 -0
  151. package/dist/core/tools/url-guard.d.ts.map +1 -1
  152. package/dist/core/tools/url-guard.js +54 -14
  153. package/dist/core/tools/web-ports-std.d.ts.map +1 -1
  154. package/dist/core/tools/web-ports-std.js +5 -2
  155. package/dist/modes/print-mode.d.ts +3 -2
  156. package/dist/modes/print-mode.d.ts.map +1 -1
  157. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  158. package/dist/modes/rpc/rpc-mode.js +2 -2
  159. package/dist/modes/shared.d.ts +12 -0
  160. package/dist/modes/shared.d.ts.map +1 -1
  161. package/dist/modes/shared.js +23 -6
  162. package/dist/modes/tui/agent-status.d.ts +20 -0
  163. package/dist/modes/tui/agent-status.d.ts.map +1 -0
  164. package/dist/modes/tui/agent-status.js +35 -0
  165. package/dist/modes/tui/ask-panel.d.ts +166 -0
  166. package/dist/modes/tui/ask-panel.d.ts.map +1 -0
  167. package/dist/modes/tui/ask-panel.js +888 -0
  168. package/dist/modes/tui/pty-console.d.ts +3 -0
  169. package/dist/modes/tui/pty-console.d.ts.map +1 -1
  170. package/dist/modes/tui/pty-console.js +19 -0
  171. package/dist/modes/tui/settings-overlay.d.ts +19 -0
  172. package/dist/modes/tui/settings-overlay.d.ts.map +1 -1
  173. package/dist/modes/tui/settings-overlay.js +46 -10
  174. package/dist/modes/tui/tui-commands-session.d.ts.map +1 -1
  175. package/dist/modes/tui/tui-commands-session.js +20 -6
  176. package/dist/modes/tui/tui-commands.d.ts +44 -3
  177. package/dist/modes/tui/tui-commands.d.ts.map +1 -1
  178. package/dist/modes/tui/tui-commands.js +380 -6
  179. package/dist/modes/tui/tui-components.d.ts +10 -0
  180. package/dist/modes/tui/tui-components.d.ts.map +1 -1
  181. package/dist/modes/tui/tui-components.js +26 -0
  182. package/dist/modes/tui/tui-format.d.ts +53 -4
  183. package/dist/modes/tui/tui-format.d.ts.map +1 -1
  184. package/dist/modes/tui/tui-format.js +137 -42
  185. package/dist/modes/tui/tui-frame-provider.d.ts +11 -3
  186. package/dist/modes/tui/tui-frame-provider.d.ts.map +1 -1
  187. package/dist/modes/tui/tui-frame-provider.js +14 -5
  188. package/dist/modes/tui/tui-interactive.d.ts.map +1 -1
  189. package/dist/modes/tui/tui-interactive.js +14 -0
  190. package/dist/modes/tui/tui-io.d.ts.map +1 -1
  191. package/dist/modes/tui/tui-io.js +150 -55
  192. package/dist/modes/tui/tui-mode.d.ts.map +1 -1
  193. package/dist/modes/tui/tui-mode.js +428 -23
  194. package/dist/modes/tui/tui-overlays.d.ts +6 -10
  195. package/dist/modes/tui/tui-overlays.d.ts.map +1 -1
  196. package/dist/modes/tui/tui-overlays.js +0 -43
  197. package/dist/modes/tui/tui-render.d.ts +10 -0
  198. package/dist/modes/tui/tui-render.d.ts.map +1 -1
  199. package/dist/modes/tui/tui-render.js +73 -38
  200. package/dist/modes/tui/tui-seam.d.ts +28 -6
  201. package/dist/modes/tui/tui-seam.d.ts.map +1 -1
  202. package/dist/modes/tui/tui-slash.d.ts.map +1 -1
  203. package/dist/modes/tui/tui-slash.js +3 -1
  204. package/dist/modes/tui/tui-tool-render.d.ts +14 -1
  205. package/dist/modes/tui/tui-tool-render.d.ts.map +1 -1
  206. package/dist/modes/tui/tui-tool-render.js +158 -50
  207. package/dist/modes/tui/tui-transcript-reconciler.d.ts +4 -0
  208. package/dist/modes/tui/tui-transcript-reconciler.d.ts.map +1 -1
  209. package/dist/modes/tui/tui-transcript-reconciler.js +12 -2
  210. package/dist/modes/tui/view-state.d.ts.map +1 -1
  211. package/dist/modes/tui/view-state.js +4 -1
  212. package/dist/protocol/transport.d.ts +24 -14
  213. package/dist/protocol/transport.d.ts.map +1 -1
  214. package/dist/protocol/transport.js +1 -0
  215. package/package.json +11 -11
package/README.md CHANGED
@@ -7,7 +7,7 @@ Product Backend → Agent Run → Adapter → spawn oma --mode rpc
7
7
  → per-Run Runtime → BackendRunOutcome → stdout → child 退出
8
8
  ```
9
9
 
10
- **不是 daemon**:一个 Run = 一个子进程 = 一个 Runtime = 一个 outcome。没有常驻进程、没有 session supervisor、没有 worker pool。
10
+ **不是 daemon**(就 Run 执行模型而言):一个 Run = 一个子进程 = 一个 Runtime = 一个 outcome。没有常驻的 session supervisor,没有 worker pool。同一个包里的 `core/gateway/` 是另一回事——`oma gateway up -d` 确实会起一个 detached daemon,那是它自己的 pidfile 加 supervisor,与 Run 无关。
11
11
 
12
12
  ## TUI
13
13
 
@@ -38,13 +38,13 @@ Product Backend → Agent Run → Adapter → spawn oma --mode rpc
38
38
 
39
39
  ## Runtime
40
40
 
41
- `createOmaRuntime()`(`src/core/create-runtime.ts`)构造一个 Runtime = 一个 Run:
41
+ `createOmaRuntime()`(`src/core/runtime/create-runtime.ts`)构造一个 Runtime = 一个 Run:
42
42
 
43
43
  - `run(input)` 返回唯一 segment,其 `outcome` 是 Run 的唯一终态;
44
44
  - `steer(input)` 注入 live loop;`stop()` 中止;
45
45
  - `close()` 拆除 MCP clients 与 SessionStore。
46
46
 
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
+ Runtime 主体就在本 app 的 `src/core/`:OmaSession(model/tool loop、retry、compaction、插件、todo、tool-result pruning)与 in-memory SessionStore(`core/store/`)。in-memory store 随 Run 销毁,但子进程会把本轮写进自己的 session 文件(`core/session/` 的 JSONL),并通过 outcome 回传 `cliSessionRef`;下一个 Run 用它 resume 那个文件,扁平的历史桥只在没有引用时才用。
48
48
 
49
49
  ## 运行
50
50
 
@@ -53,7 +53,7 @@ bun run --cwd apps/oh-my-agent dev -- -p "hello" # source CLI (dev)
53
53
  bun apps/oh-my-agent/src/cli.ts -p "hello" # source CLI, direct
54
54
 
55
55
  bun run --cwd apps/oh-my-agent build # → dist/cli.js (executable)
56
- apps/oh-my-agent/dist/cli.js -p "hello" # built binary
56
+ ./dist/cli.js -p "hello" # built binary (inside apps/oh-my-agent)
57
57
 
58
58
  cd apps/oh-my-agent && bun link # optional local install
59
59
  oma -p "hello" # then run from anywhere
@@ -69,9 +69,14 @@ oma # standalone interactive TUI
69
69
  src/
70
70
  cli.ts 可执行入口(shebang + runCli())
71
71
  main.ts main()/runCli():参数解析、模式分发、退出码(无 process.exit)
72
- cli/ print/json 模式、初始输入构建、CLI 测试
72
+ cli/ 参数解析、初始输入构建、gateway 子命令
73
73
  modes/ tui / print / json / rpc 模式
74
- core/ create-runtime.ts(per-Run Runtime 装配)、project-settings.ts(.oma/settings.json)、fake-provider(测试)
74
+ core/
75
+ runtime/ create-runtime.ts(per-Run Runtime 装配)
76
+ session/ session 文件(JSONL):/resume、--continue 与跨 Run resume 的持久侧
77
+ settings/ project-settings.ts(.oma/settings.json)
78
+ loops/ goals/ plans/ 三种持续模式的状态机与工具面
79
+ gateway/ `oma gateway` 的 daemon、supervisor、doctor、artifact
75
80
  ```
76
81
 
77
82
  ## 相关文档
@@ -1,6 +1,6 @@
1
1
  import { type GatewayCommand } from "./gateway-commands.js";
2
2
  export type CliMode = "print" | "json" | "rpc" | "tui";
3
- export type PermissionFlag = "ask" | "auto" | "deny" | "off";
3
+ export type PermissionFlag = "ask" | "auto" | "deny" | "off" | "yolo";
4
4
  export interface CliArgs {
5
5
  mode: CliMode;
6
6
  /** True when -p/--mode was given explicitly; a bare positional prompt
@@ -1 +1 @@
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"}
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,GAAG,MAAM,CAAC;AAEtE,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,CA6G1D"}
package/dist/cli/args.js CHANGED
@@ -19,7 +19,7 @@ Usage:
19
19
  oma --continue resume the most recent session
20
20
  oma --session <id> -p "..." one-shot follow-up on a session
21
21
  oma --permission ask -p "..." gate bash/write/mcp behind approval cards
22
- oma --read-only -p "..." research-only run (no mutating tools)
22
+ oma --yolo -p "..." ungated run (OS sandbox forced when present)
23
23
  oma --model <provider/model> -p "<prompt>"
24
24
  pick a model by canonical id
25
25
  (default: first available model)
@@ -30,7 +30,7 @@ Piped stdin (print/json modes):
30
30
  cat error.log | oma -p (stdin only)
31
31
  `;
32
32
  const MODES = ["print", "json", "rpc", "tui"];
33
- const PERMISSIONS = ["ask", "auto", "deny", "off"];
33
+ const PERMISSIONS = ["ask", "auto", "deny", "off", "yolo"];
34
34
  /** Parse argv SYNTAX only: whether a run actually has an input (prompt or
35
35
  * piped stdin) is decided in main() after stdin is read. */
36
36
  export function parseArgs(argv) {
@@ -111,6 +111,13 @@ export function parseArgs(argv) {
111
111
  else if (arg === "--read-only") {
112
112
  args.readOnly = true;
113
113
  }
114
+ else if (arg === "--yolo") {
115
+ // The industry's skip-permissions flag (crush --yolo / CC
116
+ // --dangerously-skip-permissions): ungated run. Boundaries that do
117
+ // not depend on judgment (workspace containment, protected files,
118
+ // secret stripping, egress rules, write freshness) all remain.
119
+ args.permission = "yolo";
120
+ }
114
121
  else if (arg === "--permission") {
115
122
  const value = argv[i + 1];
116
123
  if (!value || !PERMISSIONS.includes(value)) {
@@ -1,9 +1,14 @@
1
1
  /** The gateway domain's verbs. `oma gateway <verb>` is the CLI surface for
2
2
  * backend + web: fetch their artifact, run it, report on it. */
3
- export declare const GATEWAY_VERBS: readonly ["up", "down", "fetch", "status"];
3
+ export declare const GATEWAY_VERBS: readonly ["up", "down", "fetch", "status", "doctor", "passwd"];
4
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 ...\"'.";
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 doctor why nothing can run: artifact, tools, catalog, keys, ports, oma bin\n passwd replace the login password with a fresh random one\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
6
  export declare function isGatewayCommand(value: string): value is GatewayCommand;
7
+ /** What to tell the operator about logging in. The password is only echoed on
8
+ * an interactive terminal: a detached run's stdout is redirected into a log
9
+ * file, and a secret must not be filed away there. The pointer is always
10
+ * printed, so a missed banner is never a dead end. */
11
+ export declare function credentialLines(home: string, secrets: Record<string, string>, interactive: boolean): string[];
7
12
  export interface GatewayCommandOptions {
8
13
  home?: string;
9
14
  version?: string;
@@ -21,6 +26,13 @@ export declare function runGatewayStatus(opts?: GatewayCommandOptions): Promise<
21
26
  /** `oma gateway up`: fetch the version if it is missing, then run the whole gateway in
22
27
  * the foreground (Ctrl-C stops it, children are signalled in reverse order). */
23
28
  export declare function runGatewayUp(opts?: GatewayCommandOptions): Promise<number>;
29
+ /** `oma gateway passwd`: rotate the login password. Generated, never read from
30
+ * argv — an argument would land in shell history and process listings.
31
+ * Takes effect on the next start, because the web component reads it from its
32
+ * environment. */
33
+ export declare function runGatewayPasswd(opts?: GatewayCommandOptions): Promise<number>;
34
+ /** `oma gateway doctor`: check the deployment and say how to fix what is wrong. */
35
+ export declare function runGatewayDoctor(opts?: GatewayCommandOptions): Promise<number>;
24
36
  /** `oma gateway down`: stop whatever `up -d` started. */
25
37
  export declare function runGatewayDown(opts?: GatewayCommandOptions): Promise<number>;
26
38
  /** `oma gateway <verb>`: single entry point so the CLI owns one code path. */
@@ -1 +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"}
1
+ {"version":3,"file":"gateway-commands.d.ts","sourceRoot":"","sources":["../../src/cli/gateway-commands.ts"],"names":[],"mappings":"AAwBA;iEACiE;AACjE,eAAO,MAAM,aAAa,gEAAiE,CAAC;AAC5F,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5D,eAAO,MAAM,aAAa,0pBAaF,CAAC;AAEzB,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,cAAc,CAKvE;AAED;;;uDAGuD;AACvD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,WAAW,EAAE,OAAO,GACnB,MAAM,EAAE,CAMV;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,CAgExF;AAED;iFACiF;AACjF,wBAAsB,YAAY,CAAC,IAAI,GAAE,qBAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CAoCpF;AAED;;;mBAGmB;AACnB,wBAAsB,gBAAgB,CAAC,IAAI,GAAE,qBAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CA+BxF;AAmDD,mFAAmF;AACnF,wBAAsB,gBAAgB,CAAC,IAAI,GAAE,qBAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBxF;AAED,yDAAyD;AACzD,wBAAsB,cAAc,CAAC,IAAI,GAAE,qBAA0B,GAAG,OAAO,CAAC,MAAM,CAAC,CAUtF;AA+DD,8EAA8E;AAC9E,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,cAAc,EACpB,IAAI,GAAE,qBAA0B,GAC/B,OAAO,CAAC,MAAM,CAAC,CAOjB"}
@@ -1,12 +1,14 @@
1
- import { existsSync } from "node:fs";
1
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { writeFile } from "node:fs/promises";
2
3
  import { join, resolve } from "node:path";
3
- import { currentVersion, fetchGatewayArtifact, gatewayPaths, installedVersions, omaHome, omaVersion, readSecrets, } from "../core/gateway/artifact.js";
4
+ import { currentVersion, fetchGatewayArtifact, gatewayPaths, generatePassword, installedVersions, omaHome, omaVersion, readSecrets, } from "../core/gateway/artifact.js";
4
5
  import { isProcessAlive, readDaemon, startDetachedGateway, stopDetachedGateway, tailDaemonLog, } from "../core/gateway/daemon.js";
6
+ import { diagnoseGateway } from "../core/gateway/doctor.js";
5
7
  import { readGatewayManifest } from "../core/gateway/manifest.js";
6
8
  import { runGateway } from "../core/gateway/supervisor.js";
7
9
  /** The gateway domain's verbs. `oma gateway <verb>` is the CLI surface for
8
10
  * backend + web: fetch their artifact, run it, report on it. */
9
- export const GATEWAY_VERBS = ["up", "down", "fetch", "status"];
11
+ export const GATEWAY_VERBS = ["up", "down", "fetch", "status", "doctor", "passwd"];
10
12
  export const GATEWAY_USAGE = `oma gateway <command>
11
13
 
12
14
  up start backend + web; stays in the foreground (Ctrl-C stops it)
@@ -14,6 +16,8 @@ export const GATEWAY_USAGE = `oma gateway <command>
14
16
  down stop a detached gateway
15
17
  fetch download, verify and unpack the gateway artifact for a version
16
18
  status which version is installed, is it running, is it answering
19
+ doctor why nothing can run: artifact, tools, catalog, keys, ports, oma bin
20
+ passwd replace the login password with a fresh random one
17
21
 
18
22
  --version <v> artifact version for up/fetch (default: oma's own)
19
23
 
@@ -26,6 +30,18 @@ export function isGatewayCommand(value) {
26
30
  }
27
31
  return false;
28
32
  }
33
+ /** What to tell the operator about logging in. The password is only echoed on
34
+ * an interactive terminal: a detached run's stdout is redirected into a log
35
+ * file, and a secret must not be filed away there. The pointer is always
36
+ * printed, so a missed banner is never a dead end. */
37
+ export function credentialLines(home, secrets, interactive) {
38
+ const lines = [];
39
+ const password = secrets.MOCK_PASSWORD;
40
+ if (password && interactive)
41
+ lines.push(`login: user-001 / ${password}`);
42
+ lines.push(`login password: oma gateway status (or read ${gatewayPaths(home).secrets})`);
43
+ return lines;
44
+ }
29
45
  /** A source checkout runs the gateway from the repo, so the release artifact it
30
46
  * would download is unused. Only stay quiet there: an explicit CLI call still
31
47
  * fetches. `npm_lifecycle_event` is set while a package's postinstall runs. */
@@ -81,6 +97,13 @@ export async function runGatewayStatus(opts = {}) {
81
97
  log(`gateway home: ${paths.home}`);
82
98
  log(`versions: ${versions.length > 0 ? versions.join(", ") : "(none installed)"}`);
83
99
  log(`current: ${current ?? "(none)"}`);
100
+ // Which catalog the gateway's children will read: product runs deliberately
101
+ // ignore ~/.oma/models.yml (the agent's own bash tool can write there), so a
102
+ // custom provider only counts when OMA_HOME points at its models.yml.
103
+ const catalogHome = process.env.OMA_HOME;
104
+ log(catalogHome
105
+ ? `catalog: ${catalogHome}/models.yml via OMA_HOME`
106
+ : "catalog: built-in providers only (OMA_HOME unset — a custom models.yml is not read)");
84
107
  if (versions.length === 0) {
85
108
  log(`install one: oma gateway fetch (oma ${omaVersion()})`);
86
109
  return 1;
@@ -154,8 +177,9 @@ export async function runGatewayUp(opts = {}) {
154
177
  log("");
155
178
  log(`gateway ${handle.manifest.version} is up (${handle.manifest.components.length} processes)`);
156
179
  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}`);
180
+ for (const line of credentialLines(home, handle.secrets, process.stdout.isTTY === true)) {
181
+ log(line);
182
+ }
159
183
  log("Ctrl-C stops the gateway");
160
184
  },
161
185
  });
@@ -165,6 +189,103 @@ export async function runGatewayUp(opts = {}) {
165
189
  return 1;
166
190
  }
167
191
  }
192
+ /** `oma gateway passwd`: rotate the login password. Generated, never read from
193
+ * argv — an argument would land in shell history and process listings.
194
+ * Takes effect on the next start, because the web component reads it from its
195
+ * environment. */
196
+ export async function runGatewayPasswd(opts = {}) {
197
+ const home = opts.home ?? omaHome();
198
+ const log = loggerFor(opts, "stdout");
199
+ const secretsPath = gatewayPaths(home).secrets;
200
+ if (!existsSync(secretsPath)) {
201
+ log(`no secrets at ${secretsPath} — run 'oma gateway up' once first`);
202
+ return 1;
203
+ }
204
+ const password = generatePassword();
205
+ const secrets = { ...readSecrets(home), MOCK_PASSWORD: password };
206
+ await writeFile(secretsPath, `${JSON.stringify(secrets, null, 2)}\n`, { mode: 0o600 });
207
+ log(`login password replaced: user-001 / ${password}`);
208
+ // A password set in the console is stored as a hash in the stack's settings
209
+ // and wins over this file, so the new one has to land there too — otherwise
210
+ // rotating here would silently not take effect.
211
+ const pushed = await pushPasswordToRunningGateway(secrets, password);
212
+ if (pushed) {
213
+ log("the running gateway took it too (console-set password updated)");
214
+ return 0;
215
+ }
216
+ // Gateway not reachable: leave a reset request instead, so the next start
217
+ // adopts the secret above. Without this, "rotate while down" is a no-op — the
218
+ // stored hash outlives the rotation and the new password is refused.
219
+ const marker = requestPasswordReset(home);
220
+ if (marker) {
221
+ log(`the stored password will be dropped on the next start (${marker})`);
222
+ }
223
+ else {
224
+ log("restart to apply: oma gateway down && oma gateway up -d");
225
+ }
226
+ return 0;
227
+ }
228
+ /** Marker filename. Owned by the backend
229
+ * (`apps/backend/src/features/auth/password.ts` PASSWORD_RESET_MARKER); oma
230
+ * cannot import a backend module, so the literal is repeated here on purpose —
231
+ * change both together. */
232
+ const PASSWORD_RESET_MARKER = "password-reset";
233
+ /** Ask the backend to drop its stored password by leaving the reset marker in
234
+ * the gateway data dir; the backend consumes it on the next boot and the
235
+ * secret file becomes authoritative again.
236
+ *
237
+ * Deliberately NOT a database write: the backend owns backend.db (see
238
+ * apps/oh-my-agent/AGENTS.md — "backend is the source of truth for product
239
+ * state; the runtime is the runtime"). Writing another process's SQLite file
240
+ * from the CLI would also race a running gateway. Returns the path written, or
241
+ * null when there is no gateway data dir to write to yet. */
242
+ function requestPasswordReset(home) {
243
+ const dataDir = join(gatewayPaths(home).data, "backend");
244
+ if (!existsSync(join(gatewayPaths(home).data)))
245
+ return null;
246
+ mkdirSync(dataDir, { recursive: true });
247
+ const marker = join(dataDir, PASSWORD_RESET_MARKER);
248
+ writeFileSync(marker, `${new Date().toISOString()}\n`);
249
+ return marker;
250
+ }
251
+ /** Update the console-set password (a hash in the backend's settings) when the
252
+ * gateway is reachable. Returns false when it is not: the file value then
253
+ * applies after the next start. */
254
+ async function pushPasswordToRunningGateway(secrets, password) {
255
+ const token = secrets.BACKEND_AUTH_TOKEN;
256
+ if (!token)
257
+ return false;
258
+ try {
259
+ const res = await fetch(`${process.env.BACKEND_URL ?? "http://127.0.0.1:3000"}/api/auth/password`, {
260
+ method: "PUT",
261
+ headers: { "content-type": "application/json", "x-auth-token": token },
262
+ body: JSON.stringify({ password }),
263
+ signal: AbortSignal.timeout(2000),
264
+ });
265
+ return res.ok;
266
+ }
267
+ catch {
268
+ return false;
269
+ }
270
+ }
271
+ /** `oma gateway doctor`: check the deployment and say how to fix what is wrong. */
272
+ export async function runGatewayDoctor(opts = {}) {
273
+ const home = opts.home ?? omaHome();
274
+ const log = loggerFor(opts, "stdout");
275
+ const checks = await diagnoseGateway({ home });
276
+ log(`oma gateway doctor (home: ${home})`);
277
+ for (const check of checks) {
278
+ log(`${check.ok ? "✓" : "✗"} ${check.id.padEnd(9)} ${check.detail}`);
279
+ if (check.fix)
280
+ log(` ${check.ok ? "note" : "fix"}: ${check.fix}`);
281
+ }
282
+ const failed = checks.filter((check) => !check.ok);
283
+ log("");
284
+ log(failed.length === 0
285
+ ? "no problems found"
286
+ : `${failed.length} problem(s): ${failed.map((c) => c.id).join(", ")}`);
287
+ return failed.length === 0 ? 0 : 1;
288
+ }
168
289
  /** `oma gateway down`: stop whatever `up -d` started. */
169
290
  export async function runGatewayDown(opts = {}) {
170
291
  const home = opts.home ?? omaHome();
@@ -206,12 +327,12 @@ async function startGatewayDetached(opts) {
206
327
  try {
207
328
  const res = await fetch(healthUrl, { signal: AbortSignal.timeout(2000) });
208
329
  if (res.ok) {
209
- const password = readSecrets(opts.home).MOCK_PASSWORD;
210
330
  opts.log("");
211
331
  opts.log(`gateway ${opts.version} is up in the background (pid ${daemon.pid})`);
212
332
  opts.log(`open http://127.0.0.1:${web?.port ?? 3001}/login`);
213
- if (password)
214
- opts.log(`login: user-001 / ${password}`);
333
+ for (const line of credentialLines(opts.home, readSecrets(opts.home), process.stdout.isTTY === true)) {
334
+ opts.log(line);
335
+ }
215
336
  opts.log("stop it with: oma gateway down");
216
337
  return 0;
217
338
  }
@@ -238,5 +359,9 @@ export async function runGatewayCommand(verb, opts = {}) {
238
359
  return runGatewayDown(opts);
239
360
  if (verb === "fetch")
240
361
  return runGatewayFetch(opts);
362
+ if (verb === "doctor")
363
+ return runGatewayDoctor(opts);
364
+ if (verb === "passwd")
365
+ return runGatewayPasswd(opts);
241
366
  return runGatewayStatus(opts);
242
367
  }
@@ -28,8 +28,9 @@ 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";
31
+ /** Standalone permission gate. undefined = ungated (legacy default);
32
+ * "yolo" = ungated + OS bash sandbox forced when available. */
33
+ permissionMode?: "ask" | "auto" | "deny" | "yolo";
33
34
  /** --read-only: advertise no write/edit/bash/eval to the model. */
34
35
  readOnly?: boolean;
35
36
  /** Clipboard/pasted images riding this prompt (vision input). */
@@ -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;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"}
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;oEACgE;IAChE,cAAc,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAClD,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"}
@@ -73,6 +73,17 @@ export interface CoordinationRegistry {
73
73
  isDeliveryAcknowledged(id: string): boolean;
74
74
  settleEntry(id: string, patch: Partial<RegistryEntry>): void;
75
75
  setCompletionListener(cb: ((entry: RegistryEntry) => void) | null): void;
76
+ /** Remove THIS callback only. A TUI session installs a listener and must
77
+ * remove it on close without clobbering whichever listener a NEWER
78
+ * session has since installed (single-slot setCompletionListener(null)
79
+ * would). */
80
+ removeCompletionListener(cb: (entry: RegistryEntry) => void): void;
81
+ /** Kill every RUNNING entry that owns a kill callback (bash/eval bg
82
+ * jobs). Run teardown: the table is about to be dropped, so the children
83
+ * must go with it — clearAll() alone frees the bookkeeping and orphans
84
+ * the processes. Subagents are excluded (the delegation executor owns
85
+ * those) and settled entries have nothing to kill. */
86
+ stopRunningEntries(scope?: string): number;
76
87
  notifyEntryCompletion(entry: RegistryEntry): void;
77
88
  /** Drop every entry (Run teardown). */
78
89
  clearAll(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/core/coordination/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/core/coordination/registry.ts"],"names":[],"mappings":"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"}
@@ -130,6 +130,27 @@ export function createCoordinationRegistry() {
130
130
  function setCompletionListener(cb) {
131
131
  completionListener = cb;
132
132
  }
133
+ function removeCompletionListener(cb) {
134
+ if (completionListener === cb)
135
+ completionListener = null;
136
+ }
137
+ function stopRunningEntries(scope) {
138
+ let stopped = 0;
139
+ for (const e of entries.values()) {
140
+ if (e.status !== "running" || e.kind === "subagent" || !e.kill)
141
+ continue;
142
+ if (scope !== undefined && e.scope !== scope)
143
+ continue;
144
+ try {
145
+ e.kill();
146
+ stopped++;
147
+ }
148
+ catch {
149
+ /* a broken kill never blocks the rest of teardown */
150
+ }
151
+ }
152
+ return stopped;
153
+ }
133
154
  function acknowledgeDeliveries(ids) {
134
155
  for (const id of ids)
135
156
  ackedDeliveries.add(id);
@@ -154,6 +175,8 @@ export function createCoordinationRegistry() {
154
175
  isDeliveryAcknowledged,
155
176
  settleEntry,
156
177
  setCompletionListener,
178
+ removeCompletionListener,
179
+ stopRunningEntries,
157
180
  notifyEntryCompletion,
158
181
  clearAll,
159
182
  };
@@ -1,7 +1,6 @@
1
1
  import { type GatewayManifest } from "./manifest.js";
2
2
  export declare class GatewayArtifactError extends Error {
3
3
  }
4
- export declare const DEFAULT_STACK_REPO = "Chengchcc/my-agent-team";
5
4
  export declare function omaHome(env?: NodeJS.ProcessEnv): string;
6
5
  /** The launcher's on-disk layout, in one place: code lives under
7
6
  * gateway/versions/<version>/, state under gateway-data/ so an upgrade that swaps
@@ -29,7 +28,7 @@ export declare function releaseLocation(version: string, env?: NodeJS.ProcessEnv
29
28
  export declare function sha256File(path: string): Promise<string>;
30
29
  /** Parse the SHA256SUMS entry for one file (GNU coreutils format). */
31
30
  export declare function parseSums(sums: string, fileName: string): string;
32
- /** Read the launcher's secrets without generating anything (status paths). */
31
+ export declare function generatePassword(): string;
33
32
  export declare function readSecrets(home: string): Record<string, string>;
34
33
  /** Read the launcher's secrets, generating any missing one. 0600: they
35
34
  * authenticate the local single-user gateway. */
@@ -39,6 +38,8 @@ export interface FetchOptions {
39
38
  version?: string;
40
39
  env?: NodeJS.ProcessEnv;
41
40
  log?: (line: string) => void;
41
+ /** No-byte allowance before a download is declared dead (test seam). */
42
+ stallMs?: number;
42
43
  }
43
44
  export interface FetchResult {
44
45
  version: string;
@@ -1 +1 @@
1
- {"version":3,"file":"artifact.d.ts","sourceRoot":"","sources":["../../../src/core/gateway/artifact.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,eAAe,EAAuB,MAAM,eAAe,CAAC;AAE1E,qBAAa,oBAAqB,SAAQ,KAAK;CAAG;AAElD,eAAO,MAAM,kBAAkB,4BAA4B,CAAC;AAM5D,wBAAgB,OAAO,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAEpE;AAED;;sDAEsD;AACtD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,YAAY,CAAC,IAAI,GAAE,MAAkB,GAAG,YAAY,CAUnE;AAED;qDACqD;AACrD,wBAAgB,UAAU,IAAI,MAAM,CAQnC;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;oFACoF;AACpF,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,eAAe,CAMjB;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI9D;AAED,sEAAsE;AACtE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMhE;AA2CD,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBhE;AAED;kDACkD;AAClD,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAgBjC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;6EAC6E;AAC7E,wBAAsB,oBAAoB,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAuDxF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,MAAkB,GAAG,MAAM,EAAE,CAMpE;AAED,wBAAgB,cAAc,CAAC,IAAI,GAAE,MAAkB,GAAG,MAAM,GAAG,SAAS,CAO3E"}
1
+ {"version":3,"file":"artifact.d.ts","sourceRoot":"","sources":["../../../src/core/gateway/artifact.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,eAAe,EAAuB,MAAM,eAAe,CAAC;AAE1E,qBAAa,oBAAqB,SAAQ,KAAK;CAAG;AAQlD,wBAAgB,OAAO,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAEpE;AAED;;sDAEsD;AACtD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,YAAY,CAAC,IAAI,GAAE,MAAkB,GAAG,YAAY,CAUnE;AAED;qDACqD;AACrD,wBAAgB,UAAU,IAAI,MAAM,CAQnC;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;oFACoF;AACpF,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,eAAe,CAMjB;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI9D;AAED,sEAAsE;AACtE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMhE;AAiFD,wBAAgB,gBAAgB,IAAI,MAAM,CAYzC;AASD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBhE;AAED;kDACkD;AAClD,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAiBjC;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,eAAe,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;6EAC6E;AAC7E,wBAAsB,oBAAoB,CAAC,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,WAAW,CAAC,CAuDxF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,MAAkB,GAAG,MAAM,EAAE,CAMpE;AAED,wBAAgB,cAAc,CAAC,IAAI,GAAE,MAAkB,GAAG,MAAM,GAAG,SAAS,CAO3E"}
@@ -5,7 +5,7 @@ import { join, resolve } from "node:path";
5
5
  import { readGatewayManifest } from "./manifest.js";
6
6
  export class GatewayArtifactError extends Error {
7
7
  }
8
- export const DEFAULT_STACK_REPO = "Chengchcc/my-agent-team";
8
+ const DEFAULT_STACK_REPO = "Chengchcc/my-agent-team";
9
9
  /** Written last, after a version is fully unpacked: its presence is what makes
10
10
  * an install idempotent. */
11
11
  const INSTALL_MARKER = ".complete";
@@ -56,7 +56,24 @@ export function parseSums(sums, fileName) {
56
56
  }
57
57
  throw new GatewayArtifactError(`SHA256SUMS has no entry for ${fileName}`);
58
58
  }
59
- async function download(url, dest) {
59
+ /** How long a download may go without delivering a byte before it is called
60
+ * dead. A slow-but-moving transfer is fine; a wedged one must not hang an
61
+ * install (a postinstall sat for 10 minutes before this existed). */
62
+ const DEFAULT_STALL_MS = 60_000;
63
+ async function withStallTimeout(work, ms, onStall) {
64
+ let timer;
65
+ const stall = new Promise((_, reject) => {
66
+ timer = setTimeout(() => reject(onStall()), ms);
67
+ });
68
+ try {
69
+ return await Promise.race([work, stall]);
70
+ }
71
+ finally {
72
+ if (timer)
73
+ clearTimeout(timer);
74
+ }
75
+ }
76
+ async function download(url, dest, stallMs) {
60
77
  let res;
61
78
  try {
62
79
  res = await fetch(url, { redirect: "follow" });
@@ -73,11 +90,17 @@ async function download(url, dest) {
73
90
  // also keeps a 60MB artifact out of memory.
74
91
  const writer = Bun.file(dest).writer();
75
92
  const reader = res.body.getReader();
76
- for (;;) {
77
- const { done, value } = await reader.read();
78
- if (done)
79
- break;
80
- writer.write(value);
93
+ try {
94
+ for (;;) {
95
+ const { done, value } = await withStallTimeout(reader.read(), stallMs, () => new GatewayArtifactError(`download stalled for ${Math.round(stallMs / 1000)}s at ${url} — check the connection, then retry`));
96
+ if (done)
97
+ break;
98
+ writer.write(value);
99
+ }
100
+ }
101
+ catch (err) {
102
+ await reader.cancel().catch(() => { });
103
+ throw err;
81
104
  }
82
105
  await writer.end();
83
106
  }
@@ -99,6 +122,34 @@ async function unpack(tarball, dest) {
99
122
  }
100
123
  }
101
124
  /** Read the launcher's secrets without generating anything (status paths). */
125
+ /** Human-typed login password. Entropy comes from length, not from requiring
126
+ * character classes: 22 chars over a 56-symbol alphabet is ~128 bits. The
127
+ * alphabet drops look-alikes (l, 1, I, O, 0) and shell-hostile punctuation,
128
+ * because the person typing it may be reading it off a terminal on another
129
+ * device. */
130
+ const PASSWORD_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789";
131
+ const PASSWORD_LENGTH = 22;
132
+ export function generatePassword() {
133
+ // Rejection sampling keeps the alphabet uniform (256 % 56 is not zero).
134
+ const ceiling = Math.floor(256 / PASSWORD_ALPHABET.length) * PASSWORD_ALPHABET.length;
135
+ let password = "";
136
+ while (password.length < PASSWORD_LENGTH) {
137
+ for (const byte of crypto.getRandomValues(new Uint8Array(PASSWORD_LENGTH))) {
138
+ if (byte >= ceiling)
139
+ continue;
140
+ password += PASSWORD_ALPHABET.charAt(byte % PASSWORD_ALPHABET.length);
141
+ if (password.length === PASSWORD_LENGTH)
142
+ break;
143
+ }
144
+ }
145
+ return password;
146
+ }
147
+ /** Internal tokens (backend auth, session signing): never typed, so the cheap
148
+ * hex encoding is fine. */
149
+ function generateToken() {
150
+ const bytes = crypto.getRandomValues(new Uint8Array(24));
151
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
152
+ }
102
153
  export function readSecrets(home) {
103
154
  const path = gatewayPaths(home).secrets;
104
155
  if (!existsSync(path))
@@ -127,8 +178,9 @@ export async function ensureSecrets(home, names) {
127
178
  for (const name of names) {
128
179
  if (existing[name])
129
180
  continue;
130
- const bytes = crypto.getRandomValues(new Uint8Array(24));
131
- existing[name] = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
181
+ // MOCK_PASSWORD is the one a human retypes at the login page; the rest are
182
+ // machine-to-machine tokens.
183
+ existing[name] = name === "MOCK_PASSWORD" ? generatePassword() : generateToken();
132
184
  generated = true;
133
185
  }
134
186
  if (generated) {
@@ -163,7 +215,7 @@ export async function fetchGatewayArtifact(opts = {}) {
163
215
  if (!sums.ok)
164
216
  throw new GatewayArtifactError(`${sumsUrl} -> HTTP ${sums.status}`);
165
217
  const expected = parseSums(await sums.text(), `oma-gateway-${version}.tar.zst`);
166
- await download(tarballUrl, tarball);
218
+ await download(tarballUrl, tarball, opts.stallMs ?? DEFAULT_STALL_MS);
167
219
  const actual = await sha256File(tarball);
168
220
  if (actual !== expected) {
169
221
  throw new GatewayArtifactError(`checksum mismatch for ${version}: expected ${expected.slice(0, 12)}…, got ${actual.slice(0, 12)}…`);
@@ -1 +1 @@
1
- {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../../src/core/gateway/daemon.ts"],"names":[],"mappings":"AAaA;mDACmD;AACnD,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,8EAA8E;AAC9E,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAGrD;AAED,4EAA4E;AAC5E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CASlE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CASnD;AAED;;;gFAGgF;AAChF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAexD;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;6CAE6C;AAC7C,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC,CA6B7F;AAED;uBACuB;AACvB,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CA4B7F;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,EAAE,CAKhE"}
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../../src/core/gateway/daemon.ts"],"names":[],"mappings":"AAaA;mDACmD;AACnD,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,8EAA8E;AAC9E,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAGrD;AAED,4EAA4E;AAC5E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CASlE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CASnD;AAED;;;gFAGgF;AAChF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAexD;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;6CAE6C;AAC7C,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,aAAa,CAAC,CA+B7F;AAED;uBACuB;AACvB,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CA4B7F;AAED,kEAAkE;AAClE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,EAAE,CAKhE"}
@@ -68,7 +68,9 @@ export async function startDetachedGateway(opts) {
68
68
  const gateway = gatewayPaths(opts.home);
69
69
  await mkdir(gateway.root, { recursive: true });
70
70
  const paths = daemonPaths(opts.home);
71
- const logFd = openSync(paths.log, "a");
71
+ // 0600: the log carries the supervisor's own output, and nothing that runs
72
+ // unattended should be world-readable.
73
+ const logFd = openSync(paths.log, "a", 0o600);
72
74
  let pid;
73
75
  try {
74
76
  const proc = Bun.spawn([...opts.command], {
@@ -0,0 +1,21 @@
1
+ /** One diagnosis line: what was checked, what was found, and how to fix it. */
2
+ export interface GatewayCheck {
3
+ id: string;
4
+ ok: boolean;
5
+ detail: string;
6
+ fix?: string;
7
+ }
8
+ export interface DoctorOptions {
9
+ home?: string;
10
+ /** Seam for tests: replaces the `oma --list-models` probe. */
11
+ probeModels?: () => Promise<{
12
+ providers: string[];
13
+ }>;
14
+ /** Seam for tests: replaces the release HEAD probe. Returns the HTTP status,
15
+ * or undefined when the host could not be reached. */
16
+ probeRelease?: (url: string) => Promise<number | undefined>;
17
+ }
18
+ /** Diagnose why a gateway may not be able to run anything: artifact, tools,
19
+ * catalog source, runnable providers, ports, and the per-run oma binary. */
20
+ export declare function diagnoseGateway(opts?: DoctorOptions): Promise<GatewayCheck[]>;
21
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../../src/core/gateway/doctor.ts"],"names":[],"mappings":"AAeA,+EAA+E;AAC/E,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACrD;2DACuD;IACvD,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAC7D;AAoED;6EAC6E;AAC7E,wBAAsB,eAAe,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CA2UvF"}