@rho-workspace/rho 0.5.3 → 0.5.5

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 (277) hide show
  1. package/README.md +24 -5
  2. package/dist/browser-access.js +3 -2
  3. package/dist/capabilities.d.ts +29 -2
  4. package/dist/capabilities.js +79 -2
  5. package/dist/cli.js +237 -99
  6. package/dist/contract.generated.d.ts +441 -16
  7. package/dist/contract.generated.js +1 -1
  8. package/dist/contracts/owners.generated.js +459 -10
  9. package/dist/conversation-presentation.d.ts +3 -1
  10. package/dist/conversation-presentation.js +16 -6
  11. package/dist/conversations.d.ts +10 -6
  12. package/dist/conversations.js +17 -13
  13. package/dist/discovery.d.ts +1 -0
  14. package/dist/discovery.js +3 -3
  15. package/dist/extension-contract.d.ts +99 -0
  16. package/dist/extension-contract.js +52 -0
  17. package/dist/extension-directory.d.ts +9 -0
  18. package/dist/extension-directory.js +11 -0
  19. package/dist/extension-worker.d.ts +1 -0
  20. package/dist/extension-worker.js +36 -0
  21. package/dist/extensions.d.ts +157 -0
  22. package/dist/extensions.js +349 -0
  23. package/dist/installs.d.ts +11 -0
  24. package/dist/installs.js +179 -0
  25. package/dist/plugin-cli.d.ts +1 -0
  26. package/dist/plugin-cli.js +139 -0
  27. package/dist/plugin-inventory.json +18 -0
  28. package/dist/plugins.d.ts +3 -3
  29. package/dist/project-notes.js +2 -0
  30. package/dist/project-work.d.ts +3 -1
  31. package/dist/project-work.js +15 -2
  32. package/dist/protocol.d.ts +7 -0
  33. package/dist/protocol.js +11 -7
  34. package/dist/screen-check-skill.d.ts +2 -0
  35. package/dist/screen-check-skill.js +39 -0
  36. package/dist/server.d.ts +6 -1
  37. package/dist/server.js +105 -15
  38. package/dist/web/.vite/manifest.json +65 -65
  39. package/dist/web/assets/{canvas-BXhC8RDZ.js → canvas-D8rDdfDz.js} +1 -1
  40. package/dist/web/assets/choices-b0XhrGQV.js +1 -0
  41. package/dist/web/assets/{console-e1P5qYQ5.js → console-BSjLGe0T.js} +1 -1
  42. package/dist/web/assets/{dist-Dd3iAGFy.js → dist-Buk0lwzI.js} +2 -2
  43. package/dist/web/assets/dist-Cw8hRIlT.js +1 -0
  44. package/dist/web/assets/dist-Tzoe_zm-.js +3 -0
  45. package/dist/web/assets/{dist-DEorbOW0.js → dist-foH9IKc6.js} +1 -1
  46. package/dist/web/assets/explore-in-BVUy3ZW_.js +1 -0
  47. package/dist/web/assets/graph-1OdIJ9l7.js +2 -0
  48. package/dist/web/assets/index-CsC3sTRq.css +1 -0
  49. package/dist/web/assets/{index-BYuKpyoi.js → index-CxmItXqa.js} +220 -121
  50. package/dist/web/assets/{notes-meaning-B3HFbh84.js → notes-meaning-pVbbQUGP.js} +1 -1
  51. package/dist/web/assets/overview-B9UtVJ32.js +6 -0
  52. package/dist/web/assets/preview-CksD_5KS.js +1 -0
  53. package/dist/web/assets/{review-BVh9jWMB.js → review-CMxQlQ-C.js} +1 -1
  54. package/dist/web/assets/{skills-DPaEYkln.js → skills-BFNSyrnD.js} +1 -1
  55. package/dist/web/assets/{skills-work-dvjfy_tu.js → skills-work-BGPSnF_I.js} +1 -1
  56. package/dist/web/assets/{studio-process-BYm8mjRJ.js → studio-process-CsRoTHOh.js} +2 -2
  57. package/dist/web/assets/{timeline-events-CDZ7wiJX.js → timeline-events-BbuuFWHV.js} +1 -1
  58. package/dist/web/assets/{work-turns-BeCt303c.js → work-turns-BvJlIMmA.js} +1 -1
  59. package/dist/web/assets/workspace-CWlkjLNx.js +5 -0
  60. package/dist/web/composition.json +80 -80
  61. package/dist/web/index.html +3 -3
  62. package/dist/web/renderer.json +1 -1
  63. package/dist/web-assets.d.ts +2 -1
  64. package/dist/web-assets.js +3 -2
  65. package/dist/work-contract.js +2 -2
  66. package/docs/FRONTEND.md +30 -14
  67. package/docs/HEADLESS.md +60 -14
  68. package/docs/PLUGIN-AUTHORING.md +4 -0
  69. package/docs/THIRD-PARTY-PLUGINS.md +190 -0
  70. package/example/pa14-qs/.rho/rho/conversations/c-67f77cfebaba2cea.json +1 -1
  71. package/example/pa14-qs/.rho/rho/conversations/c-91aa2e46b1ac1a6c.json +1 -1
  72. package/example/pa14-qs/.rho/rho/conversations/c-fa24dfd80dfe4bcb.json +1 -1
  73. package/node_modules/@hono/node-server/dist/index.js +11 -0
  74. package/node_modules/@hono/node-server/dist/index.mjs +11 -0
  75. package/node_modules/@hono/node-server/dist/listener.js +11 -0
  76. package/node_modules/@hono/node-server/dist/listener.mjs +11 -0
  77. package/node_modules/@hono/node-server/dist/request.js +11 -0
  78. package/node_modules/@hono/node-server/dist/request.mjs +11 -0
  79. package/node_modules/@hono/node-server/dist/server.js +11 -0
  80. package/node_modules/@hono/node-server/dist/server.mjs +11 -0
  81. package/node_modules/@hono/node-server/dist/vercel.js +11 -0
  82. package/node_modules/@hono/node-server/dist/vercel.mjs +11 -0
  83. package/node_modules/@hono/node-server/package.json +1 -1
  84. package/node_modules/@rho-workspace/plugin-agent/README.md +42 -1
  85. package/node_modules/@rho-workspace/plugin-agent/dist/acp-conversation.js +14 -3
  86. package/node_modules/@rho-workspace/plugin-agent/dist/activity-normalize.d.ts +1 -0
  87. package/node_modules/@rho-workspace/plugin-agent/dist/activity-normalize.js +2 -2
  88. package/node_modules/@rho-workspace/plugin-agent/dist/conversation.d.ts +1 -0
  89. package/node_modules/@rho-workspace/plugin-agent/dist/conversation.js +1 -0
  90. package/node_modules/@rho-workspace/plugin-agent/dist/dsh-session.d.ts +6 -0
  91. package/node_modules/@rho-workspace/plugin-agent/dist/dsh-session.js +174 -0
  92. package/node_modules/@rho-workspace/plugin-agent/dist/external-session-contract.d.ts +82 -0
  93. package/node_modules/@rho-workspace/plugin-agent/dist/external-session-contract.js +15 -0
  94. package/node_modules/@rho-workspace/plugin-agent/dist/external-session.d.ts +73 -0
  95. package/node_modules/@rho-workspace/plugin-agent/dist/external-session.js +190 -0
  96. package/node_modules/@rho-workspace/plugin-agent/dist/generic-acp.d.ts +11 -0
  97. package/node_modules/@rho-workspace/plugin-agent/dist/generic-acp.js +7 -0
  98. package/node_modules/@rho-workspace/plugin-agent/dist/index.d.ts +373 -0
  99. package/node_modules/@rho-workspace/plugin-agent/dist/index.js +1 -0
  100. package/node_modules/@rho-workspace/plugin-agent/dist/mcp.js +5 -1
  101. package/node_modules/@rho-workspace/plugin-agent/dist/operations.d.ts +33 -0
  102. package/node_modules/@rho-workspace/plugin-agent/dist/operations.js +3 -0
  103. package/node_modules/@rho-workspace/plugin-agent/dist/presentation.d.ts +14 -0
  104. package/node_modules/@rho-workspace/plugin-agent/dist/presentation.js +2 -0
  105. package/node_modules/@rho-workspace/plugin-agent/dist/ui-external-session.d.ts +15 -0
  106. package/node_modules/@rho-workspace/plugin-agent/dist/ui-external-session.js +37 -0
  107. package/node_modules/@rho-workspace/plugin-agent/package.json +5 -1
  108. package/node_modules/@rho-workspace/plugin-annotations/package.json +1 -1
  109. package/node_modules/@rho-workspace/plugin-documents/README.md +4 -0
  110. package/node_modules/@rho-workspace/plugin-documents/dist/index.d.ts +3 -0
  111. package/node_modules/@rho-workspace/plugin-documents/dist/index.js +1 -1
  112. package/node_modules/@rho-workspace/plugin-documents/package.json +1 -1
  113. package/node_modules/@rho-workspace/plugin-kernel/README.md +71 -10
  114. package/node_modules/@rho-workspace/plugin-kernel/dist/code.d.ts +2 -0
  115. package/node_modules/@rho-workspace/plugin-kernel/dist/code.js +4 -1
  116. package/node_modules/@rho-workspace/plugin-kernel/dist/contract.js +5 -0
  117. package/node_modules/@rho-workspace/plugin-kernel/dist/index.d.ts +7 -0
  118. package/node_modules/@rho-workspace/plugin-kernel/dist/index.js +55 -8
  119. package/node_modules/@rho-workspace/plugin-kernel/dist/lineage.d.ts +9 -6
  120. package/node_modules/@rho-workspace/plugin-kernel/dist/lineage.js +18 -41
  121. package/node_modules/@rho-workspace/plugin-kernel/dist/operations.js +5 -2
  122. package/node_modules/@rho-workspace/plugin-kernel/dist/script-flow.d.ts +39 -0
  123. package/node_modules/@rho-workspace/plugin-kernel/dist/script-flow.js +661 -0
  124. package/node_modules/@rho-workspace/plugin-kernel/dist/ui-base.d.ts +3 -0
  125. package/node_modules/@rho-workspace/plugin-kernel/dist/ui-base.js +10 -0
  126. package/node_modules/@rho-workspace/plugin-kernel/dist/ui-flow.d.ts +38 -4
  127. package/node_modules/@rho-workspace/plugin-kernel/dist/ui-flow.js +194 -97
  128. package/node_modules/@rho-workspace/plugin-kernel/dist/ui-notebook-work.js +1 -2
  129. package/node_modules/@rho-workspace/plugin-kernel/dist/ui-notebook.d.ts +10 -2
  130. package/node_modules/@rho-workspace/plugin-kernel/dist/ui-notebook.js +79 -18
  131. package/node_modules/@rho-workspace/plugin-kernel/dist/ui-styles.js +115 -45
  132. package/node_modules/@rho-workspace/plugin-kernel/dist/ui.d.ts +1 -1
  133. package/node_modules/@rho-workspace/plugin-kernel/dist/ui.js +1 -1
  134. package/node_modules/@rho-workspace/plugin-kernel/dist/value-graph.d.ts +63 -0
  135. package/node_modules/@rho-workspace/plugin-kernel/dist/value-graph.js +344 -0
  136. package/node_modules/@rho-workspace/plugin-kernel/package.json +1 -1
  137. package/node_modules/@rho-workspace/plugin-kernel/runners/runner.R +6 -3
  138. package/node_modules/@rho-workspace/plugin-kernel/runners/runner.py +6 -3
  139. package/node_modules/express-rate-limit/dist/index.cjs +1 -1
  140. package/node_modules/express-rate-limit/dist/index.mjs +1 -1
  141. package/node_modules/express-rate-limit/package.json +1 -1
  142. package/node_modules/ip-address/dist/ipv6.js +1 -1
  143. package/node_modules/ip-address/package.json +1 -1
  144. package/node_modules/playwright-core/LICENSE +202 -0
  145. package/node_modules/playwright-core/NOTICE +5 -0
  146. package/node_modules/playwright-core/ThirdPartyNotices.txt +13 -0
  147. package/node_modules/playwright-core/bin/install_media_pack.ps1 +5 -0
  148. package/node_modules/playwright-core/bin/install_webkit_wsl.ps1 +33 -0
  149. package/node_modules/playwright-core/bin/reinstall_chrome_beta_linux.sh +42 -0
  150. package/node_modules/playwright-core/bin/reinstall_chrome_beta_mac.sh +13 -0
  151. package/node_modules/playwright-core/bin/reinstall_chrome_beta_win.ps1 +24 -0
  152. package/node_modules/playwright-core/bin/reinstall_chrome_stable_linux.sh +42 -0
  153. package/node_modules/playwright-core/bin/reinstall_chrome_stable_mac.sh +12 -0
  154. package/node_modules/playwright-core/bin/reinstall_chrome_stable_win.ps1 +24 -0
  155. package/node_modules/playwright-core/bin/reinstall_msedge_beta_linux.sh +48 -0
  156. package/node_modules/playwright-core/bin/reinstall_msedge_beta_mac.sh +11 -0
  157. package/node_modules/playwright-core/bin/reinstall_msedge_beta_win.ps1 +23 -0
  158. package/node_modules/playwright-core/bin/reinstall_msedge_dev_linux.sh +48 -0
  159. package/node_modules/playwright-core/bin/reinstall_msedge_dev_mac.sh +11 -0
  160. package/node_modules/playwright-core/bin/reinstall_msedge_dev_win.ps1 +23 -0
  161. package/node_modules/playwright-core/bin/reinstall_msedge_stable_linux.sh +48 -0
  162. package/node_modules/playwright-core/bin/reinstall_msedge_stable_mac.sh +11 -0
  163. package/node_modules/playwright-core/bin/reinstall_msedge_stable_win.ps1 +24 -0
  164. package/node_modules/playwright-core/browsers.json +52 -0
  165. package/node_modules/playwright-core/cli.js +22 -0
  166. package/node_modules/playwright-core/index.js +17 -0
  167. package/node_modules/playwright-core/index.mjs +28 -0
  168. package/node_modules/playwright-core/lib/bootstrap.js +149 -0
  169. package/node_modules/playwright-core/lib/coreBundle.js +78041 -0
  170. package/node_modules/playwright-core/lib/entry/cliDaemon.js +5 -0
  171. package/node_modules/playwright-core/lib/entry/dashboardApp.js +3 -0
  172. package/node_modules/playwright-core/lib/entry/mcp.js +10 -0
  173. package/node_modules/playwright-core/lib/entry/oopBrowserDownload.js +3 -0
  174. package/node_modules/playwright-core/lib/package.js +50 -0
  175. package/node_modules/playwright-core/lib/server/chromium/appIcon.png +0 -0
  176. package/node_modules/playwright-core/lib/server/electron/loader.js +123 -0
  177. package/node_modules/playwright-core/lib/serverRegistry.js +1939 -0
  178. package/node_modules/playwright-core/lib/serverRegistry.js.LICENSE +65 -0
  179. package/node_modules/playwright-core/lib/tools/cli-client/channelSessions.js +141 -0
  180. package/node_modules/playwright-core/lib/tools/cli-client/cli.js +7 -0
  181. package/node_modules/playwright-core/lib/tools/cli-client/help.json +808 -0
  182. package/node_modules/playwright-core/lib/tools/cli-client/minimist.js +128 -0
  183. package/node_modules/playwright-core/lib/tools/cli-client/output.js +352 -0
  184. package/node_modules/playwright-core/lib/tools/cli-client/program.js +422 -0
  185. package/node_modules/playwright-core/lib/tools/cli-client/registry.js +180 -0
  186. package/node_modules/playwright-core/lib/tools/cli-client/session.js +261 -0
  187. package/node_modules/playwright-core/lib/tools/dashboard/appIcon.png +0 -0
  188. package/node_modules/playwright-core/lib/tools/utils/extension.js +112 -0
  189. package/node_modules/playwright-core/lib/tools/utils/socketConnection.js +108 -0
  190. package/node_modules/playwright-core/lib/utilsBundle.js +86078 -0
  191. package/node_modules/playwright-core/lib/utilsBundle.js.LICENSE +1890 -0
  192. package/node_modules/playwright-core/lib/vite/dashboard/assets/codeMirrorModule--QdMvsKi.css +1 -0
  193. package/node_modules/playwright-core/lib/vite/dashboard/assets/codeMirrorModule-CQ8RZGBm.js +32 -0
  194. package/node_modules/playwright-core/lib/vite/dashboard/assets/codicon-DCmgc-ay.ttf +0 -0
  195. package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-1bWoP6pv.svg +1 -0
  196. package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-beta-k3eOH_eK.svg +1 -0
  197. package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-nightly-Cp5nfeDT.svg +1 -0
  198. package/node_modules/playwright-core/lib/vite/dashboard/assets/index-AwgwcYie.css +1 -0
  199. package/node_modules/playwright-core/lib/vite/dashboard/assets/index-hRvO4yU2.js +12 -0
  200. package/node_modules/playwright-core/lib/vite/dashboard/assets/safari-na3_-uQk.svg +1 -0
  201. package/node_modules/playwright-core/lib/vite/dashboard/index.html +29 -0
  202. package/node_modules/playwright-core/lib/vite/dashboard/playwright-logo.svg +24 -0
  203. package/node_modules/playwright-core/lib/vite/htmlReport/index.html +16 -0
  204. package/node_modules/playwright-core/lib/vite/htmlReport/report.css +2 -0
  205. package/node_modules/playwright-core/lib/vite/htmlReport/report.js +32 -0
  206. package/node_modules/playwright-core/lib/vite/recorder/assets/codeMirrorModule--QdMvsKi.css +1 -0
  207. package/node_modules/playwright-core/lib/vite/recorder/assets/codeMirrorModule-DK72OMRi.js +32 -0
  208. package/node_modules/playwright-core/lib/vite/recorder/assets/codicon-DCmgc-ay.ttf +0 -0
  209. package/node_modules/playwright-core/lib/vite/recorder/assets/index-BZpYJZ-P.css +1 -0
  210. package/node_modules/playwright-core/lib/vite/recorder/assets/index-Cn0mmDuv.js +129 -0
  211. package/node_modules/playwright-core/lib/vite/recorder/index.html +29 -0
  212. package/node_modules/playwright-core/lib/vite/recorder/playwright-logo.svg +9 -0
  213. package/node_modules/playwright-core/lib/vite/traceViewer/assets/codeMirrorModule-BEB2e8M3.js +32 -0
  214. package/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-D-g2vrvf.js +184 -0
  215. package/node_modules/playwright-core/lib/vite/traceViewer/assets/urlMatch-L3liM589.js +1 -0
  216. package/node_modules/playwright-core/lib/vite/traceViewer/assets/xtermModule-B794rD2Z.js +7 -0
  217. package/node_modules/playwright-core/lib/vite/traceViewer/codeMirrorModule.-QdMvsKi.css +1 -0
  218. package/node_modules/playwright-core/lib/vite/traceViewer/codicon.DCmgc-ay.ttf +0 -0
  219. package/node_modules/playwright-core/lib/vite/traceViewer/defaultSettingsView.C8BeHuxd.css +1 -0
  220. package/node_modules/playwright-core/lib/vite/traceViewer/index.B_TqY17P.css +1 -0
  221. package/node_modules/playwright-core/lib/vite/traceViewer/index.html +44 -0
  222. package/node_modules/playwright-core/lib/vite/traceViewer/index.oNry3Hjv.js +1 -0
  223. package/node_modules/playwright-core/lib/vite/traceViewer/manifest.webmanifest +16 -0
  224. package/node_modules/playwright-core/lib/vite/traceViewer/playwright-logo.svg +9 -0
  225. package/node_modules/playwright-core/lib/vite/traceViewer/snapshot.B_Jk1wbt.js +1 -0
  226. package/node_modules/playwright-core/lib/vite/traceViewer/snapshot.html +10 -0
  227. package/node_modules/playwright-core/lib/vite/traceViewer/sw.bundle.js +4 -0
  228. package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CYwC_gH1.js +5 -0
  229. package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CyMfwkXJ.css +1 -0
  230. package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +18 -0
  231. package/node_modules/playwright-core/lib/vite/traceViewer/xtermModule.kHJ-D0s7.css +1 -0
  232. package/node_modules/playwright-core/lib/webp_codec.LICENSE +173 -0
  233. package/node_modules/playwright-core/lib/webp_codec.wasm +0 -0
  234. package/node_modules/playwright-core/lib/xdg-open +1267 -0
  235. package/node_modules/playwright-core/package.json +34 -0
  236. package/package.json +13 -7
  237. package/protocol/index.json +75 -21
  238. package/protocol/operations/agent.sessions.list.json +100 -0
  239. package/protocol/operations/agent.sessions.read.json +266 -0
  240. package/protocol/operations/conversation.settings.check.json +147 -4
  241. package/protocol/operations/conversation.settings.read.json +145 -3
  242. package/protocol/operations/conversation.settings.update.json +166 -4
  243. package/protocol/operations/conversation.start.json +2 -1
  244. package/protocol/operations/extension.call.json +132 -0
  245. package/protocol/operations/extension.content.json +78 -0
  246. package/protocol/operations/extension.describe.json +195 -0
  247. package/protocol/operations/extension.install.json +198 -0
  248. package/protocol/operations/extension.list.json +123 -0
  249. package/protocol/operations/extension.manage.json +55 -0
  250. package/protocol/operations/extension.read.json +112 -0
  251. package/protocol/operations/kernel.interrupt.json +20 -0
  252. package/protocol/operations/kernel.read.json +30 -0
  253. package/protocol/operations/kernel.run.json +36 -1
  254. package/protocol/operations/kernel.stop.json +10 -0
  255. package/protocol/operations/project.work.read.json +3 -2
  256. package/protocol/operations/session.grant.json +9 -0
  257. package/scripts/browser-checks.mjs +53 -0
  258. package/scripts/screen-check.mjs +193 -0
  259. package/scripts/third-party-acceptance.mjs +77 -0
  260. package/vendor/composition.json +111 -111
  261. package/vendor/rho-workspace-plugin-agent-0.4.29.tgz +0 -0
  262. package/vendor/rho-workspace-plugin-annotations-0.5.2.tgz +0 -0
  263. package/vendor/rho-workspace-plugin-documents-0.4.11.tgz +0 -0
  264. package/vendor/rho-workspace-plugin-kernel-0.5.5.tgz +0 -0
  265. package/web/theme.css +17 -2
  266. package/dist/web/assets/choices-B-y2OYvE.js +0 -1
  267. package/dist/web/assets/dist-CBM2oq6g.js +0 -1
  268. package/dist/web/assets/dist-CH56yNDn.js +0 -3
  269. package/dist/web/assets/explore-in-muWXOGOY.js +0 -1
  270. package/dist/web/assets/graph-CK-df5lh.js +0 -2
  271. package/dist/web/assets/index-DBd77u4a.css +0 -1
  272. package/dist/web/assets/overview-D1Ev2OC_.js +0 -6
  273. package/dist/web/assets/preview-HbmQKUGY.js +0 -1
  274. package/dist/web/assets/workspace-d5Hw_ClZ.js +0 -5
  275. package/vendor/rho-workspace-plugin-agent-0.4.27.tgz +0 -0
  276. package/vendor/rho-workspace-plugin-documents-0.4.10.tgz +0 -0
  277. package/vendor/rho-workspace-plugin-kernel-0.5.2.tgz +0 -0
