@intentic/sandbox-contract 1.344.0 → 1.345.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 (307) hide show
  1. package/README.md +6 -0
  2. package/dist/contracts/accounts.contract.d.ts +24 -0
  3. package/dist/contracts/accounts.contract.d.ts.map +1 -1
  4. package/dist/contracts/agent.contract.d.ts +214 -6
  5. package/dist/contracts/agent.contract.d.ts.map +1 -1
  6. package/dist/contracts/agent.contract.js +13 -2
  7. package/dist/contracts/agent.contract.js.map +1 -1
  8. package/dist/contracts/agents.contract.d.ts +656 -0
  9. package/dist/contracts/agents.contract.d.ts.map +1 -1
  10. package/dist/contracts/agents.contract.js +5 -3
  11. package/dist/contracts/agents.contract.js.map +1 -1
  12. package/dist/contracts/device.contract.d.ts +242 -0
  13. package/dist/contracts/device.contract.d.ts.map +1 -1
  14. package/dist/contracts/device.contract.js +5 -1
  15. package/dist/contracts/device.contract.js.map +1 -1
  16. package/dist/contracts/endpoints.contract.d.ts +2 -0
  17. package/dist/contracts/endpoints.contract.d.ts.map +1 -1
  18. package/dist/contracts/endpoints.contract.js +1 -0
  19. package/dist/contracts/endpoints.contract.js.map +1 -1
  20. package/dist/contracts/push.contract.d.ts +11 -0
  21. package/dist/contracts/push.contract.d.ts.map +1 -1
  22. package/dist/contracts/push.contract.js +10 -1
  23. package/dist/contracts/push.contract.js.map +1 -1
  24. package/dist/contracts/runner.contract.d.ts +15 -0
  25. package/dist/contracts/runner.contract.d.ts.map +1 -1
  26. package/dist/contracts/secrets.contract.d.ts +169 -0
  27. package/dist/contracts/secrets.contract.d.ts.map +1 -1
  28. package/dist/contracts/secrets.contract.js +35 -0
  29. package/dist/contracts/secrets.contract.js.map +1 -1
  30. package/dist/contracts/sessions.contract.d.ts +2 -0
  31. package/dist/contracts/sessions.contract.d.ts.map +1 -1
  32. package/dist/contracts/settings.contract.d.ts +33 -0
  33. package/dist/contracts/settings.contract.d.ts.map +1 -1
  34. package/dist/contracts/system.contract.d.ts +133 -30
  35. package/dist/contracts/system.contract.d.ts.map +1 -1
  36. package/dist/contracts/translator.contract.d.ts +24 -0
  37. package/dist/contracts/translator.contract.d.ts.map +1 -1
  38. package/dist/contracts/workspace.contract.d.ts +11 -0
  39. package/dist/contracts/workspace.contract.d.ts.map +1 -1
  40. package/dist/contracts/workspace.contract.js +11 -1
  41. package/dist/contracts/workspace.contract.js.map +1 -1
  42. package/dist/events/agent-events.d.ts +17 -0
  43. package/dist/events/agent-events.d.ts.map +1 -1
  44. package/dist/events/agent-events.js +2 -1
  45. package/dist/events/agent-events.js.map +1 -1
  46. package/dist/events/agent-transcript.d.ts +727 -0
  47. package/dist/events/agent-transcript.d.ts.map +1 -0
  48. package/dist/events/agent-transcript.js +34 -0
  49. package/dist/events/agent-transcript.js.map +1 -0
  50. package/dist/events/agent-words.d.ts +5 -0
  51. package/dist/events/agent-words.d.ts.map +1 -1
  52. package/dist/events/agent-words.js +9 -0
  53. package/dist/events/agent-words.js.map +1 -1
  54. package/dist/events/requests.d.ts +143 -0
  55. package/dist/events/requests.d.ts.map +1 -1
  56. package/dist/events/requests.js +35 -1
  57. package/dist/events/requests.js.map +1 -1
  58. package/dist/events/sandbox-notice.d.ts +7 -0
  59. package/dist/events/sandbox-notice.d.ts.map +1 -1
  60. package/dist/events/sandbox-notice.js +1 -0
  61. package/dist/events/sandbox-notice.js.map +1 -1
  62. package/dist/events/system-events.d.ts +88 -0
  63. package/dist/events/system-events.d.ts.map +1 -1
  64. package/dist/events/transcript.d.ts +20 -720
  65. package/dist/events/transcript.d.ts.map +1 -1
  66. package/dist/events/transcript.js +17 -19
  67. package/dist/events/transcript.js.map +1 -1
  68. package/dist/events/undelivered.d.ts +4 -0
  69. package/dist/events/undelivered.d.ts.map +1 -1
  70. package/dist/events/undelivered.js +13 -0
  71. package/dist/events/undelivered.js.map +1 -1
  72. package/dist/ids/conversation-ids.d.ts +2 -0
  73. package/dist/ids/conversation-ids.d.ts.map +1 -1
  74. package/dist/ids/conversation-ids.js +2 -0
  75. package/dist/ids/conversation-ids.js.map +1 -1
  76. package/dist/ids/row-ids.d.ts +3 -0
  77. package/dist/ids/row-ids.d.ts.map +1 -0
  78. package/dist/ids/row-ids.js +11 -0
  79. package/dist/ids/row-ids.js.map +1 -0
  80. package/dist/index.d.ts +1281 -39
  81. package/dist/index.d.ts.map +1 -1
  82. package/dist/models/agent-lanes.d.ts.map +1 -1
  83. package/dist/models/agent-lanes.js +3 -2
  84. package/dist/models/agent-lanes.js.map +1 -1
  85. package/dist/models/agent-standing.d.ts +4 -0
  86. package/dist/models/agent-standing.d.ts.map +1 -1
  87. package/dist/models/agent-standing.js +2 -1
  88. package/dist/models/agent-standing.js.map +1 -1
  89. package/dist/models/plan-pools.d.ts +5 -1
  90. package/dist/models/plan-pools.d.ts.map +1 -1
  91. package/dist/models/plan-pools.js +57 -21
  92. package/dist/models/plan-pools.js.map +1 -1
  93. package/dist/netd/generated/wire.d.ts +5 -0
  94. package/dist/netd/generated/wire.d.ts.map +1 -1
  95. package/dist/policy/command-classes.d.ts +1 -1
  96. package/dist/policy/command-classes.d.ts.map +1 -1
  97. package/dist/policy/command-classes.js +2 -2
  98. package/dist/policy/command-classes.js.map +1 -1
  99. package/dist/policy/keyring-origins.d.ts +27 -0
  100. package/dist/policy/keyring-origins.d.ts.map +1 -0
  101. package/dist/policy/keyring-origins.js +213 -0
  102. package/dist/policy/keyring-origins.js.map +1 -0
  103. package/dist/policy/keyring-seal.d.ts +9 -0
  104. package/dist/policy/keyring-seal.d.ts.map +1 -1
  105. package/dist/policy/keyring-seal.js +18 -6
  106. package/dist/policy/keyring-seal.js.map +1 -1
  107. package/dist/policy/safety-policy.d.ts +1 -1
  108. package/dist/policy/safety-policy.d.ts.map +1 -1
  109. package/dist/policy/safety-policy.js +1 -1
  110. package/dist/policy/safety-policy.js.map +1 -1
  111. package/dist/policy/turned-away.d.ts +1 -0
  112. package/dist/policy/turned-away.d.ts.map +1 -1
  113. package/dist/policy/turned-away.js +10 -0
  114. package/dist/policy/turned-away.js.map +1 -1
  115. package/dist/protocol/doors/host-protocol.d.ts +1 -0
  116. package/dist/protocol/doors/host-protocol.d.ts.map +1 -1
  117. package/dist/protocol/doors/host-protocol.js +1 -0
  118. package/dist/protocol/doors/host-protocol.js.map +1 -1
  119. package/dist/protocol/doors/webext-links.d.ts +1 -0
  120. package/dist/protocol/doors/webext-links.d.ts.map +1 -1
  121. package/dist/protocol/doors/webext-links.js +1 -0
  122. package/dist/protocol/doors/webext-links.js.map +1 -1
  123. package/dist/protocol/peer-dial.d.ts +2 -0
  124. package/dist/protocol/peer-dial.d.ts.map +1 -1
  125. package/dist/protocol/peer-dial.js +62 -29
  126. package/dist/protocol/peer-dial.js.map +1 -1
  127. package/dist/protocol/raw/raw-json-routes.d.ts +176 -0
  128. package/dist/protocol/raw/raw-json-routes.d.ts.map +1 -1
  129. package/dist/protocol/raw/raw-json-routes.js +5 -0
  130. package/dist/protocol/raw/raw-json-routes.js.map +1 -1
  131. package/dist/protocol/raw/raw-routes.d.ts +31 -0
  132. package/dist/protocol/raw/raw-routes.d.ts.map +1 -1
  133. package/dist/protocol/raw/raw-routes.js +8 -0
  134. package/dist/protocol/raw/raw-routes.js.map +1 -1
  135. package/dist/schemas/agent-place.d.ts +10 -0
  136. package/dist/schemas/agent-place.d.ts.map +1 -0
  137. package/dist/schemas/agent-place.js +15 -0
  138. package/dist/schemas/agent-place.js.map +1 -0
  139. package/dist/schemas/agent.d.ts +116 -83
  140. package/dist/schemas/agent.d.ts.map +1 -1
  141. package/dist/schemas/agent.js +26 -39
  142. package/dist/schemas/agent.js.map +1 -1
  143. package/dist/schemas/agents-list.d.ts +38 -0
  144. package/dist/schemas/agents-list.d.ts.map +1 -1
  145. package/dist/schemas/agents.d.ts +117 -16
  146. package/dist/schemas/agents.d.ts.map +1 -1
  147. package/dist/schemas/agents.js +19 -21
  148. package/dist/schemas/agents.js.map +1 -1
  149. package/dist/schemas/attach.d.ts +8 -0
  150. package/dist/schemas/attach.d.ts.map +1 -0
  151. package/dist/schemas/attach.js +14 -0
  152. package/dist/schemas/attach.js.map +1 -0
  153. package/dist/schemas/command-admission.d.ts +71 -0
  154. package/dist/schemas/command-admission.d.ts.map +1 -0
  155. package/dist/schemas/command-admission.js +27 -0
  156. package/dist/schemas/command-admission.js.map +1 -0
  157. package/dist/schemas/conversation-links.d.ts +44 -0
  158. package/dist/schemas/conversation-links.d.ts.map +1 -0
  159. package/dist/schemas/conversation-links.js +35 -0
  160. package/dist/schemas/conversation-links.js.map +1 -0
  161. package/dist/schemas/data-protection.d.ts +1 -1
  162. package/dist/schemas/data-protection.d.ts.map +1 -1
  163. package/dist/schemas/devices.d.ts +4 -1
  164. package/dist/schemas/devices.d.ts.map +1 -1
  165. package/dist/schemas/devices.js +1 -0
  166. package/dist/schemas/devices.js.map +1 -1
  167. package/dist/schemas/hosts.d.ts +2 -0
  168. package/dist/schemas/hosts.d.ts.map +1 -1
  169. package/dist/schemas/hosts.js +2 -0
  170. package/dist/schemas/hosts.js.map +1 -1
  171. package/dist/schemas/keyring-native.d.ts +137 -0
  172. package/dist/schemas/keyring-native.d.ts.map +1 -0
  173. package/dist/schemas/keyring-native.js +69 -0
  174. package/dist/schemas/keyring-native.js.map +1 -0
  175. package/dist/schemas/keyring.d.ts +413 -0
  176. package/dist/schemas/keyring.d.ts.map +1 -1
  177. package/dist/schemas/keyring.js +139 -4
  178. package/dist/schemas/keyring.js.map +1 -1
  179. package/dist/schemas/phone-passwords.d.ts +186 -0
  180. package/dist/schemas/phone-passwords.d.ts.map +1 -0
  181. package/dist/schemas/phone-passwords.js +25 -0
  182. package/dist/schemas/phone-passwords.js.map +1 -0
  183. package/dist/schemas/providers/plan-limits.d.ts +74 -0
  184. package/dist/schemas/providers/plan-limits.d.ts.map +1 -1
  185. package/dist/schemas/providers/plan-limits.js +31 -0
  186. package/dist/schemas/providers/plan-limits.js.map +1 -1
  187. package/dist/schemas/providers/provider-oauth.d.ts +24 -0
  188. package/dist/schemas/providers/provider-oauth.d.ts.map +1 -1
  189. package/dist/schemas/providers/usage.d.ts +1 -0
  190. package/dist/schemas/providers/usage.d.ts.map +1 -1
  191. package/dist/schemas/providers/usage.js +1 -0
  192. package/dist/schemas/providers/usage.js.map +1 -1
  193. package/dist/schemas/push.d.ts +13 -0
  194. package/dist/schemas/push.d.ts.map +1 -1
  195. package/dist/schemas/push.js +11 -1
  196. package/dist/schemas/push.js.map +1 -1
  197. package/dist/schemas/sandbox-passwords.d.ts +288 -0
  198. package/dist/schemas/sandbox-passwords.d.ts.map +1 -0
  199. package/dist/schemas/sandbox-passwords.js +66 -0
  200. package/dist/schemas/sandbox-passwords.js.map +1 -0
  201. package/dist/schemas/secrets.d.ts +2 -0
  202. package/dist/schemas/secrets.d.ts.map +1 -1
  203. package/dist/schemas/secrets.js +4 -0
  204. package/dist/schemas/secrets.js.map +1 -1
  205. package/dist/schemas/settings-savings.d.ts +709 -0
  206. package/dist/schemas/settings-savings.d.ts.map +1 -0
  207. package/dist/schemas/settings-savings.js +53 -0
  208. package/dist/schemas/settings-savings.js.map +1 -0
  209. package/dist/schemas/settings.d.ts +3 -671
  210. package/dist/schemas/settings.d.ts.map +1 -1
  211. package/dist/schemas/settings.js +3 -50
  212. package/dist/schemas/settings.js.map +1 -1
  213. package/dist/schemas/terminal.d.ts +5 -0
  214. package/dist/schemas/terminal.d.ts.map +1 -1
  215. package/dist/schemas/terminal.js +4 -0
  216. package/dist/schemas/terminal.js.map +1 -1
  217. package/dist/schemas/work-assurance.d.ts +24 -0
  218. package/dist/schemas/work-assurance.d.ts.map +1 -0
  219. package/dist/schemas/work-assurance.js +23 -0
  220. package/dist/schemas/work-assurance.js.map +1 -0
  221. package/dist/schemas/workspace/workspace-tree.d.ts +23 -0
  222. package/dist/schemas/workspace/workspace-tree.d.ts.map +1 -1
  223. package/dist/schemas/workspace/workspace-tree.js +20 -0
  224. package/dist/schemas/workspace/workspace-tree.js.map +1 -1
  225. package/dist/state/auth-state.d.ts +4 -0
  226. package/dist/state/auth-state.d.ts.map +1 -0
  227. package/dist/state/auth-state.js +37 -0
  228. package/dist/state/auth-state.js.map +1 -0
  229. package/dist/state/definition.d.ts +4 -0
  230. package/dist/state/definition.d.ts.map +1 -1
  231. package/dist/state/history-state.d.ts.map +1 -1
  232. package/dist/state/history-state.js +17 -1
  233. package/dist/state/history-state.js.map +1 -1
  234. package/dist/state/runtime-state.d.ts.map +1 -1
  235. package/dist/state/runtime-state.js.map +1 -1
  236. package/dist/text/transcript-fold.js +5 -5
  237. package/dist/text/transcript-fold.js.map +1 -1
  238. package/dist/webext/index.d.ts +1 -0
  239. package/dist/webext/index.d.ts.map +1 -1
  240. package/dist/webext/index.js +1 -0
  241. package/dist/webext/index.js.map +1 -1
  242. package/package.json +6 -5
  243. package/src/contracts/agent.contract.ts +13 -1
  244. package/src/contracts/agents.contract.ts +4 -3
  245. package/src/contracts/device.contract.ts +16 -0
  246. package/src/contracts/endpoints.contract.ts +3 -0
  247. package/src/contracts/push.contract.ts +23 -1
  248. package/src/contracts/secrets.contract.ts +39 -0
  249. package/src/contracts/workspace.contract.ts +16 -0
  250. package/src/events/agent-events.ts +4 -1
  251. package/src/events/agent-transcript.ts +48 -0
  252. package/src/events/agent-words.ts +13 -0
  253. package/src/events/requests.ts +41 -3
  254. package/src/events/sandbox-notice.ts +3 -0
  255. package/src/events/transcript.ts +30 -28
  256. package/src/events/undelivered.ts +18 -0
  257. package/src/ids/conversation-ids.ts +7 -0
  258. package/src/ids/row-ids.ts +20 -0
  259. package/src/models/agent-lanes.ts +9 -3
  260. package/src/models/agent-standing.ts +9 -1
  261. package/src/models/plan-pools.test.ts +128 -20
  262. package/src/models/plan-pools.ts +114 -31
  263. package/src/netd/generated/netd-wire.json +25 -0
  264. package/src/netd/generated/wire.ts +1 -1
  265. package/src/policy/command-classes.ts +2 -2
  266. package/src/policy/keyring-origins.test.ts +132 -0
  267. package/src/policy/keyring-origins.ts +287 -0
  268. package/src/policy/keyring-seal.test.ts +37 -2
  269. package/src/policy/keyring-seal.ts +33 -7
  270. package/src/policy/safety-policy.ts +1 -1
  271. package/src/policy/tests/safety-policy.test.ts +1 -1
  272. package/src/policy/turned-away.ts +15 -0
  273. package/src/protocol/doors/host-protocol.ts +3 -0
  274. package/src/protocol/doors/webext-links.ts +3 -0
  275. package/src/protocol/peer-dial.test.ts +90 -4
  276. package/src/protocol/peer-dial.ts +83 -39
  277. package/src/protocol/raw/raw-json-routes.ts +13 -0
  278. package/src/protocol/raw/raw-routes.ts +12 -1
  279. package/src/schemas/agent-place.ts +22 -0
  280. package/src/schemas/agent.ts +42 -78
  281. package/src/schemas/agents.ts +41 -46
  282. package/src/schemas/attach.ts +23 -0
  283. package/src/schemas/command-admission.ts +57 -0
  284. package/src/schemas/conversation-links.ts +62 -0
  285. package/src/schemas/data-protection.ts +1 -1
  286. package/src/schemas/devices.ts +4 -4
  287. package/src/schemas/hosts.ts +4 -0
  288. package/src/schemas/keyring-native.test.ts +13 -0
  289. package/src/schemas/keyring-native.ts +101 -0
  290. package/src/schemas/keyring.ts +202 -4
  291. package/src/schemas/phone-passwords.ts +51 -0
  292. package/src/schemas/providers/plan-limits.ts +49 -2
  293. package/src/schemas/providers/usage.ts +2 -0
  294. package/src/schemas/push.ts +19 -3
  295. package/src/schemas/sandbox-passwords.ts +88 -0
  296. package/src/schemas/secrets.ts +4 -0
  297. package/src/schemas/settings-savings.ts +125 -0
  298. package/src/schemas/settings.ts +8 -116
  299. package/src/schemas/terminal.ts +8 -0
  300. package/src/schemas/work-assurance.ts +36 -0
  301. package/src/schemas/workspace/workspace-tree.ts +32 -0
  302. package/src/state/auth-state.ts +89 -0
  303. package/src/state/history-state.ts +44 -1
  304. package/src/state/runtime-state.ts +5 -4
  305. package/src/text/transcript-fold.test.ts +67 -0
  306. package/src/text/transcript-fold.ts +6 -6
  307. package/src/webext/index.ts +2 -0
