@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
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Opens a page in a real browser at each viewport and reports what it shows: whether it scrolls
|
|
3
|
+
// sideways, the elements that cross the right edge, unnamed buttons, overlapping boxes of a selector,
|
|
4
|
+
// page and console errors, requests that leave the page, and a screenshot per viewport. It reports
|
|
5
|
+
// what the page does; it does not judge the design, and it changes nothing on the page.
|
|
6
|
+
//
|
|
7
|
+
// rho-screen-check <url or page.html> [--viewport WxH]... [--out DIR] [--overlap SELECTOR]
|
|
8
|
+
// [--full-page] [--settle MS] [--browser auto|chrome|msedge|chromium|PATH]
|
|
9
|
+
//
|
|
10
|
+
// Prints the report as JSON and writes it to DIR/report.json (default ./screen-check).
|
|
11
|
+
// Exit status: 0 the check ran (its findings are in the report); 1 an argument was wrong;
|
|
12
|
+
// 2 the check did not run (error.kind, error.message and error.next say why and what to do).
|
|
13
|
+
import fs from 'node:fs/promises';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import { pathToFileURL } from 'node:url';
|
|
16
|
+
import { parseArgs } from 'node:util';
|
|
17
|
+
import { chromium } from 'playwright-core';
|
|
18
|
+
import { pageFindings, viewports } from './browser-checks.mjs';
|
|
19
|
+
|
|
20
|
+
class CheckError extends Error {
|
|
21
|
+
constructor(kind, message, next) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.kind = kind;
|
|
24
|
+
this.next = next;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const usage = `Usage: rho-screen-check <url or page.html> [options]
|
|
29
|
+
|
|
30
|
+
Options:
|
|
31
|
+
--viewport WxH a viewport to check, repeatable
|
|
32
|
+
(default 1440x900, 1024x768, 768x1024, 390x844)
|
|
33
|
+
--out DIR folder for the screenshots and report.json (default ./screen-check)
|
|
34
|
+
--overlap SELECTOR report pairs of visible boxes matching SELECTOR that overlap
|
|
35
|
+
--full-page screenshot the whole page, not only the window
|
|
36
|
+
--settle MS wait after load before measuring (default 800)
|
|
37
|
+
--browser NAME auto (default: Chrome, then Edge, then Playwright's Chromium), chrome,
|
|
38
|
+
msedge, chromium, or the path of a Chromium-based browser
|
|
39
|
+
-h, --help show this help
|
|
40
|
+
|
|
41
|
+
Prints the report as JSON on stdout and writes it to DIR/report.json.
|
|
42
|
+
Exit status: 0 the check ran; 1 an argument was wrong; 2 the check did not run.
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
const firstLine = error => String(error?.message ?? error).split('\n')[0].slice(0, 300);
|
|
46
|
+
|
|
47
|
+
function parseSize(text) {
|
|
48
|
+
const match = /^(\d{3,4})x(\d{3,4})$/.exec(text);
|
|
49
|
+
const width = match ? Number(match[1]) : 0;
|
|
50
|
+
const height = match ? Number(match[2]) : 0;
|
|
51
|
+
if (!match || width < 200 || width > 3840 || height < 200 || height > 2400) {
|
|
52
|
+
throw new CheckError('usage', `Viewport "${text}" is not WIDTHxHEIGHT, between 200 and 3840 wide and 200 and 2400 high.`, 'Use a form such as --viewport 390x844.');
|
|
53
|
+
}
|
|
54
|
+
return [width, height];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function targetOf(text) {
|
|
58
|
+
if (/^https?:\/\//i.test(text)) {
|
|
59
|
+
try {
|
|
60
|
+
return new URL(text);
|
|
61
|
+
} catch {
|
|
62
|
+
throw new CheckError('usage', `"${text}" is not a valid address.`, 'Give the full address, such as http://127.0.0.1:8080/.');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const file = path.resolve(text);
|
|
66
|
+
try {
|
|
67
|
+
await fs.access(file);
|
|
68
|
+
} catch {
|
|
69
|
+
throw new CheckError('usage', `There is no file at ${file}.`, 'Give the path of an HTML file, or an address that starts with http:// or https://.');
|
|
70
|
+
}
|
|
71
|
+
return new URL(pathToFileURL(file).href);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// The report names the page without its query, fragment or credentials: a token in an address stays out of the output.
|
|
75
|
+
function shownTarget(url) {
|
|
76
|
+
const copy = new URL(url.href);
|
|
77
|
+
copy.username = '';
|
|
78
|
+
copy.password = '';
|
|
79
|
+
copy.search = '';
|
|
80
|
+
copy.hash = '';
|
|
81
|
+
return copy.href;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function launchBrowser(choice) {
|
|
85
|
+
const names = choice === 'auto' ? ['chrome', 'msedge', 'chromium'] : [choice];
|
|
86
|
+
const attempts = [];
|
|
87
|
+
for (const name of names) {
|
|
88
|
+
const options = { headless: true };
|
|
89
|
+
if (name === 'chrome' || name === 'msedge') options.channel = name;
|
|
90
|
+
else if (name !== 'chromium') options.executablePath = name;
|
|
91
|
+
try {
|
|
92
|
+
return { browser: await chromium.launch(options), name };
|
|
93
|
+
} catch (error) {
|
|
94
|
+
attempts.push(`${name}: ${firstLine(error)}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
throw new CheckError('browser_missing', `No browser could be started. ${attempts.join(' | ')}`, 'Install Google Chrome or Microsoft Edge, or pass --browser with the path of an installed Chromium-based browser; then run the check again.');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function checkViewport(browser, target, [width, height], out, settle, values) {
|
|
101
|
+
const context = await browser.newContext({ viewport: { width, height } });
|
|
102
|
+
try {
|
|
103
|
+
const page = await context.newPage();
|
|
104
|
+
const pageErrors = [];
|
|
105
|
+
const consoleErrors = [];
|
|
106
|
+
const outside = new Set();
|
|
107
|
+
page.on('pageerror', error => pageErrors.push(firstLine(error)));
|
|
108
|
+
page.on('console', message => { if (message.type() === 'error') consoleErrors.push(message.text().slice(0, 300)); });
|
|
109
|
+
page.on('request', request => {
|
|
110
|
+
const url = new URL(request.url());
|
|
111
|
+
if ((url.protocol === 'http:' || url.protocol === 'https:') && url.origin !== target.origin) outside.add(url.origin + url.pathname);
|
|
112
|
+
});
|
|
113
|
+
const httpErrors = new Map();
|
|
114
|
+
page.on('response', response => {
|
|
115
|
+
if (response.status() < 400) return;
|
|
116
|
+
const url = new URL(response.url()), address = url.origin + url.pathname;
|
|
117
|
+
httpErrors.set(`${response.status()} ${address}`, { status: response.status(), url: address });
|
|
118
|
+
});
|
|
119
|
+
try {
|
|
120
|
+
await page.goto(target.href, { waitUntil: 'load', timeout: 30000 });
|
|
121
|
+
} catch (error) {
|
|
122
|
+
throw new CheckError('unreachable', `The page did not load: ${firstLine(error)}`, 'Check the address, that the service is running or the file exists, and that the page opens in a browser; then run the check again.');
|
|
123
|
+
}
|
|
124
|
+
await page.waitForTimeout(settle);
|
|
125
|
+
const findings = await pageFindings(page, { selector: values.overlap ?? null });
|
|
126
|
+
const screenshot = path.join(out, `${width}x${height}.png`);
|
|
127
|
+
await page.screenshot({ path: screenshot, fullPage: Boolean(values['full-page']) });
|
|
128
|
+
return {
|
|
129
|
+
viewport: `${width}x${height}`, screenshot, ...findings,
|
|
130
|
+
pageErrors, consoleErrors,
|
|
131
|
+
httpErrors: [...httpErrors.values()].slice(0, 20), httpErrorsTotal: httpErrors.size,
|
|
132
|
+
requestsOutsideTarget: [...outside].slice(0, 20), requestsOutsideTargetTotal: outside.size,
|
|
133
|
+
};
|
|
134
|
+
} finally {
|
|
135
|
+
await context.close();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function main(argv) {
|
|
140
|
+
let parsed;
|
|
141
|
+
try {
|
|
142
|
+
parsed = parseArgs({
|
|
143
|
+
args: argv,
|
|
144
|
+
allowPositionals: true,
|
|
145
|
+
options: {
|
|
146
|
+
viewport: { type: 'string', multiple: true },
|
|
147
|
+
out: { type: 'string' },
|
|
148
|
+
overlap: { type: 'string' },
|
|
149
|
+
'full-page': { type: 'boolean' },
|
|
150
|
+
settle: { type: 'string' },
|
|
151
|
+
browser: { type: 'string' },
|
|
152
|
+
help: { type: 'boolean', short: 'h' },
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
} catch (error) {
|
|
156
|
+
throw new CheckError('usage', firstLine(error), 'Run rho-screen-check --help to see the options.');
|
|
157
|
+
}
|
|
158
|
+
const { values, positionals } = parsed;
|
|
159
|
+
if (values.help) {
|
|
160
|
+
process.stdout.write(usage);
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
if (positionals.length !== 1) throw new CheckError('usage', 'Give exactly one page: a URL or an HTML file.', 'Run rho-screen-check --help to see the forms.');
|
|
164
|
+
const target = await targetOf(positionals[0]);
|
|
165
|
+
const sizes = values.viewport?.length ? values.viewport.map(parseSize) : viewports;
|
|
166
|
+
const settle = values.settle === undefined ? 800 : Number(values.settle);
|
|
167
|
+
if (!Number.isInteger(settle) || settle < 0 || settle > 10000) throw new CheckError('usage', `--settle must be a whole number of milliseconds from 0 to 10000, not "${values.settle}".`, 'Use a form such as --settle 800.');
|
|
168
|
+
const out = path.resolve(values.out ?? 'screen-check');
|
|
169
|
+
await fs.mkdir(out, { recursive: true });
|
|
170
|
+
const { browser, name } = await launchBrowser(values.browser ?? 'auto');
|
|
171
|
+
try {
|
|
172
|
+
const reports = [];
|
|
173
|
+
for (const size of sizes) reports.push(await checkViewport(browser, target, size, out, settle, values));
|
|
174
|
+
const report = { tool: 'rho-screen-check', target: shownTarget(target), browser: name, checkedAt: new Date().toISOString(), viewports: reports };
|
|
175
|
+
const file = path.join(out, 'report.json');
|
|
176
|
+
await fs.writeFile(file, JSON.stringify(report, null, 2) + '\n');
|
|
177
|
+
process.stdout.write(JSON.stringify({ ok: true, ...report, report: file }, null, 2) + '\n');
|
|
178
|
+
return 0;
|
|
179
|
+
} finally {
|
|
180
|
+
await browser.close();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
process.exitCode = await main(process.argv.slice(2));
|
|
186
|
+
} catch (error) {
|
|
187
|
+
const usageError = error instanceof CheckError && error.kind === 'usage';
|
|
188
|
+
const detail = error instanceof CheckError
|
|
189
|
+
? { kind: error.kind, message: error.message, next: error.next }
|
|
190
|
+
: { kind: 'failed', message: firstLine(error), next: 'Run the check again. If it fails the same way, open the page in a browser and read what it shows.' };
|
|
191
|
+
process.stdout.write(JSON.stringify({ ok: false, error: detail }, null, 2) + '\n');
|
|
192
|
+
process.exitCode = usageError ? 1 : 2;
|
|
193
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// An opt-in, real scientific episode. R packages must already be available;
|
|
3
|
+
// this script never installs dependencies or touches an existing R session.
|
|
4
|
+
import fs from 'node:fs/promises';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
import assert from 'node:assert/strict';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
import { RhoService } from '../dist/server.js';
|
|
10
|
+
import { RhoClient } from '../dist/client.js';
|
|
11
|
+
|
|
12
|
+
const repo = fileURLToPath(new URL('../', import.meta.url));
|
|
13
|
+
const source = process.env.RHO_SCLET_PLUGIN ?? path.resolve(repo, '../Rho-plugins/examples/sclet-plugin');
|
|
14
|
+
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'rho-third-party-'));
|
|
15
|
+
await fs.mkdir(path.join(root, 'project'));
|
|
16
|
+
const service = await new RhoService({ root, stateDir: path.join(root, 'state'), rscript: process.env.RHO_RSCRIPT ?? 'Rscript', example: false }).start();
|
|
17
|
+
const client = new RhoClient({ url: service.url, token: service.adminToken });
|
|
18
|
+
const project = await client.call('project.open', { path: 'project' });
|
|
19
|
+
const notes = [];
|
|
20
|
+
let sequence = 0;
|
|
21
|
+
const text = cell => cell.outputs.map(output => output.text ?? '').join('\n') + (cell.error ? '\n' + JSON.stringify(cell.error) : '');
|
|
22
|
+
const json = value => JSON.parse(value.slice(value.indexOf('{'), value.lastIndexOf('}') + 1));
|
|
23
|
+
async function finished(cell) {
|
|
24
|
+
for (let i = 0; i < 600; i++) {
|
|
25
|
+
const current = (await client.call('kernel.read', { projectId: project.id, cellId: cell.cellId })).cells[0];
|
|
26
|
+
if (['done', 'error', 'unknown', 'interrupted'].includes(current.state)) return current;
|
|
27
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
28
|
+
}
|
|
29
|
+
throw new Error('Observation deadline reached; original cell: ' + cell.cellId);
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const plugin = await client.call('extension.install', { source });
|
|
33
|
+
const invoke = (operation, input = {}, changeId = 'acceptance-' + ++sequence) => client.call('extension.call', { projectId: project.id, pluginId: plugin.id, expectedDigest: plugin.digest, operation, input, changeId });
|
|
34
|
+
assert.deepEqual((await invoke('sessions')).value.sessions, []);
|
|
35
|
+
async function run(operation, input = {}) {
|
|
36
|
+
const receipt = await invoke(operation, input); assert.equal(receipt.state, 'completed', receipt.error);
|
|
37
|
+
const cell = await finished(receipt.value.cell); notes.push({ operation, cellId: cell.cellId, state: cell.state });
|
|
38
|
+
assert.equal(cell.state, 'done', text(cell)); return { receipt, cell, text: text(cell) };
|
|
39
|
+
}
|
|
40
|
+
const library = process.env.RHO_SCLET_LIBRARY;
|
|
41
|
+
const seedCode = `${library ? '.libPaths(c(' + JSON.stringify(library) + ', .libPaths()))\n' : ''}if (!requireNamespace("sclet", quietly=TRUE)) stop("Set RHO_SCLET_LIBRARY to an existing sclet library.")\nset.seed(19)\nsce <- scuttle::mockSCE(ncells=60, ngenes=200)`;
|
|
42
|
+
const seed = await client.call('kernel.run', { projectId: project.id, language: 'r', code: seedCode, purpose: 'Disposable third-party plugin trial', changeId: 'seed', waitMs: 0 });
|
|
43
|
+
const seeded = await finished(seed.cell); assert.equal(seeded.state, 'done', text(seeded));
|
|
44
|
+
const packages = await run('check');
|
|
45
|
+
const before = json((await run('ledger', { object: 'sce', includeArtifacts: true })).text);
|
|
46
|
+
await run('registry', { object: 'sce' }); await run('skill', { name: 'sclet-driver' });
|
|
47
|
+
const plan = { task: 'plugin-acceptance', context_fingerprint: before.fingerprint, actions: [
|
|
48
|
+
{ id: 'normalize', action: 'normalize_data' },
|
|
49
|
+
{ id: 'hvg', action: 'find_variable_features', params: { nfeatures: 50 }, depends_on: 'normalize' },
|
|
50
|
+
{ id: 'scale', action: 'scale_data', depends_on: 'hvg' },
|
|
51
|
+
{ id: 'pca', action: 'run_pca', params: { ncomponents: 5 }, depends_on: 'scale' },
|
|
52
|
+
] };
|
|
53
|
+
const validated = json((await run('validate', { object: 'sce', plan })).text); assert.equal(validated.validation.valid, true);
|
|
54
|
+
const executeBody = { validationId: validated.validationId };
|
|
55
|
+
const execution = await invoke('execute', executeBody, 'execute-once'); assert.equal(execution.state, 'completed', execution.error);
|
|
56
|
+
const executed = await finished(execution.value.cell); assert.equal(executed.state, 'done', text(executed));
|
|
57
|
+
assert.equal(json(text(executed)).status, 'completed');
|
|
58
|
+
assert.equal((await invoke('execute', executeBody, 'execute-once')).value.cell.cellId, executed.cellId);
|
|
59
|
+
await run('record', { object: 'sce', recordId: 'smoke-report', result: {
|
|
60
|
+
task: 'plugin-acceptance', answer: 'A synthetic 200-gene, 60-cell input completed normalization, variable feature selection, scaling and PCA. This verifies software integration; no biological conclusion is claimed.',
|
|
61
|
+
findings: [], evidence: [], warnings: ['Synthetic input, not evidence for a biological hypothesis.'], recommendations: [], proposed_actions: [], success_criteria: [], stop_conditions: [], context: { fingerprint: json(text(executed)).fingerprint }, metadata: { provider: 'integration-test' },
|
|
62
|
+
} });
|
|
63
|
+
const report = await run('report', { object: 'sce', recordId: 'smoke-report' }); assert.match(report.text, /all checks passed/);
|
|
64
|
+
const after = json((await run('ledger', { object: 'sce', includeArtifacts: true })).text);
|
|
65
|
+
assert.equal(after.dataset.reductions, 'PCA'); assert.equal(after.features.hvg.n, 50);
|
|
66
|
+
assert.equal(json((await run('validate', { object: 'sce', plan })).text).validation.valid, false);
|
|
67
|
+
await client.call('extension.manage', { pluginId: plugin.id, expectedDigest: plugin.digest, action: 'disable' });
|
|
68
|
+
await assert.rejects(invoke('ledger', { object: 'sce' }), /disabled/);
|
|
69
|
+
await client.call('extension.manage', { pluginId: plugin.id, expectedDigest: plugin.digest, action: 'remove' });
|
|
70
|
+
assert.equal((await invoke('execute', executeBody, 'execute-once')).value.cell.cellId, executed.cellId);
|
|
71
|
+
const sessions = await client.call('kernel.read', { projectId: project.id, limit: 1 });
|
|
72
|
+
assert.ok(sessions.sessions.some(s => s.sessionId === seed.cell.sessionId && s.state !== 'ended'));
|
|
73
|
+
const output = path.resolve(process.env.RHO_THIRD_PARTY_OUTPUT ?? path.join(repo, 'output/third-party-plugins/acceptance.json'));
|
|
74
|
+
await fs.mkdir(path.dirname(output), { recursive: true });
|
|
75
|
+
await fs.writeFile(output, JSON.stringify({ at: new Date().toISOString(), node: process.version, platform: process.platform, source, digest: plugin.digest, packages: packages.text, notes, execution: json(text(executed)), report: report.text, lifecycle: 'disable/remove retained original cell and live R session', passed: true }, null, 2) + '\n');
|
|
76
|
+
console.log(JSON.stringify({ passed: true, output }));
|
|
77
|
+
} finally { await service.close(); await fs.rm(root, { recursive: true, force: true }); }
|