@plurnk/plurnk-service 4.1.0 → 4.3.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 (452) hide show
  1. package/.env.defaults +3 -0
  2. package/INSTALL.md +7 -2
  3. package/README.md +3 -1
  4. package/SPEC.md +1996 -1370
  5. package/dist/build-info.d.ts.map +1 -1
  6. package/dist/build-info.js +25 -3
  7. package/dist/build-info.js.map +1 -1
  8. package/dist/build-info.json +1 -1
  9. package/dist/completions/_plurnk-service +2 -2
  10. package/dist/completions/plurnk-service.bash +2 -2
  11. package/dist/completions/plurnk-service.fish +2 -0
  12. package/dist/content/body-preview.js.map +1 -1
  13. package/dist/content/byte-view.d.ts.map +1 -1
  14. package/dist/content/byte-view.js +3 -2
  15. package/dist/content/byte-view.js.map +1 -1
  16. package/dist/content/edit-collision.d.ts +2 -1
  17. package/dist/content/edit-collision.d.ts.map +1 -1
  18. package/dist/content/edit-collision.js.map +1 -1
  19. package/dist/content/edit-receipt.d.ts.map +1 -1
  20. package/dist/content/edit-receipt.js +28 -23
  21. package/dist/content/edit-receipt.js.map +1 -1
  22. package/dist/content/edited-span.js +1 -1
  23. package/dist/content/edited-span.js.map +1 -1
  24. package/dist/content/line-anchors.d.ts +3 -2
  25. package/dist/content/line-anchors.d.ts.map +1 -1
  26. package/dist/content/line-anchors.js +33 -19
  27. package/dist/content/line-anchors.js.map +1 -1
  28. package/dist/content/line-selection.js.map +1 -1
  29. package/dist/content/pattern-edits.js +1 -1
  30. package/dist/content/pattern-edits.js.map +1 -1
  31. package/dist/content/read-projector.d.ts +1 -1
  32. package/dist/content/read-projector.d.ts.map +1 -1
  33. package/dist/content/read-projector.js +10 -8
  34. package/dist/content/read-projector.js.map +1 -1
  35. package/dist/content/read-resolve.d.ts.map +1 -1
  36. package/dist/content/read-resolve.js +6 -5
  37. package/dist/content/read-resolve.js.map +1 -1
  38. package/dist/core/AdmittedTurnExecutor.d.ts +4 -4
  39. package/dist/core/AdmittedTurnExecutor.d.ts.map +1 -1
  40. package/dist/core/AdmittedTurnExecutor.js +20 -18
  41. package/dist/core/AdmittedTurnExecutor.js.map +1 -1
  42. package/dist/core/AmbientMembers.d.ts +18 -0
  43. package/dist/core/AmbientMembers.d.ts.map +1 -0
  44. package/dist/core/AmbientMembers.js +84 -0
  45. package/dist/core/AmbientMembers.js.map +1 -0
  46. package/dist/core/BareBatchRunner.d.ts +1 -1
  47. package/dist/core/BareBatchRunner.d.ts.map +1 -1
  48. package/dist/core/BareBatchRunner.js +2 -2
  49. package/dist/core/BareBatchRunner.js.map +1 -1
  50. package/dist/core/CapabilityPolicies.js.map +1 -1
  51. package/dist/core/CapabilityResolver.d.ts +1 -2
  52. package/dist/core/CapabilityResolver.d.ts.map +1 -1
  53. package/dist/core/CapabilityResolver.js +11 -7
  54. package/dist/core/CapabilityResolver.js.map +1 -1
  55. package/dist/core/ChannelWrite.d.ts +2 -2
  56. package/dist/core/ChannelWrite.d.ts.map +1 -1
  57. package/dist/core/ChannelWrite.js.map +1 -1
  58. package/dist/core/ChannelWrite.sql +27 -0
  59. package/dist/core/ClientInteractions.js.map +1 -1
  60. package/dist/core/ContextFit.js +1 -1
  61. package/dist/core/ContextFit.js.map +1 -1
  62. package/dist/core/CoreSchemeServices.d.ts.map +1 -1
  63. package/dist/core/CoreSchemeServices.js +6 -4
  64. package/dist/core/CoreSchemeServices.js.map +1 -1
  65. package/dist/core/DataStatementRunner.d.ts.map +1 -1
  66. package/dist/core/DataStatementRunner.js +24 -15
  67. package/dist/core/DataStatementRunner.js.map +1 -1
  68. package/dist/core/Dispatcher.d.ts +29 -5
  69. package/dist/core/Dispatcher.d.ts.map +1 -1
  70. package/dist/core/Dispatcher.js +242 -132
  71. package/dist/core/Dispatcher.js.map +1 -1
  72. package/dist/core/EditMutations.d.ts.map +1 -1
  73. package/dist/core/EditMutations.js +12 -6
  74. package/dist/core/EditMutations.js.map +1 -1
  75. package/dist/core/EditSequence.js.map +1 -1
  76. package/dist/core/Engine.d.ts +12 -6
  77. package/dist/core/Engine.d.ts.map +1 -1
  78. package/dist/core/Engine.js +29 -7
  79. package/dist/core/Engine.js.map +1 -1
  80. package/dist/core/ExecutionOutputs.js.map +1 -1
  81. package/dist/core/ExecutorRegistry.d.ts +1 -2
  82. package/dist/core/ExecutorRegistry.d.ts.map +1 -1
  83. package/dist/core/ExecutorRegistry.js +2 -2
  84. package/dist/core/ExecutorRegistry.js.map +1 -1
  85. package/dist/core/FileAddress.d.ts +1 -0
  86. package/dist/core/FileAddress.d.ts.map +1 -1
  87. package/dist/core/FileAddress.js +8 -1
  88. package/dist/core/FileAddress.js.map +1 -1
  89. package/dist/core/FilePublication.d.ts.map +1 -1
  90. package/dist/core/FilePublication.js +6 -3
  91. package/dist/core/FilePublication.js.map +1 -1
  92. package/dist/core/FileSnapshot.d.ts.map +1 -1
  93. package/dist/core/FileSnapshot.js +8 -5
  94. package/dist/core/FileSnapshot.js.map +1 -1
  95. package/dist/core/KillHandler.d.ts.map +1 -1
  96. package/dist/core/KillHandler.js +7 -0
  97. package/dist/core/KillHandler.js.map +1 -1
  98. package/dist/core/LiveSubscription.d.ts +1 -0
  99. package/dist/core/LiveSubscription.d.ts.map +1 -1
  100. package/dist/core/LiveSubscription.js +3 -2
  101. package/dist/core/LiveSubscription.js.map +1 -1
  102. package/dist/core/LiveSubscriptions.d.ts +4 -1
  103. package/dist/core/LiveSubscriptions.d.ts.map +1 -1
  104. package/dist/core/LiveSubscriptions.js +42 -1
  105. package/dist/core/LiveSubscriptions.js.map +1 -1
  106. package/dist/core/LogBody.d.ts.map +1 -1
  107. package/dist/core/LogBody.js +22 -19
  108. package/dist/core/LogBody.js.map +1 -1
  109. package/dist/core/LogVisibility.d.ts +1 -1
  110. package/dist/core/LogVisibility.d.ts.map +1 -1
  111. package/dist/core/LogVisibility.js +4 -6
  112. package/dist/core/LogVisibility.js.map +1 -1
  113. package/dist/core/LogWriter.d.ts.map +1 -1
  114. package/dist/core/LogWriter.js +6 -9
  115. package/dist/core/LogWriter.js.map +1 -1
  116. package/dist/core/LoopDriver.d.ts +4 -4
  117. package/dist/core/LoopDriver.d.ts.map +1 -1
  118. package/dist/core/LoopDriver.js +4 -5
  119. package/dist/core/LoopDriver.js.map +1 -1
  120. package/dist/core/LoopLifecycle.d.ts +2 -0
  121. package/dist/core/LoopLifecycle.d.ts.map +1 -1
  122. package/dist/core/LoopLifecycle.js +13 -3
  123. package/dist/core/LoopLifecycle.js.map +1 -1
  124. package/dist/core/LoopLifecycle.sql +4 -4
  125. package/dist/core/LoopOutcome.d.ts.map +1 -1
  126. package/dist/core/LoopOutcome.js +2 -2
  127. package/dist/core/LoopOutcome.js.map +1 -1
  128. package/dist/core/MembershipMaterialization.d.ts.map +1 -1
  129. package/dist/core/MembershipMaterialization.js +29 -29
  130. package/dist/core/MembershipMaterialization.js.map +1 -1
  131. package/dist/core/MessageResources.d.ts +5 -1
  132. package/dist/core/MessageResources.d.ts.map +1 -1
  133. package/dist/core/MessageResources.js +12 -0
  134. package/dist/core/MessageResources.js.map +1 -1
  135. package/dist/core/MessageResources.sql +8 -0
  136. package/dist/core/MutationEffects.d.ts +1 -0
  137. package/dist/core/MutationEffects.d.ts.map +1 -1
  138. package/dist/core/MutationEffects.js +14 -10
  139. package/dist/core/MutationEffects.js.map +1 -1
  140. package/dist/core/OperationHistory.d.ts.map +1 -1
  141. package/dist/core/OperationHistory.js +4 -3
  142. package/dist/core/OperationHistory.js.map +1 -1
  143. package/dist/core/OperatorConfig.d.ts.map +1 -1
  144. package/dist/core/OperatorConfig.js +3 -2
  145. package/dist/core/OperatorConfig.js.map +1 -1
  146. package/dist/core/PacketBuilder.d.ts +1 -1
  147. package/dist/core/PacketBuilder.d.ts.map +1 -1
  148. package/dist/core/PacketBuilder.js +7 -5
  149. package/dist/core/PacketBuilder.js.map +1 -1
  150. package/dist/core/ProblemLog.d.ts +2 -5
  151. package/dist/core/ProblemLog.d.ts.map +1 -1
  152. package/dist/core/ProblemLog.js +2 -3
  153. package/dist/core/ProblemLog.js.map +1 -1
  154. package/dist/core/ProposalLifecycle.d.ts +12 -11
  155. package/dist/core/ProposalLifecycle.d.ts.map +1 -1
  156. package/dist/core/ProposalLifecycle.js +92 -84
  157. package/dist/core/ProposalLifecycle.js.map +1 -1
  158. package/dist/core/ReasoningEvent.d.ts +2 -0
  159. package/dist/core/ReasoningEvent.d.ts.map +1 -1
  160. package/dist/core/ReplyMetadata.d.ts.map +1 -1
  161. package/dist/core/ReplyMetadata.js +4 -3
  162. package/dist/core/ReplyMetadata.js.map +1 -1
  163. package/dist/core/ResourceBindings.d.ts +2 -2
  164. package/dist/core/ResourceBindings.d.ts.map +1 -1
  165. package/dist/core/ResourceBindings.js.map +1 -1
  166. package/dist/core/ResourceMutations.d.ts +1 -1
  167. package/dist/core/ResourceMutations.d.ts.map +1 -1
  168. package/dist/core/ResourceMutations.js +1 -2
  169. package/dist/core/ResourceMutations.js.map +1 -1
  170. package/dist/core/ResourceSelector.js +2 -2
  171. package/dist/core/ResourceSelector.js.map +1 -1
  172. package/dist/core/ResourceTransfers.d.ts.map +1 -1
  173. package/dist/core/ResourceTransfers.js +162 -120
  174. package/dist/core/ResourceTransfers.js.map +1 -1
  175. package/dist/core/SchemeRegistry.d.ts +6 -5
  176. package/dist/core/SchemeRegistry.d.ts.map +1 -1
  177. package/dist/core/SchemeRegistry.js +32 -26
  178. package/dist/core/SchemeRegistry.js.map +1 -1
  179. package/dist/core/ServiceHelp.d.ts.map +1 -1
  180. package/dist/core/ServiceHelp.js +2 -1
  181. package/dist/core/ServiceHelp.js.map +1 -1
  182. package/dist/core/StoredPacket.d.ts.map +1 -1
  183. package/dist/core/StoredPacket.js +26 -19
  184. package/dist/core/StoredPacket.js.map +1 -1
  185. package/dist/core/StrikeRail.d.ts +1 -2
  186. package/dist/core/StrikeRail.d.ts.map +1 -1
  187. package/dist/core/StrikeRail.js +4 -4
  188. package/dist/core/StrikeRail.js.map +1 -1
  189. package/dist/core/TerminalResult.d.ts +0 -2
  190. package/dist/core/TerminalResult.d.ts.map +1 -1
  191. package/dist/core/TerminalResult.js +0 -18
  192. package/dist/core/TerminalResult.js.map +1 -1
  193. package/dist/core/ToolInputSchema.d.ts.map +1 -1
  194. package/dist/core/ToolInputSchema.js +2 -2
  195. package/dist/core/ToolInputSchema.js.map +1 -1
  196. package/dist/core/ToolResources.d.ts +1 -0
  197. package/dist/core/ToolResources.d.ts.map +1 -1
  198. package/dist/core/ToolResources.js +7 -6
  199. package/dist/core/ToolResources.js.map +1 -1
  200. package/dist/core/TurnDispositionHandler.d.ts +1 -1
  201. package/dist/core/TurnDispositionHandler.d.ts.map +1 -1
  202. package/dist/core/TurnDispositionHandler.js +0 -1
  203. package/dist/core/TurnDispositionHandler.js.map +1 -1
  204. package/dist/core/TurnMaterialization.d.ts.map +1 -1
  205. package/dist/core/TurnMaterialization.js +3 -2
  206. package/dist/core/TurnMaterialization.js.map +1 -1
  207. package/dist/core/TurnRunner.d.ts +13 -12
  208. package/dist/core/TurnRunner.d.ts.map +1 -1
  209. package/dist/core/TurnRunner.js +197 -173
  210. package/dist/core/TurnRunner.js.map +1 -1
  211. package/dist/core/TurnRunner.sql +3 -3
  212. package/dist/core/WorkerOwners.js.map +1 -1
  213. package/dist/core/caps/DbEntryCaps.js.map +1 -1
  214. package/dist/core/caps/DbMessageCaps.d.ts +3 -3
  215. package/dist/core/caps/DbMessageCaps.d.ts.map +1 -1
  216. package/dist/core/caps/DbProjectionCaps.js +1 -1
  217. package/dist/core/caps/DbProjectionCaps.js.map +1 -1
  218. package/dist/core/caps/DbSubscriptionCaps.d.ts.map +1 -1
  219. package/dist/core/caps/DbSubscriptionCaps.js +1 -0
  220. package/dist/core/caps/DbSubscriptionCaps.js.map +1 -1
  221. package/dist/core/caps/SchemeCtxImpl.d.ts +1 -0
  222. package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -1
  223. package/dist/core/caps/SchemeCtxImpl.js +10 -1
  224. package/dist/core/caps/SchemeCtxImpl.js.map +1 -1
  225. package/dist/core/env-catalog.js.map +1 -1
  226. package/dist/core/env-defaults.d.ts.map +1 -1
  227. package/dist/core/env-defaults.js +5 -3
  228. package/dist/core/env-defaults.js.map +1 -1
  229. package/dist/core/file-creation-policy.d.ts.map +1 -1
  230. package/dist/core/file-creation-policy.js +2 -1
  231. package/dist/core/file-creation-policy.js.map +1 -1
  232. package/dist/core/file-materialization.d.ts.map +1 -1
  233. package/dist/core/file-materialization.js +9 -11
  234. package/dist/core/file-materialization.js.map +1 -1
  235. package/dist/core/git-env.d.ts +1 -0
  236. package/dist/core/git-env.d.ts.map +1 -1
  237. package/dist/core/git-env.js +34 -3
  238. package/dist/core/git-env.js.map +1 -1
  239. package/dist/core/git-membership.d.ts +8 -0
  240. package/dist/core/git-membership.d.ts.map +1 -1
  241. package/dist/core/git-membership.js +107 -21
  242. package/dist/core/git-membership.js.map +1 -1
  243. package/dist/core/git-state.d.ts.map +1 -1
  244. package/dist/core/git-state.js +1 -0
  245. package/dist/core/git-state.js.map +1 -1
  246. package/dist/core/notifications.d.ts +5 -0
  247. package/dist/core/notifications.d.ts.map +1 -1
  248. package/dist/core/packet-wire.d.ts +26 -21
  249. package/dist/core/packet-wire.d.ts.map +1 -1
  250. package/dist/core/packet-wire.js +150 -112
  251. package/dist/core/packet-wire.js.map +1 -1
  252. package/dist/core/plurnk-uri.d.ts +1 -1
  253. package/dist/core/plurnk-uri.d.ts.map +1 -1
  254. package/dist/core/plurnk-uri.js +6 -5
  255. package/dist/core/plurnk-uri.js.map +1 -1
  256. package/dist/core/results.d.ts +9 -4
  257. package/dist/core/results.d.ts.map +1 -1
  258. package/dist/core/results.js +14 -1
  259. package/dist/core/results.js.map +1 -1
  260. package/dist/core/runtime-floor.d.ts +8 -0
  261. package/dist/core/runtime-floor.d.ts.map +1 -0
  262. package/dist/core/runtime-floor.js +40 -0
  263. package/dist/core/runtime-floor.js.map +1 -0
  264. package/dist/core/runtime-guard.d.ts +2 -0
  265. package/dist/core/runtime-guard.d.ts.map +1 -0
  266. package/dist/core/runtime-guard.js +5 -0
  267. package/dist/core/runtime-guard.js.map +1 -0
  268. package/dist/core/scheme-types.d.ts +20 -0
  269. package/dist/core/scheme-types.d.ts.map +1 -1
  270. package/dist/core/sqlite-synchronous.d.ts +1 -1
  271. package/dist/core/sqlite-synchronous.d.ts.map +1 -1
  272. package/dist/core/sqlite-synchronous.js.map +1 -1
  273. package/dist/core/statement-primary.d.ts +2 -2
  274. package/dist/core/statement-primary.d.ts.map +1 -1
  275. package/dist/core/statement-primary.js.map +1 -1
  276. package/dist/core/workspace-settings.js +1 -1
  277. package/dist/core/workspace-settings.js.map +1 -1
  278. package/dist/evidence/EvidenceReader.d.ts.map +1 -1
  279. package/dist/evidence/EvidenceReader.js +20 -6
  280. package/dist/evidence/EvidenceReader.js.map +1 -1
  281. package/dist/launch/Launch.d.ts +1 -0
  282. package/dist/launch/Launch.d.ts.map +1 -1
  283. package/dist/launch/Launch.js +28 -12
  284. package/dist/launch/Launch.js.map +1 -1
  285. package/dist/man/plurnk-service.1 +12 -2
  286. package/dist/schemes/EffectPolicy.js +1 -1
  287. package/dist/schemes/EffectPolicy.js.map +1 -1
  288. package/dist/schemes/Env.d.ts +1 -1
  289. package/dist/schemes/Env.d.ts.map +1 -1
  290. package/dist/schemes/Env.js +7 -1
  291. package/dist/schemes/Env.js.map +1 -1
  292. package/dist/schemes/Exec.d.ts +10 -12
  293. package/dist/schemes/Exec.d.ts.map +1 -1
  294. package/dist/schemes/Exec.js +337 -437
  295. package/dist/schemes/Exec.js.map +1 -1
  296. package/dist/schemes/ExecOutputScheme.d.ts +4 -6
  297. package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
  298. package/dist/schemes/ExecOutputScheme.js +17 -17
  299. package/dist/schemes/ExecOutputScheme.js.map +1 -1
  300. package/dist/schemes/ExecScheduler.d.ts.map +1 -1
  301. package/dist/schemes/ExecScheduler.js +1 -2
  302. package/dist/schemes/ExecScheduler.js.map +1 -1
  303. package/dist/schemes/ExecutionInput.js +3 -3
  304. package/dist/schemes/ExecutionInput.js.map +1 -1
  305. package/dist/schemes/File.d.ts +3 -18
  306. package/dist/schemes/File.d.ts.map +1 -1
  307. package/dist/schemes/File.js +148 -84
  308. package/dist/schemes/File.js.map +1 -1
  309. package/dist/schemes/Log.d.ts.map +1 -1
  310. package/dist/schemes/Log.js +193 -161
  311. package/dist/schemes/Log.js.map +1 -1
  312. package/dist/schemes/QuestionTool.d.ts.map +1 -1
  313. package/dist/schemes/QuestionTool.js +6 -8
  314. package/dist/schemes/QuestionTool.js.map +1 -1
  315. package/dist/schemes/ResourceTreeScheme.d.ts.map +1 -1
  316. package/dist/schemes/ResourceTreeScheme.js +2 -2
  317. package/dist/schemes/ResourceTreeScheme.js.map +1 -1
  318. package/dist/schemes/TurnSource.js +3 -3
  319. package/dist/schemes/TurnSource.js.map +1 -1
  320. package/dist/schemes/Worker.js.map +1 -1
  321. package/dist/schemes/_entry-crud.d.ts.map +1 -1
  322. package/dist/schemes/_entry-crud.js +4 -2
  323. package/dist/schemes/_entry-crud.js.map +1 -1
  324. package/dist/schemes/_entry-find.d.ts +2 -1
  325. package/dist/schemes/_entry-find.d.ts.map +1 -1
  326. package/dist/schemes/_entry-find.js +241 -130
  327. package/dist/schemes/_entry-find.js.map +1 -1
  328. package/dist/schemes/_entry-manifest.js +1 -1
  329. package/dist/schemes/_entry-manifest.js.map +1 -1
  330. package/dist/schemes/_entry-ops.js.map +1 -1
  331. package/dist/schemes/_search-index.js.map +1 -1
  332. package/dist/schemes/exec-entry-sink.d.ts +30 -0
  333. package/dist/schemes/exec-entry-sink.d.ts.map +1 -0
  334. package/dist/schemes/exec-entry-sink.js +238 -0
  335. package/dist/schemes/exec-entry-sink.js.map +1 -0
  336. package/dist/schemes/exec-lifetime.d.ts.map +1 -1
  337. package/dist/schemes/exec-lifetime.js +5 -2
  338. package/dist/schemes/exec-lifetime.js.map +1 -1
  339. package/dist/server/ClientOperations.d.ts +45 -0
  340. package/dist/server/ClientOperations.d.ts.map +1 -0
  341. package/dist/server/ClientOperations.js +192 -0
  342. package/dist/server/ClientOperations.js.map +1 -0
  343. package/dist/server/ClientReads.d.ts +13 -5
  344. package/dist/server/ClientReads.d.ts.map +1 -1
  345. package/dist/server/ClientReads.js +108 -21
  346. package/dist/server/ClientReads.js.map +1 -1
  347. package/dist/server/Credentials.js +2 -2
  348. package/dist/server/Credentials.js.map +1 -1
  349. package/dist/server/Daemon.d.ts +40 -28
  350. package/dist/server/Daemon.d.ts.map +1 -1
  351. package/dist/server/Daemon.js +263 -839
  352. package/dist/server/Daemon.js.map +1 -1
  353. package/dist/server/DaemonLock.d.ts +2 -0
  354. package/dist/server/DaemonLock.d.ts.map +1 -1
  355. package/dist/server/DaemonLock.js +10 -1
  356. package/dist/server/DaemonLock.js.map +1 -1
  357. package/dist/server/DaemonModules.d.ts +39 -0
  358. package/dist/server/DaemonModules.d.ts.map +1 -0
  359. package/dist/server/DaemonModules.js +219 -0
  360. package/dist/server/DaemonModules.js.map +1 -0
  361. package/dist/server/DrainSupervisor.d.ts +4 -2
  362. package/dist/server/DrainSupervisor.d.ts.map +1 -1
  363. package/dist/server/DrainSupervisor.js +318 -290
  364. package/dist/server/DrainSupervisor.js.map +1 -1
  365. package/dist/server/EnvFunctionality.d.ts +10 -7
  366. package/dist/server/EnvFunctionality.d.ts.map +1 -1
  367. package/dist/server/EnvFunctionality.js +7 -5
  368. package/dist/server/EnvFunctionality.js.map +1 -1
  369. package/dist/server/Functionality.d.ts +4 -5
  370. package/dist/server/Functionality.d.ts.map +1 -1
  371. package/dist/server/Functionality.js +24 -15
  372. package/dist/server/Functionality.js.map +1 -1
  373. package/dist/server/HttpListener.d.ts.map +1 -1
  374. package/dist/server/HttpListener.js +28 -8
  375. package/dist/server/HttpListener.js.map +1 -1
  376. package/dist/server/MembersFunctionality.d.ts +19 -7
  377. package/dist/server/MembersFunctionality.d.ts.map +1 -1
  378. package/dist/server/MembersFunctionality.js +37 -17
  379. package/dist/server/MembersFunctionality.js.map +1 -1
  380. package/dist/server/MessageDelivery.d.ts +43 -0
  381. package/dist/server/MessageDelivery.d.ts.map +1 -0
  382. package/dist/server/MessageDelivery.js +186 -0
  383. package/dist/server/MessageDelivery.js.map +1 -0
  384. package/dist/server/ModuleHost.d.ts +3 -3
  385. package/dist/server/ModuleHost.d.ts.map +1 -1
  386. package/dist/server/Places.d.ts +19 -0
  387. package/dist/server/Places.d.ts.map +1 -0
  388. package/dist/server/Places.js +76 -0
  389. package/dist/server/Places.js.map +1 -0
  390. package/dist/server/PluginSources.d.ts.map +1 -1
  391. package/dist/server/PluginSources.js +2 -1
  392. package/dist/server/PluginSources.js.map +1 -1
  393. package/dist/server/PlurnkSkill.d.ts.map +1 -1
  394. package/dist/server/PlurnkSkill.js +5 -4
  395. package/dist/server/PlurnkSkill.js.map +1 -1
  396. package/dist/server/Rollback.d.ts.map +1 -1
  397. package/dist/server/Rollback.js +2 -1
  398. package/dist/server/Rollback.js.map +1 -1
  399. package/dist/server/WorkerModels.d.ts +83 -0
  400. package/dist/server/WorkerModels.d.ts.map +1 -0
  401. package/dist/server/WorkerModels.js +500 -0
  402. package/dist/server/WorkerModels.js.map +1 -0
  403. package/dist/server/WorkerOverview.d.ts +22 -0
  404. package/dist/server/WorkerOverview.d.ts.map +1 -0
  405. package/dist/server/WorkerOverview.js +42 -0
  406. package/dist/server/WorkerOverview.js.map +1 -0
  407. package/dist/server/WorkspacePlugins.d.ts +1 -1
  408. package/dist/server/WorkspacePlugins.d.ts.map +1 -1
  409. package/dist/server/WorkspacePlugins.js +0 -1
  410. package/dist/server/WorkspacePlugins.js.map +1 -1
  411. package/dist/server/WorkspaceResidency.d.ts +3 -3
  412. package/dist/server/WorkspaceResidency.d.ts.map +1 -1
  413. package/dist/server/WorkspaceResidency.js.map +1 -1
  414. package/dist/server/client-input.d.ts +2 -2
  415. package/dist/server/client-input.d.ts.map +1 -1
  416. package/dist/server/client-input.js +19 -12
  417. package/dist/server/client-input.js.map +1 -1
  418. package/dist/server/envelope.d.ts +4 -1
  419. package/dist/server/envelope.d.ts.map +1 -1
  420. package/dist/server/envelope.js +7 -3
  421. package/dist/server/envelope.js.map +1 -1
  422. package/dist/server/envelope.sql +10 -6
  423. package/dist/server/logEntry.d.ts +38 -1
  424. package/dist/server/logEntry.d.ts.map +1 -1
  425. package/dist/server/logEntry.js +9 -9
  426. package/dist/server/logEntry.js.map +1 -1
  427. package/dist/server/logEntry.sql +4 -2
  428. package/dist/server/loopDocs.d.ts.map +1 -1
  429. package/dist/server/loopDocs.js +11 -2
  430. package/dist/server/loopDocs.js.map +1 -1
  431. package/dist/server/module-discovery.d.ts +2 -3
  432. package/dist/server/module-discovery.d.ts.map +1 -1
  433. package/dist/server/module-discovery.js +6 -6
  434. package/dist/server/module-discovery.js.map +1 -1
  435. package/dist/server/places.sql +83 -0
  436. package/dist/server/seam-loop.sql +8 -0
  437. package/dist/server/worker-overview.sql +50 -0
  438. package/dist/service.d.ts +1 -0
  439. package/dist/service.d.ts.map +1 -1
  440. package/dist/service.js +35 -9
  441. package/dist/service.js.map +1 -1
  442. package/docs/members.md +31 -33
  443. package/migrations/033_hidden_places.sql +10 -0
  444. package/package.json +48 -57
  445. package/dist/observe/init.d.ts +0 -8
  446. package/dist/observe/init.d.ts.map +0 -1
  447. package/dist/observe/init.js +0 -163
  448. package/dist/observe/init.js.map +0 -1
  449. package/dist/server/WorkerModelResolver.d.ts +0 -20
  450. package/dist/server/WorkerModelResolver.d.ts.map +0 -1
  451. package/dist/server/WorkerModelResolver.js +0 -200
  452. package/dist/server/WorkerModelResolver.js.map +0 -1
