@plurnk/plurnk-service 1.3.12 → 1.5.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 (488) hide show
  1. package/.env.defaults +95 -91
  2. package/INSTALL.md +54 -28
  3. package/README.md +25 -10
  4. package/SPEC.md +2426 -942
  5. package/dist/Paths.d.ts +4 -1
  6. package/dist/Paths.d.ts.map +1 -1
  7. package/dist/Paths.js +24 -23
  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 +4 -3
  18. package/dist/content/index.d.ts.map +1 -1
  19. package/dist/content/index.js +2 -1
  20. package/dist/content/index.js.map +1 -1
  21. package/dist/content/line-marker.d.ts +10 -9
  22. package/dist/content/line-marker.d.ts.map +1 -1
  23. package/dist/content/line-marker.js +8 -11
  24. package/dist/content/line-marker.js.map +1 -1
  25. package/dist/content/matcher.d.ts +15 -26
  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-projector.d.ts +14 -0
  36. package/dist/content/read-projector.d.ts.map +1 -0
  37. package/dist/content/read-projector.js +86 -0
  38. package/dist/content/read-projector.js.map +1 -0
  39. package/dist/content/read-resolve.d.ts +6 -7
  40. package/dist/content/read-resolve.d.ts.map +1 -1
  41. package/dist/content/read-resolve.js +36 -59
  42. package/dist/content/read-resolve.js.map +1 -1
  43. package/dist/core/BranchReceipt.d.ts +6 -0
  44. package/dist/core/BranchReceipt.d.ts.map +1 -0
  45. package/dist/core/BranchReceipt.js +24 -0
  46. package/dist/core/BranchReceipt.js.map +1 -0
  47. package/dist/core/BudgetOverflow.d.ts +20 -0
  48. package/dist/core/BudgetOverflow.d.ts.map +1 -0
  49. package/dist/core/BudgetOverflow.js +49 -0
  50. package/dist/core/BudgetOverflow.js.map +1 -0
  51. package/dist/core/BudgetReadout.d.ts +8 -0
  52. package/dist/core/BudgetReadout.d.ts.map +1 -0
  53. package/dist/core/BudgetReadout.js +79 -0
  54. package/dist/core/BudgetReadout.js.map +1 -0
  55. package/dist/core/ChannelWrite.d.ts +31 -9
  56. package/dist/core/ChannelWrite.d.ts.map +1 -1
  57. package/dist/core/ChannelWrite.js +30 -23
  58. package/dist/core/ChannelWrite.js.map +1 -1
  59. package/dist/core/ChannelWrite.sql +14 -12
  60. package/dist/core/CoreSchemeServices.d.ts +18 -4
  61. package/dist/core/CoreSchemeServices.d.ts.map +1 -1
  62. package/dist/core/CoreSchemeServices.js +7 -1
  63. package/dist/core/CoreSchemeServices.js.map +1 -1
  64. package/dist/core/Dispatcher.d.ts +26 -21
  65. package/dist/core/Dispatcher.d.ts.map +1 -1
  66. package/dist/core/Dispatcher.js +1626 -671
  67. package/dist/core/Dispatcher.js.map +1 -1
  68. package/dist/core/DurableStatement.d.ts +6 -0
  69. package/dist/core/DurableStatement.d.ts.map +1 -0
  70. package/dist/core/DurableStatement.js +51 -0
  71. package/dist/core/DurableStatement.js.map +1 -0
  72. package/dist/core/Engine.d.ts +64 -29
  73. package/dist/core/Engine.d.ts.map +1 -1
  74. package/dist/core/Engine.js +1348 -835
  75. package/dist/core/Engine.js.map +1 -1
  76. package/dist/core/Engine.sql +329 -234
  77. package/dist/core/EnvFlags.js +1 -1
  78. package/dist/core/EnvFlags.js.map +1 -1
  79. package/dist/core/ErrorDetail.d.ts +6 -0
  80. package/dist/core/ErrorDetail.d.ts.map +1 -0
  81. package/dist/core/ErrorDetail.js +20 -0
  82. package/dist/core/ErrorDetail.js.map +1 -0
  83. package/dist/core/ExecutorRegistry.d.ts +14 -3
  84. package/dist/core/ExecutorRegistry.d.ts.map +1 -1
  85. package/dist/core/ExecutorRegistry.js +56 -30
  86. package/dist/core/ExecutorRegistry.js.map +1 -1
  87. package/dist/core/GitBranch.d.ts +20 -0
  88. package/dist/core/GitBranch.d.ts.map +1 -0
  89. package/dist/core/GitBranch.js +110 -0
  90. package/dist/core/GitBranch.js.map +1 -0
  91. package/dist/core/JournalTurn.d.ts +9 -0
  92. package/dist/core/JournalTurn.d.ts.map +1 -0
  93. package/dist/core/JournalTurn.js +14 -0
  94. package/dist/core/JournalTurn.js.map +1 -0
  95. package/dist/core/JournalTurn.sql +10 -0
  96. package/dist/core/LogBody.d.ts +18 -0
  97. package/dist/core/LogBody.d.ts.map +1 -0
  98. package/dist/core/LogBody.js +180 -0
  99. package/dist/core/LogBody.js.map +1 -0
  100. package/dist/core/LoopFlagsReader.d.ts +7 -0
  101. package/dist/core/LoopFlagsReader.d.ts.map +1 -0
  102. package/dist/core/LoopFlagsReader.js +33 -0
  103. package/dist/core/LoopFlagsReader.js.map +1 -0
  104. package/dist/core/LoopLifecycle.d.ts +8 -2
  105. package/dist/core/LoopLifecycle.d.ts.map +1 -1
  106. package/dist/core/LoopLifecycle.js +54 -11
  107. package/dist/core/LoopLifecycle.js.map +1 -1
  108. package/dist/core/LoopLifecycle.sql +10 -7
  109. package/dist/core/NoticeChannel.d.ts +13 -0
  110. package/dist/core/NoticeChannel.d.ts.map +1 -0
  111. package/dist/core/NoticeChannel.js +40 -0
  112. package/dist/core/NoticeChannel.js.map +1 -0
  113. package/dist/core/Owner.d.ts +0 -1
  114. package/dist/core/Owner.d.ts.map +1 -1
  115. package/dist/core/Owner.js +2 -5
  116. package/dist/core/Owner.js.map +1 -1
  117. package/dist/core/PacketBuilder.d.ts +27 -25
  118. package/dist/core/PacketBuilder.d.ts.map +1 -1
  119. package/dist/core/PacketBuilder.js +321 -383
  120. package/dist/core/PacketBuilder.js.map +1 -1
  121. package/dist/core/ProblemLog.d.ts +26 -0
  122. package/dist/core/ProblemLog.d.ts.map +1 -0
  123. package/dist/core/ProblemLog.js +58 -0
  124. package/dist/core/ProblemLog.js.map +1 -0
  125. package/dist/core/ProposalLifecycle.d.ts +15 -21
  126. package/dist/core/ProposalLifecycle.d.ts.map +1 -1
  127. package/dist/core/ProposalLifecycle.js +291 -78
  128. package/dist/core/ProposalLifecycle.js.map +1 -1
  129. package/dist/core/ProviderInstantiate.d.ts.map +1 -1
  130. package/dist/core/ProviderInstantiate.js +51 -48
  131. package/dist/core/ProviderInstantiate.js.map +1 -1
  132. package/dist/core/SchemeRegistry.d.ts +14 -8
  133. package/dist/core/SchemeRegistry.d.ts.map +1 -1
  134. package/dist/core/SchemeRegistry.js +189 -114
  135. package/dist/core/SchemeRegistry.js.map +1 -1
  136. package/dist/core/ServiceTeardown.d.ts +11 -0
  137. package/dist/core/ServiceTeardown.d.ts.map +1 -0
  138. package/dist/core/ServiceTeardown.js +70 -0
  139. package/dist/core/ServiceTeardown.js.map +1 -0
  140. package/dist/core/StoredPacket.d.ts +29 -0
  141. package/dist/core/StoredPacket.d.ts.map +1 -0
  142. package/dist/core/StoredPacket.js +147 -0
  143. package/dist/core/StoredPacket.js.map +1 -0
  144. package/dist/core/StrikeRail.d.ts +6 -3
  145. package/dist/core/StrikeRail.d.ts.map +1 -1
  146. package/dist/core/StrikeRail.js +27 -56
  147. package/dist/core/StrikeRail.js.map +1 -1
  148. package/dist/core/TerminalResult.d.ts +16 -0
  149. package/dist/core/TerminalResult.d.ts.map +1 -0
  150. package/dist/core/TerminalResult.js +49 -0
  151. package/dist/core/TerminalResult.js.map +1 -0
  152. package/dist/core/WorkerControlAddress.d.ts +17 -0
  153. package/dist/core/WorkerControlAddress.d.ts.map +1 -0
  154. package/dist/core/WorkerControlAddress.js +44 -0
  155. package/dist/core/WorkerControlAddress.js.map +1 -0
  156. package/dist/core/WorkerName.d.ts +31 -0
  157. package/dist/core/WorkerName.d.ts.map +1 -0
  158. package/dist/core/WorkerName.js +95 -0
  159. package/dist/core/WorkerName.js.map +1 -0
  160. package/dist/core/WorkerName.sql +36 -0
  161. package/dist/core/WorkspaceGate.d.ts +14 -0
  162. package/dist/core/WorkspaceGate.d.ts.map +1 -0
  163. package/dist/core/WorkspaceGate.js +155 -0
  164. package/dist/core/WorkspaceGate.js.map +1 -0
  165. package/dist/core/caps/CapsResolve.d.ts +5 -1
  166. package/dist/core/caps/CapsResolve.d.ts.map +1 -1
  167. package/dist/core/caps/CapsResolve.js +8 -4
  168. package/dist/core/caps/CapsResolve.js.map +1 -1
  169. package/dist/core/caps/DbChannelCaps.d.ts +5 -11
  170. package/dist/core/caps/DbChannelCaps.d.ts.map +1 -1
  171. package/dist/core/caps/DbChannelCaps.js +30 -12
  172. package/dist/core/caps/DbChannelCaps.js.map +1 -1
  173. package/dist/core/caps/DbEntryCaps.d.ts +5 -14
  174. package/dist/core/caps/DbEntryCaps.d.ts.map +1 -1
  175. package/dist/core/caps/DbEntryCaps.js +27 -8
  176. package/dist/core/caps/DbEntryCaps.js.map +1 -1
  177. package/dist/core/caps/DbNotifyCaps.d.ts +1 -1
  178. package/dist/core/caps/DbNotifyCaps.d.ts.map +1 -1
  179. package/dist/core/caps/DbNotifyCaps.js +18 -15
  180. package/dist/core/caps/DbNotifyCaps.js.map +1 -1
  181. package/dist/core/caps/DbProjectionCaps.d.ts +5 -5
  182. package/dist/core/caps/DbProjectionCaps.d.ts.map +1 -1
  183. package/dist/core/caps/DbProjectionCaps.js +21 -4
  184. package/dist/core/caps/DbProjectionCaps.js.map +1 -1
  185. package/dist/core/caps/DbSubscriptionCaps.d.ts +4 -6
  186. package/dist/core/caps/DbSubscriptionCaps.d.ts.map +1 -1
  187. package/dist/core/caps/DbSubscriptionCaps.js +75 -66
  188. package/dist/core/caps/DbSubscriptionCaps.js.map +1 -1
  189. package/dist/core/caps/DbTagCaps.d.ts +5 -12
  190. package/dist/core/caps/DbTagCaps.d.ts.map +1 -1
  191. package/dist/core/caps/DbTagCaps.js +20 -11
  192. package/dist/core/caps/DbTagCaps.js.map +1 -1
  193. package/dist/core/caps/SchemeCtxImpl.d.ts +6 -1
  194. package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -1
  195. package/dist/core/caps/SchemeCtxImpl.js +6 -6
  196. package/dist/core/caps/SchemeCtxImpl.js.map +1 -1
  197. package/dist/core/content-hash.js +1 -1
  198. package/dist/core/content-hash.js.map +1 -1
  199. package/dist/core/env-defaults.d.ts.map +1 -1
  200. package/dist/core/env-defaults.js.map +1 -1
  201. package/dist/core/fork.d.ts.map +1 -1
  202. package/dist/core/fork.js +55 -30
  203. package/dist/core/fork.js.map +1 -1
  204. package/dist/core/fork.sql +43 -29
  205. package/dist/core/git-env.d.ts +2 -0
  206. package/dist/core/git-env.d.ts.map +1 -1
  207. package/dist/core/git-env.js +13 -18
  208. package/dist/core/git-env.js.map +1 -1
  209. package/dist/core/git-iso.d.ts +3 -2
  210. package/dist/core/git-iso.d.ts.map +1 -1
  211. package/dist/core/git-iso.js +36 -27
  212. package/dist/core/git-iso.js.map +1 -1
  213. package/dist/core/git-membership.d.ts +2 -1
  214. package/dist/core/git-membership.d.ts.map +1 -1
  215. package/dist/core/git-membership.js +276 -162
  216. package/dist/core/git-membership.js.map +1 -1
  217. package/dist/core/git-state.d.ts +8 -1
  218. package/dist/core/git-state.d.ts.map +1 -1
  219. package/dist/core/git-state.js +44 -26
  220. package/dist/core/git-state.js.map +1 -1
  221. package/dist/core/namespace.d.ts +1 -0
  222. package/dist/core/namespace.d.ts.map +1 -1
  223. package/dist/core/namespace.js +20 -0
  224. package/dist/core/namespace.js.map +1 -1
  225. package/dist/core/optimistic-settlement.d.ts +2 -0
  226. package/dist/core/optimistic-settlement.d.ts.map +1 -0
  227. package/dist/core/optimistic-settlement.js +14 -0
  228. package/dist/core/optimistic-settlement.js.map +1 -0
  229. package/dist/core/owner.sql +1 -1
  230. package/dist/core/packet-inject.d.ts.map +1 -1
  231. package/dist/core/packet-inject.js +7 -11
  232. package/dist/core/packet-inject.js.map +1 -1
  233. package/dist/core/packet-wire.d.ts +3 -21
  234. package/dist/core/packet-wire.d.ts.map +1 -1
  235. package/dist/core/packet-wire.js +305 -385
  236. package/dist/core/packet-wire.js.map +1 -1
  237. package/dist/core/plurnk-uri.d.ts +12 -1
  238. package/dist/core/plurnk-uri.d.ts.map +1 -1
  239. package/dist/core/plurnk-uri.js +49 -29
  240. package/dist/core/plurnk-uri.js.map +1 -1
  241. package/dist/core/results.d.ts +18 -5
  242. package/dist/core/results.d.ts.map +1 -1
  243. package/dist/core/results.js +33 -18
  244. package/dist/core/results.js.map +1 -1
  245. package/dist/core/ruler_count.d.ts +4 -0
  246. package/dist/core/ruler_count.d.ts.map +1 -0
  247. package/dist/core/ruler_count.js +7 -0
  248. package/dist/core/ruler_count.js.map +1 -0
  249. package/dist/core/scheme-types.d.ts +3 -17
  250. package/dist/core/scheme-types.d.ts.map +1 -1
  251. package/dist/core/scheme-types.js.map +1 -1
  252. package/dist/core/search-gate.d.ts.map +1 -1
  253. package/dist/core/search-gate.js +3 -11
  254. package/dist/core/search-gate.js.map +1 -1
  255. package/dist/core/teaching-corpus.d.ts +6 -0
  256. package/dist/core/teaching-corpus.d.ts.map +1 -0
  257. package/dist/core/teaching-corpus.js +23 -0
  258. package/dist/core/teaching-corpus.js.map +1 -0
  259. package/dist/core/teaching.d.ts +0 -1
  260. package/dist/core/teaching.d.ts.map +1 -1
  261. package/dist/core/teaching.js +2 -8
  262. package/dist/core/teaching.js.map +1 -1
  263. package/dist/core/token-ruler.d.ts.map +1 -1
  264. package/dist/core/token-ruler.js +3 -16
  265. package/dist/core/token-ruler.js.map +1 -1
  266. package/dist/core/turn-scheduler.d.ts +1 -1
  267. package/dist/core/turn-scheduler.d.ts.map +1 -1
  268. package/dist/core/turn-scheduler.js +1 -1
  269. package/dist/core/turn-scheduler.js.map +1 -1
  270. package/dist/core/worker-cap.d.ts +2 -4
  271. package/dist/core/worker-cap.d.ts.map +1 -1
  272. package/dist/core/worker-cap.js +13 -4
  273. package/dist/core/worker-cap.js.map +1 -1
  274. package/dist/core/{run-ops.sql → worker-ops.sql} +14 -14
  275. package/dist/core/workspace-settings.d.ts.map +1 -1
  276. package/dist/core/workspace-settings.js +17 -9
  277. package/dist/core/workspace-settings.js.map +1 -1
  278. package/dist/digest/Digest.d.ts +2 -1
  279. package/dist/digest/Digest.d.ts.map +1 -1
  280. package/dist/digest/Digest.js +510 -149
  281. package/dist/digest/Digest.js.map +1 -1
  282. package/dist/digest/digest.sql +23 -10
  283. package/dist/index.d.ts.map +1 -1
  284. package/dist/index.js +3 -5
  285. package/dist/index.js.map +1 -1
  286. package/dist/observe/api.d.ts +6 -0
  287. package/dist/observe/api.d.ts.map +1 -0
  288. package/dist/observe/api.js +11 -0
  289. package/dist/observe/api.js.map +1 -0
  290. package/dist/observe/init.d.ts +7 -0
  291. package/dist/observe/init.d.ts.map +1 -0
  292. package/dist/observe/init.js +159 -0
  293. package/dist/observe/init.js.map +1 -0
  294. package/dist/observe/metrics.d.ts +6 -0
  295. package/dist/observe/metrics.d.ts.map +1 -0
  296. package/dist/observe/metrics.js +15 -0
  297. package/dist/observe/metrics.js.map +1 -0
  298. package/dist/observe/spans.d.ts +4 -0
  299. package/dist/observe/spans.d.ts.map +1 -0
  300. package/dist/observe/spans.js +51 -0
  301. package/dist/observe/spans.js.map +1 -0
  302. package/dist/schemes/EffectPolicy.d.ts +1 -0
  303. package/dist/schemes/EffectPolicy.d.ts.map +1 -1
  304. package/dist/schemes/EffectPolicy.js +5 -2
  305. package/dist/schemes/EffectPolicy.js.map +1 -1
  306. package/dist/schemes/Exec.d.ts +9 -14
  307. package/dist/schemes/Exec.d.ts.map +1 -1
  308. package/dist/schemes/Exec.js +402 -262
  309. package/dist/schemes/Exec.js.map +1 -1
  310. package/dist/schemes/ExecOutputScheme.d.ts +9 -9
  311. package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
  312. package/dist/schemes/ExecOutputScheme.js +49 -18
  313. package/dist/schemes/ExecOutputScheme.js.map +1 -1
  314. package/dist/schemes/File.d.ts +7 -13
  315. package/dist/schemes/File.d.ts.map +1 -1
  316. package/dist/schemes/File.js +280 -151
  317. package/dist/schemes/File.js.map +1 -1
  318. package/dist/schemes/Log.d.ts +8 -12
  319. package/dist/schemes/Log.d.ts.map +1 -1
  320. package/dist/schemes/Log.js +402 -233
  321. package/dist/schemes/Log.js.map +1 -1
  322. package/dist/schemes/Log.sql +71 -32
  323. package/dist/schemes/Prompt.d.ts +3 -3
  324. package/dist/schemes/Prompt.d.ts.map +1 -1
  325. package/dist/schemes/Prompt.js +10 -10
  326. package/dist/schemes/Prompt.js.map +1 -1
  327. package/dist/schemes/Skill.d.ts +2 -3
  328. package/dist/schemes/Skill.d.ts.map +1 -1
  329. package/dist/schemes/Skill.js +2 -6
  330. package/dist/schemes/Skill.js.map +1 -1
  331. package/dist/schemes/Worker.d.ts +11 -19
  332. package/dist/schemes/Worker.d.ts.map +1 -1
  333. package/dist/schemes/Worker.js +210 -89
  334. package/dist/schemes/Worker.js.map +1 -1
  335. package/dist/schemes/_entry-chunk.d.ts.map +1 -1
  336. package/dist/schemes/_entry-chunk.js +12 -5
  337. package/dist/schemes/_entry-chunk.js.map +1 -1
  338. package/dist/schemes/_entry-crud.d.ts +11 -9
  339. package/dist/schemes/_entry-crud.d.ts.map +1 -1
  340. package/dist/schemes/_entry-crud.js +72 -13
  341. package/dist/schemes/_entry-crud.js.map +1 -1
  342. package/dist/schemes/_entry-crud.sql +28 -10
  343. package/dist/schemes/_entry-find.d.ts +49 -18
  344. package/dist/schemes/_entry-find.d.ts.map +1 -1
  345. package/dist/schemes/_entry-find.js +348 -195
  346. package/dist/schemes/_entry-find.js.map +1 -1
  347. package/dist/schemes/_entry-find.sql +20 -8
  348. package/dist/schemes/_entry-graph.d.ts +4 -2
  349. package/dist/schemes/_entry-graph.d.ts.map +1 -1
  350. package/dist/schemes/_entry-graph.js +55 -31
  351. package/dist/schemes/_entry-graph.js.map +1 -1
  352. package/dist/schemes/_entry-graph.sql +37 -22
  353. package/dist/schemes/_entry-manifest.d.ts +10 -15
  354. package/dist/schemes/_entry-manifest.d.ts.map +1 -1
  355. package/dist/schemes/_entry-manifest.js +50 -268
  356. package/dist/schemes/_entry-manifest.js.map +1 -1
  357. package/dist/schemes/_entry-ops.d.ts +14 -15
  358. package/dist/schemes/_entry-ops.d.ts.map +1 -1
  359. package/dist/schemes/_entry-ops.js +121 -110
  360. package/dist/schemes/_entry-ops.js.map +1 -1
  361. package/dist/schemes/_entry-ops.sql +2 -3
  362. package/dist/schemes/_entry-semantic.d.ts +22 -9
  363. package/dist/schemes/_entry-semantic.d.ts.map +1 -1
  364. package/dist/schemes/_entry-semantic.js +127 -67
  365. package/dist/schemes/_entry-semantic.js.map +1 -1
  366. package/dist/schemes/_entry-semantic.sql +63 -45
  367. package/dist/schemes/_entry-send.d.ts +3 -4
  368. package/dist/schemes/_entry-send.d.ts.map +1 -1
  369. package/dist/schemes/_entry-send.js +48 -23
  370. package/dist/schemes/_entry-send.js.map +1 -1
  371. package/dist/schemes/_path-scope.d.ts +23 -0
  372. package/dist/schemes/_path-scope.d.ts.map +1 -0
  373. package/dist/schemes/_path-scope.js +61 -0
  374. package/dist/schemes/_path-scope.js.map +1 -0
  375. package/dist/schemes/_search-candidate.d.ts +20 -0
  376. package/dist/schemes/_search-candidate.d.ts.map +1 -0
  377. package/dist/schemes/_search-candidate.js +19 -0
  378. package/dist/schemes/_search-candidate.js.map +1 -0
  379. package/dist/schemes/_search-exclusion.d.ts +7 -0
  380. package/dist/schemes/_search-exclusion.d.ts.map +1 -0
  381. package/dist/schemes/_search-exclusion.js +23 -0
  382. package/dist/schemes/_search-exclusion.js.map +1 -0
  383. package/dist/schemes/_search-index.d.ts +6 -0
  384. package/dist/schemes/_search-index.d.ts.map +1 -0
  385. package/dist/schemes/_search-index.js +328 -0
  386. package/dist/schemes/_search-index.js.map +1 -0
  387. package/dist/schemes/cosine.js +1 -1
  388. package/dist/schemes/cosine.js.map +1 -1
  389. package/dist/schemes/exec-abort.js +3 -3
  390. package/dist/schemes/exec-abort.js.map +1 -1
  391. package/dist/schemes/exec-env.js +3 -3
  392. package/dist/schemes/exec-env.js.map +1 -1
  393. package/dist/server/BranchBatches.d.ts +49 -0
  394. package/dist/server/BranchBatches.d.ts.map +1 -0
  395. package/dist/server/BranchBatches.js +592 -0
  396. package/dist/server/BranchBatches.js.map +1 -0
  397. package/dist/server/Daemon.d.ts +39 -71
  398. package/dist/server/Daemon.d.ts.map +1 -1
  399. package/dist/server/Daemon.js +1133 -491
  400. package/dist/server/Daemon.js.map +1 -1
  401. package/dist/server/DaemonModule.d.ts +31 -0
  402. package/dist/server/DaemonModule.d.ts.map +1 -0
  403. package/dist/server/DaemonModule.js +2 -0
  404. package/dist/server/DaemonModule.js.map +1 -0
  405. package/dist/server/branch-batch.sql +154 -0
  406. package/dist/server/client-input.d.ts +13 -0
  407. package/dist/server/client-input.d.ts.map +1 -1
  408. package/dist/server/client-input.js +268 -57
  409. package/dist/server/client-input.js.map +1 -1
  410. package/dist/server/dispatch-as-plurnk.d.ts +1 -1
  411. package/dist/server/dispatch-as-plurnk.d.ts.map +1 -1
  412. package/dist/server/dispatch-as-plurnk.js +15 -7
  413. package/dist/server/dispatch-as-plurnk.js.map +1 -1
  414. package/dist/server/drain.sql +96 -65
  415. package/dist/server/envelope.d.ts +4 -7
  416. package/dist/server/envelope.d.ts.map +1 -1
  417. package/dist/server/envelope.js +118 -95
  418. package/dist/server/envelope.js.map +1 -1
  419. package/dist/server/envelope.sql +18 -23
  420. package/dist/server/exec-poll-backoff.js +1 -1
  421. package/dist/server/exec-poll-backoff.js.map +1 -1
  422. package/dist/server/lifecycle-recovery.sql +112 -2
  423. package/dist/server/logEntry.d.ts +4 -2
  424. package/dist/server/logEntry.d.ts.map +1 -1
  425. package/dist/server/logEntry.js +6 -3
  426. package/dist/server/logEntry.js.map +1 -1
  427. package/dist/server/logEntry.sql +1 -1
  428. package/dist/server/loop-model.d.ts.map +1 -1
  429. package/dist/server/loop-model.js +22 -9
  430. package/dist/server/loop-model.js.map +1 -1
  431. package/dist/server/loopDocs.d.ts.map +1 -1
  432. package/dist/server/loopDocs.js +5 -4
  433. package/dist/server/loopDocs.js.map +1 -1
  434. package/dist/server/seam-entry-read.sql +15 -10
  435. package/dist/server/seam-log-read.sql +2 -2
  436. package/dist/server/seam-loop.sql +1 -1
  437. package/dist/server/seam-proposal-list.sql +17 -7
  438. package/dist/service.d.ts.map +1 -1
  439. package/dist/service.js +79 -61
  440. package/dist/service.js.map +1 -1
  441. package/migrations/001_schema.sql +1010 -0
  442. package/package.json +65 -32
  443. package/dist/core/PluginLoader.d.ts +0 -20
  444. package/dist/core/PluginLoader.d.ts.map +0 -1
  445. package/dist/core/PluginLoader.js +0 -142
  446. package/dist/core/PluginLoader.js.map +0 -1
  447. package/dist/core/TelemetryChannel.d.ts +0 -37
  448. package/dist/core/TelemetryChannel.d.ts.map +0 -1
  449. package/dist/core/TelemetryChannel.js +0 -80
  450. package/dist/core/TelemetryChannel.js.map +0 -1
  451. package/dist/core/path-decode.d.ts +0 -3
  452. package/dist/core/path-decode.d.ts.map +0 -1
  453. package/dist/core/path-decode.js +0 -9
  454. package/dist/core/path-decode.js.map +0 -1
  455. package/dist/core/plugin-attribution.d.ts +0 -5
  456. package/dist/core/plugin-attribution.d.ts.map +0 -1
  457. package/dist/core/plugin-attribution.js +0 -39
  458. package/dist/core/plugin-attribution.js.map +0 -1
  459. package/dist/core/world-state.d.ts +0 -10
  460. package/dist/core/world-state.d.ts.map +0 -1
  461. package/dist/core/world-state.js +0 -35
  462. package/dist/core/world-state.js.map +0 -1
  463. package/dist/core/world-state.sql +0 -35
  464. package/dist/core/zero-pin.d.ts +0 -3
  465. package/dist/core/zero-pin.d.ts.map +0 -1
  466. package/dist/core/zero-pin.js +0 -16
  467. package/dist/core/zero-pin.js.map +0 -1
  468. package/dist/server/auto.d.ts +0 -6
  469. package/dist/server/auto.d.ts.map +0 -1
  470. package/dist/server/auto.js +0 -63
  471. package/dist/server/auto.js.map +0 -1
  472. package/dist/server/clientTurn.d.ts +0 -6
  473. package/dist/server/clientTurn.d.ts.map +0 -1
  474. package/dist/server/clientTurn.js +0 -22
  475. package/dist/server/clientTurn.js.map +0 -1
  476. package/dist/server/clientTurn.sql +0 -10
  477. package/dist/server/noProposals.d.ts +0 -6
  478. package/dist/server/noProposals.d.ts.map +0 -1
  479. package/dist/server/noProposals.js +0 -37
  480. package/dist/server/noProposals.js.map +0 -1
  481. package/dist/server/version-info.d.ts +0 -14
  482. package/dist/server/version-info.d.ts.map +0 -1
  483. package/dist/server/version-info.js +0 -69
  484. package/dist/server/version-info.js.map +0 -1
  485. package/migrations/0000-00-00.01_schema.sql +0 -536
  486. package/migrations/0004_loop-provider.sql +0 -3
  487. package/migrations/0005_subscription-published-channel.sql +0 -3
  488. package/migrations/0006_loop-max-turns.sql +0 -3
