@schlenkr/ragents 0.1.14 → 0.1.16

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.
Files changed (114) hide show
  1. package/apps/server/package.json +1 -1
  2. package/apps/server/src/api/contracts.ts +19 -1
  3. package/apps/server/src/api/core-methods.ts +12 -0
  4. package/apps/server/src/chat-handler.ts +19 -0
  5. package/apps/server/src/host-api.json +2 -0
  6. package/apps/server/src/host-api.ts +2 -2
  7. package/apps/server/src/plugin-build/build.ts +1 -1
  8. package/apps/server/src/plugin-support/actor-programs/app-project.ts +62 -18
  9. package/apps/server/src/plugin-support/actor-programs/client-contracts.ts +47 -8
  10. package/apps/server/src/plugin-support/actor-programs/contract.ts +18 -1
  11. package/apps/server/src/plugin-support/actor-programs/service.ts +22 -1
  12. package/apps/server/src/plugin-support/plugin-folder.ts +14 -1
  13. package/apps/server/src/plugin-support/run-scripts.ts +27 -2
  14. package/apps/server/src/profile/compose.ts +2 -0
  15. package/apps/server/src/provider.ts +23 -4
  16. package/apps/server/src/ragents/chat-projection.ts +7 -0
  17. package/apps/server/src/ragents/global-chat.ts +5 -1
  18. package/apps/server/src/ragents/run-script-tools.ts +66 -0
  19. package/apps/server/src/ragents/session.ts +122 -60
  20. package/apps/web/dist/assets/{highlighted-body-KPVGNVTW-BslIwn_y.js → highlighted-body-KPVGNVTW-BwD4uYEe.js} +1 -1
  21. package/apps/web/dist/assets/{main-BUN8m8SW.js → main-KBrc5Q77.js} +1 -1
  22. package/apps/web/dist/assets/{mermaid-HWGCJPDP-B1erZlFM.js → mermaid-HWGCJPDP-CSCkaArr.js} +88 -88
  23. package/apps/web/dist/assets/runPanel-BjG5NBKm.js +26 -0
  24. package/apps/web/dist/help/guide-clients.html +21 -4
  25. package/apps/web/dist/help/guide-clients.md +23 -4
  26. package/apps/web/dist/help/guide-plugins.html +12 -2
  27. package/apps/web/dist/help/guide-plugins.md +9 -2
  28. package/apps/web/dist/help/guide-programs.html +8 -2
  29. package/apps/web/dist/help/guide-programs.md +9 -2
  30. package/apps/web/dist/help/guide-runtime.html +3 -2
  31. package/apps/web/dist/help/guide-runtime.md +3 -2
  32. package/apps/web/dist/help/index.html +1 -1
  33. package/apps/web/dist/help/mini-app.css +7 -2
  34. package/apps/web/dist/host-web.json +6 -6
  35. package/apps/web/dist/index.html +2 -2
  36. package/apps/web/dist/run-panel.html +2 -2
  37. package/apps/web/package.json +1 -1
  38. package/apps/web/src/run-panel/RunPanelApp.tsx +1 -1
  39. package/apps/web/src/run-panel/RunPanelMenu.tsx +47 -11
  40. package/bundles/ragents.activity/ragents-bundle.json +1 -1
  41. package/bundles/ragents.actor-programs/ragents-bundle.json +4 -2
  42. package/bundles/ragents.actor-programs/server/index.js +437 -24
  43. package/bundles/ragents.actor-programs/server/index.js.map +4 -4
  44. package/bundles/ragents.actor-programs/web/index.js.map +1 -1
  45. package/bundles/ragents.ask/ragents-bundle.json +2 -2
  46. package/bundles/ragents.ask/server/index.js +1 -0
  47. package/bundles/ragents.ask/server/index.js.map +2 -2
  48. package/bundles/ragents.browser/ragents-bundle.json +1 -1
  49. package/bundles/ragents.documents/ragents-bundle.json +1 -1
  50. package/bundles/ragents.lsp-fsharp/ragents-bundle.json +1 -1
  51. package/bundles/ragents.lsp-roslyn/ragents-bundle.json +1 -1
  52. package/bundles/ragents.lsp-typescript/ragents-bundle.json +1 -1
  53. package/bundles/ragents.model-relay/ragents-bundle.json +1 -1
  54. package/bundles/ragents.orchestration/ragents-bundle.json +7 -4
  55. package/bundles/ragents.orchestration/server/chunks/chunk-QS3WJ3D7.js +11 -0
  56. package/bundles/ragents.orchestration/server/chunks/chunk-QS3WJ3D7.js.map +7 -0
  57. package/bundles/ragents.orchestration/server/exports/server/contract.js +9 -0
  58. package/bundles/ragents.orchestration/server/exports/server/contract.js.map +7 -0
  59. package/bundles/ragents.orchestration/server/index.js +49 -3
  60. package/bundles/ragents.orchestration/server/index.js.map +2 -2
  61. package/bundles/ragents.orchestration/surface.hbs +5 -0
  62. package/bundles/ragents.overseer/ragents-bundle.json +1 -1
  63. package/bundles/ragents.processes/ragents-bundle.json +1 -1
  64. package/bundles/ragents.product/ragents-bundle.json +1 -1
  65. package/bundles/ragents.profile-distribution/ragents-bundle.json +1 -1
  66. package/bundles/ragents.reference/actors/notebook/package.json +16 -0
  67. package/bundles/ragents.reference/actors/notebook/src/client.tsx +31 -0
  68. package/bundles/ragents.reference/actors/notebook/src/server.ts +27 -0
  69. package/bundles/ragents.reference/actors/notebook/tests/program.test.ts +27 -0
  70. package/bundles/ragents.reference/ragents-bundle.json +4 -3
  71. package/bundles/ragents.reference/run-scripts/quick-note/RUN.md +14 -0
  72. package/bundles/ragents.reference/run-scripts/quick-note/package.json +9 -0
  73. package/bundles/ragents.reference/run-scripts/quick-note/src/server.ts +29 -0
  74. package/bundles/ragents.reference/run-scripts/quick-note/tests/program.test.ts +43 -0
  75. package/bundles/ragents.reference/run-scripts/run-roster/RUN.md +19 -0
  76. package/bundles/ragents.reference/run-scripts/run-roster/package.json +9 -0
  77. package/bundles/ragents.reference/run-scripts/run-roster/src/server.ts +26 -0
  78. package/bundles/ragents.reference/run-scripts/run-roster/tests/program.test.ts +47 -0
  79. package/bundles/ragents.todo/ragents-bundle.json +1 -1
  80. package/bundles/ragents.transcript/ragents-bundle.json +1 -1
  81. package/bundles/ragents.watch/ragents-bundle.json +1 -1
  82. package/bundles/ragents.workspace/ragents-bundle.json +1 -1
  83. package/package.json +3 -3
  84. package/packages/ragents/src/domain/vocabulary.ts +4 -0
  85. package/packages/ragents/src/index.ts +3 -1
  86. package/packages/ragents/src/plugin-host.ts +62 -10
  87. package/packages/ragents/src/plugin-types.ts +11 -0
  88. package/packages/ragents/src/runtime/guards.ts +2 -1
  89. package/packages/ragents/src/typescript/async-compiler.ts +11 -1
  90. package/plugins/ragents.actor-programs/server/index.ts +3 -0
  91. package/plugins/ragents.actor-programs/server/runtime.ts +424 -28
  92. package/plugins/ragents.actor-programs/server/script-state.ts +54 -0
  93. package/plugins/ragents.actor-programs/server/tool-contributor.ts +2 -0
  94. package/plugins/ragents.ask/server/ask-tool.ts +1 -0
  95. package/plugins/ragents.orchestration/ragents-plugin.json +1 -0
  96. package/plugins/ragents.orchestration/server/contract.ts +14 -0
  97. package/plugins/ragents.orchestration/server/index.ts +4 -1
  98. package/plugins/ragents.orchestration/server/surface-tool.ts +58 -2
  99. package/plugins/ragents.orchestration/surface.hbs +5 -0
  100. package/plugins/ragents.reference/actors/notebook/package.json +16 -0
  101. package/plugins/ragents.reference/actors/notebook/src/client.tsx +31 -0
  102. package/plugins/ragents.reference/actors/notebook/src/server.ts +27 -0
  103. package/plugins/ragents.reference/actors/notebook/tests/program.test.ts +27 -0
  104. package/plugins/ragents.reference/run-scripts/quick-note/RUN.md +14 -0
  105. package/plugins/ragents.reference/run-scripts/quick-note/package.json +9 -0
  106. package/plugins/ragents.reference/run-scripts/quick-note/src/server.ts +29 -0
  107. package/plugins/ragents.reference/run-scripts/quick-note/tests/program.test.ts +43 -0
  108. package/plugins/ragents.reference/run-scripts/run-roster/RUN.md +19 -0
  109. package/plugins/ragents.reference/run-scripts/run-roster/package.json +9 -0
  110. package/plugins/ragents.reference/run-scripts/run-roster/src/server.ts +26 -0
  111. package/plugins/ragents.reference/run-scripts/run-roster/tests/program.test.ts +47 -0
  112. package/scripts/agent/agent-cli.ts +46 -2
  113. package/scripts/package/ragents.mjs +3 -1
  114. package/apps/web/dist/assets/runPanel-s8gGpr9M.js +0 -21
