@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
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
{
|
|
18
18
|
"enum": [
|
|
19
19
|
"claude-acp",
|
|
20
|
-
"codex-acp"
|
|
20
|
+
"codex-acp",
|
|
21
|
+
"acp"
|
|
21
22
|
]
|
|
22
23
|
},
|
|
23
24
|
{
|
|
@@ -66,6 +67,25 @@
|
|
|
66
67
|
}
|
|
67
68
|
]
|
|
68
69
|
}
|
|
70
|
+
},
|
|
71
|
+
"acp": {
|
|
72
|
+
"type": "object",
|
|
73
|
+
"maxProperties": 12,
|
|
74
|
+
"propertyNames": {
|
|
75
|
+
"maxLength": 512
|
|
76
|
+
},
|
|
77
|
+
"additionalProperties": {
|
|
78
|
+
"anyOf": [
|
|
79
|
+
{
|
|
80
|
+
"type": "string",
|
|
81
|
+
"minLength": 1,
|
|
82
|
+
"maxLength": 512
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"type": "boolean"
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
}
|
|
69
89
|
}
|
|
70
90
|
},
|
|
71
91
|
"required": []
|
|
@@ -111,7 +131,8 @@
|
|
|
111
131
|
{
|
|
112
132
|
"enum": [
|
|
113
133
|
"claude-acp",
|
|
114
|
-
"codex-acp"
|
|
134
|
+
"codex-acp",
|
|
135
|
+
"acp"
|
|
115
136
|
]
|
|
116
137
|
},
|
|
117
138
|
{
|
|
@@ -123,7 +144,8 @@
|
|
|
123
144
|
"enum": [
|
|
124
145
|
"claude-acp",
|
|
125
146
|
"codex-acp",
|
|
126
|
-
"claude-cli"
|
|
147
|
+
"claude-cli",
|
|
148
|
+
"acp"
|
|
127
149
|
]
|
|
128
150
|
},
|
|
129
151
|
"choices": {
|
|
@@ -166,6 +188,25 @@
|
|
|
166
188
|
}
|
|
167
189
|
]
|
|
168
190
|
}
|
|
191
|
+
},
|
|
192
|
+
"acp": {
|
|
193
|
+
"type": "object",
|
|
194
|
+
"maxProperties": 12,
|
|
195
|
+
"propertyNames": {
|
|
196
|
+
"maxLength": 512
|
|
197
|
+
},
|
|
198
|
+
"additionalProperties": {
|
|
199
|
+
"anyOf": [
|
|
200
|
+
{
|
|
201
|
+
"type": "string",
|
|
202
|
+
"minLength": 1,
|
|
203
|
+
"maxLength": 512
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
"type": "boolean"
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
}
|
|
169
210
|
}
|
|
170
211
|
},
|
|
171
212
|
"required": [],
|
|
@@ -413,6 +454,126 @@
|
|
|
413
454
|
"omitted"
|
|
414
455
|
],
|
|
415
456
|
"additionalProperties": true
|
|
457
|
+
},
|
|
458
|
+
"acp": {
|
|
459
|
+
"type": "object",
|
|
460
|
+
"properties": {
|
|
461
|
+
"at": {
|
|
462
|
+
"type": "string",
|
|
463
|
+
"minLength": 1
|
|
464
|
+
},
|
|
465
|
+
"source": {
|
|
466
|
+
"enum": [
|
|
467
|
+
"check",
|
|
468
|
+
"conversation"
|
|
469
|
+
]
|
|
470
|
+
},
|
|
471
|
+
"adapter": {
|
|
472
|
+
"anyOf": [
|
|
473
|
+
{
|
|
474
|
+
"type": "object",
|
|
475
|
+
"properties": {
|
|
476
|
+
"name": {
|
|
477
|
+
"type": "string",
|
|
478
|
+
"minLength": 1
|
|
479
|
+
},
|
|
480
|
+
"version": {
|
|
481
|
+
"type": "string",
|
|
482
|
+
"minLength": 1
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
"required": [
|
|
486
|
+
"name"
|
|
487
|
+
],
|
|
488
|
+
"additionalProperties": true
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
"type": "null"
|
|
492
|
+
}
|
|
493
|
+
]
|
|
494
|
+
},
|
|
495
|
+
"options": {
|
|
496
|
+
"type": "array",
|
|
497
|
+
"items": {
|
|
498
|
+
"additionalProperties": false,
|
|
499
|
+
"properties": {
|
|
500
|
+
"category": {
|
|
501
|
+
"type": "string"
|
|
502
|
+
},
|
|
503
|
+
"current": {
|
|
504
|
+
"anyOf": [
|
|
505
|
+
{
|
|
506
|
+
"type": "string"
|
|
507
|
+
},
|
|
508
|
+
{
|
|
509
|
+
"type": "boolean"
|
|
510
|
+
}
|
|
511
|
+
]
|
|
512
|
+
},
|
|
513
|
+
"description": {
|
|
514
|
+
"type": "string"
|
|
515
|
+
},
|
|
516
|
+
"id": {
|
|
517
|
+
"type": "string"
|
|
518
|
+
},
|
|
519
|
+
"name": {
|
|
520
|
+
"type": "string"
|
|
521
|
+
},
|
|
522
|
+
"type": {
|
|
523
|
+
"enum": [
|
|
524
|
+
"select",
|
|
525
|
+
"boolean"
|
|
526
|
+
]
|
|
527
|
+
},
|
|
528
|
+
"values": {
|
|
529
|
+
"items": {
|
|
530
|
+
"additionalProperties": false,
|
|
531
|
+
"properties": {
|
|
532
|
+
"description": {
|
|
533
|
+
"type": "string"
|
|
534
|
+
},
|
|
535
|
+
"group": {
|
|
536
|
+
"type": "string"
|
|
537
|
+
},
|
|
538
|
+
"name": {
|
|
539
|
+
"type": "string"
|
|
540
|
+
},
|
|
541
|
+
"value": {
|
|
542
|
+
"type": "string"
|
|
543
|
+
}
|
|
544
|
+
},
|
|
545
|
+
"required": [
|
|
546
|
+
"value",
|
|
547
|
+
"name"
|
|
548
|
+
],
|
|
549
|
+
"type": "object"
|
|
550
|
+
},
|
|
551
|
+
"maxItems": 256,
|
|
552
|
+
"type": "array"
|
|
553
|
+
}
|
|
554
|
+
},
|
|
555
|
+
"required": [
|
|
556
|
+
"id",
|
|
557
|
+
"name",
|
|
558
|
+
"type",
|
|
559
|
+
"current"
|
|
560
|
+
],
|
|
561
|
+
"type": "object"
|
|
562
|
+
}
|
|
563
|
+
},
|
|
564
|
+
"omitted": {
|
|
565
|
+
"type": "integer",
|
|
566
|
+
"minimum": 0
|
|
567
|
+
}
|
|
568
|
+
},
|
|
569
|
+
"required": [
|
|
570
|
+
"at",
|
|
571
|
+
"source",
|
|
572
|
+
"adapter",
|
|
573
|
+
"options",
|
|
574
|
+
"omitted"
|
|
575
|
+
],
|
|
576
|
+
"additionalProperties": true
|
|
416
577
|
}
|
|
417
578
|
},
|
|
418
579
|
"required": [],
|
|
@@ -423,7 +584,8 @@
|
|
|
423
584
|
"items": {
|
|
424
585
|
"enum": [
|
|
425
586
|
"claude-acp",
|
|
426
|
-
"codex-acp"
|
|
587
|
+
"codex-acp",
|
|
588
|
+
"acp"
|
|
427
589
|
]
|
|
428
590
|
}
|
|
429
591
|
},
|
|
@@ -170,6 +170,16 @@
|
|
|
170
170
|
}
|
|
171
171
|
]
|
|
172
172
|
},
|
|
173
|
+
"program": {
|
|
174
|
+
"anyOf": [
|
|
175
|
+
{
|
|
176
|
+
"type": "string"
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
"type": "null"
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
},
|
|
173
183
|
"purpose": {
|
|
174
184
|
"anyOf": [
|
|
175
185
|
{
|
|
@@ -223,6 +233,16 @@
|
|
|
223
233
|
"type": "string"
|
|
224
234
|
},
|
|
225
235
|
"type": "array"
|
|
236
|
+
},
|
|
237
|
+
"version": {
|
|
238
|
+
"anyOf": [
|
|
239
|
+
{
|
|
240
|
+
"type": "string"
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
"type": "null"
|
|
244
|
+
}
|
|
245
|
+
]
|
|
226
246
|
}
|
|
227
247
|
},
|
|
228
248
|
"required": [
|
|
@@ -175,6 +175,16 @@
|
|
|
175
175
|
}
|
|
176
176
|
]
|
|
177
177
|
},
|
|
178
|
+
"program": {
|
|
179
|
+
"anyOf": [
|
|
180
|
+
{
|
|
181
|
+
"type": "string"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"type": "null"
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
},
|
|
178
188
|
"purpose": {
|
|
179
189
|
"anyOf": [
|
|
180
190
|
{
|
|
@@ -228,6 +238,16 @@
|
|
|
228
238
|
"type": "string"
|
|
229
239
|
},
|
|
230
240
|
"type": "array"
|
|
241
|
+
},
|
|
242
|
+
"version": {
|
|
243
|
+
"anyOf": [
|
|
244
|
+
{
|
|
245
|
+
"type": "string"
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"type": "null"
|
|
249
|
+
}
|
|
250
|
+
]
|
|
231
251
|
}
|
|
232
252
|
},
|
|
233
253
|
"required": [
|
|
@@ -364,6 +384,16 @@
|
|
|
364
384
|
}
|
|
365
385
|
]
|
|
366
386
|
},
|
|
387
|
+
"program": {
|
|
388
|
+
"anyOf": [
|
|
389
|
+
{
|
|
390
|
+
"type": "string"
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
"type": "null"
|
|
394
|
+
}
|
|
395
|
+
]
|
|
396
|
+
},
|
|
367
397
|
"sessionId": {
|
|
368
398
|
"pattern": "^s-[a-f0-9]{16}$",
|
|
369
399
|
"type": "string"
|
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
"minLength": 1,
|
|
17
17
|
"type": "string"
|
|
18
18
|
},
|
|
19
|
+
"interpreter": {
|
|
20
|
+
"maxLength": 1024,
|
|
21
|
+
"minLength": 1,
|
|
22
|
+
"type": "string"
|
|
23
|
+
},
|
|
19
24
|
"language": {
|
|
20
25
|
"enum": [
|
|
21
26
|
"r",
|
|
@@ -196,6 +201,16 @@
|
|
|
196
201
|
}
|
|
197
202
|
]
|
|
198
203
|
},
|
|
204
|
+
"program": {
|
|
205
|
+
"anyOf": [
|
|
206
|
+
{
|
|
207
|
+
"type": "string"
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"type": "null"
|
|
211
|
+
}
|
|
212
|
+
]
|
|
213
|
+
},
|
|
199
214
|
"purpose": {
|
|
200
215
|
"anyOf": [
|
|
201
216
|
{
|
|
@@ -249,6 +264,16 @@
|
|
|
249
264
|
"type": "string"
|
|
250
265
|
},
|
|
251
266
|
"type": "array"
|
|
267
|
+
},
|
|
268
|
+
"version": {
|
|
269
|
+
"anyOf": [
|
|
270
|
+
{
|
|
271
|
+
"type": "string"
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"type": "null"
|
|
275
|
+
}
|
|
276
|
+
]
|
|
252
277
|
}
|
|
253
278
|
},
|
|
254
279
|
"required": [
|
|
@@ -378,6 +403,16 @@
|
|
|
378
403
|
}
|
|
379
404
|
]
|
|
380
405
|
},
|
|
406
|
+
"program": {
|
|
407
|
+
"anyOf": [
|
|
408
|
+
{
|
|
409
|
+
"type": "string"
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
"type": "null"
|
|
413
|
+
}
|
|
414
|
+
]
|
|
415
|
+
},
|
|
381
416
|
"sessionId": {
|
|
382
417
|
"pattern": "^s-[a-f0-9]{16}$",
|
|
383
418
|
"type": "string"
|
|
@@ -508,5 +543,5 @@
|
|
|
508
543
|
],
|
|
509
544
|
"type": "object"
|
|
510
545
|
},
|
|
511
|
-
"description": "Run a cell of R or Python in the project's live session of that language, which the Agent and the person share: what one cell defines stays for the next. Starts the session when none is live, on this machine or at a place on one of the person's servers (place, or where kernel.places says that language runs next). The same changeId from the same caller returns the same cell and never runs it twice. waitMs waits for the cell to end."
|
|
546
|
+
"description": "Run a cell of R or Python in the project's live session of that language, which the Agent and the person share: what one cell defines stays for the next. Starts the session when none is live, on this machine or at a place on one of the person's servers (place, or where kernel.places says that language runs next). interpreter names the program a session on this machine starts with, in a folder of the project such as .venv/bin/python; the project keeps it for that language's later sessions, and each cell records the program and version that ran it. The same changeId from the same caller returns the same cell and never runs it twice. waitMs waits for the cell to end."
|
|
512
547
|
}
|
|
@@ -38,3 +38,56 @@ export async function facts(page) {
|
|
|
38
38
|
return { kinds: [...new Set(elements.map(el => el.dataset.fact))], agentInVerified: elements.some(el => el.dataset.fact === 'agent' && el.closest('[data-fact="verified"]')) };
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
|
+
// What one page shows at its current width, read without changing it: whether it scrolls sideways,
|
|
42
|
+
// the elements that cross the right edge (`clippedBy` names a box that scrolls or hides what is beyond
|
|
43
|
+
// its own width; the ones no box keeps in are counted in `elementsPastEdgeUnclipped` and listed first),
|
|
44
|
+
// unnamed buttons, the visible boxes of `selector` that overlap one another (a box inside another is not
|
|
45
|
+
// an overlap), and how many fonts loaded.
|
|
46
|
+
export async function pageFindings(page, { selector = null } = {}) {
|
|
47
|
+
const base = await inspectPage(page);
|
|
48
|
+
const measured = await page.evaluate(selector => {
|
|
49
|
+
const shown = el => { const r = el.getBoundingClientRect(); return r.width > 0 && r.height > 0 && getComputedStyle(el).visibility !== 'hidden'; };
|
|
50
|
+
const describe = el => {
|
|
51
|
+
const text = (el.textContent || '').replace(/\s+/g, ' ').trim().slice(0, 40);
|
|
52
|
+
const classes = [...el.classList].slice(0, 2).map(c => '.' + c).join('');
|
|
53
|
+
return el.tagName.toLowerCase() + (el.id ? '#' + el.id : '') + classes + (text ? ` "${text}"` : '');
|
|
54
|
+
};
|
|
55
|
+
const width = document.documentElement.clientWidth;
|
|
56
|
+
const clipper = el => {
|
|
57
|
+
for (let p = el.parentElement; p && p !== document.body; p = p.parentElement) {
|
|
58
|
+
if (/hidden|auto|scroll|clip/.test(getComputedStyle(p).overflowX) && p.getBoundingClientRect().right <= width + 1) return p;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
};
|
|
62
|
+
const past = [...document.querySelectorAll('body *')].filter(el => shown(el) && el.getBoundingClientRect().right > width + 1).map(el => ({ el, clip: clipper(el) }));
|
|
63
|
+
const unclipped = past.filter(item => !item.clip).length;
|
|
64
|
+
past.sort((a, b) => (a.clip ? 1 : 0) - (b.clip ? 1 : 0));
|
|
65
|
+
const elementsPastEdge = past.slice(0, 50).map(({ el, clip }) => {
|
|
66
|
+
const r = el.getBoundingClientRect();
|
|
67
|
+
return { element: describe(el), right: Math.round(r.right), width: Math.round(r.width), clippedBy: clip ? describe(clip) : null };
|
|
68
|
+
});
|
|
69
|
+
let overlaps = null;
|
|
70
|
+
if (selector) {
|
|
71
|
+
const matched = [...document.querySelectorAll(selector)];
|
|
72
|
+
const boxes = matched.filter(shown).slice(0, 400);
|
|
73
|
+
const pairs = [];
|
|
74
|
+
for (let i = 0; i < boxes.length; i++) {
|
|
75
|
+
for (let j = i + 1; j < boxes.length; j++) {
|
|
76
|
+
const a = boxes[i], b = boxes[j];
|
|
77
|
+
if (a.contains(b) || b.contains(a)) continue;
|
|
78
|
+
const ra = a.getBoundingClientRect(), rb = b.getBoundingClientRect();
|
|
79
|
+
if (Math.min(ra.right, rb.right) - Math.max(ra.left, rb.left) > 1 && Math.min(ra.bottom, rb.bottom) - Math.max(ra.top, rb.top) > 1) pairs.push([describe(a), describe(b)]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
overlaps = { selector, matched: matched.length, considered: boxes.length, total: pairs.length, pairs: pairs.slice(0, 50) };
|
|
83
|
+
}
|
|
84
|
+
return { scrollWidth: document.documentElement.scrollWidth, clientWidth: width, pastTotal: past.length, unclipped, elementsPastEdge, overlaps };
|
|
85
|
+
}, selector);
|
|
86
|
+
const fontsLoaded = await page.evaluate(async () => { await document.fonts.ready; return [...document.fonts].filter(f => f.status === 'loaded').length; });
|
|
87
|
+
return {
|
|
88
|
+
width: base.width, height: base.height, horizontalOverflow: base.overflow,
|
|
89
|
+
scrollWidth: measured.scrollWidth, clientWidth: measured.clientWidth,
|
|
90
|
+
elementsPastEdge: measured.elementsPastEdge, elementsPastEdgeTotal: measured.pastTotal, elementsPastEdgeUnclipped: measured.unclipped,
|
|
91
|
+
unnamedButtons: base.unnamed, overlaps: measured.overlaps, fontsLoaded,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -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
|
+
}
|