@@ -3,56 +3,53 @@ import Namespace from "../core/namespace.js";
3
3
  import Owner from "../core/Owner.js";
4
4
  import { dirname, relative, isAbsolute, join, matchesGlob } from "node:path";
5
5
  import { createPatch } from "diff";
6
- import { decodePathParens } from "../core/path-decode.js";
6
+ import { PathSyntax } from "@plurnk/plurnk-contracts";
7
7
  import GitMembership from "../core/git-membership.js";
8
- import EntryOps from "./_entry-ops.js";
9
8
  import EntryFind from "./_entry-find.js";
10
9
  import EntryCrud from "./_entry-crud.js";
11
10
  import { CoreSchemeAdapterBase } from "../core/CoreSchemeServices.js";
12
- import { LineMarkerOps, MimetypeBinary, editReceipt, editReceiptUnit, editedSpan, projectEditReceipt } from "../content/index.js";
11
+ import ErrorDetail from "../core/ErrorDetail.js";
12
+ import Results from "../core/results.js";
13
+ import { InvalidOperationResultError, } from "@plurnk/plurnk-schemes";
14
+ import { LineMarkerOps, MimetypeBinary, editReceipt, projectEditReceipt, reviewerReplacementReceipt, } from "../content/index.js";
13
15
  // Workspace root for file ops is sourced from `workspaces.project_root`,
