@phyzess/pappra 0.1.0-beta.13 → 0.1.0-beta.18

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 (357) hide show
  1. package/README.md +134 -15
  2. package/assets/integrations/skills/pappra/SKILL.md +28 -7
  3. package/assets/integrations/skills/pappra/references/collaboration.md +633 -0
  4. package/assets/integrations/skills/pappra/references/environment.md +360 -0
  5. package/assets/integrations/skills/pappra/references/hosts.md +20 -0
  6. package/assets/integrations/skills/pappra/references/operations.md +36 -5
  7. package/dist/adapters/pi/recovery-extension.d.ts +65 -0
  8. package/dist/adapters/pi/recovery-extension.js +238 -0
  9. package/dist/adapters/pi/session-transition-extension.d.ts +30 -0
  10. package/dist/adapters/pi/session-transition-extension.js +265 -0
  11. package/dist/app/automatic-handoff-events.d.ts +26 -0
  12. package/dist/app/automatic-handoff-events.js +134 -0
  13. package/dist/app/bounded-file.d.ts +2 -0
  14. package/dist/app/bounded-file.js +2 -0
  15. package/dist/app/capability-evidence/claude.d.ts +37 -0
  16. package/dist/app/capability-evidence/claude.js +206 -0
  17. package/dist/app/capability-evidence/codex.d.ts +35 -0
  18. package/dist/app/capability-evidence/codex.js +193 -0
  19. package/dist/app/capability-evidence/index.d.ts +33 -0
  20. package/dist/app/capability-evidence/index.js +117 -0
  21. package/dist/app/capability-evidence/pi.d.ts +73 -0
  22. package/dist/app/capability-evidence/pi.js +669 -0
  23. package/dist/app/capability-evidence/shared.d.ts +69 -0
  24. package/dist/app/capability-evidence/shared.js +195 -0
  25. package/dist/app/collab-auto-handoff.d.ts +55 -0
  26. package/dist/app/collab-auto-handoff.js +384 -0
  27. package/dist/app/collab-bindings.d.ts +57 -0
  28. package/dist/app/collab-bindings.js +1006 -0
  29. package/dist/app/collab-bootstrap-transport.d.ts +163 -0
  30. package/dist/app/collab-bootstrap-transport.js +769 -0
  31. package/dist/app/collab-bootstrap.d.ts +137 -0
  32. package/dist/app/collab-bootstrap.js +3455 -0
  33. package/dist/app/collab-handoff.d.ts +12 -0
  34. package/dist/app/collab-handoff.js +511 -0
  35. package/dist/app/collab-messages.d.ts +2 -0
  36. package/dist/app/collab-messages.js +2 -0
  37. package/dist/app/collab-notify.d.ts +156 -0
  38. package/dist/app/collab-notify.js +1208 -0
  39. package/dist/app/collab-preflight.d.ts +34 -0
  40. package/dist/app/collab-preflight.js +96 -0
  41. package/dist/app/collab-recovery-executor.d.ts +161 -0
  42. package/dist/app/collab-recovery-executor.js +1153 -0
  43. package/dist/app/collab-recovery-projection.d.ts +103 -0
  44. package/dist/app/collab-recovery-projection.js +659 -0
  45. package/dist/app/collab-recovery.d.ts +25 -0
  46. package/dist/app/collab-recovery.js +429 -0
  47. package/dist/app/collab-resources.d.ts +16 -0
  48. package/dist/app/collab-resources.js +278 -0
  49. package/dist/app/collab-role-events.d.ts +22 -0
  50. package/dist/app/collab-role-events.js +329 -0
  51. package/dist/app/collab-role-orchestration.d.ts +53 -0
  52. package/dist/app/collab-role-orchestration.js +601 -0
  53. package/dist/app/collab-role-plan.d.ts +81 -0
  54. package/dist/app/collab-role-plan.js +504 -0
  55. package/dist/app/collab-role-repair.d.ts +109 -0
  56. package/dist/app/collab-role-repair.js +821 -0
  57. package/dist/app/collab-rollover.d.ts +263 -0
  58. package/dist/app/collab-rollover.js +1112 -0
  59. package/dist/app/collab-route.d.ts +64 -0
  60. package/dist/app/collab-route.js +240 -0
  61. package/dist/app/collab-session-transition.d.ts +221 -0
  62. package/dist/app/collab-session-transition.js +3334 -0
  63. package/dist/app/collab-state.d.ts +7 -0
  64. package/dist/app/collab-state.js +162 -0
  65. package/dist/app/collab-task-store.d.ts +22 -0
  66. package/dist/app/collab-task-store.js +204 -0
  67. package/dist/app/collab-work-execution.d.ts +127 -0
  68. package/dist/app/collab-work-execution.js +1027 -0
  69. package/dist/app/collab-work-plan.d.ts +87 -0
  70. package/dist/app/collab-work-plan.js +437 -0
  71. package/dist/app/collaboration.d.ts +8 -2
  72. package/dist/app/collaboration.js +101 -12
  73. package/dist/app/doctor.js +108 -5
  74. package/dist/app/host-mcp.js +34 -8
  75. package/dist/app/host-probe.js +4 -4
  76. package/dist/app/init.d.ts +58 -4
  77. package/dist/app/init.js +768 -155
  78. package/dist/app/managed-pi-bootstrap-admission.d.ts +14 -0
  79. package/dist/app/managed-pi-bootstrap-admission.js +104 -0
  80. package/dist/app/managed-pi-bootstrap-refresh.d.ts +10 -0
  81. package/dist/app/managed-pi-bootstrap-refresh.js +78 -0
  82. package/dist/app/managed-pi-delivery.d.ts +8 -0
  83. package/dist/app/managed-pi-delivery.js +110 -0
  84. package/dist/app/managed-pi-handoff-receiver.d.ts +15 -0
  85. package/dist/app/managed-pi-handoff-receiver.js +263 -0
  86. package/dist/app/managed-pi-handoff-reference.d.ts +3 -0
  87. package/dist/app/managed-pi-handoff-reference.js +60 -0
  88. package/dist/app/managed-pi-herdr.d.ts +21 -0
  89. package/dist/app/managed-pi-herdr.js +185 -0
  90. package/dist/app/managed-pi-initial-admission.d.ts +28 -0
  91. package/dist/app/managed-pi-initial-admission.js +416 -0
  92. package/dist/app/managed-pi-initial-launch.d.ts +5 -0
  93. package/dist/app/managed-pi-initial-launch.js +61 -0
  94. package/dist/app/managed-pi-native-observation.d.ts +36 -0
  95. package/dist/app/managed-pi-native-observation.js +191 -0
  96. package/dist/app/managed-pi-readiness.d.ts +29 -0
  97. package/dist/app/managed-pi-readiness.js +288 -0
  98. package/dist/app/managed-pi-repair-stop.d.ts +21 -0
  99. package/dist/app/managed-pi-repair-stop.js +371 -0
  100. package/dist/app/managed-pi-resume-admission.d.ts +32 -0
  101. package/dist/app/managed-pi-resume-admission.js +618 -0
  102. package/dist/app/managed-pi-retirement.d.ts +28 -0
  103. package/dist/app/managed-pi-retirement.js +112 -0
  104. package/dist/app/managed-pi-sdk-control.d.ts +7 -0
  105. package/dist/app/managed-pi-sdk-control.js +169 -0
  106. package/dist/app/managed-pi-sdk-runtime.d.ts +3 -0
  107. package/dist/app/managed-pi-sdk-runtime.js +483 -0
  108. package/dist/app/managed-pi-source-admission.d.ts +14 -0
  109. package/dist/app/managed-pi-source-admission.js +323 -0
  110. package/dist/app/managed-pi-transition-host.d.ts +36 -0
  111. package/dist/app/managed-pi-transition-host.js +292 -0
  112. package/dist/app/managed-pi.d.ts +54 -0
  113. package/dist/app/managed-pi.js +248 -0
  114. package/dist/app/shell-readiness.d.ts +66 -0
  115. package/dist/app/shell-readiness.js +368 -0
  116. package/dist/app/task-pin.d.ts +2 -23
  117. package/dist/app/task-pin.js +2 -113
  118. package/dist/cli/commands/collaboration-binding.d.ts +13 -0
  119. package/dist/cli/commands/collaboration-binding.js +118 -0
  120. package/dist/cli/commands/collaboration-bootstrap.d.ts +10 -0
  121. package/dist/cli/commands/collaboration-bootstrap.js +84 -0
  122. package/dist/cli/commands/collaboration-capabilities.d.ts +13 -0
  123. package/dist/cli/commands/collaboration-capabilities.js +127 -0
  124. package/dist/cli/commands/collaboration-handoff.d.ts +13 -0
  125. package/dist/cli/commands/collaboration-handoff.js +102 -0
  126. package/dist/cli/commands/collaboration-message.d.ts +17 -0
  127. package/dist/cli/commands/collaboration-message.js +177 -0
  128. package/dist/cli/commands/collaboration-plan.d.ts +8 -0
  129. package/dist/cli/commands/collaboration-plan.js +108 -0
  130. package/dist/cli/commands/collaboration-preflight.d.ts +10 -0
  131. package/dist/cli/commands/collaboration-preflight.js +167 -0
  132. package/dist/cli/commands/collaboration-recovery-run.d.ts +46 -0
  133. package/dist/cli/commands/collaboration-recovery-run.js +224 -0
  134. package/dist/cli/commands/collaboration-recovery.d.ts +11 -0
  135. package/dist/cli/commands/collaboration-recovery.js +104 -0
  136. package/dist/cli/commands/collaboration-resources.d.ts +11 -0
  137. package/dist/cli/commands/collaboration-resources.js +96 -0
  138. package/dist/cli/commands/collaboration-role-plan.d.ts +9 -0
  139. package/dist/cli/commands/collaboration-role-plan.js +69 -0
  140. package/dist/cli/commands/collaboration-role-run.d.ts +11 -0
  141. package/dist/cli/commands/collaboration-role-run.js +128 -0
  142. package/dist/cli/commands/collaboration-rollover.d.ts +10 -0
  143. package/dist/cli/commands/collaboration-rollover.js +103 -0
  144. package/dist/cli/commands/collaboration-state.d.ts +10 -0
  145. package/dist/cli/commands/collaboration-state.js +96 -0
  146. package/dist/cli/commands/collaboration-transition.d.ts +10 -0
  147. package/dist/cli/commands/collaboration-transition.js +75 -0
  148. package/dist/cli/commands/collaboration-work-run.d.ts +34 -0
  149. package/dist/cli/commands/collaboration-work-run.js +178 -0
  150. package/dist/cli/commands/collaboration.d.ts +4 -0
  151. package/dist/cli/commands/collaboration.js +39 -4
  152. package/dist/cli/commands/continuity.js +2 -6
  153. package/dist/cli/commands/docs.d.ts +2 -0
  154. package/dist/cli/commands/docs.js +89 -15
  155. package/dist/cli/commands/host.d.ts +7 -1
  156. package/dist/cli/commands/host.js +122 -7
  157. package/dist/cli/commands/init.d.ts +20 -3
  158. package/dist/cli/commands/init.js +897 -232
  159. package/dist/cli/commands/mcp.d.ts +1 -0
  160. package/dist/cli/commands/mcp.js +11 -5
  161. package/dist/cli/commands/repair.d.ts +12 -0
  162. package/dist/cli/commands/repair.js +41 -0
  163. package/dist/cli/commands/runtime.d.ts +1 -1
  164. package/dist/cli/commands/runtime.js +139 -38
  165. package/dist/cli/commands/session.d.ts +7 -0
  166. package/dist/cli/commands/session.js +82 -0
  167. package/dist/cli/commands/task.js +19 -5
  168. package/dist/cli/run.js +866 -24
  169. package/dist/code/identity.d.ts +7 -0
  170. package/dist/code/identity.js +7 -3
  171. package/dist/code/registration.js +7 -0
  172. package/dist/code/service.d.ts +9 -0
  173. package/dist/code/service.js +16 -3
  174. package/dist/code/text.js +19 -7
  175. package/dist/collab/admission.d.ts +91 -66
  176. package/dist/collab/admission.js +21 -6
  177. package/dist/collab/canonical.d.ts +1 -1
  178. package/dist/collab/canonical.js +44 -3
  179. package/dist/collab/envelope.d.ts +2 -2
  180. package/dist/collab/envelope.js +12 -12
  181. package/dist/collab/first-work.d.ts +3 -0
  182. package/dist/collab/first-work.js +15 -0
  183. package/dist/collab/handoff.d.ts +16 -0
  184. package/dist/collab/handoff.js +39 -5
  185. package/dist/collab/index.d.ts +97 -1
  186. package/dist/collab/index.js +9 -1
  187. package/dist/collab/messages.js +126 -3
  188. package/dist/collab/persisted-messages.d.ts +123 -0
  189. package/dist/collab/persisted-messages.js +496 -0
  190. package/dist/collab/preflight.d.ts +1 -1
  191. package/dist/collab/resources.d.ts +13 -3
  192. package/dist/collab/resources.js +37 -6
  193. package/dist/collab/rollover.d.ts +311 -0
  194. package/dist/collab/rollover.js +1024 -0
  195. package/dist/collab/store.d.ts +1 -0
  196. package/dist/collab/store.js +1 -4
  197. package/dist/collab/types.d.ts +2 -354
  198. package/dist/collab/validation.d.ts +2 -10
  199. package/dist/collab/validation.js +2 -303
  200. package/dist/collab/work-plan.d.ts +105 -0
  201. package/dist/collab/work-plan.js +843 -0
  202. package/dist/continuity/context.d.ts +11 -2
  203. package/dist/continuity/context.js +100 -13
  204. package/dist/continuity/handoff-bundle.d.ts +296 -0
  205. package/dist/continuity/handoff-bundle.js +477 -0
  206. package/dist/continuity/index.d.ts +2 -0
  207. package/dist/continuity/index.js +1 -0
  208. package/dist/continuity/paths.js +10 -2
  209. package/dist/continuity/service.js +91 -15
  210. package/dist/continuity/task-pin.d.ts +24 -0
  211. package/dist/continuity/task-pin.js +590 -0
  212. package/dist/doctor.d.ts +1 -0
  213. package/dist/doctor.js +6 -0
  214. package/dist/experimental/index.d.ts +13 -0
  215. package/dist/experimental/index.js +25 -0
  216. package/dist/experimental/pi.d.ts +4 -0
  217. package/dist/experimental/pi.js +12 -0
  218. package/dist/hosts/claude/native.js +1 -1
  219. package/dist/hosts/codex/native.js +1 -1
  220. package/dist/hosts/codex/protocol.js +1 -1
  221. package/dist/hosts/integration/bootstrap-config.d.ts +58 -0
  222. package/dist/hosts/integration/bootstrap-config.js +254 -0
  223. package/dist/hosts/integration/bundle-export.d.ts +44 -0
  224. package/dist/hosts/integration/bundle-export.js +366 -3
  225. package/dist/hosts/integration/bundle.js +3 -0
  226. package/dist/hosts/integration/hook.js +36 -9
  227. package/dist/hosts/integration/pappra-bootstrap-extension.mjs +80 -0
  228. package/dist/hosts/integration/pappra-extension-runtime.mjs +59 -24631
  229. package/dist/hosts/integration/pappra-hook.mjs +61 -24749
  230. package/dist/hosts/integration/pappra-recovery-extension.mjs +259 -0
  231. package/dist/hosts/integration/pappra-session-transition-extension.mjs +276 -0
  232. package/dist/hosts/integration/pi-bootstrap-extension.d.ts +36 -0
  233. package/dist/hosts/integration/pi-bootstrap-extension.js +101 -0
  234. package/dist/hosts/integration/pi-bootstrap-guard.d.ts +125 -0
  235. package/dist/hosts/integration/pi-bootstrap-guard.js +438 -0
  236. package/dist/hosts/integration/pi-bootstrap-runtime.d.ts +63 -0
  237. package/dist/hosts/integration/pi-bootstrap-runtime.js +223 -0
  238. package/dist/hosts/integration/pi-native-events.d.ts +112 -0
  239. package/dist/hosts/integration/pi-native-events.js +348 -0
  240. package/dist/hosts/integration/pi-rollover-extension.d.ts +166 -0
  241. package/dist/hosts/integration/pi-rollover-extension.js +431 -0
  242. package/dist/hosts/integration/recovery-config.d.ts +48 -0
  243. package/dist/hosts/integration/recovery-config.js +117 -0
  244. package/dist/hosts/integration/service.d.ts +6 -1
  245. package/dist/hosts/integration/service.js +485 -35
  246. package/dist/hosts/integration/support.d.ts +7 -0
  247. package/dist/hosts/integration/support.js +9 -1
  248. package/dist/hosts/integration/templates.d.ts +3 -0
  249. package/dist/hosts/integration/templates.js +26 -3
  250. package/dist/hosts/pi/managed-host-identity.d.ts +2 -0
  251. package/dist/hosts/pi/managed-host-identity.js +40 -0
  252. package/dist/hosts/pi/managed-provider-diagnostics.d.ts +6 -0
  253. package/dist/hosts/pi/managed-provider-diagnostics.js +184 -0
  254. package/dist/hosts/pi/managed-sdk-session.d.ts +335 -0
  255. package/dist/hosts/pi/managed-sdk-session.js +1639 -0
  256. package/dist/hosts/pi/managed-session-extension.d.ts +20 -0
  257. package/dist/hosts/pi/managed-session-extension.js +84 -0
  258. package/dist/hosts/pi/managed-session.d.ts +177 -0
  259. package/dist/hosts/pi/managed-session.js +1557 -0
  260. package/dist/hosts/pi/protocol.js +1 -1
  261. package/dist/hosts/pi/query-result.js +1 -1
  262. package/dist/hosts/pi/resume-capability.d.ts +41 -0
  263. package/dist/hosts/pi/resume-capability.js +33 -0
  264. package/dist/hosts/pi/rpc.d.ts +182 -134
  265. package/dist/hosts/pi/rpc.js +230 -37
  266. package/dist/hosts/pilot.d.ts +97 -74
  267. package/dist/hosts/pilot.js +5 -1
  268. package/dist/hosts/version.d.ts +3 -0
  269. package/dist/hosts/version.js +18 -0
  270. package/dist/index.d.ts +0 -1
  271. package/dist/index.js +0 -1
  272. package/dist/infra/bounded-file.d.ts +19 -0
  273. package/dist/infra/bounded-file.js +66 -0
  274. package/dist/infra/fs.js +10 -2
  275. package/dist/infra/git.d.ts +29 -0
  276. package/dist/infra/git.js +45 -9
  277. package/dist/infra/json-property.d.ts +2 -0
  278. package/dist/infra/json-property.js +69 -0
  279. package/dist/infra/json.d.ts +4 -0
  280. package/dist/infra/json.js +24 -0
  281. package/dist/infra/owned-process-group.js +1 -1
  282. package/dist/infra/private-lock.d.ts +16 -0
  283. package/dist/infra/private-lock.js +148 -0
  284. package/dist/infra/private-state.d.ts +7 -0
  285. package/dist/infra/private-state.js +146 -0
  286. package/dist/infra/process-identity.d.ts +12 -0
  287. package/dist/infra/process-identity.js +142 -0
  288. package/dist/infra/validation.d.ts +5 -0
  289. package/dist/infra/validation.js +15 -0
  290. package/dist/init.d.ts +1 -0
  291. package/dist/init.js +6 -0
  292. package/dist/install/apply.d.ts +9 -1
  293. package/dist/install/apply.js +176 -12
  294. package/dist/install/dependencies.d.ts +38 -0
  295. package/dist/install/dependencies.js +282 -0
  296. package/dist/install/ownership.js +30 -1
  297. package/dist/install/references.d.ts +31 -0
  298. package/dist/install/references.js +208 -0
  299. package/dist/install/repair.d.ts +37 -0
  300. package/dist/install/repair.js +798 -0
  301. package/dist/install/reset-local.d.ts +16 -0
  302. package/dist/install/reset-local.js +304 -0
  303. package/dist/install/rollback.d.ts +3 -0
  304. package/dist/install/rollback.js +9 -3
  305. package/dist/install/runtime.d.ts +10 -6
  306. package/dist/install/runtime.js +299 -59
  307. package/dist/install/source-fingerprint.d.ts +2 -0
  308. package/dist/install/source-fingerprint.js +103 -0
  309. package/dist/knowledge/catalog.d.ts +1 -0
  310. package/dist/knowledge/catalog.js +143 -10
  311. package/dist/knowledge/journal.js +17 -7
  312. package/dist/knowledge/paths.js +2 -1
  313. package/dist/knowledge/refs.js +4 -0
  314. package/dist/knowledge/register-batch.d.ts +4 -0
  315. package/dist/knowledge/register-batch.js +225 -0
  316. package/dist/knowledge/relocate.d.ts +5 -0
  317. package/dist/knowledge/relocate.js +92 -0
  318. package/dist/knowledge/scan.js +103 -47
  319. package/dist/knowledge/service.d.ts +3 -0
  320. package/dist/knowledge/service.js +33 -1
  321. package/dist/knowledge/write.d.ts +4 -1
  322. package/dist/knowledge/write.js +1 -1
  323. package/dist/mcp/server.d.ts +4 -2
  324. package/dist/mcp/server.js +87 -136
  325. package/dist/schemas/collaboration-state-validation.d.ts +6 -0
  326. package/dist/schemas/collaboration-state-validation.js +342 -0
  327. package/dist/schemas/collaboration-state.d.ts +436 -0
  328. package/dist/schemas/collaboration-state.js +1 -0
  329. package/dist/schemas/collaboration.d.ts +335 -0
  330. package/dist/schemas/collaboration.js +272 -0
  331. package/dist/schemas/continuity.d.ts +8 -0
  332. package/dist/schemas/continuity.js +13 -3
  333. package/dist/schemas/doctor.d.ts +1 -0
  334. package/dist/schemas/doctor.js +1 -0
  335. package/dist/schemas/document.d.ts +61 -0
  336. package/dist/schemas/document.js +9 -0
  337. package/dist/schemas/errors.d.ts +1 -0
  338. package/dist/schemas/errors.js +1 -0
  339. package/dist/schemas/host.d.ts +24 -0
  340. package/dist/schemas/host.js +19 -0
  341. package/dist/schemas/install.d.ts +8 -2
  342. package/dist/schemas/install.js +11 -1
  343. package/dist/schemas/managed-pi-execution.d.ts +16 -0
  344. package/dist/schemas/managed-pi-execution.js +2 -0
  345. package/dist/schemas/outcome.d.ts +9 -5
  346. package/dist/workspace/config-file.js +1 -3
  347. package/dist/workspace/documents.js +12 -2
  348. package/dist/workspace/repositories.d.ts +7 -0
  349. package/dist/workspace/repositories.js +14 -5
  350. package/package.json +35 -35
  351. package/skills/pappra/SKILL.md +28 -7
  352. package/skills/pappra/references/collaboration.md +633 -0
  353. package/skills/pappra/references/environment.md +360 -0
  354. package/skills/pappra/references/hosts.md +20 -0
  355. package/skills/pappra/references/operations.md +36 -5
  356. package/dist/app/collab-from.d.ts +0 -35
  357. package/dist/app/collab-from.js +0 -84