@@ -0,0 +1,26 @@
1
+ import{a as _,H as B,u as X,r as o,j as e,B as E,I as Fe,J as Me,K as De,v as Ue,l as W,m as Y,t as He,k as $e,P as Be,G as fe,L as Ve,p as Z,q as pe,i as qe,N as xe,O as le,T as Je,V as Ge,A as ce,Y as Ke,Z as Qe,_ as We,$ as Ye,s as Ze,a0 as Xe,e as et,a1 as tt,a2 as nt,x as st,y as rt,a3 as ot,a4 as at,a5 as it,z as lt,Q as ct,a6 as dt,a7 as ut,F as ht}from"./mermaid-HWGCJPDP-CSCkaArr.js";/**
2
+ * @license lucide-react v1.46.0 - ISC
3
+ *
4
+ * This source code is licensed under the ISC license.
5
+ * See the LICENSE file in the root directory of this source tree.
6
+ */const me={name:"ellipsis-vertical",size:24,node:[["circle",{cx:"12",cy:"12",r:"1",key:"41hilf"}],["circle",{cx:"12",cy:"5",r:"1",key:"gxeob9"}],["circle",{cx:"12",cy:"19",r:"1",key:"lyex9k"}]],aliases:["more-vertical"]};me.node;const ft=_(me);/**
7
+ * @license lucide-react v1.46.0 - ISC
8
+ *
9
+ * This source code is licensed under the ISC license.
10
+ * See the LICENSE file in the root directory of this source tree.
11
+ */const ve={name:"external-link",size:24,node:[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]]};ve.node;const pt=_(ve);/**
12
+ * @license lucide-react v1.46.0 - ISC
13
+ *
14
+ * This source code is licensed under the ISC license.
15
+ * See the LICENSE file in the root directory of this source tree.
16
+ */const ge={name:"layout-grid",size:24,node:[["rect",{width:"7",height:"7",x:"3",y:"3",rx:"1",key:"1g98yp"}],["rect",{width:"7",height:"7",x:"14",y:"3",rx:"1",key:"6d4xhi"}],["rect",{width:"7",height:"7",x:"14",y:"14",rx:"1",key:"nxv5o0"}],["rect",{width:"7",height:"7",x:"3",y:"14",rx:"1",key:"1bb6yr"}]]};ge.node;const xt=_(ge);/**
17
+ * @license lucide-react v1.46.0 - ISC
18
+ *
19
+ * This source code is licensed under the ISC license.
20
+ * See the LICENSE file in the root directory of this source tree.
21
+ */const we={name:"log-out",size:24,node:[["path",{d:"m16 17 5-5-5-5",key:"1bji2h"}],["path",{d:"M21 12H9",key:"dn1m92"}],["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4",key:"1uf3rs"}]]};we.node;const mt=_(we);/**
22
+ * @license lucide-react v1.46.0 - ISC
23
+ *
24
+ * This source code is licensed under the ISC license.
25
+ * See the LICENSE file in the root directory of this source tree.
26
+ */const be={name:"play",size:24,node:[["path",{d:"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z",key:"10ikf1"}]]};be.node;const vt=_(be),O="flex w-full cursor-pointer items-center gap-2.5 rounded-md px-2 py-1.5 text-left hover:bg-accent focus-visible:outline-2 focus-visible:outline-ring/60 focus-visible:-outline-offset-2 disabled:cursor-default disabled:opacity-50 disabled:hover:bg-transparent [&>svg]:size-4 [&>svg]:flex-none [&>svg]:text-muted-foreground",K=t=>t instanceof Error?t.message:String(t);function Q({onOpenSettings:t,runId:a}){const r=B(),n=X(),[l,c]=o.useState(!1),[u,f]=o.useState(!1),[m,x]=o.useState(),[d,b]=o.useState(),k=o.useRef(null),R=o.useId(),P=i=>{var p;return i.reason==="outside-press"&&i.event.target instanceof Node&&((p=k.current)==null?void 0:p.contains(i.event.target))===!0},v=()=>{c(!1),b(void 0),x(void 0)},g=()=>{if(r.kind==="vscode"){r.requestLogout(),c(!1);return}f(!0),x(void 0),n.logout().then(()=>c(!1)).catch(i=>x(K(i))).finally(()=>f(!1))},V=i=>{b({kind:"loading"}),x(void 0),W.call(Y.runs.scripts,{runId:i}).then(p=>b({kind:"ready",scripts:p})).catch(p=>{b({kind:"ready",scripts:[]}),x(K(p))})},z=(i,p)=>{f(!0),x(void 0),W.call(Y.runs.startScript,{runId:i,entry:p,input:null}).then(v).catch(F=>x(K(F))).finally(()=>f(!1))},h=a!==void 0&&n.can("runs.write")?a:void 0;return e.jsxs(e.Fragment,{children:[e.jsx(E,{"aria-controls":l?R:void 0,"aria-expanded":l,"aria-haspopup":"dialog","aria-label":"Panel menu",className:"self-center",onClick:()=>l?v():c(!0),ref:k,size:"icon-lg",title:"Menu",variant:"ghost",children:e.jsx(ft,{})}),e.jsx(Fe,{onOpenChange:(i,p)=>{!i&&P(p)||(i?c(!0):v())},open:l,children:e.jsxs(Me,{align:"end",anchor:k,"aria-label":"Panel menu",className:"w-[260px] gap-0 p-1 text-[0.8rem]",collisionPadding:8,dim:!0,id:R,role:"dialog",side:"bottom",children:[d&&h!==void 0?e.jsxs(e.Fragment,{children:[e.jsxs("button",{className:O,onClick:()=>{b(void 0),x(void 0)},type:"button",children:[e.jsx(De,{}),"Run script"]}),e.jsxs("div",{"aria-label":"Run scripts",className:"grid max-h-[50vh] overflow-auto border-t border-border-soft pt-1",role:"list",children:[d.kind==="loading"&&e.jsx("p",{className:"px-2 py-1.5 text-muted-foreground",children:"Loading run scripts ..."}),d.kind==="ready"&&d.scripts.length===0&&!m&&e.jsx("p",{className:"px-2 py-1.5 text-muted-foreground",children:"This profile has no run scripts for you."}),d.kind==="ready"&&d.scripts.map(i=>e.jsx("button",{className:O,disabled:u||!i.available,onClick:()=>z(h,i.id),role:"listitem",title:i.reason??i.description,type:"button",children:e.jsxs("span",{className:"grid min-w-0",children:[e.jsx("span",{className:"truncate",children:i.title}),e.jsx("span",{className:"line-clamp-2 text-[0.68rem] text-muted-foreground",children:i.available?i.description:i.reason})]})},i.id))]})]}):e.jsxs(e.Fragment,{children:[e.jsxs("button",{className:O,onClick:()=>{v(),t()},type:"button",children:[e.jsx(Ue,{}),"Settings"]}),h!==void 0&&e.jsxs("button",{className:O,onClick:()=>V(h),type:"button",children:[e.jsx(vt,{}),"Run script"]}),r.kind==="vscode"&&e.jsxs("button",{className:O,onClick:()=>{v(),r.openExternal(new URL("/",window.location.href).toString())},type:"button",children:[e.jsx(pt,{}),"Open in browser"]}),n.enabled&&n.user&&e.jsxs("button",{className:O,disabled:u,onClick:g,title:n.user.id,type:"button",children:[e.jsx(mt,{}),e.jsxs("span",{className:"grid min-w-0",children:[e.jsx("span",{children:"Sign out"}),e.jsx("span",{className:"truncate text-[0.68rem] text-muted-foreground",children:n.user.label})]})]})]}),m&&e.jsx("p",{className:"px-2 py-1.5 text-[0.72rem] text-destructive",role:"alert",children:m})]})})]})}const gt=5e3;function je(t){const[a,r]=o.useState([]),[n,l]=o.useState(!1),c=o.useRef(void 0),u=o.useRef(!1),f=o.useCallback(()=>{if(!t)return Promise.resolve();if(c.current)return u.current=!0,c.current;const m=async()=>{do{u.current=!1;try{r(await He()),l(!1)}catch{l(!0)}}while(u.current)};return c.current=m().finally(()=>{c.current=void 0}),c.current},[t]);return o.useEffect(()=>{if(!t)return;f();const m=W.subscribe(Y.channels.runs,{},()=>void f()),x=setInterval(()=>void f(),gt);return()=>{m(),clearInterval(x)}},[t,f]),{sessions:a,unreachable:n,refresh:f}}const Se="relative z-[80] flex h-header flex-none items-stretch border-b border-border bg-shell shadow-bar",de="max-w-[120px] self-center truncate rounded-full bg-secondary px-2 py-0.5 text-[0.66rem] font-semibold text-muted-foreground",wt="min-w-0 flex-1 self-center truncate px-1.5 text-[0.82rem] font-semibold",bt="Stopped in the run panel",jt=5e3,S="New run",St="relative z-[80] flex h-header flex-none items-center gap-2 border-b border-border bg-shell px-3 shadow-bar",ye="m-auto max-w-[420px] p-6 text-center text-muted-foreground",yt=new Set,kt=()=>({id:crypto.randomUUID(),title:S,updatedAt:Date.now()}),ke=(t,a="Run")=>({id:t,title:a,updatedAt:Date.now()}),Nt={kind:"working",title:"Loading profile",detail:"Loading the server's interface."},Rt={kind:"working",title:"Starting run",detail:"Creating the new run."},ue={kind:"working",title:"Starting run",detail:"Starting the template."},Ct={kind:"waiting",title:"No run selected",detail:"On the Start page you start a new run or open an existing one."},Et={kind:"error",title:"No runs enabled",detail:"No runs are enabled for this user account."};function It({location:t}){const a=$e(),r=t.layout==="app";if(a.status==="loading")return e.jsx(y,{headless:r,state:Nt});if(a.status==="failed")return e.jsx(y,{headless:r,state:{kind:"error",title:"The profile could not be loaded",detail:a.error},children:e.jsx(E,{onClick:()=>window.location.reload(),size:"sm",variant:"outline",children:"Reload"})});const n=t.layout==="app"?e.jsx(Tt,{elementId:t.elementId,registry:a.registry,runId:t.runId}):e.jsx(Ot,{connection:t.connection,initialRunId:t.runId,registry:a.registry});return a.failures.length===0?n:e.jsxs("div",{className:"flex h-full flex-col",children:[e.jsx(Be,{failures:a.failures}),e.jsx("div",{className:"flex min-h-0 flex-1 flex-col",children:n})]})}function Ot({connection:t,initialRunId:a,registry:r}){var ie;const n=B(),l=X(),c=l.can("runs.read"),u=c&&l.can("runs.write"),f=u&&l.can("runs.create"),m=f||u&&r.scriptEntries.some(s=>pe(l,s.id)),x=qe((ie=l.user)==null?void 0:ie.id),[d,b]=o.useState(a),[k,R]=o.useState(),[P,v]=o.useState(),g=o.useCallback(()=>v(s=>s===d?void 0:s),[d]),[V,z]=o.useState(),[h,i]=o.useState(),[p,F]=o.useState(),q=o.useRef(void 0),j=o.useCallback(s=>{q.current=s==null?void 0:s.runId,F(s)},[]),[ee,J]=o.useState(),[L,te]=o.useState(!1),[ne,se]=o.useState(),G=o.useCallback(()=>te(!0),[]),{sessions:re,unreachable:Re,refresh:Ce}=je(c&&!h&&!p),[Ee,Ie]=o.useState(null),[Oe,Pe]=o.useState(null),T=o.useCallback((s,w)=>{var $;const N=($=r.startEntries.find(ze=>ze.id===w))==null?void 0:$.fixedStartOptions;i({session:kt(),startOptions:s&&xe(s,N),entryId:w})},[r]),Le=o.useCallback(()=>T(),[T]),A=o.useCallback((s,w)=>{i(void 0),j(void 0),z(w),b(s),v(n.kind==="vscode"?s:void 0)},[n.kind,j]),oe=o.useCallback(s=>{i(void 0),j(s),Pt(s,r,l).then(()=>{q.current===s.runId&&A(s.runId)},w=>{q.current===s.runId&&F({...s,error:w instanceof Error?w.message:String(w)})})},[l,A,r,j]),Te=o.useCallback(s=>{v(void 0),R(void 0),b(s)},[]),M=o.useCallback(()=>{v(void 0),i(void 0),j(void 0),J(void 0),n.kind==="vscode"?n.notify({type:"showStart"}):b(void 0)},[n,j]);o.useLayoutEffect(()=>{if(P){if(L||h){g();return}return window.addEventListener("pointerdown",g,!0),window.addEventListener("keydown",g,!0),window.addEventListener("blur",g),()=>{window.removeEventListener("pointerdown",g,!0),window.removeEventListener("keydown",g,!0),window.removeEventListener("blur",g)}}},[h,P,L,g]),o.useEffect(()=>n.onCommand(s=>{if(s.type==="selectRun"&&(v(void 0),i(void 0),j(void 0),J(void 0),z(void 0),R(void 0),b(s.runId??void 0)),s.type!=="newRun")return;if(n.kind!=="vscode"){m&&T(s.startOptions,s.entryId);return}const w=m?s.entryId===void 0&&!f?"Free runs are not enabled for this user account.":void 0:"New runs are not enabled for this user account.";if(J(w),w!==void 0)return;const N=r.startEntries.find($=>$.id===s.entryId);if(R((N==null?void 0:N.title)??S),s.entryId===void 0){A(crypto.randomUUID(),s.startOptions);return}if(N!==void 0&&r.guideFor(N)!==void 0){j(void 0),T(s.startOptions,N.id);return}oe({runId:crypto.randomUUID(),entryId:s.entryId,startOptions:s.startOptions})}),[m,f,n,A,r,j,T,oe]),o.useEffect(()=>{n.notify({type:"ready"})},[n]),o.useEffect(()=>{n.notify({type:"runChanged",runId:d??null})},[n,d]);const D=L&&e.jsx(Ze,{onClose:()=>te(!1),registry:r}),I=s=>e.jsxs(e.Fragment,{children:[e.jsx(E,{"aria-label":"Back to Start",className:"self-center",onClick:M,size:"icon-lg",title:"Back to Start",variant:"ghost",children:e.jsx(le,{})}),e.jsx("strong",{className:wt,children:s}),t&&e.jsx("span",{className:de,title:`Server ${t}`,children:t}),e.jsx(Q,{onOpenSettings:G})]}),U=e.jsx(E,{onClick:M,size:"sm",variant:"outline",children:"Back to Start"}),ae=h&&e.jsx(Z,{initialStartOptions:h.startOptions,onStarted:()=>{A(h.session.id),R(s=>s??S),Ce()},registry:r,session:h.session,startDialog:{onClose:n.kind==="vscode"?M:()=>i(void 0),initialEntryId:h.entryId}},h.session.id);if(p)return e.jsxs(e.Fragment,{children:[p.error===void 0?e.jsx(y,{header:I(k??S),state:ue}):e.jsx(y,{header:I(k??S),state:{kind:"error",title:"The run could not be started",detail:p.error},children:U}),D]});if(n.kind==="vscode"&&h)return e.jsxs(e.Fragment,{children:[e.jsx(y,{header:I(k??S),state:ue}),ae,D]});if(n.kind==="vscode"&&!(c&&d))return e.jsxs(e.Fragment,{children:[c?ee!==void 0?e.jsx(y,{header:I(S),state:{kind:"error",title:"No new run possible",detail:ee},children:U}):e.jsx(Lt,{header:I(S),children:U}):e.jsx(y,{header:I(S),state:Et,children:U}),D]});const H=re.find(s=>s.id===d),Ae=()=>{d!==void 0&&(se(void 0),Xe(d,bt).catch(s=>se(`Stop failed: ${s instanceof Error?s.message:String(s)}`)))},_e=c?e.jsx(et,{activeId:d,onCreate:m?Le:void 0,onSelect:Te,onToggleSelected:()=>{},registry:r,seenRevisions:x.revisions,selectMode:!1,selectedIds:yt,sessions:re}):e.jsx("p",{className:ye,children:"No runs are enabled for this user account."});return e.jsxs("div",{className:"flex h-full flex-col bg-[image:var(--surface-backdrop)]",children:[c&&d?e.jsxs(e.Fragment,{children:[e.jsxs("header",{className:Se,children:[e.jsx(E,{"aria-label":"Back to Start",className:"self-center",onClick:M,size:"icon-lg",title:"Back to Start",variant:"ghost",children:e.jsx(le,{})}),e.jsx("div",{"aria-label":"Run title bar",className:"flex min-w-0 flex-1 items-stretch overflow-x-auto no-scrollbar",ref:Ie,role:"region"}),t&&e.jsx("span",{className:de,title:`Server ${t}`,children:t}),e.jsx(Je,{className:"self-center px-1.5",state:H!=null&&H.running?"running":"idle"}),e.jsx(Ge,{className:"self-center",disabled:!u,label:"Stop run",onClick:Ae,size:"icon-lg",title:"Stop the run with all agents and flows"}),e.jsx("div",{"aria-label":"Panel tools",className:"flex flex-none items-center empty:hidden",ref:Pe,role:"toolbar"}),e.jsx(Q,{onOpenSettings:G,runId:d})]}),ne&&e.jsx(ce,{variant:"destructive",children:ne}),e.jsx("main",{className:"relative z-1 flex min-h-0 min-w-0 flex-1 @container/chat-content",children:e.jsx(Z,{autoFocusChat:P===d&&!L&&!h,onAutoFocusChatSettled:g,toolbarContainer:Oe,headerContainer:Ee,initialStartOptions:V,layout:"panel",onViewed:x.markViewed,registry:r,session:H??ke(d,k),viewing:!h&&!L},d)})]}):e.jsxs(e.Fragment,{children:[e.jsxs("header",{className:St,children:[e.jsx(xt,{"aria-hidden":!0,className:"size-4 flex-none text-muted-foreground"}),e.jsx("strong",{className:"min-w-0 flex-1 truncate text-[0.82rem] font-semibold",children:r.brand.title}),e.jsx(Q,{onOpenSettings:G})]}),e.jsxs("div",{className:"min-h-0 flex-1 overflow-auto p-3",children:[Re&&e.jsx(ce,{className:"mb-3",variant:"destructive",children:"The server is unreachable."}),_e]})]}),D,ae]})}async function Pt(t,a,r){const n=a.startEntries.find(l=>l.id===t.entryId);if(!n)throw new Error("This template does not exist in this profile.");if(!pe(r,n.id))throw new Error(`${n.title} is not enabled for this user account.`);if(t.startOptions){const l=await Ke(t.runId),c=xe(t.startOptions,n.fixedStartOptions);for(const[u,f]of Qe(l,c))await We(t.runId,u,f)}await Ye(t.runId,n,null)}function Lt({children:t,header:a}){const[r,n]=o.useState(!1);return o.useEffect(()=>{const l=window.setTimeout(()=>n(!0),jt);return()=>window.clearTimeout(l)},[]),r?e.jsx(y,{header:a,state:Ct,children:t}):e.jsx(y,{header:a,state:Rt})}function y({children:t,header:a,headless:r=!1,state:n}){return e.jsxs("div",{className:"flex h-full flex-col bg-[image:var(--surface-backdrop)]",children:[!r&&e.jsx("header",{className:Se,children:a}),e.jsx("main",{className:"grid min-h-0 flex-1 place-items-center overflow-hidden p-6",children:e.jsx(Ve,{state:n,children:t})})]})}function Tt({elementId:t,registry:a,runId:r}){const n=B(),l=X().can("runs.read"),{sessions:c}=je(l);return o.useEffect(()=>{n.notify({type:"ready"})},[n]),l?e.jsx("main",{className:"relative flex h-full min-h-0 min-w-0 flex-1 bg-background @container/chat-content",children:e.jsx(Z,{layout:{element:t},registry:a,session:c.find(u=>u.id===r)??ke(r)},r)}):e.jsx("p",{className:ye,children:"No runs are enabled for this user account."})}function At(){const t=B();return e.jsxs(fe,{children:[e.jsx("h1",{className:"my-3 text-[1.5rem]",children:"Sign-in required"}),e.jsx("p",{className:"mb-6 leading-normal text-muted-foreground",children:"Sign-in goes through VS Code. The panel then reloads."}),e.jsx(E,{className:"w-full",onClick:()=>t.requestLogin(),children:"Sign in with VS Code"})]})}const C=t=>t!=null&&t.trim()?t.trim():void 0,_t=t=>{if(t==="browser"||t==="vscode")return t;throw new Error(`Unknown host ${JSON.stringify(t)}. Allowed are browser and vscode.`)};function zt(t){const a=new URLSearchParams(t),r=C(a.get("layout"))??"panel";if(r!=="panel"&&r!=="app")throw new Error(`Unknown layout ${JSON.stringify(r)}. Allowed are panel and app.`);const n=C(a.get("theme"));if(n!==void 0&&!tt(n))throw new Error(`Unknown theme ${JSON.stringify(n)}. Allowed are light and dark.`);const l={host:_t(C(a.get("host"))??"browser"),connection:C(a.get("connection")),theme:n,access:C(a.get(nt))},c=C(a.get("run"));if(r==="panel")return{layout:r,runId:c,...l};const u=C(a.get("element"));if(!c||!u)throw new Error("The app layout needs run and element.");return{layout:r,runId:c,elementId:u,...l}}st();const Ne=document.getElementById("root");if(!Ne)throw new Error("Root element is missing");const he=rt.createRoot(Ne);try{const t=zt(window.location.search);t.access!==void 0&&ot(t.access);const a=at(t.host,window);if(t.host==="vscode"){const n=it(window)}const r=lt(window);t.theme!==void 0&&r.setPreference(t.theme),a.onCommand(n=>{n.type==="theme"&&r.setPreference(n.theme)}),he.render(e.jsx(o.StrictMode,{children:e.jsx(ct,{children:e.jsx(dt,{value:a,children:e.jsx(ut,{value:t.host==="vscode"?{open:a.openPage}:void 0,children:e.jsx(ht,{Login:t.host==="vscode"?At:void 0,children:e.jsx(It,{location:t})})})})})}))}catch(t){he.render(e.jsxs(fe,{children:[e.jsx("h1",{className:"my-3 text-[1.5rem]",children:"The RAgents panel could not be loaded"}),e.jsx("p",{className:"mb-6 leading-normal",role:"alert",children:t instanceof Error?t.message:String(t)}),e.jsx(E,{onClick:()=>window.location.reload(),variant:"outline",children:"Reload"})]}))}
@@ -137,6 +137,13 @@ tab bar on the right. Without <code>run</code>, it shows the run list with &quot
137
137
  card. <code>run-panel.html?layout=app&amp;run=&lt;id&gt;&amp;element=&lt;app-id&gt;</code> shows one mini-app without the tab bar.