14
- // supplied by the client at workspace.create (headless is forever; issue
15
- // #150 wired the RPC; F.1 added the column). Server doesn't guess —
16
- // the client owns workspace identity. If a workspace is headless
17
- // (project_root=null), file ops fail at 400; the client either supplies
18
- // a root or the op isn't appropriate for this workspace.
16
+ // supplied at {§methods-workspace-create}. Under {§fs-namespace}, core never
17
+ // guesses a root: headless workspaces fail file operations at 400.
19
18
  const loadWorkspaceRoot = async (db, workspaceId) => {
20
19
  const row = await db.envelope_get_workspace.get({ id: workspaceId });
21
20
  return row?.project_root ?? null;
22
21
  };
23
- // Detect mimetype from a file's path. Routes through the Mimetypes service
24
- // when available; falls back to the text primitive (text/markdown). The
22
+ // Detect mimetype from a file's path through the configured registry. The
25
23
  // `MimetypeBinary.normalizeAutoTextMimetype` wrapper ensures text/plain returned by the
26
24
  // service is normalized to text/markdown — plurnk-service never auto-
27
25
  // derives text/plain (see mimetype-binary.ts MimetypeBinary.TEXT_PRIMITIVE_MIMETYPE).
28
26
  const detectFileMimetype = async (canonical, ctx) => {
29
- if (ctx.mimetypes !== undefined) {
30
- const detected = await ctx.mimetypes.detect({ path: canonical });
31
- return MimetypeBinary.normalizeAutoTextMimetype(detected);
32
- }
33
- return MimetypeBinary.TEXT_PRIMITIVE_MIMETYPE;
27
+ if (ctx.mimetypes === undefined)
28
+ throw new Error("detectFileMimetype: configured mimetype registry is required");
29
+ const detected = await ctx.mimetypes.detect({ path: canonical });
30
+ return MimetypeBinary.normalizeAutoTextMimetype(detected);
34
31
  };
