@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
|
@@ -52,6 +52,15 @@ var RequestError = class extends Error {
|
|
|
52
52
|
this.name = "RequestError";
|
|
53
53
|
}
|
|
54
54
|
};
|
|
55
|
+
var validateRequestTarget = (target) => {
|
|
56
|
+
const backslash = target.indexOf("\\");
|
|
57
|
+
if (backslash !== -1) {
|
|
58
|
+
const query = target.indexOf("?");
|
|
59
|
+
if (query === -1 || backslash < query) {
|
|
60
|
+
throw new RequestError("Backslash in request path");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
55
64
|
var toRequestError = (e) => {
|
|
56
65
|
if (e instanceof RequestError) {
|
|
57
66
|
return e;
|
|
@@ -212,6 +221,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
212
221
|
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
|
213
222
|
}
|
|
214
223
|
try {
|
|
224
|
+
validateRequestTarget(incomingUrl);
|
|
215
225
|
const url2 = new URL(incomingUrl);
|
|
216
226
|
req[urlKey] = url2.href;
|
|
217
227
|
} catch (e) {
|
|
@@ -232,6 +242,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
232
242
|
} else {
|
|
233
243
|
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
|
234
244
|
}
|
|
245
|
+
validateRequestTarget(incomingUrl);
|
|
235
246
|
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
|
236
247
|
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
|
237
248
|
throw new RequestError("Invalid host header");
|
|
@@ -13,6 +13,15 @@ var RequestError = class extends Error {
|
|
|
13
13
|
this.name = "RequestError";
|
|
14
14
|
}
|
|
15
15
|
};
|
|
16
|
+
var validateRequestTarget = (target) => {
|
|
17
|
+
const backslash = target.indexOf("\\");
|
|
18
|
+
if (backslash !== -1) {
|
|
19
|
+
const query = target.indexOf("?");
|
|
20
|
+
if (query === -1 || backslash < query) {
|
|
21
|
+
throw new RequestError("Backslash in request path");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
16
25
|
var toRequestError = (e) => {
|
|
17
26
|
if (e instanceof RequestError) {
|
|
18
27
|
return e;
|
|
@@ -173,6 +182,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
173
182
|
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
|
174
183
|
}
|
|
175
184
|
try {
|
|
185
|
+
validateRequestTarget(incomingUrl);
|
|
176
186
|
const url2 = new URL(incomingUrl);
|
|
177
187
|
req[urlKey] = url2.href;
|
|
178
188
|
} catch (e) {
|
|
@@ -193,6 +203,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
193
203
|
} else {
|
|
194
204
|
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
|
195
205
|
}
|
|
206
|
+
validateRequestTarget(incomingUrl);
|
|
196
207
|
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
|
197
208
|
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
|
198
209
|
throw new RequestError("Invalid host header");
|
|
@@ -44,6 +44,15 @@ var RequestError = class extends Error {
|
|
|
44
44
|
this.name = "RequestError";
|
|
45
45
|
}
|
|
46
46
|
};
|
|
47
|
+
var validateRequestTarget = (target) => {
|
|
48
|
+
const backslash = target.indexOf("\\");
|
|
49
|
+
if (backslash !== -1) {
|
|
50
|
+
const query = target.indexOf("?");
|
|
51
|
+
if (query === -1 || backslash < query) {
|
|
52
|
+
throw new RequestError("Backslash in request path");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
47
56
|
var toRequestError = (e) => {
|
|
48
57
|
if (e instanceof RequestError) {
|
|
49
58
|
return e;
|
|
@@ -204,6 +213,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
204
213
|
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
|
205
214
|
}
|
|
206
215
|
try {
|
|
216
|
+
validateRequestTarget(incomingUrl);
|
|
207
217
|
const url2 = new URL(incomingUrl);
|
|
208
218
|
req[urlKey] = url2.href;
|
|
209
219
|
} catch (e) {
|
|
@@ -224,6 +234,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
224
234
|
} else {
|
|
225
235
|
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
|
226
236
|
}
|
|
237
|
+
validateRequestTarget(incomingUrl);
|
|
227
238
|
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
|
228
239
|
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
|
229
240
|
throw new RequestError("Invalid host header");
|
|
@@ -10,6 +10,15 @@ var RequestError = class extends Error {
|
|
|
10
10
|
this.name = "RequestError";
|
|
11
11
|
}
|
|
12
12
|
};
|
|
13
|
+
var validateRequestTarget = (target) => {
|
|
14
|
+
const backslash = target.indexOf("\\");
|
|
15
|
+
if (backslash !== -1) {
|
|
16
|
+
const query = target.indexOf("?");
|
|
17
|
+
if (query === -1 || backslash < query) {
|
|
18
|
+
throw new RequestError("Backslash in request path");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
13
22
|
var toRequestError = (e) => {
|
|
14
23
|
if (e instanceof RequestError) {
|
|
15
24
|
return e;
|
|
@@ -170,6 +179,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
170
179
|
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
|
171
180
|
}
|
|
172
181
|
try {
|
|
182
|
+
validateRequestTarget(incomingUrl);
|
|
173
183
|
const url2 = new URL(incomingUrl);
|
|
174
184
|
req[urlKey] = url2.href;
|
|
175
185
|
} catch (e) {
|
|
@@ -190,6 +200,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
190
200
|
} else {
|
|
191
201
|
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
|
192
202
|
}
|
|
203
|
+
validateRequestTarget(incomingUrl);
|
|
193
204
|
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
|
194
205
|
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
|
195
206
|
throw new RequestError("Invalid host header");
|
|
@@ -38,6 +38,15 @@ var RequestError = class extends Error {
|
|
|
38
38
|
this.name = "RequestError";
|
|
39
39
|
}
|
|
40
40
|
};
|
|
41
|
+
var validateRequestTarget = (target) => {
|
|
42
|
+
const backslash = target.indexOf("\\");
|
|
43
|
+
if (backslash !== -1) {
|
|
44
|
+
const query = target.indexOf("?");
|
|
45
|
+
if (query === -1 || backslash < query) {
|
|
46
|
+
throw new RequestError("Backslash in request path");
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
41
50
|
var toRequestError = (e) => {
|
|
42
51
|
if (e instanceof RequestError) {
|
|
43
52
|
return e;
|
|
@@ -198,6 +207,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
198
207
|
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
|
199
208
|
}
|
|
200
209
|
try {
|
|
210
|
+
validateRequestTarget(incomingUrl);
|
|
201
211
|
const url2 = new URL(incomingUrl);
|
|
202
212
|
req[urlKey] = url2.href;
|
|
203
213
|
} catch (e) {
|
|
@@ -218,6 +228,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
218
228
|
} else {
|
|
219
229
|
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
|
220
230
|
}
|
|
231
|
+
validateRequestTarget(incomingUrl);
|
|
221
232
|
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
|
222
233
|
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
|
223
234
|
throw new RequestError("Invalid host header");
|
|
@@ -7,6 +7,15 @@ var RequestError = class extends Error {
|
|
|
7
7
|
this.name = "RequestError";
|
|
8
8
|
}
|
|
9
9
|
};
|
|
10
|
+
var validateRequestTarget = (target) => {
|
|
11
|
+
const backslash = target.indexOf("\\");
|
|
12
|
+
if (backslash !== -1) {
|
|
13
|
+
const query = target.indexOf("?");
|
|
14
|
+
if (query === -1 || backslash < query) {
|
|
15
|
+
throw new RequestError("Backslash in request path");
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
10
19
|
var toRequestError = (e) => {
|
|
11
20
|
if (e instanceof RequestError) {
|
|
12
21
|
return e;
|
|
@@ -167,6 +176,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
167
176
|
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
|
168
177
|
}
|
|
169
178
|
try {
|
|
179
|
+
validateRequestTarget(incomingUrl);
|
|
170
180
|
const url2 = new URL(incomingUrl);
|
|
171
181
|
req[urlKey] = url2.href;
|
|
172
182
|
} catch (e) {
|
|
@@ -187,6 +197,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
187
197
|
} else {
|
|
188
198
|
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
|
189
199
|
}
|
|
200
|
+
validateRequestTarget(incomingUrl);
|
|
190
201
|
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
|
191
202
|
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
|
192
203
|
throw new RequestError("Invalid host header");
|
|
@@ -48,6 +48,15 @@ var RequestError = class extends Error {
|
|
|
48
48
|
this.name = "RequestError";
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
|
+
var validateRequestTarget = (target) => {
|
|
52
|
+
const backslash = target.indexOf("\\");
|
|
53
|
+
if (backslash !== -1) {
|
|
54
|
+
const query = target.indexOf("?");
|
|
55
|
+
if (query === -1 || backslash < query) {
|
|
56
|
+
throw new RequestError("Backslash in request path");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
};
|
|
51
60
|
var toRequestError = (e) => {
|
|
52
61
|
if (e instanceof RequestError) {
|
|
53
62
|
return e;
|
|
@@ -208,6 +217,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
208
217
|
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
|
209
218
|
}
|
|
210
219
|
try {
|
|
220
|
+
validateRequestTarget(incomingUrl);
|
|
211
221
|
const url2 = new URL(incomingUrl);
|
|
212
222
|
req[urlKey] = url2.href;
|
|
213
223
|
} catch (e) {
|
|
@@ -228,6 +238,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
228
238
|
} else {
|
|
229
239
|
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
|
230
240
|
}
|
|
241
|
+
validateRequestTarget(incomingUrl);
|
|
231
242
|
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
|
232
243
|
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
|
233
244
|
throw new RequestError("Invalid host header");
|
|
@@ -13,6 +13,15 @@ var RequestError = class extends Error {
|
|
|
13
13
|
this.name = "RequestError";
|
|
14
14
|
}
|
|
15
15
|
};
|
|
16
|
+
var validateRequestTarget = (target) => {
|
|
17
|
+
const backslash = target.indexOf("\\");
|
|
18
|
+
if (backslash !== -1) {
|
|
19
|
+
const query = target.indexOf("?");
|
|
20
|
+
if (query === -1 || backslash < query) {
|
|
21
|
+
throw new RequestError("Backslash in request path");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
16
25
|
var toRequestError = (e) => {
|
|
17
26
|
if (e instanceof RequestError) {
|
|
18
27
|
return e;
|
|
@@ -173,6 +182,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
173
182
|
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
|
174
183
|
}
|
|
175
184
|
try {
|
|
185
|
+
validateRequestTarget(incomingUrl);
|
|
176
186
|
const url2 = new URL(incomingUrl);
|
|
177
187
|
req[urlKey] = url2.href;
|
|
178
188
|
} catch (e) {
|
|
@@ -193,6 +203,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
193
203
|
} else {
|
|
194
204
|
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
|
195
205
|
}
|
|
206
|
+
validateRequestTarget(incomingUrl);
|
|
196
207
|
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
|
197
208
|
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
|
198
209
|
throw new RequestError("Invalid host header");
|
|
@@ -46,6 +46,15 @@ var RequestError = class extends Error {
|
|
|
46
46
|
this.name = "RequestError";
|
|
47
47
|
}
|
|
48
48
|
};
|
|
49
|
+
var validateRequestTarget = (target) => {
|
|
50
|
+
const backslash = target.indexOf("\\");
|
|
51
|
+
if (backslash !== -1) {
|
|
52
|
+
const query = target.indexOf("?");
|
|
53
|
+
if (query === -1 || backslash < query) {
|
|
54
|
+
throw new RequestError("Backslash in request path");
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
49
58
|
var toRequestError = (e) => {
|
|
50
59
|
if (e instanceof RequestError) {
|
|
51
60
|
return e;
|
|
@@ -206,6 +215,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
206
215
|
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
|
207
216
|
}
|
|
208
217
|
try {
|
|
218
|
+
validateRequestTarget(incomingUrl);
|
|
209
219
|
const url2 = new URL(incomingUrl);
|
|
210
220
|
req[urlKey] = url2.href;
|
|
211
221
|
} catch (e) {
|
|
@@ -226,6 +236,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
226
236
|
} else {
|
|
227
237
|
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
|
228
238
|
}
|
|
239
|
+
validateRequestTarget(incomingUrl);
|
|
229
240
|
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
|
230
241
|
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
|
231
242
|
throw new RequestError("Invalid host header");
|
|
@@ -10,6 +10,15 @@ var RequestError = class extends Error {
|
|
|
10
10
|
this.name = "RequestError";
|
|
11
11
|
}
|
|
12
12
|
};
|
|
13
|
+
var validateRequestTarget = (target) => {
|
|
14
|
+
const backslash = target.indexOf("\\");
|
|
15
|
+
if (backslash !== -1) {
|
|
16
|
+
const query = target.indexOf("?");
|
|
17
|
+
if (query === -1 || backslash < query) {
|
|
18
|
+
throw new RequestError("Backslash in request path");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
13
22
|
var toRequestError = (e) => {
|
|
14
23
|
if (e instanceof RequestError) {
|
|
15
24
|
return e;
|
|
@@ -170,6 +179,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
170
179
|
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
|
171
180
|
}
|
|
172
181
|
try {
|
|
182
|
+
validateRequestTarget(incomingUrl);
|
|
173
183
|
const url2 = new URL(incomingUrl);
|
|
174
184
|
req[urlKey] = url2.href;
|
|
175
185
|
} catch (e) {
|
|
@@ -190,6 +200,7 @@ var newRequest = (incoming, defaultHostname) => {
|
|
|
190
200
|
} else {
|
|
191
201
|
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
|
192
202
|
}
|
|
203
|
+
validateRequestTarget(incomingUrl);
|
|
193
204
|
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
|
194
205
|
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
|
195
206
|
throw new RequestError("Invalid host header");
|
|
@@ -343,7 +343,9 @@ results. Results survive MCP restart. One call to the service may take
|
|
|
343
343
|
`RHO_TRANSPORT_MS` (30 s), plus the `waitMs` it asks the service to wait (at most ten
|
|
344
344
|
minutes, as for a Notebook cell); the call uses `node:http`, whose wait for a reply has
|
|
345
345
|
no limit of its own. A transport overrun keeps the outcome uncertain and directs
|
|
346
|
-
observation of the original identity, never replacement work.
|
|
346
|
+
observation of the original identity, never replacement work. A refused connection is the one
|
|
347
|
+
transport failure whose outcome is known: nothing reached the service, so the call
|
|
348
|
+
returns `unavailable` naming the address and saying nothing ran (`delivered: false`).
|
|
347
349
|
|
|
348
350
|
The pure `./layered-contract` entry defines the four tool inputs and Agent note
|
|
349
351
|
props. `./layered` provides the bounded complete-object cache and caller checks;
|
|
@@ -195,10 +195,21 @@ export class AcpConversation {
|
|
|
195
195
|
let model;
|
|
196
196
|
this.observationOrigin = this.sessionId ? 'history' : 'initial';
|
|
197
197
|
if (this.sessionId) {
|
|
198
|
-
|
|
198
|
+
const caps = initialized.agentCapabilities;
|
|
199
|
+
if (caps?.loadSession) {
|
|
200
|
+
const loaded = await connection.agent.request(acp.methods.agent.session.load, { ...params, sessionId: this.sessionId });
|
|
201
|
+
this.settings = loaded.configOptions ?? [];
|
|
202
|
+
}
|
|
203
|
+
else if (caps?.sessionCapabilities?.resume) {
|
|
204
|
+
// ACP session/resume (e.g. dsh): restore the persisted session on a fresh process. It composes
|
|
205
|
+
// the request's MCP connections and validates only the workspace, so the non-standard
|
|
206
|
+
// systemPrompt is omitted; history is restored from the Agent's own persistence, not replayed.
|
|
207
|
+
const resumed = await connection.agent.request(acp.methods.agent.session.resume, { cwd: o.cwd, mcpServers: o.mcpServers, sessionId: this.sessionId });
|
|
208
|
+
this.settings = resumed?.configOptions ?? [];
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
199
211
|
throw new Error('This Agent cannot load the original session. Nothing was resent.');
|
|
200
|
-
|
|
201
|
-
this.settings = loaded.configOptions ?? [];
|
|
212
|
+
}
|
|
202
213
|
}
|
|
203
214
|
else {
|
|
204
215
|
const created = await connection.agent.request(acp.methods.agent.session.new, params);
|
|
@@ -123,5 +123,6 @@ export declare function visibleError(error: unknown, env?: NodeJS.ProcessEnv): s
|
|
|
123
123
|
export { ClaudeAcpConversation, type ClaudeAcpOptions } from './claude-acp.js';
|
|
124
124
|
export { writeClaudePlugin, claudePluginLimits, type ClaudePlugin, type ClaudePluginSkill, type ClaudePluginHook } from './claude-plugin.js';
|
|
125
125
|
export { CodexAcpConversation, type CodexAcpOptions } from './codex-acp.js';
|
|
126
|
+
export { GenericAcpConversation, type GenericAcpOptions } from './generic-acp.js';
|
|
126
127
|
export { ClaudeCliConversation } from './claude-cli.js';
|
|
127
128
|
export type { SessionObservation, SessionTool, ConfigOption, ConfigValue } from './session-observation.js';
|
|
@@ -25,4 +25,5 @@ export function visibleError(error, env = process.env) {
|
|
|
25
25
|
export { ClaudeAcpConversation } from './claude-acp.js';
|
|
26
26
|
export { writeClaudePlugin, claudePluginLimits } from './claude-plugin.js';
|
|
27
27
|
export { CodexAcpConversation } from './codex-acp.js';
|
|
28
|
+
export { GenericAcpConversation } from './generic-acp.js';
|
|
28
29
|
export { ClaudeCliConversation } from './claude-cli.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AcpConversation, type AcpConversationOptions } from './acp-conversation.js';
|
|
2
|
+
/** A generic ACP agent: any program that speaks ACP v1 over stdio. Rho starts the
|
|
3
|
+
* operator-selected command and drives it exactly as it drives Claude Code or Codex, so
|
|
4
|
+
* supporting another agent is configuration (`--acp-command`), not a new adapter. The
|
|
5
|
+
* command is a file plus its arguments and needs no per-agent environment. */
|
|
6
|
+
export interface GenericAcpOptions extends Omit<AcpConversationOptions, 'command' | 'sessionMeta'> {
|
|
7
|
+
command: AcpConversationOptions['command'];
|
|
8
|
+
}
|
|
9
|
+
export declare class GenericAcpConversation extends AcpConversation {
|
|
10
|
+
constructor(o: GenericAcpOptions);
|
|
11
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { AcpConversation } from './acp-conversation.js';
|
|
2
|
+
export class GenericAcpConversation extends AcpConversation {
|
|
3
|
+
constructor(o) {
|
|
4
|
+
// A supplied command skips the missing-client check: the operator named the program.
|
|
5
|
+
super({ ...o, command: o.command });
|
|
6
|
+
}
|
|
7
|
+
}
|
|
@@ -36,7 +36,11 @@ async function invoke(method, input = {}, contractRef) {
|
|
|
36
36
|
const response = await new Promise((resolve, reject) => {
|
|
37
37
|
const request = http.request(new URL('/api/v2/' + method, endpoint), { method: 'POST', signal: AbortSignal.timeout(allowance(input)),
|
|
38
38
|
headers: { authorization: 'Bearer ' + c.token, 'content-type': 'application/json', 'content-length': Buffer.byteLength(body), ...(contractRef ? { 'x-rho-contract-ref': contractRef } : {}) } }, resolve);
|
|
39
|
-
|
|
39
|
+
// A refused connection is the one failure whose outcome is known: nothing reached the
|
|
40
|
+
// service, so nothing ran. It is usually Rho not running, and the person can start it.
|
|
41
|
+
request.once('error', error => reject(error.code === 'ECONNREFUSED'
|
|
42
|
+
? new Fault('unavailable', `Rho is not running at ${c.url}, so this call did not reach it and nothing ran. Ask the person to start Rho, then call again.`, { url: c.url, delivered: false })
|
|
43
|
+
: error));
|
|
40
44
|
request.end(body);
|
|
41
45
|
});
|
|
42
46
|
const chunks = [];
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"@rho-workspace/plugin-contracts": "0.4.0"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
|
-
"@rho-workspace/plugin-documents": "0.4.1 || 0.4.2 || 0.4.3 || 0.4.4 || 0.4.5 || 0.4.6 || 0.4.7 || 0.4.8 || 0.4.9 || 0.4.10",
|
|
26
|
+
"@rho-workspace/plugin-documents": "0.4.1 || 0.4.2 || 0.4.3 || 0.4.4 || 0.4.5 || 0.4.6 || 0.4.7 || 0.4.8 || 0.4.9 || 0.4.10 || 0.4.11",
|
|
27
27
|
"react": "19.3.1",
|
|
28
28
|
"react-dom": "19.3.1"
|
|
29
29
|
},
|
|
@@ -157,3 +157,7 @@ Documents 0.4.7 adds a confirmed-text selection callback for Review and an optio
|
|
|
157
157
|
excerpt, reads at most 1 MiB per version and previews at most 64 KiB without cutting
|
|
158
158
|
a Unicode sequence. Buffer snapshots continue to identify their version/dirty
|
|
159
159
|
state separately from disk captures. No comparison rewrites a buffer or its undo.
|
|
160
|
+
|
|
161
|
+
Documents 0.4.11 lets the editor view (`rho.editor`) keep a boolean `flow` beside its
|
|
162
|
+
`title`: an application that shows a script's data flow beside the editor saves the person's
|
|
163
|
+
switch with the page. The buffer, its undo and its saves are unchanged by it.
|
|
@@ -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.
|