@plurnk/plurnk-service 1.3.12 → 1.4.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 (469) hide show
  1. package/.env.defaults +84 -77
  2. package/INSTALL.md +50 -25
  3. package/README.md +24 -10
  4. package/SPEC.md +2311 -928
  5. package/dist/Paths.d.ts +4 -1
  6. package/dist/Paths.d.ts.map +1 -1
  7. package/dist/Paths.js +23 -21
  8. package/dist/Paths.js.map +1 -1
  9. package/dist/build-info.json +1 -1
  10. package/dist/content/edit-receipt.d.ts +13 -28
  11. package/dist/content/edit-receipt.d.ts.map +1 -1
  12. package/dist/content/edit-receipt.js +285 -104
  13. package/dist/content/edit-receipt.js.map +1 -1
  14. package/dist/content/edited-span.d.ts.map +1 -1
  15. package/dist/content/edited-span.js +2 -5
  16. package/dist/content/edited-span.js.map +1 -1
  17. package/dist/content/index.d.ts +3 -3
  18. package/dist/content/index.d.ts.map +1 -1
  19. package/dist/content/index.js +1 -1
  20. package/dist/content/index.js.map +1 -1
  21. package/dist/content/line-marker.d.ts +6 -9
  22. package/dist/content/line-marker.d.ts.map +1 -1
  23. package/dist/content/line-marker.js +7 -11
  24. package/dist/content/line-marker.js.map +1 -1
  25. package/dist/content/matcher.d.ts +14 -25
  26. package/dist/content/matcher.d.ts.map +1 -1
  27. package/dist/content/matcher.js +77 -107
  28. package/dist/content/matcher.js.map +1 -1
  29. package/dist/content/mimetype-binary.d.ts +2 -2
  30. package/dist/content/mimetype-binary.d.ts.map +1 -1
  31. package/dist/content/mimetype-binary.js +10 -10
  32. package/dist/content/mimetype-binary.js.map +1 -1
  33. package/dist/content/path-mimetype.js +3 -3
  34. package/dist/content/path-mimetype.js.map +1 -1
  35. package/dist/content/read-resolve.d.ts +8 -4
  36. package/dist/content/read-resolve.d.ts.map +1 -1
  37. package/dist/content/read-resolve.js +101 -49
  38. package/dist/content/read-resolve.js.map +1 -1
  39. package/dist/core/BranchReceipt.d.ts +7 -0
  40. package/dist/core/BranchReceipt.d.ts.map +1 -0
  41. package/dist/core/BranchReceipt.js +27 -0
  42. package/dist/core/BranchReceipt.js.map +1 -0
  43. package/dist/core/BudgetOverflow.d.ts +23 -0
  44. package/dist/core/BudgetOverflow.d.ts.map +1 -0
  45. package/dist/core/BudgetOverflow.js +61 -0
  46. package/dist/core/BudgetOverflow.js.map +1 -0
  47. package/dist/core/BudgetReadout.d.ts +8 -0
  48. package/dist/core/BudgetReadout.d.ts.map +1 -0
  49. package/dist/core/BudgetReadout.js +79 -0
  50. package/dist/core/BudgetReadout.js.map +1 -0
  51. package/dist/core/ChannelWrite.d.ts +28 -9
  52. package/dist/core/ChannelWrite.d.ts.map +1 -1
  53. package/dist/core/ChannelWrite.js +28 -21
  54. package/dist/core/ChannelWrite.js.map +1 -1
  55. package/dist/core/ChannelWrite.sql +11 -10
  56. package/dist/core/CoreSchemeServices.d.ts +10 -4
  57. package/dist/core/CoreSchemeServices.d.ts.map +1 -1
  58. package/dist/core/CoreSchemeServices.js +7 -1
  59. package/dist/core/CoreSchemeServices.js.map +1 -1
  60. package/dist/core/Dispatcher.d.ts +29 -20
  61. package/dist/core/Dispatcher.d.ts.map +1 -1
  62. package/dist/core/Dispatcher.js +1488 -599
  63. package/dist/core/Dispatcher.js.map +1 -1
  64. package/dist/core/DurableStatement.d.ts +6 -0
  65. package/dist/core/DurableStatement.d.ts.map +1 -0
  66. package/dist/core/DurableStatement.js +51 -0
  67. package/dist/core/DurableStatement.js.map +1 -0
  68. package/dist/core/Engine.d.ts +48 -20
  69. package/dist/core/Engine.d.ts.map +1 -1
  70. package/dist/core/Engine.js +1208 -789
  71. package/dist/core/Engine.js.map +1 -1
  72. package/dist/core/Engine.sql +309 -217
  73. package/dist/core/EnvFlags.js +1 -1
  74. package/dist/core/EnvFlags.js.map +1 -1
  75. package/dist/core/ErrorDetail.d.ts +6 -0
  76. package/dist/core/ErrorDetail.d.ts.map +1 -0
  77. package/dist/core/ErrorDetail.js +20 -0
  78. package/dist/core/ErrorDetail.js.map +1 -0
  79. package/dist/core/ExecutorRegistry.d.ts +14 -3
  80. package/dist/core/ExecutorRegistry.d.ts.map +1 -1
  81. package/dist/core/ExecutorRegistry.js +56 -30
  82. package/dist/core/ExecutorRegistry.js.map +1 -1
  83. package/dist/core/GitBranch.d.ts +20 -0
  84. package/dist/core/GitBranch.d.ts.map +1 -0
  85. package/dist/core/GitBranch.js +110 -0
  86. package/dist/core/GitBranch.js.map +1 -0
  87. package/dist/core/JournalTurn.d.ts +9 -0
  88. package/dist/core/JournalTurn.d.ts.map +1 -0
  89. package/dist/core/JournalTurn.js +14 -0
  90. package/dist/core/JournalTurn.js.map +1 -0
  91. package/dist/core/JournalTurn.sql +10 -0
  92. package/dist/core/LogBody.d.ts +17 -0
  93. package/dist/core/LogBody.d.ts.map +1 -0
  94. package/dist/core/LogBody.js +148 -0
  95. package/dist/core/LogBody.js.map +1 -0
  96. package/dist/core/LoopFlagsReader.d.ts +7 -0
  97. package/dist/core/LoopFlagsReader.d.ts.map +1 -0
  98. package/dist/core/LoopFlagsReader.js +33 -0
  99. package/dist/core/LoopFlagsReader.js.map +1 -0
  100. package/dist/core/LoopLifecycle.d.ts +8 -1
  101. package/dist/core/LoopLifecycle.d.ts.map +1 -1
  102. package/dist/core/LoopLifecycle.js +55 -9
  103. package/dist/core/LoopLifecycle.js.map +1 -1
  104. package/dist/core/LoopLifecycle.sql +9 -3
  105. package/dist/core/NoticeChannel.d.ts +13 -0
  106. package/dist/core/NoticeChannel.d.ts.map +1 -0
  107. package/dist/core/NoticeChannel.js +40 -0
  108. package/dist/core/NoticeChannel.js.map +1 -0
  109. package/dist/core/Owner.d.ts +0 -1
  110. package/dist/core/Owner.d.ts.map +1 -1
  111. package/dist/core/Owner.js +2 -5
  112. package/dist/core/Owner.js.map +1 -1
  113. package/dist/core/PacketBuilder.d.ts +25 -24
  114. package/dist/core/PacketBuilder.d.ts.map +1 -1
  115. package/dist/core/PacketBuilder.js +313 -375
  116. package/dist/core/PacketBuilder.js.map +1 -1
  117. package/dist/core/ProblemLog.d.ts +26 -0
  118. package/dist/core/ProblemLog.d.ts.map +1 -0
  119. package/dist/core/ProblemLog.js +58 -0
  120. package/dist/core/ProblemLog.js.map +1 -0
  121. package/dist/core/ProposalLifecycle.d.ts +15 -21
  122. package/dist/core/ProposalLifecycle.d.ts.map +1 -1
  123. package/dist/core/ProposalLifecycle.js +291 -78
  124. package/dist/core/ProposalLifecycle.js.map +1 -1
  125. package/dist/core/ProviderInstantiate.d.ts.map +1 -1
  126. package/dist/core/ProviderInstantiate.js +51 -48
  127. package/dist/core/ProviderInstantiate.js.map +1 -1
  128. package/dist/core/SchemeRegistry.d.ts +14 -8
  129. package/dist/core/SchemeRegistry.d.ts.map +1 -1
  130. package/dist/core/SchemeRegistry.js +189 -114
  131. package/dist/core/SchemeRegistry.js.map +1 -1
  132. package/dist/core/ServiceTeardown.d.ts +11 -0
  133. package/dist/core/ServiceTeardown.d.ts.map +1 -0
  134. package/dist/core/ServiceTeardown.js +70 -0
  135. package/dist/core/ServiceTeardown.js.map +1 -0
  136. package/dist/core/StoredPacket.d.ts +29 -0
  137. package/dist/core/StoredPacket.d.ts.map +1 -0
  138. package/dist/core/StoredPacket.js +147 -0
  139. package/dist/core/StoredPacket.js.map +1 -0
  140. package/dist/core/StrikeRail.d.ts +1 -2
  141. package/dist/core/StrikeRail.d.ts.map +1 -1
  142. package/dist/core/StrikeRail.js +25 -55
  143. package/dist/core/StrikeRail.js.map +1 -1
  144. package/dist/core/WorkerControlAddress.d.ts +17 -0
  145. package/dist/core/WorkerControlAddress.d.ts.map +1 -0
  146. package/dist/core/WorkerControlAddress.js +44 -0
  147. package/dist/core/WorkerControlAddress.js.map +1 -0
  148. package/dist/core/WorkerName.d.ts +31 -0
  149. package/dist/core/WorkerName.d.ts.map +1 -0
  150. package/dist/core/WorkerName.js +95 -0
  151. package/dist/core/WorkerName.js.map +1 -0
  152. package/dist/core/WorkerName.sql +36 -0
  153. package/dist/core/WorkspaceGate.d.ts +14 -0
  154. package/dist/core/WorkspaceGate.d.ts.map +1 -0
  155. package/dist/core/WorkspaceGate.js +155 -0
  156. package/dist/core/WorkspaceGate.js.map +1 -0
  157. package/dist/core/caps/CapsResolve.d.ts +1 -1
  158. package/dist/core/caps/CapsResolve.d.ts.map +1 -1
  159. package/dist/core/caps/CapsResolve.js.map +1 -1
  160. package/dist/core/caps/DbChannelCaps.d.ts +5 -11
  161. package/dist/core/caps/DbChannelCaps.d.ts.map +1 -1
  162. package/dist/core/caps/DbChannelCaps.js +24 -8
  163. package/dist/core/caps/DbChannelCaps.js.map +1 -1
  164. package/dist/core/caps/DbEntryCaps.d.ts +4 -13
  165. package/dist/core/caps/DbEntryCaps.d.ts.map +1 -1
  166. package/dist/core/caps/DbEntryCaps.js +15 -6
  167. package/dist/core/caps/DbEntryCaps.js.map +1 -1
  168. package/dist/core/caps/DbNotifyCaps.d.ts +1 -1
  169. package/dist/core/caps/DbNotifyCaps.d.ts.map +1 -1
  170. package/dist/core/caps/DbNotifyCaps.js +12 -11
  171. package/dist/core/caps/DbNotifyCaps.js.map +1 -1
  172. package/dist/core/caps/DbProjectionCaps.d.ts +5 -5
  173. package/dist/core/caps/DbProjectionCaps.d.ts.map +1 -1
  174. package/dist/core/caps/DbProjectionCaps.js +21 -4
  175. package/dist/core/caps/DbProjectionCaps.js.map +1 -1
  176. package/dist/core/caps/DbSubscriptionCaps.d.ts +4 -4
  177. package/dist/core/caps/DbSubscriptionCaps.d.ts.map +1 -1
  178. package/dist/core/caps/DbSubscriptionCaps.js +57 -62
  179. package/dist/core/caps/DbSubscriptionCaps.js.map +1 -1
  180. package/dist/core/caps/DbTagCaps.d.ts +5 -12
  181. package/dist/core/caps/DbTagCaps.d.ts.map +1 -1
  182. package/dist/core/caps/DbTagCaps.js +14 -7
  183. package/dist/core/caps/DbTagCaps.js.map +1 -1
  184. package/dist/core/content-hash.js +1 -1
  185. package/dist/core/content-hash.js.map +1 -1
  186. package/dist/core/env-defaults.d.ts.map +1 -1
  187. package/dist/core/env-defaults.js.map +1 -1
  188. package/dist/core/fork.d.ts.map +1 -1
  189. package/dist/core/fork.js +55 -30
  190. package/dist/core/fork.js.map +1 -1
  191. package/dist/core/fork.sql +41 -27
  192. package/dist/core/git-env.d.ts +2 -0
  193. package/dist/core/git-env.d.ts.map +1 -1
  194. package/dist/core/git-env.js +13 -18
  195. package/dist/core/git-env.js.map +1 -1
  196. package/dist/core/git-iso.d.ts.map +1 -1
  197. package/dist/core/git-iso.js +9 -15
  198. package/dist/core/git-iso.js.map +1 -1
  199. package/dist/core/git-membership.d.ts +1 -1
  200. package/dist/core/git-membership.d.ts.map +1 -1
  201. package/dist/core/git-membership.js +198 -146
  202. package/dist/core/git-membership.js.map +1 -1
  203. package/dist/core/git-state.d.ts.map +1 -1
  204. package/dist/core/git-state.js +10 -11
  205. package/dist/core/git-state.js.map +1 -1
  206. package/dist/core/owner.sql +1 -1
  207. package/dist/core/packet-inject.d.ts.map +1 -1
  208. package/dist/core/packet-inject.js +7 -11
  209. package/dist/core/packet-inject.js.map +1 -1
  210. package/dist/core/packet-wire.d.ts +2 -20
  211. package/dist/core/packet-wire.d.ts.map +1 -1
  212. package/dist/core/packet-wire.js +242 -368
  213. package/dist/core/packet-wire.js.map +1 -1
  214. package/dist/core/plurnk-uri.d.ts +12 -1
  215. package/dist/core/plurnk-uri.d.ts.map +1 -1
  216. package/dist/core/plurnk-uri.js +49 -29
  217. package/dist/core/plurnk-uri.js.map +1 -1
  218. package/dist/core/results.d.ts +16 -5
  219. package/dist/core/results.d.ts.map +1 -1
  220. package/dist/core/results.js +27 -18
  221. package/dist/core/results.js.map +1 -1
  222. package/dist/core/ruler_count.d.ts +4 -0
  223. package/dist/core/ruler_count.d.ts.map +1 -0
  224. package/dist/core/ruler_count.js +7 -0
  225. package/dist/core/ruler_count.js.map +1 -0
  226. package/dist/core/scheme-types.d.ts +9 -11
  227. package/dist/core/scheme-types.d.ts.map +1 -1
  228. package/dist/core/scheme-types.js.map +1 -1
  229. package/dist/core/search-gate.d.ts.map +1 -1
  230. package/dist/core/search-gate.js +3 -11
  231. package/dist/core/search-gate.js.map +1 -1
  232. package/dist/core/teaching-corpus.d.ts +6 -0
  233. package/dist/core/teaching-corpus.d.ts.map +1 -0
  234. package/dist/core/teaching-corpus.js +23 -0
  235. package/dist/core/teaching-corpus.js.map +1 -0
  236. package/dist/core/teaching.d.ts +0 -1
  237. package/dist/core/teaching.d.ts.map +1 -1
  238. package/dist/core/teaching.js +2 -8
  239. package/dist/core/teaching.js.map +1 -1
  240. package/dist/core/token-ruler.d.ts.map +1 -1
  241. package/dist/core/token-ruler.js +3 -16
  242. package/dist/core/token-ruler.js.map +1 -1
  243. package/dist/core/turn-scheduler.d.ts +1 -1
  244. package/dist/core/turn-scheduler.d.ts.map +1 -1
  245. package/dist/core/turn-scheduler.js +1 -1
  246. package/dist/core/turn-scheduler.js.map +1 -1
  247. package/dist/core/worker-cap.d.ts +2 -4
  248. package/dist/core/worker-cap.d.ts.map +1 -1
  249. package/dist/core/worker-cap.js +13 -4
  250. package/dist/core/worker-cap.js.map +1 -1
  251. package/dist/core/{run-ops.sql → worker-ops.sql} +11 -11
  252. package/dist/core/workspace-settings.d.ts.map +1 -1
  253. package/dist/core/workspace-settings.js +17 -9
  254. package/dist/core/workspace-settings.js.map +1 -1
  255. package/dist/digest/Digest.d.ts +2 -1
  256. package/dist/digest/Digest.d.ts.map +1 -1
  257. package/dist/digest/Digest.js +337 -138
  258. package/dist/digest/Digest.js.map +1 -1
  259. package/dist/digest/digest.sql +19 -10
  260. package/dist/index.d.ts.map +1 -1
  261. package/dist/index.js +3 -5
  262. package/dist/index.js.map +1 -1
  263. package/dist/matrix/live-specimen.d.ts +9 -0
  264. package/dist/matrix/live-specimen.d.ts.map +1 -0
  265. package/dist/matrix/live-specimen.js +37 -0
  266. package/dist/matrix/live-specimen.js.map +1 -0
  267. package/dist/observe/api.d.ts +6 -0
  268. package/dist/observe/api.d.ts.map +1 -0
  269. package/dist/observe/api.js +11 -0
  270. package/dist/observe/api.js.map +1 -0
  271. package/dist/observe/init.d.ts +7 -0
  272. package/dist/observe/init.d.ts.map +1 -0
  273. package/dist/observe/init.js +159 -0
  274. package/dist/observe/init.js.map +1 -0
  275. package/dist/observe/metrics.d.ts +6 -0
  276. package/dist/observe/metrics.d.ts.map +1 -0
  277. package/dist/observe/metrics.js +15 -0
  278. package/dist/observe/metrics.js.map +1 -0
  279. package/dist/observe/spans.d.ts +4 -0
  280. package/dist/observe/spans.d.ts.map +1 -0
  281. package/dist/observe/spans.js +51 -0
  282. package/dist/observe/spans.js.map +1 -0
  283. package/dist/schemes/EffectPolicy.d.ts +1 -0
  284. package/dist/schemes/EffectPolicy.d.ts.map +1 -1
  285. package/dist/schemes/EffectPolicy.js +5 -2
  286. package/dist/schemes/EffectPolicy.js.map +1 -1
  287. package/dist/schemes/Exec.d.ts +6 -11
  288. package/dist/schemes/Exec.d.ts.map +1 -1
  289. package/dist/schemes/Exec.js +364 -247
  290. package/dist/schemes/Exec.js.map +1 -1
  291. package/dist/schemes/ExecOutputScheme.d.ts +8 -7
  292. package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
  293. package/dist/schemes/ExecOutputScheme.js +48 -9
  294. package/dist/schemes/ExecOutputScheme.js.map +1 -1
  295. package/dist/schemes/File.d.ts +7 -11
  296. package/dist/schemes/File.d.ts.map +1 -1
  297. package/dist/schemes/File.js +279 -142
  298. package/dist/schemes/File.js.map +1 -1
  299. package/dist/schemes/Log.d.ts +4 -8
  300. package/dist/schemes/Log.d.ts.map +1 -1
  301. package/dist/schemes/Log.js +475 -208
  302. package/dist/schemes/Log.js.map +1 -1
  303. package/dist/schemes/Log.sql +62 -30
  304. package/dist/schemes/Prompt.d.ts +3 -2
  305. package/dist/schemes/Prompt.d.ts.map +1 -1
  306. package/dist/schemes/Prompt.js +9 -6
  307. package/dist/schemes/Prompt.js.map +1 -1
  308. package/dist/schemes/Skill.d.ts +1 -1
  309. package/dist/schemes/Skill.d.ts.map +1 -1
  310. package/dist/schemes/Skill.js +2 -3
  311. package/dist/schemes/Skill.js.map +1 -1
  312. package/dist/schemes/Worker.d.ts +8 -16
  313. package/dist/schemes/Worker.d.ts.map +1 -1
  314. package/dist/schemes/Worker.js +179 -69
  315. package/dist/schemes/Worker.js.map +1 -1
  316. package/dist/schemes/_entry-chunk.d.ts.map +1 -1
  317. package/dist/schemes/_entry-chunk.js +12 -5
  318. package/dist/schemes/_entry-chunk.js.map +1 -1
  319. package/dist/schemes/_entry-crud.d.ts +10 -9
  320. package/dist/schemes/_entry-crud.d.ts.map +1 -1
  321. package/dist/schemes/_entry-crud.js +59 -13
  322. package/dist/schemes/_entry-crud.js.map +1 -1
  323. package/dist/schemes/_entry-crud.sql +20 -8
  324. package/dist/schemes/_entry-find.d.ts +20 -15
  325. package/dist/schemes/_entry-find.d.ts.map +1 -1
  326. package/dist/schemes/_entry-find.js +339 -174
  327. package/dist/schemes/_entry-find.js.map +1 -1
  328. package/dist/schemes/_entry-find.sql +20 -8
  329. package/dist/schemes/_entry-graph.d.ts +4 -2
  330. package/dist/schemes/_entry-graph.d.ts.map +1 -1
  331. package/dist/schemes/_entry-graph.js +55 -31
  332. package/dist/schemes/_entry-graph.js.map +1 -1
  333. package/dist/schemes/_entry-graph.sql +37 -22
  334. package/dist/schemes/_entry-manifest.d.ts +10 -15
  335. package/dist/schemes/_entry-manifest.d.ts.map +1 -1
  336. package/dist/schemes/_entry-manifest.js +50 -268
  337. package/dist/schemes/_entry-manifest.js.map +1 -1
  338. package/dist/schemes/_entry-ops.d.ts +9 -14
  339. package/dist/schemes/_entry-ops.d.ts.map +1 -1
  340. package/dist/schemes/_entry-ops.js +149 -77
  341. package/dist/schemes/_entry-ops.js.map +1 -1
  342. package/dist/schemes/_entry-ops.sql +1 -1
  343. package/dist/schemes/_entry-semantic.d.ts +23 -8
  344. package/dist/schemes/_entry-semantic.d.ts.map +1 -1
  345. package/dist/schemes/_entry-semantic.js +141 -60
  346. package/dist/schemes/_entry-semantic.js.map +1 -1
  347. package/dist/schemes/_entry-semantic.sql +63 -45
  348. package/dist/schemes/_entry-send.d.ts +3 -4
  349. package/dist/schemes/_entry-send.d.ts.map +1 -1
  350. package/dist/schemes/_entry-send.js +48 -23
  351. package/dist/schemes/_entry-send.js.map +1 -1
  352. package/dist/schemes/_path-scope.d.ts +23 -0
  353. package/dist/schemes/_path-scope.d.ts.map +1 -0
  354. package/dist/schemes/_path-scope.js +61 -0
  355. package/dist/schemes/_path-scope.js.map +1 -0
  356. package/dist/schemes/_search-candidate.d.ts +20 -0
  357. package/dist/schemes/_search-candidate.d.ts.map +1 -0
  358. package/dist/schemes/_search-candidate.js +19 -0
  359. package/dist/schemes/_search-candidate.js.map +1 -0
  360. package/dist/schemes/_search-exclusion.d.ts +7 -0
  361. package/dist/schemes/_search-exclusion.d.ts.map +1 -0
  362. package/dist/schemes/_search-exclusion.js +23 -0
  363. package/dist/schemes/_search-exclusion.js.map +1 -0
  364. package/dist/schemes/_search-index.d.ts +6 -0
  365. package/dist/schemes/_search-index.d.ts.map +1 -0
  366. package/dist/schemes/_search-index.js +326 -0
  367. package/dist/schemes/_search-index.js.map +1 -0
  368. package/dist/schemes/cosine.js +1 -1
  369. package/dist/schemes/cosine.js.map +1 -1
  370. package/dist/schemes/exec-abort.js +3 -3
  371. package/dist/schemes/exec-abort.js.map +1 -1
  372. package/dist/schemes/exec-env.js +3 -3
  373. package/dist/schemes/exec-env.js.map +1 -1
  374. package/dist/server/BranchBatches.d.ts +48 -0
  375. package/dist/server/BranchBatches.d.ts.map +1 -0
  376. package/dist/server/BranchBatches.js +591 -0
  377. package/dist/server/BranchBatches.js.map +1 -0
  378. package/dist/server/Daemon.d.ts +36 -66
  379. package/dist/server/Daemon.d.ts.map +1 -1
  380. package/dist/server/Daemon.js +920 -446
  381. package/dist/server/Daemon.js.map +1 -1
  382. package/dist/server/DaemonModule.d.ts +31 -0
  383. package/dist/server/DaemonModule.d.ts.map +1 -0
  384. package/dist/server/DaemonModule.js +2 -0
  385. package/dist/server/DaemonModule.js.map +1 -0
  386. package/dist/server/branch-batch.sql +152 -0
  387. package/dist/server/client-input.d.ts +12 -0
  388. package/dist/server/client-input.d.ts.map +1 -1
  389. package/dist/server/client-input.js +262 -57
  390. package/dist/server/client-input.js.map +1 -1
  391. package/dist/server/dispatch-as-plurnk.d.ts +1 -1
  392. package/dist/server/dispatch-as-plurnk.d.ts.map +1 -1
  393. package/dist/server/dispatch-as-plurnk.js +15 -7
  394. package/dist/server/dispatch-as-plurnk.js.map +1 -1
  395. package/dist/server/drain.sql +92 -62
  396. package/dist/server/envelope.d.ts +2 -5
  397. package/dist/server/envelope.d.ts.map +1 -1
  398. package/dist/server/envelope.js +119 -95
  399. package/dist/server/envelope.js.map +1 -1
  400. package/dist/server/envelope.sql +19 -23
  401. package/dist/server/exec-poll-backoff.js +1 -1
  402. package/dist/server/exec-poll-backoff.js.map +1 -1
  403. package/dist/server/lifecycle-recovery.sql +79 -2
  404. package/dist/server/logEntry.d.ts +3 -1
  405. package/dist/server/logEntry.d.ts.map +1 -1
  406. package/dist/server/logEntry.js +4 -2
  407. package/dist/server/logEntry.js.map +1 -1
  408. package/dist/server/logEntry.sql +1 -1
  409. package/dist/server/loop-model.d.ts.map +1 -1
  410. package/dist/server/loop-model.js +22 -9
  411. package/dist/server/loop-model.js.map +1 -1
  412. package/dist/server/loopDocs.d.ts.map +1 -1
  413. package/dist/server/loopDocs.js +5 -4
  414. package/dist/server/loopDocs.js.map +1 -1
  415. package/dist/server/seam-entry-read.sql +15 -10
  416. package/dist/server/seam-log-read.sql +2 -2
  417. package/dist/server/seam-loop.sql +1 -1
  418. package/dist/server/seam-proposal-list.sql +17 -7
  419. package/dist/service.d.ts.map +1 -1
  420. package/dist/service.js +66 -60
  421. package/dist/service.js.map +1 -1
  422. package/migrations/001_schema.sql +897 -0
  423. package/package.json +57 -26
  424. package/dist/core/PluginLoader.d.ts +0 -20
  425. package/dist/core/PluginLoader.d.ts.map +0 -1
  426. package/dist/core/PluginLoader.js +0 -142
  427. package/dist/core/PluginLoader.js.map +0 -1
  428. package/dist/core/TelemetryChannel.d.ts +0 -37
  429. package/dist/core/TelemetryChannel.d.ts.map +0 -1
  430. package/dist/core/TelemetryChannel.js +0 -80
  431. package/dist/core/TelemetryChannel.js.map +0 -1
  432. package/dist/core/path-decode.d.ts +0 -3
  433. package/dist/core/path-decode.d.ts.map +0 -1
  434. package/dist/core/path-decode.js +0 -9
  435. package/dist/core/path-decode.js.map +0 -1
  436. package/dist/core/plugin-attribution.d.ts +0 -5
  437. package/dist/core/plugin-attribution.d.ts.map +0 -1
  438. package/dist/core/plugin-attribution.js +0 -39
  439. package/dist/core/plugin-attribution.js.map +0 -1
  440. package/dist/core/world-state.d.ts +0 -10
  441. package/dist/core/world-state.d.ts.map +0 -1
  442. package/dist/core/world-state.js +0 -35
  443. package/dist/core/world-state.js.map +0 -1
  444. package/dist/core/world-state.sql +0 -35
  445. package/dist/core/zero-pin.d.ts +0 -3
  446. package/dist/core/zero-pin.d.ts.map +0 -1
  447. package/dist/core/zero-pin.js +0 -16
  448. package/dist/core/zero-pin.js.map +0 -1
  449. package/dist/server/auto.d.ts +0 -6
  450. package/dist/server/auto.d.ts.map +0 -1
  451. package/dist/server/auto.js +0 -63
  452. package/dist/server/auto.js.map +0 -1
  453. package/dist/server/clientTurn.d.ts +0 -6
  454. package/dist/server/clientTurn.d.ts.map +0 -1
  455. package/dist/server/clientTurn.js +0 -22
  456. package/dist/server/clientTurn.js.map +0 -1
  457. package/dist/server/clientTurn.sql +0 -10
  458. package/dist/server/noProposals.d.ts +0 -6
  459. package/dist/server/noProposals.d.ts.map +0 -1
  460. package/dist/server/noProposals.js +0 -37
  461. package/dist/server/noProposals.js.map +0 -1
  462. package/dist/server/version-info.d.ts +0 -14
  463. package/dist/server/version-info.d.ts.map +0 -1
  464. package/dist/server/version-info.js +0 -69
  465. package/dist/server/version-info.js.map +0 -1
  466. package/migrations/0000-00-00.01_schema.sql +0 -536
  467. package/migrations/0004_loop-provider.sql +0 -3
  468. package/migrations/0005_subscription-published-channel.sql +0 -3
  469. package/migrations/0006_loop-max-turns.sql +0 -3