@@ -499,5 +499,5 @@ export const plugin = {
499
499
  description: 'Change a project file that is open in Rho through its shared buffer (document.read, document.edit, document.save), so a person\'s unsaved text, undo and saves stay intact.' }],
500
500
  hooks: [{ id: 'documents.unsaved-text', event: 'PreToolUse', matcher: 'Edit|Write|MultiEdit', entry: './claude-hook', timeoutSeconds: 10 }]
501
501
  },
502
- components: [{ id: 'rho.editor', version: '0.2.0', owner: 'rho-plugins.documents', bindings: { document: 'document' }, ui: './ui', presentation: viewPresentation, propsSchema: { type: 'object', additionalProperties: false, properties: { title: { type: 'string', minLength: 1 } }, required: ['title'] } }]
502
+ components: [{ id: 'rho.editor', version: '0.2.0', owner: 'rho-plugins.documents', bindings: { document: 'document' }, ui: './ui', presentation: viewPresentation, propsSchema: { type: 'object', additionalProperties: false, properties: { title: { type: 'string', minLength: 1 }, flow: { type: 'boolean' } }, required: ['title'] } }]
503
503
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rho-workspace/plugin-documents",
3
- "version": "0.4.10",
3
+ "version": "0.4.11",
4
4
  "type": "module",