35
- // SECURITY — File is entry-backed, identical to Known: read()/find()/readEntry()
36
- // delegate to the shared Entry* helpers over the membership-materialized entries
37
- // (scheme=null). The membership gate is now ENTRY-EXISTENCE — a non-member has no
38
- // entry, so read/find/readEntry 404 it for free, the same invariant Known runs on
32
+ // SECURITY — File's exact READ uses the core projector and broad FIND uses the
33
+ // shared entry query over the membership-materialized entries
34
+ // (stored under scheme="file"). The membership gate is now ENTRY-EXISTENCE — a non-member has no
35
+ // entry, so every read-side consumer 404s it at the shared entry boundary
39
36
  // (a gitignored `.env` is never a member → never an entry → never readable). Disk
40
37
  // I/O is confined to the two edges that own it: the git-membership materialize-IN
41
- // and edit()/applyResolution()'s proposal-gated write-OUT (§membership), where the
38
+ // and edit()/applyResolution()'s proposal-gated write-OUT ({§membership}), where the
42
39
  // containment/traversal checks live.
43
40
  //
44
- // writeEntry() is the proposal-gated write-back: a COPY/MOVE *into* file:/// is a disk
45
- // write, so it flows through the SAME §membership gate as EDIT (#resolveWriteTarget) — a
41
+ // Core-only writeEntry() is the proposal-gated write-back: a COPY/MOVE *into* file:/// is a disk
42
+ // write, so it flows through the SAME {§membership} gate as EDIT (#resolveWriteTarget) — a
46
43
  // 202 proposal, then applyResolution() writes on accept — never an ungated overwrite (the