@@ -1,13 +1,14 @@
1
1
  // agents: the conversation fleet
2
2
  import { LandingDeliverySchema } from "./project-delivery.js";
3
3
  import { z } from "zod";
4
- import { AgentHarnessSchema, AgentOriginSchema, AgentProviderSchema, ConversationQueueSchema, ForkedFromSchema } from "./agent.js";
4
+ import { AgentHarnessSchema, AgentOriginSchema, AgentProviderSchema, ConversationQueueSchema, ForkedFromSchema, FreshSessionSchema } from "./agent.js";
5
5
  import { LoopStateSchema } from "./loops.js";
6
6
  import { LimitPolicySchema, RetryPolicySchema, RoomPolicySchema, TurnBreakPolicySchema, TurnBreakSchema } from "./turn-break.js";
7
7
  import { KeepWarmSchema } from "./keep-warm.js";
8
8
  import { AgentNeedSchema } from "./needs.js";
9
9
  import { EMOJI_MAX_LENGTH, isSingleEmoji } from "../text/emoji.js";
10
10
  import { ProgramAskSchema } from "../events/requests.js";
11
+ import { ReviewTallySchema, TurnProofSchema } from "./work-assurance.js";
11
12
  // A fleet agent is any conversation with a registry entry, keyed by conversationId. Isolated ones own a git worktree