5
5
  "description": "Rho documents plugin",
6
6
  "license": "AGPL-3.0-only",
@@ -1,6 +1,6 @@
1
1
  # Notebook
2
2
 
3
- `@rho-workspace/plugin-kernel` 0.5.2 keeps a live R session and a live Python
3
+ `@rho-workspace/plugin-kernel` 0.5.4 keeps a live R session and a live Python
4
4
  session for a project, which an Agent and the person share, on this machine or on a
5
5
  server: one the person manages with serverctl, reached through it, or one reached with
6
6
  ssh.
@@ -71,6 +71,24 @@ once; Stop raises Ctrl+Break and then ends the process tree. R there cannot open
71
71
  so its answers come on a named pipe the host serves and names in `RHO_KERNEL_ANSWERS`. R and
72
72
  Python end printed lines with `\r\n` there; a cell keeps them as `\n`, as elsewhere.
73
73
 
74
+ A session on this machine runs `Rscript` or `python3` from PATH until the project names
75
+ another program. `kernel.run` takes `interpreter`, a program in a folder of the project
76
+ such as the python of a virtual environment made there (`.venv/bin/python`): its folder
77
+ must resolve inside the project, while the file may be the link a virtual environment makes
78
+ to the Python it was made from, and it is started by that name so the environment is the
79
+ one that runs. A path outside the project is refused (`scope`), as is one that is not a
80
+ program (`not_found`) and one named for a session on a server. The project keeps the last
81
+ program named for each language, so later sessions, the person's too, start with it; one
82
+ that is gone is forgotten and the default runs. A cell naming another program than the live
83
+ session's is refused while anyone else ran cells in that session; a session in which only
84
+ the caller ran cells, none of them running, is stopped (recorded as stopped by that caller)
85
+ and started again with the program named. Each session records the program it ran as it
86
+ reported it (`sys.executable`, R's `Rscript`), relative to the project when it is in it, and
87
+ each cell keeps the program and version that ran it, since a cell outlasts its session's
88
+ record. The Notebook and the Overview name such a session by its environment's folder
89
+ (`Python 3.13.5 · .venv`). Where one session ends as the next starts, at the same instant,
90
+ the Notebook lists the end first.
91
+
74
92
  A session can run on a server. A place names the server, a folder there (absolute
75
93
  or `~/…`) and setup lines run in that folder before a session starts (`module load R`,
76
94
  `conda activate env`). Setup lines that make the folder (`mkdir -p`) run in the home folder
@@ -135,7 +153,9 @@ Limits (`kernelLimits`, each configurable): one session per language, at most 16
135
153
  cells waiting in each, cells of at most 64 KiB of code, the first 256 KiB of each
136
154
  cell's output (the rest is counted and the cell marked cut), at most 8 plots of at
137
155
  most 4 MiB per cell, 500 kept cells (the oldest finished ones go first, with their
138
- plots), 200 listed variables, 32 files named per cell (`lineageLimits`) and a 10 minute wait for a cell. A session that is not
156
+ plots), 200 listed variables, 32 strings looked at as paths per cell (those that look like a
157
+ file's path first, so a script's labels do not crowd out the file it writes last), 24 files
158
+ named per cell (`lineageLimits`) and a 10 minute wait for a cell. A session that is not
139
159
  ready within 30 seconds (90 on a server) is ended. At most 16 places are named; a check
