@intentic/sandbox-contract 1.316.0 → 1.318.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 (362) hide show
  1. package/README.md +12 -4
  2. package/dist/chores/chores.js +1 -1
  3. package/dist/chores/chores.js.map +1 -1
  4. package/dist/chores/probes.js +1 -1
  5. package/dist/chores/probes.js.map +1 -1
  6. package/dist/contracts/accounts.contract.d.ts +75 -0
  7. package/dist/contracts/accounts.contract.d.ts.map +1 -1
  8. package/dist/contracts/accounts.contract.js +10 -1
  9. package/dist/contracts/accounts.contract.js.map +1 -1
  10. package/dist/contracts/agent.contract.d.ts +616 -1
  11. package/dist/contracts/agent.contract.d.ts.map +1 -1
  12. package/dist/contracts/agents.contract.d.ts +1134 -29
  13. package/dist/contracts/agents.contract.d.ts.map +1 -1
  14. package/dist/contracts/agents.contract.js +12 -12
  15. package/dist/contracts/agents.contract.js.map +1 -1
  16. package/dist/contracts/capabilities.contract.d.ts +16 -0
  17. package/dist/contracts/capabilities.contract.d.ts.map +1 -1
  18. package/dist/contracts/capabilities.contract.js +10 -1
  19. package/dist/contracts/capabilities.contract.js.map +1 -1
  20. package/dist/contracts/ci.contract.d.ts +22 -4
  21. package/dist/contracts/ci.contract.d.ts.map +1 -1
  22. package/dist/contracts/device.contract.d.ts +39 -0
  23. package/dist/contracts/device.contract.d.ts.map +1 -1
  24. package/dist/contracts/device.contract.js +2 -0
  25. package/dist/contracts/device.contract.js.map +1 -1
  26. package/dist/contracts/endpoints.contract.d.ts +23 -0
  27. package/dist/contracts/endpoints.contract.d.ts.map +1 -1
  28. package/dist/contracts/endpoints.contract.js +6 -1
  29. package/dist/contracts/endpoints.contract.js.map +1 -1
  30. package/dist/contracts/extensions.contract.d.ts +12 -0
  31. package/dist/contracts/extensions.contract.d.ts.map +1 -1
  32. package/dist/contracts/needs.contract.d.ts +534 -0
  33. package/dist/contracts/needs.contract.d.ts.map +1 -0
  34. package/dist/contracts/needs.contract.js +80 -0
  35. package/dist/contracts/needs.contract.js.map +1 -0
  36. package/dist/contracts/providers.contract.d.ts +4 -0
  37. package/dist/contracts/providers.contract.d.ts.map +1 -1
  38. package/dist/contracts/runner.contract.d.ts +193 -2
  39. package/dist/contracts/runner.contract.d.ts.map +1 -1
  40. package/dist/contracts/secrets.contract.d.ts +53 -0
  41. package/dist/contracts/secrets.contract.d.ts.map +1 -1
  42. package/dist/contracts/secrets.contract.js +31 -2
  43. package/dist/contracts/secrets.contract.js.map +1 -1
  44. package/dist/contracts/sessions.contract.d.ts +83 -0
  45. package/dist/contracts/sessions.contract.d.ts.map +1 -1
  46. package/dist/contracts/settings.contract.d.ts +33 -2
  47. package/dist/contracts/settings.contract.d.ts.map +1 -1
  48. package/dist/contracts/settings.contract.js +20 -1
  49. package/dist/contracts/settings.contract.js.map +1 -1
  50. package/dist/contracts/system.contract.d.ts +177 -356
  51. package/dist/contracts/system.contract.d.ts.map +1 -1
  52. package/dist/contracts/system.contract.js +13 -12
  53. package/dist/contracts/system.contract.js.map +1 -1
  54. package/dist/contracts/translator.contract.d.ts +7 -0
  55. package/dist/contracts/translator.contract.d.ts.map +1 -1
  56. package/dist/contracts/translator.contract.js.map +1 -1
  57. package/dist/contracts/webext.contract.d.ts +38 -0
  58. package/dist/contracts/webext.contract.d.ts.map +1 -1
  59. package/dist/contracts/webext.contract.js +3 -0
  60. package/dist/contracts/webext.contract.js.map +1 -1
  61. package/dist/contracts/workspace.contract.d.ts +1 -80
  62. package/dist/contracts/workspace.contract.d.ts.map +1 -1
  63. package/dist/contracts/workspace.contract.js +0 -27
  64. package/dist/contracts/workspace.contract.js.map +1 -1
  65. package/dist/events/agent-events.d.ts +330 -0
  66. package/dist/events/agent-events.d.ts.map +1 -1
  67. package/dist/events/agent-events.js +13 -0
  68. package/dist/events/agent-events.js.map +1 -1
  69. package/dist/events/agent-words.d.ts +1 -0
  70. package/dist/events/agent-words.d.ts.map +1 -1
  71. package/dist/events/agent-words.js +3 -2
  72. package/dist/events/agent-words.js.map +1 -1
  73. package/dist/events/land-breakage.d.ts.map +1 -1
  74. package/dist/events/land-breakage.js.map +1 -1
  75. package/dist/events/need-wake.d.ts +17 -0
  76. package/dist/events/need-wake.d.ts.map +1 -0
  77. package/dist/events/need-wake.js +34 -0
  78. package/dist/events/need-wake.js.map +1 -0
  79. package/dist/events/resume.d.ts +6 -1
  80. package/dist/events/resume.d.ts.map +1 -1
  81. package/dist/events/resume.js +17 -10
  82. package/dist/events/resume.js.map +1 -1
  83. package/dist/events/sandbox-notice.d.ts +183 -0
  84. package/dist/events/sandbox-notice.d.ts.map +1 -0
  85. package/dist/events/sandbox-notice.js +56 -0
  86. package/dist/events/sandbox-notice.js.map +1 -0
  87. package/dist/events/system-events.d.ts +84 -0
  88. package/dist/events/system-events.d.ts.map +1 -1
  89. package/dist/events/system-events.js +2 -0
  90. package/dist/events/system-events.js.map +1 -1
  91. package/dist/events/transcript.d.ts +508 -0
  92. package/dist/events/transcript.d.ts.map +1 -1
  93. package/dist/events/transcript.js +12 -1
  94. package/dist/events/transcript.js.map +1 -1
  95. package/dist/ids/conversation-ids.d.ts +1 -3
  96. package/dist/ids/conversation-ids.d.ts.map +1 -1
  97. package/dist/ids/conversation-ids.js +1 -3
  98. package/dist/ids/conversation-ids.js.map +1 -1
  99. package/dist/ids/project-dir.d.ts +6 -0
  100. package/dist/ids/project-dir.d.ts.map +1 -0
  101. package/dist/ids/project-dir.js +43 -0
  102. package/dist/ids/project-dir.js.map +1 -0
  103. package/dist/index.d.ts +3474 -1163
  104. package/dist/index.d.ts.map +1 -1
  105. package/dist/index.js +13 -4
  106. package/dist/index.js.map +1 -1
  107. package/dist/models/agent-runtimes.d.ts.map +1 -1
  108. package/dist/models/agent-runtimes.js +2 -2
  109. package/dist/models/agent-runtimes.js.map +1 -1
  110. package/dist/models/model-roles.d.ts +1 -9
  111. package/dist/models/model-roles.d.ts.map +1 -1
  112. package/dist/models/model-roles.js +1 -9
  113. package/dist/models/model-roles.js.map +1 -1
  114. package/dist/policy/command-classes.d.ts.map +1 -1
  115. package/dist/policy/command-classes.js +52 -3
  116. package/dist/policy/command-classes.js.map +1 -1
  117. package/dist/policy/safety-policy.d.ts +7 -1
  118. package/dist/policy/safety-policy.d.ts.map +1 -1
  119. package/dist/policy/safety-policy.js +2 -0
  120. package/dist/policy/safety-policy.js.map +1 -1
  121. package/dist/policy/secret-hosts.d.ts +13 -0
  122. package/dist/policy/secret-hosts.d.ts.map +1 -0
  123. package/dist/policy/secret-hosts.js +41 -0
  124. package/dist/policy/secret-hosts.js.map +1 -0
  125. package/dist/policy/turned-away.d.ts.map +1 -1
  126. package/dist/policy/turned-away.js +1 -0
  127. package/dist/policy/turned-away.js.map +1 -1
  128. package/dist/protocol/raw-routes.d.ts +7 -5
  129. package/dist/protocol/raw-routes.d.ts.map +1 -1
  130. package/dist/protocol/raw-routes.js +4 -1
  131. package/dist/protocol/raw-routes.js.map +1 -1
  132. package/dist/protocol/routes.d.ts +2 -6
  133. package/dist/protocol/routes.d.ts.map +1 -1
  134. package/dist/protocol/routes.js +2 -3
  135. package/dist/protocol/routes.js.map +1 -1
  136. package/dist/protocol/stream-of.d.ts +6 -0
  137. package/dist/protocol/stream-of.d.ts.map +1 -0
  138. package/dist/protocol/stream-of.js +4 -0
  139. package/dist/protocol/stream-of.js.map +1 -0
  140. package/dist/schemas/activity.js +1 -1
  141. package/dist/schemas/activity.js.map +1 -1
  142. package/dist/schemas/agent.d.ts +19 -2
  143. package/dist/schemas/agent.d.ts.map +1 -1
  144. package/dist/schemas/agent.js +2 -1
  145. package/dist/schemas/agent.js.map +1 -1
  146. package/dist/schemas/agents.d.ts +119 -0
  147. package/dist/schemas/agents.d.ts.map +1 -1
  148. package/dist/schemas/agents.js +45 -0
  149. package/dist/schemas/agents.js.map +1 -1
  150. package/dist/schemas/automations.d.ts +37 -0
  151. package/dist/schemas/automations.d.ts.map +1 -1
  152. package/dist/schemas/capabilities.d.ts +21 -0
  153. package/dist/schemas/capabilities.d.ts.map +1 -1
  154. package/dist/schemas/capabilities.js +50 -4
  155. package/dist/schemas/capabilities.js.map +1 -1
  156. package/dist/schemas/ci.d.ts +69 -9
  157. package/dist/schemas/ci.d.ts.map +1 -1
  158. package/dist/schemas/ci.js +29 -8
  159. package/dist/schemas/ci.js.map +1 -1
  160. package/dist/schemas/context-trim.d.ts +5 -1
  161. package/dist/schemas/context-trim.d.ts.map +1 -1
  162. package/dist/schemas/context-trim.js +8 -4
  163. package/dist/schemas/context-trim.js.map +1 -1
  164. package/dist/schemas/devices.d.ts +91 -0
  165. package/dist/schemas/devices.d.ts.map +1 -1
  166. package/dist/schemas/devices.js +23 -1
  167. package/dist/schemas/devices.js.map +1 -1
  168. package/dist/schemas/environment.d.ts +48 -0
  169. package/dist/schemas/environment.d.ts.map +1 -1
  170. package/dist/schemas/environment.js +15 -0
  171. package/dist/schemas/environment.js.map +1 -1
  172. package/dist/schemas/extension-updates.d.ts +24 -0
  173. package/dist/schemas/extension-updates.d.ts.map +1 -1
  174. package/dist/schemas/git/git.d.ts +13 -0
  175. package/dist/schemas/git/git.d.ts.map +1 -1
  176. package/dist/schemas/git/git.js +11 -1
  177. package/dist/schemas/git/git.js.map +1 -1
  178. package/dist/schemas/hosts.d.ts +4 -0
  179. package/dist/schemas/hosts.d.ts.map +1 -1
  180. package/dist/schemas/hosts.js +3 -1
  181. package/dist/schemas/hosts.js.map +1 -1
  182. package/dist/schemas/keep-warm.d.ts +4 -0
  183. package/dist/schemas/keep-warm.d.ts.map +1 -1
  184. package/dist/schemas/keep-warm.js +15 -5
  185. package/dist/schemas/keep-warm.js.map +1 -1
  186. package/dist/schemas/loopback-catch.d.ts +33 -0
  187. package/dist/schemas/loopback-catch.d.ts.map +1 -0
  188. package/dist/schemas/loopback-catch.js +20 -0
  189. package/dist/schemas/loopback-catch.js.map +1 -0
  190. package/dist/schemas/maintenance.js +1 -1
  191. package/dist/schemas/maintenance.js.map +1 -1
  192. package/dist/schemas/needs.d.ts +664 -0
  193. package/dist/schemas/needs.d.ts.map +1 -0
  194. package/dist/schemas/needs.js +203 -0
  195. package/dist/schemas/needs.js.map +1 -0
  196. package/dist/schemas/personas.d.ts.map +1 -1
  197. package/dist/schemas/personas.js +6 -3
  198. package/dist/schemas/personas.js.map +1 -1
  199. package/dist/schemas/providers/provider-oauth.d.ts +87 -0
  200. package/dist/schemas/providers/provider-oauth.d.ts.map +1 -1
  201. package/dist/schemas/providers/provider-oauth.js +20 -0
  202. package/dist/schemas/providers/provider-oauth.js.map +1 -1
  203. package/dist/schemas/secrets.d.ts +84 -0
  204. package/dist/schemas/secrets.d.ts.map +1 -1
  205. package/dist/schemas/secrets.js +70 -0
  206. package/dist/schemas/secrets.js.map +1 -1
  207. package/dist/schemas/settings-history.d.ts +1 -1
  208. package/dist/schemas/settings-history.d.ts.map +1 -1
  209. package/dist/schemas/settings-history.js +1 -0
  210. package/dist/schemas/settings-history.js.map +1 -1
  211. package/dist/schemas/settings.d.ts +44 -2
  212. package/dist/schemas/settings.d.ts.map +1 -1
  213. package/dist/schemas/settings.js +30 -4
  214. package/dist/schemas/settings.js.map +1 -1
  215. package/dist/schemas/state-plan.d.ts +1 -0
  216. package/dist/schemas/state-plan.d.ts.map +1 -1
  217. package/dist/schemas/state-plan.js +3 -1
  218. package/dist/schemas/state-plan.js.map +1 -1
  219. package/dist/schemas/system.d.ts +20 -0
  220. package/dist/schemas/system.d.ts.map +1 -1
  221. package/dist/schemas/system.js +7 -0
  222. package/dist/schemas/system.js.map +1 -1
  223. package/dist/schemas/terminal.d.ts +2 -3
  224. package/dist/schemas/terminal.d.ts.map +1 -1
  225. package/dist/schemas/terminal.js +12 -4
  226. package/dist/schemas/terminal.js.map +1 -1
  227. package/dist/schemas/updates.d.ts +39 -0
  228. package/dist/schemas/updates.d.ts.map +1 -0
  229. package/dist/schemas/updates.js +31 -0
  230. package/dist/schemas/updates.js.map +1 -0
  231. package/dist/schemas/webext.d.ts +3 -0
  232. package/dist/schemas/webext.d.ts.map +1 -1
  233. package/dist/schemas/webext.js +1 -0
  234. package/dist/schemas/webext.js.map +1 -1
  235. package/dist/schemas/workflows.js +3 -3
  236. package/dist/schemas/workflows.js.map +1 -1
  237. package/dist/schemas/workspace/workspace-tree.d.ts +2 -0
  238. package/dist/schemas/workspace/workspace-tree.d.ts.map +1 -1
  239. package/dist/schemas/workspace/workspace-tree.js +4 -0
  240. package/dist/schemas/workspace/workspace-tree.js.map +1 -1
  241. package/dist/state/definition.d.ts +28 -4
  242. package/dist/state/definition.d.ts.map +1 -1
  243. package/dist/state/history-state.d.ts.map +1 -1
  244. package/dist/state/history-state.js +10 -0
  245. package/dist/state/history-state.js.map +1 -1
  246. package/dist/state/runtime-state.d.ts +0 -3
  247. package/dist/state/runtime-state.d.ts.map +1 -1
  248. package/dist/state/runtime-state.js +0 -1
  249. package/dist/state/runtime-state.js.map +1 -1
  250. package/dist/state/workspace-state.d.ts +4 -5
  251. package/dist/state/workspace-state.d.ts.map +1 -1
  252. package/dist/state/workspace-state.js +1 -6
  253. package/dist/state/workspace-state.js.map +1 -1
  254. package/dist/text/documents.d.ts +3 -0
  255. package/dist/text/documents.d.ts.map +1 -1
  256. package/dist/text/documents.js +14 -0
  257. package/dist/text/documents.js.map +1 -1
  258. package/dist/text/transcript-fold.d.ts +4 -3
  259. package/dist/text/transcript-fold.d.ts.map +1 -1
  260. package/dist/text/transcript-fold.js +140 -31
  261. package/dist/text/transcript-fold.js.map +1 -1
  262. package/dist/webext/index.d.ts +1 -0
  263. package/dist/webext/index.d.ts.map +1 -1
  264. package/dist/webext/index.js +1 -0
  265. package/dist/webext/index.js.map +1 -1
  266. package/package.json +5 -5
  267. package/src/chores/chores.ts +2 -2
  268. package/src/chores/probes.ts +1 -1
  269. package/src/contracts/accounts.contract.ts +12 -0
  270. package/src/contracts/agents.contract.ts +13 -13
  271. package/src/contracts/capabilities.contract.ts +14 -1
  272. package/src/contracts/device.contract.ts +5 -0
  273. package/src/contracts/endpoints.contract.ts +20 -4
  274. package/src/contracts/needs.contract.ts +103 -0
  275. package/src/contracts/secrets.contract.ts +45 -3
  276. package/src/contracts/settings.contract.ts +29 -0
  277. package/src/contracts/system.contract.ts +19 -14
  278. package/src/contracts/translator.contract.ts +2 -1
  279. package/src/contracts/webext.contract.ts +7 -1
  280. package/src/contracts/workspace.contract.ts +0 -37
  281. package/src/events/agent-events.ts +22 -1
  282. package/src/events/agent-words.ts +6 -2
  283. package/src/events/land-breakage.ts +3 -4
  284. package/src/events/need-wake.test.ts +55 -0
  285. package/src/events/need-wake.ts +71 -0
  286. package/src/events/resume.test.ts +13 -2
  287. package/src/events/resume.ts +25 -12
  288. package/src/events/sandbox-notice.ts +92 -0
  289. package/src/events/system-events.ts +7 -0
  290. package/src/events/transcript.ts +23 -1
  291. package/src/events/verify-nudge.ts +3 -3
  292. package/src/ids/conversation-ids.test.ts +2 -26
  293. package/src/ids/conversation-ids.ts +6 -12
  294. package/src/ids/project-dir.fixture.json +65 -0
  295. package/src/ids/project-dir.test.ts +60 -0
  296. package/src/ids/project-dir.ts +70 -0
  297. package/src/index.ts +18 -4
  298. package/src/models/agent-catalog.test.ts +7 -1
  299. package/src/models/agent-runtimes.ts +7 -5
  300. package/src/models/model-roles.ts +1 -9
  301. package/src/policy/command-classes.test.ts +39 -0
  302. package/src/policy/command-classes.ts +70 -3
  303. package/src/policy/safety-policy.ts +10 -0
  304. package/src/policy/secret-hosts.test.ts +89 -0
  305. package/src/policy/secret-hosts.ts +73 -0
  306. package/src/policy/turned-away.ts +1 -0
  307. package/src/protocol/raw-routes.ts +6 -3
  308. package/src/protocol/routes.test.ts +6 -6
  309. package/src/protocol/routes.ts +2 -9
  310. package/src/protocol/stream-of.ts +13 -0
  311. package/src/schemas/activity.ts +1 -1
  312. package/src/schemas/agent.ts +4 -1
  313. package/src/schemas/agents.ts +72 -5
  314. package/src/schemas/automations.ts +2 -2
  315. package/src/schemas/capabilities.ts +72 -7
  316. package/src/schemas/ci.ts +56 -11
  317. package/src/schemas/context-trim.ts +11 -6
  318. package/src/schemas/devices.ts +55 -2
  319. package/src/schemas/environment.ts +39 -0
  320. package/src/schemas/git/git.ts +20 -2
  321. package/src/schemas/hosts.ts +7 -1
  322. package/src/schemas/keep-warm.ts +19 -6
  323. package/src/schemas/loopback-catch.ts +45 -0
  324. package/src/schemas/maintenance.ts +1 -1
  325. package/src/schemas/needs.ts +301 -0
  326. package/src/schemas/personas.ts +8 -3
  327. package/src/schemas/providers/provider-oauth.ts +35 -0
  328. package/src/schemas/secrets.ts +93 -0
  329. package/src/schemas/settings-history.ts +2 -0
  330. package/src/schemas/settings.test.ts +19 -1
  331. package/src/schemas/settings.ts +66 -9
  332. package/src/schemas/speaker.ts +5 -5
  333. package/src/schemas/state-plan.ts +8 -1
  334. package/src/schemas/system.ts +15 -0
  335. package/src/schemas/terminal.ts +19 -6
  336. package/src/schemas/updates.ts +56 -0
  337. package/src/schemas/webext.ts +3 -0
  338. package/src/schemas/workflows.ts +5 -5
  339. package/src/schemas/workspace/workspace-tree.ts +7 -0
  340. package/src/state/fix-attempt-plan.test.ts +1 -1
  341. package/src/state/fix-stance.ts +1 -1
  342. package/src/state/history-state.ts +19 -0
  343. package/src/state/runtime-state.ts +0 -3
  344. package/src/state/workspace-state.ts +4 -6
  345. package/src/text/documents.test.ts +25 -1
  346. package/src/text/documents.ts +24 -0
  347. package/src/text/title.ts +1 -1
  348. package/src/text/transcript-fold.test.ts +218 -25
  349. package/src/text/transcript-fold.ts +170 -45
  350. package/src/webext/index.ts +1 -0
  351. package/dist/schemas/workspace/push-checks.d.ts +0 -222
  352. package/dist/schemas/workspace/push-checks.d.ts.map +0 -1
  353. package/dist/schemas/workspace/push-checks.js +0 -97
  354. package/dist/schemas/workspace/push-checks.js.map +0 -1
  355. package/dist/state/red-streak.d.ts +0 -7
  356. package/dist/state/red-streak.d.ts.map +0 -1
  357. package/dist/state/red-streak.js +0 -11
  358. package/dist/state/red-streak.js.map +0 -1
  359. package/src/schemas/workspace/push-checks.test.ts +0 -28
  360. package/src/schemas/workspace/push-checks.ts +0 -155
  361. package/src/state/red-streak.test.ts +0 -28
  362. package/src/state/red-streak.ts +0 -28
