@plurnk/plurnk-service 1.0.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 (343) hide show
  1. package/.env.defaults +208 -0
  2. package/INSTALL.md +69 -0
  3. package/LICENSE +21 -0
  4. package/README.md +46 -0
  5. package/SPEC.md +1511 -0
  6. package/dist/Paths.d.ts +13 -0
  7. package/dist/Paths.d.ts.map +1 -0
  8. package/dist/Paths.js +60 -0
  9. package/dist/Paths.js.map +1 -0
  10. package/dist/content/edited-span.d.ts +2 -0
  11. package/dist/content/edited-span.d.ts.map +1 -0
  12. package/dist/content/edited-span.js +33 -0
  13. package/dist/content/edited-span.js.map +1 -0
  14. package/dist/content/index.d.ts +10 -0
  15. package/dist/content/index.d.ts.map +1 -0
  16. package/dist/content/index.js +11 -0
  17. package/dist/content/index.js.map +1 -0
  18. package/dist/content/line-marker.d.ts +15 -0
  19. package/dist/content/line-marker.d.ts.map +1 -0
  20. package/dist/content/line-marker.js +21 -0
  21. package/dist/content/line-marker.js.map +1 -0
  22. package/dist/content/matcher.d.ts +44 -0
  23. package/dist/content/matcher.d.ts.map +1 -0
  24. package/dist/content/matcher.js +126 -0
  25. package/dist/content/matcher.js.map +1 -0
  26. package/dist/content/mimetype-binary.d.ts +8 -0
  27. package/dist/content/mimetype-binary.d.ts.map +1 -0
  28. package/dist/content/mimetype-binary.js +17 -0
  29. package/dist/content/mimetype-binary.js.map +1 -0
  30. package/dist/content/path-mimetype.d.ts +5 -0
  31. package/dist/content/path-mimetype.d.ts.map +1 -0
  32. package/dist/content/path-mimetype.js +15 -0
  33. package/dist/content/path-mimetype.js.map +1 -0
  34. package/dist/content/read-resolve.d.ts +20 -0
  35. package/dist/content/read-resolve.d.ts.map +1 -0
  36. package/dist/content/read-resolve.js +68 -0
  37. package/dist/content/read-resolve.js.map +1 -0
  38. package/dist/core/ChannelWrite.d.ts +100 -0
  39. package/dist/core/ChannelWrite.d.ts.map +1 -0
  40. package/dist/core/ChannelWrite.js +112 -0
  41. package/dist/core/ChannelWrite.js.map +1 -0
  42. package/dist/core/ChannelWrite.sql +84 -0
  43. package/dist/core/Db.d.ts +14 -0
  44. package/dist/core/Db.d.ts.map +1 -0
  45. package/dist/core/Db.js +7 -0
  46. package/dist/core/Db.js.map +1 -0
  47. package/dist/core/Dispatcher.d.ts +67 -0
  48. package/dist/core/Dispatcher.d.ts.map +1 -0
  49. package/dist/core/Dispatcher.js +1021 -0
  50. package/dist/core/Dispatcher.js.map +1 -0
  51. package/dist/core/Engine.d.ts +113 -0
  52. package/dist/core/Engine.d.ts.map +1 -0
  53. package/dist/core/Engine.js +1410 -0
  54. package/dist/core/Engine.js.map +1 -0
  55. package/dist/core/Engine.sql +538 -0
  56. package/dist/core/EnvFlags.d.ts +13 -0
  57. package/dist/core/EnvFlags.d.ts.map +1 -0
  58. package/dist/core/EnvFlags.js +84 -0
  59. package/dist/core/EnvFlags.js.map +1 -0
  60. package/dist/core/ExecutorRegistry.d.ts +45 -0
  61. package/dist/core/ExecutorRegistry.d.ts.map +1 -0
  62. package/dist/core/ExecutorRegistry.js +128 -0
  63. package/dist/core/ExecutorRegistry.js.map +1 -0
  64. package/dist/core/PacketBuilder.d.ts +67 -0
  65. package/dist/core/PacketBuilder.d.ts.map +1 -0
  66. package/dist/core/PacketBuilder.js +524 -0
  67. package/dist/core/PacketBuilder.js.map +1 -0
  68. package/dist/core/PluginLoader.d.ts +17 -0
  69. package/dist/core/PluginLoader.d.ts.map +1 -0
  70. package/dist/core/PluginLoader.js +97 -0
  71. package/dist/core/PluginLoader.js.map +1 -0
  72. package/dist/core/ProposalLifecycle.d.ts +59 -0
  73. package/dist/core/ProposalLifecycle.d.ts.map +1 -0
  74. package/dist/core/ProposalLifecycle.js +215 -0
  75. package/dist/core/ProposalLifecycle.js.map +1 -0
  76. package/dist/core/ProviderInstantiate.d.ts +9 -0
  77. package/dist/core/ProviderInstantiate.d.ts.map +1 -0
  78. package/dist/core/ProviderInstantiate.js +156 -0
  79. package/dist/core/ProviderInstantiate.js.map +1 -0
  80. package/dist/core/SchemeRegistry.d.ts +26 -0
  81. package/dist/core/SchemeRegistry.d.ts.map +1 -0
  82. package/dist/core/SchemeRegistry.js +205 -0
  83. package/dist/core/SchemeRegistry.js.map +1 -0
  84. package/dist/core/StrikeRail.d.ts +28 -0
  85. package/dist/core/StrikeRail.d.ts.map +1 -0
  86. package/dist/core/StrikeRail.js +165 -0
  87. package/dist/core/StrikeRail.js.map +1 -0
  88. package/dist/core/TelemetryChannel.d.ts +37 -0
  89. package/dist/core/TelemetryChannel.d.ts.map +1 -0
  90. package/dist/core/TelemetryChannel.js +77 -0
  91. package/dist/core/TelemetryChannel.js.map +1 -0
  92. package/dist/core/TokenGauge.d.ts +16 -0
  93. package/dist/core/TokenGauge.d.ts.map +1 -0
  94. package/dist/core/TokenGauge.js +58 -0
  95. package/dist/core/TokenGauge.js.map +1 -0
  96. package/dist/core/caps/CapsResolve.d.ts +5 -0
  97. package/dist/core/caps/CapsResolve.d.ts.map +1 -0
  98. package/dist/core/caps/CapsResolve.js +13 -0
  99. package/dist/core/caps/CapsResolve.js.map +1 -0
  100. package/dist/core/caps/DbChannelCaps.d.ts +16 -0
  101. package/dist/core/caps/DbChannelCaps.d.ts.map +1 -0
  102. package/dist/core/caps/DbChannelCaps.js +41 -0
  103. package/dist/core/caps/DbChannelCaps.js.map +1 -0
  104. package/dist/core/caps/DbEntryCaps.d.ts +19 -0
  105. package/dist/core/caps/DbEntryCaps.d.ts.map +1 -0
  106. package/dist/core/caps/DbEntryCaps.js +28 -0
  107. package/dist/core/caps/DbEntryCaps.js.map +1 -0
  108. package/dist/core/caps/DbNotifyCaps.d.ts +8 -0
  109. package/dist/core/caps/DbNotifyCaps.d.ts.map +1 -0
  110. package/dist/core/caps/DbNotifyCaps.js +35 -0
  111. package/dist/core/caps/DbNotifyCaps.js.map +1 -0
  112. package/dist/core/caps/DbSubscriptionCaps.d.ts +10 -0
  113. package/dist/core/caps/DbSubscriptionCaps.d.ts.map +1 -0
  114. package/dist/core/caps/DbSubscriptionCaps.js +86 -0
  115. package/dist/core/caps/DbSubscriptionCaps.js.map +1 -0
  116. package/dist/core/caps/DbTagCaps.d.ts +17 -0
  117. package/dist/core/caps/DbTagCaps.d.ts.map +1 -0
  118. package/dist/core/caps/DbTagCaps.js +37 -0
  119. package/dist/core/caps/DbTagCaps.js.map +1 -0
  120. package/dist/core/caps/SchemeCtxImpl.d.ts +18 -0
  121. package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -0
  122. package/dist/core/caps/SchemeCtxImpl.js +42 -0
  123. package/dist/core/caps/SchemeCtxImpl.js.map +1 -0
  124. package/dist/core/env-defaults.d.ts +19 -0
  125. package/dist/core/env-defaults.d.ts.map +1 -0
  126. package/dist/core/env-defaults.js +89 -0
  127. package/dist/core/env-defaults.js.map +1 -0
  128. package/dist/core/fork.d.ts +6 -0
  129. package/dist/core/fork.d.ts.map +1 -0
  130. package/dist/core/fork.js +84 -0
  131. package/dist/core/fork.js.map +1 -0
  132. package/dist/core/fork.sql +85 -0
  133. package/dist/core/git-membership.d.ts +23 -0
  134. package/dist/core/git-membership.d.ts.map +1 -0
  135. package/dist/core/git-membership.js +366 -0
  136. package/dist/core/git-membership.js.map +1 -0
  137. package/dist/core/git-state.d.ts +15 -0
  138. package/dist/core/git-state.d.ts.map +1 -0
  139. package/dist/core/git-state.js +67 -0
  140. package/dist/core/git-state.js.map +1 -0
  141. package/dist/core/packet-inject.d.ts +5 -0
  142. package/dist/core/packet-inject.d.ts.map +1 -0
  143. package/dist/core/packet-inject.js +48 -0
  144. package/dist/core/packet-inject.js.map +1 -0
  145. package/dist/core/packet-wire.d.ts +46 -0
  146. package/dist/core/packet-wire.d.ts.map +1 -0
  147. package/dist/core/packet-wire.js +453 -0
  148. package/dist/core/packet-wire.js.map +1 -0
  149. package/dist/core/path-decode.d.ts +2 -0
  150. package/dist/core/path-decode.d.ts.map +1 -0
  151. package/dist/core/path-decode.js +8 -0
  152. package/dist/core/path-decode.js.map +1 -0
  153. package/dist/core/plugin-attribution.d.ts +5 -0
  154. package/dist/core/plugin-attribution.d.ts.map +1 -0
  155. package/dist/core/plugin-attribution.js +39 -0
  156. package/dist/core/plugin-attribution.js.map +1 -0
  157. package/dist/core/plurnk-uri.d.ts +7 -0
  158. package/dist/core/plurnk-uri.d.ts.map +1 -0
  159. package/dist/core/plurnk-uri.js +52 -0
  160. package/dist/core/plurnk-uri.js.map +1 -0
  161. package/dist/core/resolveForLoop.d.ts +5 -0
  162. package/dist/core/resolveForLoop.d.ts.map +1 -0
  163. package/dist/core/resolveForLoop.js +12 -0
  164. package/dist/core/resolveForLoop.js.map +1 -0
  165. package/dist/core/results.d.ts +12 -0
  166. package/dist/core/results.d.ts.map +1 -0
  167. package/dist/core/results.js +27 -0
  168. package/dist/core/results.js.map +1 -0
  169. package/dist/core/run-cap.d.ts +8 -0
  170. package/dist/core/run-cap.d.ts.map +1 -0
  171. package/dist/core/run-cap.js +20 -0
  172. package/dist/core/run-cap.js.map +1 -0
  173. package/dist/core/run-ops.sql +43 -0
  174. package/dist/core/scheme-types.d.ts +45 -0
  175. package/dist/core/scheme-types.d.ts.map +1 -0
  176. package/dist/core/scheme-types.js +6 -0
  177. package/dist/core/scheme-types.js.map +1 -0
  178. package/dist/core/session-settings.d.ts +23 -0
  179. package/dist/core/session-settings.d.ts.map +1 -0
  180. package/dist/core/session-settings.js +55 -0
  181. package/dist/core/session-settings.js.map +1 -0
  182. package/dist/core/teaching.d.ts +3 -0
  183. package/dist/core/teaching.d.ts.map +1 -0
  184. package/dist/core/teaching.js +13 -0
  185. package/dist/core/teaching.js.map +1 -0
  186. package/dist/core/types.d.ts +3 -0
  187. package/dist/core/types.d.ts.map +1 -0
  188. package/dist/core/types.js +2 -0
  189. package/dist/core/types.js.map +1 -0
  190. package/dist/digest/Digest.d.ts +20 -0
  191. package/dist/digest/Digest.d.ts.map +1 -0
  192. package/dist/digest/Digest.js +451 -0
  193. package/dist/digest/Digest.js.map +1 -0
  194. package/dist/digest/Digest.sql +1 -0
  195. package/dist/digest/digest.sql +55 -0
  196. package/dist/index.d.ts +18 -0
  197. package/dist/index.d.ts.map +1 -0
  198. package/dist/index.js +28 -0
  199. package/dist/index.js.map +1 -0
  200. package/dist/schemes/EffectPolicy.d.ts +6 -0
  201. package/dist/schemes/EffectPolicy.d.ts.map +1 -0
  202. package/dist/schemes/EffectPolicy.js +18 -0
  203. package/dist/schemes/EffectPolicy.js.map +1 -0
  204. package/dist/schemes/Exec.d.ts +39 -0
  205. package/dist/schemes/Exec.d.ts.map +1 -0
  206. package/dist/schemes/Exec.js +510 -0
  207. package/dist/schemes/Exec.js.map +1 -0
  208. package/dist/schemes/ExecOutputScheme.d.ts +20 -0
  209. package/dist/schemes/ExecOutputScheme.d.ts.map +1 -0
  210. package/dist/schemes/ExecOutputScheme.js +39 -0
  211. package/dist/schemes/ExecOutputScheme.js.map +1 -0
  212. package/dist/schemes/File.d.ts +42 -0
  213. package/dist/schemes/File.d.ts.map +1 -0
  214. package/dist/schemes/File.js +356 -0
  215. package/dist/schemes/File.js.map +1 -0
  216. package/dist/schemes/Known.d.ts +17 -0
  217. package/dist/schemes/Known.d.ts.map +1 -0
  218. package/dist/schemes/Known.js +40 -0
  219. package/dist/schemes/Known.js.map +1 -0
  220. package/dist/schemes/Log.d.ts +22 -0
  221. package/dist/schemes/Log.d.ts.map +1 -0
  222. package/dist/schemes/Log.js +269 -0
  223. package/dist/schemes/Log.js.map +1 -0
  224. package/dist/schemes/Log.sql +59 -0
  225. package/dist/schemes/Plurnk.d.ts +17 -0
  226. package/dist/schemes/Plurnk.d.ts.map +1 -0
  227. package/dist/schemes/Plurnk.js +46 -0
  228. package/dist/schemes/Plurnk.js.map +1 -0
  229. package/dist/schemes/Run.d.ts +25 -0
  230. package/dist/schemes/Run.d.ts.map +1 -0
  231. package/dist/schemes/Run.js +172 -0
  232. package/dist/schemes/Run.js.map +1 -0
  233. package/dist/schemes/Skill.d.ts +17 -0
  234. package/dist/schemes/Skill.d.ts.map +1 -0
  235. package/dist/schemes/Skill.js +40 -0
  236. package/dist/schemes/Skill.js.map +1 -0
  237. package/dist/schemes/Unknown.d.ts +17 -0
  238. package/dist/schemes/Unknown.d.ts.map +1 -0
  239. package/dist/schemes/Unknown.js +39 -0
  240. package/dist/schemes/Unknown.js.map +1 -0
  241. package/dist/schemes/_entry-chunk.d.ts +11 -0
  242. package/dist/schemes/_entry-chunk.d.ts.map +1 -0
  243. package/dist/schemes/_entry-chunk.js +100 -0
  244. package/dist/schemes/_entry-chunk.js.map +1 -0
  245. package/dist/schemes/_entry-crud.d.ts +31 -0
  246. package/dist/schemes/_entry-crud.d.ts.map +1 -0
  247. package/dist/schemes/_entry-crud.js +77 -0
  248. package/dist/schemes/_entry-crud.js.map +1 -0
  249. package/dist/schemes/_entry-crud.sql +101 -0
  250. package/dist/schemes/_entry-find.d.ts +32 -0
  251. package/dist/schemes/_entry-find.d.ts.map +1 -0
  252. package/dist/schemes/_entry-find.js +226 -0
  253. package/dist/schemes/_entry-find.js.map +1 -0
  254. package/dist/schemes/_entry-find.sql +54 -0
  255. package/dist/schemes/_entry-graph.d.ts +16 -0
  256. package/dist/schemes/_entry-graph.d.ts.map +1 -0
  257. package/dist/schemes/_entry-graph.js +94 -0
  258. package/dist/schemes/_entry-graph.js.map +1 -0
  259. package/dist/schemes/_entry-graph.sql +52 -0
  260. package/dist/schemes/_entry-manifest.d.ts +25 -0
  261. package/dist/schemes/_entry-manifest.d.ts.map +1 -0
  262. package/dist/schemes/_entry-manifest.js +266 -0
  263. package/dist/schemes/_entry-manifest.js.map +1 -0
  264. package/dist/schemes/_entry-ops.d.ts +32 -0
  265. package/dist/schemes/_entry-ops.d.ts.map +1 -0
  266. package/dist/schemes/_entry-ops.js +216 -0
  267. package/dist/schemes/_entry-ops.js.map +1 -0
  268. package/dist/schemes/_entry-ops.sql +31 -0
  269. package/dist/schemes/_entry-semantic.d.ts +38 -0
  270. package/dist/schemes/_entry-semantic.d.ts.map +1 -0
  271. package/dist/schemes/_entry-semantic.js +202 -0
  272. package/dist/schemes/_entry-semantic.js.map +1 -0
  273. package/dist/schemes/_entry-semantic.sql +95 -0
  274. package/dist/schemes/_entry-send.d.ts +11 -0
  275. package/dist/schemes/_entry-send.d.ts.map +1 -0
  276. package/dist/schemes/_entry-send.js +66 -0
  277. package/dist/schemes/_entry-send.js.map +1 -0
  278. package/dist/schemes/cosine.d.ts +4 -0
  279. package/dist/schemes/cosine.d.ts.map +1 -0
  280. package/dist/schemes/cosine.js +9 -0
  281. package/dist/schemes/cosine.js.map +1 -0
  282. package/dist/schemes/exec-abort.d.ts +15 -0
  283. package/dist/schemes/exec-abort.d.ts.map +1 -0
  284. package/dist/schemes/exec-abort.js +29 -0
  285. package/dist/schemes/exec-abort.js.map +1 -0
  286. package/dist/schemes/exec-env.d.ts +5 -0
  287. package/dist/schemes/exec-env.d.ts.map +1 -0
  288. package/dist/schemes/exec-env.js +34 -0
  289. package/dist/schemes/exec-env.js.map +1 -0
  290. package/dist/server/Daemon.d.ts +244 -0
  291. package/dist/server/Daemon.d.ts.map +1 -0
  292. package/dist/server/Daemon.js +1119 -0
  293. package/dist/server/Daemon.js.map +1 -0
  294. package/dist/server/client-input.d.ts +11 -0
  295. package/dist/server/client-input.d.ts.map +1 -0
  296. package/dist/server/client-input.js +145 -0
  297. package/dist/server/client-input.js.map +1 -0
  298. package/dist/server/clientTurn.d.ts +6 -0
  299. package/dist/server/clientTurn.d.ts.map +1 -0
  300. package/dist/server/clientTurn.js +23 -0
  301. package/dist/server/clientTurn.js.map +1 -0
  302. package/dist/server/clientTurn.sql +10 -0
  303. package/dist/server/dispatch-as-plurnk.d.ts +7 -0
  304. package/dist/server/dispatch-as-plurnk.d.ts.map +1 -0
  305. package/dist/server/dispatch-as-plurnk.js +23 -0
  306. package/dist/server/dispatch-as-plurnk.js.map +1 -0
  307. package/dist/server/drain.sql +124 -0
  308. package/dist/server/envelope.d.ts +53 -0
  309. package/dist/server/envelope.d.ts.map +1 -0
  310. package/dist/server/envelope.js +172 -0
  311. package/dist/server/envelope.js.map +1 -0
  312. package/dist/server/envelope.sql +76 -0
  313. package/dist/server/logEntry.d.ts +35 -0
  314. package/dist/server/logEntry.d.ts.map +1 -0
  315. package/dist/server/logEntry.js +49 -0
  316. package/dist/server/logEntry.js.map +1 -0
  317. package/dist/server/logEntry.sql +10 -0
  318. package/dist/server/loopDocs.d.ts +6 -0
  319. package/dist/server/loopDocs.d.ts.map +1 -0
  320. package/dist/server/loopDocs.js +22 -0
  321. package/dist/server/loopDocs.js.map +1 -0
  322. package/dist/server/noProposals.d.ts +6 -0
  323. package/dist/server/noProposals.d.ts.map +1 -0
  324. package/dist/server/noProposals.js +37 -0
  325. package/dist/server/noProposals.js.map +1 -0
  326. package/dist/server/seam-entry-read.sql +21 -0
  327. package/dist/server/seam-log-read.sql +21 -0
  328. package/dist/server/seam-loop.sql +9 -0
  329. package/dist/server/seam-proposal-list.sql +13 -0
  330. package/dist/server/version-info.d.ts +14 -0
  331. package/dist/server/version-info.d.ts.map +1 -0
  332. package/dist/server/version-info.js +69 -0
  333. package/dist/server/version-info.js.map +1 -0
  334. package/dist/server/yolo.d.ts +6 -0
  335. package/dist/server/yolo.d.ts.map +1 -0
  336. package/dist/server/yolo.js +64 -0
  337. package/dist/server/yolo.js.map +1 -0
  338. package/dist/service.d.ts +6 -0
  339. package/dist/service.d.ts.map +1 -0
  340. package/dist/service.js +309 -0
  341. package/dist/service.js.map +1 -0
  342. package/migrations/0000-00-00.01_schema.sql +500 -0
  343. package/package.json +86 -0
