@mono-agent/agent-app 0.6.2 → 0.9.0

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 (313) hide show
  1. package/README.md +259 -19
  2. package/dist/account-home.d.ts +6 -0
  3. package/dist/account-home.d.ts.map +1 -0
  4. package/dist/account-home.js +9 -0
  5. package/dist/account-home.js.map +1 -0
  6. package/dist/adapter-send-proxy.d.ts +18 -0
  7. package/dist/adapter-send-proxy.d.ts.map +1 -0
  8. package/dist/adapter-send-proxy.js +229 -0
  9. package/dist/adapter-send-proxy.js.map +1 -0
  10. package/dist/adapter-send-tools-main.js +62 -4
  11. package/dist/adapter-send-tools-main.js.map +1 -1
  12. package/dist/adapter-send-tools.d.ts +33 -6
  13. package/dist/adapter-send-tools.d.ts.map +1 -1
  14. package/dist/adapter-send-tools.js +485 -87
  15. package/dist/adapter-send-tools.js.map +1 -1
  16. package/dist/app-config.d.ts +3 -1
  17. package/dist/app-config.d.ts.map +1 -1
  18. package/dist/app-config.js +16 -5
  19. package/dist/app-config.js.map +1 -1
  20. package/dist/app.d.ts +27 -0
  21. package/dist/app.d.ts.map +1 -1
  22. package/dist/app.js +761 -147
  23. package/dist/app.js.map +1 -1
  24. package/dist/background-environment.d.ts +16 -0
  25. package/dist/background-environment.d.ts.map +1 -0
  26. package/dist/background-environment.js +68 -0
  27. package/dist/background-environment.js.map +1 -0
  28. package/dist/background-runtime.d.ts +62 -0
  29. package/dist/background-runtime.d.ts.map +1 -0
  30. package/dist/background-runtime.js +1115 -0
  31. package/dist/background-runtime.js.map +1 -0
  32. package/dist/background-snapshot-key.d.ts +13 -0
  33. package/dist/background-snapshot-key.d.ts.map +1 -0
  34. package/dist/background-snapshot-key.js +194 -0
  35. package/dist/background-snapshot-key.js.map +1 -0
  36. package/dist/background-snapshot.d.ts +96 -0
  37. package/dist/background-snapshot.d.ts.map +1 -0
  38. package/dist/background-snapshot.js +450 -0
  39. package/dist/background-snapshot.js.map +1 -0
  40. package/dist/background-worker-lease.d.ts +39 -0
  41. package/dist/background-worker-lease.d.ts.map +1 -0
  42. package/dist/background-worker-lease.js +356 -0
  43. package/dist/background-worker-lease.js.map +1 -0
  44. package/dist/background.d.ts +74 -2
  45. package/dist/background.d.ts.map +1 -1
  46. package/dist/background.js +815 -73
  47. package/dist/background.js.map +1 -1
  48. package/dist/broadcast-recorder.d.ts.map +1 -1
  49. package/dist/broadcast-recorder.js +24 -2
  50. package/dist/broadcast-recorder.js.map +1 -1
  51. package/dist/channel-plugins.d.ts +2 -0
  52. package/dist/channel-plugins.d.ts.map +1 -1
  53. package/dist/channel-plugins.js +8 -0
  54. package/dist/channel-plugins.js.map +1 -1
  55. package/dist/channels.d.ts +10 -0
  56. package/dist/channels.d.ts.map +1 -1
  57. package/dist/channels.js +87 -9
  58. package/dist/channels.js.map +1 -1
  59. package/dist/cli.d.ts +86 -4
  60. package/dist/cli.d.ts.map +1 -1
  61. package/dist/cli.js +2421 -143
  62. package/dist/cli.js.map +1 -1
  63. package/dist/config-reference.d.ts.map +1 -1
  64. package/dist/config-reference.js +448 -6
  65. package/dist/config-reference.js.map +1 -1
  66. package/dist/configuration-proposal-main.d.ts +3 -0
  67. package/dist/configuration-proposal-main.d.ts.map +1 -0
  68. package/dist/configuration-proposal-main.js +13 -0
  69. package/dist/configuration-proposal-main.js.map +1 -0
  70. package/dist/configuration-proposal-tool.d.ts +33 -0
  71. package/dist/configuration-proposal-tool.d.ts.map +1 -0
  72. package/dist/configuration-proposal-tool.js +188 -0
  73. package/dist/configuration-proposal-tool.js.map +1 -0
  74. package/dist/configured-agent.d.ts +16 -0
  75. package/dist/configured-agent.d.ts.map +1 -1
  76. package/dist/configured-agent.js +165 -18
  77. package/dist/configured-agent.js.map +1 -1
  78. package/dist/consumer-contract.d.ts +3 -0
  79. package/dist/consumer-contract.d.ts.map +1 -1
  80. package/dist/consumer-contract.js +44 -1
  81. package/dist/consumer-contract.js.map +1 -1
  82. package/dist/continuation-command.d.ts +15 -0
  83. package/dist/continuation-command.d.ts.map +1 -0
  84. package/dist/continuation-command.js +170 -0
  85. package/dist/continuation-command.js.map +1 -0
  86. package/dist/continuation-config.d.ts +25 -0
  87. package/dist/continuation-config.d.ts.map +1 -0
  88. package/dist/continuation-config.js +236 -0
  89. package/dist/continuation-config.js.map +1 -0
  90. package/dist/continuation-service.d.ts +99 -0
  91. package/dist/continuation-service.d.ts.map +1 -0
  92. package/dist/continuation-service.js +1313 -0
  93. package/dist/continuation-service.js.map +1 -0
  94. package/dist/continuation-store.d.ts +104 -0
  95. package/dist/continuation-store.d.ts.map +1 -0
  96. package/dist/continuation-store.js +688 -0
  97. package/dist/continuation-store.js.map +1 -0
  98. package/dist/continuations.d.ts +167 -0
  99. package/dist/continuations.d.ts.map +1 -0
  100. package/dist/continuations.js +71 -0
  101. package/dist/continuations.js.map +1 -0
  102. package/dist/doctor.d.ts +29 -5
  103. package/dist/doctor.d.ts.map +1 -1
  104. package/dist/doctor.js +1611 -116
  105. package/dist/doctor.js.map +1 -1
  106. package/dist/first-run-managed-memory.d.ts +39 -0
  107. package/dist/first-run-managed-memory.d.ts.map +1 -0
  108. package/dist/first-run-managed-memory.js +584 -0
  109. package/dist/first-run-managed-memory.js.map +1 -0
  110. package/dist/first-run-readiness.d.ts +111 -0
  111. package/dist/first-run-readiness.d.ts.map +1 -0
  112. package/dist/first-run-readiness.js +728 -0
  113. package/dist/first-run-readiness.js.map +1 -0
  114. package/dist/index.d.ts +17 -3
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js +8 -1
  117. package/dist/index.js.map +1 -1
  118. package/dist/init.d.ts +95 -3
  119. package/dist/init.d.ts.map +1 -1
  120. package/dist/init.js +1218 -24
  121. package/dist/init.js.map +1 -1
  122. package/dist/interaction-bridge.d.ts +25 -1
  123. package/dist/interaction-bridge.d.ts.map +1 -1
  124. package/dist/interaction-bridge.js +281 -19
  125. package/dist/interaction-bridge.js.map +1 -1
  126. package/dist/launchd.d.ts +16 -6
  127. package/dist/launchd.d.ts.map +1 -1
  128. package/dist/launchd.js +30 -15
  129. package/dist/launchd.js.map +1 -1
  130. package/dist/local-configuration.d.ts +99 -0
  131. package/dist/local-configuration.d.ts.map +1 -0
  132. package/dist/local-configuration.js +1299 -0
  133. package/dist/local-configuration.js.map +1 -0
  134. package/dist/managed-runtime-packages.d.ts +9 -0
  135. package/dist/managed-runtime-packages.d.ts.map +1 -0
  136. package/dist/managed-runtime-packages.js +56 -0
  137. package/dist/managed-runtime-packages.js.map +1 -0
  138. package/dist/memory-command.d.ts +4 -0
  139. package/dist/memory-command.d.ts.map +1 -1
  140. package/dist/memory-command.js +751 -27
  141. package/dist/memory-command.js.map +1 -1
  142. package/dist/memory-embedding-service.d.ts +33 -0
  143. package/dist/memory-embedding-service.d.ts.map +1 -0
  144. package/dist/memory-embedding-service.js +207 -0
  145. package/dist/memory-embedding-service.js.map +1 -0
  146. package/dist/memory-recall.d.ts +43 -14
  147. package/dist/memory-recall.d.ts.map +1 -1
  148. package/dist/memory-recall.js +103 -33
  149. package/dist/memory-recall.js.map +1 -1
  150. package/dist/memory-retrieval.d.ts +66 -0
  151. package/dist/memory-retrieval.d.ts.map +1 -0
  152. package/dist/memory-retrieval.js +332 -0
  153. package/dist/memory-retrieval.js.map +1 -0
  154. package/dist/modules/base.d.ts +6 -5
  155. package/dist/modules/base.d.ts.map +1 -1
  156. package/dist/modules/base.js +11 -7
  157. package/dist/modules/base.js.map +1 -1
  158. package/dist/modules/catalog.d.ts.map +1 -1
  159. package/dist/modules/catalog.js +141 -25
  160. package/dist/modules/catalog.js.map +1 -1
  161. package/dist/modules/index.d.ts +2 -2
  162. package/dist/modules/index.d.ts.map +1 -1
  163. package/dist/modules/index.js +1 -1
  164. package/dist/modules/index.js.map +1 -1
  165. package/dist/modules/known-tools.d.ts +3 -0
  166. package/dist/modules/known-tools.d.ts.map +1 -1
  167. package/dist/modules/known-tools.js +11 -1
  168. package/dist/modules/known-tools.js.map +1 -1
  169. package/dist/modules/types.d.ts +20 -6
  170. package/dist/modules/types.d.ts.map +1 -1
  171. package/dist/modules/types.js.map +1 -1
  172. package/dist/notify-runtime.d.ts +26 -0
  173. package/dist/notify-runtime.d.ts.map +1 -0
  174. package/dist/notify-runtime.js +27 -0
  175. package/dist/notify-runtime.js.map +1 -0
  176. package/dist/notify-tool.d.ts +51 -0
  177. package/dist/notify-tool.d.ts.map +1 -0
  178. package/dist/notify-tool.js +182 -0
  179. package/dist/notify-tool.js.map +1 -0
  180. package/dist/package-version.d.ts +3 -0
  181. package/dist/package-version.d.ts.map +1 -0
  182. package/dist/package-version.js +14 -0
  183. package/dist/package-version.js.map +1 -0
  184. package/dist/pi-auth-store-inspection.d.ts +21 -0
  185. package/dist/pi-auth-store-inspection.d.ts.map +1 -0
  186. package/dist/pi-auth-store-inspection.js +120 -0
  187. package/dist/pi-auth-store-inspection.js.map +1 -0
  188. package/dist/pi-oauth-login-main.d.ts +3 -0
  189. package/dist/pi-oauth-login-main.d.ts.map +1 -0
  190. package/dist/pi-oauth-login-main.js +14 -0
  191. package/dist/pi-oauth-login-main.js.map +1 -0
  192. package/dist/pi-oauth-login.d.ts +22 -0
  193. package/dist/pi-oauth-login.d.ts.map +1 -0
  194. package/dist/pi-oauth-login.js +79 -0
  195. package/dist/pi-oauth-login.js.map +1 -0
  196. package/dist/proactive-notify.d.ts +2 -0
  197. package/dist/proactive-notify.d.ts.map +1 -1
  198. package/dist/proactive-notify.js +1 -0
  199. package/dist/proactive-notify.js.map +1 -1
  200. package/dist/process-incarnation.d.ts +23 -0
  201. package/dist/process-incarnation.d.ts.map +1 -0
  202. package/dist/process-incarnation.js +208 -0
  203. package/dist/process-incarnation.js.map +1 -0
  204. package/dist/project-skills.d.ts +40 -0
  205. package/dist/project-skills.d.ts.map +1 -0
  206. package/dist/project-skills.js +573 -0
  207. package/dist/project-skills.js.map +1 -0
  208. package/dist/provider-setup.d.ts +117 -2
  209. package/dist/provider-setup.d.ts.map +1 -1
  210. package/dist/provider-setup.js +1505 -49
  211. package/dist/provider-setup.js.map +1 -1
  212. package/dist/readiness-probe-worker.d.ts +12 -0
  213. package/dist/readiness-probe-worker.d.ts.map +1 -0
  214. package/dist/readiness-probe-worker.js +276 -0
  215. package/dist/readiness-probe-worker.js.map +1 -0
  216. package/dist/readiness-probe.d.ts +100 -0
  217. package/dist/readiness-probe.d.ts.map +1 -0
  218. package/dist/readiness-probe.js +780 -0
  219. package/dist/readiness-probe.js.map +1 -0
  220. package/dist/recipes/base.d.ts +15 -0
  221. package/dist/recipes/base.d.ts.map +1 -0
  222. package/dist/recipes/base.js +51 -0
  223. package/dist/recipes/base.js.map +1 -0
  224. package/dist/recipes/catalog.d.ts +4 -0
  225. package/dist/recipes/catalog.d.ts.map +1 -0
  226. package/dist/recipes/catalog.js +525 -0
  227. package/dist/recipes/catalog.js.map +1 -0
  228. package/dist/recipes/index.d.ts +11 -0
  229. package/dist/recipes/index.d.ts.map +1 -0
  230. package/dist/recipes/index.js +14 -0
  231. package/dist/recipes/index.js.map +1 -0
  232. package/dist/recipes/types.d.ts +70 -0
  233. package/dist/recipes/types.d.ts.map +1 -0
  234. package/dist/recipes/types.js +15 -0
  235. package/dist/recipes/types.js.map +1 -0
  236. package/dist/request-model-override.d.ts +43 -1
  237. package/dist/request-model-override.d.ts.map +1 -1
  238. package/dist/request-model-override.js +178 -19
  239. package/dist/request-model-override.js.map +1 -1
  240. package/dist/run-history.d.ts +32 -0
  241. package/dist/run-history.d.ts.map +1 -0
  242. package/dist/run-history.js +859 -0
  243. package/dist/run-history.js.map +1 -0
  244. package/dist/runs-health.d.ts.map +1 -1
  245. package/dist/runs-health.js +12 -4
  246. package/dist/runs-health.js.map +1 -1
  247. package/dist/runtime-option-extensions.d.ts +14 -0
  248. package/dist/runtime-option-extensions.d.ts.map +1 -0
  249. package/dist/runtime-option-extensions.js +98 -0
  250. package/dist/runtime-option-extensions.js.map +1 -0
  251. package/dist/runtime-routes.d.ts +9 -0
  252. package/dist/runtime-routes.d.ts.map +1 -0
  253. package/dist/runtime-routes.js +13 -0
  254. package/dist/runtime-routes.js.map +1 -0
  255. package/dist/sandbox-manager.d.ts +86 -0
  256. package/dist/sandbox-manager.d.ts.map +1 -0
  257. package/dist/sandbox-manager.js +1402 -0
  258. package/dist/sandbox-manager.js.map +1 -0
  259. package/dist/setup.d.ts +29 -0
  260. package/dist/setup.d.ts.map +1 -0
  261. package/dist/setup.js +97 -0
  262. package/dist/setup.js.map +1 -0
  263. package/dist/supermemory-plugin.d.ts +56 -0
  264. package/dist/supermemory-plugin.d.ts.map +1 -0
  265. package/dist/supermemory-plugin.js +142 -0
  266. package/dist/supermemory-plugin.js.map +1 -0
  267. package/dist/tui-command.d.ts +56 -0
  268. package/dist/tui-command.d.ts.map +1 -1
  269. package/dist/tui-command.js +305 -31
  270. package/dist/tui-command.js.map +1 -1
  271. package/dist/web-command.d.ts +8 -0
  272. package/dist/web-command.d.ts.map +1 -1
  273. package/dist/web-command.js +174 -17
  274. package/dist/web-command.js.map +1 -1
  275. package/dist/wizard/answers.d.ts +31 -4
  276. package/dist/wizard/answers.d.ts.map +1 -1
  277. package/dist/wizard/answers.js +141 -29
  278. package/dist/wizard/answers.js.map +1 -1
  279. package/dist/wizard/from-flags.d.ts +7 -0
  280. package/dist/wizard/from-flags.d.ts.map +1 -1
  281. package/dist/wizard/from-flags.js +36 -2
  282. package/dist/wizard/from-flags.js.map +1 -1
  283. package/dist/wizard/index.d.ts +4 -4
  284. package/dist/wizard/index.d.ts.map +1 -1
  285. package/dist/wizard/index.js +2 -2
  286. package/dist/wizard/index.js.map +1 -1
  287. package/dist/wizard/model-discovery.d.ts +33 -2
  288. package/dist/wizard/model-discovery.d.ts.map +1 -1
  289. package/dist/wizard/model-discovery.js +826 -108
  290. package/dist/wizard/model-discovery.js.map +1 -1
  291. package/dist/wizard/presets.d.ts +1 -1
  292. package/dist/wizard/presets.d.ts.map +1 -1
  293. package/dist/wizard/presets.js +7 -12
  294. package/dist/wizard/presets.js.map +1 -1
  295. package/dist/wizard/prompts.d.ts +56 -9
  296. package/dist/wizard/prompts.d.ts.map +1 -1
  297. package/dist/wizard/prompts.js +172 -20
  298. package/dist/wizard/prompts.js.map +1 -1
  299. package/dist/wizard/run.d.ts +59 -3
  300. package/dist/wizard/run.d.ts.map +1 -1
  301. package/dist/wizard/run.js +1290 -191
  302. package/dist/wizard/run.js.map +1 -1
  303. package/package.json +21 -16
  304. package/resources/srt/package-lock.json +66 -0
  305. package/resources/srt/package.json +9 -0
  306. package/schema/mono-agent.config.schema.json +587 -20
  307. package/skills/mono-agent-composer/SKILL.md +6 -6
  308. package/skills/mono-agent-composer/references/config-blueprint.md +11 -10
  309. package/skills/mono-agent-composer/references/discovery-questions.md +33 -18
  310. package/skills/mono-agent-composer/references/feature-coverage.md +14 -12
  311. package/skills/mono-agent-composer/references/package-map.md +2 -2
  312. package/skills/mono-agent-composer/references/playbooks.md +8 -7
  313. package/skills/mono-agent-composer/references/validation.md +3 -3