@@ -1,4 +1,4 @@
1
- import { errorCode, object, parseJson } from '../../collab/validation.js';
1
+ import { errorCode, object, parseJson } from '../../infra/validation.js';
2
2
  import { isAssignment } from '../../collab/contracts.js';
3
3
  import { isPiRecord } from './protocol.js';
4
4
  function errorDetail(error) {
@@ -15,6 +15,7 @@ import { admitLaunch, claimCovers, classifyIdentity, hasPendingCancellation, res
15
15
  import { describeResource } from '../../collab/canonical.js';
16
16
  import { buildMessage, sha256File } from '../../collab/envelope.js';
17
17
  import { submitMessage } from '../../collab/messages.js';
18
+ import { readMessageFromTaskRoot } from '../../collab/persisted-messages.js';
18
19
  import { findAttempt } from '../../collab/lifecycle.js';
19
20
  import { createNonce, nowIso, readRecord } from '../../collab/store.js';
20
21
  // Gated, owned Pi RPC lifecycle. One launch, one frozen prompt, repeated native queries and an
@@ -37,14 +38,19 @@ import { createNonce, nowIso, readRecord } from '../../collab/store.js';
37
38
  const RPC_SCHEMA = 'harness-collab/pi-rpc/1';
38
39
  const EXECUTION_SCHEMA = 'harness-collab/native-execution/1';
39
40
  const DEFAULT_REQUEST_TIMEOUT_MS = 15000;
40
- const DEFAULT_OPERATION_TIMEOUT_MS = 120000;
41
+ const DEFAULT_OPERATION_TIMEOUT_MS = 30 * 60 * 1000;
41
42
  const DEFAULT_SHUTDOWN_TIMEOUT_MS = 5000;
42
43
  const DEFAULT_SIGNAL_GRACE_MS = 2000;
43
44
  const DEFAULT_STREAM_CLOSE_GRACE_MS = 500;
44
45
  const DEFAULT_MAX_BYTES = 16 * 1024 * 1024;
46
+ const DEFAULT_MAX_LOG_BYTES = 16 * 1024 * 1024;
47
+ const MAX_CAPTURE_BYTES = 256 * 1024 * 1024;
48
+ const MAX_RETAINED_RECORDS = 256;
49
+ const MAX_RETAINED_BYTES = 1024 * 1024;
50
+ const MAX_REQUESTS = 4096;
45
51
  const DEFAULT_MAX_STDERR_BYTES = 64 * 1024;
46
52
  const MAX_REQUEST_TIMEOUT_MS = 60000;
47
- const MAX_OPERATION_TIMEOUT_MS = 600000;
53
+ const MAX_OPERATION_TIMEOUT_MS = 24 * 60 * 60 * 1000;
48
54
  const MAX_PROMPT_BYTES = 20000;
49
55
  const HEADER_READ_BYTES = 64 * 1024;
50
56
  const PHASES = new Set([
@@ -127,10 +133,16 @@ function attachTransport(child, options = {}) {
127
133
  const decoder = new StringDecoder('utf8');
128
134
  const records = [];
129
135
  const pending = new Map();
136
+ const expiredRequests = new Map();
130
137
  const eventWaiters = [];
131
138
  let drainQueue = [];
132
139
  let text = '';
133
140
  let bytes = 0;
141
+ let recordCount = 0;
142
+ let retainedBytes = 0;
143
+ let historyTruncated = false;
144
+ let lateResponses = 0;
145
+ let lastSettled = null;
134
146
  let stderrBytes = 0;
135
147
  const stderrChunks = [];
136
148
  let sequence = 0;
@@ -169,10 +181,16 @@ function attachTransport(child, options = {}) {
169
181
  resolve();
170
182
  }
171
183
  function findRecord(predicate, fromOrdinal) {
172
- for (let index = fromOrdinal; index < records.length; index += 1) {
173
- if (predicate(records[index], index))
174
- return { record: records[index], ordinal: index };
184
+ for (const found of records) {
185
+ if (found.ordinal >= fromOrdinal &&
186
+ predicate(found.record, found.ordinal))
187
+ return found;
175
188
  }
189
+ // The only awaited lifecycle event must survive noisy tool/token traffic.
190
+ if (lastSettled &&
191
+ lastSettled.ordinal >= fromOrdinal &&
192
+ predicate(lastSettled.record, lastSettled.ordinal))
193
+ return lastSettled;
176
194
  return null;
177
195
  }
178
196
  function settleWaiters() {
@@ -197,6 +215,8 @@ function attachTransport(child, options = {}) {
197
215
  }
198
216
  }
199
217
  function handleLine(line) {
218
+ if (fatal)
219
+ return;
200
220
  const trimmed = line.endsWith('\r') ? line.slice(0, -1) : line;
201
221
  if (!trimmed.length)
202
222
  return;
@@ -221,10 +241,27 @@ function attachTransport(child, options = {}) {
221
241
  fail('invalid', 'malformed_record', 'a stdout record is not a JSON object');
222
242
  return;
223
243
  }
224
- records.push(record);
244
+ const ordinal = recordCount++;
245
+ const recordBytes = Buffer.byteLength(trimmed);
246
+ records.push({ record, ordinal, bytes: recordBytes });
247
+ retainedBytes += recordBytes;
248
+ if (record.type === 'agent_settled')
249
+ lastSettled = { record: { type: 'agent_settled' }, ordinal };
250
+ while (records.length > MAX_RETAINED_RECORDS ||
251
+ retainedBytes > MAX_RETAINED_BYTES) {
252
+ retainedBytes -= records.shift().bytes;
253
+ historyTruncated = true;
254
+ }
225
255
  if (record.type === 'response') {
226
256
  const waiter = record.id !== undefined ? pending.get(record.id) : null;
227
257
  if (!waiter) {
258
+ if (record.id !== undefined &&
259
+ expiredRequests.get(record.id) === record.command) {
260
+ expiredRequests.delete(record.id);
261
+ lateResponses++;
262
+ settleWaiters();
263
+ return;
264
+ }
228
265
  fail('invalid', record.command === 'parse'
229
266
  ? 'rpc_parse_error'
230
267
  : 'unexpected_response_id', `a response arrived for ${record.id ?? 'no request id'}`);
@@ -299,19 +336,27 @@ function attachTransport(child, options = {}) {
299
336
  child.stdin.on('drain', flushDrains);
300
337
  child.stdout.on('data', (chunk) => {
301
338
  bytes += chunk.length;
302
- if (bytes > maxBytes) {
303
- fail('invalid', 'rpc_response_too_large', `${bytes} bytes of stdout exceeds ${maxBytes}`);
304
- child.kill('SIGKILL');
339
+ if (fatal)
305
340
  return;
306
- }
307
341
  text += decoder.write(chunk);
308
342
  let index = text.indexOf('\n');
309
343
  while (index !== -1) {
310
344
  const line = text.slice(0, index);
311
345
  text = text.slice(index + 1);
346
+ if (Buffer.byteLength(line) > maxBytes)
347
+ break;
312
348
  handleLine(line);
349
+ if (fatal) {
350
+ text = '';
351
+ return;
352
+ }
313
353
  index = text.indexOf('\n');
314
354
  }
355
+ if (index !== -1 || Buffer.byteLength(text) > maxBytes) {
356
+ fail('invalid', 'rpc_response_too_large', `one stdout record exceeds ${maxBytes} bytes`);
357
+ text = '';
358
+ child.kill('SIGKILL');
359
+ }
315
360
  });
316
361
  child.stderr.on('data', (chunk) => {
317
362
  if (stderrBytes < maxStderrBytes)
@@ -346,11 +391,14 @@ function attachTransport(child, options = {}) {
346
391
  return Promise.reject(fatal);
347
392
  if (streamsClosed)
348
393
  return Promise.reject(new PiRpcRefusal('rpc_exited_early', 'needs_input'));
394
+ if (sequence >= MAX_REQUESTS)
395
+ return Promise.reject(new PiRpcRefusal('rpc_request_limit', 'needs_input'));
349
396
  const id = `pirpc-${nonce}-${sequence}`;
350
397
  sequence += 1;
351
398
  return new Promise((resolve, reject) => {
352
399
  const timer = setTimeout(() => {
353
400
  pending.delete(id);
401
+ expiredRequests.set(id, type);
354
402
  reject(new PiRpcRefusal('rpc_response_deadline', 'needs_input', `no response to ${type} within ${timeoutMs}ms`));
355
403
  }, timeoutMs);
356
404
  pending.set(id, { type, resolve, reject, timer });
@@ -370,6 +418,8 @@ function attachTransport(child, options = {}) {
370
418
  return Promise.reject(fatal);
371
419
  if (streamsClosed)
372
420
  return Promise.reject(new PiRpcRefusal('rpc_exited_early', 'needs_input'));
421
+ if (eventWaiters.length >= MAX_RETAINED_RECORDS)
422
+ return Promise.reject(new PiRpcRefusal('rpc_waiter_limit', 'needs_input'));
373
423
  return new Promise((resolve, reject) => {
374
424
  const timer = setTimeout(() => {
375
425
  const index = eventWaiters.findIndex((waiter) => waiter.resolve === resolve);
@@ -441,8 +491,17 @@ function attachTransport(child, options = {}) {
441
491
  };
442
492
  }
443
493
  return {
444
- records,
445
- recordCount: () => records.length,
494
+ recordCount: () => recordCount,
495
+ capture: () => ({
496
+ stdout_bytes: bytes,
497
+ received_records: recordCount,
498
+ retained_records: records.length,
499
+ retained_bytes: retainedBytes,
500
+ history_truncated: historyTruncated,
501
+ late_responses: lateResponses,
502
+ stderr_bytes: stderrBytes,
503
+ stderr_truncated: stderrBytes > maxStderrBytes,
504
+ }),
446
505
  fatal: () => fatal,
447
506
  parentExited: () => declared(),
448
507
  streamsDetached: () => streamsDetached,
@@ -652,6 +711,18 @@ export async function startOwnedPiRpc(options) {
652
711
  stop_scope: 'owned RPC child only; no arbitrary background or descendant stop guarantee',
653
712
  };
654
713
  let namespaceLost = false;
714
+ let logBytes = 0;
715
+ let omittedLogRecords = 0;
716
+ const logCapture = () => ({
717
+ max_bytes: opts.maxLogBytes,
718
+ written_bytes: logBytes,
719
+ omitted_records: omittedLogRecords,
720
+ complete: omittedLogRecords === 0 &&
721
+ !namespaceLost &&
722
+ rpc.fatal() === null &&
723
+ rpc.parentExited() &&
724
+ !rpc.streamsDetached(),
725
+ });
655
726
  const rpc = attachTransport(child, {
656
727
  requestTimeoutMs: opts.requestTimeoutMs,
657
728
  shutdownTimeoutMs: opts.shutdownTimeoutMs,
@@ -661,6 +732,11 @@ export async function startOwnedPiRpc(options) {
661
732
  onRecord: (line) => {
662
733
  if (namespaceLost)
663
734
  return;
735
+ const lineBytes = Buffer.byteLength(line) + 1;
736
+ if (omittedLogRecords > 0 || logBytes + lineBytes > opts.maxLogBytes) {
737
+ omittedLogRecords++;
738
+ return;
739
+ }
664
740
  try {
665
741
  assertNamespaceGuard(opts);
666
742
  }
@@ -670,9 +746,11 @@ export async function startOwnedPiRpc(options) {
670
746
  }
671
747
  try {
672
748
  fs.appendFileSync(artifacts.eventsFile, `${line}\n`);
749
+ logBytes += lineBytes;
673
750
  }
674
- catch {
751
+ catch (error) {
675
752
  namespaceLost = true;
753
+ throw new PiRpcRefusal('evidence_write_failed', 'failed', errorDetail(error));
676
754
  }
677
755
  },
678
756
  });
@@ -684,15 +762,18 @@ export async function startOwnedPiRpc(options) {
684
762
  let lastPromptOrdinal = 0;
685
763
  let operationError = null;
686
764
  let finishPromise = null;
765
+ let operationTimer;
687
766
  const setOperationError = (error) => {
688
767
  operationError = operationError ?? error;
689
768
  };
690
- async function request(type, fields = {}) {
769
+ async function request(type, fields = {}, cleanup = false) {
691
770
  const remaining = opts.deadlineAt - Date.now();
692
- if (remaining <= 0)
771
+ if (!cleanup && remaining <= 0)
693
772
  throw new PiRpcRefusal('operation_deadline', 'needs_input');
694
773
  return rpc.request(type, fields, {
695
- timeoutMs: Math.min(opts.requestTimeoutMs, remaining),
774
+ timeoutMs: cleanup
775
+ ? opts.requestTimeoutMs
776
+ : Math.min(opts.requestTimeoutMs, remaining),
696
777
  });
697
778
  }
698
779
  /** Bound an event wait by the remaining total operation budget as well as its own limit. */
@@ -776,13 +857,78 @@ export async function startOwnedPiRpc(options) {
776
857
  }
777
858
  }
778
859
  }
860
+ async function verifyCancellationIntent(intent) {
861
+ if (intent === null ||
862
+ typeof intent !== 'object' ||
863
+ typeof intent.messageId !== 'string' ||
864
+ intent.messageId.trim() === '' ||
865
+ typeof intent.contentDigest !== 'string' ||
866
+ typeof intent.fileDigest !== 'string' ||
867
+ !/^sha256:[0-9a-f]{64}$/.test(intent.contentDigest) ||
868
+ !/^sha256:[0-9a-f]{64}$/.test(intent.fileDigest))
869
+ throw new PiRpcRefusal('cancel_intent_reference_invalid', 'needs_input');
870
+ assertNamespaceGuard(opts);
871
+ assertCurrentAuthority({ requireResources: false });
872
+ const registered = await readMessageFromTaskRoot(opts.taskRoot, intent.messageId);
873
+ if (!registered.ok)
874
+ throw new PiRpcRefusal('cancel_intent_not_registered', 'needs_input', registered.code);
875
+ assertNamespaceGuard(opts);
876
+ const { message, entry, digest } = registered.value;
877
+ const record = readRecord(opts.taskRoot);
878
+ const attempt = record
879
+ ? findAttempt(record, opts.assignmentId, opts.attempt)
880
+ : null;
881
+ const coordinator = record?.coordinator ?? null;
882
+ const assignee = attempt?.assignee ?? null;
883
+ const sameIdentity = (left, right) => left !== null &&
884
+ left !== undefined &&
885
+ right !== null &&
886
+ right !== undefined &&
887
+ left.agent_id === right.agent_id &&
888
+ left.session_id === right.session_id &&
889
+ (left.harness ?? null) === (right.harness ?? null);
890
+ if (digest !== intent.fileDigest ||
891
+ message.message_id !== intent.messageId ||
892
+ message.content_digest !== intent.contentDigest ||
893
+ message.type !== 'CANCEL' ||
894
+ message.task_id !== opts.assignment.task_id ||
895
+ message.subtask_id !== opts.assignmentId ||
896
+ message.attempt !== opts.attempt ||
897
+ message.owner_epoch !== opts.assignment.coordinator.owner_epoch ||
898
+ message.owner_epoch !== protocol.ownerEpoch ||
899
+ entry === null ||
900
+ entry.message_id !== message.message_id ||
901
+ entry.type !== 'CANCEL' ||
902
+ entry.state !== 'applied' ||
903
+ entry.subtask_id !== message.subtask_id ||
904
+ entry.attempt !== message.attempt ||
905
+ entry.owner_epoch !== message.owner_epoch ||
906
+ entry.content_digest !== intent.contentDigest ||
907
+ !sameIdentity(entry.from, message.from) ||
908
+ !sameIdentity(entry.to, message.to) ||
909
+ record === null ||
910
+ record.task_id !== message.task_id ||
911
+ coordinator === null ||
912
+ coordinator.owner_epoch !== message.owner_epoch ||
913
+ !sameIdentity(coordinator, message.from) ||
914
+ !sameIdentity(coordinator, protocol.coordinator) ||
915
+ !sameIdentity(coordinator, opts.assignment.coordinator) ||
916
+ assignee === null ||
917
+ !sameIdentity(assignee, message.to) ||
918
+ !sameIdentity(assignee, opts.assignment.assignee) ||
919
+ !sameIdentity(assignee, protocol.assignee))
920
+ throw new PiRpcRefusal('cancel_intent_mismatch', 'needs_input');
921
+ assertNamespaceGuard(opts);
922
+ assertCurrentAuthority({ requireResources: false });
923
+ return { message, fileDigest: digest };
924
+ }
779
925
  /**
780
926
  * Read `get_state` and bind the exact native session file. The id alone is not enough: the
781
927
  * reported file must exist, its header must carry the contracted id and cwd, and once bound it
782
928
  * may not switch to a different path.
783
929
  */
784
- async function assertIdentity({ requireBinding = false } = {}) {
785
- const response = await request('get_state');
930
+ async function assertIdentity({ requireBinding = false, cleanup = false, } = {}) {
931
+ const response = await request('get_state', {}, cleanup);
786
932
  const data = response.data;
787
933
  if (!isObject(data) || typeof data.sessionId !== 'string')
788
934
  throw new PiRpcRefusal('state_malformed');
@@ -956,7 +1102,7 @@ export async function startOwnedPiRpc(options) {
956
1102
  }
957
1103
  },
958
1104
  /** Bounded wait for the run started by `prompt` to settle. Used by the run helper. */
959
- async awaitSettled({ timeoutMs = opts.settleTimeoutMs } = {}) {
1105
+ async awaitSettled({ timeoutMs = opts.operationTimeoutMs } = {}) {
960
1106
  try {
961
1107
  if (proof.prompt?.disposition === 'handled')
962
1108
  return null;
@@ -975,11 +1121,25 @@ export async function startOwnedPiRpc(options) {
975
1121
  * Explicit cancellation of this owned runtime. It never sends a prompt, never sends
976
1122
  * CANCELLED and never releases claims: a caller must reconcile the stop externally.
977
1123
  */
978
- async cancel({ reason = 'bounded RPC cancellation request' } = {}) {
1124
+ async cancel(options = {}) {
1125
+ const intent = options.intent;
979
1126
  try {
980
1127
  assertNamespaceGuard(opts);
1128
+ let verifiedIntent = intent === undefined ? null : await verifyCancellationIntent(intent);
1129
+ const reason = verifiedIntent &&
1130
+ typeof verifiedIntent.message.body.reason === 'string'
1131
+ ? verifiedIntent.message.body.reason
1132
+ : (options.reason ?? 'bounded RPC cancellation request');
1133
+ if (verifiedIntent === null)
1134
+ assertCurrentAuthority({ requireResources: false });
1135
+ const before = await assertIdentity({
1136
+ requireBinding: true,
1137
+ cleanup: true,
1138
+ });
1139
+ if (intent !== undefined)
1140
+ verifiedIntent = await verifyCancellationIntent(intent);
1141
+ assertNamespaceGuard(opts);
981
1142
  assertCurrentAuthority({ requireResources: false });
982
- const before = await assertIdentity({ requireBinding: true });
983
1143
  const ordinalBeforeAbort = rpc.recordCount();
984
1144
  const entry = {
985
1145
  at: nowIso(),
@@ -989,17 +1149,28 @@ export async function startOwnedPiRpc(options) {
989
1149
  reconciliation_required: true,
990
1150
  stop_scope: 'owned RPC child only; a native abort response is not proof that arbitrary descendants stopped',
991
1151
  };
992
- // Recorded immediately, so partial cancellation evidence survives a later failure.
1152
+ // Record cancellation evidence before queue clearing or abort so partial failure remains inspectable.
993
1153
  proof.cancel = entry;
994
- const cancel = protocolMessage({
995
- type: 'CANCEL',
996
- from: protocol.coordinator,
997
- to: protocol.assignee,
998
- owner_epoch: protocol.ownerEpoch,
999
- body: { reason },
1000
- });
1001
- entry.cancel_message_id = cancel.message_id;
1002
- const clear = await request('clear_queue');
1154
+ if (verifiedIntent === null) {
1155
+ const cancel = protocolMessage({
1156
+ type: 'CANCEL',
1157
+ from: protocol.coordinator,
1158
+ to: protocol.assignee,
1159
+ owner_epoch: protocol.ownerEpoch,
1160
+ body: { reason },
1161
+ });
1162
+ entry.cancel_message_id = cancel.message_id;
1163
+ }
1164
+ else {
1165
+ entry.cancel_message_id = verifiedIntent.message.message_id;
1166
+ entry.cancel_intent = {
1167
+ content_digest: verifiedIntent.message.content_digest,
1168
+ file_digest: verifiedIntent.fileDigest,
1169
+ };
1170
+ }
1171
+ assertNamespaceGuard(opts);
1172
+ assertCurrentAuthority({ requireResources: false });
1173
+ const clear = await request('clear_queue', {}, true);
1003
1174
  entry.clear_queue = {
1004
1175
  id: clear.id,
1005
1176
  steering: Array.isArray(clear.data?.steering)
@@ -1009,7 +1180,7 @@ export async function startOwnedPiRpc(options) {
1009
1180
  ? clear.data.followUp
1010
1181
  : [],
1011
1182
  };
1012
- const abort = await request('abort');
1183
+ const abort = await request('abort', {}, true);
1013
1184
  entry.abort = {
1014
1185
  id: abort.id,
1015
1186
  success: abort.success === true,
@@ -1022,7 +1193,7 @@ export async function startOwnedPiRpc(options) {
1022
1193
  // sufficient because retries/compaction/follow-ups can still follow it.
1023
1194
  settledEvent = await rpc.waitForEvent((record) => record.type === 'agent_settled', {
1024
1195
  fromOrdinal: ordinalBeforeAbort,
1025
- timeoutMs: eventTimeout(opts.settleTimeoutMs),
1196
+ timeoutMs: opts.settleTimeoutMs,
1026
1197
  });
1027
1198
  }
1028
1199
  catch (error) {
@@ -1033,7 +1204,10 @@ export async function startOwnedPiRpc(options) {
1033
1204
  if (settledEvent)
1034
1205
  entry.agent_settled = { ordinal: settledEvent.ordinal, at: nowIso() };
1035
1206
  try {
1036
- const after = await assertIdentity({ requireBinding: true });
1207
+ const after = await assertIdentity({
1208
+ requireBinding: true,
1209
+ cleanup: true,
1210
+ });
1037
1211
  entry.native_idle =
1038
1212
  after.data.isStreaming === false &&
1039
1213
  after.data.isCompacting === false &&
@@ -1069,6 +1243,7 @@ export async function startOwnedPiRpc(options) {
1069
1243
  finish() {
1070
1244
  if (finishPromise)
1071
1245
  return finishPromise;
1246
+ clearTimeout(operationTimer);
1072
1247
  finishPromise = (async () => {
1073
1248
  let exit = null;
1074
1249
  let shutdownError = null;
@@ -1143,6 +1318,8 @@ export async function startOwnedPiRpc(options) {
1143
1318
  shutdown_timeout_ms: opts.shutdownTimeoutMs,
1144
1319
  stream_close_grace_ms: opts.streamCloseGraceMs,
1145
1320
  max_bytes: opts.maxBytes,
1321
+ max_log_bytes: opts.maxLogBytes,
1322
+ cancel_settle_timeout_ms: opts.settleTimeoutMs,
1146
1323
  model_override: null,
1147
1324
  effort_override: null,
1148
1325
  },
@@ -1164,6 +1341,7 @@ export async function startOwnedPiRpc(options) {
1164
1341
  },
1165
1342
  planned_outcome: outcome,
1166
1343
  rpc_child_pid: child.pid ?? null,
1344
+ rpc_capture: { ...rpc.capture(), log: logCapture() },
1167
1345
  };
1168
1346
  let namespaceError = null;
1169
1347
  const checkNamespace = () => {
@@ -1212,7 +1390,7 @@ export async function startOwnedPiRpc(options) {
1212
1390
  evidenceError === null &&
1213
1391
  checkNamespace()) {
1214
1392
  try {
1215
- fs.writeFileSync(artifacts.proofFile, `${JSON.stringify({ ...proof, finished_at: finishedAt, exit }, null, 2)}\n`, { flag: 'wx', mode: 0o600 });
1393
+ fs.writeFileSync(artifacts.proofFile, `${JSON.stringify({ ...proof, finished_at: finishedAt, exit, rpc_capture: { ...rpc.capture(), log: logCapture() } }, null, 2)}\n`, { flag: 'wx', mode: 0o600 });
1216
1394
  }
1217
1395
  catch (error) {
1218
1396
  evidenceError = errorDetail(error) ?? 'proof_write_failed';
@@ -1345,6 +1523,8 @@ export async function startOwnedPiRpc(options) {
1345
1523
  evidence: {
1346
1524
  evidence_dir: opts.evidenceDir,
1347
1525
  events_file: artifacts.eventsFile,
1526
+ events_complete: logCapture().complete,
1527
+ events_omitted_records: omittedLogRecords,
1348
1528
  execution_file: namespaceError === null && !evidenceError
1349
1529
  ? artifacts.executionFile
1350
1530
  : null,
@@ -1368,6 +1548,12 @@ export async function startOwnedPiRpc(options) {
1368
1548
  return finishPromise;
1369
1549
  },
1370
1550
  };
1551
+ operationTimer = setTimeout(() => {
1552
+ setOperationError(new PiRpcRefusal('operation_deadline', 'needs_input'));
1553
+ void session.finish().catch(() => { });
1554
+ }, Math.max(1, opts.deadlineAt - Date.now()));
1555
+ if (typeof operationTimer.unref === 'function')
1556
+ operationTimer.unref();
1371
1557
  // Accepted alias for callers of the earlier revision; like `finish` it takes no arguments,
1372
1558
  // so it cannot override the authoritative outcome.
1373
1559
  // Bind the contracted identity and native session header before returning a live handle.
@@ -1375,6 +1561,7 @@ export async function startOwnedPiRpc(options) {
1375
1561
  await assertIdentity({ requireBinding: false });
1376
1562
  }
1377
1563
  catch (error) {
1564
+ setOperationError(error);
1378
1565
  const failure = await session.finish();
1379
1566
  return {
1380
1567
  ok: false,
@@ -1516,11 +1703,16 @@ function normalizeOwnedOptions(options) {
1516
1703
  const streamCloseGraceMs = boundedTimeout(options.streamCloseGraceMs, DEFAULT_STREAM_CLOSE_GRACE_MS, MAX_REQUEST_TIMEOUT_MS, 'stream_close_grace_out_of_range');
1517
1704
  const maxBytes = options.maxBytes === undefined
1518
1705
  ? DEFAULT_MAX_BYTES
1519
- : Number.isSafeInteger(options.maxBytes) && options.maxBytes > 0
1706
+ : Number.isSafeInteger(options.maxBytes) &&
1707
+ options.maxBytes > 0 &&
1708
+ options.maxBytes <= MAX_CAPTURE_BYTES
1520
1709
  ? options.maxBytes
1521
1710
  : (() => {
1522
1711
  throw new PiRpcRefusal('max_bytes_out_of_range');
1523
1712
  })();
1713
+ const maxLogBytes = options.maxLogBytes === undefined
1714
+ ? DEFAULT_MAX_LOG_BYTES
1715
+ : boundedTimeout(options.maxLogBytes, DEFAULT_MAX_LOG_BYTES, MAX_CAPTURE_BYTES, 'max_log_bytes_out_of_range');
1524
1716
  const maxAgeMinutes = options.maxAgeMinutes === undefined ? 30 : options.maxAgeMinutes;
1525
1717
  if (!Number.isFinite(maxAgeMinutes) || maxAgeMinutes < 0)
1526
1718
  throw new PiRpcRefusal('invalid_max_age');
@@ -1554,6 +1746,7 @@ function normalizeOwnedOptions(options) {
1554
1746
  signalGraceMs,
1555
1747
  streamCloseGraceMs,
1556
1748
  maxBytes,
1749
+ maxLogBytes,
1557
1750
  maxAgeMinutes,
1558
1751
  namespaceGuard: options.namespaceGuard,
1559
1752
  deadlineAt: Date.now() + operationTimeoutMs,