@rho-workspace/rho 0.5.3 → 0.5.4
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/capabilities.d.ts +27 -0
- package/dist/capabilities.js +73 -1
- package/dist/cli.js +150 -25
- package/dist/contract.generated.d.ts +112 -12
- package/dist/contracts/owners.generated.js +103 -8
- 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/installs.d.ts +11 -0
- package/dist/installs.js +179 -0
- package/dist/project-notes.js +2 -0
- package/dist/protocol.js +7 -5
- package/dist/screen-check-skill.d.ts +2 -0
- package/dist/screen-check-skill.js +39 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +50 -7
- package/dist/web/.vite/manifest.json +51 -51
- package/dist/web/assets/{choices-B-y2OYvE.js → choices-DU9kHlyQ.js} +1 -1
- package/dist/web/assets/{console-e1P5qYQ5.js → console-Dbdo-5oO.js} +1 -1
- package/dist/web/assets/{dist-Dd3iAGFy.js → dist-B2V0VDO0.js} +1 -1
- package/dist/web/assets/{dist-CH56yNDn.js → dist-BV3hWfn_.js} +1 -1
- package/dist/web/assets/{dist-CBM2oq6g.js → dist-CLNF2g-E.js} +1 -1
- package/dist/web/assets/{dist-DEorbOW0.js → dist-D25Vn17i.js} +1 -1
- package/dist/web/assets/{explore-in-muWXOGOY.js → explore-in-8Q5ftt-E.js} +1 -1
- package/dist/web/assets/{graph-CK-df5lh.js → graph-hS2kvHTI.js} +1 -1
- package/dist/web/assets/{index-BYuKpyoi.js → index-BHQIaDsx.js} +220 -121
- package/dist/web/assets/index-Cj1_iqyK.css +1 -0
- package/dist/web/assets/{notes-meaning-B3HFbh84.js → notes-meaning-DdPbtNzJ.js} +1 -1
- package/dist/web/assets/{overview-D1Ev2OC_.js → overview-BV6ZO5TO.js} +3 -3
- package/dist/web/assets/{preview-HbmQKUGY.js → preview-n5lOOdjN.js} +1 -1
- package/dist/web/assets/{review-BVh9jWMB.js → review-CmWou4Iv.js} +1 -1
- package/dist/web/assets/{skills-DPaEYkln.js → skills-Dy7n3L9d.js} +1 -1
- package/dist/web/assets/{skills-work-dvjfy_tu.js → skills-work-Cj0W6b-I.js} +1 -1
- package/dist/web/assets/{studio-process-BYm8mjRJ.js → studio-process-QOY_n2_8.js} +1 -1
- package/dist/web/assets/{timeline-events-CDZ7wiJX.js → timeline-events-DmX1BCh3.js} +1 -1
- package/dist/web/assets/{work-turns-BeCt303c.js → work-turns-Co0C71rJ.js} +1 -1
- package/dist/web/assets/{workspace-d5Hw_ClZ.js → workspace-BKFefRfJ.js} +2 -2
- package/dist/web/composition.json +73 -73
- package/dist/web/index.html +2 -2
- package/dist/web/renderer.json +1 -1
- package/docs/FRONTEND.md +30 -14
- package/docs/HEADLESS.md +59 -13
- 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 +3 -1
- package/node_modules/@rho-workspace/plugin-agent/dist/acp-conversation.js +14 -3
- 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/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/mcp.js +5 -1
- package/node_modules/@rho-workspace/plugin-agent/package.json +1 -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 +10 -6
- package/protocol/index.json +17 -17
- 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/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/scripts/browser-checks.mjs +53 -0
- package/scripts/screen-check.mjs +193 -0
- package/vendor/composition.json +102 -102
- package/vendor/rho-workspace-plugin-agent-0.4.28.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/index-DBd77u4a.css +0 -1
- 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
|
@@ -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;
|