12
13
  // (branch agent/<id>); workspace conversations have none, but both share one status/activity/cost lifecycle.
13
14
 
@@ -62,8 +63,7 @@ export const AgentAttentionSchema = z.object({
62
63
  // A missing capability on a card from before needs (docs/architecture/needs.md); lets the lane say "setup needed" rather than a generic
63
64
  // pause.
64
65
  capability: z.boolean().describe("It needs something connected that is not connected yet."),
65
- // A gated credential parked on a named person's click; the one pause the board's reader may not be able to clear
66
- // themselves.
66
+ // A gated credential parked on a named person's click; the one pause the board's reader may not be able to clear themselves.
67
67
  credential: z
68
68
  .boolean()
69
69
  .describe("It is waiting for a named person to release a credential. The one pause that may not be yours to clear, whatever your role."),
@@ -101,22 +101,8 @@ export const UnfinishedWorkSchema = z.object({
101
101
  ),
102
102
  });
103
103
  export type UnfinishedWork = z.infer<typeof UnfinishedWorkSchema>;
104
- // What the last turn showed of its own work, read off its tool calls and never asked of the model: the record a card
105
- // badges instead of sending the turn back to prove anything. CI checks what the owner pushes (schemas/ci.ts).
106
- export const TurnProofSchema = z.object({
107
- at: z.number().describe("When the turn that left this ended, in milliseconds."),
108
- verification: z
109
- .enum(["verified", "unproven", "failing", "no-code"])
110
- .describe(
111
- "Verified: a check it ran passed after its last edit to code. Failing: the last one it ran failed. Unproven: it changed code and ran nothing that checked it. No-code: it changed nothing a check could speak to.",
112
- ),
113
- check: z.string().optional().describe("The command that spoke, when one did, so a targeted test is never read as the whole suite."),
114
- unviewed: z
115
- .number()
116
- .optional()
117
- .describe("How many rendered files it changed (pages, components, styles) without looking at the result afterwards. Absent when none."),
118
- });
119
- export type TurnProof = z.infer<typeof TurnProofSchema>;
104
+ // What has looked at a conversation's work (its last turn's own checks, its latest code review): work-assurance.ts.
105
+ export * from "./work-assurance.js";
120
106
  // How many entries each of a reach's lists carries; past it, the list's `…More` count says how many were left out.
121
107
  export const TURN_REACH_LIST_MAX = 10;
122
108
  // Where the last turn's work went when it went somewhere other than its own branch, read off what the turn touched and
@@ -175,8 +161,7 @@ export type TurnReach = z.infer<typeof TurnReachSchema>;
175
161
  // A landing's commit message: subject plus the two trailer sentences a changelog repo gets. One schema, not three
176
162
  // duplicated fields, since both the live roster and the review carrier must read the same shape and can't disagree.
177
163
  export const LandedMessageSchema = z.object({
178
- // Written from the landed diff, not the opening prompt: a session that drifts from its title still needs an
179
- // accurate subject.
164
+ // Written from the landed diff, not the opening prompt: a session that drifts from its title still needs an accurate subject.
180
165
  subject: z
181
166
  .string()
182
167
  .describe(
@@ -189,8 +174,7 @@ export const LandedMessageSchema = z.object({
189
174
  .describe(
190
175
  "The same change said to somebody who uses the product, for a repository that keeps a changelog. Usually absent, because most changes are not ones a user would notice.",
191
176
  ),
192
- // Nearly always absent (removals only); required and mechanically guaranteed when a landing shrinks a wire-contract
193
- // lock.
177
+ // Nearly always absent (removals only); required and mechanically guaranteed when a landing shrinks a wire-contract lock.
194
178
  breaking: z
195
179
  .string()
196
180
  .optional()
@@ -220,8 +204,7 @@ export const LandedMessageStepSchema = z.object({
220
204
  status: z
221
205
  .enum(["asking", "answered", "refused", "skipped"])
222
206
  .describe("How this one went. Skipped means it was not asked at all, because it refused a few minutes ago and the walk stepped over it."),
223
- // Epoch ms it started; client-measures an in-flight step's ticking display. Absent for `skipped`, which cost no
224
- // time.
207
+ // Epoch ms it started; client-measures an in-flight step's ticking display. Absent for `skipped`, which cost no time.
225
208
  at: z.number().optional().describe("When it started being asked, in milliseconds. Absent for one that was skipped, which cost no time."),
226
209
  ms: z.number().optional().describe("How long it took. Absent while it is still being asked."),
227
210
  reason: z.string().optional().describe("Why it refused, in its own words."),
@@ -297,16 +280,14 @@ export const AgentSummarySchema = z.object({
297
280
  status: AgentStatusSchema.describe(
298
281
  "What it is doing. Stopping and stopped are the two halves of somebody pressing stop, because a cancel is not instant; dismissing is the same window for a question waved away, which ends the turn too but owes the user nothing; resuming means the sandbox is already putting right whatever killed the turn; landing means its work is being carried into the workspace right now, and nothing may act on its branch until that settles.",
299
282
  ),
300
- // Sentence the last turn died on; carried since `error` status alone isn't an answer, especially for an unwatched
301
- // run.
283
+ // Sentence the last turn died on; carried since `error` status alone isn't an answer, especially for an unwatched run.
302
284
  failure: z
303
285
  .string()
304
286
  .optional()
305
287
  .describe(
306
288
  "Why the last turn failed, in the words it died on. Absent unless it did, and cleared the moment it runs again. Carried here because the word error on its own is not an answer, least of all for a run nobody was watching.",
307
289
  ),
308
- // The error frame's own code, so the board can distinguish e.g. a rate limit from a crash the way chat already
309
- // does.
290
+ // The error frame's own code, so the board can distinguish e.g. a rate limit from a crash the way chat already does.
310
291
  failureCode: z
311
292
  .string()
312
293
  .optional()
@@ -316,12 +297,18 @@ export const AgentSummarySchema = z.object({
316
297
  // Epoch seconds the spent allowance reopens; absent means genuinely unknown (Grok, Cursor) — never guess one.
317
298
  limitResetsAt: z.number().optional().describe("When the spent allowance reopens, in epoch seconds. Absent when the provider publishes no instant."),
318
299
  limitHeld: z.boolean().optional().describe("Whether the refused turn is held whole, so sending again re-runs it instead of appending to it."),
319
- // Whether the daemon has already booked a retry at the reset; the one thing that keeps a stranded card out of the
320
- // Attention lane.
300
+ // Whether the daemon has already booked a retry at the reset; the one thing that keeps a stranded card out of the Attention lane.
321
301
  limitScheduled: z.boolean().optional().describe("Whether the held turn is already booked to go again at the reset, so nobody has to press anything."),
322
- // Account a booked move is sending the held turn to; set alongside `limitScheduled`, cleared by the move's own
323
- // turn.
302
+ // Account a booked move is sending the held turn to; set alongside `limitScheduled`, cleared by the move's own turn.
324
303
  limitMoving: z.string().optional().describe("The account the held turn is being moved to by the owner's policy, while that move is booked."),
304
+ // The resume pass's own instant for the booked re-run, the one it fires by (limit-due.ts), so a card states when it
305
+ // goes rather than inferring it from the reset: they differ once the account it goes on is still spent at the reset.
306
+ limitNextAt: z
307
+ .number()
308
+ .optional()
309
+ .describe(
310
+ "When the held turn goes again by itself, in epoch seconds, while it is booked to (limitScheduled): later than the reset where the account it goes on is still spent, and already past for a booked move, which goes on the next pass. Absent while only a press sends it.",
311
+ ),
325
312
  provider: AgentProviderSchema.describe("Which model provider it runs on."),
326
313
  harness: AgentHarnessSchema.describe("Which agentic loop it runs on."),
327
314
  // Latched with the conversation, so the card can say where work runs without asking anything else.
@@ -414,6 +401,10 @@ export const AgentSummarySchema = z.object({
414
401
  forkedFrom: ForkedFromSchema.optional().describe(
415
402
  "The conversation this one was cut from. Recorded once and never cleared: it is the relationship, not a pending state.",
416
403
  ),
404
+ // Recorded once on a fresh session's first turn and never cleared; `startedBy` names the same origin as its parent.
405
+ fresh: FreshSessionSchema.optional().describe(
406
+ "Set on a conversation started on another conversation's work without its messages (a code review, a test pass, a person's own ask): which one, for what, and when. Absent for every other conversation.",
407
+ ),
417
408
  // Root repo's short base sha; per-repo bases stay daemon-internal.
418
409
  base: z.string().optional().describe("The commit its private copy started from, shortened."),
419
410
  costUsd: z.number().optional().describe("What it has cost so far, in dollars. A subagent's spend is its own and is not folded in here."),
@@ -543,6 +534,10 @@ export const AgentSummarySchema = z.object({
543
534
  proof: TurnProofSchema.optional().describe(
544
535
  "What its last turn showed of its work: whether a check it ran passed after its last edit, and whether it looked at interface files it changed. Absent until a turn that edited or checked anything has ended.",
545
536
  ),
537
+ // Written by the settle of the turn that reported a review, from its review frames; never asked of the model.
538
+ review: ReviewTallySchema.optional().describe(
539
+ "The latest code review this conversation reported: how many findings, and how many are still open. Absent until one has.",
540
+ ),
546
541
  // Written by the turn's own settle from its tool calls and a read of the clones and installs it could have touched;
547
542
  // replaced by every turn, so it says where the LAST turn's work went.
548
543
  reach: TurnReachSchema.optional().describe(
@@ -750,6 +745,19 @@ export const AgentTranscriptQuerySchema = AgentIdSchema.extend({
750
745
  .optional()
751
746
  .describe("Return the messages before this position in the record: the `from` of the page below. Absent asks for the most recent turns."),
752
747
  turns: z.coerce.number().int().min(1).max(200).optional().describe("How many of the user's turns to return, newest first. Absent takes the daemon's default."),
748
+ // Reading forward from the reader's cursor, checked by the row it names: a rewind since reuses positions.
749
+ after: z.coerce
750
+ .number()
751
+ .int()
752
+ .nonnegative()
753
+ .optional()
754
+ .describe(
755
+ "Return what the record holds from this position on: the `through` of the reader's last page. Answered `continuous` when it still runs through there; otherwise with its latest page. Ignored beside `before`.",
756
+ ),
757
+ afterRow: z
758
+ .string()
759
+ .optional()
760
+ .describe("The `rowId` of the row just before `after`, as the reader holds it: how a record rewound since is told apart from one that only grew."),
753
761
  });
754
762
 
755
763
  // Fills in what a page counted instead of carrying: a delegation's own calls, addressed by the card's id, which is
@@ -871,19 +879,6 @@ export const AgentReactSchema = z.object({
871
879
  .describe("The mark to leave, as the emoji character itself. Exactly one: a chip has room for one mark, and a press is one press."),
872
880
  on: z.boolean().describe("Whether to add your mark or take it back. Saying what you want rather than flipping what is there, so pressing twice lands where pressing once did."),
873
881
  });
874
- // Bounded just above the handoff's per-message render cap, so a line too long to carry whole doesn't reach the agent
875
- // truncated.
876
- export const AgentPlaceSchema = z.object({
877
- id: z.string().min(1).describe("Which conversation."),
878
- text: z
879
- .string()
880
- .trim()
881
- .min(1)
882
- .max(8_000)
883
- .describe(
884
- "The words to put in the agent's mouth. Bounded just above what the next turn can carry whole, because a line too long to be handed over intact would reach the agent truncated and quietly break the very thing this is for.",
885
- ),
886
- });
887
882
  // `null` clears the override back to inheriting the sandbox setting, so an agent doesn't hold a frozen copy that stops
888
883
  // following it.
889
884
  export const AgentAutoLandSchema = z.object({
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ import { ConversationIdSchema } from "./agent.js";
3
+
4
+ // Attaches to a conversation's newest run (live, or finished within retention); no cursor to resume from, the head
5
+ // carries all rows. `run` names what the client was watching, so a newer run's head id tells it to catch up.
6
+ export const AttachTurnSchema = z.object({
7
+ conversationId: ConversationIdSchema.describe("Which conversation to watch."),
8
+ run: z
9
+ .string()
10
+ .optional()
11
+ .describe(
12
+ "The run you were watching. The stream opens on the conversation's newest run whatever you name: if a newer turn has started since, the head names that one instead, and its rows are that turn's.",
13
+ ),
14
+ // The next run after one the reader saw end, which the conversation's queue starts a moment after: waited for here,
15
+ // where the start is an event, rather than looked for by a client asking again on a timer.
16
+ after: z
17
+ .string()
18
+ .optional()
19
+ .describe(
20
+ "A run you already watched to its end. The stream opens on the first run after it, waiting a few seconds for one to start (the message the conversation's queue sends next) before answering that nothing runs.",
21
+ ),
22
+ });
23
+ export type AttachTurn = z.infer<typeof AttachTurnSchema>;
@@ -0,0 +1,57 @@
1
+ import { z } from "zod";
2
+
3
+ // The class of thing asking to start a session, the admission policy's key space; derived daemon-side, never sent by a
4
+ // client. Chat and loops are absent since both begin with the owner's own click.
5
+ export const WakeSourceSchema = z.enum(["schedule", "event", "listener", "webchat", "issues", "workspace", "workflow"]);
6
+ export type WakeSource = z.infer<typeof WakeSourceSchema>;
7
+ // One admission verdict the owner can configure: let it run, hold it for approval, or refuse it outright.
8
+ export const AdmissionRuleSchema = z.enum(["allow", "hold", "deny"]);
9
+ export type AdmissionRule = z.infer<typeof AdmissionRuleSchema>;
10
+ // Where a command would run; the same string means different things on each machine (rm -rf /usr is recoverable here,
11
+ // fatal on a laptop). Read with a locus (command-classes.ts CommandContext); callers must state one rather than
12
+ // default.
13
+ export const CommandLocusSchema = z.enum([
14
+ // This sandbox's own shell: a disposable container, /work a git worktree, /history every other agent's.
15
+ "sandbox",
16
+ // One of the owner's own computers, reached through the machine agent. Nothing here is disposable.
17
+ "device",
18
+ ]);
19
+ export type CommandLocus = z.infer<typeof CommandLocusSchema>;
20
+ // What kind of thing a shell command is, the command gate's key space under the admission floor; gates one command
21
+ // inside an already-running session. Six classes, chosen because each is hard or impossible to undo somewhere.
22
+ export const CommandClassSchema = z.enum([
23
+ // Rewrites or discards committed work: force-push, hard reset, force-delete a branch, clean -f, filter-branch.
24
+ "git.destructive",
25
+ // Moves a checkout to another branch. Only ever matches in a tree the conversation SHARES with its owner: inside
26
+ // its own copy a conversation may stand where it likes, and the drift that causes is reported, not refused.
27
+ "git.branch-switch",
28
+ // Recursive-force deletion (`rm -rf`), and its spelling in a script (`fs.rm(p, { recursive: true })`).
29
+ "files.destructive",
30
+ // State nothing recovers at this locus; which roots count (/, /history in the sandbox) depends on the locus.
31
+ "system.destructive",
32
+ // A container volume or its data; the sandbox's blast radius (nested engine) differs sharply from a device's.
33
+ "container.state",
34
+ // Reads credential material: a secret reference, or a file confirmed to actually hold one.
35
+ "secrets.access",
36
+ // Publishes outward and irreversibly: npm/pnpm/yarn/cargo publish, gh release create, docker push.
37
+ "package.publish",
38
+ // A network program (curl, nc, ssh, scp, …) or interpreter one-liner aimed at a non-loopback or run-time-built
39
+ // destination, the general exfiltration channel under the per-provider actionRules.
40
+ "network.outbound",
41
+ ]);
42
+ export type CommandClass = z.infer<typeof CommandClassSchema>;
43
+ // Workspace-wide admission floor per wake source, consulted on every outside-driven wake; composes with per-automation
44
+ // overrides most-restrictive-wins. `workflow` is allow|deny only, since a hold there is indistinguishable from a CI
45
+ // runner's timeout.
46
+ export const AdmissionPolicySchema = z.object({
47
+ schedule: AdmissionRuleSchema.default("allow"),
48
+ event: AdmissionRuleSchema.default("allow"),
49
+ listener: AdmissionRuleSchema.default("allow"),
50
+ webchat: AdmissionRuleSchema.default("allow"),
51
+ // Defaults to hold, unlike the others: a bug-report wake has full repo powers and a stranger's stack trace as its
52
+ // brief.
53
+ issues: AdmissionRuleSchema.default("hold"),
54
+ workspace: AdmissionRuleSchema.default("allow"),
55
+ workflow: z.enum(["allow", "deny"]).default("allow"),
56
+ });
57
+ export type AdmissionPolicy = z.infer<typeof AdmissionPolicySchema>;
@@ -0,0 +1,62 @@
1
+ import { z } from "zod";
2
+ import { CONVERSATION_ID } from "../ids/conversation-ids.js";
3
+
4
+ // HOW ONE CONVERSATION RELATES TO ANOTHER at its birth, latched on its registry entry and carried on its card: the
5
+ // conversation a fork was cut from, and the work a fresh session was opened on. Re-exported by agent.ts, whose turn
6
+ // names them on a conversation's first turn.
7
+
8
+ // agent.ts's ConversationIdSchema, spelled here rather than imported, since agent.ts re-exports this module.
9
+ const ConversationIdSchema = z.string().regex(CONVERSATION_ID);
10
+
11
+ // Where a conversation was cut from, the durable half of a fork, carried on the registry entry. `index` is the message
12
+ // the cut sat above in the source, so its transcript can put the mark back.
13
+ export const ForkedFromSchema = z.object({
14
+ conversationId: ConversationIdSchema,
15
+ index: z.number().int().nonnegative(),
16
+ // Which files this fork opened on; kept so the fork can still say it later, not only right after the click.
17
+ files: z.enum(["then", "now"]),
18
+ });
19
+ export type ForkedFrom = z.infer<typeof ForkedFromSchema>;
20
+ // A FRESH SESSION on another conversation's work: a code review, a test pass, or a person's own ask, started from that
21
+ // conversation's work as it stands now and with none of its messages. A harness's own reviewer runs this way (Claude
22
+ // Code's /code-review in a forked subagent, Codex's /review in a thread of its own) so it judges the diff rather than
23
+ // the reasoning that produced it. Its first turn names the origin; the daemon then treats it as the origin's child: cut
24
+ // from its current work, its edits going back into it, folded under its card. It is still a person's chat, never woken
25
+ // for nor waking its origin: findings reach the origin only when a person sends them.
26
+ export const FRESH_KINDS = ["review", "test", "ask"] as const;
27
+ export const FreshKindSchema = z.enum(FRESH_KINDS);
28
+ export type FreshKind = z.infer<typeof FreshKindSchema>;
29
+ export const FreshOfSchema = z.object({
30
+ conversationId: ConversationIdSchema.describe("The conversation whose work this one starts from."),
31
+ kind: FreshKindSchema.describe("What it is opened for: a code review, a test pass, or the person's own ask."),
32
+ });
33
+ export type FreshOf = z.infer<typeof FreshOfSchema>;
34
+ // The durable half, latched on the entry by the first turn and never cleared: the relationship, not a pending state.
35
+ export const FreshSessionSchema = z.object({
36
+ of: ConversationIdSchema.describe("The conversation whose work it started from."),
37
+ kind: FreshKindSchema.describe("What it was opened for: a code review, a test pass, or the person's own ask."),
38
+ at: z.number().describe("When it started, in milliseconds. Work its origin changed after this is work it has not seen."),
39
+ });
40
+ export type FreshSession = z.infer<typeof FreshSessionSchema>;
41
+
42
+ export const FRESH_OF_DESCRIPTION =
43
+ "Open this conversation on another conversation's work as it stands now, with none of that conversation's messages: for a review or a test that should judge the work, not the reasoning behind it. Its edits go back into that work. First turn only, and only on a private copy.";
44
+
45
+ // The turn's own rules for `freshOf`: a new private copy of its own, never beside a fork's copy of a chat, never on itself.
46
+ export const freshOfIssues = (
47
+ turn: { readonly freshOf?: FreshOf | undefined; readonly conversationId?: string | undefined; readonly isolated?: boolean | undefined; readonly forkOf?: unknown },
48
+ ctx: z.RefinementCtx,
49
+ ): void => {
50
+ if (turn.freshOf === undefined) {
51
+ return;
52
+ }
53
+ if (turn.conversationId === undefined || turn.isolated !== true) {
54
+ ctx.addIssue({ code: "custom", message: "freshOf requires an isolated conversationId" });
55
+ }
56
+ if (turn.forkOf !== undefined) {
57
+ ctx.addIssue({ code: "custom", message: "freshOf and forkOf are two different starts: a fork carries the conversation, a fresh session carries none of it" });
58
+ }
59
+ if (turn.freshOf.conversationId === turn.conversationId) {
60
+ ctx.addIssue({ code: "custom", message: "a conversation cannot start fresh on its own work" });
61
+ }
62
+ };
@@ -4,7 +4,7 @@
4
4
  // behaviour except for restore points: that copy grows without bound on disk. Thirty days still covers recovering a
5
5
  // deleted file; zero remains available for people who want every snapshot. The public-office preset sets the rest.
6
6
  import { z } from "zod";
7
- import type { AdmissionRule } from "./agent.js";
7
+ import type { AdmissionRule } from "./command-admission.js";
8
8
 
9
9
  export const AgentRetentionDaysSchema = z
10
10
  .number()
@@ -117,13 +117,13 @@ export type DeviceSandbox = z.infer<typeof DeviceSandboxSchema>;
117
117
  // One operation on one sandbox, streamed as lines ending in a `result` or `error` frame. `prepare` builds the pending
118
118
  // update without touching the container. `set-shape` sets its resources and privileges, now or for the next restart;
119
119
  // `forget-shape` drops a shape saved for the next restart. `start`/`restart` apply a saved shape (all through `ic`).
120
- // `reshape` is the older spelling of `set-shape`, kept one release for pages served by older sandboxes.
121
- // `runner-up`/`runner-remove` act on a runner (this sandbox's own container), not a person's sandbox; gated by the
122
- // `sandboxes` switch, not removal, since a runner holds no separate workspace to lose.
120
+ // `reshape` is `set-shape`'s older spelling, kept one release. `runner-up`/`runner-remove` act on a runner (this
121
+ // sandbox's own container); gated by the `sandboxes` switch, not removal, as a runner holds no workspace to lose.
123
122
  export const DeviceSandboxOpSchema = z.enum([
124
123
  "start",
125
124
  "stop",
126
125
  "restart",
126
+ "sleep",
127
127
  "prepare",
128
128
  // `prepare` under the unattended rules (`ic sandbox prepare --auto`): nobody pressed anything, so low disk is "not
129
129
  // now" and a pinned sandbox or the version it went back from is left alone. What the update card sends by itself
@@ -203,7 +203,7 @@ export const icShapeArgs = (slug: string, fields: SandboxShapeFields, when: Sand
203
203
  ];
204
204
  export const icForgetShapeArgs = (slug: string): string[] => ["sandbox", "shape", slug, "--forget"];
205
205
  // Power goes through ic too, so a Start or Restart from any door applies the shape saved for the next restart.
206
- export const icPowerArgs = (op: "start" | "stop" | "restart", slug: string): string[] => ["sandbox", op, slug];
206
+ export const icPowerArgs = (op: "start" | "stop" | "restart" | "sleep", slug: string): string[] => ["sandbox", op, slug];
207
207
  // Adds the device id to the flow input; the daemon looks up machines by id. `resumeTurns` is the owner saying, as they
208
208
  // restart the sandbox relaying this, that the turns it cuts should run again once it is back; the daemon keeps it for
209
209
  // its next boot and never forwards it to the machine. A sandbox older than it ignores it, and the cut turns wait.
@@ -113,6 +113,8 @@ export type DeviceFacts = z.infer<typeof DeviceFactsSchema>;
113
113
  // - `keyring`: the keyring* procedures, intentic-keyring on this computer reached through the machine (keyring.ts);
114
114
  // advertised only while a keyring is installed, so a sandbox never offers a computer without one as a place to keep or
115
115
  // type a secret.
116
+ // - `sleep`: the `sleep` op, a sandbox put to sleep now (`ic sandbox sleep <slug>`): stopped, and started again by
117
+ // itself when somebody opens it; advertised only when the agent's `ic` has `sandbox sleep`.
116
118
  export const DeviceFeatureSchema = z.enum([
117
119
  "reshape-later",
118
120
  "set-shape",
@@ -122,6 +124,7 @@ export const DeviceFeatureSchema = z.enum([
122
124
  "project-delivery",
123
125
  "programs",
124
126
  "keyring",
127
+ "sleep",
125
128
  ]);
126
129
  export type DeviceFeature = z.infer<typeof DeviceFeatureSchema>;
127
130
  export const DEVICE_FEATURE_RESHAPE_LATER: DeviceFeature = "reshape-later";
@@ -132,6 +135,7 @@ export const DEVICE_FEATURE_BACKGROUND_PREPARE: DeviceFeature = "background-prep
132
135
  export const DEVICE_FEATURE_PROJECT_DELIVERY: DeviceFeature = "project-delivery";
133
136
  export const DEVICE_FEATURE_PROGRAMS: DeviceFeature = "programs";
134
137
  export const DEVICE_FEATURE_KEYRING: DeviceFeature = "keyring";
138
+ export const DEVICE_FEATURE_SLEEP: DeviceFeature = "sleep";
135
139
  // The features an agent advertised that this build knows; an unknown one is a newer agent's and means nothing here.
136
140
  export const deviceFeatures = (facts: Pick<DeviceFacts, "features"> | undefined): DeviceFeature[] =>
137
141
  (facts?.features ?? []).flatMap((feature) => {
@@ -0,0 +1,13 @@
1
+ import { KEYRING_NAME_RE, KeyringCaptureOutcomeSchema, KeyringRefusalCodeSchema } from "./keyring.js";
2
+ import { KeyringNativeNameSchema, KeyringNativeOutcomeSchema, KeyringNativeRefusalCodeSchema } from "./keyring-native.js";
3
+
4
+ // keyring-native.ts spells three of keyring.ts's schemas again so the browser extension's bundle never reaches keyring.ts
5
+ // (and the zod namespace it imports); these hold the two spellings equal.
6
+
7
+ test("the extension's copies of keyring.ts's names, refusals and outcomes are the same", () => {
8
+ expect(KeyringNativeRefusalCodeSchema.options).toEqual(KeyringRefusalCodeSchema.options);
9
+ expect(KeyringNativeOutcomeSchema.options).toEqual(KeyringCaptureOutcomeSchema.options);
10
+ for (const name of ["GITHUB_COM", "_1PASSWORD", "a", "1BAD", "has-dash", ""]) {
11
+ expect(KeyringNativeNameSchema.safeParse(name).success).toBe(KEYRING_NAME_RE.test(name));
12
+ }
13
+ });
@@ -0,0 +1,101 @@
1
+ // Named imports rather than the `z` namespace, and nothing from schemas/keyring.ts: this module is bundled into the
2
+ // browser extension, where the namespace keeps zod's locales (~330 kB) that esbuild can otherwise drop
3
+ // (_devices/webext/scripts/size-budget.mjs holds the ceiling). The three schemas it shares with keyring.ts are spelled
4
+ // again below, and keyring-native.test.ts holds them equal.
5
+ import { array, boolean, discriminatedUnion, enum as zEnum, literal, number, object, string, union } from "zod";
6
+ import type * as z from "zod";
7
+
8
+ // What the browser extension and `intentic-keyring native-host` say to each other over Chrome's native messaging: one
9
+ // JSON message each way per request, length-prefixed by the browser, correlated by `id`. The native host is a process
10
+ // the browser starts as the person's user; it seals a captured value to the vault's inbox key before it reaches the
11
+ // keyring's pipe, and asks the keyring (which asks the person, with Windows Hello or polkit) before any value goes back
12
+ // to the page. A site's host, never a full address, is all the extension ever names.
13
+ //
14
+ // `@intentic/sandbox-contract/webext` re-exports it.
15
+
16
+ /** The name the extension connects to (`chrome.runtime.connectNative`), and the native host's manifest declares. */
17
+ export const KEYRING_NATIVE_HOST = "dev.intentic.keyring";
18
+
19
+ const id = string().min(1).max(64);
20
+ const host = string().min(1).max(253);
21
+
22
+ /** keyring.ts's secret name, refusal code and capture outcome, as the extension sees them. */
23
+ export const KeyringNativeNameSchema = string().regex(/^[A-Za-z_][A-Za-z0-9_]{0,127}$/u);
24
+ export const KeyringNativeRefusalCodeSchema = zEnum([
25
+ "no-keyring",
26
+ "locked",
27
+ "declined",
28
+ "unknown",
29
+ "not-shared",
30
+ "bad-grant",
31
+ "expired",
32
+ "replayed",
33
+ "guard",
34
+ "unavailable",
35
+ "busy",
36
+ "pending",
37
+ ]);
38
+ export const KeyringNativeOutcomeSchema = zEnum(["saved", "updated", "unchanged", "pending", "skipped"]);
39
+
40
+ export const KeyringNativeRequestSchema = discriminatedUnion("type", [
41
+ // What the extension needs before it shows anything: whether remembering is on for browsers, and the vault's state.
42
+ object({
43
+ type: literal("hello"),
44
+ id,
45
+ browser: string().min(1).max(100).describe("The browser's own name, `Brave`, for the title line."),
46
+ }).strict(),
47
+ // A sign-in, sign-up or password change the page just submitted.
48
+ object({
49
+ type: literal("capture"),
50
+ id,
51
+ browser: string().min(1).max(100),
52
+ host,
53
+ username: string().max(256).optional(),
54
+ password: string().min(1).max(4096),
55
+ title: string().max(200).optional().describe("The site's own name (`og:site_name`, the title), when it has one."),
56
+ failed: boolean().optional().describe("The form came back for the same user: the last value saved for it did not work."),
57
+ }).strict(),
58
+ // What the keyring holds for this site: names, titles and users, never values.
59
+ object({ type: literal("candidates"), id, host }).strict(),
60
+ // One entry's value for the focused field, after the person's yes at the computer.
61
+ object({ type: literal("fill"), id, host, name: KeyringNativeNameSchema }).strict(),
62
+ // Take back a capture made moments ago (the toast's Undo).
63
+ object({ type: literal("undo"), id, name: KeyringNativeNameSchema, at: number().int() }).strict(),
64
+ // Never save for this site (the toast's "Never for this site").
65
+ object({ type: literal("never"), id, host }).strict(),
66
+ ]);
67
+ export type KeyringNativeRequest = z.infer<typeof KeyringNativeRequestSchema>;
68
+
69
+ const refused = object({ ok: literal(false), code: KeyringNativeRefusalCodeSchema, refusal: string() });
70
+
71
+ export const KeyringNativeCandidateSchema = object({ name: KeyringNativeNameSchema, title: string(), username: string().optional() });
72
+ export type KeyringNativeCandidate = z.infer<typeof KeyringNativeCandidateSchema>;
73
+
74
+ // A plain union: a refusal shares its `type` with the answer it stands in for, which a discriminated union cannot hold.
75
+ export const KeyringNativeResponseSchema = union([
76
+ object({
77
+ type: literal("hello"),
78
+ id,
79
+ ok: literal(true),
80
+ setUp: boolean(),
81
+ locked: boolean(),
82
+ remember: boolean().describe("Whether the person turned on remembering for browsers."),
83
+ version: string(),
84
+ }),
85
+ object({
86
+ type: literal("capture"),
87
+ id,
88
+ ok: literal(true),
89
+ outcome: KeyringNativeOutcomeSchema,
90
+ name: KeyringNativeNameSchema.optional(),
91
+ title: string().optional(),
92
+ at: number().int(),
93
+ }),
94
+ object({ type: literal("candidates"), id, ok: literal(true), items: array(KeyringNativeCandidateSchema) }),
95
+ object({ type: literal("fill"), id, ok: literal(true), username: string().optional(), password: string() }),
96
+ object({ type: literal("undo"), id, ok: literal(true) }),
97
+ object({ type: literal("never"), id, ok: literal(true) }),
98
+ // Any request refused, under the type it was asked as.
99
+ refused.extend({ type: zEnum(["hello", "capture", "candidates", "fill", "undo", "never"]), id }),
100
+ ]);
101
+ export type KeyringNativeResponse = z.infer<typeof KeyringNativeResponseSchema>;