47
- // `.env`-wipe this guard prevents). COPY/MOVE *from* file:/// is readEntry (read-only).
44
+ // `.env`-wipe this guard prevents). COPY/MOVE *from* file:/// uses the core-only
45
+ // readEntry adapter.
48
46
  export default class File extends CoreSchemeAdapterBase {
49
47
  static manifest = {
50
48
  name: "file",
51
- storedScheme: "file", // {§entry-identity-no-null} — file rows persist under the reserved 'file' scheme (a NULL identity component voids the UNIQUE index; run59/#545); renders as a bare path
49
+ storedScheme: "file", // {§entry-identity-no-null} — durable identity; file addresses still render as bare paths
52
50
  channels: {}, // dynamic mimetype per file extension
53
51
  defaultChannel: "body",
54
52
  category: "data",
55
- scope: "workspace",
56
53
  writableBy: ["model", "client", "plugin"],
57
54
  volatile: false,
58
55
  modelVisible: true,
@@ -60,18 +57,6 @@ export default class File extends CoreSchemeAdapterBase {
60
57
  example: "<<READ(README.md)::READ",
61
58
  documentation: "The project's workspace files (git-tracked members, shown as bare paths) — THE TASK'S FILES: when asked to change the project, EDIT these, not your notes or scratch. READ and FIND them like any entry; EDIT proposes a diff for review and only writes to disk once accepted — the review is normal, not a refusal, so propose the edit rather than working around it. Non-members are invisible, so you can't read or clobber a file outside the tracked surface.",
62
59
  };
63
- // Entry-backed, identical to Known (the unified-addressing promise): read the
64
- // membership-materialized entry (scheme=null) through the shared helper. <L> /
65
- // body / binary-415 / tag-404 are all handled there; a non-member has no entry
66
- // → 404, the same gate Known runs on. Disk is reached only at the materialize
67
- // and write-back edges (git-membership, applyResolution) — never on a read.
68
- async read(statement, ctx) {
69
- const core = this.coreContext(ctx);
70
- // {§fs-namei} — canonicalize ONCE, up front: resolution never depends on what exists
71
- // (the old fold-on-miss retry was existence-dependent meaning, run59's disease class).
72
- const canon = File.#canonTarget(statement, await loadWorkspaceRoot(core.db, core.workspaceId));
73
- return EntryOps.readWorkspaceEntry(canon ?? statement, core, File.manifest);
74
- }
75
60
  // {§fs-namei}/{§fs-canonical-name} — the ONE statement-normalizing seam: every model
76
61
  // spelling resolves through Namespace.canonicalize before storage, comparison, or render.
77
62
  // null (a spelling that names nothing a file can be) falls back to the original statement,
@@ -94,11 +79,16 @@ export default class File extends CoreSchemeAdapterBase {
94
79
  }
95
80
  return statement; // regex — not a path
96
81
  }
97
- // Folderhood survives canonicalization (§find-scope-prefix-filter) — the shared
82
+ // Folderhood survives canonicalization ({§find-scope-prefix-filter}) — the shared
98
83
  // spelling canon lives on Namespace (the Dispatcher's log columns use the same one).
99
84
  static #canonSpelling(raw, root) {
100
85
  return Namespace.canonicalizeSpelling(raw, root);
101
86
  }
