@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
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { installText, readInstall } from './installs.js';
|
|
1
2
|
// Only an explicit Agent limit report qualifies; an unknown outcome never does.
|
|
2
3
|
export function agentTurnLimit(turn) {
|
|
3
4
|
return turn.state === 'failed' && (turn.result?.kind === 'error_max_turns' || turn.result?.reason === 'max_turn_requests' || /^(?:Internal error: )?Reached maximum number of turns \(\d+\)\.?$/i.test(turn.problem ?? ''));
|
|
@@ -181,6 +182,10 @@ export function toolActivity(step, location, root, key) {
|
|
|
181
182
|
targetKind = detail || location ? 'path' : 'text';
|
|
182
183
|
}
|
|
183
184
|
else if (action === 'execute') {
|
|
185
|
+
// A command that installs packages reads as what it installed; its command stays in the details.
|
|
186
|
+
const installed = detail ? readInstall(detail, step.output?.text) : null;
|
|
187
|
+
if (installed)
|
|
188
|
+
return { key: key ?? step.id ?? tool + '-' + step.at, step, action, verb: outcome === 'returned' ? 'Installed' : outcome === 'requested' ? 'Installing' : 'Tried to install', target: installText(installed), targetKind: 'packages', installed, title, location, outcome };
|
|
184
189
|
target = detail ? displayCommand(detail) : (title && title.toLowerCase() !== tool.toLowerCase() ? title : null);
|
|
185
190
|
targetKind = detail ? 'command' : 'text';
|
|
186
191
|
}
|
|
@@ -199,17 +204,22 @@ export function toolActivity(step, location, root, key) {
|
|
|
199
204
|
return { key: key ?? step.id ?? tool + '-' + step.at, step, action, verb, target, targetKind, title, location, outcome };
|
|
200
205
|
}
|
|
201
206
|
// Files are counted once however often the Agent touched them: nine edits of one script
|
|
202
|
-
// are "Edited 1 file". Other actions count each time they happened.
|
|
207
|
+
// are "Edited 1 file". Other actions count each time they happened. Installs are named by
|
|
208
|
+
// their packages, "Installed pandas, statsmodels", and are not counted as commands.
|
|
203
209
|
const onFiles = new Set(['read', 'edit', 'write', 'delete', 'move']);
|
|
204
210
|
export function activitySummary(activities) {
|
|
205
211
|
const seen = new Map();
|
|
206
212
|
activities.forEach((activity, i) => {
|
|
207
|
-
const
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
seen.
|
|
213
|
+
const group = activity.installed ? activity.verb : activity.action;
|
|
214
|
+
const file = activity.installed ? activity.installed.packages.map(p => p.name).join('\n') || 'packages from ' + activity.installed.from
|
|
215
|
+
: onFiles.has(activity.action) ? activity.location ?? activity.step.detail ?? activity.target : null;
|
|
216
|
+
const named = seen.get(group) ?? new Set();
|
|
217
|
+
for (const name of activity.installed ? file.split('\n') : [file ?? '#' + i])
|
|
218
|
+
named.add(name);
|
|
219
|
+
seen.set(group, named);
|
|
211
220
|
});
|
|
212
|
-
const
|
|
221
|
+
const listed = (names) => names.length > 3 ? names.slice(0, 3).join(', ') + ` and ${names.length - 3} more` : names.join(', ');
|
|
222
|
+
const parts = [...seen].map(([group, named]) => group in summaries ? summaries[group][named.size === 1 ? 0 : 1].replace('{n}', String(named.size)) : group + ' ' + listed([...named]));
|
|
213
223
|
const count = (outcome) => activities.filter(a => a.outcome === outcome).length;
|
|
214
224
|
const failed = count('failed'), refused = count('rejected'), unknown = count('unknown');
|
|
215
225
|
if (failed)
|
package/dist/conversations.d.ts
CHANGED
|
@@ -41,7 +41,11 @@ interface Permission extends AgentPermission {
|
|
|
41
41
|
}
|
|
42
42
|
export interface ConversationConfig {
|
|
43
43
|
settingsFile?: string;
|
|
44
|
-
backend?: 'claude-acp' | 'codex-acp' | 'claude-cli';
|
|
44
|
+
backend?: 'claude-acp' | 'codex-acp' | 'claude-cli' | 'acp';
|
|
45
|
+
acpCommand?: {
|
|
46
|
+
file: string;
|
|
47
|
+
args: string[];
|
|
48
|
+
};
|
|
45
49
|
codex?: string;
|
|
46
50
|
codexAcp?: Omit<CodexAcpOptions, 'cwd' | 'mcpServers' | 'limits' | 'sessionId' | 'codex' | 'observation' | 'observe'>;
|
|
47
51
|
claudeAcp?: Omit<ClaudeAcpOptions, 'cwd' | 'mcpServers' | 'limits' | 'sessionId' | 'claude' | 'observation' | 'observe'>;
|
|
@@ -125,7 +129,7 @@ interface FileChange {
|
|
|
125
129
|
modifiedAt: string | null;
|
|
126
130
|
bytes: number | null;
|
|
127
131
|
}
|
|
128
|
-
type Backend = 'claude-acp' | 'codex-acp';
|
|
132
|
+
type Backend = 'claude-acp' | 'codex-acp' | 'acp';
|
|
129
133
|
type Choices = Record<string, string | boolean>;
|
|
130
134
|
interface Offered {
|
|
131
135
|
at: string;
|
|
@@ -406,7 +410,7 @@ export declare class Conversations {
|
|
|
406
410
|
private sessionObservation;
|
|
407
411
|
work(project: Project, limit?: number): Promise<{
|
|
408
412
|
sessions: {
|
|
409
|
-
backend: "claude-acp" | "codex-acp" | "claude-cli";
|
|
413
|
+
backend: "acp" | "claude-acp" | "codex-acp" | "claude-cli";
|
|
410
414
|
sessionId: string | null;
|
|
411
415
|
observation: SessionObservation | null;
|
|
412
416
|
state: string;
|
|
@@ -574,7 +578,7 @@ export declare class Conversations {
|
|
|
574
578
|
version: number;
|
|
575
579
|
updatedAt: string | null;
|
|
576
580
|
backend: Backend | null;
|
|
577
|
-
serviceBackend: "claude-acp" | "codex-acp" | "claude-cli";
|
|
581
|
+
serviceBackend: "acp" | "claude-acp" | "codex-acp" | "claude-cli";
|
|
578
582
|
choices: Partial<Record<Backend, Choices>>;
|
|
579
583
|
offered: Partial<Record<Backend, Offered>>;
|
|
580
584
|
checking: Backend[];
|
|
@@ -593,7 +597,7 @@ export declare class Conversations {
|
|
|
593
597
|
version: number;
|
|
594
598
|
updatedAt: string | null;
|
|
595
599
|
backend: Backend | null;
|
|
596
|
-
serviceBackend: "claude-acp" | "codex-acp" | "claude-cli";
|
|
600
|
+
serviceBackend: "acp" | "claude-acp" | "codex-acp" | "claude-cli";
|
|
597
601
|
choices: Partial<Record<Backend, Choices>>;
|
|
598
602
|
offered: Partial<Record<Backend, Offered>>;
|
|
599
603
|
checking: Backend[];
|
|
@@ -607,7 +611,7 @@ export declare class Conversations {
|
|
|
607
611
|
version: number;
|
|
608
612
|
updatedAt: string | null;
|
|
609
613
|
backend: Backend | null;
|
|
610
|
-
serviceBackend: "claude-acp" | "codex-acp" | "claude-cli";
|
|
614
|
+
serviceBackend: "acp" | "claude-acp" | "codex-acp" | "claude-cli";
|
|
611
615
|
choices: Partial<Record<Backend, Choices>>;
|
|
612
616
|
offered: Partial<Record<Backend, Offered>>;
|
|
613
617
|
checking: Backend[];
|
package/dist/conversations.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { projectPath, commandFiles, buildWorkGraph } from './work-graph.js';
|
|
2
2
|
import { notesInstructions, projectNotesPath } from './project-notes.js';
|
|
3
3
|
import { addSpend, describeLimits, describable, fileFacts, figureContext, raster } from './file-describer.js';
|
|
4
|
-
import { agentTurnLimit, toolActivity } from './conversation-presentation.js';
|
|
4
|
+
import { agentTurnLimit, displayCommand, toolActivity } from './conversation-presentation.js';
|
|
5
5
|
import { privateEvidencePath } from './evidence-capture.js';
|
|
6
6
|
import * as fs from 'node:fs/promises';
|
|
7
7
|
import path from 'node:path';
|
|
@@ -127,7 +127,7 @@ function compare(before, after, limit) {
|
|
|
127
127
|
changed.sort((a, b) => (a.modifiedAt ?? '\uffff').localeCompare(b.modifiedAt ?? '\uffff') || a.path.localeCompare(b.path));
|
|
128
128
|
return { changed: changed.slice(0, limit), omitted: Math.max(0, changed.length - limit), partial };
|
|
129
129
|
}
|
|
130
|
-
const backends = ['claude-acp', 'codex-acp'];
|
|
130
|
+
const backends = ['claude-acp', 'codex-acp', 'acp'];
|
|
131
131
|
const blankSettings = () => ({ format: 1, version: 0, updatedAt: null, backend: null, choices: {}, offered: {} });
|
|
132
132
|
const acpDriver = (driver) => !!driver && 'configure' in driver;
|
|
133
133
|
const identity = /^c-[a-f0-9]{16}$/;
|
|
@@ -196,7 +196,7 @@ export class Conversations {
|
|
|
196
196
|
this.limits = { ...conversationLimits, ...limits };
|
|
197
197
|
for (const key of ['maxCaptureFiles', 'maxCaptureBytes', 'maxSnapshotBytes', 'maxCaptureConcurrent'])
|
|
198
198
|
requireThat(Number.isSafeInteger(this.limits[key]) && this.limits[key] > 0 && this.limits[key] <= conversationLimits[key], 'invalid', 'Capture budgets must be positive integers no greater than the supported defaults.', { limit: key, maximum: conversationLimits[key] });
|
|
199
|
-
requireThat(!config.backend || ['claude-acp', 'codex-acp', 'claude-cli'].includes(config.backend), 'invalid', 'Choose claude-acp, codex-acp
|
|
199
|
+
requireThat(!config.backend || ['claude-acp', 'codex-acp', 'claude-cli', 'acp'].includes(config.backend), 'invalid', 'Choose claude-acp, codex-acp, claude-cli or acp.');
|
|
200
200
|
}
|
|
201
201
|
serial(key, run) {
|
|
202
202
|
const task = (this.queues.get(key) ?? Promise.resolve()).catch(() => { }).then(run);
|
|
@@ -408,7 +408,7 @@ export class Conversations {
|
|
|
408
408
|
const saved = await this.readSettings();
|
|
409
409
|
const backend = input.backend ?? saved.backend ?? this.config.backend ?? 'claude-acp';
|
|
410
410
|
const config = backend === 'claude-cli' ? undefined : input.config ?? saved.choices[backend];
|
|
411
|
-
const at = now(), c = { format: 2, backend, id: 'c-' + randomBytes(8).toString('hex'), changeId: input.changeId, requestDigest, createdAt: at, createdBy: by, updatedAt: at, version: 0, client: backend === 'codex-acp' ? 'codex' : 'claude-code', nativeSessionId: backend === 'claude-cli' ? randomUUID() : null, confirmed: false, principal: null, title: titleOf(text), turns: [], ...(config && Object.keys(config).length ? { config } : {}) };
|
|
411
|
+
const at = now(), c = { format: 2, backend, id: 'c-' + randomBytes(8).toString('hex'), changeId: input.changeId, requestDigest, createdAt: at, createdBy: by, updatedAt: at, version: 0, client: backend === 'codex-acp' ? 'codex' : backend === 'acp' ? 'acp' : 'claude-code', nativeSessionId: backend === 'claude-cli' ? randomUUID() : null, confirmed: false, principal: null, title: titleOf(text), turns: [], ...(config && Object.keys(config).length ? { config } : {}) };
|
|
412
412
|
for (const id of input.contexts ?? [])
|
|
413
413
|
await this.ports.context?.(project, id);
|
|
414
414
|
const turn = this.turn(input.changeId, requestDigest, by, text, 1);
|
|
@@ -468,7 +468,7 @@ export class Conversations {
|
|
|
468
468
|
this.choices({ [input.configId]: input.value });
|
|
469
469
|
return this.serial(project.id, async () => {
|
|
470
470
|
const c = await this.load(project, input.conversationId), last = c.turns.at(-1);
|
|
471
|
-
requireThat(c.backend === 'claude-acp' || c.backend === 'codex-acp', 'unavailable', 'This conversation\'s Agent has no settings Rho can change.');
|
|
471
|
+
requireThat(c.backend === 'claude-acp' || c.backend === 'codex-acp' || c.backend === 'acp', 'unavailable', 'This conversation\'s Agent has no settings Rho can change.');
|
|
472
472
|
requireThat(!c.trashedAt, 'conflict', 'This conversation is in the trash. Restore it to change its settings.');
|
|
473
473
|
requireThat(!last || last.state !== 'running' || !this.liveTurn(project, c, last), 'conflict', 'The Agent is answering. Change its settings after this message.');
|
|
474
474
|
const driver = this.drivers.get(project.id + '/' + c.id)?.driver;
|
|
@@ -558,9 +558,9 @@ export class Conversations {
|
|
|
558
558
|
return this.settings();
|
|
559
559
|
}
|
|
560
560
|
async inspect(project, backend) {
|
|
561
|
-
const { ClaudeAcpConversation, CodexAcpConversation } = await import('@rho-workspace/plugin-agent/conversation');
|
|
561
|
+
const { ClaudeAcpConversation, CodexAcpConversation, GenericAcpConversation } = await import('@rho-workspace/plugin-agent/conversation');
|
|
562
562
|
const common = { cwd: project.root, mcpServers: [], limits: this.limits };
|
|
563
|
-
const driver = backend === 'codex-acp' ? new CodexAcpConversation({ ...this.config.codexAcp, ...common, codex: this.config.codex }) : new ClaudeAcpConversation({ preferred: claudePreferred, ...this.config.claudeAcp, ...common, claude: this.binary });
|
|
563
|
+
const driver = backend === 'codex-acp' ? new CodexAcpConversation({ ...this.config.codexAcp, ...common, codex: this.config.codex }) : backend === 'acp' ? new GenericAcpConversation({ ...common, command: this.config.acpCommand }) : new ClaudeAcpConversation({ preferred: claudePreferred, ...this.config.claudeAcp, ...common, claude: this.binary });
|
|
564
564
|
let found;
|
|
565
565
|
try {
|
|
566
566
|
found = await driver.inspect();
|
|
@@ -750,11 +750,11 @@ export class Conversations {
|
|
|
750
750
|
const grant = await this.ports.grant(project, c);
|
|
751
751
|
c.principal = grant.principal;
|
|
752
752
|
const mcpServers = [{ name: 'rho', command: process.execPath, args: [fileURLToPath(import.meta.resolve('@rho-workspace/plugin-agent/mcp'))], env: [{ name: 'RHO_AGENT_CONNECTION', value: grant.file }] }];
|
|
753
|
-
const { ClaudeAcpConversation, CodexAcpConversation, ClaudeCliConversation } = await import('@rho-workspace/plugin-agent/conversation');
|
|
753
|
+
const { ClaudeAcpConversation, CodexAcpConversation, ClaudeCliConversation, GenericAcpConversation } = await import('@rho-workspace/plugin-agent/conversation');
|
|
754
754
|
const observed = { observation: c.observation, observe: (observation) => {
|
|
755
755
|
requireThat(observation.sessionId === c.acpSessionId, 'conflict', 'The observed Agent session differs from the retained identity.');
|
|
756
756
|
requireThat(Buffer.byteLength(JSON.stringify(observation)) <= this.limits.maxObservationBytes, 'limit', 'The session projection exceeded maxObservationBytes; prior observations were kept.');
|
|
757
|
-
const config = observation.config, learned = config && config.at !== c.observation?.config?.at && config.origin === 'initial' && !c.config && (c.backend === 'claude-acp' || c.backend === 'codex-acp');
|
|
757
|
+
const config = observation.config, learned = config && config.at !== c.observation?.config?.at && config.origin === 'initial' && !c.config && (c.backend === 'claude-acp' || c.backend === 'codex-acp' || c.backend === 'acp');
|
|
758
758
|
c.observation = observation;
|
|
759
759
|
this.schedule(project, c);
|
|
760
760
|
for (const live of this.live.values())
|
|
@@ -775,7 +775,9 @@ export class Conversations {
|
|
|
775
775
|
? new CodexAcpConversation({ ...this.config.codexAcp, ...common, codex: this.config.codex })
|
|
776
776
|
: c.backend === 'claude-acp'
|
|
777
777
|
? new ClaudeAcpConversation({ preferred: claudePreferred, ...this.config.claudeAcp, ...common, claude: this.binary, plugins: [...this.config.claudeAcp?.plugins ?? [], ...await this.ports.claudePlugins?.(project) ?? []] })
|
|
778
|
-
:
|
|
778
|
+
: c.backend === 'acp'
|
|
779
|
+
? new GenericAcpConversation({ ...common, command: this.config.acpCommand })
|
|
780
|
+
: new ClaudeCliConversation({ cwd: project.root, binary: this.binary, sessionId: c.nativeSessionId, confirmed: c.confirmed, projectName: project.name ?? path.basename(project.root), mcpServers, limits: this.limits, instructions });
|
|
779
781
|
this.drivers.set(key, { driver, project, conversation: c });
|
|
780
782
|
return driver;
|
|
781
783
|
});
|
|
@@ -895,8 +897,9 @@ export class Conversations {
|
|
|
895
897
|
const action = toolActivity(incoming, null, project.root);
|
|
896
898
|
if (action.targetKind === 'path' && (action.location || incoming.detail))
|
|
897
899
|
this.capture(live, action.location ?? incoming.detail, 'step:' + incoming.id + ':' + incoming.outcome);
|
|
898
|
-
|
|
899
|
-
|
|
900
|
+
// A command's files are captured however its row reads (an install names its packages).
|
|
901
|
+
if (action.action === 'execute' && incoming.detail)
|
|
902
|
+
for (const file of commandFiles(displayCommand(incoming.detail), project))
|
|
900
903
|
this.capture(live, file, 'command:' + incoming.id + ':' + incoming.outcome);
|
|
901
904
|
}
|
|
902
905
|
if (!kept)
|
|
@@ -1068,7 +1071,8 @@ export class Conversations {
|
|
|
1068
1071
|
const given = shown.get(file);
|
|
1069
1072
|
const reason = !enabled ? 'Descriptions by a model are switched off; the facts are kept.'
|
|
1070
1073
|
: c.backend === 'codex-acp' ? 'Descriptions are written with Claude Code; this session\'s Agent is Codex.'
|
|
1071
|
-
:
|
|
1074
|
+
: c.backend === 'acp' ? 'Descriptions are written with Claude Code; this session\'s Agent is a configured ACP agent.'
|
|
1075
|
+
: !this.ports.describe ? 'No model is set up to describe files.' : null;
|
|
1072
1076
|
const keep = (why) => { if (record.reason !== why) {
|
|
1073
1077
|
record.state = record.sentence ? 'described' : 'facts';
|
|
1074
1078
|
record.reason = why;
|
package/dist/discovery.d.ts
CHANGED
package/dist/discovery.js
CHANGED
|
@@ -3,11 +3,11 @@ import { Capabilities, rhoWorkspaceSkill } from './capabilities.js';
|
|
|
3
3
|
import { protocol } from './protocol.js';
|
|
4
4
|
import { schemaClosure } from './protocol-discovery.js';
|
|
5
5
|
const size = (v) => Buffer.byteLength(JSON.stringify(v)) + 64;
|
|
6
|
-
const applicationEffects = Object.fromEntries([
|
|
7
|
-
...['protocol.describe', 'protocol.validate', 'project.entries', 'capability.list', 'skill.list', 'skill.read', 'action.lookup', 'action.observe', 'action.output', 'action.list', 'composition.read', 'observation.snapshot', 'interaction.selection.read', 'workspace.observe', 'task.map.read'].map(m => [m, 'read']),
|
|
6
|
+
export const applicationEffects = Object.fromEntries([
|
|
7
|
+
...['extension.list', 'extension.describe', 'extension.content', 'extension.read', 'protocol.describe', 'protocol.validate', 'project.entries', 'capability.list', 'skill.list', 'skill.read', 'action.lookup', 'action.observe', 'action.output', 'action.list', 'composition.read', 'observation.snapshot', 'interaction.selection.read', 'workspace.observe', 'task.map.read'].map(m => [m, 'read']),
|
|
8
8
|
...['composition.put', 'view.close', 'capability.configure', 'composition.apply', 'composition.undo', 'view.protection.set', 'interaction.selection.set', 'selection.set', 'workspace.enhance', 'task.map.declare', 'task.map.present', 'task.map.respond'].map(m => [m, 'metadata']),
|
|
9
9
|
...['workspace.save', 'workspace.export', 'workspace.restore', 'action.export'].map(m => [m, 'file']),
|
|
10
|
-
...['action.retry', 'action.cancel'].map(m => [m, 'native']),
|
|
10
|
+
...['extension.call', 'extension.install', 'extension.manage', 'action.retry', 'action.cancel'].map(m => [m, 'native']),
|
|
11
11
|
]);
|
|
12
12
|
const rhoSummary = 'The project in Rho: its folder\'s entries, managed runs, the views on the person\'s screen and what is selected in them, the task map, and which plugins are on.';
|
|
13
13
|
const metadata = new Set(['capability.index', 'capability.resolve', 'binding.activity.append', 'task.routing.put', 'feedback.submit', 'view.observe', 'view.observations.read']);
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export declare const extensionOperations: {
|
|
2
|
+
'extension.list': {
|
|
3
|
+
type: string;
|
|
4
|
+
properties: Record<string, unknown>;
|
|
5
|
+
required: string[];
|
|
6
|
+
additionalProperties: boolean;
|
|
7
|
+
};
|
|
8
|
+
'extension.describe': {
|
|
9
|
+
type: string;
|
|
10
|
+
properties: Record<string, unknown>;
|
|
11
|
+
required: string[];
|
|
12
|
+
additionalProperties: boolean;
|
|
13
|
+
};
|
|
14
|
+
'extension.content': {
|
|
15
|
+
type: string;
|
|
16
|
+
properties: Record<string, unknown>;
|
|
17
|
+
required: string[];
|
|
18
|
+
additionalProperties: boolean;
|
|
19
|
+
};
|
|
20
|
+
'extension.call': {
|
|
21
|
+
type: string;
|
|
22
|
+
properties: Record<string, unknown>;
|
|
23
|
+
required: string[];
|
|
24
|
+
additionalProperties: boolean;
|
|
25
|
+
};
|
|
26
|
+
'extension.read': {
|
|
27
|
+
type: string;
|
|
28
|
+
properties: Record<string, unknown>;
|
|
29
|
+
required: string[];
|
|
30
|
+
additionalProperties: boolean;
|
|
31
|
+
};
|
|
32
|
+
'extension.install': {
|
|
33
|
+
type: string;
|
|
34
|
+
properties: Record<string, unknown>;
|
|
35
|
+
required: string[];
|
|
36
|
+
additionalProperties: boolean;
|
|
37
|
+
};
|
|
38
|
+
'extension.manage': {
|
|
39
|
+
type: string;
|
|
40
|
+
properties: Record<string, unknown>;
|
|
41
|
+
required: string[];
|
|
42
|
+
additionalProperties: boolean;
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
export declare const extensionResponses: {
|
|
46
|
+
'extension.list': {
|
|
47
|
+
type: string;
|
|
48
|
+
properties: Record<string, unknown>;
|
|
49
|
+
required: string[];
|
|
50
|
+
additionalProperties: boolean;
|
|
51
|
+
};
|
|
52
|
+
'extension.describe': {
|
|
53
|
+
type: string;
|
|
54
|
+
properties: Record<string, unknown>;
|
|
55
|
+
required: string[];
|
|
56
|
+
additionalProperties: boolean;
|
|
57
|
+
};
|
|
58
|
+
'extension.install': {
|
|
59
|
+
type: string;
|
|
60
|
+
properties: Record<string, unknown>;
|
|
61
|
+
required: string[];
|
|
62
|
+
additionalProperties: boolean;
|
|
63
|
+
};
|
|
64
|
+
'extension.content': {
|
|
65
|
+
type: string;
|
|
66
|
+
properties: Record<string, unknown>;
|
|
67
|
+
required: string[];
|
|
68
|
+
additionalProperties: boolean;
|
|
69
|
+
};
|
|
70
|
+
'extension.call': {
|
|
71
|
+
type: string;
|
|
72
|
+
properties: Record<string, unknown>;
|
|
73
|
+
required: string[];
|
|
74
|
+
additionalProperties: boolean;
|
|
75
|
+
};
|
|
76
|
+
'extension.read': {
|
|
77
|
+
type: string;
|
|
78
|
+
properties: Record<string, unknown>;
|
|
79
|
+
required: string[];
|
|
80
|
+
additionalProperties: boolean;
|
|
81
|
+
};
|
|
82
|
+
'extension.manage': {
|
|
83
|
+
type: string;
|
|
84
|
+
properties: Record<string, unknown>;
|
|
85
|
+
required: string[];
|
|
86
|
+
additionalProperties: boolean;
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
export declare const extensionDescriptions: {
|
|
90
|
+
'extension.list': string;
|
|
91
|
+
'extension.describe': string;
|
|
92
|
+
'extension.content': string;
|
|
93
|
+
'extension.call': string;
|
|
94
|
+
'extension.read': string;
|
|
95
|
+
'extension.install': string;
|
|
96
|
+
'extension.manage': string;
|
|
97
|
+
};
|
|
98
|
+
export declare const extensionManagement: string[];
|
|
99
|
+
export declare const extensionMethods: string[];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Installed third-party packages are application assembly, independent of the
|
|
2
|
+
// functional owners compiled into Rho. This protocol never imports their code.
|
|
3
|
+
const str = { type: 'string', minLength: 1, maxLength: 1024 };
|
|
4
|
+
const id = { type: 'string', pattern: '^[a-z0-9][a-z0-9._-]{0,95}$' };
|
|
5
|
+
const sha = { type: 'string', pattern: '^[a-f0-9]{64}$' };
|
|
6
|
+
const object = (properties, required = Object.keys(properties)) => ({ type: 'object', properties, required, additionalProperties: false });
|
|
7
|
+
const json = { type: 'object', additionalProperties: true };
|
|
8
|
+
const project = { projectId: str };
|
|
9
|
+
const selected = { ...project, pluginId: id, expectedDigest: sha };
|
|
10
|
+
export const extensionOperations = {
|
|
11
|
+
'extension.list': object(project, []),
|
|
12
|
+
'extension.describe': object({ ...project, pluginId: id }),
|
|
13
|
+
'extension.content': object({ ...selected, kind: { enum: ['skill', 'view'] }, entryId: id }),
|
|
14
|
+
'extension.call': object({ ...selected, operation: id, input: json, changeId: { type: 'string', pattern: '^[A-Za-z0-9._:@-]{1,128}$' } }),
|
|
15
|
+
'extension.read': object({ ...project, invocationId: sha }),
|
|
16
|
+
'extension.install': object({ source: str, replace: id, expectedDigest: sha }, ['source']),
|
|
17
|
+
'extension.manage': object({ pluginId: id, expectedDigest: sha, action: { enum: ['enable', 'disable', 'remove'] } }),
|
|
18
|
+
};
|
|
19
|
+
const array = (items) => ({ type: 'array', items });
|
|
20
|
+
const text = { type: 'string' };
|
|
21
|
+
const entry = { ...object({ id, title: text, file: text }), additionalProperties: true };
|
|
22
|
+
const manifest = { ...object({ apiVersion: { const: 1 }, id, title: text, description: text, host: text,
|
|
23
|
+
operations: array({ ...object({ id, title: text, description: text, effect: { enum: ['read', 'native'] }, methods: array(text), inputSchema: json }), additionalProperties: true }),
|
|
24
|
+
skills: array(entry), views: array(entry),
|
|
25
|
+
}, ['apiVersion', 'id', 'title', 'description', 'operations', 'skills', 'views']), additionalProperties: true };
|
|
26
|
+
const installed = { id, name: text, version: text, title: text, description: text, digest: sha, source: text, sourceCommit: text, enabled: { type: 'boolean' }, installedAt: text };
|
|
27
|
+
const installedRequired = Object.keys(installed).filter(key => key !== 'sourceCommit');
|
|
28
|
+
const descriptor = object({ ...installed, manifest }, [...installedRequired, 'manifest']);
|
|
29
|
+
const receipt = object({ invocationId: sha, caller: text, projectId: text, pluginId: id, packageDigest: sha, operation: id, requestDigest: sha,
|
|
30
|
+
state: { enum: ['pending', 'completed', 'unknown'] }, startedAt: text, endedAt: text, value: {}, error: text,
|
|
31
|
+
delegations: array(object({ method: text, request: {}, state: { enum: ['pending', 'completed', 'unknown'] }, value: {}, error: text }, ['method', 'request', 'state'])),
|
|
32
|
+
}, ['invocationId', 'caller', 'projectId', 'pluginId', 'packageDigest', 'operation', 'requestDigest', 'state', 'startedAt']);
|
|
33
|
+
export const extensionResponses = {
|
|
34
|
+
'extension.list': object({ plugins: array(object(installed, installedRequired)), directory: array(object({ id, title: text, version: text, description: text, source: text, repository: text, needs: text })), limits: json }),
|
|
35
|
+
'extension.describe': descriptor,
|
|
36
|
+
'extension.install': descriptor,
|
|
37
|
+
'extension.content': object({ pluginId: id, packageDigest: sha, entryId: id, kind: { enum: ['skill', 'view'] }, title: text, text }),
|
|
38
|
+
'extension.call': receipt,
|
|
39
|
+
'extension.read': receipt,
|
|
40
|
+
'extension.manage': object({ pluginId: id, action: { enum: ['enable', 'disable', 'remove'] }, retained: text }),
|
|
41
|
+
};
|
|
42
|
+
export const extensionDescriptions = {
|
|
43
|
+
'extension.list': 'List independently installed third-party packages and their enabled state, source and immutable digest. Reads start no plugin or runtime. Use extension.describe to discover operation schemas and Skills.',
|
|
44
|
+
'extension.describe': 'Read an installed third-party package manifest, operation input schemas, required Rho methods, Skills and views. Read its Skill with extension.content before use. Disabled packages cannot run.',
|
|
45
|
+
'extension.content': 'Read one installed plugin Skill or standalone HTML view at its selected package digest. Reading starts no plugin or runtime.',
|
|
46
|
+
'extension.call': 'Call an enabled third-party operation at the described package digest, under the caller and project. The package runs trusted native code. Non-read calls retain the original changeId: repeat observes that invocation, including unknown outcomes, without re-execution. Completion is not scientific validity.',
|
|
47
|
+
'extension.read': 'Observe an original plugin invocation, including pending or unknown outcomes. Never reruns code. Only its original caller can read it.',
|
|
48
|
+
'extension.install': 'Local person/operator: install a trusted prebuilt npm package, local folder, tarball, or Git source. Lifecycle scripts are disabled. Replacement stages and checks the new package before switching; use replace and expectedDigest for updates.',
|
|
49
|
+
'extension.manage': 'Local person/operator: enable, disable or remove an installed third-party package at the expected digest. Existing native tasks, R sessions, project files and retained receipts are preserved.',
|
|
50
|
+
};
|
|
51
|
+
export const extensionManagement = ['extension.install', 'extension.manage'];
|
|
52
|
+
export const extensionMethods = Object.keys(extensionOperations);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Optional discovery, not a registration requirement. Packages keep their own
|
|
2
|
+
// repositories/releases; an entry records the source a maintainer actually checked.
|
|
3
|
+
export const extensionDirectory = [
|
|
4
|
+
{
|
|
5
|
+
id: 'yulab.sclet', title: 'sclet', version: '0.1.0',
|
|
6
|
+
description: 'State-aware single-cell analysis using sclet in your shared R Notebook.',
|
|
7
|
+
source: 'git+https://github.com/YuLab-SMU/Rho-plugins.git#82df99f8cbab868c30949692172c6cf11db2f5c0:examples/sclet-plugin',
|
|
8
|
+
repository: 'https://github.com/YuLab-SMU/Rho-plugins/tree/82df99f8cbab868c30949692172c6cf11db2f5c0/examples/sclet-plugin',
|
|
9
|
+
needs: 'R, sclet, SingleCellExperiment and jsonlite in the selected R environment.',
|
|
10
|
+
},
|
|
11
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// A process boundary for crashes/timeouts, NOT an OS sandbox. An installed host
|
|
2
|
+
// has this user's native permissions. Never send it service credentials.
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
const pending = new Map();
|
|
5
|
+
let next = 0;
|
|
6
|
+
process.on('message', async (message) => {
|
|
7
|
+
if (message.type === 'reply') {
|
|
8
|
+
const waiter = pending.get(message.id);
|
|
9
|
+
pending.delete(message.id);
|
|
10
|
+
if (message.error)
|
|
11
|
+
waiter?.reject(new Error(message.error));
|
|
12
|
+
else
|
|
13
|
+
waiter?.resolve(message.value);
|
|
14
|
+
}
|
|
15
|
+
if (message.type !== 'start')
|
|
16
|
+
return;
|
|
17
|
+
try {
|
|
18
|
+
const plugin = await import(pathToFileURL(message.entry).href);
|
|
19
|
+
if (typeof plugin.run !== 'function')
|
|
20
|
+
throw new Error('The plugin host must export run(operation, input, context).');
|
|
21
|
+
const value = await plugin.run(message.operation, message.input, {
|
|
22
|
+
projectRoot: message.projectRoot,
|
|
23
|
+
invocationId: message.invocationId,
|
|
24
|
+
changeId: (label) => 'ext:' + message.invocationId + ':' + String(label).slice(0, 40),
|
|
25
|
+
call: (method, body) => new Promise((resolve, reject) => {
|
|
26
|
+
const id = ++next;
|
|
27
|
+
pending.set(id, { resolve, reject });
|
|
28
|
+
process.send?.({ type: 'call', id, method, body });
|
|
29
|
+
}),
|
|
30
|
+
});
|
|
31
|
+
process.send?.({ type: 'result', value }, () => process.exit(0));
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
process.send?.({ type: 'error', error: error instanceof Error ? error.message : String(error) }, () => process.exit(1));
|
|
35
|
+
}
|
|
36
|
+
});
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
export declare const extensionLimits: {
|
|
2
|
+
maxPlugins: number;
|
|
3
|
+
maxVersions: number;
|
|
4
|
+
maxFiles: number;
|
|
5
|
+
maxPackageBytes: number;
|
|
6
|
+
maxContentBytes: number;
|
|
7
|
+
maxReceipts: number;
|
|
8
|
+
maxResultBytes: number;
|
|
9
|
+
maxRunning: number;
|
|
10
|
+
maxDelegations: number;
|
|
11
|
+
timeoutMs: number;
|
|
12
|
+
installTimeoutMs: number;
|
|
13
|
+
};
|
|
14
|
+
export interface ExtensionManifest {
|
|
15
|
+
apiVersion: 1;
|
|
16
|
+
id: string;
|
|
17
|
+
title: string;
|
|
18
|
+
description: string;
|
|
19
|
+
host?: string;
|
|
20
|
+
operations: {
|
|
21
|
+
id: string;
|
|
22
|
+
title: string;
|
|
23
|
+
description: string;
|
|
24
|
+
effect: 'read' | 'native';
|
|
25
|
+
methods: string[];
|
|
26
|
+
inputSchema: Record<string, any>;
|
|
27
|
+
}[];
|
|
28
|
+
skills: {
|
|
29
|
+
id: string;
|
|
30
|
+
title: string;
|
|
31
|
+
file: string;
|
|
32
|
+
}[];
|
|
33
|
+
views: {
|
|
34
|
+
id: string;
|
|
35
|
+
title: string;
|
|
36
|
+
file: string;
|
|
37
|
+
}[];
|
|
38
|
+
}
|
|
39
|
+
export interface InstalledExtension {
|
|
40
|
+
id: string;
|
|
41
|
+
name: string;
|
|
42
|
+
version: string;
|
|
43
|
+
title: string;
|
|
44
|
+
description: string;
|
|
45
|
+
digest: string;
|
|
46
|
+
source: string;
|
|
47
|
+
sourceCommit?: string;
|
|
48
|
+
enabled: boolean;
|
|
49
|
+
installedAt: string;
|
|
50
|
+
manifest: ExtensionManifest;
|
|
51
|
+
}
|
|
52
|
+
interface Receipt {
|
|
53
|
+
invocationId: string;
|
|
54
|
+
caller: string;
|
|
55
|
+
projectId: string;
|
|
56
|
+
pluginId: string;
|
|
57
|
+
packageDigest: string;
|
|
58
|
+
operation: string;
|
|
59
|
+
requestDigest: string;
|
|
60
|
+
state: 'pending' | 'completed' | 'unknown';
|
|
61
|
+
startedAt: string;
|
|
62
|
+
endedAt?: string;
|
|
63
|
+
value?: unknown;
|
|
64
|
+
error?: string;
|
|
65
|
+
delegations?: {
|
|
66
|
+
method: string;
|
|
67
|
+
request: unknown;
|
|
68
|
+
state: 'pending' | 'completed' | 'unknown';
|
|
69
|
+
value?: unknown;
|
|
70
|
+
error?: string;
|
|
71
|
+
}[];
|
|
72
|
+
}
|
|
73
|
+
export declare class Extensions {
|
|
74
|
+
readonly directory: string;
|
|
75
|
+
readonly limits: typeof extensionLimits;
|
|
76
|
+
private installed;
|
|
77
|
+
private running;
|
|
78
|
+
private workers;
|
|
79
|
+
private receiptCount;
|
|
80
|
+
private mutation;
|
|
81
|
+
constructor(directory: string, limits?: Partial<typeof extensionLimits>);
|
|
82
|
+
init(): Promise<void>;
|
|
83
|
+
close(): void;
|
|
84
|
+
private serial;
|
|
85
|
+
list(): {
|
|
86
|
+
directory: {
|
|
87
|
+
id: string;
|
|
88
|
+
title: string;
|
|
89
|
+
version: string;
|
|
90
|
+
description: string;
|
|
91
|
+
source: string;
|
|
92
|
+
repository: string;
|
|
93
|
+
needs: string;
|
|
94
|
+
}[];
|
|
95
|
+
plugins: {
|
|
96
|
+
id: string;
|
|
97
|
+
name: string;
|
|
98
|
+
version: string;
|
|
99
|
+
title: string;
|
|
100
|
+
description: string;
|
|
101
|
+
digest: string;
|
|
102
|
+
source: string;
|
|
103
|
+
sourceCommit?: string;
|
|
104
|
+
enabled: boolean;
|
|
105
|
+
installedAt: string;
|
|
106
|
+
}[];
|
|
107
|
+
limits: {
|
|
108
|
+
maxPlugins: number;
|
|
109
|
+
maxVersions: number;
|
|
110
|
+
maxFiles: number;
|
|
111
|
+
maxPackageBytes: number;
|
|
112
|
+
maxContentBytes: number;
|
|
113
|
+
maxReceipts: number;
|
|
114
|
+
maxResultBytes: number;
|
|
115
|
+
maxRunning: number;
|
|
116
|
+
maxDelegations: number;
|
|
117
|
+
timeoutMs: number;
|
|
118
|
+
installTimeoutMs: number;
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
describe(id: string): InstalledExtension;
|
|
122
|
+
private selected;
|
|
123
|
+
private root;
|
|
124
|
+
private file;
|
|
125
|
+
private hash;
|
|
126
|
+
check(root: string): Promise<{
|
|
127
|
+
name: string;
|
|
128
|
+
version: string;
|
|
129
|
+
manifest: ExtensionManifest;
|
|
130
|
+
}>;
|
|
131
|
+
private verify;
|
|
132
|
+
content(id: string, expected: string, kind: 'skill' | 'view', entryId: string): Promise<{
|
|
133
|
+
pluginId: string;
|
|
134
|
+
packageDigest: string;
|
|
135
|
+
entryId: string;
|
|
136
|
+
kind: "skill" | "view";
|
|
137
|
+
title: string;
|
|
138
|
+
text: string;
|
|
139
|
+
}>;
|
|
140
|
+
install(source: string, replace?: string, expected?: string): Promise<InstalledExtension>;
|
|
141
|
+
manage(id: string, expected: string, action: 'enable' | 'disable' | 'remove'): Promise<{
|
|
142
|
+
pluginId: string;
|
|
143
|
+
action: "remove" | "enable" | "disable";
|
|
144
|
+
retained: string;
|
|
145
|
+
}>;
|
|
146
|
+
read(invocationId: string, caller: string, projectId: string): Promise<Receipt>;
|
|
147
|
+
call(b: {
|
|
148
|
+
pluginId: string;
|
|
149
|
+
expectedDigest: string;
|
|
150
|
+
operation: string;
|
|
151
|
+
input: any;
|
|
152
|
+
changeId: string;
|
|
153
|
+
projectId: string;
|
|
154
|
+
}, caller: string, projectRoot: string, dispatch: (method: string, body: any, effect: 'read' | 'native') => Promise<unknown>): Promise<Receipt>;
|
|
155
|
+
private execute;
|
|
156
|
+
}
|
|
157
|
+
export {};
|