@@ -0,0 +1,172 @@
1
+ // Envelope lifecycle helpers for client connections. SPEC §connection-lifecycle.
2
+ //
3
+ // Every connected client gets a (session, run, client-loop) envelope. Either
4
+ // the client picks the session explicitly (session.create / session.attach)
5
+ // or the daemon auto-creates one on first requiresInit RPC. In both cases
6
+ // the daemon opens a NEW run within the session and a NEW client loop within
7
+ // that run; the client loop closes on disconnect.
8
+ import GitMembership from "../core/git-membership.js";
9
+ export default class Envelope {
10
+ // Run names reserved for non-client actors: a client must not create OR
11
+ // attach to a run under a reserved name (origin-impersonation — `plurnk`
12
+ // is the runtime actor, §authority-terms/§actor-boundary). Checked case-insensitively, before
13
+ // lookup, so a client can neither forge nor hijack one (SPEC §methods).
14
+ static RESERVED_RUN_NAMES = new Set(["plurnk"]); // §methods-run-name-reserved
15
+ // Grammar 0.5.0 (#10): Session and Run carry user-renameable string names.
16
+ // Defaults are `session-{unixtime}` and `run-{unixtime}`; random suffix avoids
17
+ // collisions when two creations land in the same second.
18
+ static #tsName(prefix) {
19
+ const ts = Math.floor(Date.now() / 1000);
20
+ const rand = Math.floor(Math.random() * 0xFFFFFF).toString(36).padStart(4, "0");
21
+ return `${prefix}-${ts}-${rand}`;
22
+ }
23
+ static generateSessionName() {
24
+ return Envelope.#tsName("session");
25
+ }
26
+ static generateRunName() {
27
+ return Envelope.#tsName("run");
28
+ }
29
+ static async createClientEnvelope(db, opts = {}) {
30
+ const name = opts.name ?? Envelope.#tsName(opts.prefix ?? "session");
31
+ const projectRoot = opts.projectRoot ?? null;
32
+ const session = await db.envelope_insert_session.get({ name, project_root: projectRoot, settings: opts.settings ?? "{}" });
33
+ if (session === undefined)
34
+ throw new Error("createClientEnvelope: session insert returned no row");
35
+ // SPEC §membership D4 — establish git-ls-files membership at workspace setup so
36
+ // tracked files are members before the first op. No-op when projectRoot is
37
+ // null (headless) or not a git working tree.
38
+ await GitMembership.resolveGitMembership(db, session.id, undefined);
39
+ const runName = Envelope.generateRunName();
40
+ const run = await db.envelope_insert_run.get({ session_id: session.id, name: runName, origin: "client" });
41
+ if (run === undefined)
42
+ throw new Error("createClientEnvelope: run insert returned no row");
43
+ return {
44
+ sessionId: session.id, sessionName: session.name,
45
+ projectRoot: session.project_root,
46
+ runId: run.id, runName: run.name,
47
+ modelRunId: null,
48
+ clientLoopId: null,
49
+ };
50
+ }
51
+ // Resolve the run inside a session. Three modes:
52
+ // - opts.runId given: lookup by id, verify session ownership (else throw).
53
+ // - opts.runName given: lookup by (sessionId, name); reuse if found, create otherwise.
54
+ // - neither: create a new run with an auto-generated name (current behavior).
55
+ // `runId` and `runName` are alternatives — passing both throws (use one).
56
+ static async #resolveRun(db, sessionId, opts) {
57
+ if (opts.runId !== undefined && opts.runName !== undefined) {
58
+ throw new Error("attachToSession: pass runId OR runName, not both");
59
+ }
60
+ if (opts.runId !== undefined) {
61
+ const existing = await db.envelope_get_run_by_id.get({ id: opts.runId });
62
+ if (existing === undefined)
63
+ throw new Error(`run ${opts.runId} not found`);
64
+ if (existing.session_id !== sessionId)
65
+ throw new Error(`run ${opts.runId} belongs to session ${existing.session_id}, not ${sessionId}`);
66
+ return { id: existing.id, name: existing.name };
67
+ }
68
+ if (opts.runName !== undefined) {
69
+ if (Envelope.RESERVED_RUN_NAMES.has(opts.runName.toLowerCase())) {
70
+ throw new Error(`run name "${opts.runName}" is reserved for a non-client actor`);
71
+ }
72
+ const existing = await db.envelope_get_run_by_name.get({ session_id: sessionId, name: opts.runName });
73
+ if (existing !== undefined)
74
+ return existing;
75
+ const created = await db.envelope_insert_run.get({ session_id: sessionId, name: opts.runName, origin: "client" });
76
+ if (created === undefined)
77
+ throw new Error("resolveRun: run insert returned no row");
78
+ return created;
79
+ }
80
+ const created = await db.envelope_insert_run.get({ session_id: sessionId, name: Envelope.generateRunName(), origin: "client" });
81
+ if (created === undefined)
82
+ throw new Error("resolveRun: run insert returned no row");
83
+ return created;
84
+ }
85
+ static async attachToSession(db, sessionId, opts = {}) {
86
+ const session = await db.envelope_get_session.get({ id: sessionId });
87
+ if (session === undefined)
88
+ throw new Error(`session ${sessionId} not found`);
89
+ const run = await Envelope.#resolveRun(db, session.id, opts);
90
+ return {
91
+ sessionId: session.id, sessionName: session.name,
92
+ projectRoot: session.project_root,
93
+ runId: run.id, runName: run.name,
94
+ modelRunId: null,
95
+ clientLoopId: null,
96
+ };
97
+ }
98
+ // Lazy client-loop allocator. Called from dispatchAsClient on the first
99
+ // client-origin op for this connection; subsequent ops reuse the same
100
+ // loop until the connection closes.
101
+ static async ensureClientLoop(db, runId) {
102
+ const loop = await db.envelope_insert_client_loop.get({ run_id: runId });
103
+ if (loop === undefined)
104
+ throw new Error("ensureClientLoop: loop insert returned no row");
105
+ return loop.id;
106
+ }
107
+ // Lazy model-run allocator (§connection-lifecycle, §machine-processes — the client writes to its own run).
108
+ // The model's conversation lives in its OWN run, distinct from the connection's
109
+ // (client) run, so the packet — rendered from the model's run — never carries
110
+ // the client's op.*. Created on the first loop.run; reused for the connection.
111
+ // #366 — a FRESH conversation over the same world (§machine-processes: two runs are two
112
+ // conversations about one curated workspace): a named, empty-log, model-origin ROOT run.
113
+ // Distinct from ensureModelRun (the stable default conversation) and forkRun (copies history).
114
+ static async createModelRun(db, sessionId, name) {
115
+ const run = await db.envelope_insert_run.get({ session_id: sessionId, name: name ?? Envelope.#tsName("model"), origin: "model" });
116
+ if (run === undefined)
117
+ throw new Error("createModelRun: run insert returned no row");
118
+ return run;
119
+ }
120
+ static async ensureModelRun(db, sessionId) {
121
+ // #371 — ensure means FIND-FIRST (the WS connection's per-session cache used to hide the
122
+ // insert-only bug; the seam has no connection state, so idempotence lives HERE): reuse the
123
+ // session's canonical conversation run — the earliest model-origin root (forks/workers
124
+ // inherit origin and are excluded by parent_run_id). #366 is the explicit fresh-run door.
125
+ const existing = await db.envelope_get_model_run.get({ session_id: sessionId });
126
+ if (existing !== undefined)
127
+ return existing.id;
128
+ const run = await db.envelope_insert_run.get({ session_id: sessionId, name: Envelope.#tsName("model"), origin: "model" });
129
+ if (run === undefined)
130
+ throw new Error("ensureModelRun: run insert returned no row");
131
+ return run.id;
132
+ }
133
+ // Self-hosting keystone (§actor-boundary): the session's reserved `plurnk` run, where the
134
+ // runtime acts as an ordinary actor (doc materialization today; fs/git work
135
+ // later). One per session, reused; its log is the runtime's own — invisible
136
+ // to other runs except through the shared session filesystem.
137
+ static async ensurePlurnkRun(db, sessionId) {
138
+ const existing = await db.envelope_get_run_by_name.get({ session_id: sessionId, name: "plurnk" });
139
+ if (existing !== undefined)
140
+ return existing.id;
141
+ const run = await db.envelope_insert_run.get({ session_id: sessionId, name: "plurnk", origin: "plurnk" });
142
+ if (run === undefined)
143
+ throw new Error("ensurePlurnkRun: run insert returned no row");
144
+ return run.id;
145
+ }
146
+ static async listRunsForSession(db, sessionId) {
147
+ return await db.envelope_list_runs_for_session.all({ session_id: sessionId });
148
+ }
149
+ // #238 — a session's prior user prompts, newest-first, capped. The conversation run's
150
+ // loop seeds (engine_get_loop_prompt is the per-loop read); exposed directly so a
151
+ // client seeds up/down history without log archaeology.
152
+ static async listPromptsForSession(db, sessionId, limit) {
153
+ const rows = await db.envelope_list_session_prompts.all({ session_id: sessionId, limit });
154
+ return rows.map((r) => r.prompt);
155
+ }
156
+ static async closeClientLoop(db, loopId, status) {
157
+ await db.envelope_close_client_loop.run({ status, loop_id: loopId });
158
+ }
159
+ static async listSessions(db) {
160
+ return await db.envelope_list_sessions.all();
161
+ }
162
+ // session.rename — the session name is a mutable handle (vs a run's immutable
163
+ // name, §machine-processes). Mutates sessions.name only; the UNIQUE constraint is
164
+ // the real guard against collision (the handler pre-checks for a clean error).
165
+ static async updateSessionName(db, sessionId, name) {
166
+ const row = await db.envelope_set_session_name.get({ id: sessionId, name });
167
+ if (row === undefined)
168
+ throw new Error(`session ${sessionId} not found`);
169
+ return row.name;
170
+ }
171
+ }
172
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/server/envelope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,76 @@
1
+ -- Envelope lifecycle queries. SPEC §connection-lifecycle.
2
+
3
+ -- PREP: envelope_insert_session
4
+ INSERT INTO sessions (name, project_root, settings)
5
+ VALUES ($name, $project_root, $settings)
6
+ RETURNING id, name, project_root;
7
+
8
+ -- PREP: envelope_get_session
9
+ SELECT id, name, project_root FROM sessions WHERE id = $id;
10
+
11
+
12
+ -- PREP: envelope_get_session_by_name
13
+ -- session.rename collision check — sessions.name is UNIQUE.
14
+ SELECT id FROM sessions WHERE name = $name;
15
+
16
+ -- PREP: envelope_set_session_name
17
+ -- Used by session.rename. The session name is a MUTABLE handle (vs a run's
18
+ -- immutable name, §machine-processes). Returns the updated row to refresh the
19
+ -- caller's ClientEnvelope copy.
20
+ UPDATE sessions SET name = $name WHERE id = $id
21
+ RETURNING id, name;
22
+
23
+ -- PREP: envelope_insert_run
24
+ -- origin is the run's actor (§machine-processes): 'model' (the conversation),
25
+ -- 'client' (a connection's own run), or 'plurnk' (the runtime self-hosting run).
26
+ INSERT INTO runs (session_id, name, origin)
27
+ VALUES ($session_id, $name, $origin)
28
+ RETURNING id, name, origin;
29
+
30
+ -- PREP: envelope_get_run_by_id
31
+ SELECT id, name, session_id, origin FROM runs WHERE id = $id;
32
+
33
+ -- PREP: envelope_get_run_by_name
34
+ SELECT id, name FROM runs WHERE session_id = $session_id AND name = $name;
35
+
36
+ -- PREP: envelope_list_runs_for_session
37
+ SELECT id, name, created_at, cost_pico, origin
38
+ FROM runs
39
+ WHERE session_id = $session_id
40
+ ORDER BY created_at DESC;
41
+
42
+ -- PREP: envelope_list_session_prompts
43
+ -- #238 — a session's user prompts for client up/down history: the conversation run's
44
+ -- non-empty loop seeds, newest-first, capped. The conversation run is origin='model' +
45
+ -- parentless; spawned/forked run:// sub-runs (parent_run_id set) are excluded — their
46
+ -- seed prompts are not user input.
47
+ SELECT l.prompt
48
+ FROM loops l
49
+ JOIN runs r ON r.id = l.run_id
50
+ WHERE r.session_id = $session_id
51
+ AND r.origin = 'model'
52
+ AND r.parent_run_id IS NULL
53
+ AND length(l.prompt) > 0
54
+ ORDER BY l.id DESC
55
+ LIMIT $limit;
56
+
57
+ -- PREP: envelope_insert_client_loop
58
+ -- sequence is auto-computed: 1 + max(existing sequence in this run) so
59
+ -- multiple client connections attaching to the same run get distinct loops.
60
+ INSERT INTO loops (run_id, sequence, status, prompt)
61
+ VALUES ($run_id, COALESCE((SELECT MAX(sequence) FROM loops WHERE run_id = $run_id), 0) + 1, 102, '')
62
+ RETURNING id;
63
+
64
+ -- PREP: envelope_close_client_loop
65
+ UPDATE loops SET status = $status WHERE id = $loop_id AND status = 102;
66
+
67
+ -- PREP: envelope_list_sessions
68
+ SELECT id, name, project_root, created_at, cost_pico
69
+ FROM sessions
70
+ ORDER BY created_at DESC;
71
+
72
+ -- PREP: envelope_get_model_run
73
+ -- #371 — the session's canonical model CONVERSATION run: the earliest model-origin ROOT run
74
+ -- (parent_run_id NULL excludes forks and spawned workers, which inherit origin='model').
75
+ -- ensureModelRun finds this first; only a session with none mints one.
76
+ SELECT id FROM runs WHERE session_id = $session_id AND origin = 'model' AND parent_run_id IS NULL ORDER BY id LIMIT 1;
@@ -0,0 +1,35 @@
1
+ import type { Db } from "../core/Db.ts";
2
+ export type LogEntryWire = {
3
+ id: number;
4
+ run_id: number;
5
+ loop_id: number;
6
+ loop_seq: number;
7
+ turn_id: number;
8
+ turn_seq: number;
9
+ sequence: number;
10
+ at: string;
11
+ origin: string;
12
+ op: string;
13
+ suffix: string;
14
+ signal: unknown;
15
+ scheme: string | null;
16
+ username: string | null;
17
+ password: string | null;
18
+ hostname: string | null;
19
+ port: number | null;
20
+ pathname: string | null;
21
+ params: unknown;
22
+ fragment: string | null;
23
+ lineMarker: unknown;
24
+ tx: unknown;
25
+ mimetype_tx: string;
26
+ rx: unknown;
27
+ mimetype_rx: string;
28
+ status_rx: number;
29
+ tokens: number;
30
+ };
31
+ export default class LogEntry {
32
+ #private;
33
+ static fetchLogEntry(db: Db, id: number): Promise<LogEntryWire>;
34
+ }
35
+ //# sourceMappingURL=logEntry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logEntry.d.ts","sourceRoot":"","sources":["../../src/server/logEntry.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAAE,EAAc,MAAM,eAAe,CAAC;AAMpD,MAAM,MAAM,YAAY,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,OAAO,CAAC;IACpB,EAAE,EAAE,OAAO,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,OAAO,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,CAAC,OAAO,OAAO,QAAQ;;IASzB,OAAa,aAAa,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAgCpE;CACJ"}
@@ -0,0 +1,49 @@
1
+ // Hydrate a log_entries row for the wire. Re-parses JSON-encoded columns
2
+ // (signal, params, lineMarker, tx, rx) so the client receives
3
+ // structured values, not opaque strings.
4
+ export default class LogEntry {
5
+ static #parseJsonOrNull(v) {
6
+ // "" is the actionless-row sentinel for "no statement" (error/model rows store tx="");
7
+ // JSON.parse("") throws, so an empty string is no-value → null, like NULL itself.
8
+ if (v === null || v === undefined || v === "")
9
+ return null;
10
+ if (typeof v !== "string")
11
+ return v;
12
+ return JSON.parse(v);
13
+ }
14
+ static async fetchLogEntry(db, id) {
15
+ const row = await db.log_entry_by_id.get({ id });
16
+ if (row === undefined)
17
+ throw new Error(`log_entries row ${id} not found`);
18
+ return {
19
+ id: row.id,
20
+ run_id: row.run_id,
21
+ loop_id: row.loop_id,
22
+ loop_seq: row.loop_seq,
23
+ turn_id: row.turn_id,
24
+ turn_seq: row.turn_seq,
25
+ sequence: row.sequence,
26
+ at: row.at,
27
+ origin: row.origin,
28
+ op: row.op,
29
+ suffix: row.suffix,
30
+ signal: LogEntry.#parseJsonOrNull(row.signal),
31
+ scheme: row.scheme,
32
+ username: row.username,
33
+ password: row.password,
34
+ hostname: row.hostname,
35
+ port: row.port,
36
+ pathname: row.pathname,
37
+ params: LogEntry.#parseJsonOrNull(row.params),
38
+ fragment: row.fragment,
39
+ lineMarker: LogEntry.#parseJsonOrNull(row.lineMarker),
40
+ tx: LogEntry.#parseJsonOrNull(row.tx),
41
+ mimetype_tx: row.mimetype_tx,
42
+ rx: LogEntry.#parseJsonOrNull(row.rx),
43
+ mimetype_rx: row.mimetype_rx,
44
+ status_rx: row.status_rx,
45
+ tokens: row.tokens,
46
+ };
47
+ }
48
+ }
49
+ //# sourceMappingURL=logEntry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logEntry.js","sourceRoot":"","sources":["../../src/server/logEntry.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,8DAA8D;AAC9D,yCAAyC;AAsCzC,MAAM,CAAC,OAAO,OAAO,QAAQ;IACzB,MAAM,CAAC,gBAAgB,CAAC,CAAU;QAC9B,uFAAuF;QACvF,kFAAkF;QAClF,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,EAAE;YAAE,OAAO,IAAI,CAAC;QAC3D,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,OAAO,CAAC,CAAC;QACpC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;IAED,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,EAAM,EAAE,EAAU;QACzC,MAAM,GAAG,GAAG,MAAO,EAAE,CAAC,eAA8B,CAAC,GAAG,CAA0B,EAAE,EAAE,EAAE,CAAC,CAAC;QAC1F,IAAI,GAAG,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,EAAE,YAAY,CAAC,CAAC;QAC1E,OAAO;YACH,EAAE,EAAE,GAAG,CAAC,EAAY;YACpB,MAAM,EAAE,GAAG,CAAC,MAAgB;YAC5B,OAAO,EAAE,GAAG,CAAC,OAAiB;YAC9B,QAAQ,EAAE,GAAG,CAAC,QAAkB;YAChC,OAAO,EAAE,GAAG,CAAC,OAAiB;YAC9B,QAAQ,EAAE,GAAG,CAAC,QAAkB;YAChC,QAAQ,EAAE,GAAG,CAAC,QAAkB;YAChC,EAAE,EAAE,GAAG,CAAC,EAAY;YACpB,MAAM,EAAE,GAAG,CAAC,MAAgB;YAC5B,EAAE,EAAE,GAAG,CAAC,EAAY;YACpB,MAAM,EAAE,GAAG,CAAC,MAAgB;YAC5B,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC;YAC7C,MAAM,EAAE,GAAG,CAAC,MAAuB;YACnC,QAAQ,EAAE,GAAG,CAAC,QAAyB;YACvC,QAAQ,EAAE,GAAG,CAAC,QAAyB;YACvC,QAAQ,EAAE,GAAG,CAAC,QAAyB;YACvC,IAAI,EAAE,GAAG,CAAC,IAAqB;YAC/B,QAAQ,EAAE,GAAG,CAAC,QAAyB;YACvC,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC;YAC7C,QAAQ,EAAE,GAAG,CAAC,QAAyB;YACvC,UAAU,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,CAAC,UAAU,CAAC;YACrD,EAAE,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;YACrC,WAAW,EAAE,GAAG,CAAC,WAAqB;YACtC,EAAE,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,CAAC;YACrC,WAAW,EAAE,GAAG,CAAC,WAAqB;YACtC,SAAS,EAAE,GAAG,CAAC,SAAmB;YAClC,MAAM,EAAE,GAAG,CAAC,MAAgB;SAC/B,CAAC;IACN,CAAC;CACJ"}
@@ -0,0 +1,10 @@
1
+ -- Log-entry hydration for wire surfacing.
2
+
3
+ -- PREP: log_entry_by_id
4
+ -- loop_seq / turn_seq are the loop+turn ordinals (the logical coordinate clients
5
+ -- render, e.g. 01/02/03) — distinct from the loop_id/turn_id DB keys (#208).
6
+ SELECT le.*, l.sequence AS loop_seq, t.sequence AS turn_seq
7
+ FROM log_entries le
8
+ JOIN loops l ON l.id = le.loop_id
9
+ JOIN turns t ON t.id = le.turn_id
10
+ WHERE le.id = $id;
@@ -0,0 +1,6 @@
1
+ import type Engine from "../core/Engine.ts";
2
+ import type { Db } from "../core/Db.ts";
3
+ export default class LoopDocs {
4
+ static materialize(engine: Engine, db: Db, sessionId: number): Promise<void>;
5
+ }
6
+ //# sourceMappingURL=loopDocs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loopDocs.d.ts","sourceRoot":"","sources":["../../src/server/loopDocs.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAKxC,MAAM,CAAC,OAAO,OAAO,QAAQ;IACzB,OAAa,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAejF;CACJ"}
@@ -0,0 +1,22 @@
1
+ import SessionSettings from "../core/session-settings.js";
2
+ import DispatchAsPlurnk from "./dispatch-as-plurnk.js";
3
+ export default class LoopDocs {
4
+ static async materialize(engine, db, sessionId) {
5
+ const { mdDocs } = await SessionSettings.read(db, sessionId);
6
+ const docStmts = (await SessionSettings.resolveDocs(mdDocs)).map((doc) => ({
7
+ op: "EDIT", suffix: "", signal: null,
8
+ target: { kind: "url", raw: `plurnk:///${doc.entryName}`, scheme: "plurnk", username: null, password: null, hostname: null, port: null, pathname: `/${doc.entryName}`, params: {}, fragment: null },
9
+ lineMarker: null, body: doc.content, position: { line: 1, column: 1 },
10
+ }));
11
+ for (const { name, content } of await engine.docEntries(sessionId)) {
12
+ docStmts.push({
13
+ op: "EDIT", suffix: "", signal: null,
14
+ target: { kind: "url", raw: `plurnk://docs/${name}.md`, scheme: "plurnk", username: null, password: null, hostname: "docs", port: null, pathname: `/${name}.md`, params: {}, fragment: null },
15
+ lineMarker: null, body: content, position: { line: 1, column: 1 },
16
+ });
17
+ }
18
+ if (docStmts.length > 0)
19
+ await DispatchAsPlurnk.dispatch(engine, db, sessionId, docStmts);
20
+ }
21
+ }
22
+ //# sourceMappingURL=loopDocs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loopDocs.js","sourceRoot":"","sources":["../../src/server/loopDocs.ts"],"names":[],"mappings":"AASA,OAAO,eAAe,MAAM,6BAA6B,CAAC;AAC1D,OAAO,gBAAgB,MAAM,yBAAyB,CAAC;AAEvD,MAAM,CAAC,OAAO,OAAO,QAAQ;IACzB,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,MAAc,EAAE,EAAM,EAAE,SAAiB;QAC9D,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QAC7D,MAAM,QAAQ,GAAoB,CAAC,MAAM,eAAe,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACxF,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI;YACpC,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,aAAa,GAAG,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,GAAG,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;YACnM,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;SACxE,CAAC,CAAC,CAAC;QACJ,KAAK,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,MAAM,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACjE,QAAQ,CAAC,IAAI,CAAC;gBACV,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI;gBACpC,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,iBAAiB,IAAI,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;gBAC7L,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;aACpE,CAAC,CAAC;QACP,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,MAAM,gBAAgB,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,QAA6B,CAAC,CAAC;IACnH,CAAC;CACJ"}
@@ -0,0 +1,6 @@
1
+ import type Engine from "../core/Engine.ts";
2
+ import type { Db } from "../core/Db.ts";
3
+ export default class NoProposals {
4
+ static attachNoProposals(engine: Engine, _db: Db): void;
5
+ }
6
+ //# sourceMappingURL=noProposals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"noProposals.d.ts","sourceRoot":"","sources":["../../src/server/noProposals.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAE5C,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAExC,MAAM,CAAC,OAAO,OAAO,WAAW;IAC5B,MAAM,CAAC,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,GAAG,IAAI,CAUtD;CACJ"}
@@ -0,0 +1,37 @@
1
+ // Server-side noProposals listener — the exact inverse of yolo.ts. When a
2
+ // loop's persisted flags.noProposals === true, proposals auto-REJECT
3
+ // in-process, mirroring server-YOLO's auto-ACCEPT. No client roundtrip; no
4
+ // human review.
5
+ //
6
+ // Invisibility is the whole point. The model sees only the ordinary
7
+ // post-resolution result — identical to a human declining the proposal or a
8
+ // client's no_tty_review reject. The `outcome` reason is forensics-only,
9
+ // never in the rx (see ProposalResolution), so a reject under noProposals is
10
+ // indistinguishable, to the model, from any other reject. How a proposal is
11
+ // handled — manual review, client YOLO, server YOLO, noProposals — leaves no
12
+ // fingerprint in the model's experience.
13
+ //
14
+ // Use case: a client with no review channel (no TTY — piped, scripted,
15
+ // redirected) sets noProposals so side-effecting ops fail closed WITHOUT a
16
+ // client roundtrip per proposal. The client, which set the flag, owns any
17
+ // end-user "edits were blocked, no review channel" messaging; the model is
18
+ // mode-blind.
19
+ //
20
+ // yolo wins if both are (nonsensically) set — the explicit auto-accept
21
+ // opt-in takes precedence over the auto-reject.
22
+ export default class NoProposals {
23
+ static attachNoProposals(engine, _db) {
24
+ engine.onProposalPending((event) => {
25
+ if (event.flags.yolo || !event.flags.noProposals)
26
+ return;
27
+ try {
28
+ engine.resolveProposal(event.logEntryId, { decision: "reject", outcome: "no_review_channel" });
29
+ }
30
+ catch {
31
+ // Errors here don't abort dispatch — the proposal stays
32
+ // pending and falls through to the RPC / timeout path.
33
+ }
34
+ });
35
+ }
36
+ }
37
+ //# sourceMappingURL=noProposals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"noProposals.js","sourceRoot":"","sources":["../../src/server/noProposals.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,qEAAqE;AACrE,2EAA2E;AAC3E,gBAAgB;AAChB,EAAE;AACF,oEAAoE;AACpE,4EAA4E;AAC5E,yEAAyE;AACzE,6EAA6E;AAC7E,4EAA4E;AAC5E,6EAA6E;AAC7E,yCAAyC;AACzC,EAAE;AACF,uEAAuE;AACvE,2EAA2E;AAC3E,0EAA0E;AAC1E,2EAA2E;AAC3E,cAAc;AACd,EAAE;AACF,uEAAuE;AACvE,gDAAgD;AAMhD,MAAM,CAAC,OAAO,OAAO,WAAW;IAC5B,MAAM,CAAC,iBAAiB,CAAC,MAAc,EAAE,GAAO;QAC5C,MAAM,CAAC,iBAAiB,CAAC,CAAC,KAA2B,EAAE,EAAE;YACrD,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW;gBAAE,OAAO;YACzD,IAAI,CAAC;gBACD,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC;YACnG,CAAC;YAAC,MAAM,CAAC;gBACL,wDAAwD;gBACxD,uDAAuD;YAC3D,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC;CACJ"}
@@ -0,0 +1,21 @@
1
+ -- entry.read RPC queries. SPEC §methods.
2
+
3
+ -- PREP: entry_read_lookup
4
+ SELECT id, scope, session_id, scheme, pathname
5
+ FROM entries
6
+ WHERE session_id = $session_id AND scheme = $scheme AND pathname = $pathname;
7
+
8
+ -- PREP: entry_read_channels
9
+ SELECT name, content, length(content) AS contentLength, mimetype, tokens, state
10
+ FROM entry_channels
11
+ WHERE entry_id = $entry_id;
12
+
13
+ -- entry.read({channel, offset}) — incremental delta read for streaming viewers
14
+ -- (#192): substr ships only content from $offset (chars — the unit contentLength
15
+ -- counts), and contentLength is the full length so the client's next offset
16
+ -- survives growth between a stream/event and this read. $offset=0 → whole channel;
17
+ -- $offset past the end → '' (caught up). SQLite substr is 1-indexed → $offset + 1.
18
+ -- PREP: entry_read_channel_slice
19
+ SELECT name, substr(content, $offset + 1) AS content, length(content) AS contentLength, mimetype, tokens, state
20
+ FROM entry_channels
21
+ WHERE entry_id = $entry_id AND name = $channel;
@@ -0,0 +1,21 @@
1
+ -- log.read RPC query. SPEC §methods.
2
+ -- Static query with IS-NULL guards on optional filters. The loops/turns joins
3
+ -- resolve the DISPLAY coordinate (loop_seq/turn_seq/op-sequence) so a client can
4
+ -- target one entry by its `L/T/S` coordinate (plurnk-service#271) instead of
5
+ -- fetching a run and matching client-side. INNER JOINs are safe: log_entries
6
+ -- carries run_id/loop_id/turn_id NOT NULL, so no row is dropped; the coordinate
7
+ -- guards are inert when their param is NULL (identical to the id-only filters).
8
+
9
+ -- PREP: log_read_recent_ids
10
+ SELECT le.id FROM log_entries le
11
+ JOIN turns t ON t.id = le.turn_id
12
+ JOIN loops l ON l.id = t.loop_id
13
+ WHERE le.run_id = $run_id
14
+ AND ($loop_id IS NULL OR le.loop_id = $loop_id)
15
+ AND ($turn_id IS NULL OR le.turn_id = $turn_id)
16
+ AND ($since_id IS NULL OR le.id > $since_id)
17
+ AND ($loop_seq IS NULL OR l.sequence = $loop_seq)
18
+ AND ($turn_seq IS NULL OR t.sequence = $turn_seq)
19
+ AND ($sequence IS NULL OR le.sequence = $sequence)
20
+ ORDER BY le.at DESC
21
+ LIMIT $limit;
@@ -0,0 +1,9 @@
1
+ -- loop.run RPC queries. SPEC §rpc.
2
+
3
+ -- PREP: loop_run_next_sequence
4
+ SELECT COALESCE(MAX(sequence), 0) + 1 AS next FROM loops WHERE run_id = $run_id;
5
+
6
+ -- PREP: loop_run_insert_loop
7
+ INSERT INTO loops (run_id, sequence, status, prompt)
8
+ VALUES ($run_id, $sequence, 102, $prompt)
9
+ RETURNING id;
@@ -0,0 +1,13 @@
1
+ -- PREP: proposal_list_pending
2
+ -- §proposal-list — every stopped-world proposal in the session (state='proposed'): file edits,
3
+ -- MCP auths, [300] questions. The ruling's mandatory companion ({§proposal-timeout-cancels}
4
+ -- ships indefinite): a world that can stay stopped for days MUST be discoverable by a
5
+ -- reconnecting client, or granted patience reads as a mystery hang.
6
+ SELECT le.id AS logEntryId, le.run_id AS runId, le.loop_id AS loopId, le.turn_id AS turnId,
7
+ le.op, le.suffix, le.scheme, le.pathname, le.tx, le.attrs, le.at,
8
+ l.flags AS loop_flags
9
+ FROM log_entries le
10
+ JOIN runs r ON r.id = le.run_id
11
+ JOIN loops l ON l.id = le.loop_id
12
+ WHERE r.session_id = $session_id AND le.state = 'proposed'
13
+ ORDER BY le.id;
@@ -0,0 +1,14 @@
1
+ export type Versions = {
2
+ service: {
3
+ installed: string;
4
+ latest?: string;
5
+ };
6
+ client: {
7
+ latest?: string;
8
+ };
9
+ };
10
+ export default class VersionInfo {
11
+ #private;
12
+ static get(): Promise<Versions>;
13
+ }
14
+ //# sourceMappingURL=version-info.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-info.d.ts","sourceRoot":"","sources":["../../src/server/version-info.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,QAAQ,GAAG;IAAE,OAAO,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAAC,MAAM,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAExG,MAAM,CAAC,OAAO,OAAO,WAAW;;IAQ5B,OAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC,CAQpC;CA0CJ"}
@@ -0,0 +1,69 @@
1
+ // #235 — version advertising for the client's update notifier. The daemon is the
2
+ // long-lived, already-network-capable process, so it owns the registry poll: a one-shot
3
+ // CLI does zero registry IO and just renders what `discover` hands it. We self-report the
4
+ // installed version and poll npm for `latest` of the service + client packages — CACHED
5
+ // (TTL) and BEST-EFFORT (offline / registry-down omits `latest`; never blocks `discover`).
6
+ import { readFile } from "node:fs/promises";
7
+ import { fileURLToPath } from "node:url";
8
+ import { dirname, resolve, join } from "node:path";
9
+ const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
10
+ const SERVICE_PKG = "@plurnk/plurnk-service";
11
+ const CLIENT_PKG = "@plurnk/plurnk";
12
+ export default class VersionInfo {
13
+ static #installed;
14
+ static #cache = { service: undefined, client: undefined, at: 0 };
15
+ static #inflight = false;
16
+ // `discover` rides this. Returns immediately with whatever is cached; a stale/cold
17
+ // cache triggers a background refresh (never awaited), so the call never blocks on the
18
+ // network. `installed` is the daemon's honest self-report; `latest` is best-effort.
19
+ static async get() {
20
+ const installed = await VersionInfo.#installedVersion();
21
+ VersionInfo.#maybeRefresh();
22
+ const { service, client } = VersionInfo.#cache;
23
+ return {
24
+ service: service === undefined ? { installed } : { installed, latest: service },
25
+ client: client === undefined ? {} : { latest: client },
26
+ };
27
+ }
28
+ static async #installedVersion() {
29
+ if (VersionInfo.#installed === undefined) {
30
+ const raw = await readFile(join(PACKAGE_ROOT, "package.json"), "utf8");
31
+ VersionInfo.#installed = JSON.parse(raw).version;
32
+ }
33
+ return VersionInfo.#installed;
34
+ }
35
+ static #maybeRefresh() {
36
+ const ttl = VersionInfo.#envMs("PLURNK_SERVICE_VERSION_POLL_TTL", 0);
37
+ const timeout = VersionInfo.#envMs("PLURNK_PROVIDERS_FETCH_TIMEOUT", 1);
38
+ if (VersionInfo.#inflight || Date.now() - VersionInfo.#cache.at < ttl)
39
+ return;
40
+ VersionInfo.#inflight = true;
41
+ void VersionInfo.#refresh(timeout).finally(() => { VersionInfo.#inflight = false; });
42
+ }
43
+ // No code fallback hides a magic number — the law-file (.env.defaults) carries it.
44
+ static #envMs(name, min) {
45
+ const raw = process.env[name];
46
+ const n = raw === undefined ? Number.NaN : Number.parseInt(raw, 10);
47
+ if (!Number.isFinite(n) || n < min)
48
+ throw new Error(`${name} must be an integer >= ${min} (ms), got ${JSON.stringify(raw)}`);
49
+ return n;
50
+ }
51
+ static async #refresh(timeout) {
52
+ const [service, client] = await Promise.all([VersionInfo.#poll(SERVICE_PKG, timeout), VersionInfo.#poll(CLIENT_PKG, timeout)]);
53
+ // Keep the prior cached value on a failed poll (don't clobber a good `latest` with undefined).
54
+ VersionInfo.#cache = { service: service ?? VersionInfo.#cache.service, client: client ?? VersionInfo.#cache.client, at: Date.now() };
55
+ }
56
+ static async #poll(pkg, timeout) {
57
+ try {
58
+ const res = await fetch(`https://registry.npmjs.org/${pkg.replace("/", "%2F")}/latest`, { signal: AbortSignal.timeout(timeout) });
59
+ if (!res.ok)
60
+ return undefined;
61
+ const body = (await res.json());
62
+ return typeof body.version === "string" ? body.version : undefined;
63
+ }
64
+ catch {
65
+ return undefined; // best-effort: offline / registry-down / abort → omit `latest`
66
+ }
67
+ }
68
+ }
69
+ //# sourceMappingURL=version-info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-info.js","sourceRoot":"","sources":["../../src/server/version-info.ts"],"names":[],"mappings":"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"}