@@ -1,5 +1,6 @@
1
1
  // context-trim: what a window too small for a full turn made the sandbox leave out
2
2
  import { z } from "zod";
3
+ import type { SandboxNotice } from "../events/sandbox-notice.js";
3
4
 
4
5
  // The only disclosure of a note that never rode; without it a turn runs thinner and nothing on screen says why.
5
6
  export const ContextTrimSchema = z.object({
@@ -18,12 +19,16 @@ export type ContextTrim = z.infer<typeof ContextTrimSchema>;
18
19
  // 16k, 32k; a server's own odd number spelled out in full.
19
20
  const windowLabel = (tokens: number): string => (tokens % 1024 === 0 ? `${tokens / 1024}k` : tokens.toLocaleString("en-US"));
20
21
 
22
+ /** The trim's notice by code and facts, for a reader that words it in its own language. */
23
+ export const contextTrimNotice = ({ window, omitted, base }: ContextTrim): Extract<SandboxNotice, { code: "contextTrim" }> => ({
24
+ code: "contextTrim",
25
+ params: { window: windowLabel(window), ...(omitted.length === 0 ? {} : { omitted: omitted.join(`, `) }), base },
26
+ });
27
+
21
28
  // The closing clause is load-bearing: without it the row reads as "my AGENTS.md may not have arrived".
22
- export const contextTrimLine = ({ window, omitted, base }: ContextTrim): string => {
29
+ export const contextTrimLine = (trim: ContextTrim): string => {
30
+ const { window, omitted, base } = contextTrimNotice(trim).params;
23
31
  const swapped = base ? ` The agent's own base instructions were swapped for a short paragraph, too.` : ``;
24
- const left = omitted.length === 0 ? `` : ` — left out: ${omitted.join(`, `)}`;
25
- return (
26
- `Sent thin for this model's ${windowLabel(window)} window${left}.${swapped}` +
27
- ` Your workspace rules, this turn's persona and where its files live still rode.`
28
- );
32
+ const left = omitted === undefined ? `` : ` — left out: ${omitted}`;
33
+ return `Sent thin for this model's ${window} window${left}.${swapped}` + ` Your workspace rules, this turn's persona and where its files live still rode.`;
29
34
  };
@@ -1,6 +1,7 @@
1
1
  // What one of the user's own machines is running.
2
2
  import { z } from "zod";
3
3
  import { parseHostConnection, type DeviceFacts, DeviceFactsSchema, MachineIdSchema, userDistrosOf, WslEnvironmentSchema } from "./hosts.js";
4
+ import { RollbackTargetSchema, UpdateOutcomeSchema } from "./updates.js";
4
5
  import { DEV_VERSION } from "../state/versions.js";
5
6
  // Desktop-sync report shape shared by the agent, daemon and browser, produced only by the agent's own `deviceReport`.
6
7
  // The agent never reports `sandboxes`; the docker half is filled in by whoever reads the report, scoped to the reader's
@@ -76,6 +77,19 @@ export const DeviceSandboxSchema = z.object({
76
77
  resources: SandboxResourcesSchema.optional(),
77
78
  // The update `ic sandbox prepare` built and left waiting for this sandbox; absent when nothing is staged.
78
79
  staged: z.object({ image: z.string(), version: z.string().optional(), channel: z.string().optional() }).optional(),
80
+ // Everything below is read off an `ic` new enough to know it; an older ic's listing simply lacks it.
81
+ // What the running image says it is.
82
+ version: z.string().optional(),
83
+ // An interrupted swap left the old container set aside with no replacement: the sandbox is down, and `start` (or
84
+ // any swap) puts it back. `running` is false while this is true.
85
+ parked: z.boolean().optional(),
86
+ // A swap has just happened and the previous version is still parked and ready: until this moment the host watches
87
+ // the new one and goes back by itself if it keeps crashing, never becomes ready, or loses its tunnel.
88
+ probationUntil: z.number().optional(),
89
+ // What the host last did about this sandbox's version (the same record the sandbox reads as `lastUpdate`).
90
+ lastUpdate: UpdateOutcomeSchema.optional(),
91
+ // Newest first: what `rollback` would return to, then the older versions kept on this machine for `rollback --to`.
92
+ rollbackTargets: z.array(RollbackTargetSchema).optional(),
79
93
  });
80
94
  export type DeviceSandbox = z.infer<typeof DeviceSandboxSchema>;
81
95
  // One operation on one sandbox, streamed as lines ending in a `result` or `error` frame. `prepare` builds the pending
@@ -118,6 +132,9 @@ export const DeviceSandboxFlowSchema = z.strictObject({
118
132
  slug: z.string().min(1),
119
133
  // Approved overlay's sha256, required only by `rebuild`; only content matching it is ever built.
120
134
  hash: z.string().optional(),
135
+ // `rollback` only: a version or pinned image from the sandbox's `rollbackTargets` to go back to instead of the
136
+ // previous one. Sent only to an agent that advertises `rollback-to`: an older one refuses the field.
137
+ to: z.string().min(1).optional(),
121
138
  // `set-shape` only, both required by it: the whole shape, and when it takes effect.
122
139
  // Strict too, unlike the same shape read off a report (where a newer ic's extra field must not fail an older
123
140
  // reader): an order carrying a field this agent does not know is refused rather than carried out without it.
@@ -161,8 +178,10 @@ export const icShapeArgs = (slug: string, fields: SandboxShapeFields, when: Sand
161
178
  export const icForgetShapeArgs = (slug: string): string[] => ["sandbox", "shape", slug, "--forget"];
162
179
  // Power goes through ic too, so a Start or Restart from any door applies the shape saved for the next restart.
163
180
  export const icPowerArgs = (op: "start" | "stop" | "restart", slug: string): string[] => ["sandbox", op, slug];
164
- // Adds the device id to the flow input; the daemon looks up machines by id.
165
- export const DeviceSandboxFlowInputSchema = DeviceSandboxFlowSchema.extend({ id: z.string().min(1) });
181
+ // Adds the device id to the flow input; the daemon looks up machines by id. `resumeTurns` is the owner saying, as they
182
+ // restart the sandbox relaying this, that the turns it cuts should run again once it is back; the daemon keeps it for
183
+ // its next boot and never forwards it to the machine. A sandbox older than it ignores it, and the cut turns wait.
184
+ export const DeviceSandboxFlowInputSchema = DeviceSandboxFlowSchema.extend({ id: z.string().min(1), resumeTurns: z.boolean().optional() });
166
185
  export type DeviceSandboxFlowInput = z.infer<typeof DeviceSandboxFlowInputSchema>;
167
186
  // Streamed operation output, matching `IntenticLineSchema`: `line` frames as printed, then one terminal frame, `result`
168
187
  // or `error`, carrying the machine's own message rather than a code.
@@ -357,6 +376,9 @@ export const DevicePairingSchema = z.object({
357
376
  mode: z.enum(["sync", "mirror"]),
358
377
  // Set only for mode "sync", and only for the sandbox being reported to.
359
378
  localDir: z.string().optional(),
379
+ // Which sandbox folder `localDir` holds when it is not /work itself: a project pairing's `/work/<name>`, the
380
+ // owner's own folder, which carries no state backup and no git bridge. Absent means /work.
381
+ remoteDir: z.string().optional(),
360
382
  // Machine-owned switch (agent's own `sync mirror off`); absent reads as "on", not merely unknown.
361
383
  mirroring: z.enum(["on", "off"]).optional(),
362
384
  // Mutagen's own status word, kept verbatim rather than reduced to a traffic light.
@@ -495,6 +517,37 @@ export const DeviceSyncSchema = z.object({
495
517
  environment: z.string().optional(),
496
518
  });
497
519
  export type DeviceSync = z.infer<typeof DeviceSyncSchema>;
520
+
521
+ // A public host key as a machine pins it in known_hosts: its type and base64 body, no comment and nothing after.
522
+ export const SshHostKeySchema = z
523
+ .string()
524
+ .regex(/^(?:ssh-ed25519|ssh-rsa|ecdsa-sha2-nistp(?:256|384|521)|sk-ssh-ed25519@openssh\.com|sk-ecdsa-sha2-nistp256@openssh\.com) [A-Za-z0-9+/]+={0,2}$/);
525
+
526
+ // POST /system/authorized-key: a machine's agent enrolling its SSH key for desktop sync, redeeming a pairing token.
527
+ // Every field past `key` is optional: an older agent sends none of them and is still enrolled.
528
+ export const SyncEnrollmentRequestSchema = z.object({
529
+ // One authorized_keys line; its comment is the name the enrollment goes by (`DeviceSync.machine`).
530
+ key: z.string(),
531
+ // The computer and the environment on it that are enrolling, so the enrollment joins that machine's card.
532
+ machineId: MachineIdSchema.optional(),
533
+ environment: z.string().min(1).optional(),
534
+ });
535
+ export type SyncEnrollmentRequest = z.infer<typeof SyncEnrollmentRequestSchema>;
536
+
537
+ // The daemon's answer to an enrollment. Every field is optional for the agent reading it, since each arrived in a later
538
+ // daemon than the route: without `syncToken` the agent refuses the enrollment, without `mode` it reads "sync", and
539
+ // without `hostKey` it falls back to recording whatever key the sandbox presents first.
540
+ export const SyncEnrollmentAnswerSchema = z.object({
541
+ ok: z.literal(true).optional(),
542
+ // Authorizes the ports poll, the machine report and the SSH transport, sent as `x-intentic-sync`.
543
+ syncToken: z.string().optional(),
544
+ // What the pairing granted: a member's pairing only ever enrolls "mirror".
545
+ mode: z.enum(["sync", "mirror"]).optional(),
546
+ // The public key the sandbox's sshd presents (an SshHostKeySchema line), for the agent to pin under the pairing's
547
+ // alias. Checked by the agent on its own, so a key it cannot read costs the pin, never the enrollment.
548
+ hostKey: z.string().optional(),
549
+ });
550
+ export type SyncEnrollmentAnswer = z.infer<typeof SyncEnrollmentAnswerSchema>;
498
551
  export const DeviceSchema = z.object({
499
552
  // Stable row key: the reported hostname when either door produced one, else the name that door knows it by.
500
553
  key: z.string(),
@@ -40,10 +40,17 @@ export const RuntimeInstallSchema = z.object({
40
40
  declinedAt: z.number().optional(),
41
41
  });
42
42
  export type RuntimeInstall = z.infer<typeof RuntimeInstallSchema>;
43
+ // A draft the owner already answered (approved, removed or declined), by its tool and the hash of its steps: the same
44
+ // file coming back with an agent's land, which still carries it on its branch, proposes nothing. An agent asking again
45
+ // (`environment propose`) clears its tool's entries.
46
+ export const SettledDraftSchema = z.object({ tool: z.string(), hash: z.string(), at: z.number() });
47
+ export type SettledDraft = z.infer<typeof SettledDraftSchema>;
43
48
  export const RuntimeInstallsFileSchema = z.object({
44
49
  installs: z.array(RuntimeInstallSchema),
45
50
  // The last drift snapshot, persisted so a daemon restart does not blank the card until the next sweep.
46
51
  drift: EnvironmentDriftSchema.optional(),
52
+ // Drafts already answered, newest last and capped; absent on a ledger written before removal existed.
53
+ settled: z.array(SettledDraftSchema).optional(),
47
54
  });
48
55
  export type RuntimeInstallsFile = z.infer<typeof RuntimeInstallsFileSchema>;
49
56
  // Ledger entry as the Environment card shows it: recurrence joined with whether it's present in the live container
@@ -74,6 +81,26 @@ export type EnvironmentRuntimeDecision = z.infer<typeof EnvironmentRuntimeDecisi
74
81
  // there (SANDBOX_DEV_ROOT), absent on a sandbox that was handed a local image without one.
75
82
  export const EnvironmentLocalImageSchema = z.object({ base: z.string(), root: z.string().optional() });
76
83
  export type EnvironmentLocalImage = z.infer<typeof EnvironmentLocalImageSchema>;
84
+ // A rebuild the owner asked to start by itself once no agent is mid-turn, kept by the sandbox rather than the page that
85
+ // asked, so a page closed or a phone locked meanwhile does not lose it. Held in the sandbox's memory: a restart of the
86
+ // sandbox for any other reason drops it, and the card offers the rebuild again.
87
+ export const EnvironmentRebuildWaitSchema = z.object({
88
+ // The approved overlay it builds, and the connected device that runs it.
89
+ hash: z.string(),
90
+ host: z.string(),
91
+ requestedAt: z.number(),
92
+ // waiting: until no agent is mid-turn. rebuilding: handed to the device, which restarts this sandbox at the end.
93
+ // failed: the device refused or could not be reached; said until the owner dismisses it or asks again.
94
+ phase: z.enum(["waiting", "rebuilding", "failed"]),
95
+ // Who it waits on, by the title the board shows them under; empty once it is no longer waiting.
96
+ waitingOn: z.array(z.string()),
97
+ // The device's own words for a failed one.
98
+ message: z.string().optional(),
99
+ });
100
+ export type EnvironmentRebuildWait = z.infer<typeof EnvironmentRebuildWaitSchema>;
101
+ // Asks for that rebuild: the approved overlay's hash and the device that rebuilds this sandbox.
102
+ export const EnvironmentRebuildWhenIdleSchema = z.object({ host: z.string().min(1), hash: z.string().min(1) });
103
+ export type EnvironmentRebuildWhenIdle = z.infer<typeof EnvironmentRebuildWhenIdleSchema>;
77
104
  export const EnvironmentSchema = z.object({
78
105
  proposal: environmentFileSchema.optional(),
79
106
  // The owner-approved agent-written custom section (.intentic/config/environment.custom.Dockerfile).
@@ -89,6 +116,12 @@ export const EnvironmentSchema = z.object({
89
116
  recurring: z.array(EnvironmentRecurringSchema).optional(),
90
117
  // Absent on a sandbox running a published image, which is every sandbox but a dogfooding one.
91
118
  localImage: EnvironmentLocalImageSchema.optional(),
119
+ // A rebuild waiting for the agents to be idle, or started or refused once they were; absent when none is asked.
120
+ rebuildWhenIdle: EnvironmentRebuildWaitSchema.optional(),
121
+ // This sandbox can hold a rebuild until no agent is mid-turn (POST /environment/rebuild-when-idle), and resume the
122
+ // turns a restart the owner starts cuts when asked (a device swap's `resumeTurns`). Absent from one too old to,
123
+ // where the rebuild dialog offers only "Rebuild now" and the cut turns wait to be continued, as before.
124
+ waitsForAgents: z.literal(true).optional(),
92
125
  });
93
126
  export type Environment = z.infer<typeof EnvironmentSchema>;
94
127
  export const EnvironmentApproveSchema = z.object({ hash: z.string().min(1) });
@@ -127,8 +160,14 @@ export const EnvironmentItemSchema = z.object({
127
160
  detail: z.string().optional(),
128
161
  // The block's own instruction lines, for the reader who wants to see exactly what runs.
129
162
  commands: z.string().optional(),
163
+ // The custom-section block this row is, which the owner may take out (POST /environment/remove names it). Absent
164
+ // on capability and base rows, and from a sandbox that cannot remove one, so no Remove is offered there.
165
+ block: z.string().optional(),
130
166
  });
131
167
  export type EnvironmentItem = z.infer<typeof EnvironmentItemSchema>;
168
+ // Takes one tool out of the environment: its approved block, its pending draft, or both.
169
+ export const EnvironmentRemoveSchema = z.object({ block: z.string() });
170
+ export type EnvironmentRemove = z.infer<typeof EnvironmentRemoveSchema>;
132
171
  export const EnvironmentContentsSchema = z.object({ items: z.array(EnvironmentItemSchema) });
133
172
  export type EnvironmentContents = z.infer<typeof EnvironmentContentsSchema>;
134
173
  // A sandbox is four stores: /work, /history, the container, and the AI-provider credential root. A bundle carries only
@@ -86,7 +86,7 @@ export const PushSchema = RepoParamSchema.extend({
86
86
  });
87
87
  // Who said no to a push, read off git's own words (`pushRefusal`); the three answers ask three different things of the
88
88
  // owner.
89
- // hook: this repo's own pre-push hook refused it; the code is known wrong, worth a fix.
89
+ // hook: this repo's own pre-push hook refused it; what it printed is about the code, and the terminal holds all of it.
90
90
  // remote: the server rejected the refs (non-fast-forward, protected branch); pull first or push elsewhere.
91
91
  // transport: it never got there (credentials, unreachable host); a retry is the only useful button.
92
92
  export const PushRefusalSchema = z.enum(["hook", "remote", "transport"]);
@@ -100,7 +100,7 @@ export const PushRunSchema = CommandRunSchema.extend({
100
100
  .optional()
101
101
  .describe("Why not, in git's own words: the last verdict line, for a row that has room for one line. The whole tail is `output`."),
102
102
  refusedBy: PushRefusalSchema.optional().describe(
103
- "Who refused a failed push: this repository's pre-push hook (the code is wrong, a fix is worth proposing), the remote (pull first), or the transport (credentials, network: retry). Absent while it runs and for a push that went.",
103
+ "Who refused a failed push: this repository's own pre-push hook (what it printed is about the code), the remote (pull first), or the transport (credentials, network: retry). Absent while it runs and for a push that went.",
104
104
  ),
105
105
  });
106
106
  export type PushRun = z.infer<typeof PushRunSchema>;
@@ -389,6 +389,17 @@ export const AgentChangeSchema = GitChangeSchema.extend({
389
389
  ),
390
390
  });
391
391
  export type AgentChange = z.infer<typeof AgentChangeSchema>;
392
+ // One manifest's new dependency names: the file at the delta's anchor against the file as it stands now, so a review
393
+ // can say what the project takes on before it lands.
394
+ export const AddedDependenciesSchema = z.object({
395
+ path: z.string().describe("The manifest, relative to the repository root, such as video/package.json."),
396
+ added: z
397
+ .array(z.string())
398
+ .describe(
399
+ "The names it declares now and did not declare before, sorted. Only new names: a version bump of a dependency already there is not listed.",
400
+ ),
401
+ });
402
+ export type AddedDependencies = z.infer<typeof AddedDependenciesSchema>;
392
403
  // An agent worktree's delta vs its base, deliberately not RepoChanges: no index here, so sharing that shape would force
393
404
  // an empty `staged` and a staging affordance that cannot work on a worktree nobody checks out.
394
405
  export const AgentRepoChangesSchema = z.object({
@@ -401,6 +412,13 @@ export const AgentRepoChangesSchema = z.object({
401
412
  .describe(
402
413
  "The packages of the tree these changes came from, so a review can group by package. Carried with the changes rather than looked up separately, because a package the conversation has just created exists only in its own copy and the shared tree has never heard of it.",
403
414
  ),
415
+ // Absent rather than empty when nothing was added, the common case.
416
+ addedDependencies: z
417
+ .array(AddedDependenciesSchema)
418
+ .optional()
419
+ .describe(
420
+ "Dependencies the changed manifests here declare that they did not before (package.json, pyproject.toml, requirements.txt), one entry per manifest that gained any. The review is where a new dependency is approved: a conversation installs freely in its own copy, and this is what the project takes on if the work lands. Absent when none was added.",
421
+ ),
404
422
  });
405
423
  export type AgentRepoChanges = z.infer<typeof AgentRepoChangesSchema>;
406
424
  // The review, plus why the last land refused: a conflict is found when the turn ends but resolved later on this
@@ -68,10 +68,16 @@ export type DeviceFacts = z.infer<typeof DeviceFactsSchema>;
68
68
  // - `set-shape`: the `set-shape`/`forget-shape` ops, and `start`/`restart` applying a saved shape, all through an `ic`
69
69
  // whose `ic sandbox shape` takes the contract's own shape (`--set`); advertised only when the agent's `ic` does.
70
70
  // Both features ride that verb, so an agent advertises both or neither.
71
- export const DeviceFeatureSchema = z.enum(["reshape-later", "set-shape"]);
71
+ // - `rollback-to`: the `rollback` op's `to`, going back to an older version kept on the machine rather than the
72
+ // previous one; advertised only when the agent's `ic sandbox rollback` takes `--to`.
73
+ // - `loopback-catch`: the `catchLoopback` procedure, a sign-in's loopback redirect caught on this machine
74
+ // (loopback-catch.ts); an agent without it rejects the call as an unknown procedure.
75
+ export const DeviceFeatureSchema = z.enum(["reshape-later", "set-shape", "rollback-to", "loopback-catch"]);
72
76
  export type DeviceFeature = z.infer<typeof DeviceFeatureSchema>;
73
77
  export const DEVICE_FEATURE_RESHAPE_LATER: DeviceFeature = "reshape-later";
74
78
  export const DEVICE_FEATURE_SET_SHAPE: DeviceFeature = "set-shape";
79
+ export const DEVICE_FEATURE_ROLLBACK_TO: DeviceFeature = "rollback-to";
80
+ export const DEVICE_FEATURE_LOOPBACK_CATCH: DeviceFeature = "loopback-catch";
75
81
  // The features an agent advertised that this build knows; an unknown one is a newer agent's and means nothing here.
76
82
  export const deviceFeatures = (facts: Pick<DeviceFacts, "features"> | undefined): DeviceFeature[] =>
77
83
  (facts?.features ?? []).flatMap((feature) => {
@@ -2,6 +2,7 @@
2
2
  // clock lives here; how many refreshes a hold may spend is priced by the provider that serves it (runtimes/claude).
3
3
 
4
4
  import { z } from "zod";
5
+ import type { SandboxNotice } from "../events/sandbox-notice.js";
5
6
 
6
7
  // A cache clock as the daemon publishes it: the last request that touched the entry, and the entry's lifetime.
7
8
  export interface CacheClock {
@@ -95,16 +96,28 @@ const spanLabel = (ms: number): string => {
95
96
  return hours === 0 ? `${minutes}m` : `${hours}h ${minutes % 60}m`;
96
97
  };
97
98
 
98
- /** The transcript's line for a turn that picked up a conversation kept warm for it; undefined for any other turn. */
99
- export const keptWarmLine = (opening: PromptCacheOpening): string | undefined => {
99
+ /** The notice for a turn that picked up a conversation kept warm for it, by code and facts; undefined for any other turn. */
100
+ export const keptWarmNotice = (opening: PromptCacheOpening): Extract<SandboxNotice, { code: "keptWarm" | "keptCold" }> | undefined => {
100
101
  const { kept } = opening;
101
102
  if (kept === undefined) {
102
103
  return undefined;
103
104
  }
104
- const held = `kept warm for ${spanLabel(kept.forMs)} with ${kept.refreshes} ${kept.refreshes === 1 ? "refresh" : "refreshes"}`;
105
- return opening.readTokens >= opening.writtenTokens
106
- ? `Picked up warm: ${tokensLabel(opening.readTokens)} tokens read from the cache, ${held}.`
107
- : `Picked up cold despite being ${held}: ${tokensLabel(opening.writtenTokens)} tokens sent again, because this turn's prompt no longer matched the cache.`;
105
+ const warm = opening.readTokens >= opening.writtenTokens;
106
+ const params = { tokens: tokensLabel(warm ? opening.readTokens : opening.writtenTokens), span: spanLabel(kept.forMs), refreshes: kept.refreshes };
107
+ return warm ? { code: "keptWarm", params } : { code: "keptCold", params };
108
+ };
109
+
110
+ /** The transcript's line for a turn that picked up a conversation kept warm for it; undefined for any other turn. */
111
+ export const keptWarmLine = (opening: PromptCacheOpening): string | undefined => {
112
+ const notice = keptWarmNotice(opening);
113
+ if (notice === undefined) {
114
+ return undefined;
115
+ }
116
+ const { tokens, span, refreshes } = notice.params;
117
+ const held = `kept warm for ${span} with ${refreshes} ${refreshes === 1 ? "refresh" : "refreshes"}`;
118
+ return notice.code === "keptWarm"
119
+ ? `Picked up warm: ${tokens} tokens read from the cache, ${held}.`
120
+ : `Picked up cold despite being ${held}: ${tokens} tokens sent again, because this turn's prompt no longer matched the cache.`;
108
121
  };
109
122
 
110
123
  // A turn's prefix, part by part, so two turns that should share a cache can say which part stopped matching.
@@ -0,0 +1,45 @@
1
+ // Loopback catch: how a sign-in whose redirect lands on http://localhost:<port>/… finishes without a paste. The daemon
2
+ // is not on the machine the browser is on, so something that is (a device agent, the browser extension) watches that
3
+ // one address for the attempt's lifetime and hands back where the browser landed. Both peers answer the same
4
+ // procedure (`catchLoopback`) with the same frames, so the daemon drives them identically.
5
+ // Named imports rather than the `z` namespace: the extension bundles this module (see webext.ts).
6
+ import { discriminatedUnion, enum as zEnum, literal, number, object, string } from "zod";
7
+ import type * as z from "zod";
8
+
9
+ // What one catcher is asked to watch. The state is deliberately absent: the daemon checks it on what comes back, so a
10
+ // catcher can hold nothing that tells a real landing from a forged one, and needs nothing to.
11
+ export const LoopbackCatchSchema = object({
12
+ // The attempt's own id, for logs on both ends; not redeemable.
13
+ id: string().min(1),
14
+ // The host the provider redirects to, spelled as its registration spells it: some are registered as
15
+ // `localhost`, some as `127.0.0.1`, and a browser treats the two as different origins.
16
+ host: zEnum(["localhost", "127.0.0.1"]),
17
+ port: number().int().min(1).max(65535),
18
+ // The path only, leading slash included; the query is the grant and is never matched.
19
+ path: string().startsWith("/"),
20
+ // Epoch ms; a catcher stops watching by itself here even if nobody aborts the stream.
21
+ expiresAt: number(),
22
+ // Who the page thanks once the browser lands ("Claude"), so the tab says what just happened.
23
+ title: string().min(1),
24
+ }).strict();
25
+ export type LoopbackCatch = z.infer<typeof LoopbackCatchSchema>;
26
+
27
+ // What a catcher streams back. `busy` ends its part (the port is taken on that machine, or it cannot watch at all);
28
+ // `landed` may come more than once, since anything on the machine can hit a loopback port and only the daemon can
29
+ // tell which hit is the sign-in.
30
+ export const LoopbackCatchEventSchema = discriminatedUnion("type", [
31
+ object({ type: literal("listening") }),
32
+ object({ type: literal("busy"), reason: string() }),
33
+ object({ type: literal("landed"), url: string().min(1) }),
34
+ ]);
35
+ export type LoopbackCatchEvent = z.infer<typeof LoopbackCatchEventSchema>;
36
+
37
+ // Advertised in a device's `features` and a browser's facts; only a peer that says it is asked.
38
+ export const LOOPBACK_CATCH_FEATURE = "loopback-catch";
39
+
40
+ // Who is watching for this attempt's landing, for the card to say "finishes by itself on rog".
41
+ export const SignInCatcherSchema = object({
42
+ kind: zEnum(["device", "browser"]),
43
+ label: string().min(1),
44
+ });
45
+ export type SignInCatcher = z.infer<typeof SignInCatcherSchema>;
@@ -137,7 +137,7 @@ export const MutationScoreSchema = z.object({
137
137
  .number()
138
138
  .describe("The share of injected faults the suite caught. Not a coverage figure: coverage says a line ran, this says an assertion depended on it."),
139
139
  killed: z.number().int().nonnegative().describe("Faults the suite caught."),
140
- survived: z.number().int().nonnegative().describe("Faults it did not: code that can be broken with every test still green."),
140
+ survived: z.number().int().nonnegative().describe("Faults it did not: code that can be broken with every test still passing."),
141
141
  // A timeout counts as detected here (Stryker's own convention), not as inconclusive.
142
142
  inconclusive: z
143
143
  .number()