@@ -55,6 +55,7 @@ const uniqueMatchLocations = (locations) => {
55
55
  // label describes the same visible-body cost shown in the packet, a region reads in the one scope
56
56
  // notation ({§packet-extent-metadata}), and a location names its channel only off the default.
57
57
  const scoped = (key, value) => key === "region" || key === "enclosingRegion"
58
+ // oxlint-disable-next-line typescript/no-unsafe-type-assertion -- an item's region fields hold the TextRegions this module built; an entries walk does not carry which key holds which type
58
59
  ? ScopeFormat.region(value)
59
60
  : value;
60
61
  const renderFindContent = (items, defaultChannel) => renderJsonResult(items.map((item) => Array.isArray(item)
@@ -130,7 +131,7 @@ export const projectFindResult = (statement, scope, resources, scopes = [], defa
130
131
  if (page.status !== 200) {
131
132
  if (page.problem === undefined)
132
133
  throw new Error("FIND pagination failed without Problem Details");
133
- return Results.assert({ status: page.status, problem: page.problem, ...fields, range: page.range });
134
+ return Results.assert({ status: page.status, problem: page.problem, ...fields, ...(page.range === undefined ? {} : { range: page.range }) });
134
135
  }
135
136
  if (statement.matcher !== null && matchingPathCount === 0) {
136
137
  return {
@@ -142,7 +143,7 @@ export const projectFindResult = (statement, scope, resources, scopes = [], defa
142
143
  const results = page.items ?? [];
143
144
  const returnedItemsWeightTotal = locationMode
144
145
  ? itemsWeightTotal
145
- : results.reduce((sum, item) => sum + findItemWeight(item), 0);
146
+ : results.reduce((sum, item) => sum + (Array.isArray(item) ? findItemWeight(item) : 0), 0);
146
147
  return {
147
148
  status: 200,
148
149
  content: renderFindContent(results, defaultChannel), // {§find-result-projection} {§json-result-rendering}
@@ -155,6 +156,18 @@ export const projectFindResult = (statement, scope, resources, scopes = [], defa
155
156
  ...(page.range === undefined ? {} : { range: page.range }),
156
157
  };
157
158
  };
159
+ // {§relation-indexed-dialects} An indexed dialect over candidates the index does not yet cover.
160
+ const incompleteIndex = (search, what) => ({
161
+ status: 503,
162
+ matches: [],
163
+ error: `The persistent search index covers ${search.indexed} of ${search.total} ${what}.`,
164
+ extensions: {
165
+ search,
166
+ stage: "search-index",
167
+ recovery: "Wait for search indexing to complete before repeating the search.",
168
+ retryable: true,
169
+ },
170
+ });
158
171
  export default class EntryFind {
159
172
  static #targetPath(scheme, authority, pathname, fragment, projectRoot) {
160
173
  const path = EntryManifest.toPath(scheme, authority, pathname, projectRoot);
@@ -173,6 +186,10 @@ export default class EntryFind {
173
186
  // framework) and INCLUDES/EXCLUDES the entry - 200 keeps it, 204/203 drop it, and a
174
187
  // 4xx matcher failure ends the whole operation. Path-scoping stays in the (target). Match
175
188
  // locations remain grouped by resource internally until the target-shaped public projection.
189
+ //
190
+ // The steps run in the order their refusals are owed — the channel, the scope and its exact
191
+ // miss, the candidates, the universe beyond membership, the scope filter, the matcher — and each
192
+ // returns either the refusal or what the next step needs.
176
193
  static async #matchPathnames(statement, ctx, manifest, address) {
177
194
  if (statement.target === null) {
178
195
  return {
@@ -186,12 +203,57 @@ export default class EntryFind {
186
203
  };
187
204
  }
188
205
  const fragment = statement.target.fragment ?? null;
189
- const channel = fragment;
206
+ const unaddressed = EntryFind.#checkChannel(fragment, manifest);
207
+ if (unaddressed !== null)
208
+ return unaddressed;
209
+ const found = await EntryFind.#resolveScope(statement, ctx, manifest, address, fragment);
210
+ if ("status" in found)
211
+ return found;
212
+ const { scheme, authority, multipleAuthorities, scopePathname, scope } = found;
213
+ const superset = await EntryFind.#selectCandidates(statement, ctx, address, fragment, found);
214
+ if ("status" in superset)
215
+ return superset;
216
+ const coordinateByKey = new Map(superset.map((candidate) => [
217
+ multipleAuthorities ? EntryManifest.toPath(scheme, candidate.authority, candidate.pathname) : candidate.pathname,
218
+ { authority: candidate.authority, pathname: candidate.pathname },
219
+ ]));
220
+ const ambientKeys = await EntryFind.#ambientKeys(statement, address, found, superset);
221
+ const folders = EntryFind.#folderSummaries(statement, address, found, coordinateByKey, ambientKeys);
222
+ const inScope = EntryFind.#scopeCandidates(superset, found, address, fragment, ambientKeys);
223
+ if ("status" in inScope)
224
+ return inScope;
225
+ const candidates = multipleAuthorities
226
+ ? inScope.map((candidate) => ({ ...candidate, pathname: EntryManifest.toPath(scheme, candidate.authority, candidate.pathname) }))
227
+ : inScope;
228
+ const channels = new Map(candidates.map((candidate) => [candidate.pathname, candidate.channel]));
229
+ const channelOf = (key) => {
230
+ const selected = channels.get(key);
231
+ if (selected === undefined)
232
+ throw new Error(`FIND candidate lost its selected channel: ${key}`);
233
+ return selected;
234
+ };
235
+ const effectiveBytes = address.bytes === undefined ? undefined : (key) => {
236
+ const coordinate = coordinateByKey.get(key);
237
+ if (coordinate === undefined)
238
+ throw new Error(`FIND byte source lost coordinate ${key}`);
239
+ return address.bytes(coordinate.pathname, coordinate.authority);
240
+ };
241
+ const matches = await EntryFind.#selectMatches(statement, ctx, address, { candidates, ambientKeys, channelOf, effectiveBytes });
242
+ if ("status" in matches)
243
+ return matches;
244
+ const projectedScope = multipleAuthorities && scopePathname !== null
245
+ ? pathScope(EntryManifest.toPath(scheme, authority, scopePathname), manifest.folderScopes === true)
246
+ : scope;
247
+ return { status: 200, matches, channel: fragment ?? candidates[0]?.channel, ...(projectedScope === null ? {} : { scope: projectedScope }), folders,
248
+ ...(ambientKeys.length === 0 ? {} : { ambient: new Set(ambientKeys) }) };
249
+ }
250
+ // The channel the FIND addresses, refused when the scheme has no default or does not declare it.
251
+ static #checkChannel(fragment, manifest) {
190
252
  const availableChannels = [...new Set([
191
253
  manifest.defaultChannel,
192
254
  ...Object.keys(manifest.channels),
193
255
  ])].filter((candidate) => candidate.length > 0);
194
- if (manifest.defaultChannel.length === 0 && Object.keys(manifest.channels).length > 0 && channel === null) {
256
+ if (manifest.defaultChannel.length === 0 && Object.keys(manifest.channels).length > 0 && fragment === null) {
195
257
  return {
196
258
  status: 400,
197
259
  matches: [],
@@ -227,6 +289,11 @@ export default class EntryFind {
227
289
  },
228
290
  };
229
291
  }
292
+ return null;
293
+ }
294
+ // The scheme, authority and path scope the target names; an exact path that names nothing is the
295
+ // scheme's miss ({§fs-errno}) unless the universe beyond membership holds it ({§membership-auto-add}).
296
+ static async #resolveScope(statement, ctx, manifest, address, fragment) {
230
297
  // Scope by the manifest's persisted entries.scheme (storedScheme; absent →
231
298
  // name). File persists under the reserved 'file' scheme ({§entry-identity-no-null}).
232
299
  const scheme = EntryCrud.identityScheme(manifest);
@@ -248,7 +315,10 @@ export default class EntryFind {
248
315
  workspace_id: ctx.workspaceId,
249
316
  scheme, authority, pathname: scope.pathname,
250
317
  });
251
- if (exact === undefined) {
318
+ // {§membership-auto-add} — an exact miss on a candidate is a listing or a match, not a 404.
319
+ const ambientExact = exact === undefined && address.ambient !== undefined && scheme === "file"
320
+ && !scope.pathname.startsWith("../") && (await address.ambient.candidates(scope.pathname)).includes(scope.pathname);
321
+ if (exact === undefined && !ambientExact) {
252
322
  const target = EntryFind.#targetPath(scheme, authority, scope.pathname, fragment, projectRoot);
253
323
  return {
254
324
  status: 404,
@@ -259,6 +329,13 @@ export default class EntryFind {
259
329
  };
260
330
  }
261
331
  }
332
+ return { scheme, projectRoot, authority, multipleAuthorities, authorityScope, scopePathname, scope };
333
+ }
334
+ // {§find-scope-prefix-filter} {§find-scoped-isolation} The candidate rows: SQL's safe superset on the
335
+ // literal prefix, the authority glob applied, the asker's visibility applied, and derivation
336
+ // settled before an indexed dialect reads it.
337
+ static async #selectCandidates(statement, ctx, address, fragment, found) {
338
+ const { scheme, authority, multipleAuthorities, authorityScope, scope } = found;
262
339
  // SQL receives only the literal prefix and returns a safe superset. The
263
340
  // path matcher owns the shell-glob truth below: unlike SQLite GLOB, `*`
264
341
  // cannot cross `/`, while `**` can. A declared folder scope remains a
@@ -269,7 +346,7 @@ export default class EntryFind {
269
346
  workspace_id: workspaceId,
270
347
  scheme,
271
348
  authority: multipleAuthorities ? null : authority,
272
- channel,
349
+ channel: fragment,
273
350
  scope_prefix: address.pathBase !== undefined && scope?.candidatePrefix?.startsWith("../")
274
351
  ? null : scope?.candidatePrefix ?? null,
275
352
  });
@@ -283,21 +360,48 @@ export default class EntryFind {
283
360
  if (ctx.settleDerivations !== undefined && candidates.some((candidate) => candidate.deep_hash === null)) {
284
361
  return { status: 503, matches: [], error: "Resource metadata is still being derived.", extensions: { stage: "search-index" } };
285
362
  }
286
- const coordinateByKey = new Map(candidates.map((candidate) => [
287
- multipleAuthorities ? EntryManifest.toPath(scheme, candidate.authority, candidate.pathname) : candidate.pathname,
288
- { authority: candidate.authority, pathname: candidate.pathname },
289
- ]));
290
- const folders = statement.matcher === null && scope !== null
291
- ? [...Map.groupBy([...coordinateByKey.entries()], ([, coordinate]) => coordinate.authority)]
292
- .flatMap(([authority, entries]) => pathFolderSummaries(scope, entries.map(([, coordinate]) => coordinate.pathname), address.pathBase)
363
+ return candidates;
364
+ }
365
+ // {§membership-auto-add} The universe beyond membership that joins the listing and the text match.
366
+ static async #ambientKeys(statement, address, found, candidates) {
367
+ const { scheme, multipleAuthorities, scope } = found;
368
+ // {§membership-auto-add} — the universe beyond membership joins the listing and the text match;
369
+ // the indexed dialects (`~`, `&`) see members only, since nothing unadmitted is indexed.
370
+ let ambientKeys = [];
371
+ if (address.ambient !== undefined && scheme === "file" && !multipleAuthorities
372
+ && !(statement.matcher !== null && (statement.matcher.dialect === "fts" || statement.matcher.dialect === "graph"))
373
+ && !(scope?.candidatePrefix?.startsWith("../") ?? false)) {
374
+ const known = new Set(candidates.map((candidate) => candidate.pathname));
375
+ try {
376
+ ambientKeys = (await address.ambient.candidates(scope?.candidatePrefix ?? null))
377
+ .filter((key) => !known.has(key) && (scope === null || pathScopeMatches(scope, key, address.pathBase)));
378
+ }
379
+ catch {
380
+ ambientKeys = []; // a malformed glob is reported below, by the members' own filter
381
+ }
382
+ }
383
+ return ambientKeys;
384
+ }
385
+ // A listing's folder rows, grouped by authority when the target spans several.
386
+ static #folderSummaries(statement, address, found, coordinateByKey, ambientKeys) {
387
+ const { scheme, authority, multipleAuthorities, scope } = found;
388
+ return statement.matcher === null && scope !== null
389
+ ? [...Map.groupBy([...coordinateByKey.entries(), ...ambientKeys.map((key) => [key, { authority, pathname: key }])], ([, coordinate]) => coordinate.authority)]
390
+ .flatMap(([groupAuthority, entries]) => pathFolderSummaries(scope, entries.map(([, coordinate]) => coordinate.pathname), address.pathBase)
293
391
  .map((folder) => ({
294
- selector: multipleAuthorities ? EntryManifest.toPath(scheme, authority, folder.selector) : folder.selector,
295
- pathnames: folder.pathnames.map((pathname) => multipleAuthorities ? EntryManifest.toPath(scheme, authority, pathname) : pathname),
392
+ selector: multipleAuthorities ? EntryManifest.toPath(scheme, groupAuthority, folder.selector) : folder.selector,
393
+ pathnames: folder.pathnames.map((pathname) => multipleAuthorities ? EntryManifest.toPath(scheme, groupAuthority, pathname) : pathname),
296
394
  })))
297
395
  : [];
396
+ }
397
+ // The shell-glob truth over the candidates ({§find-scope-prefix-filter}): a malformed glob is refused by
398
+ // name, and an exact path left with nothing is the scheme's miss.
399
+ static #scopeCandidates(candidates, found, address, fragment, ambientKeys) {
400
+ const { scheme, projectRoot, authority, multipleAuthorities, scopePathname, scope } = found;
401
+ let inScope = candidates;
298
402
  if (scope !== null) {
299
403
  try {
300
- candidates = candidates.filter((c) => pathScopeMatches(scope, c.pathname, address.pathBase));
404
+ inScope = candidates.filter((c) => pathScopeMatches(scope, c.pathname, address.pathBase));
301
405
  }
302
406
  catch {
303
407
  return {
@@ -312,7 +416,7 @@ export default class EntryFind {
312
416
  };
313
417
  }
314
418
  }
315
- if (!multipleAuthorities && scope?.kind === "exact" && candidates.length === 0) {
419
+ if (!multipleAuthorities && scope?.kind === "exact" && inScope.length === 0 && ambientKeys.length === 0) {
316
420
  const target = EntryFind.#targetPath(scheme, authority, scope.pathname, fragment, projectRoot);
317
421
  return {
318
422
  status: 404,
@@ -322,49 +426,26 @@ export default class EntryFind {
322
426
  extensions: missExtensions(scheme, target),
323
427
  };
324
428
  }
325
- if (multipleAuthorities) {
326
- candidates = candidates.map((candidate) => ({
327
- ...candidate, pathname: EntryManifest.toPath(scheme, candidate.authority, candidate.pathname),
328
- }));
329
- }
330
- const channels = new Map(candidates.map((candidate) => [candidate.pathname, candidate.channel]));
331
- const channelOf = (key) => {
332
- const selected = channels.get(key);
333
- if (selected === undefined)
334
- throw new Error(`FIND candidate lost its selected channel: ${key}`);
335
- return selected;
336
- };
337
- const effectiveBytes = address.bytes === undefined ? undefined : (key) => {
338
- const coordinate = coordinateByKey.get(key);
339
- if (coordinate === undefined)
340
- throw new Error(`FIND byte source lost coordinate ${key}`);
341
- return address.bytes(coordinate.pathname, coordinate.authority);
342
- };
343
- // Every dialect resolves to one selection per resource. Content
344
- // dialects already carry honest match evidence; relation dialects map
345
- // their indexed source spans into readable TextRegions below.
429
+ return inScope;
430
+ }
431
+ // Every dialect resolves to one selection per resource: rank for ~full-text, the relation index for
432
+ // &graph, every candidate for a bare listing, and the content matcher otherwise. Content dialects
433
+ // already carry honest match evidence; relation dialects map their indexed source spans into readable
434
+ // TextRegions.
435
+ static async #selectMatches(statement, ctx, address, selection) {
436
+ const { candidates, ambientKeys, channelOf } = selection;
346
437
  let matches;
347
438
  if (statement.matcher !== null && statement.matcher.dialect === "fts") {
348
439
  const candidateSet = resolveSearchCandidates(candidates.map(({ pathname, deep_hash }) => ({ key: pathname, deepHash: deep_hash })));
349
440
  if (candidateSet.state === "incomplete")
350
- return {
351
- status: 503,
352
- matches: [],
353
- error: `The persistent search index covers ${candidateSet.indexed} of ${candidateSet.total} selected entries.`,
354
- extensions: {
355
- search: candidateSet,
356
- stage: "search-index",
357
- recovery: "Wait for search indexing to complete before repeating the search.",
358
- retryable: true,
359
- },
360
- };
441
+ return incompleteIndex(candidateSet, "selected entries");
361
442
  const ranked = await EntryFts.rankCandidates(ctx.db, candidateSet.candidates, statement.matcher.raw.slice(1), ctx.signal);
362
443
  if (ranked.status !== 200)
363
444
  return { status: ranked.status, matches: [], problem: ranked.problem };
364
445
  matches = ranked.matches.map(({ key, matches: locations }) => ({ pathname: key, matches: locations }));
365
446
  }
366
447
  else if (statement.matcher === null) {
367
- matches = candidates.map((c) => ({ pathname: c.pathname, matches: [] }));
448
+ matches = [...candidates.map((c) => ({ pathname: c.pathname, matches: [] })), ...ambientKeys.map((pathname) => ({ pathname, matches: [] }))];
368
449
  }
369
450
  else if (statement.matcher.dialect === "graph") {
370
451
  // {§relation-indexed-dialects} Parser admission owns graph syntax;
@@ -385,33 +466,13 @@ export default class EntryFind {
385
466
  // in-scope candidates from the target glob for the final set.
386
467
  const scopedCandidates = resolveSearchCandidates(candidates.map(({ pathname, deep_hash }) => ({ key: pathname, deepHash: deep_hash })));
387
468
  if (scopedCandidates.state === "incomplete")
388
- return {
389
- status: 503,
390
- matches: [],
391
- error: `The persistent search index covers ${scopedCandidates.indexed} of ${scopedCandidates.total} selected entries.`,
392
- extensions: {
393
- search: scopedCandidates,
394
- stage: "search-index",
395
- recovery: "Wait for search indexing to complete before repeating the search.",
396
- retryable: true,
397
- },
398
- };
469
+ return incompleteIndex(scopedCandidates, "selected entries");
399
470
  const universeRows = await ctx.db.find_workspace_derivation_candidates.all({
400
471
  workspace_id: ctx.workspaceId,
401
472
  });
402
473
  const universe = resolveSearchCandidates(universeRows.map(({ key, deep_hash }) => ({ key, deepHash: deep_hash })));
403
474
  if (universe.state === "incomplete")
404
- return {
405
- status: 503,
406
- matches: [],
407
- error: `The persistent search index covers ${universe.indexed} of ${universe.total} entries in the relationship universe.`,
408
- extensions: {
409
- search: universe,
410
- stage: "search-index",
411
- recovery: "Wait for search indexing to complete before repeating the search.",
412
- retryable: true,
413
- },
414
- };
475
+ return incompleteIndex(universe, "entries in the relationship universe");
415
476
  const graph = await EntryGraph.matchCandidates(ctx.db, universe.candidates, scopedCandidates.candidates, statement.matcher.raw);
416
477
  if (graph.status !== 200) {
417
478
  return {
@@ -430,63 +491,99 @@ export default class EntryFind {
430
491
  }));
431
492
  }
432
493
  else {
433
- const { mimetypes } = ctx;
434
- if (mimetypes === undefined)
435
- throw new Error("EntryFind.#matchPathnames: body matcher requires the mimetypes capability in ctx");
436
- // {§find-source-agnostic} — the shared content-matcher primitive (Log.find runs the same
437
- // one over log rows). Candidates key by pathname; each hit becomes a Match.
438
- const textCandidates = [];
439
- const byteCandidates = [];
440
- // {§find-bytes}/{§binary-parity} — a binary channel is searched as bytes, never as its stored
441
- // text form: from the scheme's byte supplier (a File member's disk) or, absent one, from the
442
- // bytes a DB entry keeps base64 in its content. It is never handed to the text matcher, so its
443
- // bytes cannot poison a text search; a binary channel with neither source has nothing to search.
444
- const contentBytes = new Map();
445
- for (const c of candidates) {
446
- if (c.content === undefined || c.mimetype === undefined)
447
- throw new Error("EntryFind.#matchPathnames: content candidate is incomplete");
448
- if (await MimetypeBinary.isBinaryMimetype(c.mimetype, mimetypes)) {
449
- if (effectiveBytes !== undefined)
450
- byteCandidates.push(c.pathname);
451
- else if (c.content !== "") {
452
- byteCandidates.push(c.pathname);
453
- contentBytes.set(c.pathname, EntryCrud.contentByteSource(c.content));
454
- }
494
+ const content = await EntryFind.#matchContent(statement.matcher, ctx, address, selection);
495
+ if ("status" in content)
496
+ return content;
497
+ matches = content;
498
+ }
499
+ return matches;
500
+ }
501
+ // {§find-source-agnostic} The content matcher over the candidates' text and bytes, and over the universe
502
+ // beyond membership: a hit there proposes admission instead of showing content ({§membership-auto-add}).
503
+ static async #matchContent(matcher, ctx, address, selection) {
504
+ const { candidates, ambientKeys, channelOf, effectiveBytes } = selection;
505
+ const { mimetypes } = ctx;
506
+ if (mimetypes === undefined)
507
+ throw new Error("EntryFind.#matchContent: body matcher requires the mimetypes capability in ctx");
508
+ // {§find-source-agnostic} — the shared content-matcher primitive (Log.find runs the same
509
+ // one over log rows). Candidates key by pathname; each hit becomes a Match.
510
+ const textCandidates = [];
511
+ const byteCandidates = [];
512
+ // {§find-bytes}/{§binary-parity} — a binary channel is searched as bytes, never as its stored
513
+ // text form: from the scheme's byte supplier (a File member's disk) or, absent one, from the
514
+ // bytes a DB entry keeps base64 in its content. It is never handed to the text matcher, so its
515
+ // bytes cannot poison a text search; a binary channel with neither source has nothing to search.
516
+ const contentBytes = new Map();
517
+ for (const c of candidates) {
518
+ if (c.content === undefined || c.mimetype === undefined)
519
+ throw new Error("EntryFind.#matchContent: content candidate is incomplete");
520
+ if (await MimetypeBinary.isBinaryMimetype(c.mimetype, mimetypes)) {
521
+ if (effectiveBytes !== undefined)
522
+ byteCandidates.push(c.pathname);
523
+ else if (c.content !== "") {
524
+ byteCandidates.push(c.pathname);
525
+ contentBytes.set(c.pathname, EntryCrud.contentByteSource(c.content));
455
526
  }
456
- else
457
- textCandidates.push({ key: c.pathname, content: c.content, mimetype: c.mimetype });
458
527
  }
459
- const byteSupplier = effectiveBytes ?? ((pathname) => contentBytes.get(pathname));
460
- const r = textCandidates.length === 0
461
- ? { status: 200, matches: [] }
462
- : await Matcher.matchCandidates(statement.matcher, textCandidates, mimetypes);
463
- if (r.status !== 200)
464
- return {
465
- status: r.status,
466
- matches: [],
467
- problem: r.problem,
468
- };
469
- const bytesMatched = byteCandidates.length === 0
470
- ? { status: 200, matches: [] }
471
- : await EntryFind.#matchBytes(statement.matcher, byteCandidates, byteSupplier, mimetypes, channelOf);
472
- if (bytesMatched.status !== 200)
473
- return {
474
- status: bytesMatched.status,
475
- matches: [],
476
- problem: bytesMatched.problem,
477
- };
478
- matches = [
479
- ...r.matches.map((match) => ({
480
- pathname: match.key,
481
- matches: match.matches.map((evidence) => ({ channel: channelOf(match.key), ...evidence })),
482
- })),
483
- ...bytesMatched.matches,
484
- ];
528
+ else
529
+ textCandidates.push({ key: c.pathname, content: c.content, mimetype: c.mimetype });
485
530
  }
486
- const projectedScope = multipleAuthorities && scopePathname !== null
487
- ? pathScope(EntryManifest.toPath(scheme, authority, scopePathname), manifest.folderScopes === true)
488
- : scope;
489
- return { status: 200, matches, channel: fragment ?? candidates[0]?.channel, ...(projectedScope === null ? {} : { scope: projectedScope }), folders };
531
+ // {§membership-auto-add} — a candidate's text is matched from disk; a match admits it, and the
532
+ // selection runs again over members, so an unadmitted candidate never shows its content.
533
+ const ambientSet = new Set(ambientKeys);
534
+ for (const key of ambientKeys) {
535
+ const text = await address.ambient.text(key);
536
+ if (text?.content != null)
537
+ textCandidates.push({ key, content: text.content, mimetype: text.mimetype });
538
+ }
539
+ const byteSupplier = effectiveBytes ?? ((pathname) => contentBytes.get(pathname));
540
+ const r = textCandidates.length === 0
541
+ ? { status: 200, matches: [] }
542
+ : await Matcher.matchCandidates(matcher, textCandidates, mimetypes);
543
+ if (r.status !== 200)
544
+ return {
545
+ status: r.status,
546
+ matches: [],
547
+ problem: r.problem,
548
+ };
549
+ const ambientMatched = r.matches.filter((match) => ambientSet.has(match.key)).map((match) => match.key);
550
+ if (ambientMatched.length > 0) {
551
+ const proposal = await address.ambient.propose(ambientMatched);
552
+ if (proposal !== null)
553
+ return { status: 202, matches: [], proposal };
554
+ }
555
+ r.matches = r.matches.filter((match) => !ambientSet.has(match.key));
556
+ const bytesMatched = byteCandidates.length === 0
557
+ ? { status: 200, matches: [] }
558
+ : await EntryFind.#matchBytes(matcher, byteCandidates, byteSupplier, mimetypes, channelOf);
559
+ if (bytesMatched.status !== 200)
560
+ return {
561
+ status: bytesMatched.status,
562
+ matches: [],
563
+ problem: bytesMatched.problem,
564
+ };
565
+ return [
566
+ ...r.matches.map((match) => ({
567
+ pathname: match.key,
568
+ matches: match.matches.map((evidence) => ({ channel: channelOf(match.key), ...evidence })),
569
+ })),
570
+ ...bytesMatched.matches,
571
+ ];
572
+ }
573
+ // {§membership-auto-add} — a candidate's listing row: its type, weight and extent from disk, marked
574
+ // untracked; a binary or oversized candidate lists with no weight until a READ admits it.
575
+ static async #ambientItem(ambient, key, path, weigh) {
576
+ const text = await ambient.text(key);
577
+ if (text === null)
578
+ return null;
579
+ const content = text.content;
580
+ return [{
581
+ path,
582
+ mimetype: text.mimetype,
583
+ weight: content === null || weigh === undefined ? 0 : weigh(content),
584
+ lines: content === null ? 0 : content.split("\n").length,
585
+ aside: "untracked",
586
+ }];
490
587
  }
491
588
  // {§find-bytes} — the matcher runs over the bytes as one character each, so a text pattern
492
589
  // finds strings and `\xNN` escapes find byte sequences; every hit is re-expressed in byte
@@ -523,6 +620,9 @@ export default class EntryFind {
523
620
  match = await EntryFind.#matchPathnames(statement, ctx, manifest, address);
524
621
  }
525
622
  const empty = emptyFindFields();
623
+ // {§membership-auto-add} — the FIND proposes the admission of the candidates its pattern matched.
624
+ if (match.status === 202 && match.proposal !== undefined)
625
+ return { ...empty, ...match.proposal };
526
626
  if (match.status !== 200) {
527
627
  if (match.problem !== undefined) {
528
628
  return Results.assert({
@@ -552,9 +652,16 @@ export default class EntryFind {
552
652
  const resources = [];
553
653
  for (const m of match.matches) {
554
654
  const row = byPath.get(addressOf(m.pathname));
555
- if (row === undefined)
655
+ if (row !== undefined) {
656
+ resources.push({ item: row, match: m });
556
657
  continue;
557
- resources.push({ item: row, match: m });
658
+ }
659
+ // {§membership-auto-add} — a listed candidate has no catalog row; its row is read from disk.
660
+ if (match.ambient?.has(m.pathname) && address.ambient !== undefined) {
661
+ const item = await EntryFind.#ambientItem(address.ambient, m.pathname, addressOf(m.pathname), ctx.weigh);
662
+ if (item !== null)
663
+ resources.push({ item, match: m });
664
+ }
558
665
  }
559
666
  // A terminal single-star catalog is a one-level map. Keep real entries
560
667
  // at that level and collapse deeper descendants into exact, actionable
@@ -567,8 +674,11 @@ export default class EntryFind {
567
674
  let items = 0;
568
675
  for (const pathname of folder.pathnames) {
569
676
  const row = byPath.get(addressOf(pathname));
570
- if (row === undefined)
677
+ if (row === undefined) {
678
+ if (match.ambient?.has(pathname))
679
+ items++;
571
680
  continue;
681
+ }
572
682
  items++;
573
683
  weight += row.reduce((sum, channel) => sum + channel.weight, 0);
574
684
  }
@@ -580,7 +690,8 @@ export default class EntryFind {
580
690
  if (match.scope === undefined)
581
691
  throw new Error("FIND selection succeeded without a path scope");
582
692
  const projected = projectFindResult(statement, match.scope, resources, scopes, manifest.defaultChannel);
583
- if (address.pathname === undefined)
693
+ // {§membership-auto-add} — a listed candidate has no stored representation to consume.
694
+ if (address.pathname === undefined || match.ambient?.has(address.pathname))
584
695
  return projected;
585
696
  // Exact FIND consumes the same selected canonical producer as exact
586
697
  // READ. Query projection remains core-owned, while the durable selected-