87
+ async resolveEntryAddress(target, ctx) {
88
+ const core = this.coreContext(ctx);
89
+ const pathname = File.#canonSpelling(target.kind === "url" ? target.pathname : target.raw, await loadWorkspaceRoot(core.db, core.workspaceId));
90
+ return pathname === null ? null : { pathname, owner: "commons" };
91
+ }
102
92
  async find(statement, ctx) {
103
93
  const core = this.coreContext(ctx);
104
94
  // {§fs-namei} — canonicalize the glob's path portion before the candidate scan, the
@@ -111,29 +101,47 @@ export default class File extends CoreSchemeAdapterBase {
111
101
  // see the SECURITY note above.
112
102
  async readEntry(pathname, ctx) {
113
103
  const core = this.coreContext(ctx);
114
- // §scheme-address — normalize the model-typed path (bare `brief.md`) to its `/rel` member key,
104
+ // {§scheme-address} — normalize the model-typed path (bare `brief.md`) to its `/rel` member key,
115
105
  // the same parity READ/EDIT/deleteEntry have. Without it a COPY/MOVE FROM a bare file path
116
106
  // misses the canonical-stored member and 404s a source that plainly exists.
117
107
  const root = await loadWorkspaceRoot(core.db, core.workspaceId);
118
108
  const key = root === null ? pathname : Namespace.canonicalize(pathname, root);
119
109
  return EntryCrud.readEntry(key ?? pathname, core, "file");
120
110
  }
121
- // §membership disk-write gate, shared by edit() and writeEntry() (the COPY/MOVE
111
+ // {§membership} disk-write gate, shared by edit() and writeEntry() (the COPY/MOVE
122
112
  // dest). Resolves the canonical path; enforces containment (traversal → 403),
123
113
  // membership (existing non-member → 403, the `.env` protection), the read-only
124
114
  // overlay (→ 403), and binary (→ 415); reads current content for the diff. A
125
115
  // not-found path is fine — we propose to CREATE. ONE home for the gate: an edit
126
116
  // and a copy into file:/// are the same disk write under the same review.
127
- // §membership-edit-membership-gate — membership/containment/read-only/binary gate before any disk write
117
+ // {§membership-edit-membership-gate} — membership/containment/read-only/binary gate before any disk write
128
118
  async #resolveWriteTarget(pathname, ctx) {
129
119
  const root = await loadWorkspaceRoot(ctx.db, ctx.workspaceId);
130
- if (root === null)
131
- return { ok: false, status: 400, error: "workspace has no project_root (headless is forever) — file ops need a workspace created with projectRoot" };
120
+ if (root === null) {
121
+ return {
122
+ ok: false,
123
+ code: "project-root-required",
124
+ status: 400,
125
+ detail: "The workspace has no project root, so it cannot write files.",
126
+ extensions: { retryable: false },
127
+ };
128
+ }
132
129
  // {§fs-namei} — the write side resolves through the SAME canonicalizer as reads;
133
130
  // a spelling that names nothing a file can be is refused before any disk touch.
134
131
  const key = Namespace.canonicalize(pathname, root);
135
- if (key === null)
136
- return { ok: false, status: 403, error: "path escapes workspace root" };
132
+ if (key === null) {
133
+ return {
134
+ ok: false,
135
+ code: "path-outside-workspace",
136
+ status: 403,
137
+ detail: `The requested path '${pathname}' is outside the workspace.`,
138
+ extensions: {
139
+ requestedPath: pathname,
140
+ recovery: "Use a path within the workspace.",
141
+ retryable: false,
142
+ },
143
+ };
144
+ }
137
145
  const isMount = key.startsWith("../");
138
146
  let canonical;
139
147
  const requested = join(root, key);
@@ -148,13 +156,35 @@ export default class File extends CoreSchemeAdapterBase {
148
156
  fileExists = false;
149
157
  }
150
158
  // {§fs-write-surface} 6 — only the root mints: no create on any mount, ever.
151
- if (isMount && !fileExists)
152
- return { ok: false, status: 403, error: "only the project root mints — create outside it is refused" };
159
+ if (isMount && !fileExists) {
160
+ return {
161
+ ok: false,
162
+ code: "mount-create-forbidden",
163
+ status: 403,
164
+ detail: `The mounted path '${key}' does not permit file creation.`,
165
+ extensions: {
166
+ path: key,
167
+ recovery: "Create the file inside the project root.",
168
+ retryable: false,
169
+ },
170
+ };
171
+ }
153
172
  if (!isMount) {
154
173
  const relBare = relative(root, canonical);
155
174
  // in-tree keys whose realpath escapes (a symlink out) stay refused — the jail holds.
156
- if (relBare.startsWith("..") || isAbsolute(relBare))
157
- return { ok: false, status: 403, error: "path escapes workspace root" };
175
+ if (relBare.startsWith("..") || isAbsolute(relBare)) {
176
+ return {
177
+ ok: false,
178
+ code: "path-outside-workspace",
179
+ status: 403,
180
+ detail: `The requested path '${pathname}' resolves outside the workspace.`,
181
+ extensions: {
182
+ requestedPath: pathname,
183
+ recovery: "Use a path within the workspace.",
184
+ retryable: false,
185
+ },
186
+ };
187
+ }
158
188
  }
159
189
  const rel = key; // the bare canonical member key ({§fs-canonical-name}) — storage ≡ wire
160
190
  let original = "";
@@ -164,116 +194,178 @@ export default class File extends CoreSchemeAdapterBase {
164
194
  const member = await ctx.db.crud_get_member_sig.get({ workspace_id: ctx.workspaceId, owner_id: await Owner.commonsId(ctx.db, ctx.workspaceId), scheme: "file", pathname: rel });
165
195
  // {§fs-errno} — the occupancy fact (POSIX O_EXCL precedent): something invisible
166
196
  // occupies the path; existence leaks, content stays dark. The model picks another name.
167
- if (member === undefined)
168
- return { ok: false, status: 403, error: `a file exists at ${rel}` };
197
+ if (member === undefined) {
198
+ return {
199
+ ok: false,
200
+ code: "path-occupied-by-nonmember",
201
+ status: 403,
202
+ detail: `A non-member file already occupies '${rel}'.`,
203
+ extensions: {
204
+ path: rel,
205
+ recovery: "Choose an unoccupied member path.",
206
+ retryable: false,
207
+ },
208
+ };
209
+ }
169
210
  // {§fs-write-surface} 5 — a git-included mount member is read-only: git's grants
170
211
  // confer rw only within the project; only an explicit client grant carries write.
171
- if (isMount && member.membership_origin === "git")
172
- return { ok: false, status: 403, error: "member is read-only" };
212
+ if (isMount && member.membership_origin === "git") {
213
+ return {
214
+ ok: false,
215
+ code: "member-read-only",
216
+ status: 403,
217
+ detail: `The mounted member '${rel}' is read-only.`,
218
+ extensions: { path: rel, retryable: false },
219
+ };
220
+ }
173
221
  const viewGlobs = (await ctx.db.crud_list_workspace_constraints.all({ workspace_id: ctx.workspaceId }))
174
222
  .filter((c) => c.effect === "view").map((c) => c.glob);
175
- if (viewGlobs.some((g) => matchesGlob(rel, g)))
176
- return { ok: false, status: 403, error: "member is read-only" }; // view = read-only member, 403 on edit — §membership-overlay-view
223
+ if (viewGlobs.some((g) => matchesGlob(rel, g))) {
224
+ return {
225
+ ok: false,
226
+ code: "member-read-only",
227
+ status: 403,
228
+ detail: `The member '${rel}' is read-only.`,
229
+ extensions: { path: rel, retryable: false },
230
+ };
231
+ } // view = read-only member, 403 on edit - {§membership-overlay-view}
177
232
  // The diff base is the entry's snapshot — the body channel the model READ — not a fresh
178
233
  // disk read. EDIT is naive against the view the model saw; the write-side CAS (applyResolution)
179
234
  // guards the landing. baseSig is that snapshot's stat, carried with the proposal so a sibling
180
- // worker's reconcile can't advance it under the paused proposal. §membership-edit-write-cas
235
+ // worker's reconcile can't advance it under the paused proposal. {§membership-edit-write-cas}
181
236
  const snapshot = await ctx.db.ops_read_channel.get({ workspace_id: ctx.workspaceId, owner_id: await Owner.commonsId(ctx.db, ctx.workspaceId), scheme: "file", pathname: rel, channel: "body" });
182
237
  original = snapshot?.content ?? "";
183
238
  baseSig = member.synced_sig;
184
239
  }
185
240
  else {
186
241
  // {§fs-write-surface} 1 — the blind-write closure: an exclusive CREATE is legal only
187
- // where the RESULT will be a member. A client pick admits it; else git's auto-add
188
- // must (untracked-not-ignored). A non-git root grants nothing by itself.
242
+ // where the RESULT will be a member. A client pick admits it; otherwise
243
+ // Git's untracked-not-ignored membership must ({§membership-auto-add}).
244
+ // No staging occurs. A non-git root grants nothing by itself.
189
245
  const picks = (await ctx.db.crud_list_workspace_constraints.all({ workspace_id: ctx.workspaceId }))
190
246
  .filter((c) => c.effect === "pick").map((c) => c.glob);
191
247
  const clientAdmits = picks.some((g) => matchesGlob(rel, g));
192
248
  if (!clientAdmits && !(await GitMembership.wouldGitAdmit(root, rel, ctx.signal))) {
193
- return { ok: false, status: 403, error: "create refused — the result would not be a member (git ignores it and no client pick covers it)" };
249
+ return {
250
+ ok: false,
251
+ code: "file-not-admitted",
252
+ status: 403,
253
+ detail: `The new file '${rel}' would not belong to the workspace because Git ignores it and no client pick includes it.`,
254
+ extensions: {
255
+ path: rel,
256
+ recovery: "Choose a path admitted by Git or the workspace picks.",
257
+ retryable: false,
258
+ },
259
+ };
194
260
  }
195
261
  // {§fs-write-surface} — the closure PROVED the grantor; the accept stamps what was
196
262
  // proven instead of leaving provenance NULL until the next reconcile guesses it.
197
263
  admittedBy = clientAdmits ? "client" : "git";
198
264
  }
199
265
  const mimetype = await detectFileMimetype(canonical, ctx);
200
- if (MimetypeBinary.isBinaryMimetype(mimetype))
201
- return { ok: false, status: 415, error: `cannot write binary mimetype \`${mimetype}\`` };
266
+ if (await MimetypeBinary.isBinaryMimetype(mimetype, ctx.mimetypes)) {
267
+ return {
268
+ ok: false,
269
+ code: "binary-write-unsupported",
270
+ status: 415,
271
+ detail: `File EDIT does not support binary mimetype '${mimetype}'.`,
272
+ extensions: {
273
+ mimetype,
274
+ retryable: false,
275
+ },
276
+ };
277
+ }
202
278
  return { ok: true, canonical, rel, fileExists, original, mimetype, baseSig, ...(admittedBy !== undefined ? { admittedBy } : {}) };
203
279
  }
204
- // Edit op (task #42 canonical proposal consumer). Returns status=202
205
- // with a udiff body for client review + attrs carrying the full patched
206
- // content. Engine writes the proposed log entry, pauses dispatch, and
207
- // calls applyResolution() (below) after the proposal accepts.
280
+ // {§membership-edit-write-cas}, {§proposal-202-pauses}: return status=202
281
+ // with a udiff body for client review and attrs carrying the full patched
282
+ // content. Engine pauses dispatch and calls applyResolution() after accept.
208
283
  async editBatch(statements, ctx) {
284
+ const failure = (code, status, detail, extensions = {}) => Results.failure("scheme:file", code, status, detail, {}, extensions);
209
285
  const statement = statements[0];
210
- if (statement === undefined)
211
- return { status: 400, error: "EDIT batch is empty" };
286
+ if (statement === undefined) {
287
+ return failure("edit-empty", 400, "EDIT requires at least one statement.", {
288
+ recovery: "Provide an EDIT statement.",
289
+ retryable: false,
290
+ });
291
+ }
212
292
  const core = this.coreContext(ctx);
213
- if (statement.target === null)
214
- return { status: 400, error: "EDIT requires a path" };
215
- const pathname = statement.target.kind === "regex" ? statement.target.raw
216
- : decodePathParens(statement.target.kind === "url" ? statement.target.pathname : statement.target.raw); // #239 item 4
293
+ if (statement.target === null) {
294
+ return failure("edit-target-required", 400, "EDIT requires a target path.", {
295
+ recovery: "Provide the file target.",
296
+ retryable: false,
297
+ });
298
+ }
299
+ const pathname = PathSyntax.decodeParens(statement.target.kind === "url" ? statement.target.pathname : statement.target.raw); // {§path-parentheses}
217
300
  const target = await this.#resolveWriteTarget(pathname, core);
218
301
  if (!target.ok)
219
- return { status: target.status, error: target.error };
302
+ return failure(target.code, target.status, target.detail, target.extensions);
220
303
  const { canonical, rel, fileExists, original, mimetype, baseSig, admittedBy } = target;
221
304
  for (const candidate of statements.slice(1)) {
222
- if (candidate.target === null)
223
- return { status: 400, error: "EDIT batch spans multiple resources" };
224
- const candidatePathname = candidate.target.kind === "regex" ? candidate.target.raw
225
- : decodePathParens(candidate.target.kind === "url" ? candidate.target.pathname : candidate.target.raw);
305
+ if (candidate.target === null) {
306
+ return failure("edit-batch-mismatch", 400, "The EDIT batch spans multiple resources.", {
307
+ recovery: "Submit a separate EDIT batch for each resource.",
308
+ retryable: false,
309
+ });
310
+ }
311
+ const candidatePathname = PathSyntax.decodeParens(candidate.target.kind === "url" ? candidate.target.pathname : candidate.target.raw);
226
312
  const candidateTarget = await this.#resolveWriteTarget(candidatePathname, core);
227
- if (!candidateTarget.ok || candidateTarget.rel !== rel)
228
- return { status: 400, error: "EDIT batch spans multiple resources" };
229
- }
230
- // `<L>` line marker dispatches on file mimetype: JSON →
231
- // LineMarkerOps.applyJsonItemEdit (structural item edit); otherwise →
232
- // LineMarkerOps.applyLineMarkerEdit (line edit). A CREATE (no existing file) has
233
- // nothing to scope into, so a markerless body becomes the new file's content.
234
- // {§edit-marker-required-on-existing} (#571) — an EXISTING file has no easy-clobber
235
- // path: a marker is REQUIRED, even for a deliberate full rewrite (`<1,-1>` states
236
- // that intent explicitly). run126: an omitted marker (a misplaced `<356>` landed
237
- // in the body, not the marker slot) silently replaced a 1,693-line file with 2 —
238
- // the model's own subsequent reads told it so, repeatedly, and it never noticed.
239
- // Refusing the omission converts a silent accident into a loud, immediate one.
313
+ if (!candidateTarget.ok || candidateTarget.rel !== rel) {
314
+ return failure("edit-batch-mismatch", 400, "The EDIT batch spans multiple resources.", {
315
+ recovery: "Submit a separate EDIT batch for each resource.",
316
+ retryable: false,
317
+ });
318
+ }
319
+ }
320
+ // {§edit-marker-required-on-existing} — markerless content creates a new
321
+ // file; every existing-file rewrite states its range explicitly.
240
322
  let patched;
323
+ let scopeNormalizations;
241
324
  if (fileExists) {
242
- if (statements.some(({ lineMarker }) => lineMarker === null))
243
- return { status: 400, error: "EDIT of an existing file requires a line marker — use <1,-1> to replace the whole file deliberately" };
325
+ if (statements.some(({ lineMarker }) => lineMarker === null)) {
326
+ return failure("line-marker-required", 400, "EDIT of an existing file requires a line marker.", {
327
+ recovery: "Use <1,-1> to replace the whole file or select a narrower range.",
328
+ retryable: false,
329
+ });
330
+ }
244
331
  const edits = statements.map((candidate) => ({ marker: candidate.lineMarker, body: candidate.body ?? "" }));
245
- const result = MimetypeBinary.isJsonMimetype(mimetype)
246
- ? LineMarkerOps.applyJsonItemEditBatch(original, edits)
247
- : LineMarkerOps.applyLineMarkerEditBatch(original, edits);
332
+ const result = LineMarkerOps.applyLineMarkerEditBatch(original, edits);
248
333
  if (result.status !== 200)
249
- return { status: result.status, error: result.error };
334
+ return Results.assert(result);
250
335
  patched = result.result ?? "";
336
+ scopeNormalizations = result.scopeNormalizations;
251
337
  }
252
338
  else {
253
- if (statements.length !== 1)
254
- return { status: 409, error: "creation cannot coexist with another EDIT" };
339
+ if (statements.length !== 1) {
340
+ return failure("creation-batch-conflict", 409, "Multiple EDIT operations attempted to create the same file.", {
341
+ recovery: "Create the file with one EDIT before applying additional edits.",
342
+ retryable: false,
343
+ });
344
+ }
255
345
  patched = statement.body ?? "";
256
346
  }
257
347
  if (fileExists && patched === original)
258
- return { status: 304 }; // §edit-noop-304
348
+ return {
349
+ status: 304,
350
+ ...(scopeNormalizations === undefined ? {} : { scopeNormalizations }),
351
+ }; // {§edit-noop-304}
259
352
  const patch = createPatch(rel, original, patched, "current", "proposed");
260
353
  const receiptEdits = fileExists
261
354
  ? statements.map((candidate) => ({ marker: candidate.lineMarker, body: candidate.body ?? "" }))
262
355
  : [{ marker: { marks: [1, -1] }, body: patched }];
263
- const batchReceipt = editReceipt(original, patched, receiptEdits, {
264
- unit: editReceiptUnit(MimetypeBinary.isJsonMimetype(mimetype), original, patched),
265
- });
356
+ const batchReceipt = editReceipt(original, patched, receiptEdits);
266
357
  return {
267
358
  status: 202,
268
359
  body: patch,
269
360
  editReceipt: batchReceipt,
361
+ ...(scopeNormalizations === undefined ? {} : { scopeNormalizations }),
270
362
  attrs: { path: rel, canonical, patch, patched, editReceipt: batchReceipt, baseSig, existed: fileExists, ...(admittedBy !== undefined ? { admittedBy } : {}) },
271
363
  };
272
364
  }