@@ -0,0 +1,780 @@
1
+ import { createHash } from "node:crypto";
2
+ import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { Worker } from "node:worker_threads";
6
+ import { loadAppCoreConfig } from "./app-config.js";
7
+ import { validateMonoAgentFolder } from "./doctor.js";
8
+ const CLOUD_READINESS_TIMEOUT_MS = 90_000;
9
+ const LOCAL_READINESS_TIMEOUT_MS = 240_000;
10
+ const MAX_SAFE_MESSAGE_CHARS = 400;
11
+ const WORKER_SHUTDOWN_GRACE_MS = 1_000;
12
+ const LOCAL_PI_PROVIDERS = new Set(["ollama", "lmstudio", "llamacpp"]);
13
+ const SENSITIVE_ENV_NAME = /(api.?key|credential|password|secret|token)/iu;
14
+ const SENSITIVE_FINGERPRINT_KEY = /(api.?key|authorization|cookie|credential|password|secret|token)/iu;
15
+ /** Provider-aware hard deadline for the one-turn primary-model probe. */
16
+ export function readinessProbeTimeoutMs(model) {
17
+ return model.sdk === "pi" && model.provider !== undefined && LOCAL_PI_PROVIDERS.has(model.provider)
18
+ ? LOCAL_READINESS_TIMEOUT_MS
19
+ : CLOUD_READINESS_TIMEOUT_MS;
20
+ }
21
+ /**
22
+ * The probe must not inherit a configured agent from the shell it happens to
23
+ * run in. Provider auth/runtime variables remain available, while every
24
+ * ambient MONO_AGENT_* override is excluded before layered config loading.
25
+ * Selected wizard secrets are an in-memory overlay and are intentionally added
26
+ * afterwards; they are never written to the disposable workspace.
27
+ */
28
+ export function readinessProbeEnvironment(hostEnv, secretValues = {}, options = {}) {
29
+ const sanitized = Object.fromEntries(Object.entries(hostEnv).filter((entry) => !entry[0].startsWith("MONO_AGENT_") && typeof entry[1] === "string"));
30
+ const piAuthPath = options.resolvedPiAuthPath?.trim();
31
+ return {
32
+ ...sanitized,
33
+ ...secretValues,
34
+ ...(piAuthPath === undefined || piAuthPath.length === 0
35
+ ? {}
36
+ : { MONO_AGENT_PI_AUTH_PATH: piAuthPath }),
37
+ };
38
+ }
39
+ function safeMessage(value, secretValues, fallback) {
40
+ let message = typeof value === "string"
41
+ ? value
42
+ : value instanceof Error
43
+ ? value.message
44
+ : value === null || value === undefined
45
+ ? fallback
46
+ : String(value);
47
+ for (const secret of Object.values(secretValues)) {
48
+ if (secret.length >= 4) {
49
+ message = message.replaceAll(secret, "[REDACTED]");
50
+ }
51
+ }
52
+ message = message
53
+ .replace(/\bBearer\s+[^\s,;]+/giu, "Bearer [REDACTED]")
54
+ .replace(/\b(api[ _-]?key|access[ _-]?token|auth[ _-]?token|password|secret)(\s*[=:]\s*)([^\s,;]+)/giu, (_match, label, separator) => `${label}${separator}[REDACTED]`)
55
+ .replace(/\s+/gu, " ")
56
+ .trim();
57
+ if (message.length === 0) {
58
+ return fallback;
59
+ }
60
+ return message.length > MAX_SAFE_MESSAGE_CHARS
61
+ ? `${message.slice(0, MAX_SAFE_MESSAGE_CHARS - 1)}…`
62
+ : message;
63
+ }
64
+ function redactionValues(hostEnv, secretValues) {
65
+ const sensitiveHostValues = Object.fromEntries(Object.entries(hostEnv).filter((entry) => SENSITIVE_ENV_NAME.test(entry[0]) && typeof entry[1] === "string" && entry[1].length > 0));
66
+ return { ...sensitiveHostValues, ...secretValues };
67
+ }
68
+ const DIRECT_TOOL_EVENT_TYPES = new Set([
69
+ "bash",
70
+ "collab_agent_tool_call",
71
+ "command_execution",
72
+ "dynamic_tool_call",
73
+ "file_change",
74
+ "image_generation",
75
+ "image_view",
76
+ "mcp_tool_call",
77
+ "sleep",
78
+ "subagent_activity",
79
+ "tool_call",
80
+ "tool_result",
81
+ "tool_use",
82
+ "web_search",
83
+ ]);
84
+ function normalizedEventType(value) {
85
+ return typeof value === "string"
86
+ ? value.replace(/([a-z0-9])([A-Z])/gu, "$1_$2").replace(/[./-]+/gu, "_").toLowerCase()
87
+ : "";
88
+ }
89
+ function toolActionInEvent(event) {
90
+ const eventType = normalizedEventType(event.type);
91
+ if (DIRECT_TOOL_EVENT_TYPES.has(eventType)) {
92
+ return eventType;
93
+ }
94
+ const item = event.item;
95
+ if (typeof item === "object" && item !== null && !Array.isArray(item)) {
96
+ const itemType = normalizedEventType(item.type);
97
+ if (DIRECT_TOOL_EVENT_TYPES.has(itemType)) {
98
+ return itemType;
99
+ }
100
+ }
101
+ const message = event.message;
102
+ if (typeof message !== "object" || message === null || Array.isArray(message)) {
103
+ return undefined;
104
+ }
105
+ const content = message.content;
106
+ if (!Array.isArray(content)) {
107
+ return undefined;
108
+ }
109
+ for (const block of content) {
110
+ if (typeof block !== "object" || block === null || Array.isArray(block)) {
111
+ continue;
112
+ }
113
+ const blockType = normalizedEventType(block.type);
114
+ if (blockType === "tool_use" || blockType === "tool_call" || blockType === "tool_result") {
115
+ return blockType;
116
+ }
117
+ }
118
+ return undefined;
119
+ }
120
+ function positiveTimeout(value, model) {
121
+ return typeof value === "number" && Number.isFinite(value) && value > 0
122
+ ? Math.trunc(value)
123
+ : readinessProbeTimeoutMs(model);
124
+ }
125
+ function isReadinessWorkerMessage(value) {
126
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
127
+ return false;
128
+ }
129
+ const message = value;
130
+ if (message.type === "disposed") {
131
+ return true;
132
+ }
133
+ if (message.type === "error") {
134
+ return typeof message.message === "string" && message.message.length <= MAX_SAFE_MESSAGE_CHARS;
135
+ }
136
+ if (message.type === "tool") {
137
+ return typeof message.action === "string" && DIRECT_TOOL_EVENT_TYPES.has(message.action);
138
+ }
139
+ return message.type === "result"
140
+ && typeof message.hasText === "boolean"
141
+ && typeof message.cancelled === "boolean"
142
+ && (message.failureKind === undefined
143
+ || (typeof message.failureKind === "string" && message.failureKind.length <= MAX_SAFE_MESSAGE_CHARS))
144
+ && (message.errorMessage === undefined
145
+ || (typeof message.errorMessage === "string" && message.errorMessage.length <= MAX_SAFE_MESSAGE_CHARS));
146
+ }
147
+ function workerResult(message) {
148
+ return {
149
+ text: message.hasText ? "ready" : "",
150
+ ...(message.cancelled ? { cancelled: true } : {}),
151
+ ...(message.failureKind === undefined ? {} : { failureKind: message.failureKind }),
152
+ ...(message.errorMessage === undefined ? {} : { error: message.errorMessage }),
153
+ };
154
+ }
155
+ function startReadinessWorker(input) {
156
+ const model = input.runtime.model;
157
+ const worker = new Worker(input.workerUrl ?? new URL("./readiness-probe-worker.js", import.meta.url), {
158
+ // The parent has already loaded and validated the disposable config. Only
159
+ // this clone-safe, credential-free execution spec crosses workerData.
160
+ workerData: {
161
+ cwd: input.cwd,
162
+ runtime: {
163
+ model: {
164
+ sdk: model.sdk,
165
+ model: model.model,
166
+ ...(model.provider === undefined ? {} : { provider: model.provider }),
167
+ ...(model.reference === undefined ? {} : { reference: model.reference }),
168
+ },
169
+ ...(input.runtime.executionMode === undefined
170
+ ? {}
171
+ : { executionMode: input.runtime.executionMode }),
172
+ ...(input.runtime.effort === undefined ? {} : { effort: input.runtime.effort }),
173
+ workspace: input.runtime.workspace,
174
+ artifactDir: input.runtime.artifactDir,
175
+ ...(input.runtime.piAuthPath === undefined ? {} : { piAuthPath: input.runtime.piAuthPath }),
176
+ },
177
+ },
178
+ env: { ...input.env },
179
+ // Provider SDKs must not be able to leak credentials through inherited
180
+ // worker stdout/stderr. The streams are deliberately drained below.
181
+ stdout: true,
182
+ stderr: true,
183
+ });
184
+ worker.stdout?.resume();
185
+ worker.stderr?.resume();
186
+ let exited = false;
187
+ let outcomeSettled = false;
188
+ let resolveOutcome;
189
+ let resolveStopped;
190
+ const stopped = new Promise((resolve) => {
191
+ resolveStopped = resolve;
192
+ });
193
+ const outcome = new Promise((resolve) => {
194
+ resolveOutcome = resolve;
195
+ });
196
+ const settleOutcome = (next) => {
197
+ if (!outcomeSettled) {
198
+ outcomeSettled = true;
199
+ resolveOutcome?.(next);
200
+ }
201
+ };
202
+ const abort = () => {
203
+ if (exited) {
204
+ return;
205
+ }
206
+ try {
207
+ worker.postMessage({ type: "abort" });
208
+ }
209
+ catch {
210
+ // The worker exited between the state check and postMessage.
211
+ }
212
+ };
213
+ worker.on("message", (value) => {
214
+ if (!isReadinessWorkerMessage(value)) {
215
+ settleOutcome({ type: "error", error: new Error("The isolated readiness worker returned an invalid response.") });
216
+ abort();
217
+ return;
218
+ }
219
+ if (value.type === "disposed") {
220
+ resolveStopped?.();
221
+ return;
222
+ }
223
+ if (value.type === "error") {
224
+ settleOutcome({ type: "error", error: new Error(value.message) });
225
+ return;
226
+ }
227
+ if (value.type === "tool") {
228
+ settleOutcome({ type: "tool", action: value.action });
229
+ abort();
230
+ return;
231
+ }
232
+ settleOutcome({ type: "result", result: workerResult(value) });
233
+ });
234
+ worker.once("error", () => {
235
+ // Deliberately discard the worker error object: a provider SDK may include
236
+ // credential-bearing request details in it.
237
+ settleOutcome({ type: "error", error: new Error("The isolated readiness worker failed.") });
238
+ resolveStopped?.();
239
+ });
240
+ worker.once("exit", () => {
241
+ exited = true;
242
+ settleOutcome({ type: "error", error: new Error("The isolated readiness worker exited before returning a result.") });
243
+ resolveStopped?.();
244
+ });
245
+ return {
246
+ outcome,
247
+ abort,
248
+ async shutdown() {
249
+ abort();
250
+ let timer;
251
+ try {
252
+ await Promise.race([
253
+ stopped,
254
+ new Promise((resolve) => {
255
+ timer = setTimeout(resolve, WORKER_SHUTDOWN_GRACE_MS);
256
+ }),
257
+ ]);
258
+ }
259
+ finally {
260
+ if (timer !== undefined) {
261
+ clearTimeout(timer);
262
+ }
263
+ if (!exited) {
264
+ // disposeAllSessions in the worker is best-effort and bounded. A
265
+ // provider that ignores both abort and disposal cannot keep worker JS
266
+ // alive. Any SDK-spawned orphan still has only the worker's exact env.
267
+ await worker.terminate().catch(() => undefined);
268
+ }
269
+ }
270
+ },
271
+ };
272
+ }
273
+ function selectedReadinessRoutes(plan, options = {}) {
274
+ const runtime = (plan.configJson.runtime ?? {});
275
+ const primary = typeof runtime.model === "string" ? runtime.model : "";
276
+ const inheritedEffort = typeof runtime.effort === "string" ? runtime.effort : undefined;
277
+ const authored = [];
278
+ if (primary.length > 0) {
279
+ authored.push({ model: primary, ...(inheritedEffort === undefined ? {} : { effort: inheritedEffort }) });
280
+ }
281
+ // Canonical fallbacks have independent effort semantics: omission means the
282
+ // provider default, not inheritance from the primary route.
283
+ if (Array.isArray(runtime.fallbacks)) {
284
+ for (const raw of runtime.fallbacks) {
285
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw))
286
+ continue;
287
+ const entry = raw;
288
+ if (typeof entry.model !== "string" || entry.model.length === 0)
289
+ continue;
290
+ authored.push({
291
+ model: entry.model,
292
+ ...(typeof entry.effort === "string" ? { effort: entry.effort } : {}),
293
+ });
294
+ }
295
+ }
296
+ else if (Array.isArray(runtime.fallbackModels)) {
297
+ // Legacy fallbackModels intentionally retain their historical inheritance.
298
+ for (const model of runtime.fallbackModels) {
299
+ if (typeof model !== "string" || model.length === 0)
300
+ continue;
301
+ authored.push({ model, ...(inheritedEffort === undefined ? {} : { effort: inheritedEffort }) });
302
+ }
303
+ }
304
+ const immutableRoutes = authored.map((route, index) => ({ index, model: route.model, effort: route.effort ?? null }));
305
+ const executionRuntime = { ...runtime };
306
+ delete executionRuntime.model;
307
+ delete executionRuntime.effort;
308
+ delete executionRuntime.fallbacks;
309
+ delete executionRuntime.fallbackModels;
310
+ delete executionRuntime.session;
311
+ delete executionRuntime.workspace;
312
+ const nonSecretEnvironment = Object.fromEntries(Object.entries(options.hostEnv ?? process.env)
313
+ .filter((entry) => typeof entry[1] === "string"
314
+ && !SENSITIVE_ENV_NAME.test(entry[0])
315
+ && !entry[0].startsWith("MONO_AGENT_"))
316
+ .sort(([left], [right]) => left.localeCompare(right)));
317
+ const immutable = canonicalFingerprintValue({
318
+ version: 2,
319
+ routes: immutableRoutes,
320
+ runtime: executionRuntime,
321
+ providers: plan.configJson.providers ?? null,
322
+ resolvedPiAuthPath: options.resolvedPiAuthPath ?? null,
323
+ nonSecretEnvironment,
324
+ selectedSecretNames: Object.keys(options.secretValues ?? {}).sort(),
325
+ timeoutMs: options.timeoutMs ?? null,
326
+ });
327
+ const fingerprint = createHash("sha256")
328
+ .update(JSON.stringify(immutable))
329
+ .digest("hex");
330
+ return {
331
+ fingerprint,
332
+ routes: authored.map((route, index) => ({
333
+ index,
334
+ ...route,
335
+ key: createHash("sha256")
336
+ .update(JSON.stringify({ version: 1, index, model: route.model, effort: route.effort ?? null }))
337
+ .digest("hex"),
338
+ })),
339
+ };
340
+ }
341
+ function canonicalFingerprintValue(value, key = "") {
342
+ if (SENSITIVE_FINGERPRINT_KEY.test(key))
343
+ return "[secret-redacted]";
344
+ if (Array.isArray(value))
345
+ return value.map((entry) => canonicalFingerprintValue(entry));
346
+ if (typeof value !== "object" || value === null)
347
+ return value;
348
+ return Object.fromEntries(Object.entries(value)
349
+ .sort(([left], [right]) => left.localeCompare(right))
350
+ .map(([entryKey, entryValue]) => [entryKey, canonicalFingerprintValue(entryValue, entryKey)]));
351
+ }
352
+ function singleRouteWizardPlan(plan, route) {
353
+ const configJson = structuredClone(plan.configJson);
354
+ const runtime = {
355
+ ...(configJson.runtime ?? {}),
356
+ model: route.model,
357
+ };
358
+ delete runtime.fallbacks;
359
+ delete runtime.fallbackModels;
360
+ delete runtime.session;
361
+ if (route.effort === undefined)
362
+ delete runtime.effort;
363
+ else
364
+ runtime.effort = route.effort;
365
+ configJson.runtime = runtime;
366
+ return { ...plan, configJson: configJson };
367
+ }
368
+ /**
369
+ * Make one real, sequential no-tool turn for every selected persistent runtime
370
+ * route. A route is never allowed to invoke its configured fallback chain.
371
+ * Ordinary failures are collected so the operator gets one complete summary;
372
+ * caller cancellation stops the current route and records interruption state.
373
+ */
374
+ export async function runReadinessProbe(options) {
375
+ const selected = selectedReadinessRoutes(options.plan, options);
376
+ if (selected.routes.length <= 1 && options.resume === undefined) {
377
+ return runSingleReadinessProbe(options);
378
+ }
379
+ return runSelectedReadinessRoutes(options, selected);
380
+ }
381
+ /**
382
+ * Always return the ordered route ledger, including for a primary-only plan.
383
+ * Guided setup uses this surface so a successful call can be resumed by its
384
+ * stable key; legacy callers may keep using runReadinessProbe's compact result.
385
+ */
386
+ export async function runAllRouteReadinessProbe(options) {
387
+ return runSelectedReadinessRoutes(options, selectedReadinessRoutes(options.plan, options));
388
+ }
389
+ async function runSelectedReadinessRoutes(options, selected) {
390
+ if (selected.routes.length === 0) {
391
+ return {
392
+ ok: false,
393
+ kind: "invalid_plan",
394
+ message: "The readiness plan does not contain a selected runtime model.",
395
+ planFingerprint: selected.fingerprint,
396
+ routes: [],
397
+ };
398
+ }
399
+ const mayResume = options.resume?.planFingerprint === selected.fingerprint;
400
+ const successful = mayResume
401
+ ? new Set(options.resume?.successfulRouteKeys ?? [])
402
+ : new Set();
403
+ const results = [];
404
+ for (const route of selected.routes) {
405
+ const displayRoute = {
406
+ ...route,
407
+ model: boundedRouteField(route.model, 200),
408
+ ...(route.effort === undefined ? {} : { effort: boundedRouteField(route.effort, 32) }),
409
+ };
410
+ await notifyReadinessProgress(options.onRouteStart, {
411
+ ...displayRoute,
412
+ total: selected.routes.length,
413
+ });
414
+ if (options.abortSignal?.aborted === true) {
415
+ const completed = {
416
+ ...displayRoute,
417
+ status: "interrupted",
418
+ kind: "cancelled",
419
+ message: "The route check was interrupted before it started.",
420
+ };
421
+ results.push(completed);
422
+ await notifyReadinessProgress(options.onRouteComplete, completed);
423
+ return {
424
+ ok: false,
425
+ kind: "cancelled",
426
+ message: `Readiness was interrupted after ${results.filter((entry) => entry.status === "verified" || entry.status === "skipped_verified").length} of ${selected.routes.length} routes were verified.`,
427
+ planFingerprint: selected.fingerprint,
428
+ routes: results,
429
+ interrupted: true,
430
+ };
431
+ }
432
+ if (successful.has(route.key)) {
433
+ const completed = { ...displayRoute, status: "skipped_verified" };
434
+ results.push(completed);
435
+ await notifyReadinessProgress(options.onRouteComplete, completed);
436
+ continue;
437
+ }
438
+ const { resume: _resume, ...singleOptions } = options;
439
+ const result = await runSingleReadinessProbe({
440
+ ...singleOptions,
441
+ plan: singleRouteWizardPlan(options.plan, route),
442
+ });
443
+ if (result.ok) {
444
+ const completed = { ...displayRoute, status: "verified" };
445
+ results.push(completed);
446
+ await notifyReadinessProgress(options.onRouteComplete, completed);
447
+ continue;
448
+ }
449
+ const interrupted = result.kind === "cancelled";
450
+ const completed = {
451
+ ...displayRoute,
452
+ status: interrupted ? "interrupted" : "failed",
453
+ kind: result.kind,
454
+ message: result.message,
455
+ };
456
+ results.push(completed);
457
+ await notifyReadinessProgress(options.onRouteComplete, completed);
458
+ if (interrupted) {
459
+ return {
460
+ ok: false,
461
+ kind: "cancelled",
462
+ message: `Readiness was interrupted while checking route ${route.index + 1} of ${selected.routes.length}.`,
463
+ planFingerprint: selected.fingerprint,
464
+ routes: results,
465
+ interrupted: true,
466
+ };
467
+ }
468
+ }
469
+ const failures = results.filter((entry) => entry.status === "failed");
470
+ if (failures.length > 0) {
471
+ const first = failures[0];
472
+ return {
473
+ ok: false,
474
+ kind: first?.kind ?? "provider_failed",
475
+ message: `${failures.length} of ${selected.routes.length} runtime route checks failed. ${first?.model ?? "Selected route"}: ${first?.message ?? "provider failure"}`,
476
+ planFingerprint: selected.fingerprint,
477
+ routes: results,
478
+ };
479
+ }
480
+ return { ok: true, planFingerprint: selected.fingerprint, routes: results };
481
+ }
482
+ async function notifyReadinessProgress(callback, value) {
483
+ try {
484
+ await callback?.(value);
485
+ }
486
+ catch {
487
+ // Rendering/progress observers never alter readiness semantics.
488
+ }
489
+ }
490
+ function boundedRouteField(value, limit) {
491
+ const normalized = value.replace(/[\u0000-\u001f\u007f]/gu, " ").replace(/\s+/gu, " ").trim();
492
+ return normalized.length <= limit ? normalized : `${normalized.slice(0, Math.max(0, limit - 1))}…`;
493
+ }
494
+ /** Run exactly one route with no fallback chain. */
495
+ async function runSingleReadinessProbe(options) {
496
+ const selectedModel = options.plan.configJson.runtime?.model;
497
+ if (typeof selectedModel === "string" && selectedModel.startsWith("opencode:")) {
498
+ return {
499
+ ok: false,
500
+ kind: "unsupported_guided_probe",
501
+ message: "Direct opencode:* is an advanced config-only backend and cannot run the guided no-tool readiness probe. " +
502
+ "Choose pi:opencode-go:<model>, or use non-interactive --model opencode:<provider>:<model> scaffolding and validate the explicit runtime.permissionMode configuration.",
503
+ };
504
+ }
505
+ const dir = await mkdtemp(join(tmpdir(), "mono-agent-readiness-"));
506
+ const secrets = options.secretValues ?? {};
507
+ const safeValues = redactionValues(options.hostEnv ?? process.env, secrets);
508
+ try {
509
+ const config = structuredClone(options.plan.configJson);
510
+ config.tools = { allowedTools: [], disallowedTools: [] };
511
+ const runtime = config.runtime;
512
+ config.runtime = { ...runtime, workspace: ".mono-agent/workspace" };
513
+ delete config.runtime.fallbackModels;
514
+ delete config.runtime.fallbacks;
515
+ delete config.runtime.session;
516
+ delete config.memory;
517
+ delete config.artifacts;
518
+ delete config.traceability;
519
+ delete config.observability;
520
+ const providers = config.providers;
521
+ if (providers?.piNative !== undefined && typeof providers.piNative === "object" && providers.piNative !== null) {
522
+ const piNative = { ...providers.piNative };
523
+ delete piNative.piSessionsRoot;
524
+ config.providers = { ...providers, piNative };
525
+ }
526
+ delete config.webhook;
527
+ delete config.telegram;
528
+ delete config.slack;
529
+ delete config.openaiApi;
530
+ delete config.cron;
531
+ // The target's context can point to files outside this ephemeral workspace.
532
+ // A probe validates a known-good, self-contained identity instead.
533
+ config.context = { identityPath: "./IDENTITY.md", selectedSkills: [] };
534
+ await writeFile(join(dir, "mono-agent.config.json"), `${JSON.stringify(config, null, 2)}\n`, { mode: 0o600 });
535
+ await writeFile(join(dir, "IDENTITY.md"), "# Readiness probe identity\n\nYou are checking that the selected model can produce one concise response.\n", { mode: 0o600 });
536
+ await mkdir(join(dir, ".mono-agent", "workspace"), { recursive: true });
537
+ await mkdir(join(dir, ".mono-agent", "artifacts"), { recursive: true });
538
+ const overlay = readinessProbeEnvironment(options.hostEnv ?? process.env, secrets, {
539
+ ...(options.resolvedPiAuthPath === undefined ? {} : { resolvedPiAuthPath: options.resolvedPiAuthPath }),
540
+ });
541
+ const loaded = await loadAppCoreConfig({
542
+ cwd: dir,
543
+ configPath: join(dir, "mono-agent.config.json"),
544
+ env: overlay,
545
+ });
546
+ // This checks the generated config plus its IDENTITY.md before contacting a
547
+ // provider. No channel driver is loaded, no liveness probe runs, and writes
548
+ // are disabled; the disposable probe remains side-effect free.
549
+ const validation = await validateMonoAgentFolder({
550
+ cwd: dir,
551
+ configPath: join(dir, "mono-agent.config.json"),
552
+ env: overlay,
553
+ drivers: [],
554
+ liveness: false,
555
+ allowFilesystemWrites: false,
556
+ codexNoToolsProbe: true,
557
+ });
558
+ if (!validation.ok) {
559
+ return {
560
+ ok: false,
561
+ kind: "invalid_plan",
562
+ message: safeMessage(validation.sections.flatMap((section) => section.details).join(" "), safeValues, "The generated primary-model probe configuration is invalid."),
563
+ };
564
+ }
565
+ let firstToolAction;
566
+ const timeoutMs = positiveTimeout(options.timeoutMs, loaded.runtime.model);
567
+ const controller = new AbortController();
568
+ let resolveToolOutcome;
569
+ const toolOutcome = new Promise((resolve) => {
570
+ resolveToolOutcome = resolve;
571
+ });
572
+ let callerAbortListener;
573
+ const callerCancellation = new Promise((resolve) => {
574
+ if (options.abortSignal === undefined) {
575
+ return;
576
+ }
577
+ callerAbortListener = () => {
578
+ // Settle this race branch before aborting the provider. A runtime may
579
+ // synchronously reject on abort; the caller's cancellation must remain
580
+ // the reported reason.
581
+ resolve({ type: "cancelled" });
582
+ controller.abort();
583
+ };
584
+ if (options.abortSignal.aborted) {
585
+ callerAbortListener();
586
+ }
587
+ else {
588
+ options.abortSignal.addEventListener("abort", callerAbortListener, { once: true });
589
+ }
590
+ });
591
+ const runOptions = {
592
+ model: loaded.runtime.model,
593
+ ...(loaded.runtime.executionMode === undefined ? {} : { executionMode: loaded.runtime.executionMode }),
594
+ ...(loaded.runtime.effort === undefined ? {} : { effort: loaded.runtime.effort }),
595
+ messages: [{ role: "user", content: "Reply with a short readiness acknowledgement." }],
596
+ abortSignal: controller.signal,
597
+ cwd: dir,
598
+ maxTurns: 1,
599
+ allowedTools: [],
600
+ disallowedTools: [],
601
+ mcpServers: {},
602
+ // Codex app-server has no general allowlist. This dedicated mode uses a
603
+ // read-only/never-approve payload and fails on the first tool action.
604
+ codexNoToolsProbe: true,
605
+ onEvent: (event) => {
606
+ const action = toolActionInEvent(event);
607
+ if (action !== undefined && firstToolAction === undefined) {
608
+ firstToolAction = action;
609
+ // As with caller cancellation, publish the policy failure before
610
+ // aborting so an abort-triggered provider rejection cannot mask it.
611
+ resolveToolOutcome?.({ type: "tool", action });
612
+ controller.abort();
613
+ }
614
+ },
615
+ sessionKeepAlive: false,
616
+ // The production runtime receives this environment through worker
617
+ // isolation. The explicit immutable copy gives injected runs the same
618
+ // deterministic contract without replacing the host process environment.
619
+ providerEnv: Object.freeze({ ...overlay }),
620
+ };
621
+ let workerHandle;
622
+ let workerAbortListener;
623
+ let providerOutcome;
624
+ if (options.abortSignal?.aborted === true) {
625
+ providerOutcome = new Promise(() => { });
626
+ }
627
+ else if (options.run !== undefined) {
628
+ const injectedRun = options.run;
629
+ const runPromise = Promise.resolve().then(() => injectedRun({ config: loaded, options: runOptions }));
630
+ // The timeout wins independently of provider abort support. Keep an explicit
631
+ // rejection consumer because an ignored abort may settle after we return.
632
+ void runPromise.catch(() => { });
633
+ providerOutcome = runPromise.then((result) => ({ type: "result", result }), (error) => ({ type: "error", error }));
634
+ }
635
+ else {
636
+ try {
637
+ workerHandle = startReadinessWorker({
638
+ cwd: dir,
639
+ runtime: {
640
+ model: loaded.runtime.model,
641
+ ...(loaded.runtime.executionMode === undefined
642
+ ? {}
643
+ : { executionMode: loaded.runtime.executionMode }),
644
+ ...(loaded.runtime.effort === undefined ? {} : { effort: loaded.runtime.effort }),
645
+ workspace: loaded.runtime.workspace,
646
+ artifactDir: loaded.artifacts.dir,
647
+ ...(loaded.providers?.piAuthPath === undefined
648
+ ? {}
649
+ : { piAuthPath: loaded.providers.piAuthPath }),
650
+ },
651
+ env: overlay,
652
+ ...(options.workerUrl === undefined ? {} : { workerUrl: options.workerUrl }),
653
+ });
654
+ workerAbortListener = () => workerHandle?.abort();
655
+ controller.signal.addEventListener("abort", workerAbortListener, { once: true });
656
+ providerOutcome = workerHandle.outcome;
657
+ }
658
+ catch {
659
+ // Worker constructor details are not surfaced: exec arguments or a
660
+ // provider loader may have included sensitive values.
661
+ providerOutcome = Promise.resolve({
662
+ type: "error",
663
+ error: new Error("The isolated readiness worker could not be started."),
664
+ });
665
+ }
666
+ }
667
+ let timer;
668
+ const timeout = new Promise((resolve) => {
669
+ timer = setTimeout(() => {
670
+ resolve({ type: "timeout" });
671
+ controller.abort();
672
+ }, timeoutMs);
673
+ });
674
+ let outcome;
675
+ try {
676
+ outcome = await Promise.race([
677
+ providerOutcome,
678
+ timeout,
679
+ callerCancellation,
680
+ toolOutcome,
681
+ ]);
682
+ }
683
+ finally {
684
+ if (timer !== undefined) {
685
+ clearTimeout(timer);
686
+ }
687
+ if (callerAbortListener !== undefined) {
688
+ options.abortSignal?.removeEventListener("abort", callerAbortListener);
689
+ }
690
+ if (workerAbortListener !== undefined) {
691
+ controller.signal.removeEventListener("abort", workerAbortListener);
692
+ }
693
+ if (workerHandle !== undefined) {
694
+ await workerHandle.shutdown();
695
+ }
696
+ else {
697
+ await options.dispose?.();
698
+ }
699
+ }
700
+ if (outcome.type === "cancelled") {
701
+ return {
702
+ ok: false,
703
+ kind: "cancelled",
704
+ message: "The primary-model check was cancelled before completion.",
705
+ };
706
+ }
707
+ if (outcome.type === "tool") {
708
+ return {
709
+ ok: false,
710
+ kind: "tool_used",
711
+ message: `The selected model attempted a tool action (${outcome.action}) during the no-tool primary-model check.`,
712
+ };
713
+ }
714
+ if (outcome.type === "timeout") {
715
+ return {
716
+ ok: false,
717
+ kind: "timeout",
718
+ message: `The selected model did not finish the primary-model check within ${Math.ceil(timeoutMs / 1_000)} seconds.`,
719
+ };
720
+ }
721
+ if (outcome.type === "error") {
722
+ return {
723
+ ok: false,
724
+ kind: "probe_failed",
725
+ message: safeMessage(outcome.error, safeValues, "The primary-model check failed unexpectedly."),
726
+ };
727
+ }
728
+ const result = outcome.result;
729
+ for (const event of result.events ?? []) {
730
+ firstToolAction ??= toolActionInEvent(event);
731
+ }
732
+ if (firstToolAction !== undefined || result.failureKind === "tool_policy_violation") {
733
+ return {
734
+ ok: false,
735
+ kind: "tool_used",
736
+ message: `The selected model attempted a tool action (${firstToolAction ?? "provider tool"}) during the no-tool primary-model check.`,
737
+ };
738
+ }
739
+ if (result.cancelled === true) {
740
+ return {
741
+ ok: false,
742
+ kind: "cancelled",
743
+ message: "The selected model cancelled before completing the primary-model check.",
744
+ };
745
+ }
746
+ if (result.failureKind !== undefined && result.failureKind !== null) {
747
+ return {
748
+ ok: false,
749
+ kind: "provider_failed",
750
+ message: safeMessage(result.error, safeValues, `The selected model reported ${safeMessage(result.failureKind, safeValues, "a provider failure")}.`),
751
+ };
752
+ }
753
+ if (result.error !== undefined && result.error !== null) {
754
+ return {
755
+ ok: false,
756
+ kind: "provider_failed",
757
+ message: safeMessage(result.error, safeValues, "The selected model reported an error."),
758
+ };
759
+ }
760
+ if ((result.text ?? "").trim().length === 0) {
761
+ return {
762
+ ok: false,
763
+ kind: "empty_response",
764
+ message: "The selected model returned an empty primary-model response.",
765
+ };
766
+ }
767
+ return { ok: true };
768
+ }
769
+ catch (error) {
770
+ return {
771
+ ok: false,
772
+ kind: "probe_failed",
773
+ message: safeMessage(error, safeValues, "The primary-model check failed unexpectedly."),
774
+ };
775
+ }
776
+ finally {
777
+ await rm(dir, { recursive: true, force: true });
778
+ }
779
+ }
780
+ //# sourceMappingURL=readiness-probe.js.map