138
138
  Run-panel state, including the selected app and actor, view mode, chat width, collapsed chat
139
139
  height, open tab, and tab-area height, is stored per run in the browser.</p>
140
+ <p>With write rights, the menu at the top right of an open run offers &quot;Run script&quot;: it lists the run
141
+ scripts you may start, each with its description, and greyed out with the reason when it cannot
142
+ join this run, because its <code>RUN.md</code> does not set <code>embeddable: true</code> or because it fixes a start
143
+ option to a value the run does not have. A click starts it inside the run without a start value;
144
+ the primary actor stays, a repeated start reuses the script, its main view is placed next to the
145
+ tiles, and its output and summary appear in the chat as <code>@handle: ...</code>. If the start is refused,
146
+ the menu shows why. The same menu works in the VS Code run panel.</p>
140
147
  <p>The narrow tab bar on the right contains the same tabs as the full web view: files, documents,
141
148
  functions, executions, and language-server diagnostics, depending on the run and the user&#39;s
142
149
  permissions. The tab name appears in a tooltip. A small counter sits at the top right of its
@@ -328,9 +335,9 @@ in their URL (the server accepts a bearer token or the <code>access</code> query
328
335
  After expiry or a server restart, that server asks for sign-in again without affecting others.
329
336
  <code>RAgents: Sign out</code> revokes the session.</p>
330
337
  <h2 id="control-ragents-as-an-agent">Control RAgents as an agent</h2>
331
- <p>An AI agent working on the same machine controls RAgents through four <code>ragents</code> subcommands. In
332
- a checkout, use <code>pnpm ragents &lt;command&gt;</code>. These commands are the agent-facing contract: each one
333
- waits for the turn to end and returns an exit code.</p>
338
+ <p>An AI agent working on the same machine controls RAgents through five <code>ragents</code> subcommands. In
339
+ a checkout, use <code>pnpm ragents &lt;command&gt;</code>. These commands are the agent-facing contract: <code>run</code> and
340
+ <code>send</code> wait for the turn to end, and every command returns an exit code.</p>
334
341
  <pre><code class="language-sh">ragents provision developer # once per machine
335
342
  ragents run selftest/workspace-project &quot;Fix the type error in src/broken.ts&quot;
336
343
  ragents send &lt;runId&gt; &quot;Read README.md and report the passphrase&quot;
@@ -338,6 +345,8 @@ ragents journal &lt;runId&gt; --tools
338
345
  ragents stop &lt;runId&gt; # interrupt the primary actor&#39;s active turn
339
346
  ragents stop &lt;runId&gt; --run # emergency stop: halt the whole run
340
347
  ragents stop --host # stop the remembered host
348
+ ragents script &lt;runId&gt; # list the run scripts and whether each can join the run
349
+ ragents script &lt;runId&gt; &lt;entry&gt; --input &#39;{&quot;topic&quot;:&quot;Launch&quot;}&#39; # start one inside the running run
341
350
  ragents --help # same as ragents help
342
351
  </code></pre>
343
352
  <p><code>run</code> checks <code>GET &lt;address&gt;/health</code> to see whether the profile host is already running. If not,
@@ -370,7 +379,11 @@ exactly like the stop button in the chat input: the run and all actors stay acti
370
379
  next task, and without an active turn nothing happens. <code>stop &lt;runId&gt; --run</code> is the emergency stop (<code>ragents.chat.stop</code>): it aborts every turn
371
380
  and stops all actors of the run. <code>stop --host</code> terminates exactly the PID in <code>host.json</code>, never a
372
381
  process pattern, and only if the host at the recorded address reports that same PID from
373
- <code>/health</code>; otherwise it fails, leaves the process alone and removes the stale record. <code>ragents --help</code> and <code>ragents help</code> show usage and exit with 0; invoking the
382
+ <code>/health</code>; otherwise it fails, leaves the process alone and removes the stale record.
383
+ <code>script &lt;runId&gt;</code> lists the run scripts through <code>ragents.runs.scripts</code>, one per line with id, title,
384
+ and the reason if one cannot join; <code>script &lt;runId&gt; &lt;entry&gt; [--input &lt;json&gt;]</code> starts it inside the
385
+ run through <code>ragents.runs.startScript</code> as the run&#39;s user and prints <code>script: @&lt;handle&gt;, start &lt;n&gt;</code>;
386
+ a refusal is an error with exit code 1. <code>--json</code> prints the RPC results instead. <code>ragents --help</code> and <code>ragents help</code> show usage and exit with 0; invoking the
374
387
  command without arguments is an error with exit code 1.</p>
375
388
  <p><code>--profile &lt;profile|path&gt;</code> selects something other than <code>developer</code>: a profile name beside the
376
389
  host or the path to a custom <code>ragents.config.&lt;profile&gt;.ts</code> anywhere on disk. Resolution matches
@@ -436,6 +449,10 @@ requests as Server-Sent Events:</p>
436
449
  -d &#39;{&quot;jsonrpc&quot;:&quot;2.0&quot;,&quot;id&quot;:1,&quot;method&quot;:&quot;ragents.runs.list&quot;,&quot;params&quot;:{}}&#39;
437
450
  </code></pre>
438
451
  <p>The response contains either <code>result</code> or <code>error</code>; <code>error.data</code> provides <code>code</code> and <code>status</code>.</p>
452
+ <p>A run script whose <code>RUN.md</code> sets <code>embeddable: true</code> also starts inside a running run:
453
+ <code>ragents.runs.startScript</code> with <code>runId</code>, <code>entry</code>, and <code>input</code> waits and returns the script actor and
454
+ which start of its package in the run this was, or the reason in <code>error</code>. The primary actor stays;
455
+ a repeated start reuses the script&#39;s actor.</p>
439
456
  <p>Without HTTP, use stdio: <code>pnpm start -- --stdio</code> exchanges one JSON message per line through
440
457
  stdin and stdout and opens no port. The startup modes are:</p>
441
458
  <ul>
@@ -11,6 +11,14 @@ card. `run-panel.html?layout=app&run=<id>&element=<app-id>` shows one mini-app w
11
11
  Run-panel state, including the selected app and actor, view mode, chat width, collapsed chat
12
12
  height, open tab, and tab-area height, is stored per run in the browser.
13
13
 
14
+ With write rights, the menu at the top right of an open run offers "Run script": it lists the run
15
+ scripts you may start, each with its description, and greyed out with the reason when it cannot
16
+ join this run, because its `RUN.md` does not set `embeddable: true` or because it fixes a start
17
+ option to a value the run does not have. A click starts it inside the run without a start value;
18
+ the primary actor stays, a repeated start reuses the script, its main view is placed next to the
19
+ tiles, and its output and summary appear in the chat as `@handle: ...`. If the start is refused,
20
+ the menu shows why. The same menu works in the VS Code run panel.
21
+
14
22
  The narrow tab bar on the right contains the same tabs as the full web view: files, documents,
15
23
  functions, executions, and language-server diagnostics, depending on the run and the user's
16
24
  permissions. The tab name appears in a tooltip. A small counter sits at the top right of its
@@ -224,9 +232,9 @@ After expiry or a server restart, that server asks for sign-in again without aff
224
232
 
225
233
  ## Control RAgents as an agent
226
234
 
227
- An AI agent working on the same machine controls RAgents through four `ragents` subcommands. In
228
- a checkout, use `pnpm ragents <command>`. These commands are the agent-facing contract: each one
229
- waits for the turn to end and returns an exit code.
235
+ An AI agent working on the same machine controls RAgents through five `ragents` subcommands. In
236
+ a checkout, use `pnpm ragents <command>`. These commands are the agent-facing contract: `run` and
237
+ `send` wait for the turn to end, and every command returns an exit code.
230
238
 
231
239
  ```sh
232
240
  ragents provision developer # once per machine
@@ -236,6 +244,8 @@ ragents journal <runId> --tools
236
244
  ragents stop <runId> # interrupt the primary actor's active turn
237
245
  ragents stop <runId> --run # emergency stop: halt the whole run
238
246
  ragents stop --host # stop the remembered host
247
+ ragents script <runId> # list the run scripts and whether each can join the run
248
+ ragents script <runId> <entry> --input '{"topic":"Launch"}' # start one inside the running run
239
249
  ragents --help # same as ragents help
240
250
  ```
241
251
 
@@ -272,7 +282,11 @@ exactly like the stop button in the chat input: the run and all actors stay acti
272
282
  next task, and without an active turn nothing happens. `stop <runId> --run` is the emergency stop (`ragents.chat.stop`): it aborts every turn
273
283
  and stops all actors of the run. `stop --host` terminates exactly the PID in `host.json`, never a
274
284
  process pattern, and only if the host at the recorded address reports that same PID from
275
- `/health`; otherwise it fails, leaves the process alone and removes the stale record. `ragents --help` and `ragents help` show usage and exit with 0; invoking the
285
+ `/health`; otherwise it fails, leaves the process alone and removes the stale record.
286
+ `script <runId>` lists the run scripts through `ragents.runs.scripts`, one per line with id, title,
287
+ and the reason if one cannot join; `script <runId> <entry> [--input <json>]` starts it inside the
288
+ run through `ragents.runs.startScript` as the run's user and prints `script: @<handle>, start <n>`;
289
+ a refusal is an error with exit code 1. `--json` prints the RPC results instead. `ragents --help` and `ragents help` show usage and exit with 0; invoking the
276
290
  command without arguments is an error with exit code 1.
277
291
 
278
292
  `--profile <profile|path>` selects something other than `developer`: a profile name beside the
@@ -355,6 +369,11 @@ curl -s http://localhost:4710/rpc -H 'content-type: application/json' \
355
369
 
356
370
  The response contains either `result` or `error`; `error.data` provides `code` and `status`.
357
371
 
372
+ A run script whose `RUN.md` sets `embeddable: true` also starts inside a running run:
373
+ `ragents.runs.startScript` with `runId`, `entry`, and `input` waits and returns the script actor and
374
+ which start of its package in the run this was, or the reason in `error`. The primary actor stays;
375
+ a repeated start reuses the script's actor.
376
+
358
377
  Without HTTP, use stdio: `pnpm start -- --stdio` exchanges one JSON message per line through
359
378
  stdin and stdout and opens no port. The startup modes are:
360
379
 
@@ -194,6 +194,11 @@ functions, actor programs, language servers, and interfaces; they add no new mec
194
194
  <td>Setup in code, domain decisions in the responsible model</td>
195
195
  </tr>
196
196
  <tr>
197
+ <td>Program several run scripts use</td>
198
+ <td>Shared actor package in the owning plugin (<code>actors/&lt;name&gt;/</code>)</td>
199
+ <td>One actor per run; scripts name it and ensure it, none copies it</td>
200
+ </tr>
201
+ <tr>
197
202
  <td>Reusable work instructions</td>
198
203
  <td>Skill in the owning plugin</td>
199
204
  <td>Describes the approach but does not perform required initialization</td>
@@ -253,6 +258,11 @@ a successful check. A compact status contract can expose state and work step wit
253
258
  reasoning or tool arguments. Grant diagnostic and change permissions independently from full
254
259
  technical inspection and enforce them on the server. Roles belong in configuration; neutral
255
260
  components check permissions, not user names.</p>
261
+ <p>A service that trusts a TypeScript actor more than others asks the actor programs service who it
262
+ is: <code>programOf(runId, actorId)</code> names the package, its revision, and its origin, a shared package
263
+ of a plugin, a run script&#39;s template, or a package created in the run, and a package changed in the
264
+ run counts as created there. Authorize by that identity, never by handle or package name: any
265
+ agent with the program functions creates a package under any free name.</p>
256
266
  <h3 id="7-develop-mini-apps-in-the-actual-host">7. Develop mini-apps in the actual host</h3>
257
267
  <p>The iframe constrains interaction, layout, and communication. Use shared controls and the
258
268
  declared function bridge. For a dialog spanning host areas, the app signals intent through a
@@ -341,8 +351,8 @@ bound identity apply equally, while a program&#39;s <code>capabilities</code> li
341
351
  <p>Every domain function is available through <code>context.functions</code> in <code>typescript_eval</code>.
342
352
  <code>nativeTool: true</code> additionally exposes it as a native model tool when the model normally must
343
353
  read its result before taking the next step: browser interactions, domain reports and status,
344
- language diagnostics, <code>read</code>, <code>edit</code>, <code>write</code>, <code>bash</code>, <code>document_write</code>, <code>show_document</code>, and
345
- <code>browser_view_screenshot</code>, which can return image pixels only natively. Snippets remain the right
354
+ language diagnostics, <code>read</code>, <code>edit</code>, <code>write</code>, <code>bash</code>, <code>document_write</code>, <code>show_document</code>,
355
+ <code>ask_user</code>, and <code>browser_view_screenshot</code>, which can return image pixels only natively. Snippets remain the right
346
356
  form for calls that combine, filter, or pass results onward, including data queries, management
347
357
  functions, list results, and values passed from earlier responses without transcription. Native
348
358
  tools remain callable from snippets. The building-block reference marks them in the catalog and
@@ -37,6 +37,7 @@ functions, actor programs, language servers, and interfaces; they add no new mec
37
37
  | Investigation, conversation, or multi-step implementation | LLM actor with suitable functions | Context and tools must match the task |
38
38
  | Controls or status for an existing actor | View on that actor | An interface alone does not justify another actor |
39
39
  | Repeatable prepared run | Run script in the owning plugin | Setup in code, domain decisions in the responsible model |
40
+ | Program several run scripts use | Shared actor package in the owning plugin (`actors/<name>/`) | One actor per run; scripts name it and ensure it, none copies it |
40
41
  | Reusable work instructions | Skill in the owning plugin | Describes the approach but does not perform required initialization |
41
42
 
42
43
  ### 1. Keep capabilities and workflows separate
@@ -105,6 +106,12 @@ reasoning or tool arguments. Grant diagnostic and change permissions independent
105
106
  technical inspection and enforce them on the server. Roles belong in configuration; neutral
106
107
  components check permissions, not user names.
107
108
 
109
+ A service that trusts a TypeScript actor more than others asks the actor programs service who it
110
+ is: `programOf(runId, actorId)` names the package, its revision, and its origin, a shared package
111
+ of a plugin, a run script's template, or a package created in the run, and a package changed in the
112
+ run counts as created there. Authorize by that identity, never by handle or package name: any
113
+ agent with the program functions creates a package under any free name.
114
+
108
115
  ### 7. Develop mini-apps in the actual host
109
116
 
110
117
  The iframe constrains interaction, layout, and communication. Use shared controls and the
@@ -212,8 +219,8 @@ bound identity apply equally, while a program's `capabilities` limit its install
212
219
  Every domain function is available through `context.functions` in `typescript_eval`.
213
220
  `nativeTool: true` additionally exposes it as a native model tool when the model normally must
214
221
  read its result before taking the next step: browser interactions, domain reports and status,
215
- language diagnostics, `read`, `edit`, `write`, `bash`, `document_write`, `show_document`, and
216
- `browser_view_screenshot`, which can return image pixels only natively. Snippets remain the right
222
+ language diagnostics, `read`, `edit`, `write`, `bash`, `document_write`, `show_document`,
223
+ `ask_user`, and `browser_view_screenshot`, which can return image pixels only natively. Snippets remain the right
217
224
  form for calls that combine, filter, or pass results onward, including data queries, management
218
225
  functions, list results, and values passed from earlier responses without transcription. Native
219
226
  tools remain callable from snippets. The building-block reference marks them in the catalog and
@@ -181,8 +181,11 @@ views.</p>
181
181
  as its default export. The TypeBox contract describes <code>state</code>, <code>functions</code>, and optional <code>input</code>.</p>
182
182
  <p>State must accept the initial value <code>{}</code>. Each function declares its input and output, with
183
183
  optional granted capabilities, confirmation, and publication as a tool. The implementation
184
- contains the same functions and, when input is declared, an <code>onInput</code> handler. TypeScript derives
185
- input, result, and state types from the contract.</p>
184
+ contains the same functions and, when input is declared, an <code>onInput</code> handler; a run script can
185
+ add <code>onStart</code>, which receives its starts instead of <code>onInput</code>, <code>onResult</code> for the results of scripts
186
+ it starts itself, and ends a start with <code>context.finish</code> (details in
187
+ <a href="https://github.com/SchlenkR/RAgents/blob/main/docs/spec/typescript-platform.md">TypeScript platform</a>, Run scripts). TypeScript derives input, result, and
188
+ state types from the contract.</p>
186
189
  <p>Each function receives <code>(input, context)</code> and returns only its domain result.
187
190
  <code>context.state.replace</code> stages state changes; a return value is never also interpreted as new
188
191
  state. <code>context.actor</code> identifies the actor that owns the function and state.
@@ -227,6 +230,9 @@ only then activates the verified version. Errors identify the location to fix.</
227
230
  <code>typescript_api</code> returns their exact contracts, and snippets call them through
228
231
  <code>context.functions</code>. Reactivation updates the schemas; removed functions disappear from the same
229
232
  catalog. No additional call contract is needed.</p>
233
+ <p><code>actor_program_ensure</code> makes a package active only when it is not: it returns an active package
234
+ unchanged, restarts its stopped actor, activates an installed package, or installs a shared
235
+ package of the profile (<a href="https://github.com/SchlenkR/RAgents/blob/main/docs/spec/typescript-platform.md">TypeScript platform</a>, Run scripts).</p>
230
236
  <p><code>actor_program_list</code> shows installed programs. <code>actor_program_remove</code> removes the binding and its
231
237
  views. It also stops a TypeScript actor, while an existing LLM actor remains. Activating a package
232
238
  of the same name again restarts that stopped actor with its state instead of creating another. Sources stay
@@ -65,8 +65,11 @@ as its default export. The TypeBox contract describes `state`, `functions`, and
65
65
 
66
66
  State must accept the initial value `{}`. Each function declares its input and output, with
67
67
  optional granted capabilities, confirmation, and publication as a tool. The implementation
68
- contains the same functions and, when input is declared, an `onInput` handler. TypeScript derives
69
- input, result, and state types from the contract.
68
+ contains the same functions and, when input is declared, an `onInput` handler; a run script can
69
+ add `onStart`, which receives its starts instead of `onInput`, `onResult` for the results of scripts
70
+ it starts itself, and ends a start with `context.finish` (details in
71
+ [TypeScript platform](https://github.com/SchlenkR/RAgents/blob/main/docs/spec/typescript-platform.md), Run scripts). TypeScript derives input, result, and
72
+ state types from the contract.
70
73
 
71
74
  Each function receives `(input, context)` and returns only its domain result.
72
75
  `context.state.replace` stages state changes; a return value is never also interpreted as new
@@ -119,6 +122,10 @@ Published functions appear in the current TypeScript API even during an active L
119
122
  `context.functions`. Reactivation updates the schemas; removed functions disappear from the same
120
123
  catalog. No additional call contract is needed.
121
124
 
125
+ `actor_program_ensure` makes a package active only when it is not: it returns an active package
126
+ unchanged, restarts its stopped actor, activates an installed package, or installs a shared
127
+ package of the profile ([TypeScript platform](https://github.com/SchlenkR/RAgents/blob/main/docs/spec/typescript-platform.md), Run scripts).
128
+
122
129
  `actor_program_list` shows installed programs. `actor_program_remove` removes the binding and its
123
130
  views. It also stops a TypeScript actor, while an existing LLM actor remains. Activating a package
124
131
  of the same name again restarts that stopped actor with its state instead of creating another. Sources stay
@@ -317,8 +317,9 @@ way, by the host, a run script, or an actor program, are checked by the schedule
317
317
  it runs (any driver except <code>manual</code>) is created or restarted, it resolves the requested names the way a turn would, counting functions
318
318
  that are currently unavailable as known. A name that no host function provides stops the actor
319
319
  before its first turn, and the stop reason names the unknown tools. The selection is not
320
- inherited, although delegable engine capabilities still are. <code>withoutCapabilities</code> removes
321
- named technical permissions. Availability and grants also apply when the value is <code>null</code>.
320
+ inherited, although delegable engine capabilities still are, except that an inherited copy of a
321
+ first-hand capability (<code>firstHandCapabilities</code> in <code>domain/vocabulary.ts</code>, today <code>script.start</code>) is
322
+ not delegable further. <code>withoutCapabilities</code> removes named technical permissions. Availability and grants also apply when the value is <code>null</code>.
322
323
  <code>forkOf</code> (a handle or ID) makes the new agent a fork of an LLM agent in the same run:
323
324
  <code>agent.spawned</code> records the source, and the new agent&#39;s context begins with an unchanged copy of
324
325
  the source&#39;s context up to the end of the source&#39;s last finished turn, reasoning blocks included.
@@ -203,8 +203,9 @@ way, by the host, a run script, or an actor program, are checked by the schedule
203
203
  it runs (any driver except `manual`) is created or restarted, it resolves the requested names the way a turn would, counting functions
204
204
  that are currently unavailable as known. A name that no host function provides stops the actor
205
205
  before its first turn, and the stop reason names the unknown tools. The selection is not
206
- inherited, although delegable engine capabilities still are. `withoutCapabilities` removes
207
- named technical permissions. Availability and grants also apply when the value is `null`.
206
+ inherited, although delegable engine capabilities still are, except that an inherited copy of a
207
+ first-hand capability (`firstHandCapabilities` in `domain/vocabulary.ts`, today `script.start`) is
208
+ not delegable further. `withoutCapabilities` removes named technical permissions. Availability and grants also apply when the value is `null`.
208
209
  `forkOf` (a handle or ID) makes the new agent a fork of an LLM agent in the same run:
209
210
  `agent.spawned` records the source, and the new agent's context begins with an unchanged copy of
210
211
  the source's context up to the end of the source's last finished turn, reasoning blocks included.
@@ -290,7 +290,7 @@ a { color: inherit; text-underline-offset: 4px; }
290
290
  <div class="end" data-end><button type="button" class="end-button" data-replay><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>Replay</button><button type="button" class="end-button" data-onward><svg class="end-arrow" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 5v14"/><path d="m19 12-7 7-7-7"/></svg>Scroll down</button></div>
291
291
  </div>
292
292
  <div class="sr-only story" data-story>
293
- <article data-chapter="workspace" id="setups" data-anchor="setups"><h2><span>Tailor a workspace</span> <span>for a task</span></h2><p>The script builds the workspace, so the agents start with everything in place.</p><ul class="bullets"><li>A setup script creates agents, scripts and mini-apps</li><li>Start it again with one click</li><li>Ask for inputs before the run starts</li></ul><p class="how"><span class="how-label">How it works</span> A setup is a tested TypeScript package that appears as a start card. Its script starts agents, TypeScript programs and mini-apps through the same functions the AI uses. A setup dialog can ask for values, such as a repository or a topic, before the run starts.</p></article>
293
+ <article data-chapter="workspace" id="setups" data-anchor="setups"><h2><span>Tailor a workspace</span> <span>for a task</span></h2><p>The script builds the workspace, so the agents start with everything in place.</p><ul class="bullets"><li>A setup script creates agents, scripts and mini-apps</li><li>Start it again with one click</li><li>Add a setup to a run that is already running</li><li>Ask for inputs before the run starts</li></ul><p class="how"><span class="how-label">How it works</span> A setup is a tested TypeScript package that appears as a start card. Its script starts agents, TypeScript programs and mini-apps through the same functions the AI uses. A setup dialog can ask for values, such as a repository or a topic, before the run starts. A setup marked as embeddable also joins a running run, from the run menu, the command line or the coordinator, and reports its result back.</p></article>
294
294
  <article data-chapter="agents" id="agents" data-anchor="agents"><h2><span>Everyone talks</span> <span>to everyone</span></h2><p>Agents write plain text to each other, addressed by handle, such as @agent1.</p><ul class="bullets"><li>Agents hand work to each other</li><li>Agents talk to scripts, scripts answer</li><li>People talk to agents and mini-apps</li><li>Mini-apps talk to people and agents</li><li class="wink">... you get the idea :)</li></ul><p class="how"><span class="how-label">How it works</span> Each agent has its own model, prompt, history and handle. A coordinator takes the task and hands out work. A helper starts with no tools, a picked list, or all tools. When an agent asks you something, the choices appear in the chat and your answer goes back to that agent.</p></article>
295
295
  <article data-chapter="ui" id="ui" data-anchor="ui"><h2><span>Agents with</span> <span>their own UI</span></h2><p>People are used to working with interfaces. A UI shows what the agent is doing, and you step in with a click.</p><ul class="bullets"><li>The AI builds a UI while it works</li><li>Extensions ship UIs ready to use</li><li>You and the agent use the same UI and state</li><li>Your click goes straight to the agent</li><li>A new UI goes live after its tests pass</li></ul><p class="how"><span class="how-label">How it works</span> A mini-app is a React view on the state of an agent or a TypeScript program. Its buttons call the program's typed functions directly. The AI type-checks and tests a new view before it goes live; if a rebuild fails, the old version stays active. In VS Code, a mini-app opens in its own editor tab.</p></article>
296
296
  <article data-chapter="typescript" id="typescript" data-anchor="typescript"><h2><span>Tools are</span> <span>TypeScript functions</span></h2><ul class="bullets"><li>Register a typed function once, from your own plugin</li><li>Agents get it as a tool</li><li>AI-written code calls it, type-checked first</li><li>A button calls it without a model</li><li>Programs call it when events arrive</li></ul><p class="how"><span class="how-label">How it works</span> A snippet runs once and returns its result to the model. A program keeps its state and reacts to later messages. A setup starts agents, programs and UIs. All of them call the same typed functions, with the same permission checks.</p></article>
@@ -855,8 +855,8 @@
855
855
  .w-\[42px\] {
856
856
  width: 42px;
857
857
  }
858
- .w-\[220px\] {
859
- width: 220px;
858
+ .w-\[260px\] {
859
+ width: 260px;
860
860
  }
861
861
  .w-\[calc\(100\%-3rem\)\] {
862
862
  width: calc(100% - 3rem);
@@ -3238,6 +3238,11 @@
3238
3238
  .disabled\:opacity-60:disabled {
3239
3239
  opacity: 60%;
3240
3240
  }
3241
+ @media (hover: hover) {
3242
+ .disabled\:hover\:bg-transparent:disabled:hover {
3243
+ background-color: transparent;
3244
+ }
3245
+ }
3241
3246
  :where([data-detail-level="summary"]) .in-data-\[detail-level\=summary\]\:py-\[10px\] {
3242
3247
  padding-block: 10px;
3243
3248
  }
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "inputs": {
3
- "apps/server/src/api/contracts.ts": "88d12d6b852a8d3b76a9fdba310f6e0e2e173558dd5663ab6e311c8ab9944346",
4
- "apps/server/src/host-api.ts": "0495247e24ec1d62b148f4293d526f62994855d4072c5d06b1c6ec551b1201d1",
5
- "apps/server/src/plugin-support/actor-programs/contract.ts": "70923e56f2780f71378a3420613256e27c724e6a82844c5486112d6fefc16624",
3
+ "apps/server/src/api/contracts.ts": "5dcbff61b0e317a674fa58475027e1d30da6ac9f1812aced1fdbf325c4271a91",
4
+ "apps/server/src/host-api.ts": "e5cd123304fbf0567eef1985e0e1b9ce3b1cf845f111238fa755b36d928a3e1f",
5
+ "apps/server/src/plugin-support/actor-programs/contract.ts": "e8a1ba7dde7b73ad8904bafba2f61b4ef1ea0f0aa957fae2a76920edfc668974",
6
6
  "apps/server/src/plugin-support/chat-display-contract.ts": "2fb8aab13b5a60b4fe28f87f93cc82afb34b7d8ef1463e376bc3cbc0bcdc797b",
7
7
  "apps/server/src/plugin-support/language-server/contract.ts": "01794d6b63c19bb3c201412b45480d8dde5bd0f3d50459fb936a5e9b314d5a83",
8
8
  "apps/server/src/plugin-support/product-model-settings-contract.ts": "40d139db6a5c9047ad832c4f29465321e939cdf610789c367f9d064878c3e5f7",
@@ -64,9 +64,9 @@
64
64
  "apps/web/src/run-panel/input-bridge.ts": "4c3deb8fe115286d20f29f92a6ae6cb38dbae8c883deb97e6f6c32c64fba843d",
65
65
  "apps/web/src/run-panel/keyboard.ts": "e89266a2e99c2d96dbec79f5c1aef937101cebdfa74fdc0b4bb1688986097526",
66
66
  "apps/web/src/run-panel/run-panel-location.ts": "d191d3d9da695f277cd8f899b9682ba149c4bf1ae8e3cecc1bc2bc60bf3e7adb",
67
- "apps/web/src/run-panel/RunPanelApp.tsx": "534c14df4d66d2c677812a0952a8622f41b826acf167bec2ec90ac732fb8f0f1",
67
+ "apps/web/src/run-panel/RunPanelApp.tsx": "a9541eafa3f67fc01e02ae3219bb6304bb0f91f43a97ade6a8313ab4c9b4c695",
68
68
  "apps/web/src/run-panel/RunPanelHeader.tsx": "a1ffbdbf4a705f14b859f11041f7954bfaccc7abe9b7640e7235774a953e0bad",
69
- "apps/web/src/run-panel/RunPanelMenu.tsx": "db7809ac8ed1730e9504a237b977ec11b9629031a3ac9f7794f3aa600f220f46",
69
+ "apps/web/src/run-panel/RunPanelMenu.tsx": "ea12a2e0a0867dbaee5e01473822ef238a9edb1739819140e3a669c01b219b28",
70
70
  "apps/web/src/run-panel/RunPanelRail.tsx": "d3c0cddb28805690f92d1aeb5fe32a9d7459022cae2a4cdeb4c15b1c6196bd10",
71
71
  "apps/web/src/run-panel/RunPanelWorkspace.tsx": "f240418198b9b2dc39c041aa4f7dccd2412d9d46b06c8fa748e1f055aa04aeca",
72
72
  "apps/web/src/run-panel/use-session-list.ts": "740a1040b50b597055b3950fcd99c42b3c6eef2cbbbac00eaee1c02370540838",
@@ -138,6 +138,6 @@
138
138
  "packages/ragents/src/rpc/peer.ts": "9050dff218bdc6603478a77bdca241629f55c03b65f6efe7df598b53446b4c09",
139
139
  "packages/ragents/src/rpc/protocol.ts": "82bbcb8181a2f90708dc607922fef4a9d472cd82d6dede09324df778773699a6",
140
140
  "packages/ragents/src/runtime/domain-error.ts": "d6bf8fa09769c4137e616c83a84cb9c05a58bfa6c2e32c9404a1c202815837a4",
141
- "pnpm-lock.yaml": "c7edb4e9414089daad46f922bae423d42b1257eb53ef490a3f0e3a8afb055fb3"
141
+ "pnpm-lock.yaml": "7a0ed220c7b68d8da22c5b6df864934dafa53aecad8e61d438ee86ddf79ee108"
142
142
  }
143
143
  }
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <link rel="stylesheet" href="/ragents.css" />
7
7
  <title>RAgents</title>
8
- <script type="module" crossorigin src="/assets/main-BUN8m8SW.js"></script>
9
- <link rel="modulepreload" crossorigin href="/assets/mermaid-HWGCJPDP-B1erZlFM.js">
8
+ <script type="module" crossorigin src="/assets/main-KBrc5Q77.js"></script>
9
+ <link rel="modulepreload" crossorigin href="/assets/mermaid-HWGCJPDP-CSCkaArr.js">
10
10
  <link rel="stylesheet" crossorigin href="/assets/mermaid-HWGCJPDP-BPn4aV2r.css">
11
11
  </head>
12
12
  <body>
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <link rel="stylesheet" href="/ragents.css" />
7
7
  <title>RAgents Panel</title>
8
- <script type="module" crossorigin src="/assets/runPanel-s8gGpr9M.js"></script>
9
- <link rel="modulepreload" crossorigin href="/assets/mermaid-HWGCJPDP-B1erZlFM.js">
8
+ <script type="module" crossorigin src="/assets/runPanel-BjG5NBKm.js"></script>
9
+ <link rel="modulepreload" crossorigin href="/assets/mermaid-HWGCJPDP-CSCkaArr.js">
10
10
  <link rel="stylesheet" crossorigin href="/assets/mermaid-HWGCJPDP-BPn4aV2r.css">
11
11
  </head>
12
12
  <body>
@@ -21,7 +21,7 @@
21
21
  "dompurify": "^3.4.13",
22
22
  "highlight.js": "^11.12.0",
23
23
  "lucide-react": "^1.46.0",
24
- "quassel": "^0.4.0",
24
+ "quassel": "^0.4.2",
25
25
  "react": "^19.2.0",
26
26
  "react-diff-view": "^3.3.3",
27
27
  "react-dom": "^19.2.0",
@@ -231,7 +231,7 @@ function RunPanelPage({ connection, initialRunId, registry }: { connection: stri
231
231
  <RunStateIcon className="self-center px-1.5" state={session?.running ? "running" : "idle"} />
232
232
  <StopButton className="self-center" disabled={!writeRuns} label="Stop run" onClick={stop} size="icon-lg" title="Stop the run with all agents and flows" />
233
233
  <div aria-label="Panel tools" className="flex flex-none items-center empty:hidden" ref={setToolsContainer} role="toolbar" />
234
- <RunPanelMenu onOpenSettings={openSettings} />
234
+ <RunPanelMenu onOpenSettings={openSettings} runId={runId} />
235
235
  </header>
236
236
  {stopError && <Alert variant="destructive">{stopError}</Alert>}
237
237
  <main className="relative z-1 flex min-h-0 min-w-0 flex-1 @container/chat-content">
@@ -1,35 +1,71 @@
1
1
  import { useId, useRef, useState } from "react";
2
- import { ExternalLinkIcon, LogOutIcon, MoreVerticalIcon, SettingsIcon } from "lucide-react";
2
+ import { ChevronLeftIcon, ExternalLinkIcon, LogOutIcon, MoreVerticalIcon, PlayIcon, SettingsIcon } from "lucide-react";
3
+ import { coreContracts } from "@ragents/host/api/contracts";
4
+ import type { RunScriptListing } from "../../../server/src/chat-handler";
3
5
  import { useAccess } from "../AccessContext";
6
+ import { rpc } from "../rpc";
4
7
  import { Button, Popover, PopoverContent } from "../ui";
5
8
  import { useRunPanelHost } from "./host";
6
9
 
7
- const itemClass = "flex w-full cursor-pointer items-center gap-2.5 rounded-md px-2 py-1.5 text-left hover:bg-accent focus-visible:outline-2 focus-visible:outline-ring/60 focus-visible:-outline-offset-2 disabled:cursor-default disabled:opacity-50 [&>svg]:size-4 [&>svg]:flex-none [&>svg]:text-muted-foreground";
10
+ const itemClass = "flex w-full cursor-pointer items-center gap-2.5 rounded-md px-2 py-1.5 text-left hover:bg-accent focus-visible:outline-2 focus-visible:outline-ring/60 focus-visible:-outline-offset-2 disabled:cursor-default disabled:opacity-50 disabled:hover:bg-transparent [&>svg]:size-4 [&>svg]:flex-none [&>svg]:text-muted-foreground";
8
11
 
9
- /** The menu at the top right of the panel: settings, server in the browser, and sign-out behind one button. */
10
- export function RunPanelMenu({ onOpenSettings }: { onOpenSettings: () => void }) {
12
+ const messageOf = (cause: unknown): string => cause instanceof Error ? cause.message : String(cause);
13
+
14
+ type Scripts = { readonly kind: "loading" } | { readonly kind: "ready"; readonly scripts: readonly RunScriptListing[] };
15
+
16
+ /** The menu at the top right of the panel: settings, run scripts for the open run, server in the browser, and sign-out behind one button. */
17
+ export function RunPanelMenu({ onOpenSettings, runId }: { onOpenSettings: () => void; runId?: string }) {
11
18
  const host = useRunPanelHost();
12
19
  const access = useAccess();
13
20
  const [open, setOpen] = useState(false);
14
21
  const [pending, setPending] = useState(false);
15
22
  const [error, setError] = useState<string>();
23
+ const [scripts, setScripts] = useState<Scripts>();
16
24
  const buttonRef = useRef<HTMLButtonElement>(null);
17
25
  const panelId = useId();
18
26
  const pressedAnchor = (details: { reason: string; event: Event }) =>
19
27
  details.reason === "outside-press" && details.event.target instanceof Node && buttonRef.current?.contains(details.event.target) === true;
28
+ const close = () => { setOpen(false); setScripts(undefined); setError(undefined); };
20
29
  const logout = () => {
21
30
  if (host.kind === "vscode") { host.requestLogout(); setOpen(false); return; }
22
31
  setPending(true);
23
32
  setError(undefined);
24
- void access.logout().then(() => setOpen(false)).catch((cause: unknown) => setError(cause instanceof Error ? cause.message : String(cause))).finally(() => setPending(false));
33
+ void access.logout().then(() => setOpen(false)).catch((cause: unknown) => setError(messageOf(cause))).finally(() => setPending(false));
34
+ };
35
+ const listScripts = (run: string) => {
36
+ setScripts({ kind: "loading" });
37
+ setError(undefined);
38
+ void rpc.call(coreContracts.runs.scripts, { runId: run }).then((listed) => setScripts({ kind: "ready", scripts: listed }))
39
+ .catch((cause: unknown) => { setScripts({ kind: "ready", scripts: [] }); setError(messageOf(cause)); });
40
+ };
41
+ const startScript = (run: string, entry: string) => {
42
+ setPending(true);
43
+ setError(undefined);
44
+ void rpc.call(coreContracts.runs.startScript, { runId: run, entry, input: null }).then(close)
45
+ .catch((cause: unknown) => setError(messageOf(cause))).finally(() => setPending(false));
25
46
  };
47
+ const scriptRun = runId !== undefined && access.can("runs.write") ? runId : undefined;
26
48
  return <>
27
- <Button aria-controls={open ? panelId : undefined} aria-expanded={open} aria-haspopup="dialog" aria-label="Panel menu" className="self-center" onClick={() => setOpen((value) => !value)} ref={buttonRef} size="icon-lg" title="Menu" variant="ghost"><MoreVerticalIcon /></Button>
28
- <Popover onOpenChange={(next, details) => { if (!next && pressedAnchor(details)) return; setOpen(next); }} open={open}>
29
- <PopoverContent align="end" anchor={buttonRef} aria-label="Panel menu" className="w-[220px] gap-0 p-1 text-[0.8rem]" collisionPadding={8} dim id={panelId} role="dialog" side="bottom">
30
- <button className={itemClass} onClick={() => { setOpen(false); onOpenSettings(); }} type="button"><SettingsIcon />Settings</button>
31
- {host.kind === "vscode" && <button className={itemClass} onClick={() => { setOpen(false); host.openExternal(new URL("/", window.location.href).toString()); }} type="button"><ExternalLinkIcon />Open in browser</button>}
32
- {access.enabled && access.user && <button className={itemClass} disabled={pending} onClick={logout} title={access.user.id} type="button"><LogOutIcon /><span className="grid min-w-0"><span>Sign out</span><span className="truncate text-[0.68rem] text-muted-foreground">{access.user.label}</span></span></button>}
49
+ <Button aria-controls={open ? panelId : undefined} aria-expanded={open} aria-haspopup="dialog" aria-label="Panel menu" className="self-center" onClick={() => (open ? close() : setOpen(true))} ref={buttonRef} size="icon-lg" title="Menu" variant="ghost"><MoreVerticalIcon /></Button>
50
+ <Popover onOpenChange={(next, details) => { if (!next && pressedAnchor(details)) return; if (next) setOpen(true); else close(); }} open={open}>
51
+ <PopoverContent align="end" anchor={buttonRef} aria-label="Panel menu" className="w-[260px] gap-0 p-1 text-[0.8rem]" collisionPadding={8} dim id={panelId} role="dialog" side="bottom">
52
+ {scripts && scriptRun !== undefined ? <>
53
+ <button className={itemClass} onClick={() => { setScripts(undefined); setError(undefined); }} type="button"><ChevronLeftIcon />Run script</button>
54
+ <div aria-label="Run scripts" className="grid max-h-[50vh] overflow-auto border-t border-border-soft pt-1" role="list">
55
+ {scripts.kind === "loading" && <p className="px-2 py-1.5 text-muted-foreground">Loading run scripts ...</p>}
56
+ {scripts.kind === "ready" && scripts.scripts.length === 0 && !error && <p className="px-2 py-1.5 text-muted-foreground">This profile has no run scripts for you.</p>}
57
+ {scripts.kind === "ready" && scripts.scripts.map((script) => <button className={itemClass} disabled={pending || !script.available} key={script.id}
58
+ onClick={() => startScript(scriptRun, script.id)} role="listitem" title={script.reason ?? script.description} type="button">
59
+ <span className="grid min-w-0"><span className="truncate">{script.title}</span>
60
+ <span className="line-clamp-2 text-[0.68rem] text-muted-foreground">{script.available ? script.description : script.reason}</span></span>
61
+ </button>)}
62
+ </div>
63
+ </> : <>
64
+ <button className={itemClass} onClick={() => { close(); onOpenSettings(); }} type="button"><SettingsIcon />Settings</button>
65
+ {scriptRun !== undefined && <button className={itemClass} onClick={() => listScripts(scriptRun)} type="button"><PlayIcon />Run script</button>}
66
+ {host.kind === "vscode" && <button className={itemClass} onClick={() => { close(); host.openExternal(new URL("/", window.location.href).toString()); }} type="button"><ExternalLinkIcon />Open in browser</button>}
67
+ {access.enabled && access.user && <button className={itemClass} disabled={pending} onClick={logout} title={access.user.id} type="button"><LogOutIcon /><span className="grid min-w-0"><span>Sign out</span><span className="truncate text-[0.68rem] text-muted-foreground">{access.user.label}</span></span></button>}
68
+ </>}
33
69
  {error && <p className="px-2 py-1.5 text-[0.72rem] text-destructive" role="alert">{error}</p>}
34
70
  </PopoverContent>
35
71
  </Popover>
@@ -23,7 +23,7 @@
23
23
  }
24
24
  },
25
25
  "revision": "b7b04d050f5f4bcb0980880167b8e2cdd3ad533ba07f589dd0de471b9e55c0fd",
26
- "sourceRevision": "d0f96d5406c652a4ed17f8642adfc889bb3be49fc7948f84e0f889ecb910f26e",
26
+ "sourceRevision": "047290b262944aedbbbb4c4a819509c4bc3a7e0df4fa76b38d9e21ebe5626828",
27
27
  "server": "server/index.js",
28
28
  "web": {
29
29
  "entry": "web/index.js",
@@ -18,6 +18,7 @@
18
18
  "handleKey",
19
19
  "holdsUsable",
20
20
  "implement",
21
+ "inheritedGrants",
21
22
  "runCapabilityBindingHash",
22
23
  "runCapabilityContractHash",
23
24
  "schemaComplaints",
@@ -26,6 +27,7 @@
26
27
  "@ragents/host/plugin-support/actor-programs/app-project": [
27
28
  "compileAppBackend",
28
29
  "installServerSdk",
30
+ "packageIdentity",
29
31
  "prepareAppProject",
30
32
  "prepareAppWorkspace",
31
33
  "projectSourceFiles",
@@ -192,8 +194,8 @@
192
194
  ]
193
195
  }
194
196
  },
195
- "revision": "e25685f9ef95c00333e76e28047747da063b0367833419273d936820fbf1078a",
196
- "sourceRevision": "a90150418157ee1b04b3a4c91d1502f32d2e4b7dde1924b63598df7f9ff7360b",
197
+ "revision": "15fc5afb9aac414335069c28989cae4fa95fec8a2937584f8497a42ce01ffaba",
198
+ "sourceRevision": "6abd7c9e82683655c2bf5010641391a3960ccf495729a87ef00ef58cfb07f7af",
197
199
  "server": "server/index.js",
198
200
  "web": {
199
201
  "entry": "web/index.js",