273
365
  async edit(statement, ctx) {
274
366
  return this.editBatch([statement], ctx);
275
367
  }
276
- // COPY/MOVE INTO file:/// — the dest write. Same §membership gate as edit, same 202
368
+ // COPY/MOVE INTO file:/// — the dest write. Same {§membership} gate as edit, same 202
277
369
  // proposal + applyResolution path: a copy onto disk is a disk write and earns
278
370
  // the identical human review. Dispatcher.#copyOrchestration propagates this 202;
279
371
  // ProposalLifecycle.workerApply routes the accept back here via the dest scheme;
@@ -282,24 +374,28 @@ export default class File extends CoreSchemeAdapterBase {
282
374
  async writeEntry(pathname, entry, ctx) {
283
375
  const core = this.coreContext(ctx);
284
376
  const bodyChannel = entry.channels.body;
285
- if (bodyChannel === undefined)
286
- return { status: 400, created: false, entryId: null };
377
+ if (bodyChannel === undefined) {
378
+ return Results.failure("scheme:file", "body-channel-required", 400, "A file write requires a body channel.", { created: false, entryId: null }, {
379
+ recovery: "Provide the file content in the body channel.",
380
+ retryable: false,
381
+ });
382
+ }
287
383
  const target = await this.#resolveWriteTarget(pathname, core);
288
- if (!target.ok)
289
- return { status: target.status, created: false, entryId: null };
384
+ if (!target.ok) {
385
+ return Results.failure("scheme:file", target.code, target.status, target.detail, { created: false, entryId: null }, target.extensions);
386
+ }
290
387
  const { canonical, rel, fileExists, original, baseSig, admittedBy } = target;
291
388
  const patched = bodyChannel.content;
292
389
  const patch = createPatch(rel, original, patched, "current", "proposed");
293
- return { status: 202, created: !fileExists, entryId: null, body: patch, attrs: { path: rel, canonical, patch, patched, span: editedSpan(original, patched), baseSig, existed: fileExists, ...(admittedBy !== undefined ? { admittedBy } : {}) } };
390
+ return { status: 202, created: !fileExists, entryId: null, body: patch, attrs: { path: rel, canonical, patch, patched, baseSig, existed: fileExists, ...(admittedBy !== undefined ? { admittedBy } : {}) } };
294
391
  }
295
392
  // applyResolution — called by Engine.dispatch after a proposed log
296
393
  // entry resolves with decision=accept. Two responsibilities:
297
394
  // 1. Write the patched content to disk.
298
395
  // 2. Register the file as an entry so it appears in the manifest and the
299
396
  // model can READ its full landed work.
300
- // The accepted result returns the editedSpan diff as its body, so the EDIT row
301
- // itself carries the line-numbered confirmation of what changed — parity with the
302
- // entry-scheme EDIT's span; default-folding reclaims it at the next turn boundary.
397
+ // {§edit-result-receipt-truth} — accepted EDITs return the receipt for what
398
+ // landed. Dispatcher composes COPY/MOVE effects after this hook returns.
303
399
  async applyResolution(args, ctx) {
304
400
  const core = this.coreContext(ctx);
305
401
  const { attrs, body } = args;
@@ -308,14 +404,22 @@ export default class File extends CoreSchemeAdapterBase {
308
404
  // failure surfaces as 500, never a silent noop; ENOENT ⇒ file already gone, still deregister.
309
405
  if (typeof attrs.deletePath === "string") {
310
406
  const root = await loadWorkspaceRoot(core.db, core.workspaceId);
311
- if (root === null)
312
- return { status: 500, outcome: "no project_root" };
407
+ if (root === null) {
408
+ throw new InvalidOperationResultError("An accepted file deletion has no workspace project root.");
409
+ }
313
410
  try {
314
411
  await rm(join(root, attrs.deletePath));
315
412
  }
316
413
  catch (err) {
317
- if (err.code !== "ENOENT")
318
- return { status: 500, outcome: "delete_failed", body: err instanceof Error ? err.message : String(err) };
414
+ if (err.code !== "ENOENT") {
415
+ console.error(`File deletion failed for '${attrs.deletePath}':`, err);
416
+ return Results.failure("scheme:file", "delete-failed", 500, `The file could not be deleted: ${ErrorDetail.preview(err)}`, {
417
+ outcome: "delete_failed",
418
+ }, {
419
+ path: attrs.deletePath,
420
+ stage: "filesystem-delete",
421
+ });
422
+ }
319
423
  }
320
424
  await EntryCrud.deleteEntry(attrs.deletePath, core, "file");
321
425
  return { status: 200 };
@@ -324,19 +428,19 @@ export default class File extends CoreSchemeAdapterBase {
324
428
  const relPath = attrs.path;
325
429
  const patched = body ?? attrs.patched;
326
430
  if (typeof canonical !== "string" || canonical.length === 0) {
327
- return { status: 500, outcome: "applyResolution: missing attrs.canonical" };
431
+ throw new InvalidOperationResultError("The accepted file proposal is missing attrs.canonical.");
328
432
  }
329
433
  if (typeof relPath !== "string" || relPath.length === 0) {
330
- return { status: 500, outcome: "applyResolution: missing attrs.path" };
434
+ throw new InvalidOperationResultError("The accepted file proposal is missing attrs.path.");
331
435
  }
332
436
  if (typeof patched !== "string") {
333
- return { status: 500, outcome: "applyResolution: missing patched content" };
437
+ throw new InvalidOperationResultError("The accepted file proposal is missing patched content.");
334
438
  }
335
439
  // CAS — the write-side twin of #materializeMember's read-gate (synced_sig === sig). The
336
440
  // proposal was computed against the snapshot (body + baseSig); if disk drifted out-of-band
337
441
  // since propose, the full-blob write would clobber it. Refuse and surface a write_conflict —
338
442
  // the next reconcile narrates disk truth via FsDivergence; the model re-reads + re-proposes.
339
- // No clever re-diff, no clobber. §membership-edit-write-cas
443
+ // No clever re-diff, no clobber. {§membership-edit-write-cas}
340
444
  const baseSig = (args.attrs.baseSig ?? null);
341
445
  const existed = args.attrs.existed === true; // proposal targeted an existing member (edit) vs a fresh create
342
446
  let currentSig = null;
@@ -353,18 +457,28 @@ export default class File extends CoreSchemeAdapterBase {
353
457
  // assumed an absent path, so any file present now is the conflict.
354
458
  const conflict = existed ? (baseSig !== null && currentSig !== baseSig) : (currentSig !== null);
355
459
  if (conflict) {
356
- return { status: 409, outcome: `write_conflict: ${relPath} changed on disk since the proposal (expected ${existed ? baseSig : "absent"}, found ${currentSig ?? "absent"}) — re-read and re-propose` };
460
+ const expected = existed ? baseSig : null;
461
+ const detail = `${relPath} changed on disk since the proposal; expected ${expected ?? "absence"} but found ${currentSig ?? "absence"}.`;
462
+ return Results.failure("scheme:file", "write-conflict", 409, detail, {
463
+ outcome: "write_conflict",
464
+ }, {
465
+ path: relPath,
466
+ expectedSignature: expected,
467
+ currentSignature: currentSig,
468
+ recovery: "READ the current file before proposing a new EDIT.",
469
+ retryable: false,
470
+ });
357
471
  }
358
472
  let receipt = attrs.editReceipt;
359
473
  if (body !== undefined && body !== attrs.patched) {
360
474
  const original = existed ? await readFile(canonical, "utf8") : "";
361
- const mimetype = await detectFileMimetype(canonical, core);
362
- const reviewed = editReceipt(original, patched, [{ marker: { marks: [1, -1] }, body: patched }], { unit: editReceiptUnit(MimetypeBinary.isJsonMimetype(mimetype), original, patched) });
363
- const statementCount = attrs.editReceipt?.effects.length ?? 1;
364
- receipt = {
365
- ...reviewed,
366
- effects: Array.from({ length: statementCount }, () => reviewed.effects[0]),
367
- };
475
+ if (receipt === undefined) {
476
+ if (typeof attrs.patched !== "string") {
477
+ throw new InvalidOperationResultError("The reviewer-modified file proposal is missing its proposed content.");
478
+ }
479
+ receipt = editReceipt(original, attrs.patched, [{ marker: { marks: [1, -1] }, body: attrs.patched }]);
480
+ }
481
+ receipt = reviewerReplacementReceipt(original, patched, receipt);
368
482
  }
369
483
  try {
370
484
  // A write into a not-yet-existing subtree creates it — an accepted proposal must not
@@ -373,20 +487,19 @@ export default class File extends CoreSchemeAdapterBase {
373
487
  await writeFile(canonical, patched, "utf8");
374
488
  }
375
489
  catch (err) {
376
- return {
377
- status: 500,
378
- outcome: "write_failed",
379
- body: err instanceof Error ? err.message : String(err),
380
- };
490
+ console.error(`File write failed for '${relPath}':`, err);
491
+ return Results.failure("scheme:file", "write-failed", 500, `The file could not be written: ${ErrorDetail.preview(err)}`, { outcome: "write_failed" }, {
492
+ path: relPath,
493
+ stage: "filesystem-write",
494
+ });
381
495
  }
382
496
  // Register the file as an entry so it appears in the manifest
383
497
  // under file:///<relPath> and is READ-able. mimetype is best-effort
384
498
  // by file extension; .md → text/markdown, anything else → text/plain.
385
499
  const mimetype = relPath.endsWith(".md") ? "text/markdown" : "text/plain";
386
500
  try {
387
- // scheme=null: the "file" scheme is a routing internal only;
388
- // never stored. Entries.scheme stays NULL for filesystem rows
389
- // so render-time bare-path output requires no special case.
501
+ // {§entry-identity-no-null} — file members persist under the reserved
502
+ // `file` identity; bare-path rendering is a projection of that row.
390
503
  const { entryId } = await EntryCrud.writeEntry(relPath, {
391
504
  channels: { body: { content: patched, mimetype } },
392
505
  tags: [],
@@ -396,6 +509,10 @@ export default class File extends CoreSchemeAdapterBase {
396
509
  const admitted = args.attrs.admittedBy;
397
510
  if (entryId !== null && (admitted === "client" || admitted === "git")) {
398
511
  await core.db.crud_stamp_origin.run({ entry_id: entryId, membership_origin: admitted });
512
+ const root = await loadWorkspaceRoot(core.db, core.workspaceId);
513
+ if (root !== null) {
514
+ await GitMembership.stageFile(root, relPath, ctx.signal);
515
+ }
399
516
  }
400
517
  // Restamp synced_sig to the landed write so the next reconcile recognizes our own
401
518
  // write as the synced state — not an FsDivergence narrated back at the model.
@@ -405,37 +522,49 @@ export default class File extends CoreSchemeAdapterBase {
405
522
  }
406
523
  }
407
524
  catch (err) {
408
- // Disk write succeeded; entry registration failed. Surface
409
- // the write as 200 (file is on disk) but log the failure —
410
- // the manifest just won't reflect it until next time.
411
- // (Could harden to roll back the file write; for v0,
412
- // disk-truth-of-record wins.)
413
- return {
414
- status: 200,
415
- outcome: "materialize_failed",
416
- body: err instanceof Error ? err.message : String(err),
417
- };
525
+ // Disk truth changed but the addressable entry did not. This is a
526
+ // partial failure, never a successful operation result.
527
+ console.error(`File registration failed for '${relPath}':`, err);
528
+ return Results.failure("scheme:file", "materialization-failed", 500, `The file was written to disk but could not be registered: ${ErrorDetail.preview(err)}`, { outcome: "materialize_failed" }, {
529
+ path: relPath,
530
+ stage: "entry-registration",
531
+ retryable: false,
532
+ });
418
533
  }
419
534
  if (receipt === undefined)
420
- return { status: 200, body: attrs.span };
421
- return { status: 200, result: { receipt: projectEditReceipt(receipt, 0), editReceipt: receipt } };
535
+ return { status: 200 };
536
+ return {
537
+ status: 200,
538
+ editReceipt: receipt,
539
+ result: { receipt: projectEditReceipt(receipt, 0) },
540
+ };
422
541
  }
423
542
  // deleteEntry — the KILL / MOVE-source counterpart of writeEntry. Deleting a host file is
424
543
  // DESTRUCTIVE, so it PROPOSES for review (202), exactly as edit() does — never an ungated unlink.
425
- // §membership — only a MEMBER reaches the proposal; a non-member is invisible (404), so untracked
544
+ // {§membership} — only a MEMBER reaches the proposal; a non-member is invisible (404), so untracked
426
545
  // disk is never probed or touched. applyResolution unlinks + deregisters on accept.
427
546
  async deleteEntry(pathname, ctx) {
428
547
  const core = this.coreContext(ctx);
429
548
  const root = await loadWorkspaceRoot(core.db, core.workspaceId);
430
- if (root === null)
431
- return { status: 400 };
549
+ if (root === null) {
550
+ return Results.failure("scheme:file", "project-root-required", 400, "File deletion requires a workspace project root.", {}, { retryable: false });
551
+ }
432
552
  const rel = Namespace.canonicalize(pathname, root);
433
553
  if (rel === null)
434
- return { status: 404 };
554
+ return Results.failure("scheme:file", "entry-not-found", 404, `No file entry exists at ${pathname}.`, {}, { target: pathname });
435
555
  const member = await core.db.crud_find_workspace_entry.get({ workspace_id: core.workspaceId, owner_id: await Owner.commonsId(core.db, core.workspaceId), scheme: "file", pathname: rel });
436
556
  if (member === undefined)
437
- return { status: 404 };
557
+ return Results.failure("scheme:file", "entry-not-found", 404, `No file entry exists at ${rel}.`, {}, { target: rel });
438
558
  return { status: 202, attrs: { deletePath: rel } };
439
559
  }
560
+ async deleteChannel(pathname, channel, ctx) {
561
+ if (channel !== File.manifest.defaultChannel) {
562
+ return Results.failure("scheme:file", "channel-not-found", 404, `No channel named #${channel} exists at ${pathname}.`, {}, {
563
+ target: pathname,
564
+ channel,
565
+ });
566
+ }
567
+ return this.deleteEntry(pathname, ctx);
568
+ }
440
569
  }
441
570
  //# sourceMappingURL=File.js.map