140
160
  ends after 60 seconds, a listing after 30 with at most 500 entries from 1 MiB, a signal
141
161
  after 15, and a read of serverctl's registry after 15; files larger than 64 MiB are not copied and a copy ends after 10 minutes; the
@@ -172,14 +192,55 @@ highlighting and Markdown; without them code stays plain and a server's skill sh
172
192
  written. The views add their own styles once, in the page's color and type variables, and
173
193
  use its base controls (`text-button`, `primary`, `secondary`, `inline-error`).
174
194
 
175
- `NotebookPage` is the Notebook as a page, `NotebookWorkSection` the newest cells for an
176
- overview, `useLiveValues` the sessions' values, and `askCell` and `showOnServer` bring the
177
- Notebook to a cell and Servers to a file. The pure `./code` entry finds the statement a
178
- script line belongs to (`statementAt`, `statements`, `unfinished`), writes the code that
179
- loads a project table or runs a script (`loadCode`, `sourceCode`), and makes Data flow's
180
- steps and lanes from each cell's `defined`, `used` and `files` (`lineage`, `lanes`).
181
- The views read at most 300 cells, show 14 lines of code and 12 of output before a click,
182
- keep 64 plots read, and list the 24 newest plots in Plots.
195
+ The Notebook names, under each cell, the values it read with the cell that made the version it
196
+ read ("Read co from R 3"), and for each value it made the later cells that read that version
197
+ ("ratio read in R 6", at most three, the rest counted); a cell named there goes to that cell and
198
+ marks it for a moment. Variables names the cell that made each value as it is now and the cells
199
+ that read it; on the Notebook's page these go to the cells too.
200
+
201
+ Data flow draws how each result came about as a graph of values, one node per value or file: the
202
+ files read at the top, the results at the bottom (the files written and the plots drawn, else the
203
+ values nothing reads), the values between in rows. A node is titled with the meaning its `# means:`
204
+ comment gives, with its name beneath; a value without one shows its name alone. Functions and
205
+ constants are not drawn; each value names those it uses, and so does a value that changes another
206
+ through a helper made from it (a row mask). A bar above names the results. Choosing one draws only
207
+ what leads to it, and when every result at once would put more than six values in a row, the first
208
+ is chosen to begin with. What leads to no result is named below the graph; choosing one draws what
209
+ leads to it. Choosing a value shows what it comes from and what comes of it in two colors, and names
210
+ how it was made, where, what it comes from, uses, leads to and which results it reaches; a session's
211
+ value can be looked at, a file opened, and the cell that made a value shown in the Notebook. In a
212
+ view of its own, or narrower than 640 px, the chosen value sits above the graph and stays in view;
213
+ wider, it sits beside it. A narrow view titles each node in up to three lines of its meaning, a wide
214
+ one in two. A cell that makes at least three values offers how they came about, in the same drawing.
215
+ `ScriptFlowView` draws a script's graph for a page that follows the chosen value (`selected`,
216
+ `onSelect`) and goes to where a value is made (`onGo`), as a script's editor does. At most 80 values
217
+ are drawn at once, those nearest the results first, and the bar names 8 results until asked for the
218
+ rest (`lineageViewLimits`).
219
+
220
+ `NotebookPage` is the Notebook as a page, `NotebookWorkSection` the newest cells for an overview,
221
+ `useLiveValues` the sessions' values, and `askCell` and `showOnServer` bring the Notebook to a cell
222
+ and Servers to a file. The pure `./code` entry finds the statement a script line belongs to
223
+ (`statementAt`, `statements`, `unfinished`), writes the code that loads a project table or runs a
224
+ script (`loadCode`, `sourceCode`), follows each cell's `defined`, `used` and `files` to the cell
225
+ that made each value it read (`lineage`, `cellRelations`), and makes Data flow's graph from a
226
+ session's cells (`sessionGraph`) or a script read as text (`scriptGraph`; `scriptFlow` gives a
227
+ script's values, files and their `# means:` comments, and `markersAbove` the comments above one
228
+ statement), with a value's path (`graphPath`), its rows (`graphRows`), the lines behind and in front
229
+ of it (`graphMarks`) and the value made at a line (`graphNodeAt`). In a session, a cell that makes
230
+ its values over several statements is read statement by statement, so each value comes from what its
231
+ own statements read, and a plot from what the statement that drew it read. A value made only from
232
+ literals and calls that put literals together (`c()`, `paste0()`, `dict()`, not a `read.csv()` of a
233
+ URL) is a constant. `scriptFlow` reads a script's values from its text alone, R or Python, in the
234
+ same shape: each top-level statement makes the values it assigns outside its functions, reads the
235
+ script's values it mentions (not what a function keeps for itself, a field after `$` or `.`, an
236
+ argument's name, the columns in `aes()`, `vars()` or a formula, or an import) and reads or writes
237
+ the files its strings name as the call they are given to does (`read.csv`, `write.csv`, `ggsave`,
238
+ `to_csv`, `open(…, "w")`, or a value holding the path). A statement that changes only what the step
239
+ before made, or makes something from nothing after a step that did, joins that step; one that makes
240
+ and writes nothing is counted, with the values it reads, and not drawn. Nothing runs, so names built
241
+ at run time and paths pasted from parts are not seen. A script over 512 KiB is not read and at most
242
+ 150 steps are drawn (`scriptFlowLimits`). The views read at most 300 cells, show 14 lines of code
243
+ and 12 of output before a click, keep 64 plots read, and list the 24 newest plots in Plots.
183
244
 