@@ -4,17 +4,13 @@
4
4
  // digest tool imports it to write byte-identical packetNNN.{system,user}.md
5
5
  // files. No second implementation, no drift.
6
6
  //
7
- // Format: markdown. user picked it over rummy's XML and JSON alternatives
8
- // 2026-05-22. Standard markdown idioms only — headers as section delimiters,
9
- // fenced code blocks for entry bodies, lists for arrays. No invented
10
- // separators. Models parse markdown natively.
11
- //
12
- // Section headers follow the `## Plurnk Service X` convention so the model
13
- // sees consistent framing across every section it might receive. Sections
14
- // with no content are omitted entirely (no empty headers in the wire).
15
- import { MimetypeBinary } from "../content/index.js";
16
- import { renderAddress } from "./plurnk-uri.js";
17
- import { encodePathParens } from "./path-decode.js";
7
+ // Format and omission rules are owned by {§packet-markdown}. Section producers
8
+ // supply names and typed content; this projection preserves their ordered evidence.
9
+ import { Validator } from "@plurnk/plurnk-contracts";
10
+ import { Results as SchemeResults } from "@plurnk/plurnk-schemes";
11
+ import { renderTarget } from "./plurnk-uri.js";
12
+ import LogBody from "./LogBody.js";
13
+ import { assertEditReceipt, assertResourceEffects, } from "../content/index.js";
18
14
  const editReceiptRevisionChars = () => {
19
15
  const raw = process.env.PLURNK_SERVICE_EDIT_RECEIPT_REVISION_CHARS;
20
16
  const value = Number(raw);
@@ -23,9 +19,22 @@ const editReceiptRevisionChars = () => {
23
19
  }
24
20
  return value;
25
21
  };
