@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.
- package/README.md +24 -5
- package/dist/browser-access.js +3 -2
- package/dist/capabilities.d.ts +29 -2
- package/dist/capabilities.js +79 -2
- package/dist/cli.js +237 -99
- package/dist/contract.generated.d.ts +441 -16
- package/dist/contract.generated.js +1 -1
- package/dist/contracts/owners.generated.js +459 -10
- package/dist/conversation-presentation.d.ts +3 -1
- package/dist/conversation-presentation.js +16 -6
- package/dist/conversations.d.ts +10 -6
- package/dist/conversations.js +17 -13
- package/dist/discovery.d.ts +1 -0
- package/dist/discovery.js +3 -3
- package/dist/extension-contract.d.ts +99 -0
- package/dist/extension-contract.js +52 -0
- package/dist/extension-directory.d.ts +9 -0
- package/dist/extension-directory.js +11 -0
- package/dist/extension-worker.d.ts +1 -0
- package/dist/extension-worker.js +36 -0
- package/dist/extensions.d.ts +157 -0
- package/dist/extensions.js +349 -0
- package/dist/installs.d.ts +11 -0
- package/dist/installs.js +179 -0
- package/dist/plugin-cli.d.ts +1 -0
- package/dist/plugin-cli.js +139 -0
- package/dist/plugin-inventory.json +18 -0
- package/dist/plugins.d.ts +3 -3
- package/dist/project-notes.js +2 -0
- package/dist/project-work.d.ts +3 -1
- package/dist/project-work.js +15 -2
- package/dist/protocol.d.ts +7 -0
- package/dist/protocol.js +11 -7
- package/dist/screen-check-skill.d.ts +2 -0
- package/dist/screen-check-skill.js +39 -0
- package/dist/server.d.ts +6 -1
- package/dist/server.js +105 -15
- package/dist/web/.vite/manifest.json +65 -65
- package/dist/web/assets/{canvas-BXhC8RDZ.js → canvas-D8rDdfDz.js} +1 -1
- package/dist/web/assets/choices-b0XhrGQV.js +1 -0
- package/dist/web/assets/{console-e1P5qYQ5.js → console-BSjLGe0T.js} +1 -1
- package/dist/web/assets/{dist-Dd3iAGFy.js → dist-Buk0lwzI.js} +2 -2
- package/dist/web/assets/dist-Cw8hRIlT.js +1 -0
- package/dist/web/assets/dist-Tzoe_zm-.js +3 -0
- package/dist/web/assets/{dist-DEorbOW0.js → dist-foH9IKc6.js} +1 -1
- package/dist/web/assets/explore-in-BVUy3ZW_.js +1 -0
- package/dist/web/assets/graph-1OdIJ9l7.js +2 -0
- package/dist/web/assets/index-CsC3sTRq.css +1 -0
- package/dist/web/assets/{index-BYuKpyoi.js → index-CxmItXqa.js} +220 -121
- package/dist/web/assets/{notes-meaning-B3HFbh84.js → notes-meaning-pVbbQUGP.js} +1 -1
- package/dist/web/assets/overview-B9UtVJ32.js +6 -0
- package/dist/web/assets/preview-CksD_5KS.js +1 -0
- package/dist/web/assets/{review-BVh9jWMB.js → review-CMxQlQ-C.js} +1 -1
- package/dist/web/assets/{skills-DPaEYkln.js → skills-BFNSyrnD.js} +1 -1
- package/dist/web/assets/{skills-work-dvjfy_tu.js → skills-work-BGPSnF_I.js} +1 -1
- package/dist/web/assets/{studio-process-BYm8mjRJ.js → studio-process-CsRoTHOh.js} +2 -2
- package/dist/web/assets/{timeline-events-CDZ7wiJX.js → timeline-events-BbuuFWHV.js} +1 -1
- package/dist/web/assets/{work-turns-BeCt303c.js → work-turns-BvJlIMmA.js} +1 -1
- package/dist/web/assets/workspace-CWlkjLNx.js +5 -0
- package/dist/web/composition.json +80 -80
- package/dist/web/index.html +3 -3
- package/dist/web/renderer.json +1 -1
- package/dist/web-assets.d.ts +2 -1
- package/dist/web-assets.js +3 -2
- package/dist/work-contract.js +2 -2
- package/docs/FRONTEND.md +30 -14
- package/docs/HEADLESS.md +60 -14
- package/docs/PLUGIN-AUTHORING.md +4 -0
- package/docs/THIRD-PARTY-PLUGINS.md +190 -0
- package/example/pa14-qs/.rho/rho/conversations/c-67f77cfebaba2cea.json +1 -1
- package/example/pa14-qs/.rho/rho/conversations/c-91aa2e46b1ac1a6c.json +1 -1
- package/example/pa14-qs/.rho/rho/conversations/c-fa24dfd80dfe4bcb.json +1 -1
- package/node_modules/@hono/node-server/dist/index.js +11 -0
- package/node_modules/@hono/node-server/dist/index.mjs +11 -0
- package/node_modules/@hono/node-server/dist/listener.js +11 -0
- package/node_modules/@hono/node-server/dist/listener.mjs +11 -0
- package/node_modules/@hono/node-server/dist/request.js +11 -0
- package/node_modules/@hono/node-server/dist/request.mjs +11 -0
- package/node_modules/@hono/node-server/dist/server.js +11 -0
- package/node_modules/@hono/node-server/dist/server.mjs +11 -0
- package/node_modules/@hono/node-server/dist/vercel.js +11 -0
- package/node_modules/@hono/node-server/dist/vercel.mjs +11 -0
- package/node_modules/@hono/node-server/package.json +1 -1
- package/node_modules/@rho-workspace/plugin-agent/README.md +42 -1
- package/node_modules/@rho-workspace/plugin-agent/dist/acp-conversation.js +14 -3
- package/node_modules/@rho-workspace/plugin-agent/dist/activity-normalize.d.ts +1 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/activity-normalize.js +2 -2
- package/node_modules/@rho-workspace/plugin-agent/dist/conversation.d.ts +1 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/conversation.js +1 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/dsh-session.d.ts +6 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/dsh-session.js +174 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/external-session-contract.d.ts +82 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/external-session-contract.js +15 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/external-session.d.ts +73 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/external-session.js +190 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/generic-acp.d.ts +11 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/generic-acp.js +7 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/index.d.ts +373 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/index.js +1 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/mcp.js +5 -1
- package/node_modules/@rho-workspace/plugin-agent/dist/operations.d.ts +33 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/operations.js +3 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/presentation.d.ts +14 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/presentation.js +2 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/ui-external-session.d.ts +15 -0
- package/node_modules/@rho-workspace/plugin-agent/dist/ui-external-session.js +37 -0
- package/node_modules/@rho-workspace/plugin-agent/package.json +5 -1
- package/node_modules/@rho-workspace/plugin-annotations/package.json +1 -1
- package/node_modules/@rho-workspace/plugin-documents/README.md +4 -0
- package/node_modules/@rho-workspace/plugin-documents/dist/index.d.ts +3 -0
- package/node_modules/@rho-workspace/plugin-documents/dist/index.js +1 -1
- package/node_modules/@rho-workspace/plugin-documents/package.json +1 -1
- package/node_modules/@rho-workspace/plugin-kernel/README.md +71 -10
- package/node_modules/@rho-workspace/plugin-kernel/dist/code.d.ts +2 -0
- package/node_modules/@rho-workspace/plugin-kernel/dist/code.js +4 -1
- package/node_modules/@rho-workspace/plugin-kernel/dist/contract.js +5 -0
- package/node_modules/@rho-workspace/plugin-kernel/dist/index.d.ts +7 -0
- package/node_modules/@rho-workspace/plugin-kernel/dist/index.js +55 -8
- package/node_modules/@rho-workspace/plugin-kernel/dist/lineage.d.ts +9 -6
- package/node_modules/@rho-workspace/plugin-kernel/dist/lineage.js +18 -41
- package/node_modules/@rho-workspace/plugin-kernel/dist/operations.js +5 -2
- package/node_modules/@rho-workspace/plugin-kernel/dist/script-flow.d.ts +39 -0
- package/node_modules/@rho-workspace/plugin-kernel/dist/script-flow.js +661 -0
- package/node_modules/@rho-workspace/plugin-kernel/dist/ui-base.d.ts +3 -0
- package/node_modules/@rho-workspace/plugin-kernel/dist/ui-base.js +10 -0
- package/node_modules/@rho-workspace/plugin-kernel/dist/ui-flow.d.ts +38 -4
- package/node_modules/@rho-workspace/plugin-kernel/dist/ui-flow.js +194 -97
- package/node_modules/@rho-workspace/plugin-kernel/dist/ui-notebook-work.js +1 -2
- package/node_modules/@rho-workspace/plugin-kernel/dist/ui-notebook.d.ts +10 -2
- package/node_modules/@rho-workspace/plugin-kernel/dist/ui-notebook.js +79 -18
- package/node_modules/@rho-workspace/plugin-kernel/dist/ui-styles.js +115 -45
- package/node_modules/@rho-workspace/plugin-kernel/dist/ui.d.ts +1 -1
- package/node_modules/@rho-workspace/plugin-kernel/dist/ui.js +1 -1
- package/node_modules/@rho-workspace/plugin-kernel/dist/value-graph.d.ts +63 -0
- package/node_modules/@rho-workspace/plugin-kernel/dist/value-graph.js +344 -0
- package/node_modules/@rho-workspace/plugin-kernel/package.json +1 -1
- package/node_modules/@rho-workspace/plugin-kernel/runners/runner.R +6 -3
- package/node_modules/@rho-workspace/plugin-kernel/runners/runner.py +6 -3
- package/node_modules/express-rate-limit/dist/index.cjs +1 -1
- package/node_modules/express-rate-limit/dist/index.mjs +1 -1
- package/node_modules/express-rate-limit/package.json +1 -1
- package/node_modules/ip-address/dist/ipv6.js +1 -1
- package/node_modules/ip-address/package.json +1 -1
- package/node_modules/playwright-core/LICENSE +202 -0
- package/node_modules/playwright-core/NOTICE +5 -0
- package/node_modules/playwright-core/ThirdPartyNotices.txt +13 -0
- package/node_modules/playwright-core/bin/install_media_pack.ps1 +5 -0
- package/node_modules/playwright-core/bin/install_webkit_wsl.ps1 +33 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_beta_linux.sh +42 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_beta_mac.sh +13 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_beta_win.ps1 +24 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_stable_linux.sh +42 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_stable_mac.sh +12 -0
- package/node_modules/playwright-core/bin/reinstall_chrome_stable_win.ps1 +24 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_beta_linux.sh +48 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_beta_mac.sh +11 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_beta_win.ps1 +23 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_dev_linux.sh +48 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_dev_mac.sh +11 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_dev_win.ps1 +23 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_stable_linux.sh +48 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_stable_mac.sh +11 -0
- package/node_modules/playwright-core/bin/reinstall_msedge_stable_win.ps1 +24 -0
- package/node_modules/playwright-core/browsers.json +52 -0
- package/node_modules/playwright-core/cli.js +22 -0
- package/node_modules/playwright-core/index.js +17 -0
- package/node_modules/playwright-core/index.mjs +28 -0
- package/node_modules/playwright-core/lib/bootstrap.js +149 -0
- package/node_modules/playwright-core/lib/coreBundle.js +78041 -0
- package/node_modules/playwright-core/lib/entry/cliDaemon.js +5 -0
- package/node_modules/playwright-core/lib/entry/dashboardApp.js +3 -0
- package/node_modules/playwright-core/lib/entry/mcp.js +10 -0
- package/node_modules/playwright-core/lib/entry/oopBrowserDownload.js +3 -0
- package/node_modules/playwright-core/lib/package.js +50 -0
- package/node_modules/playwright-core/lib/server/chromium/appIcon.png +0 -0
- package/node_modules/playwright-core/lib/server/electron/loader.js +123 -0
- package/node_modules/playwright-core/lib/serverRegistry.js +1939 -0
- package/node_modules/playwright-core/lib/serverRegistry.js.LICENSE +65 -0
- package/node_modules/playwright-core/lib/tools/cli-client/channelSessions.js +141 -0
- package/node_modules/playwright-core/lib/tools/cli-client/cli.js +7 -0
- package/node_modules/playwright-core/lib/tools/cli-client/help.json +808 -0
- package/node_modules/playwright-core/lib/tools/cli-client/minimist.js +128 -0
- package/node_modules/playwright-core/lib/tools/cli-client/output.js +352 -0
- package/node_modules/playwright-core/lib/tools/cli-client/program.js +422 -0
- package/node_modules/playwright-core/lib/tools/cli-client/registry.js +180 -0
- package/node_modules/playwright-core/lib/tools/cli-client/session.js +261 -0
- package/node_modules/playwright-core/lib/tools/dashboard/appIcon.png +0 -0
- package/node_modules/playwright-core/lib/tools/utils/extension.js +112 -0
- package/node_modules/playwright-core/lib/tools/utils/socketConnection.js +108 -0
- package/node_modules/playwright-core/lib/utilsBundle.js +86078 -0
- package/node_modules/playwright-core/lib/utilsBundle.js.LICENSE +1890 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/codeMirrorModule--QdMvsKi.css +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/codeMirrorModule-CQ8RZGBm.js +32 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/codicon-DCmgc-ay.ttf +0 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-1bWoP6pv.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-beta-k3eOH_eK.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/firefox-nightly-Cp5nfeDT.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/index-AwgwcYie.css +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/index-hRvO4yU2.js +12 -0
- package/node_modules/playwright-core/lib/vite/dashboard/assets/safari-na3_-uQk.svg +1 -0
- package/node_modules/playwright-core/lib/vite/dashboard/index.html +29 -0
- package/node_modules/playwright-core/lib/vite/dashboard/playwright-logo.svg +24 -0
- package/node_modules/playwright-core/lib/vite/htmlReport/index.html +16 -0
- package/node_modules/playwright-core/lib/vite/htmlReport/report.css +2 -0
- package/node_modules/playwright-core/lib/vite/htmlReport/report.js +32 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/codeMirrorModule--QdMvsKi.css +1 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/codeMirrorModule-DK72OMRi.js +32 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/codicon-DCmgc-ay.ttf +0 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/index-BZpYJZ-P.css +1 -0
- package/node_modules/playwright-core/lib/vite/recorder/assets/index-Cn0mmDuv.js +129 -0
- package/node_modules/playwright-core/lib/vite/recorder/index.html +29 -0
- package/node_modules/playwright-core/lib/vite/recorder/playwright-logo.svg +9 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/codeMirrorModule-BEB2e8M3.js +32 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-D-g2vrvf.js +184 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/urlMatch-L3liM589.js +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/assets/xtermModule-B794rD2Z.js +7 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/codeMirrorModule.-QdMvsKi.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/codicon.DCmgc-ay.ttf +0 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/defaultSettingsView.C8BeHuxd.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/index.B_TqY17P.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/index.html +44 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/index.oNry3Hjv.js +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/manifest.webmanifest +16 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/playwright-logo.svg +9 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/snapshot.B_Jk1wbt.js +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/snapshot.html +10 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/sw.bundle.js +4 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CYwC_gH1.js +5 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CyMfwkXJ.css +1 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +18 -0
- package/node_modules/playwright-core/lib/vite/traceViewer/xtermModule.kHJ-D0s7.css +1 -0
- package/node_modules/playwright-core/lib/webp_codec.LICENSE +173 -0
- package/node_modules/playwright-core/lib/webp_codec.wasm +0 -0
- package/node_modules/playwright-core/lib/xdg-open +1267 -0
- package/node_modules/playwright-core/package.json +34 -0
- package/package.json +13 -7
- package/protocol/index.json +75 -21
- package/protocol/operations/agent.sessions.list.json +100 -0
- package/protocol/operations/agent.sessions.read.json +266 -0
- package/protocol/operations/conversation.settings.check.json +147 -4
- package/protocol/operations/conversation.settings.read.json +145 -3
- package/protocol/operations/conversation.settings.update.json +166 -4
- package/protocol/operations/conversation.start.json +2 -1
- package/protocol/operations/extension.call.json +132 -0
- package/protocol/operations/extension.content.json +78 -0
- package/protocol/operations/extension.describe.json +195 -0
- package/protocol/operations/extension.install.json +198 -0
- package/protocol/operations/extension.list.json +123 -0
- package/protocol/operations/extension.manage.json +55 -0
- package/protocol/operations/extension.read.json +112 -0
- package/protocol/operations/kernel.interrupt.json +20 -0
- package/protocol/operations/kernel.read.json +30 -0
- package/protocol/operations/kernel.run.json +36 -1
- package/protocol/operations/kernel.stop.json +10 -0
- package/protocol/operations/project.work.read.json +3 -2
- package/protocol/operations/session.grant.json +9 -0
- package/scripts/browser-checks.mjs +53 -0
- package/scripts/screen-check.mjs +193 -0
- package/scripts/third-party-acceptance.mjs +77 -0
- package/vendor/composition.json +111 -111
- package/vendor/rho-workspace-plugin-agent-0.4.29.tgz +0 -0
- package/vendor/rho-workspace-plugin-annotations-0.5.2.tgz +0 -0
- package/vendor/rho-workspace-plugin-documents-0.4.11.tgz +0 -0
- package/vendor/rho-workspace-plugin-kernel-0.5.5.tgz +0 -0
- package/web/theme.css +17 -2
- package/dist/web/assets/choices-B-y2OYvE.js +0 -1
- package/dist/web/assets/dist-CBM2oq6g.js +0 -1
- package/dist/web/assets/dist-CH56yNDn.js +0 -3
- package/dist/web/assets/explore-in-muWXOGOY.js +0 -1
- package/dist/web/assets/graph-CK-df5lh.js +0 -2
- package/dist/web/assets/index-DBd77u4a.css +0 -1
- package/dist/web/assets/overview-D1Ev2OC_.js +0 -6
- package/dist/web/assets/preview-HbmQKUGY.js +0 -1
- package/dist/web/assets/workspace-d5Hw_ClZ.js +0 -5
- package/vendor/rho-workspace-plugin-agent-0.4.27.tgz +0 -0
- package/vendor/rho-workspace-plugin-documents-0.4.10.tgz +0 -0
- 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
|
# Notebook
|
|
2
2
|
|
|
3
|
-
`@rho-workspace/plugin-kernel` 0.5.
|
|
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
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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,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
|
|
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
|
-
|
|
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(!
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
-
|
|
133
|
-
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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 {
|
|
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;
|