184
245
  ```sh
185
246
  npm run build
@@ -1,3 +1,5 @@
1
1
  export * from './statements.js';
2
2
  export * from './explore-code.js';
3
3
  export * from './lineage.js';
4
+ export * from './script-flow.js';
5
+ export * from './value-graph.js';
@@ -1,6 +1,9 @@
1
1
  // What the sessions know about code, for any page that hands code to them: the whole statement a
2
2
  // line belongs to, the code that loads a project table or runs a script, and how the values of a
3
- // session were made. Pure functions; nothing here runs code or reads the project.
3
+ // session, or of a script read as text, were made. Pure functions; nothing here runs code or reads
4
+ // the project.
4
5
  export * from './statements.js';
5
6
  export * from './explore-code.js';
6
7
  export * from './lineage.js';
8
+ export * from './script-flow.js';
9
+ export * from './value-graph.js';
@@ -68,6 +68,9 @@ export const sessionSchema = obj({
68
68
  cells: { type: 'integer', minimum: 0 },
69
69
  // Where it ran (null: this machine) and the machine's own name. Sessions recorded before have neither.
70
70
  place: maybe(sessionPlaceSchema), host: maybe({ type: 'string' }),
71
+ // The program it ran, as the session reported it: relative to the project when it is in it
72
+ // (.venv/bin/python). Sessions recorded before have none.
73
+ program: maybe({ type: 'string' }),
71
74
  }, ['sessionId', 'language', 'state', 'version', 'pid', 'startedAt', 'startedBy', 'endedAt', 'ending', 'stop', 'problem', 'variables', 'variablesOmitted', 'variablesAt', 'cells']);
72
75
  export const outputSchema = obj({ kind: { enum: ['stdout', 'stderr', 'warning', 'error', 'plot'] }, text: { type: 'string' }, plot: { type: 'integer', minimum: 1 }, width: { type: 'integer' }, height: { type: 'integer' } }, ['kind']);
73
76
  export const cellSchema = obj({
@@ -87,6 +90,8 @@ export const cellSchema = obj({
87
90
  // the project files and folders (ending in /) its strings name, as read or written. Cells
88
91
  // recorded before have neither.
89
92
  used: { type: 'array', items: text }, files: { type: 'array', items: obj({ path: text, how: { enum: ['read', 'wrote'] } }) },
93
+ // The program and version that ran it. Cells recorded before have neither.
94
+ program: maybe({ type: 'string' }), version: maybe({ type: 'string' }),
90
95
  }, ['cellId', 'changeId', 'by', 'sessionId', 'language', 'code', 'purpose', 'queuedAt', 'startedAt', 'endedAt', 'state', 'number', 'outputs', 'bytes', 'kept', 'cut', 'interrupt', 'problem']);
91
96
  // One value of a live session as its session describes it: the kind of thing it is, short facts,
92
97
  // and one page of its rows, its elements or its parts, each part with the code that reaches it.
@@ -27,6 +27,7 @@ export interface SessionRecord {
27
27
  cells: number;
28
28
  place?: SessionPlace | null;
29
29
  host?: string | null;
30
+ program?: string | null;
30
31
  }
31
32
  export interface SessionPlace {
32
33
  placeId: string;
@@ -80,6 +81,8 @@ export interface CellRecord {
80
81
  path: string;
81
82
  how: 'read' | 'wrote';
82
83
  }>;
84
+ program?: string | null;
85
+ version?: string | null;
83
86
  }
84
87
  export type InspectInput = {
85
88
  language: Language;
@@ -142,6 +145,7 @@ export declare class KernelHost {
142
145
  private loading?;
143
146
  private turn;
144
147
  private exclusive;
148
+ private programs;
145
149
  private placesRead?;
146
150
  private placesWriting;
147
151
  private ssh;
@@ -154,6 +158,8 @@ export declare class KernelHost {
154
158
  serverctl?: string;
155
159
  onChange?: () => void;
156
160
  });
161
+ private program;
162
+ private named;
157
163
  private transport;
158
164
  private get limits();
159
165
  private folder;
@@ -180,6 +186,7 @@ export declare class KernelHost {
180
186
  by: string;
181
187
  waitMs?: number;
182
188
  place?: string;
189
+ interpreter?: string;
183
190
  }): Promise<{
184
191
  cell: CellRecord;
185
192
  session: SessionRecord;
@@ -1,5 +1,6 @@
1
1
  import { spawn } from 'node:child_process';
2
2
  import * as fs from 'node:fs/promises';
3
+ import { constants as fsConstants } from 'node:fs';
3
4
  import net from 'node:net';
4
5
  import path from 'node:path';
5
6
  import { fileURLToPath } from 'node:url';
@@ -96,6 +97,9 @@ export class KernelHost {
96
97
  this.turn = next.catch(() => { });
97
98
  return next;
98
99
  }
100
+ // The program each language's sessions start with when the project has named one (a path in
101
+ // the project, as named): the last one a cell named, until another is named.
102
+ programs = {};
99
103
  placesRead;
100
104
  placesWriting = Promise.resolve();
101
105
  ssh;
@@ -107,6 +111,24 @@ export class KernelHost {
107
111
  const limits = this.limits;
108
112
  this.serverctl = new Serverctl(options.serverctl ?? 'serverctl', { reuseS: 60, sessionS: limits.serverctlSessionS, readMs: limits.serverctlReadMs, skillBytes: limits.serverSkillBytes });
109
113
  }
114
+ // A program named for a session: one in a folder of the project, such as the python of a
115
+ // virtual environment made there (.venv/bin/python). Its folder must be the project's own; the
116
+ // file itself may be the link a virtual environment makes to the Python it was made from, and
117
+ // it is started by that name so the environment is the one that runs.
118
+ async program(named) {
119
+ const root = await fs.realpath(this.root), file = path.resolve(root, named);
120
+ const folder = await fs.realpath(path.dirname(file)).catch(() => null);
121
+ requireThat(folder && (folder === root || folder.startsWith(root + path.sep)), 'scope', `Name a program in a folder of this project, such as .venv/bin/python; ${named} is not.`, { interpreter: named });
122
+ const program = path.join(folder, path.basename(file));
123
+ const runs = await fs.stat(program).then(s => s.isFile(), () => false) && await fs.access(program, fsConstants.X_OK).then(() => true, () => false);
124
+ requireThat(runs, 'not_found', `${named} is not a program that can run here.`, { interpreter: named });
125
+ return program;
126
+ }
127
+ // A program in the project is named relative to it (.venv/bin/python), so the record stays true
128
+ // when the project moves; any other keeps the path the session reported.
129
+ named(live, program) {
130
+ return !live.place && program.startsWith(live.root + path.sep) ? path.relative(live.root, program) : program;
131
+ }
110
132
  transport(place) { return place.via === 'serverctl' ? this.serverctl : this.ssh; }
111
133
  get limits() { return { ...kernelLimits, ...this.options.limits }; }
112
134
  async folder() { return stateDirectory(this.root, '.rho/plugins/kernel'); }
@@ -114,6 +136,7 @@ export class KernelHost {
114
136
  load() { return this.loading ??= this.readRecord(); }
115
137
  async readRecord() {
116
138
  const state = await readJson(path.join(await this.folder(), 'state.json'), { sessions: [], cells: [] });
139
+ this.programs = state.programs ?? {};
117
140
  let changed = false;
118
141
  for (const s of state.sessions)
119
142
  if (s.state !== 'ended') {
@@ -134,7 +157,7 @@ export class KernelHost {
134
157
  save() {
135
158
  clearTimeout(this.saveTimer);
136
159
  this.saveTimer = undefined;
137
- this.writing = this.writing.then(async () => atomicJson(path.join(await this.folder(), 'state.json'), { sessions: this.sessions ?? [], cells: this.cells }));
160
+ this.writing = this.writing.then(async () => atomicJson(path.join(await this.folder(), 'state.json'), { sessions: this.sessions ?? [], cells: this.cells, programs: this.programs }));
138
161
  return this.writing;
139
162
  }
140
163
  // Output arrives in many small pieces; it is written at most twice a second.
@@ -178,7 +201,7 @@ export class KernelHost {
178
201
  }
179
202
  else {
180
203
  requireThat(input.code.trim().length > 0 && Buffer.byteLength(input.code) <= this.limits.maxCodeBytes, 'invalid', `Write code of at most ${this.limits.maxCodeBytes} bytes.`, { limit: 'maxCodeBytes' });
181
- const live = await this.ensure(input.language, input.by, input.place);
204
+ const live = await this.ensure(input.language, input.by, input.place, input.interpreter);
182
205
  requireThat(live.queue.length < this.limits.maxQueued, 'limit', `At most ${this.limits.maxQueued} cells wait in a session. Wait for some to run or interrupt the one running.`, { limit: 'maxQueued', maximum: this.limits.maxQueued });
183
206
  // The oldest finished cells make room, with their plots.
184
207
  while (this.cells.length >= this.limits.maxCells) {
@@ -202,14 +225,24 @@ export class KernelHost {
202
225
  // The language's live session, started for this caller when there is none: where the cell
203
226
  // names, else where the project runs that language (this machine unless chosen). A cell that
204
227
  // names another place than where the live session runs is refused; its values stay there.
205
- async ensure(language, by, placeId) {
228
+ async ensure(language, by, placeId, interpreter) {
206
229
  const running = this.live.get(language), name = language === 'r' ? 'R' : 'Python';
207
230
  const where = (live) => live.place ? `on ${live.place.label}` : 'on this machine';
231
+ requireThat(!interpreter || !placeId || placeId === 'local', 'invalid', 'An interpreter names a program in the project on this machine; a session on a server runs that server\'s.');
232
+ const named = interpreter ? await this.program(interpreter) : null;
208
233
  if (running && !running.stopping) {
209
234
  requireThat(!placeId || placeId === (running.place?.placeId ?? 'local'), 'conflict', `The ${name} session runs ${where(running)}. Run the cell there, or stop that session first; its values stay until then.`, { place: running.place?.placeId ?? 'local' });
210
- return running;
235
+ if (!named || !running.place && running.started === named)
236
+ return running;
237
+ // A session in which only this caller ran cells, none of them now, is its own to start
238
+ // again with the program it names. Once anyone else ran a cell there, the values are shared
239
+ // and only the person stops it.
240
+ const own = !running.place && !running.current && !running.queue.length && this.cells.filter(c => c.sessionId === running.record.sessionId).every(c => c.by === by);
241
+ requireThat(own, 'conflict', `The ${name} session runs ${running.record.program ?? 'another program'}${running.current || running.queue.length ? ' and has a cell running' : ', and others ran cells in it'}. Ask the person to stop it in the Notebook, then run this cell again to start one with ${interpreter}; its values stay until then.`, { program: running.started ?? running.record.program ?? null });
242
+ this.stopping(this.sessions, running.record.sessionId, by);
243
+ await running.ended;
211
244
  }
212
- requireThat(!running, 'conflict', 'The session is stopping. Run the cell again when it has ended.');
245
+ requireThat(!this.live.get(language), 'conflict', 'The session is stopping. Run the cell again when it has ended.');
213
246
  const chosen = placeId ?? (await this.placeState()).use[language] ?? 'local';
214
247
  const place = chosen === 'local' ? null : (await this.placeState()).places.find(p => p.placeId === chosen) ?? null;
215
248
  requireThat(chosen === 'local' || place, 'not_found', `No place is named ${chosen}. Read kernel.places for the places there are.`);
@@ -220,7 +253,15 @@ export class KernelHost {
220
253
  if (old.length > this.limits.maxEndedSessions)
221
254
  this.sessions.splice(this.sessions.indexOf(old[0]), 1);
222
255
  const windows = !place && process.platform === 'win32';
223
- const program = place ? 'ssh' : language === 'r' ? this.options.rscript ?? 'Rscript' : this.options.python ?? (windows ? 'python' : 'python3');
256
+ // A program the cell named, else the one the project named last while it is still there.
257
+ requireThat(!named || !place, 'invalid', `${name} runs on ${place?.label} in this project; an interpreter names a program in the project on this machine.`);
258
+ const kept = !named && !place && this.programs[language] ? await this.program(this.programs[language]).catch(() => null) : null;
259
+ if (named)
260
+ this.programs[language] = path.relative(await fs.realpath(this.root), named);
261
+ else if (!kept && this.programs[language])
262
+ delete this.programs[language];
263
+ const selected = named ?? kept;
264
+ const program = place ? 'ssh' : selected ?? (language === 'r' ? this.options.rscript ?? 'Rscript' : this.options.python ?? (windows ? 'python' : 'python3'));
224
265
  const root = await fs.realpath(this.root);
225
266
  // On a server the runner is sent first on the session's own input, named by its digest, so
226
267
  // the session needs nothing installed there but R or Python.
@@ -229,7 +270,9 @@ export class KernelHost {
229
270
  const pipe = windows && language === 'r' ? await answerPipe() : null;
230
271
  const child = place ? await this.transport(place).spawn(place, sessionCommand(place, language === 'r' ? 'Rscript' : 'python3', runner, source.length), root)
231
272
  : spawn(program, [runners[language], root], { cwd: root, ...ownGroup, stdio: ['pipe', 'pipe', 'pipe', 'pipe'], env: { ...process.env, MPLBACKEND: 'Agg', PYTHONUNBUFFERED: '1', ...(pipe ? { RHO_KERNEL_ANSWERS: pipe.name } : {}) } });
232
- const live = { record, child, place, remotePid: null, answers: '', early: '', order: Promise.resolve(), queue: [], current: null, stopping: false, printed: '', mark: 0, held: [], answered: 0, looking: null, lookups: Promise.resolve(), pipe: pipe?.server };
273
+ let settle = () => { };
274
+ const ended = new Promise(resolve => { settle = resolve; });
275
+ const live = { started: selected, root, ended, settle, record, child, place, remotePid: null, answers: '', early: '', order: Promise.resolve(), queue: [], current: null, stopping: false, printed: '', mark: 0, held: [], answered: 0, looking: null, lookups: Promise.resolve(), pipe: pipe?.server };
233
276
  this.live.set(language, live);
234
277
  record.pid = place ? null : child.pid ?? null;
235
278
  const startMs = place ? this.limits.remoteStartTimeoutMs : this.limits.startTimeoutMs;
@@ -411,6 +454,8 @@ export class KernelHost {
411
454
  cell.state = 'running';
412
455
  cell.startedAt = now();
413
456
  live.record.state = 'busy';
457
+ cell.program = live.record.program ?? null;
458
+ cell.version = live.record.version;
414
459
  // A session on a server draws in its own temporary folder and sends each plot with its answer.
415
460
  live.child.stdin.write(JSON.stringify({ op: 'run', id: cell.cellId, number: cell.number, code: cell.code, plots: live.place ? null : await this.plots(), inline: !!live.place, maxPlots: this.limits.maxPlots, maxVariables: this.limits.maxVariables }) + '\n');
416
461
  this.changed();
@@ -437,7 +482,7 @@ export class KernelHost {
437
482
  const record = live.record, cell = live.current;
438
483
  if (msg.kind === 'ready') {
439
484
  clearTimeout(live.timer);
440
- Object.assign(record, { state: 'idle', version: String(msg.version ?? ''), variables: msg.variables?.items ?? [], variablesOmitted: msg.variables?.omitted ?? 0, variablesAt: now(), host: typeof msg.host === 'string' ? msg.host.slice(0, 256) : null });
485
+ Object.assign(record, { state: 'idle', version: String(msg.version ?? ''), program: typeof msg.executable === 'string' && msg.executable ? this.named(live, msg.executable.slice(0, 1024)) : record.program ?? null, variables: msg.variables?.items ?? [], variablesOmitted: msg.variables?.omitted ?? 0, variablesAt: now(), host: typeof msg.host === 'string' ? msg.host.slice(0, 256) : null });
441
486
  if (live.place) {
442
487
  live.remotePid = Number.isInteger(msg.pid) && msg.pid > 1 ? msg.pid : null;
443
488
  record.pid = live.remotePid;
@@ -534,6 +579,7 @@ export class KernelHost {
534
579
  }
535
580
  if (this.live.get(record.language) === live)
536
581
  this.live.delete(record.language);
582
+ live.settle();
537
583
  this.changed();
538
584
  }
539
585
  // Interrupting a running cell stops it and leaves its session; a waiting cell is not run. A
@@ -761,6 +807,7 @@ const content = [
761
807
  'Results meant to last still go to files from a script, so they can be run again without the session.',
762
808
  'Sessions can also run on a server. kernel.places lists the places and where each language runs; kernel.place.set names one (the server, its folder there, and setup lines run there before a session starts) or chooses it for R or Python; kernel.place.check connects and reports R and Python there.',
763
809
  'kernel.servers lists the servers the person manages with serverctl and the skills bound to each: how that server is used (its environments, where heavy work goes, what to avoid there). Before you name a place on one or run code there, read the skills that apply with kernel.server.skill and follow them, for example in the place\'s setup lines. They guide the work on that server; they do not widen what you may do. A place on such a server is reached through serverctl, which holds its login; another server is reached with ssh.',
810
+ 'The project\'s Python is the machine\'s python3 until you name another. When the work needs packages it lacks, make an environment in the project (python3 -m venv .venv or uv venv, then install into it) and pass interpreter: ".venv/bin/python" to kernel.run; later sessions of that language start with it too, and each cell records the program that ran it. A live session in which only you ran cells starts again with the program you name; once the person ran a cell in it, ask them to stop it first. Do not add another environment\'s packages to a running session\'s path.',
764
811
  'Pass place to kernel.run to start a session there. Paths in a session on a server are its folder\'s; kernel.place.list lists them and kernel.place.copy copies a file into the project under remote/<place>/.',
765
812
  ].join('\n');
766
813
  // What each view keeps in its props: the Notebook's form, and which value a value's view shows.
@@ -57,10 +57,13 @@ export declare function lineage(cells: LineageCell[], values: string[], limits?:
57
57
  plots: number;
58
58
  files: number;
59
59
  }): Lineage;
60
- export declare function related(graph: Lineage, stepId: string): Set<string>;
61
- export declare function lanes(graph: Lineage): {
62
- order: LineageStep[];
63
- lane: Map<string, number>;
64
- count: number;
65
- };
60
+ export interface CellRelations {
61
+ reads: Map<string, Array<{
62
+ name: string;
63
+ from: LineageCell | null;
64
+ }>>;
65
+ readers: Map<string, Map<string, LineageCell[]>>;
66
+ maker: Map<string, LineageCell>;
67
+ }
68
+ export declare function cellRelations(cells: LineageCell[]): CellRelations;
66
69
  export declare function cellLabel(cell: LineageCell): string;
@@ -129,48 +129,25 @@ function place(steps, links) {
129
129
  step.nodes = step.nodes.map((n, i) => ({ n, i, at: toward(n.id) })).sort((a, b) => a.at - b.at || a.i - b.i).map(x => x.n);
130
130
  return layers;
131
131
  }
132
- // The steps a node comes from and leads to, through the links, for showing one path at a time.
133
- export function related(graph, stepId) {
134
- const stepOfNode = new Map(graph.steps.flatMap(s => s.nodes.map(n => [n.id, s.id])));
135
- const up = new Map(), down = new Map();
136
- for (const link of graph.links) {
137
- const from = stepOfNode.get(link.from);
138
- up.set(link.to, [...up.get(link.to) ?? [], from]);
139
- down.set(from, [...down.get(from) ?? [], link.to]);
140
- }
141
- const reach = (start, next) => {
142
- const seen = new Set([start]), queue = [start];
143
- while (queue.length)
144
- for (const id of next.get(queue.pop()) ?? [])
145
- if (!seen.has(id)) {
146
- seen.add(id);
147
- queue.push(id);
148
- }
149
- return seen;
150
- };
151
- return new Set([...reach(stepId, up), ...reach(stepId, down)]);
152
- }
153
- // The boxes in the order their cells ran (which is also an order in which each reads only from
154
- // boxes above it), and a lane in the margin for each value or file something read: from the line
155
- // that made it down past the boxes between, to each box that read it. Lanes whose spans do not
156
- // overlap share a place; lane 0 is nearest the boxes.
157
- export function lanes(graph) {
158
- const order = [...graph.steps].sort((a, b) => (a.cell?.number ?? -1) - (b.cell?.number ?? -1));
159
- const index = new Map(order.map((s, i) => [s.id, i])), stepOfNode = new Map(order.flatMap(s => s.nodes.map(n => [n.id, s.id])));
160
- const spans = new Map();
161
- for (const link of graph.links) {
162
- const from = index.get(stepOfNode.get(link.from)), to = index.get(link.to), span = spans.get(link.from);
163
- spans.set(link.from, { from, to: Math.max(to, span?.to ?? to) });
164
- }
165
- const ends = [], lane = new Map();
166
- for (const [node, span] of [...spans].sort((a, b) => a[1].from - b[1].from || a[1].to - b[1].to)) {
167
- let free = ends.findIndex(end => end <= span.from);
168
- if (free < 0)
169
- free = ends.length;
170
- ends[free] = span.to;
171
- lane.set(node, free);
132
+ export function cellRelations(cells) {
133
+ const reads = new Map(), readers = new Map(), maker = new Map();
134
+ for (const cell of finished(cells)) {
135
+ reads.set(cell.cellId, (cell.used ?? []).map(name => {
136
+ const from = maker.get(name) ?? null;
137
+ if (from) {
138
+ let by = readers.get(from.cellId);
139
+ if (!by)
140
+ readers.set(from.cellId, by = new Map());
141
+ by.set(name, [...by.get(name) ?? [], cell]);
142
+ }
143
+ return { name, from };
144
+ }));
145
+ for (const name of cell.removed ?? [])
146
+ maker.delete(name);
147
+ for (const name of cell.defined ?? [])
148
+ maker.set(name, cell);
172
149
  }
173
- return { order, lane, count: ends.length };
150
+ return { reads, readers, maker };
174
151
  }
175
152
  // What a cell is called where it is named: its purpose (a script's lines), else its first line.
176
153
  export function cellLabel(cell) {
@@ -3,9 +3,12 @@ import { cellId, cellSchema, changeId, copySchema, inspectStates, language, obje
3
3
  // Owner business contracts. Application project/authentication fields are separate.
4
4
  export const operationContracts = {
5
5
  // place names where a session that is not live yet starts ("local" is this machine); a cell
6
- // naming another place than the live session's is refused.
6
+ // naming another place than the live session's is refused. interpreter names the program a
7
+ // session on this machine starts with, in a folder of the project (.venv/bin/python); the
8
+ // project keeps it for the language's later sessions. A cell naming another program than the
9
+ // live session's is refused.
7
10
  'kernel.run': {
8
- inputSchema: obj({ language, code: { type: 'string', minLength: 1, maxLength: 65536 }, purpose: { type: 'string', maxLength: 200 }, changeId, waitMs: { type: 'integer', minimum: 0, maximum: 600000 }, place: placeRef }, ['language', 'code', 'changeId']),
11
+ inputSchema: obj({ language, code: { type: 'string', minLength: 1, maxLength: 65536 }, purpose: { type: 'string', maxLength: 200 }, changeId, waitMs: { type: 'integer', minimum: 0, maximum: 600000 }, place: placeRef, interpreter: { type: 'string', minLength: 1, maxLength: 1024 } }, ['language', 'code', 'changeId']),
9
12
  outputSchema: obj({ cell: cellSchema, session: sessionSchema }),
10
13
  requires: [], effect: 'native',
11
14
  },
@@ -0,0 +1,39 @@
1
+ import type { Language } from './explore-code.js';
2
+ import type { Lineage, LineageCell, LineageStep } from './lineage.js';
3
+ export interface ScriptStep extends LineageStep {
4
+ cell: LineageCell;
5
+ from: number;
6
+ to: number;
7
+ changed: string[];
8
+ functions: string[];
9
+ }
10
+ export interface ScriptFlow extends Lineage {
11
+ steps: ScriptStep[];
12
+ quiet: number;
13
+ cut: number;
14
+ quietReads: Array<{
15
+ from: number;
16
+ to: number;
17
+ used: string[];
18
+ means?: string;
19
+ }>;
20
+ means: Map<string, string>;
21
+ outside: Array<{
22
+ name: string;
23
+ to: string;
24
+ }>;
25
+ tooLong: boolean;
26
+ }
27
+ export declare const scriptFlowLimits: {
28
+ bytes: number;
29
+ steps: number;
30
+ };
31
+ export declare function looksLikePath(s: string): boolean;
32
+ export declare function markersAbove(lines: string[], line: number): Array<{
33
+ name: string | null;
34
+ text: string;
35
+ }>;
36
+ export declare function scriptFlow(text: string, language: Language, limits?: {
37
+ bytes: number;
38
+ steps: number;
39
+ }, outside?: string[]): ScriptFlow;