22
+ const previewBounds = () => {
23
+ const rawLines = process.env.PLURNK_SERVICE_PREVIEW_LINES;
24
+ const rawChars = process.env.PLURNK_SERVICE_PREVIEW_CHARS;
25
+ const lines = Number(rawLines);
26
+ const chars = Number(rawChars);
27
+ if (!Number.isSafeInteger(lines) || lines < 1) {
28
+ throw new Error(`PLURNK_SERVICE_PREVIEW_LINES must be a positive safe integer, got ${JSON.stringify(rawLines)}`);
29
+ }
30
+ if (!Number.isSafeInteger(chars) || chars < 1) {
31
+ throw new Error(`PLURNK_SERVICE_PREVIEW_CHARS must be a positive safe integer, got ${JSON.stringify(rawChars)}`);
32
+ }
33
+ return { lines, chars };
34
+ };
26
35
  export default class PacketWire {
27
- // Render the sections in `slot` to one ChatMessage.content string. Sections
28
- // render in list order; empties are omitted (no empty headers on the wire);
36
+ // {§packet-markdown} Render the sections in `slot` to one ChatMessage.content
37
+ // string. Sections render in list order; empties are omitted (no empty headers on the wire);
29
38
  // each is `## {header}\n\n{content}` (or bare content when header is null),
30
39
  // trailing newlines stripped, joined with a blank line.
31
40
  static renderSlot(sections, slot) {
@@ -45,15 +54,35 @@ export default class PacketWire {
45
54
  const header = typeof s.header === "string" && s.header.length > 0 ? s.header : null;
46
55
  return (header ? `## ${header}\n\n${s.content}` : s.content).replace(/\n+$/, "");
47
56
  }
48
- // The errors section content: the structured telemetry events rendered to
49
- // meta lines (+ snippet blocks). "" when empty (the section is omitted). The
50
- // events are ALSO kept structured on the packet (packet.telemetryErrors) —
51
- // ephemeral (the buffer drains on read), so the packet is their only home.
52
- static renderErrors(errors) {
53
- const events = Array.isArray(errors) ? errors : [];
54
- return events.length > 0 ? PacketWire.#renderTelemetryErrors(events) : "";
57
+ // Durable operation failures render as terse pointers to the log rows that
58
+ // own their exact RFC 9457 results.
59
+ static renderFailurePointers(failures) {
60
+ const rows = Array.isArray(failures) ? failures : [];
61
+ return rows
62
+ .filter((row) => typeof row.status === "number" && typeof row.coordinate === "string")
63
+ .map((row) => `* ${row.status} log:///${row.coordinate}`)
64
+ .join("\n");
65
+ }
66
+ // Non-terminal model-facing observations are deliberately separate from
67
+ // operation failures. Producer messages are normalized and bounded by the
68
+ // shared preview limit; typed positions remain legible.
69
+ static renderNotices(notices) {
70
+ const observations = Array.isArray(notices) ? notices : [];
71
+ return observations.map((notice) => {
72
+ const kind = typeof notice.kind === "string" ? notice.kind : "notice";
73
+ const rawMessage = typeof notice.message === "string"
74
+ ? notice.message.replace(/\s+/g, " ").trim()
75
+ : "";
76
+ const message = rawMessage.length > 0
77
+ ? PacketWire.#preview(rawMessage).text
78
+ : "";
79
+ const position = notice.position?.type === "content-offset"
80
+ ? ` @ ${String(notice.position.line)}:${String(notice.position.column)}`
81
+ : "";
82
+ return `* ${kind}${message.length > 0 ? `: ${message}` : ""}${position}`;
83
+ }).join("\n");
55
84
  }
56
- // The Child Streams / Child Runs sections (§child-orientation) — the OPPOSITE of advice: terse
85
+ // The Child Streams / Active Child Workers sections ({§child-orientation}) — the OPPOSITE of advice: terse
57
86
  // `* <status> <path>` pointers (same shape as the errors section) to the live things the worker holds,
58
87
  // so the model SEES its open streams + unconcluded workers each turn and reasons for itself (READ /
59
88
  // OPEN / KILL via the path). Orienting state, never an instruction. "" when none → section omitted.
@@ -65,7 +94,7 @@ export default class PacketWire {
65
94
  static renderGit(git) {
66
95
  return git === null || git === undefined ? "" : PacketWire.#renderGitState(git);
67
96
  }
68
- // The log section's content: the model's curated rows as a fenced `jsonplurnk` array (§jsonplurnk).
97
+ // The log section's content: the model's curated rows as a fenced `jsonplurnk` array ({§jsonplurnk}).
69
98
  // Data only — no prose leads the fence (the log carries rules for no one). Empty log → ""
70
99
  // (the section is omitted).
71
100
  static renderLog(entries, countTokens) {
@@ -73,9 +102,9 @@ export default class PacketWire {
73
102
  if (log.length === 0)
74
103
  return "";
75
104
  const items = PacketWire.#renderLogEntries(log, countTokens);
76
- // The opening fence is DYNAMIC — one backtick longer than the longest run in any body — so a
77
- // code sample inside a body can never close the block early (CommonMark closes a fence only on
78
- // a line of ≥ its own length). §jsonplurnk-dynamic-fence
105
+ // The opening fence is DYNAMIC — one backtick longer than the longest run in the rendered
106
+ // entries — so a code sample inside a body can never close the block early (CommonMark closes
107
+ // a fence only on a line of ≥ its own length). {§jsonplurnk-dynamic-fence}
79
108
  const longestTicks = Math.max(0, ...[...items.matchAll(/`+/g)].map((m) => m[0].length));
80
109
  const fence = "`".repeat(Math.max(3, longestTicks + 1));
81
110
  return `${fence}jsonplurnk\n[\n${items}\n]\n${fence}`;
@@ -97,64 +126,8 @@ export default class PacketWire {
97
126
  { role: "user", content: PacketWire.renderSlot(sections, "user") },
98
127
  ];
99
128
  }
100
- // Measure the curatable log section's budget subtotals from the STRUCTURED
101
- // log (the foldable unit), using the provider's tokenizer — meta lines and
102
- // fences included, matching what ships. Feeds the per-turn rollup (chronological;
103
- // the grinder folds the newest turn) and the FOLD unit (heaviest entries) — the
104
- // two budget levers the model can pull (§tokenomics {§tokenomics-turn-totals},
105
- // {§tokenomics-largest-entries}). Build-time only; the stored log section is
106
- // the rendered result. §tokenomics-render-weight-budget
107
- static measureLogBudget(entries, countTokens) {
108
- const logEntries = Array.isArray(entries) ? entries : [];
109
- const logBody = logEntries.length > 0 ? PacketWire.renderLog(logEntries, countTokens) : "";
110
- const HEAVIEST_COUNT = 5;
111
- const currentLoop = logEntries.reduce((max, e) => {
112
- const l = typeof e.coordinate === "string" ? Number(e.coordinate.split("/")[0]) : NaN;
113
- return Number.isFinite(l) && l > max ? l : max;
114
- }, 0);
115
- const byTurn = new Map();
116
- const perEntry = [];
117
- for (const e of logEntries) {
118
- // Two weights, two purposes (#466 — one labeled semantic per number): the row's FULL
119
- // render (meta line + fences + body) composes the turn rollup — the room the turn takes in
120
- // the packet; the heaviest list carries the row's BODY weight — the FOLD unit, the SAME
121
- // number the row's own `tokens` shows, so the budget and the log can never disagree
122
- // about one row. A row ranks ONLY when a FOLD would actually reclaim it: a bodyless
123
- // row has nothing to fold, an already-folded row is already reclaimed (its price is
124
- // an OPEN's cost), and the current loop's foisted preview is refused (§prompt-fold-
125
- // illegal) — listing any of these sells the model a lever that 403s or no-ops.
126
- const bodyPrice = [];
127
- const weight = countTokens(PacketWire.#renderLogEntries([e], countTokens, bodyPrice));
128
- const coordinate = typeof e.coordinate === "string" ? e.coordinate : null;
129
- const op = typeof e.op === "string" && e.op.length > 0 ? e.op : null;
130
- // Turn = the loop_seq/turn_seq prefix of the coordinate
131
- // (log:///<loop_seq>/<turn_seq>/<sequence>); the sequence drops off.
132
- if (coordinate !== null) {
133
- const turn = coordinate.split("/").slice(0, 2).join("/");
134
- byTurn.set(turn, (byTurn.get(turn) ?? 0) + weight);
135
- }
136
- const path = PacketWire.#entryPath(coordinate, op);
137
- const isPreview = e.target?.scheme === "prompt" && e.origin === "plurnk" && op === "READ"
138
- && coordinate !== null && Number(coordinate.split("/")[0]) === currentLoop;
139
- const foldable = e.folded !== true && !isPreview;
140
- if (path !== null && foldable && (bodyPrice[0] ?? 0) > 0)
141
- perEntry.push({ path, tokens: bodyPrice[0] });
142
- }
143
- return {
144
- entries: logEntries.length,
145
- tokens: logBody ? countTokens(`## Plurnk Service Log\n\n${logBody}`) : 0,
146
- byTurn: [...byTurn.entries()]
147
- .map(([turn, tokens]) => ({ turn, tokens }))
148
- .toSorted((a, b) => {
149
- const [al, at] = a.turn.split("/").map(Number);
150
- const [bl, bt] = b.turn.split("/").map(Number);
151
- return al - bl || at - bt;
152
- }),
153
- largest: perEntry.toSorted((a, b) => b.tokens - a.tokens).slice(0, HEAVIEST_COUNT),
154
- };
155
- }
156
129
  // Number each line of body as `<N>:<line>` — a bare `N:` prefix, NO separator whitespace
157
- // (#564, owner policy pivot): the leading digit prevents column-zero fence collisions and gives
130
+ // ({§render-rule-line-navigable-prefix}): the leading digit prevents column-zero fence collisions and gives
158
131
  // the model line refs for free (`READ<42-46>`), while the absence of any separator means a
159
132
  // reproduced line has nothing between `N:` and the content to copy — the hard-tab separator used
160
133
  // to leak into edit bodies and corrupt indentation. The content's OWN leading whitespace is
@@ -162,32 +135,25 @@ export default class PacketWire {
162
135
  // Used for READ@200 content; index-preview numbering is the framework's
163
136
  // job now (baked into the preview string — see renderHeredoc).
164
137
  static #numberLines(body, start = 1) {
165
- if (!body)
166
- return "";
167
- const trailingNewline = body.endsWith("\n");
168
- const source = trailingNewline ? body.slice(0, -1) : body;
169
- const numbered = source.split("\n").map((line, i) => `${start + i}:${line}`).join("\n");
170
- return trailingNewline ? `${numbered}\n` : numbered;
138
+ let line = start;
139
+ return body.replace(/(^|\r\n|\r|\n)(?=[\s\S])/g, (separator) => `${separator}${line++}:`);
171
140
  }
172
141
  // The single content-body renderer EVERY output-emitting op routes through, so the line-number
173
- // convention the model orients on can't drift: line-navigable mimetypes (text/*) get the `N:`
174
- // prefix from `startLine`; tree-navigable (JSON/XML/HTML) render verbatim so jsonpath/xpath
175
- // isn't shifted. Empty content ⇒ "" (the meta line stands alone). §render-rule-line-navigable-prefix
176
- static #renderContentBody(fence, content, mimetype, startLine = 1) {
142
+ // convention the model orients on can't drift. Every textual body receives
143
+ // the `N:` prefix from `startLine`; matchers consume canonical content before
144
+ // this presentation projection. Empty content produces no body.
145
+ static #renderContentBody(fence, content, startLine = 1) {
177
146
  if (content.length === 0)
178
147
  return "";
179
- // Line-navigable text gets the `N:` source-line prefix from startLine. `startLine === null`
180
- // means the content is ALREADY source-numbered — a matcher result whose lines carry their own
181
- // (non-contiguous) source numbers like `143:…`; re-numbering would double it to `1:143:…`
182
- // (one source-line prefix). Render verbatim. §render-rule-line-navigable-prefix
183
- const rendered = MimetypeBinary.isLineNavigableMimetype(mimetype) && startLine !== null
148
+ // `startLine === null` means the producer already supplied numbered
149
+ // content; re-numbering would duplicate its coordinates.
150
+ const rendered = startLine !== null
184
151
  ? PacketWire.#numberLines(content, startLine)
185
152
  : content;
186
153
  return PacketWire.#wrapHeredocBody(fence, rendered);
187
154
  }
188
- // Tolerant JSON parser for log entries' rx/tx fields. The engine
189
- // pre-parses application/json mimetypes, but render may also receive
190
- // strings (legacy paths, manual tests). Returns null on parse failure.
155
+ // Tolerant JSON parser for log entries' persisted rx/tx strings. The engine
156
+ // pre-parses application/json mimetypes; malformed stored text is not JSON.
191
157
  static #safeParse(s) {
192
158
  try {
193
159
  return JSON.parse(s);
@@ -197,8 +163,7 @@ export default class PacketWire {
197
163
  }
198
164
  }
199
165
  // Stable JSON: keys sorted alphabetically so the same meta produces the
200
- // same string across turns — prefix-cache friendly. Mirrors rummy
201
- // plugins/helpers.js canonicalJson.
166
+ // same string across turns — prefix-cache friendly.
202
167
  static #canonicalJson(obj) {
203
168
  const keys = Object.keys(obj).sort();
204
169
  const sorted = {};
@@ -206,107 +171,81 @@ export default class PacketWire {
206
171
  sorted[k] = obj[k];
207
172
  return JSON.stringify(sorted);
208
173
  }
209
- // Wrap a body in heredoc fences. Leading `\n` always (separates the
210
- // opening fence from the first body character — necessary because
211
- // numbered bodies start with `1:…` which would otherwise collide
212
- // visually with the `:::FENCE` markers). Trailing `\n` only when the
213
- // body doesn't already end with one — otherwise you get a doubled
214
- // newline that renders as a blank line before the closing fence, which
215
- // reads as "the content has a trailing blank line" when actually it
174
+ static #receiptMeta(value) {
175
+ const receipt = assertEditReceipt(value);
176
+ const head = {
177
+ rev: receipt.revision.slice(0, editReceiptRevisionChars()),
178
+ extent: `${receipt.unit} ${receipt.before}->${receipt.after}`,
179
+ };
180
+ if ("effect" in receipt) {
181
+ return {
182
+ ...head,
183
+ change: `-${receipt.effect.removed} +${receipt.effect.inserted}`,
184
+ range: `${receipt.effect.requested} ${receipt.effect.source}->${receipt.effect.result}`,
185
+ };
186
+ }
187
+ return {
188
+ ...head,
189
+ disposition: receipt.disposition,
190
+ requested: receipt.requested,
191
+ ...(receipt.replacement === undefined
192
+ ? {}
193
+ : {
194
+ change: `-${receipt.replacement.removed} +${receipt.replacement.inserted}`,
195
+ replacement: `${receipt.replacement.requested} ${receipt.replacement.source}->${receipt.replacement.result}`,
196
+ }),
197
+ };
198
+ }
199
+ // Wrap a body in heredoc fences. The fence is FIXED (`<<BODY`/`BODY`), never the
200
+ // target: every body line is `N:`-prefixed, so a bare fence line can never occur
201
+ // inside a body, and a fixed fence gives the model nothing address-shaped to
202
+ // mimic back as op syntax — identity lives in the adjacent meta JSON. Leading
203
+ // `\n` always (separates the opening fence from the first body character).
204
+ // Trailing `\n` only when the body doesn't already end with one — otherwise you
205
+ // get a doubled newline that renders as a blank line before the closing fence,
206
+ // which reads as "the content has a trailing blank line" when actually it
216
207
  // doesn't. The body's own whitespace decides the shape.
217
208
  static #wrapHeredocBody(fence, body) {
218
209
  const sep = body.endsWith("\n") ? "" : "\n";
219
- return `<<:::${fence}\n${body}${sep}:::${fence}`;
220
- }
221
- // Heredoc block for one channel of one entry. Fence is `URI#channel`
222
- // (the `<<:::FENCE` packet-rendering marker per wrapHeredocBody — a
223
- // projection is read-only context, NOT an emittable op, so it must not
224
- // wear the DSL op-fence; that conflation was the demo.sh corruption bug).
225
- // When `channel` is null/empty the fence is path-only —
226
- // this is the default-channel convention: the absence of `#channel` is
227
- // the addressing of the scheme's default channel, not a missing field.
228
- // Body is a mimetypes preview, rendered VERBATIM — the framework owns its
229
- // formatting (N: line numbers for text, source-annotated outline for
230
- // symbols, correct start-line for tail slices) and bakes it into the
231
- // preview string as of mimetypes 0.7.3, so the service must not re-number
232
- // it (re-numbering would double-prefix text and mis-number symbol
233
- // outlines — plurnk-mimetypes#8).
234
- static #renderHeredoc(uri, channel, body) {
235
- const fence = channel ? `${uri}#${channel}` : uri;
236
- return PacketWire.#wrapHeredocBody(fence, body);
237
- }
238
- // Render a (scheme, pathname) tuple as the URI the model should SEE.
239
- // Null scheme → bare pathname. The `file` scheme never reaches this
240
- // function because Dispatcher.#extractTarget normalizes it to null at the
241
- // storage boundary; storage and wire output are uniform on this.
242
- static #renderModelUri(scheme, pathname) {
243
- const path = pathname ?? "";
244
- // #370 — a null scheme is a workspace file, whose member key is /rel but whose MODEL-FACING
245
- // form is the bare relative path (the catalog lists data/users.json; FIND returns it; the
246
- // model types it). Rendering /data/users.json minted a second spelling of the same file.
247
- if (scheme === null || scheme === undefined)
248
- return encodePathParens(path.replace(/^\//, ""));
249
- return renderAddress(scheme, path);
210
+ return `<<BODY\n${body}${sep}BODY`;
250
211
  }
251
212
  // Render one Log entry → a single bullet line carrying the meta JSON.
252
213
  // No body, no fence — every meaningful field is in the JSON. Naming
253
214
  // follows the uniform principle: `path` is identity (this log row's
254
- // own URI), `target` is the URI the action acted on. COPY/MOVE add
255
- // `source`; currently the engine emits target only (source plumbing
256
- // pending the COPY/MOVE-specific log shape pass).
215
+ // own URI), `target` is the URI in the statement's target slot. COPY/MOVE
216
+ // retain their source and destination selections separately from ordered
217
+ // applied `effects`.
257
218
  //
258
- // On error, status >= 400 signals the failure; the message lives in
259
- // the next packet's user.telemetry.errors[] per SPEC §telemetry. (Forward:
260
- // meta will gain tokensBefore/After + linesBefore/After to convey
261
- // change scope without carrying the body content.)
219
+ // On error, status >= 400 signals the failure; Problem Details live on
220
+ // this durable row and the next packet's Errors section points here.
262
221
  //
263
- // Per-entry render: one meta JSON line plus a body block that the model
264
- // can read to know what it did. Two body cases:
265
- // 1. READ@200 with content → render rx.content under the target fence.
266
- // The model asked for content; show it the content. (Matcher is in
267
- // meta.matcher, count is in meta.matches.)
268
- // 2. Every other op → re-emit tx as a heredoc in the model's native
269
- // syntax. The model wrote this; mirror it back so the log is a true
270
- // record of its actions instead of a row of opaque status codes.
271
- // The log:/// handle the model sees for an entry — its FOLD target
272
- // (§open-fold) and the label the budget's heaviest-entries readout reuses,
273
- // so the readout names an entry exactly as the log does.
222
+ // Per-entry render: one meta JSON line plus the row's canonical body.
223
+ // LogBody owns tx/rx storage interpretation; packet projection owns only
224
+ // visibility, previewing, mimetype rendering, and metadata.
225
+ // The log:/// handle the model sees for an entry.
226
+ // ({§open-fold}).
274
227
  static #entryPath(coordinate, op) {
275
228
  if (coordinate === null)
276
229
  return null;
277
230
  return op !== null ? `log:///${coordinate}/${op}` : `log:///${coordinate}`;
278
231
  }
279
- // `collectBodyTokens`, when supplied, receives each row's body weight (the rendered meta.tokens)
280
- // in order — the FOLD unit measureLogBudget ranks, guaranteed identical to what the row shows.
281
- // §arrival-law (#499) — the pushed-lane bound: another actor's text rides OPEN only up to
282
- // the preview (N lines AND 80×N chars — the char cap guards single-line bombs); over, the
283
- // head rides with the cut stated and the address for a deliberate pull. run111 entry 56:
284
- // a child's ratified 19,363-token deliverable landed whole in its parent and cascaded.
285
- static #arrivalPreview(text) {
286
- const maxLines = Number(process.env.PLURNK_SERVICE_ARRIVAL_PREVIEW_LINES ?? "16");
287
- const maxChars = 80 * maxLines;
288
- const lines = text.split("\n");
289
- if (lines.length <= maxLines && text.length <= maxChars)
290
- return { text, cut: false };
291
- const head = lines.slice(0, maxLines).join("\n").slice(0, maxChars);
292
- return { text: head, cut: true };
293
- }
294
- // §arrival-law (#566): a model-COMPOSED op body — a PLAN/SEND/WORK/FORK's text or an EXEC
295
- // command — renders PREVIEW-bounded, so the model can never compose an unbounded OPEN log row.
296
- // run42: an unclosed `<<PLAN` swallowed a 57k-char runaway into ONE 29k open row the grinder is
297
- // forbidden to fold (op NOT IN … 'PLAN') — a permanent budget bomb that pushed the packet past
298
- // the physical window and gated out the recovery. CONTENT ops are exempt and render FULL —
299
- // READ/FIND (retrieved bytes; capping a READ would break its `<start,end>` slice contract) and
300
- // EDIT/COPY/MOVE spans (the resulting file content the model inspects). The verbatim emission
301
- // always survives in the folded `model` mirror, so nothing is lost; a cut states the true extent.
302
- static #renderAuthoredBody(logAddr, body, preNumbered) {
303
- const arrival = PacketWire.#arrivalPreview(body);
304
- const rendered = preNumbered
305
- ? PacketWire.#wrapHeredocBody(logAddr, arrival.text)
306
- : PacketWire.#renderContentBody(logAddr, arrival.text, "text/plain");
307
- return arrival.cut ? `${rendered}\n… preview — the full body is ${body.split("\n").length} line(s)` : rendered;
232
+ // One preview function for every bounded model-facing projection. Lines
233
+ // protect ordinary documents and chars protect a single-line bomb.
234
+ static #preview(text) {
235
+ const { lines: maxLines, chars: maxChars } = previewBounds();
236
+ let lineEnd = text.length;
237
+ let newline = -1;
238
+ for (let line = 0; line < maxLines; line++) {
239
+ newline = text.indexOf("\n", newline + 1);
240
+ if (newline === -1)
241
+ break;
242
+ if (line === maxLines - 1)
243
+ lineEnd = newline + 1;
244
+ }
245
+ const end = Math.min(text.length, lineEnd, maxChars);
246
+ return { text: text.slice(0, end), cut: end < text.length };
308
247
  }
309
- static #renderLogEntries(entries, countTokens, collectBodyTokens) {
248
+ static #renderLogEntries(entries, countTokens) {
310
249
  return entries.map((e) => {
311
250
  const meta = {};
312
251
  const coordinate = typeof e.coordinate === "string" ? e.coordinate : null;
@@ -327,186 +266,126 @@ export default class PacketWire {
327
266
  meta.path = path;
328
267
  if (typeof e.origin === "string")
329
268
  meta.origin = e.origin;
330
- // §env-delta: the environment-delta cause (a sibling run or a scheme),
331
- // rendered when present; absent ⇒ the owning run itself (self).
269
+ // {§env-delta-attribution}: render the causal worker address or
270
+ // subsystem token when present; absence means the owning worker.
332
271
  if (typeof e.source === "string" && e.source.length > 0)
333
- meta.run = e.source;
272
+ meta.source = e.source;
334
273
  if (renderedOp !== null)
335
274
  meta.op = renderedOp;
336
275
  if (typeof e.status === "number")
337
276
  meta.status = e.status;
277
+ const tx = (typeof e.tx === "string" ? PacketWire.#safeParse(e.tx) : e.tx);
338
278
  const target = PacketWire.#renderActionTarget(e.target);
339
- if (target !== null)
340
- meta.target = target;
341
- // EXEC's output is a separate stream entry (§exec-stream); its address rides in a
279
+ if (op === "COPY" || op === "MOVE") {
280
+ const source = PacketWire.#renderSelection(e.target ?? tx?.target, tx?.lineMarker);
281
+ const destinationBody = tx?.body !== null && typeof tx?.body === "object"
282
+ ? tx.body
283
+ : null;
284
+ const destination = PacketWire.#renderSelection(destinationBody?.target, destinationBody?.lineMarker);
285
+ if (source !== null)
286
+ meta.source = source;
287
+ if (destination !== null)
288
+ meta.destination = destination;
289
+ if (typeof e.status === "number"
290
+ && e.status < 400
291
+ && (source === null || destination === null)) {
292
+ throw new Error(`A successful ${op} log row must retain both operand selections.`);
293
+ }
294
+ }
295
+ else {
296
+ if (target !== null)
297
+ meta.target = target;
298
+ }
299
+ // EXEC's output is a separate stream entry ({§exec-stream}); its address rides in a
342
300
  // `stream` link, distinct from `target` (the cwd / executable path it ran in).
343
301
  if (op === "EXEC" && e.attrs !== null && typeof e.attrs === "object" && typeof e.attrs.stream === "string") {
344
302
  meta.stream = e.attrs.stream;
345
303
  }
346
304
  // Parse rx once — reused for the matcher/items enrichment and the body.
347
305
  const rx = (typeof e.rx === "string" ? PacketWire.#safeParse(e.rx) : e.rx);
348
- // §log-row-self-explains — a FAILED op row carries its failure message ON THE META LINE,
349
- // so the record explains itself in every packet, folded or open. The old shape (a bare
350
- // status; the message buried in an rx no render shows) is what sent the wildcard model
351
- // theorizing "SEND[409] probably means bad request?" for 201s, and the jumbo model
352
- // chasing a phantom "engine error" off a message-less item. The row IS the model's op
353
- // result — it states its own why; the errors section stays a terse pointer at it.
306
+ // {§log-row-self-explains} — a failed operation projects its exact
307
+ // Problem on the row meta line; Errors remains only an index.
354
308
  if (typeof e.status === "number" && e.status >= 400 && rx !== null && typeof rx === "object") {
355
- const why = rx;
356
- const text = typeof why.error === "string" ? why.error : typeof why.reason === "string" ? why.reason : typeof why.message === "string" ? why.message : null;
357
- if (text !== null && text.length > 0)
358
- meta.error = text;
309
+ const problem = rx.problem;
310
+ Validator.assertProblemDetails(problem);
311
+ meta.problem = problem;
359
312
  }
360
- // READ + FIND enrichment: the matcher body (from tx) + `items`, the count
361
- // of rows the op returned — a matcher's hits, or a bare catalog FIND's entry
362
- // count. Without it the model can't tell "0 results" from "empty content",
363
- // nor weigh a re-FIND. `matches` when the dispatch tallied it; else a FIND
364
- // body is a JSON array whose length IS the count.
313
+ // READ + FIND enrichment: the matcher body, READ match coordinates,
314
+ // and FIND resource count. Match coordinates let the model choose a
315
+ // surgical follow-up READ without silently narrowing this result.
365
316
  let items = null;
366
317
  if (op === "READ" || op === "FIND") {
367
- const tx = e.tx;
368
318
  if (tx !== null && tx !== undefined && typeof tx === "object" && tx.body !== null && typeof tx.body === "object") {
369
319
  if (typeof tx.body.raw === "string")
370
320
  meta.matcher = tx.body.raw;
371
321
  }
372
- if (op === "FIND" && rx !== null && typeof rx === "object" && typeof rx.overflow === "number") {
373
- items = rx.overflow; // §find-count-not-contents — the full match count, though the rows weren't enumerated
374
- }
375
- else if (rx !== null && typeof rx === "object" && typeof rx.matches === "number") {
376
- items = rx.matches;
322
+ if (op === "FIND" && rx !== null && typeof rx === "object" && typeof rx.omittedItems === "number") {
323
+ items = rx.omittedItems; // {§find-count-not-contents} - selected-resource count, though rows were not enumerated
377
324
  }
378
325
  else if (op === "FIND" && rx !== null && typeof rx === "object" && typeof rx.content === "string") {
379
326
  const parsed = PacketWire.#safeParse(rx.content);
380
327
  if (Array.isArray(parsed))
381
328
  items = parsed.length;
382
329
  }
330
+ if (op === "READ" && rx !== null && typeof rx === "object" && rx.matches !== undefined) {
331
+ meta.matches = SchemeResults.assertMatchEvidenceList(rx.matches);
332
+ }
333
+ if (op === "READ" && rx !== null && typeof rx === "object" && rx.region !== undefined) {
334
+ meta.region = Validator.assertTextRegion(rx.region);
335
+ }
383
336
  // The matched set's content weight (sum of the entries' live channel tokens) — the
384
337
  // FIND self-describes its hits' READ-weight; carries the per-scheme roll-up in the foist.
385
338
  if (op === "FIND" && rx !== null && typeof rx === "object" && typeof rx.itemsTokenTotal === "number") {
386
339
  meta.itemsTokenTotal = rx.itemsTokenTotal;
387
340
  }
388
341
  }
389
- // The foldable body — computed ALWAYS (folded too), because `tokens` measures it: for
390
- // an open row that's what a FOLD would save, for a folded row what an OPEN would cost.
391
- // "" ⇒ genuinely no body (an empty FIND, an empty EDIT span, a @204).
392
- let body = "";
393
- if (op === "FIND" && e.status === 200 && items === 0) {
394
- // Empty FIND result → no body. items:0 already says "empty"; rendering [] under a
395
- // fence is redundant noise. (The always-foisted empty known:///** / unknown:///**
396
- // workspace rows are the common case.)
397
- body = "";
398
- }
399
- else if ((op === "READ" || op === "FIND") && e.status === 200 &&
400
- rx !== null && typeof rx === "object" && typeof rx.content === "string" && rx.content.length > 0) {
401
- // READ@200 / FIND@200: the content READ pulled, or the catalog rows / matched
402
- // entries FIND returned (§render-rule-find-renders-result) — the turn-0 foisted
403
- // FIND(scheme:///**) reaches the packet here, as does the exec-stream injector's
404
- // foisted READ of the channel. #renderContentBody applies the line-number convention
405
- // (§render-rule-line-navigable-prefix / §render-rule-tree-navigable-verbatim).
406
- const mimetype = typeof rx.mimetype === "string" ? rx.mimetype : "text/plain";
407
- // startLine === null is the matcher-result signal (already source-numbered → verbatim);
408
- // a number numbers from it; absent → 1 (whole-content default).
409
- const start = rx.startLine === null ? null : (typeof rx.startLine === "number" ? rx.startLine : 1);
410
- // §arrival-law — a foisted READ of a prompt path is PUSHED content (user- or
411
- // sibling-authored); the render-side preview bounds it like any arrival, closing
412
- // the single-line char-bomb the line-slice alone cannot cut (line markers cannot
413
- // cut mid-line; the render can). Model-authored READs stay self-invited — untouched.
414
- const promptPush = e.origin === "plurnk" && op === "READ"
415
- && e.target !== null && typeof e.target === "object" && e.target.scheme === "prompt";
416
- const streamPush = e.origin === "plurnk" && op === "READ" && mimetype === "text/stream";
417
- if (promptPush || streamPush) {
418
- const arrival = PacketWire.#arrivalPreview(rx.content);
419
- body = PacketWire.#renderContentBody(target ?? `log:///${coordinate}`, arrival.text, mimetype, start);
420
- if (arrival.cut) {
421
- const noun = streamPush ? "stream output" : "prompt";
422
- body += `\n… arrival preview — the full ${noun} is ${rx.content.split("\n").length} line(s), ${rx.content.length} chars: READ ${target}`;
423
- }
424
- }
425
- else {
426
- body = PacketWire.#renderContentBody(target ?? `log:///${coordinate}`, rx.content, mimetype, start);
427
- }
428
- }
429
- else if (op === "EDIT" && rx !== null && typeof rx === "object" && rx.receipt !== null && typeof rx.receipt === "object") {
430
- const receipt = rx.receipt;
431
- const effect = receipt.effect;
432
- if (typeof receipt.revision !== "string" || !/^[a-f0-9]{64}$/.test(receipt.revision)
433
- || (receipt.unit !== "lines" && receipt.unit !== "items")
434
- || typeof receipt.before !== "number" || typeof receipt.after !== "number"
435
- || effect === undefined
436
- || typeof effect.requested !== "string" || typeof effect.source !== "string" || typeof effect.result !== "string"
437
- || typeof effect.removed !== "number" || typeof effect.inserted !== "number" || typeof effect.context !== "string") {
438
- throw new Error("invalid structured EDIT receipt");
439
- }
440
- meta.rev = receipt.revision.slice(0, editReceiptRevisionChars());
441
- meta.extent = `${receipt.unit} ${receipt.before}→${receipt.after}`;
442
- meta.change = `-${effect.removed} +${effect.inserted}`;
443
- meta.range = `${effect.requested} ${effect.source}→${effect.result}`;
444
- if (effect.context.length > 0)
445
- body = PacketWire.#wrapHeredocBody(target ?? `log:///${coordinate}`, effect.context);
446
- }
447
- else if ((op === "EDIT" || op === "COPY" || op === "MOVE") && rx !== null && typeof rx === "object" && (typeof rx.receipt === "string" || typeof rx.span === "string" || typeof rx.body === "string")) {
448
- // EDIT renders its bounded effect receipt; COPY/MOVE and environment-delta
449
- // EDITs retain their resulting span. Each is already line-addressed where
450
- // appropriate, so wrapping is verbatim.
451
- const r = rx;
452
- const span = typeof r.receipt === "string" ? r.receipt : typeof r.span === "string" ? r.span : (r.body ?? "");
453
- // An EDIT/COPY/MOVE span is the RESULTING file content — bytes the model inspects to
454
- // confirm its edit landed, CONTENT not composed directive text — so it renders FULL
455
- // like READ/FIND (#566). Grinder-foldable (not PLAN-exempt), so a large span reclaims.
456
- if (span.length > 0)
457
- body = PacketWire.#wrapHeredocBody(target ?? `log:///${coordinate}`, span);
458
- }
459
- else if (op === "EXEC" && e.tx !== null && e.tx !== undefined && typeof e.tx.body === "string") {
460
- // EXEC: the literal command body, :::-fenced + line-numbered at the op's log address —
461
- // the model sees what it ran and can reference lines of its own code. The OUTPUT is a
462
- // SEPARATE stream (meta.stream), surfaced by the injector, never re-emitted here. §exec-stream
463
- body = PacketWire.#renderAuthoredBody(path ?? `log:///${coordinate}`, e.tx.body, false);
342
+ // {§edit-result-receipt-projection} {§edit-result-copy-move-effects}
343
+ // Mutations expose compact, validated outcome metadata. EDIT owns
344
+ // one receipt; COPY/MOVE own ordered resource effects whose
345
+ // optional receipts describe scoped textual materializations.
346
+ if (op === "EDIT" && rx !== null && typeof rx === "object" && Object.hasOwn(rx, "receipt")) {
347
+ Object.assign(meta, PacketWire.#receiptMeta(rx.receipt));
464
348
  }
465
- else if ((op === "PLAN" || op === "SEND" || op === "WORK" || op === "FORK") && e.tx !== null && e.tx !== undefined) {
466
- // PLAN's plan / SEND's message / WORK's & FORK's seed task ride into the log as N:
467
- // content at the op's log address — a dispatch's record IS the task it dispatched, so
468
- // the next turn reads what each worker is doing (the spawn-then-retask confusion was
469
- // this body missing: the log showed "spawned worker-db" with no task). The log
470
- // mirrors the model's WORK, NEVER a repeated <<OP:…:OP tag (tags are emission
471
- // syntax, not the log paradigm). Bodyless ops (COPY/MOVE/OPEN/FOLD, a non-200 READ/FIND
472
- // whose matcher already rides in meta, a span-less EDIT) fall through to their meta line.
473
- const b = e.tx.body;
474
- const opBody = typeof b === "string" ? b
475
- : b !== null && typeof b === "object" && typeof b.raw === "string" ? b.raw : "";
476
- if (opBody.length > 0)
477
- body = PacketWire.#renderAuthoredBody(path ?? `log:///${coordinate}`, opBody, false);
478
- // §worker-scheme-collect: an injected SEND (a child worker's concluded deliverable surfaced in
479
- // the parent) has no authored tx body — its payload is the deliverable in rx (a raw string,
480
- // not the {status} envelope a model SEND gets). Surface it so a child's 2xx reaches the
481
- // parent OPEN (born-open at the insert), never a bodyless `*` row.
482
- else if (op === "SEND" && opBody.length === 0 && typeof e.rx === "string" && e.rx.length > 0) {
483
- // §arrival-law — the deliverable is PUSHED content: preview-bounded, never whole-by-default.
484
- const arrival = PacketWire.#arrivalPreview(e.rx);
485
- body = PacketWire.#renderContentBody(path ?? `log:///${coordinate}`, arrival.text, "text/plain");
486
- if (arrival.cut)
487
- body += `\n… arrival preview — the full deliverable is ${e.rx.split("\n").length} lines: READ worker://${(e.target && typeof e.target === "object" && "pathname" in e.target ? String(e.target.pathname ?? "") : "").replace(/^\//, "")}`;
488
- }
349
+ if ((op === "COPY" || op === "MOVE")
350
+ && rx !== null
351
+ && typeof rx === "object"
352
+ && Object.hasOwn(rx, "effects")) {
353
+ meta.effects = assertResourceEffects(rx.effects).map((effect) => ({
354
+ target: effect.target,
355
+ action: effect.action,
356
+ ...(effect.receipt === undefined
357
+ ? {}
358
+ : PacketWire.#receiptMeta(effect.receipt)),
359
+ }));
489
360
  }
490
- else if (op === "error") {
491
- // §telemetry — a parse-error row is a LOG ITEM; its body is the parser message, which
492
- // carries the content-offset `line:col`. The model resolves that line against its own
493
- // emission — READ the folded `model` mirror row (§model-entry) — so no snippet is embedded.
494
- // Foldable like any body; the errors section keeps only a pointer (status + coordinate).
495
- const detail = (rx !== null && typeof rx === "object" ? rx : {});
496
- if (typeof detail.message === "string" && detail.message.length > 0) {
497
- body = PacketWire.#wrapHeredocBody(path ?? `log:///${coordinate}`, detail.message);
498
- }
361
+ // The canonical full body is shared with READ(log://), FIND(log://),
362
+ // and search derivation. Only a worker-issued READ/FIND result renders
363
+ // complete; every pushed, authored, ambient, plugin, and engine body
364
+ // uses this one preview projection.
365
+ const fullBody = LogBody.resolve({
366
+ op: op ?? "",
367
+ tx: e.tx,
368
+ rx: e.rx,
369
+ mimetypeTx: typeof e.mimetype_tx === "string" ? e.mimetype_tx : undefined,
370
+ mimetypeRx: typeof e.mimetype_rx === "string" ? e.mimetype_rx : undefined,
371
+ });
372
+ const emptyFind = op === "FIND" && e.status === 200 && items === 0;
373
+ const previewExempt = e.origin === "model" && (op === "READ" || op === "FIND");
374
+ const projection = previewExempt
375
+ ? { text: fullBody.content, cut: false }
376
+ : PacketWire.#preview(fullBody.content);
377
+ const resourceBody = op === "READ" || op === "FIND" || op === "EDIT"
378
+ || op === "prompt";
379
+ const bodyFence = resourceBody ? (target ?? path) : path;
380
+ if (projection.cut && path === null) {
381
+ throw new Error("a previewed log body requires an addressable log path");
499
382
  }
500
- else if (op === "model") {
501
- // §model-entry — the model's own verbatim emission, mirrored back so it sees exactly
502
- // what it produced. Line-numbered like all content (the parser reports errors by line,
503
- // so the model can reason about its own syntax error). Folded by default → just the
504
- // meta line until OPENed; the turn-0 exemplar is born open (the worked example).
505
- if (rx !== null && typeof rx === "object" && typeof rx.content === "string" && rx.content.length > 0) {
506
- const mimetype = typeof rx.mimetype === "string" ? rx.mimetype : "text/vnd.plurnk";
507
- body = PacketWire.#renderContentBody(path ?? `log:///${coordinate}`, rx.content, mimetype);
508
- }
383
+ if (projection.cut) {
384
+ meta.overflow = `Body content truncated. Use READ ${path} to view the full body.`;
509
385
  }
386
+ const body = emptyFind || projection.text.length === 0
387
+ ? ""
388
+ : PacketWire.#renderContentBody(bodyFence ?? `log:///${coordinate}`, projection.text, fullBody.startLine);
510
389
  // tokens on EVERY row (0 when there's genuinely no body) so the model can always weigh
511
390
  // it; for a folded row this is the room an OPEN would add. items present even at 0.
512
391
  if (items !== null)
@@ -514,7 +393,6 @@ export default class PacketWire {
514
393
  // 0 for a genuinely empty body — never call countTokens("") (some providers return
515
394
  // undefined for it, which JSON.stringify would drop, leaving the row with no tokens).
516
395
  meta.tokens = body.length > 0 ? countTokens(body) : 0;
517
- collectBodyTokens?.push(meta.tokens);
518
396
  // lines beside tokens on any row with a navigable body — the count of `N:`-numbered
519
397
  // lines (fences and unnumbered prose don't count), so the model can plan a <start,end>
520
398
  // slice before paying for an OPEN. Omitted when the body isn't line-addressable.
@@ -523,13 +401,14 @@ export default class PacketWire {
523
401
  if (navigable > 0)
524
402
  meta.lines = navigable;
525
403
  }
526
- // §jsonplurnk — the `display` field (grammar-ratified name #437) replaces the old -/+/*
527
- // glyph: `none` (no body, nothing to OPEN), `folded` (body exists, hidden — OPEN to expand),
528
- // `open` (body shown). `display:none` mirrors CSS the model knows; `folded`/`open` echo the
529
- // FOLD/OPEN ops. The one deviation from valid JSON: an OPEN row appends its heredoc body as a
530
- // raw `body` value (unescaped, delimited by its <<:::tag … :::tag fence). §jsonplurnk
404
+ // {§jsonplurnk} — `display` describes the three body states: `none` carries an explicit
405
+ // empty JSON string, `folded` withholds an existing body, and `open` appends that body as
406
+ // the format's one non-JSON value (a raw, tagged heredoc). The explicit empty body keeps
407
+ // every state self-describing; OPEN/FOLD remain friendly no-ops on `none`.
531
408
  const display = body.length === 0 ? "none" : e.folded === true ? "folded" : "open";
532
409
  meta.display = display;
410
+ if (display === "none")
411
+ meta.body = "";
533
412
  const obj = PacketWire.#canonicalJson(meta);
534
413
  return display === "open" ? obj.replace(/\}$/, `,"body":\n${body}\n}`) : obj;
535
414
  }).join(",\n");
@@ -537,41 +416,36 @@ export default class PacketWire {
537
416
  static #renderActionTarget(target) {
538
417
  if (target === null || target === undefined)
539
418
  return null;
540
- // An authority-bearing target (worker://<name> — the worker IS the authority, §worker-scheme;
541
- // a web host http://host/path) keeps its name in `hostname`. Without it a spawn renders
542
- // as a bare `worker://`, indistinguishable across workers — the model goes blind to what it
543
- // spawned and re-spawns. Reconstruct the authority form when a hostname is present;
544
- // namespace schemes (plurnk/known) fold their authority into the path and fall through.
545
- const host = typeof target.hostname === "string" && target.hostname.length > 0 ? target.hostname : null;
546
- const rendered = host !== null && typeof target.scheme === "string" && target.scheme.length > 0
547
- ? `${target.scheme}://${host}${target.port ? `:${target.port}` : ""}${encodePathParens(target.pathname ?? "")}`
548
- : PacketWire.#renderModelUri(target.scheme, target.pathname);
549
- if (rendered.length === 0)
419
+ return renderTarget({
420
+ scheme: target.scheme,
421
+ hostname: target.hostname,
422
+ port: target.port,
423
+ pathname: target.pathname,
424
+ query: target.query,
425
+ fragment: target.fragment,
426
+ });
427
+ }
428
+ static #renderSelection(target, marker) {
429
+ if (target === null || target === undefined)
430
+ return null;
431
+ const address = target.kind === "local" && typeof target.raw === "string"
432
+ ? renderTarget({ scheme: null, pathname: target.raw })
433
+ : target.scheme === "file"
434
+ ? renderTarget({ scheme: null, pathname: target.pathname ?? "" })
435
+ : PacketWire.#renderActionTarget(target);
436
+ if (address === null || address.length === 0)
550
437
  return null;
551
- // The channel fragment (#stdout/#stderr) is part of the address — a stream delta has to
552
- // say WHICH channel it is, not just the entry. §exec-stream
553
- const fragment = typeof target.fragment === "string" && target.fragment.length > 0 ? `#${target.fragment}` : "";
554
- return rendered + fragment;
438
+ if (marker === null || marker === undefined)
439
+ return address;
440
+ const validation = Validator.validateLineMarker(marker);
441
+ if (!validation.valid) {
442
+ throw new TypeError("A COPY/MOVE operand contains an invalid line marker.");
443
+ }
444
+ return `${address}<${marker.marks.join(",")}>`;
555
445
  }
556
446
  static #renderGitState(git) {
557
447
  const sync = git.ahead > 0 || git.behind > 0 ? ` (↑${git.ahead} ↓${git.behind})` : "";
558
448
  return `branch \`${git.branch}\`${sync} — ${git.staged} staged, ${git.unstaged} unstaged, ${git.untracked} untracked`;
559
449
  }
560
- static #renderTelemetryErrors(errors) {
561
- // Uniform projection off the formal TelemetryEvent envelope (grammar TelemetryEvent.json):
562
- // render each error by its typed `position`, never by sniffing `kind`. A LogCoordinate is a
563
- // terse `<status> log:///<coord>` link to the row (the row holds the term + detail); a
564
- // ContentOffset points the model at the line in its own born-OPEN emission (§model-entry).
565
- // No JSON dump — the packet teaches, the row carries the body.
566
- return errors.map((e) => {
567
- const ev = e;
568
- const pos = ev.position;
569
- if (pos?.type === "log-coordinate")
570
- return `* ${ev.status ?? ""} log:///${pos.coordinate}`.replace(/ +/g, " ");
571
- if (pos?.type === "content-offset")
572
- return `* ${ev.kind ?? "error"} ${pos.line}:${pos.column}`;
573
- return `* ${ev.kind ?? "error"}`;
574
- }).join("\n");
575
- }
576
450
  }
577
451
  //# sourceMappingURL=packet-wire.js.map