@akira-tl/forgerelay 0.5.6 → 0.6.0

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 (152) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +7 -3
  3. package/capabilities/host-integration/GUIDE.md +15 -9
  4. package/dist/activity/host-turn-store.js +9 -7
  5. package/dist/activity/lifecycle.js +1 -1
  6. package/dist/activity/mcp-query-tools.js +110 -18
  7. package/dist/activity/query-service.js +4 -4
  8. package/dist/activity/ui/contract.js +2 -0
  9. package/dist/cli.js +47 -32
  10. package/dist/config.js +31 -3
  11. package/dist/db/migrations.js +30 -0
  12. package/dist/db/schema.js +2 -0
  13. package/dist/logger.js +6 -5
  14. package/dist/lsp/test-support/server-fixture.js +1 -1
  15. package/dist/mcp/server-instructions.js +7 -6
  16. package/dist/mcp-app-template.js +108 -12
  17. package/dist/oauth/public-url.js +14 -0
  18. package/dist/oauth/router.js +49 -0
  19. package/dist/process-sessions.js +2 -1
  20. package/dist/request-meta.js +4 -0
  21. package/dist/server.js +250 -84
  22. package/dist/skills.js +58 -1
  23. package/dist/ui/.vite/manifest.json +360 -312
  24. package/dist/ui/activity-panel-app.html +17 -0
  25. package/dist/ui/assets/activity-panel-app-CjZVvVNc.js +2 -0
  26. package/dist/ui/assets/angular-html-BkgDQl-G.js +1 -0
  27. package/dist/ui/assets/{angular-ts-BwPE8YDt.js → angular-ts-Bxh4-O1-.js} +1 -1
  28. package/dist/ui/assets/{apl-CGbONVvU.js → apl-BmYHKQ6m.js} +1 -1
  29. package/dist/ui/assets/{astro-DIAPy7cj.js → astro-C51vqDKq.js} +1 -1
  30. package/dist/ui/assets/{blade-Cgtd19Ky.js → blade-CdhVsmwq.js} +1 -1
  31. package/dist/ui/assets/c-IBzBpxAO.js +1 -0
  32. package/dist/ui/assets/chunk-EyZ2wyi3.js +1 -0
  33. package/dist/ui/assets/{cobol-G-7HLVKW.js → cobol-Cf6azoN_.js} +1 -1
  34. package/dist/ui/assets/{coffee-DQFyKxEB.js → coffee-vVdGzlmt.js} +1 -1
  35. package/dist/ui/assets/cpp-CVHeO-Jk.js +1 -0
  36. package/dist/ui/assets/{crystal-DuiWhEO3.js → crystal-5UZy6KIX.js} +1 -1
  37. package/dist/ui/assets/css-DEfus9J5.js +1 -0
  38. package/dist/ui/assets/{edge-COkalhFi.js → edge-CESgo4ia.js} +1 -1
  39. package/dist/ui/assets/{elixir-cdlzbYR1.js → elixir-9FKfw4cJ.js} +1 -1
  40. package/dist/ui/assets/{elm-ZwDYuYpb.js → elm-Dv7A0aLa.js} +1 -1
  41. package/dist/ui/assets/{erb-C8WG9TtC.js → erb-DHFmDvM0.js} +1 -1
  42. package/dist/ui/assets/{git-rebase-CMlDVJBT.js → git-rebase-utbU6CzV.js} +1 -1
  43. package/dist/ui/assets/{glimmer-js-DeLOQlol.js → glimmer-js-t2kiCkyB.js} +1 -1
  44. package/dist/ui/assets/{glimmer-ts-DTEM04TK.js → glimmer-ts-F0Jv5okV.js} +1 -1
  45. package/dist/ui/assets/glsl-_ooCjaeB.js +1 -0
  46. package/dist/ui/assets/graphql-B9LqP-cY.js +1 -0
  47. package/dist/ui/assets/{hack-C14sh6Lh.js → hack-8yjdbaSA.js} +1 -1
  48. package/dist/ui/assets/haml-BU5EoZBn.js +1 -0
  49. package/dist/ui/assets/{handlebars-eS-J0O-M.js → handlebars-BBFEg4Lo.js} +1 -1
  50. package/dist/ui/assets/{heavy-payload-BKB0QDOI.js → heavy-payload-vGgBRvNX.js} +1 -1
  51. package/dist/ui/assets/html-D-C6YZk4.js +1 -0
  52. package/dist/ui/assets/{html-derivative-BlVZU2id.js → html-derivative-DJAQcZyc.js} +1 -1
  53. package/dist/ui/assets/{http-BmbZzA5x.js → http-Dg5LSYRK.js} +1 -1
  54. package/dist/ui/assets/{hurl-Dnd_YpOD.js → hurl-Y5uYzMZR.js} +1 -1
  55. package/dist/ui/assets/java-ppHvycj5.js +1 -0
  56. package/dist/ui/assets/javascript-DDTjKLlQ.js +1 -0
  57. package/dist/ui/assets/{jinja-DTvkZdHA.js → jinja-Bt30h8Ik.js} +1 -1
  58. package/dist/ui/assets/{jison-DUJG-tmh.js → jison-D5uZ1Nyo.js} +1 -1
  59. package/dist/ui/assets/json-Cw91r8h1.js +1 -0
  60. package/dist/ui/assets/jsx-04X2FT_1.js +1 -0
  61. package/dist/ui/assets/{julia-P5B4pHFa.js → julia-76hRaaGz.js} +1 -1
  62. package/dist/ui/assets/{just-DYaoh7C6.js → just-CDE7W0vW.js} +1 -1
  63. package/dist/ui/assets/{latex-CI5lnkWV.js → latex-CVO2Byab.js} +1 -1
  64. package/dist/ui/assets/{liquid-D3LnAs_z.js → liquid-CA-AS3EX.js} +1 -1
  65. package/dist/ui/assets/lua-CiyBp52Y.js +1 -0
  66. package/dist/ui/assets/{marko-CRDrjqfS.js → marko-_BWrPfny.js} +1 -1
  67. package/dist/ui/assets/{mdc-ZzwgmJVn.js → mdc-PyJv85eS.js} +1 -1
  68. package/dist/ui/assets/{nginx-BAvFXGSV.js → nginx-DAWVw8yu.js} +1 -1
  69. package/dist/ui/assets/{nim-BHIFawe9.js → nim-CKE1dzpU.js} +1 -1
  70. package/dist/ui/assets/{perl-C_f5AnLa.js → perl-BBhWva19.js} +1 -1
  71. package/dist/ui/assets/{php-DDqpegL5.js → php-ChIeaAoF.js} +1 -1
  72. package/dist/ui/assets/{pug-CSaAZXyd.js → pug-CMgI5afi.js} +1 -1
  73. package/dist/ui/assets/{qml-CNHvRs_z.js → qml-CjxTkcFH.js} +1 -1
  74. package/dist/ui/assets/r-DfFga4si.js +1 -0
  75. package/dist/ui/assets/{razor-BDfAPy7I.js → razor-i4DbHr8p.js} +1 -1
  76. package/dist/ui/assets/regexp-iC9_nbSI.js +1 -0
  77. package/dist/ui/assets/{review-payload-D7GIdYDj.js → review-payload-4erWKckt.js} +1 -1
  78. package/dist/ui/assets/{rst-BzPP2gle.js → rst-oy_97Kl4.js} +1 -1
  79. package/dist/ui/assets/{ruby-CQjzokzX.js → ruby-C5zYZIyl.js} +1 -1
  80. package/dist/ui/assets/{sas-Bp37KGr7.js → sas-BnMEh2S3.js} +1 -1
  81. package/dist/ui/assets/{scrollbar-HUMBdLLK.js → scrollbar-CaOPzUJd.js} +6 -6
  82. package/dist/ui/assets/scss-BfZXsAWQ.js +1 -0
  83. package/dist/ui/assets/shellscript-BC2srNaB.js +1 -0
  84. package/dist/ui/assets/{shellsession-CNc62UhY.js → shellsession-BpE5o7_3.js} +1 -1
  85. package/dist/ui/assets/{soy-CF44SpBo.js → soy-COesmhTY.js} +1 -1
  86. package/dist/ui/assets/sql-Ccv_yeUm.js +1 -0
  87. package/dist/ui/assets/{stata-DVeMA68W.js → stata-CGQEuSZq.js} +1 -1
  88. package/dist/ui/assets/{surrealql-52sF96Yv.js → surrealql-Bz4JbU-9.js} +1 -1
  89. package/dist/ui/assets/{svelte-ydwT7UbF.js → svelte-1jM2ejXj.js} +1 -1
  90. package/dist/ui/assets/{templ-BXcoVoGh.js → templ-C-VwELcp.js} +1 -1
  91. package/dist/ui/assets/{tex-COsYFp7O.js → tex-t1rUiQCm.js} +1 -1
  92. package/dist/ui/assets/{ts-tags-CF--LE1s.js → ts-tags-Bewoa6pS.js} +1 -1
  93. package/dist/ui/assets/tsx-CTXzrBkN.js +1 -0
  94. package/dist/ui/assets/{twig-YoM-DiI5.js → twig-DVg-vELl.js} +1 -1
  95. package/dist/ui/assets/typescript--ElHoFkw.js +1 -0
  96. package/dist/ui/assets/{vue-html-CPdGGk4T.js → vue-html-BHtJ8geX.js} +1 -1
  97. package/dist/ui/assets/{vue-vine-B5bjgk0a.js → vue-vine-CNSGAWwc.js} +1 -1
  98. package/dist/ui/assets/{vue-B5LDEy4l.js → vue-wPQ7UlMy.js} +1 -1
  99. package/dist/ui/assets/workspace-app-CcrHAUIn.css +1 -0
  100. package/dist/ui/assets/workspace-app-DJmkPYJC.js +1 -0
  101. package/dist/ui/assets/workspace-app-DkAiSl_0.js +111 -0
  102. package/dist/ui/assets/workspace-app-QyauBrJX.js +5 -0
  103. package/dist/ui/assets/workspace-lifecycle-app-BIXEo53I.js +1 -0
  104. package/dist/ui/assets/xml-JnmX6vyS.js +1 -0
  105. package/dist/ui/assets/{xsl-wls_CEK_.js → xsl-3_vJ27aE.js} +1 -1
  106. package/dist/ui/assets/yaml-OAcZkP-w.js +1 -0
  107. package/dist/ui/workspace-app.html +5 -2
  108. package/dist/ui/workspace-lifecycle-app.html +18 -0
  109. package/dist/workspaces.js +11 -0
  110. package/docs/configuration.md +36 -4
  111. package/docs/debugging.md +75 -17
  112. package/docs/gotchas.md +15 -9
  113. package/docs/setup.md +24 -10
  114. package/package.json +4 -3
  115. package/scripts/debug/accept.mjs +79 -27
  116. package/scripts/debug/host/run.sh +180 -0
  117. package/scripts/debug/host/serve.mjs +64 -0
  118. package/scripts/debug/runtime.mjs +57 -2
  119. package/scripts/debug/runtime.test.mjs +74 -0
  120. package/scripts/debug/serve.mjs +4 -5
  121. package/scripts/dev-server.mjs +32 -3
  122. package/scripts/release/release-gate.test.mjs +43 -0
  123. package/scripts/release/release-version.test.mjs +107 -0
  124. package/scripts/release-parity.mjs +70 -46
  125. package/scripts/release-proof.mjs +2 -2
  126. package/scripts/release-proof.test.mjs +18 -0
  127. package/scripts/release-version.mjs +17 -8
  128. package/dist/ui/assets/angular-html-BT2Z6jee.js +0 -1
  129. package/dist/ui/assets/c-acnvZ8tm.js +0 -1
  130. package/dist/ui/assets/cpp-UyrmHXan.js +0 -1
  131. package/dist/ui/assets/css-D_WCbY6m.js +0 -1
  132. package/dist/ui/assets/glsl-IJV4SB-M.js +0 -1
  133. package/dist/ui/assets/graphql-PM-WDnoB.js +0 -1
  134. package/dist/ui/assets/haml-B_5nS6Kx.js +0 -1
  135. package/dist/ui/assets/html-C3TPjrC5.js +0 -1
  136. package/dist/ui/assets/java-ne9HdIVn.js +0 -1
  137. package/dist/ui/assets/javascript-DpHT58rr.js +0 -1
  138. package/dist/ui/assets/json-DJmnBdxW.js +0 -1
  139. package/dist/ui/assets/jsx-BclJnZnN.js +0 -1
  140. package/dist/ui/assets/lua-dZC7ZQIY.js +0 -1
  141. package/dist/ui/assets/r-CAfoQND2.js +0 -1
  142. package/dist/ui/assets/regexp-Mug5jltQ.js +0 -1
  143. package/dist/ui/assets/scss-C_Z1DYnw.js +0 -1
  144. package/dist/ui/assets/shellscript-CLfJpn3I.js +0 -1
  145. package/dist/ui/assets/sql-CYnzfiQ1.js +0 -1
  146. package/dist/ui/assets/tsx-DLBt2-2f.js +0 -1
  147. package/dist/ui/assets/typescript-Ce9JGkNI.js +0 -1
  148. package/dist/ui/assets/workspace-app-Cm9EX5x4.js +0 -117
  149. package/dist/ui/assets/workspace-app-DHvE2ojW.css +0 -1
  150. package/dist/ui/assets/xml-Cun8xb0T.js +0 -1
  151. package/dist/ui/assets/yaml-BxuXn9OL.js +0 -1
  152. package/scripts/release/tag-local-ci.mjs +0 -144
@@ -0,0 +1,5 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./heavy-payload-vGgBRvNX.js","./scrollbar-CaOPzUJd.js","./chunk-EyZ2wyi3.js","./workspace-app-DkAiSl_0.js","./workspace-app-CcrHAUIn.css","./review-payload-4erWKckt.js"])))=>i.map(i=>d[i]);
2
+ import{a as e,c as t,d as n,i as r,l as i,n as a,o,s,t as c,u as l}from"./workspace-app-DkAiSl_0.js";function u(e){return e===`open_workspace`||e===`close_workspace`||e===`capability`||e===`apply_patch`||e===`exec_command`||e===`write_stdin`||e===`read`||e===`write`||e===`edit`||e===`rename`||e===`delete`||e===`grep`||e===`glob`||e===`ls`||e===`bash`}function d(e){return e===`read`}function f(e){return e===`write`}function p(e){return e===`edit`}function m(e){return e===`apply_patch`}function ee(e){return e===`bash`||e===`exec_command`||e===`write_stdin`}function h(e){return e.tool===`capability`&&e.capabilityName===`review.changes`}function te(e){return!!(e&&typeof e==`object`)}function ne(e){return e?.content?.map(e=>e.type===`text`?e.text??``:`[${e.mimeType??`image`} image payload]`).filter(Boolean).join(`
3
+
4
+ `)??``}function g(e,t){let n=e?.[t];return typeof n==`number`&&Number.isFinite(n)?n:void 0}function _(e){return e.tool===`open_workspace`?Number(e.summary?.agentsFiles??0)>0||Number(e.summary?.skills??0)>0||Number(e.summary?.agentProviders??0)>0||Number(e.summary?.agents??0)>0||!!e.agentsFiles?.length||!!e.availableAgentsFiles?.length||!!e.skills?.length||!!e.agentProviders?.length||!!e.agents?.length||!!e.worktree||!!e.instruction:h(e)?!!(e.files?.length||e.payload?.patch):m(e.tool)?!!e.payload?.patch:!!e.payload}function re(e){return e.tool===`open_workspace`||h(e)?_(e):m(e.tool)?e.files?.length===1&&_(e):!1}var ie={added:`Added`,edited:`Edited`,deleted:`Deleted`,renamed:`Renamed`,"renamed-edited":`Renamed and edited`};function ae(e,t={}){let n=e.files??[],r=le(n);if(r===0)return{title:t.emptyTitle??`Applied patch`,tone:`edit`};let i=new Set(n.map(v)),a=i.size===1?[...i][0]:void 0,o={title:ue(a,r),tone:de(a)};return a&&a!==`unknown`&&(o.iconKind=a),o}function v(e){switch(e.operation){case`add`:return`added`;case`update`:return`edited`;case`delete`:return`deleted`;case`move`:return`renamed`}switch(e.type){case`new`:return`added`;case`change`:return`edited`;case`deleted`:return`deleted`;case`rename-pure`:return`renamed`;case`rename-changed`:return`renamed-edited`;default:return`unknown`}}function oe(e,t,n){let r=v(t);if(r!==`edited`&&r!==`unknown`)return r;let i=e[n];return i?.operation===`move`&&(!t.path||i.path===t.path)||e.find(e=>e.operation===`move`&&e.path===t.path&&(!t.previousPath||e.previousPath===t.previousPath))?`renamed`:r===`edited`?`edited`:i?v(i):`unknown`}function y(e){let t=e.path??e.previousPath;if(!t)return;let n=e.previousPath;if(!n||n===t)return{current:t,title:t};let r=x(n)===x(t);return{current:r?S(t):t,previous:r?S(n):n,title:`${n} → ${t}`}}function se(e,t,n){let r=e[n],i=(r?.path===t.path?r:e.find(e=>e.path===t.path&&(!t.previousPath||!e.previousPath||e.previousPath===t.previousPath)))??r;return y({path:t.path??i?.path,previousPath:t.previousPath??i?.previousPath})}function ce(e){return e===`unknown`?`Changed`:ie[e]}function le(e){let t=new Set,n=0;for(let r of e){let e=r.path??r.previousPath;e?t.add(e):n+=1}return t.size+n}function ue(e,t){return e&&e!==`unknown`?`${ie[e]} ${t} ${b(t)}`:`Changed ${t} ${b(t)}`}function de(e){return e===`added`?`write`:e===`deleted`?`delete`:`edit`}function b(e){return e===1?`file`:`files`}function x(e){let t=Math.max(e.lastIndexOf(`/`),e.lastIndexOf(`\\`));return t===-1?``:e.slice(0,t)}function S(e){let t=Math.max(e.lastIndexOf(`/`),e.lastIndexOf(`\\`));return t===-1?e:e.slice(t+1)}function fe(e){switch(e.tool){case`open_workspace`:return{icon:e.mode===`worktree`?o.gitBranch:o.folderOpen,title:he(e),label:e.root??e.path,tone:`workspace`};case`close_workspace`:return{icon:e.mode===`worktree`?o.gitBranch:o.folderOpen,title:`Closed workspace`,label:e.sourceRoot??e.root??e.path??e.workspaceId,tone:`workspace`};case`read`:return{icon:o.readFile,title:`Read file`,label:e.path,tone:`read`};case`write`:return{icon:o.writeFile,title:`Wrote file`,label:e.path,tone:`write`};case`edit`:return{icon:o.editFile,title:`Edited file`,label:e.path,tone:`edit`};case`rename`:return{icon:o.editFile,title:`Renamed path`,label:e.path,tone:`edit`};case`delete`:return{icon:o.deleteFile,title:`Deleted path`,label:e.path,tone:`delete`};case`apply_patch`:{let t=ae(e);return{icon:me(t.iconKind),title:t.title,label:C(e),tone:t.tone}}case`grep`:return{icon:o.search,title:`Searched files`,label:ge(e),tone:`search`};case`glob`:return{icon:o.files,title:`Found files`,label:ge(e),tone:`search`};case`ls`:return{icon:o.folderTree,title:`Listed directory`,label:e.path,tone:`directory`};case`bash`:case`exec_command`:return{icon:o.terminalSquare,title:_e(e,`command`),label:w(e),tone:`shell`,state:ve(e)};case`write_stdin`:return{icon:o.terminal,title:_e(e,`process`),label:w(e),tone:`shell`,state:ve(e)};case`capability`:if(h(e)){let t=ae(e,{emptyTitle:`Changes ready`}),n=e.files?.length??0;return{icon:o.diff,title:n>0||e.payload?.patch?t.title:`No changes`,label:C(e),tone:`review`}}return{icon:o.skills,title:e.capabilityName?`Capability: ${e.capabilityName}`:`Capability completed`,tone:`workspace`}}}function pe(e){let t=e.summary??{};if(h(e)||m(e.tool)||p(e.tool)||f(e.tool))return{kind:`diff`,additions:g(t,`additions`)??0,removals:g(t,`removals`)??0};if(e.tool===`open_workspace`){let e=[T(g(t,`agentsFiles`),`instruction`),T(g(t,`skills`),`skill`)].filter(e=>!!e);return e.length>0?{kind:`text`,text:e.join(` · `)}:{kind:`empty`}}if(ee(e.tool)){let e=[T(g(t,`lines`),`line`),ye(g(t,`wallTimeMs`))].filter(e=>!!e);return e.length>0?{kind:`text`,text:e.join(` · `)}:{kind:`empty`}}if(e.tool===`grep`||e.tool===`read`||e.tool===`ls`){let e=T(g(t,`lines`),`line`);return e?{kind:`text`,text:e}:{kind:`empty`}}return{kind:`empty`}}function me(e){return e===`added`?o.writeFile:e===`deleted`?o.deleteFile:e===`renamed`||e===`renamed-edited`?o.files:o.editFile}function he(e){return`${e.workspaceReused?`Reused`:`Opened`} workspace`}function C(e){if(e.files?.length===1)return y(e.files[0])?.title??e.path}function ge(e){let t=e.summary?.pattern,n=e.summary?.scope;return typeof t==`string`?typeof n==`string`&&n!==`.`?`${t} in ${n}`:t:e.path}function _e(e,t){if(e.summary?.running===!0)return t===`command`?`Command running`:`Process running`;let n=g(e.summary,`exitCode`);return n!==void 0&&n!==0?t===`command`?`Command failed`:`Process failed`:t===`command`?`Ran command`:`Process finished`}function ve(e){if(e.summary?.running===!0)return`running`;let t=g(e.summary,`exitCode`);return t!==void 0&&t!==0?`error`:t===0?`success`:void 0}function w(e){let t=e.summary?.command;if(typeof t==`string`)return t;let n=e.summary?.sessionId;return typeof n==`number`||typeof n==`string`?`Session ${String(n)}`:e.path}function T(e,t){if(e!==void 0)return`${e} ${t}${e===1?``:`s`}`}function ye(e){if(e!==void 0)return e<1e3?`${Math.round(e)}ms`:`${(e/1e3).toFixed(+(e<1e4))}s`}var E=null,D=!1,O=null,k,A=null,j=!1,M=!1,N=null,P=null,F=null,I=null,L=!1,R=document.querySelector(`#app`);if(!R)throw Error(`Missing #app root element.`);var z=R,B=new c(z);be();async function be(){H(),E=new i({name:`forgerelay-tool-cards`,version:`0.1.0`},{}),E.ontoolresult=e=>{let t=a(B.active,e.structuredContent);if(t===`activity`&&B.accept(e)){A=null,j=!1,M=!1,I=null,L=!1,N=null,H();return}if(t===`preserve-panel`)return;let n=Re(e),r=Le(e),i=r?{...n,...r}:n,o=Ie(e);if(!o||!te(i)){A=null,j=!1,M=!1,I=null,L=!1,N=`No result card is available for this tool result.`,H();return}let s={...i,tool:o};A=s,j=re(s),M=!1,I=null,L=!1,N=null,H()},E.onhostcontextchanged=e=>{k={...k,...e},V(),B.active?B.render():A?.tool!==`open_workspace`&&W()},E.onteardown=async()=>(D=!1,B.detach(),G(),{});try{await E.connect();let e=E.getHostContext();e&&(k=e),V(),D=!0,B.attach(E)}catch(e){O=e instanceof Error?e.message:String(e)}H()}function V(){k?.theme&&l(k.theme),k?.styles?.variables&&t(k.styles.variables),k?.styles?.css?.fonts&&s(k.styles.css.fonts);let e=k?.safeAreaInsets;e&&(document.body.style.padding=`${e.top}px ${e.right}px ${e.bottom}px ${e.left}px`)}function H(){if(G(),O){U(O,`error`);return}if(!D){U(`Connecting to host...`);return}if(B.render())return;if(!A){U(N??`Waiting for a tool result.`,N?`error`:`muted`);return}let t=fe(A);if(h(A)){Ce(A,t);return}let n=_(A),r=$(`main`,{className:`shell`}),i=$(`section`,{className:Te(t)}),a=$(`button`,{className:`tool-header`,type:`button`,ariaExpanded:String(j),disabled:!n});n&&a.addEventListener(`click`,()=>{j=!j,H()});let o=$(`span`,{className:`tool-icon`,ariaHidden:`true`});o.append(e(t.icon));let s=$(`span`,{className:`tool-main`}),c=$(`span`,{className:`tool-title`,text:t.title});if(s.append(c),t.label&&s.append($(`span`,{className:`tool-label`,text:t.label,title:t.label})),a.append(o,s,J(A),we(j,n)),i.append(a),j){let e=$(`div`,{className:`tool-body`});F=e,i.append(e)}r.append(i),z.replaceChildren(r),W()}function U(e,t=`muted`){let n=$(`main`,{className:`shell`});n.append($(`section`,{className:`empty ${t}`,text:e})),z.replaceChildren(n)}async function W(){if(!A||!F||!j)return;let e=F;if(N){q(e,N,`error`);return}if(A.tool===`open_workspace`){Ee(e,A);return}if(xe(A)){if(P){P.update({card:A,hostContext:k,errorMessage:N});return}Y(e,!0);try{let{mountHeavyPayload:t}=await n(async()=>{let{mountHeavyPayload:e}=await import(`./heavy-payload-vGgBRvNX.js`);return{mountHeavyPayload:e}},__vite__mapDeps([0,1,2,3,4]),import.meta.url);if(e!==F||!j||!A)return;Y(e,!1),P=t(e,{card:A,hostContext:k,errorMessage:N})}catch(t){if(e!==F||!j)return;Y(e,!1),q(e,t instanceof Error?t.message:`Unable to load details.`,`error`)}return}if(h(A)||m(A.tool)){let t=h(A)&&!M?Math.max(3,(A.files??[]).slice(0,3).length):void 0;if(P){P.update({card:A,hostContext:k,errorMessage:N,visibleFileCount:t});return}q(e,h(A)?`Loading review...`:`Loading diff...`);let{mountReviewPayload:r}=await n(async()=>{let{mountReviewPayload:e}=await import(`./review-payload-4erWKckt.js`);return{mountReviewPayload:e}},__vite__mapDeps([5,1,2,3,4]),import.meta.url);if(e!==F||!A)return;P=r(e,{card:A,hostContext:k,errorMessage:N,visibleFileCount:t});return}let t=ne(A.payload);if(!t){q(e,`No details available.`);return}Se(e,t,A.tool)}function xe(e){return d(e.tool)||p(e.tool)||f(e.tool)}function G(){K(),P=null,F=null}function K(){P?.unmount(),P=null}function q(e,t,n=`muted`){K(),e.replaceChildren($(`div`,{className:`status ${n}`,text:t}))}function Se(e,t,n){K(),e.replaceChildren($(`pre`,{className:`text-payload pretty-scrollbar ${n}`,text:t}))}function J(e){let t=pe(e);if(t.kind===`diff`){let e=$(`span`,{className:`stats`});return e.setAttribute(`aria-label`,`Diff statistics`),e.append($(`span`,{className:`add`,text:`+${String(t.additions)}`}),$(`span`,{className:`remove`,text:`-${String(t.removals)}`})),e}let n=$(`span`,{className:`header-meta ${t.kind===`empty`?`empty`:``}`,text:t.kind===`text`?t.text:``});return t.kind===`empty`&&n.setAttribute(`aria-hidden`,`true`),n}function Ce(t,n){G();let r=t.files??[],i=M?r:r.slice(0,3),a=Math.max(0,r.length-i.length),o=_(t),s=$(`main`,{className:`shell`}),c=$(`section`,{className:Te(n)}),l=$(`button`,{className:`tool-header review-header`,type:`button`,ariaExpanded:String(j),disabled:!o});o&&l.addEventListener(`click`,()=>{j=!j,H()});let u=$(`span`,{className:`tool-icon`,ariaHidden:`true`});u.append(e(n.icon));let d=$(`span`,{className:`tool-main review-title-group`});if(d.append($(`span`,{className:`tool-title`,text:n.title})),n.label&&d.append($(`span`,{className:`tool-label`,text:n.label,title:n.label})),l.append(u,d,J(t),we(j,o)),c.append(l),j){let e=$(`div`,{className:`review-summary`}),t=$(`div`,{className:`review-payload`});if(F=t,e.append(t),a>0){let t=$(`button`,{className:`review-more`,type:`button`,text:`Show ${a} more ${a===1?`file`:`files`}`});t.addEventListener(`click`,()=>{M=!0,H()}),e.append(t)}c.append(e)}s.append(c),z.replaceChildren(s),W()}function we(t,n){let r=$(`span`,{className:n?`chevron ${t?`expanded`:``}`:`chevron`,ariaHidden:`true`});return n&&r.append(e(o.chevronDown)),r}function Te(e){return[`tool-card`,e.tone,e.state?`state-${e.state}`:void 0].filter(Boolean).join(` `)}function Y(t,n){let r=t.previousElementSibling,i=r?.querySelector(`.chevron`);if(!i)return;i.classList.toggle(`loading`,n),i.replaceChildren(e(n?o.loading:o.chevronDown));let a=r instanceof HTMLButtonElement?r:null;a&&a.setAttribute(`aria-busy`,String(n))}function Ee(t,n){K();let i=$(`div`,{className:`workspace-details pretty-scrollbar`}),a=$(`div`,{className:`workspace-rows`}),s=n.worktree;if(s){let t=[s.baseRef,s.baseSha?.slice(0,8)].filter(e=>!!e).join(` · `)||`Worktree`,n=$(`span`,{className:`workspace-base-value`});if(n.append($(`span`,{className:`workspace-value`,text:t,title:t})),s.dirtySource){let t=$(`span`,{className:`workspace-base-warning`,title:`The source checkout had uncommitted changes when this worktree was created. Those changes are not included here.`,ariaLabel:`Source checkout changes are not included in this worktree`});t.append(e(o.warning,`workspace-base-warning-svg`)),n.append(t)}Z(a,`Base`,n,o.base),s.branch&&X(a,`Worktree branch`,s.branch,o.gitBranch,!1),s.targetBranch&&X(a,`Merge target`,s.targetBranch,o.gitBranch,!1)}n.sourceRoot&&n.sourceRoot!==n.root&&X(a,`Source checkout`,n.sourceRoot,o.sourceCheckout,!0),De(a,n.agentsFiles??[],n.availableAgentsFiles??[]);let c=n.skills??[];c.length>0&&Pe(a,c);let l=n.agentProviders??[],u=(n.agents??[]).map(e=>{let t=e.name??`Unnamed agent`,n=e.provider?.trim(),i=e.providerAvailable===!1,a=[e.description,n?`Provider: ${n}`:void 0,e.model?`Model: ${e.model}`:void 0,e.thinking?`Thinking: ${e.thinking}`:void 0,i?e.providerUnavailableReason??`Provider unavailable`:void 0].filter(e=>!!e).join(`
5
+ `);return{label:t,logo:n?r(n):void 0,profile:!0,tone:i?`muted`:void 0,title:a||void 0}}),d=l.map(e=>{let t=e.name?.trim()||`Unknown provider`,n=e.available===!1,i=r(t);return{label:t,logo:i,bareLogo:!!i,ariaLabel:t,tone:n?`muted`:void 0,title:n?e.reason??`Provider unavailable`:t}});if(u.length>0){let e=Q([...u,...d]);e.classList.add(`workspace-agents-list`),Z(a,`Agents`,e,o.agents,`workspace-agents-row`)}else d.length>0&&Ne(a,`Providers`,d,o.providers);a.childElementCount>0&&i.append(a),i.childElementCount===0&&i.append($(`div`,{className:`status muted`,text:`No workspace details available.`})),t.replaceChildren(i)}function De(e,t,n){let r=[],i=new Set;for(let[e,n]of t.entries())r.push({key:`loaded:${e}`,path:n.path,label:n.path??`Loaded instructions`,content:n.content,status:`loaded`}),n.path&&i.add(n.path);let a=[];for(let[e,t]of n.entries())t.path&&i.has(t.path)||a.push({key:`available:${e}`,path:t.path,label:t.path??`Nested instructions`,status:`available`});if(r.length===0&&a.length===0)return;let s=Oe(L?[...r,...a]:r);if(a.length>0){let e=L,t=$(`button`,{className:`workspace-instructions-toggle`,type:`button`,text:e?`Show less`:`View all`,ariaLabel:e?`Show only loaded instruction files`:`View all ${a.length} available instruction files`,ariaExpanded:String(e)});t.addEventListener(`click`,()=>{L=!L,L||(I=null),H()}),s.append(t)}let c=$(`div`,{className:`workspace-instructions-content`});c.append(s),Z(e,`Instructions`,c,o.instructions,`workspace-instructions-row`)}function Oe(t){let n=$(`span`,{className:`workspace-instruction-list`});for(let r of t){let t=$(`span`,{className:`workspace-instruction-item`});t.dataset.instructionKey=r.key;let i=r.status===`loaded`&&r.content!==void 0,a=$(i?`button`:`span`,{className:`workspace-instruction-header${i?` interactive`:``}`,type:i?`button`:void 0,ariaLabel:i?`View ${r.label}`:void 0,ariaExpanded:i?`false`:void 0}),s=$(`span`,{className:`workspace-instruction-text`}),c=Me(r.label);if(s.append($(`span`,{className:`workspace-instruction-name`,text:c})),r.path&&r.path!==c&&s.append($(`span`,{className:`workspace-instruction-path`,text:r.path,title:r.path})),a.append(Ae(r.status),s),i){let i=$(`span`,{className:`workspace-instruction-chevron`,ariaHidden:`true`});i.append(e(o.chevronDown,`workspace-instruction-chevron-svg`)),a.append(i),a.addEventListener(`click`,()=>{I=I===r.key?null:r.key,ke(n)});let s=$(`pre`,{className:`workspace-instruction-preview pretty-scrollbar`,text:r.content});s.hidden=!0,t.append(a,s)}else t.append(a);n.append(t)}return ke(n),n}function ke(e){for(let t of e.querySelectorAll(`.workspace-instruction-item`)){let e=t.dataset.instructionKey===I;t.classList.toggle(`expanded`,e),t.querySelector(`.workspace-instruction-header.interactive`)?.setAttribute(`aria-expanded`,String(e));let n=t.querySelector(`.workspace-instruction-preview`);n&&(n.hidden=!e)}}function Ae(t){let n=je(t),r=$(`span`,{className:`workspace-instruction-status ${t}`,title:n,ariaLabel:n});return r.setAttribute(`role`,`img`),r.append(e(t===`loaded`?o.instructionLoaded:o.instructionAvailable,`workspace-instruction-status-svg`)),r}function je(e){return e===`loaded`?`Loaded into the current workspace context`:`Available for a nested directory`}function Me(e){return e.replaceAll(`\\`,`/`).split(`/`).filter(Boolean).at(-1)??e}function X(e,t,n,r,i=!1){Z(e,t,$(`span`,{className:`workspace-value${i?` mono`:``}`,text:n,title:n}),r)}function Ne(e,t,n,r){Z(e,t,Q(n),r)}function Z(e,t,n,r,i){let a=$(`div`,{className:[`workspace-row`,i].filter(Boolean).join(` `)});a.append(Fe(r),$(`span`,{className:`workspace-key`,text:t}),n),e.append(a)}function Pe(e,t){let n=Q(t.map(e=>({label:e.name??`Unnamed skill`,title:e.description||void 0})));n.classList.add(`workspace-skills-list`),Z(e,`Skills`,n,o.skills,`workspace-skills-row`)}function Fe(t){let n=$(`span`,{className:`workspace-row-icon`,ariaHidden:`true`});return n.append(e(t,`workspace-row-icon-svg`)),n}function Q(e){let t=$(`span`,{className:`workspace-chip-list`});for(let n of e){let e=!!(n.bareLogo&&n.logo),r=$(`span`,{className:[e?`workspace-provider-logo`:n.profile?`workspace-agent-profile`:`workspace-chip`,n.tone].filter(Boolean).join(` `),title:n.title});if(e&&(r.setAttribute(`role`,`img`),r.setAttribute(`aria-label`,n.ariaLabel??n.label)),n.logo){let t=document.createElement(`img`);t.className=e?`workspace-provider-logo-image`:n.profile?`workspace-agent-profile-logo`:`workspace-chip-logo`,t.src=n.logo,t.alt=``,t.setAttribute(`aria-hidden`,`true`),r.append(t)}e||r.append($(`span`,{className:`workspace-chip-label`,text:n.label})),t.append(r)}return t}function Ie(e){let t=e._meta?.tool;return u(t)?t:void 0}function Le(e){let t=e._meta?.card;return t&&typeof t==`object`?t:void 0}function Re(e){return e.structuredContent}function $(e,t={}){let n=document.createElement(e);return t.className&&(n.className=t.className),t.text!==void 0&&(n.textContent=t.text),t.type!==void 0&&`type`in n&&n.setAttribute(`type`,t.type),t.title!==void 0&&(n.title=t.title),t.ariaHidden!==void 0&&n.setAttribute(`aria-hidden`,t.ariaHidden),t.ariaLabel!==void 0&&n.setAttribute(`aria-label`,t.ariaLabel),t.ariaExpanded!==void 0&&n.setAttribute(`aria-expanded`,t.ariaExpanded),t.disabled!==void 0&&`disabled`in n&&(n.disabled=t.disabled),n}export{d as a,g as c,p as i,oe as n,f as o,se as r,ne as s,ce as t};
@@ -0,0 +1 @@
1
+ import"./workspace-app-DkAiSl_0.js";import"./workspace-app-QyauBrJX.js";document.documentElement.dataset.forgerelayApp=`workspace-lifecycle-compatibility`;
@@ -0,0 +1 @@
1
+ import{n as e}from"./chunk-EyZ2wyi3.js";import{t}from"./java-ppHvycj5.js";var n=e({default:()=>i}),r=Object.freeze(JSON.parse(`{"displayName":"XML","name":"xml","patterns":[{"begin":"(<\\\\?)\\\\s*([-0-9A-Z_a-z]+)","captures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"entity.name.tag.xml"}},"end":"(\\\\?>)","name":"meta.tag.preprocessor.xml","patterns":[{"match":" ([-A-Za-z]+)","name":"entity.other.attribute-name.xml"},{"include":"#doublequotedString"},{"include":"#singlequotedString"}]},{"begin":"(<!)(DOCTYPE)\\\\s+([:A-Z_a-z][-.0-:A-Z_a-z]*)","captures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"keyword.other.doctype.xml"},"3":{"name":"variable.language.documentroot.xml"}},"end":"\\\\s*(>)","name":"meta.tag.sgml.doctype.xml","patterns":[{"include":"#internalSubset"}]},{"include":"#comments"},{"begin":"(<)((?:([-0-9A-Z_a-z]+)(:))?([-0-:A-Z_a-z]+))(?=(\\\\s[^>]*)?></\\\\2>)","beginCaptures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"entity.name.tag.xml"},"3":{"name":"entity.name.tag.namespace.xml"},"4":{"name":"punctuation.separator.namespace.xml"},"5":{"name":"entity.name.tag.localname.xml"}},"end":"(>)(</)((?:([-0-9A-Z_a-z]+)(:))?([-0-:A-Z_a-z]+))(>)","endCaptures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"punctuation.definition.tag.xml"},"3":{"name":"entity.name.tag.xml"},"4":{"name":"entity.name.tag.namespace.xml"},"5":{"name":"punctuation.separator.namespace.xml"},"6":{"name":"entity.name.tag.localname.xml"},"7":{"name":"punctuation.definition.tag.xml"}},"name":"meta.tag.no-content.xml","patterns":[{"include":"#tagStuff"}]},{"begin":"(</?)(?:([-.\\\\w]+)((:)))?([-.:\\\\w]+)","captures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"entity.name.tag.namespace.xml"},"3":{"name":"entity.name.tag.xml"},"4":{"name":"punctuation.separator.namespace.xml"},"5":{"name":"entity.name.tag.localname.xml"}},"end":"(/?>)","name":"meta.tag.xml","patterns":[{"include":"#tagStuff"}]},{"include":"#entity"},{"include":"#bare-ampersand"},{"begin":"<%@","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.xml"}},"end":"%>","endCaptures":{"0":{"name":"punctuation.section.embedded.end.xml"}},"name":"source.java-props.embedded.xml","patterns":[{"match":"page|include|taglib","name":"keyword.other.page-props.xml"}]},{"begin":"<%[!=]?(?!--)","beginCaptures":{"0":{"name":"punctuation.section.embedded.begin.xml"}},"end":"(?!--)%>","endCaptures":{"0":{"name":"punctuation.section.embedded.end.xml"}},"name":"source.java.embedded.xml","patterns":[{"include":"source.java"}]},{"begin":"<!\\\\[CDATA\\\\[","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.xml"}},"end":"]]>","endCaptures":{"0":{"name":"punctuation.definition.string.end.xml"}},"name":"string.unquoted.cdata.xml"}],"repository":{"EntityDecl":{"begin":"(<!)(ENTITY)\\\\s+(%\\\\s+)?([:A-Z_a-z][-.0-:A-Z_a-z]*)(\\\\s+(?:SYSTEM|PUBLIC)\\\\s+)?","captures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"keyword.other.entity.xml"},"3":{"name":"punctuation.definition.entity.xml"},"4":{"name":"variable.language.entity.xml"},"5":{"name":"keyword.other.entitytype.xml"}},"end":"(>)","patterns":[{"include":"#doublequotedString"},{"include":"#singlequotedString"}]},"bare-ampersand":{"match":"&","name":"invalid.illegal.bad-ampersand.xml"},"comments":{"patterns":[{"begin":"<%--","captures":{"0":{"name":"punctuation.definition.comment.xml"},"end":"--%>","name":"comment.block.xml"}},{"begin":"<!--","captures":{"0":{"name":"punctuation.definition.comment.xml"}},"end":"-->","name":"comment.block.xml","patterns":[{"begin":"--(?!>)","captures":{"0":{"name":"invalid.illegal.bad-comments-or-CDATA.xml"}}}]}]},"doublequotedString":{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.xml"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.xml"}},"name":"string.quoted.double.xml","patterns":[{"include":"#entity"},{"include":"#bare-ampersand"}]},"entity":{"captures":{"1":{"name":"punctuation.definition.constant.xml"},"3":{"name":"punctuation.definition.constant.xml"}},"match":"(&)([:A-Z_a-z][-.0-:A-Z_a-z]*|#[0-9]+|#x\\\\h+)(;)","name":"constant.character.entity.xml"},"internalSubset":{"begin":"(\\\\[)","captures":{"1":{"name":"punctuation.definition.constant.xml"}},"end":"(])","name":"meta.internalsubset.xml","patterns":[{"include":"#EntityDecl"},{"include":"#parameterEntity"},{"include":"#comments"}]},"parameterEntity":{"captures":{"1":{"name":"punctuation.definition.constant.xml"},"3":{"name":"punctuation.definition.constant.xml"}},"match":"(%)([:A-Z_a-z][-.0-:A-Z_a-z]*)(;)","name":"constant.character.parameter-entity.xml"},"singlequotedString":{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.xml"}},"end":"'","endCaptures":{"0":{"name":"punctuation.definition.string.end.xml"}},"name":"string.quoted.single.xml","patterns":[{"include":"#entity"},{"include":"#bare-ampersand"}]},"tagStuff":{"patterns":[{"captures":{"1":{"name":"entity.other.attribute-name.namespace.xml"},"2":{"name":"entity.other.attribute-name.xml"},"3":{"name":"punctuation.separator.namespace.xml"},"4":{"name":"entity.other.attribute-name.localname.xml"}},"match":"(?:^|\\\\s+)(?:([-.\\\\w]+)((:)))?([-.:\\\\w]+)\\\\s*="},{"include":"#doublequotedString"},{"include":"#singlequotedString"}]}},"scopeName":"text.xml","embeddedLangs":["java"]}`)),i=[...t,r];export{n,i as t};
@@ -1 +1 @@
1
- import{t as e}from"./xml-Cun8xb0T.js";var t=Object.freeze(JSON.parse(`{"displayName":"XSL","name":"xsl","patterns":[{"begin":"(<)(xsl)((:))(template)","captures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"entity.name.tag.namespace.xml"},"3":{"name":"entity.name.tag.xml"},"4":{"name":"punctuation.separator.namespace.xml"},"5":{"name":"entity.name.tag.localname.xml"}},"end":"(>)","name":"meta.tag.xml.template","patterns":[{"captures":{"1":{"name":"entity.other.attribute-name.namespace.xml"},"2":{"name":"entity.other.attribute-name.xml"},"3":{"name":"punctuation.separator.namespace.xml"},"4":{"name":"entity.other.attribute-name.localname.xml"}},"match":" (?:([-0-9A-Z_a-z]+)((:)))?([-A-Za-z]+)"},{"include":"#doublequotedString"},{"include":"#singlequotedString"}]},{"include":"text.xml"}],"repository":{"doublequotedString":{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.xml"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.xml"}},"name":"string.quoted.double.xml"},"singlequotedString":{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.xml"}},"end":"'","endCaptures":{"0":{"name":"punctuation.definition.string.end.xml"}},"name":"string.quoted.single.xml"}},"scopeName":"text.xml.xsl","embeddedLangs":["xml"]}`)),n=[...e,t];export{n as default};
1
+ import{t as e}from"./xml-JnmX6vyS.js";var t=Object.freeze(JSON.parse(`{"displayName":"XSL","name":"xsl","patterns":[{"begin":"(<)(xsl)((:))(template)","captures":{"1":{"name":"punctuation.definition.tag.xml"},"2":{"name":"entity.name.tag.namespace.xml"},"3":{"name":"entity.name.tag.xml"},"4":{"name":"punctuation.separator.namespace.xml"},"5":{"name":"entity.name.tag.localname.xml"}},"end":"(>)","name":"meta.tag.xml.template","patterns":[{"captures":{"1":{"name":"entity.other.attribute-name.namespace.xml"},"2":{"name":"entity.other.attribute-name.xml"},"3":{"name":"punctuation.separator.namespace.xml"},"4":{"name":"entity.other.attribute-name.localname.xml"}},"match":" (?:([-0-9A-Z_a-z]+)((:)))?([-A-Za-z]+)"},{"include":"#doublequotedString"},{"include":"#singlequotedString"}]},{"include":"text.xml"}],"repository":{"doublequotedString":{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.xml"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.xml"}},"name":"string.quoted.double.xml"},"singlequotedString":{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.xml"}},"end":"'","endCaptures":{"0":{"name":"punctuation.definition.string.end.xml"}},"name":"string.quoted.single.xml"}},"scopeName":"text.xml.xsl","embeddedLangs":["xml"]}`)),n=[...e,t];export{n as default};
@@ -0,0 +1 @@
1
+ import{n as e}from"./chunk-EyZ2wyi3.js";var t=e({default:()=>n}),n=[Object.freeze(JSON.parse(`{"displayName":"YAML","fileTypes":["yaml","yml","rviz","reek","clang-format","yaml-tmlanguage","syntax","sublime-syntax"],"firstLineMatch":"^%YAML( ?1.\\\\d+)?","name":"yaml","patterns":[{"include":"#comment"},{"include":"#property"},{"include":"#directive"},{"match":"^---","name":"entity.other.document.begin.yaml"},{"match":"^\\\\.{3}","name":"entity.other.document.end.yaml"},{"include":"#node"}],"repository":{"block-collection":{"patterns":[{"include":"#block-sequence"},{"include":"#block-mapping"}]},"block-mapping":{"patterns":[{"include":"#block-pair"}]},"block-node":{"patterns":[{"include":"#prototype"},{"include":"#block-scalar"},{"include":"#block-collection"},{"include":"#flow-scalar-plain-out"},{"include":"#flow-node"}]},"block-pair":{"patterns":[{"begin":"\\\\?","beginCaptures":{"1":{"name":"punctuation.definition.key-value.begin.yaml"}},"end":"(?=\\\\?)|^ *(:)|(:)","endCaptures":{"1":{"name":"punctuation.separator.key-value.mapping.yaml"},"2":{"name":"invalid.illegal.expected-newline.yaml"}},"name":"meta.block-mapping.yaml","patterns":[{"include":"#block-node"}]},{"begin":"(?=(?:[^-\\\\]!\\"#%\\\\&'*,:>?@\\\\[\`{|}\\\\s]|[-:?]\\\\S)([^:\\\\s]|:\\\\S|\\\\s+(?![#\\\\s]))*\\\\s*:(\\\\s|$))","end":"(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$))","patterns":[{"include":"#flow-scalar-plain-out-implicit-type"},{"begin":"[^-\\\\]!\\"#%\\\\&'*,:>?@\\\\[\`{|}\\\\s]|[-:?]\\\\S","beginCaptures":{"0":{"name":"entity.name.tag.yaml"}},"contentName":"entity.name.tag.yaml","end":"(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$))","name":"string.unquoted.plain.out.yaml"}]},{"match":":(?=\\\\s|$)","name":"punctuation.separator.key-value.mapping.yaml"}]},"block-scalar":{"begin":"(?:(\\\\|)|(>))([1-9])?([-+])?(.*\\\\n?)","beginCaptures":{"1":{"name":"keyword.control.flow.block-scalar.literal.yaml"},"2":{"name":"keyword.control.flow.block-scalar.folded.yaml"},"3":{"name":"constant.numeric.indentation-indicator.yaml"},"4":{"name":"storage.modifier.chomping-indicator.yaml"},"5":{"patterns":[{"include":"#comment"},{"match":".+","name":"invalid.illegal.expected-comment-or-newline.yaml"}]}},"end":"^(?=\\\\S)|(?!\\\\G)","patterns":[{"begin":"^( +)(?! )","end":"^(?!\\\\1|\\\\s*$)","name":"string.unquoted.block.yaml"}]},"block-sequence":{"match":"(-)(?!\\\\S)","name":"punctuation.definition.block.sequence.item.yaml"},"comment":{"begin":"(?:^([\\\\t ]*)|[\\\\t ]+)(?=#\\\\p{print}*$)","beginCaptures":{"1":{"name":"punctuation.whitespace.comment.leading.yaml"}},"end":"(?!\\\\G)","patterns":[{"begin":"#","beginCaptures":{"0":{"name":"punctuation.definition.comment.yaml"}},"end":"\\\\n","name":"comment.line.number-sign.yaml"}]},"directive":{"begin":"^%","beginCaptures":{"0":{"name":"punctuation.definition.directive.begin.yaml"}},"end":"(?=$|[\\\\t ]+($|#))","name":"meta.directive.yaml","patterns":[{"captures":{"1":{"name":"keyword.other.directive.yaml.yaml"},"2":{"name":"constant.numeric.yaml-version.yaml"}},"match":"\\\\G(YAML)[\\\\t ]+(\\\\d+\\\\.\\\\d+)"},{"captures":{"1":{"name":"keyword.other.directive.tag.yaml"},"2":{"name":"storage.type.tag-handle.yaml"},"3":{"name":"support.type.tag-prefix.yaml"}},"match":"\\\\G(TAG)(?:[\\\\t ]+(!(?:[-0-9A-Za-z]*!)?)(?:[\\\\t ]+(!(?:%\\\\h{2}|[]!#$\\\\&-;=?-\\\\[_a-z~])*|(?![]!,\\\\[{}])(?:%\\\\h{2}|[]!#$\\\\&-;=?-\\\\[_a-z~])+))?)?"},{"captures":{"1":{"name":"support.other.directive.reserved.yaml"},"2":{"name":"string.unquoted.directive-name.yaml"},"3":{"name":"string.unquoted.directive-parameter.yaml"}},"match":"\\\\G(\\\\w+)(?:[\\\\t ]+(\\\\w+)(?:[\\\\t ]+(\\\\w+))?)?"},{"match":"\\\\S+","name":"invalid.illegal.unrecognized.yaml"}]},"flow-alias":{"captures":{"1":{"name":"keyword.control.flow.alias.yaml"},"2":{"name":"punctuation.definition.alias.yaml"},"3":{"name":"variable.other.alias.yaml"},"4":{"name":"invalid.illegal.character.anchor.yaml"}},"match":"((\\\\*))([^],/\\\\[{}\\\\s]+)([^],}\\\\s]\\\\S*)?"},"flow-collection":{"patterns":[{"include":"#flow-sequence"},{"include":"#flow-mapping"}]},"flow-mapping":{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.mapping.begin.yaml"}},"end":"}","endCaptures":{"0":{"name":"punctuation.definition.mapping.end.yaml"}},"name":"meta.flow-mapping.yaml","patterns":[{"include":"#prototype"},{"match":",","name":"punctuation.separator.mapping.yaml"},{"include":"#flow-pair"}]},"flow-node":{"patterns":[{"include":"#prototype"},{"include":"#flow-alias"},{"include":"#flow-collection"},{"include":"#flow-scalar"}]},"flow-pair":{"patterns":[{"begin":"\\\\?","beginCaptures":{"0":{"name":"punctuation.definition.key-value.begin.yaml"}},"end":"(?=[],}])","name":"meta.flow-pair.explicit.yaml","patterns":[{"include":"#prototype"},{"include":"#flow-pair"},{"include":"#flow-node"},{"begin":":(?=\\\\s|$|[],\\\\[{}])","beginCaptures":{"0":{"name":"punctuation.separator.key-value.mapping.yaml"}},"end":"(?=[],}])","patterns":[{"include":"#flow-value"}]}]},{"begin":"(?=(?:[^-\\\\]!\\"#%\\\\&'*,:>?@\\\\[\`{|}\\\\s]|[-:?][^],\\\\[{}\\\\s])([^],:\\\\[{}\\\\s]|:[^],\\\\[{}\\\\s]|\\\\s+(?![#\\\\s]))*\\\\s*:(\\\\s|$))","end":"(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$)|\\\\s*:[],\\\\[{}]|\\\\s*[],\\\\[{}])","name":"meta.flow-pair.key.yaml","patterns":[{"include":"#flow-scalar-plain-in-implicit-type"},{"begin":"[^-\\\\]!\\"#%\\\\&'*,:>?@\\\\[\`{|}\\\\s]|[-:?][^],\\\\[{}\\\\s]","beginCaptures":{"0":{"name":"entity.name.tag.yaml"}},"contentName":"entity.name.tag.yaml","end":"(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$)|\\\\s*:[],\\\\[{}]|\\\\s*[],\\\\[{}])","name":"string.unquoted.plain.in.yaml"}]},{"include":"#flow-node"},{"begin":":(?=\\\\s|$|[],\\\\[{}])","captures":{"0":{"name":"punctuation.separator.key-value.mapping.yaml"}},"end":"(?=[],}])","name":"meta.flow-pair.yaml","patterns":[{"include":"#flow-value"}]}]},"flow-scalar":{"patterns":[{"include":"#flow-scalar-double-quoted"},{"include":"#flow-scalar-single-quoted"},{"include":"#flow-scalar-plain-in"}]},"flow-scalar-double-quoted":{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.yaml"}},"end":"\\"","endCaptures":{"0":{"name":"punctuation.definition.string.end.yaml"}},"name":"string.quoted.double.yaml","patterns":[{"match":"\\\\\\\\([ \\"/0LN\\\\\\\\_abefnprtv]|x\\\\d\\\\d|u\\\\d{4}|U\\\\d{8})","name":"constant.character.escape.yaml"},{"match":"\\\\\\\\\\\\n","name":"constant.character.escape.double-quoted.newline.yaml"}]},"flow-scalar-plain-in":{"patterns":[{"include":"#flow-scalar-plain-in-implicit-type"},{"begin":"[^-\\\\]!\\"#%\\\\&'*,:>?@\\\\[\`{|}\\\\s]|[-:?][^],\\\\[{}\\\\s]","end":"(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$)|\\\\s*:[],\\\\[{}]|\\\\s*[],\\\\[{}])","name":"string.unquoted.plain.in.yaml"}]},"flow-scalar-plain-in-implicit-type":{"patterns":[{"captures":{"1":{"name":"constant.language.null.yaml"},"2":{"name":"constant.language.boolean.yaml"},"3":{"name":"constant.numeric.integer.yaml"},"4":{"name":"constant.numeric.float.yaml"},"5":{"name":"constant.other.timestamp.yaml"},"6":{"name":"constant.language.value.yaml"},"7":{"name":"constant.language.merge.yaml"}},"match":"(?:(null|Null|NULL|~)|([Yy]|yes|Yes|YES|[Nn]|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF)|([-+]?0b[01_]+|[-+]?0[0-7_]+|[-+]?(?:0|[1-9][0-9_]*)|[-+]?0x[_\\\\h]+|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)|([-+]?(?:[0-9][0-9_]*)?\\\\.[.0-9]*(?:[Ee][-+][0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\\\.[0-9_]*|[-+]?\\\\.(?:inf|Inf|INF)|\\\\.(?:nan|NaN|NAN))|(\\\\d{4}-\\\\d{2}-\\\\d{2}|\\\\d{4}-\\\\d{1,2}-\\\\d{1,2}(?:[Tt]|[\\\\t ]+)\\\\d{1,2}:\\\\d{2}:\\\\d{2}(?:\\\\.\\\\d*)?(?:[\\\\t ]*Z|[-+]\\\\d{1,2}(?::\\\\d{1,2})?)?)|(=)|(<<))(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$)|\\\\s*:[],\\\\[{}]|\\\\s*[],\\\\[{}])"}]},"flow-scalar-plain-out":{"patterns":[{"include":"#flow-scalar-plain-out-implicit-type"},{"begin":"[^-\\\\]!\\"#%\\\\&'*,:>?@\\\\[\`{|}\\\\s]|[-:?]\\\\S","end":"(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$))","name":"string.unquoted.plain.out.yaml"}]},"flow-scalar-plain-out-implicit-type":{"patterns":[{"captures":{"1":{"name":"constant.language.null.yaml"},"2":{"name":"constant.language.boolean.yaml"},"3":{"name":"constant.numeric.integer.yaml"},"4":{"name":"constant.numeric.float.yaml"},"5":{"name":"constant.other.timestamp.yaml"},"6":{"name":"constant.language.value.yaml"},"7":{"name":"constant.language.merge.yaml"}},"match":"(?:(null|Null|NULL|~)|([Yy]|yes|Yes|YES|[Nn]|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF)|([-+]?0b[01_]+|[-+]?0[0-7_]+|[-+]?(?:0|[1-9][0-9_]*)|[-+]?0x[_\\\\h]+|[-+]?[1-9][0-9_]*(?::[0-5]?[0-9])+)|([-+]?(?:[0-9][0-9_]*)?\\\\.[.0-9]*(?:[Ee][-+][0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\\\.[0-9_]*|[-+]?\\\\.(?:inf|Inf|INF)|\\\\.(?:nan|NaN|NAN))|(\\\\d{4}-\\\\d{2}-\\\\d{2}|\\\\d{4}-\\\\d{1,2}-\\\\d{1,2}(?:[Tt]|[\\\\t ]+)\\\\d{1,2}:\\\\d{2}:\\\\d{2}(?:\\\\.\\\\d*)?(?:[\\\\t ]*Z|[-+]\\\\d{1,2}(?::\\\\d{1,2})?)?)|(=)|(<<))(?=\\\\s*$|\\\\s+#|\\\\s*:(\\\\s|$))"}]},"flow-scalar-single-quoted":{"begin":"'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.yaml"}},"end":"'(?!')","endCaptures":{"0":{"name":"punctuation.definition.string.end.yaml"}},"name":"string.quoted.single.yaml","patterns":[{"match":"''","name":"constant.character.escape.single-quoted.yaml"}]},"flow-sequence":{"begin":"\\\\[","beginCaptures":{"0":{"name":"punctuation.definition.sequence.begin.yaml"}},"end":"]","endCaptures":{"0":{"name":"punctuation.definition.sequence.end.yaml"}},"name":"meta.flow-sequence.yaml","patterns":[{"include":"#prototype"},{"match":",","name":"punctuation.separator.sequence.yaml"},{"include":"#flow-pair"},{"include":"#flow-node"}]},"flow-value":{"patterns":[{"begin":"\\\\G(?![],}])","end":"(?=[],}])","name":"meta.flow-pair.value.yaml","patterns":[{"include":"#flow-node"}]}]},"node":{"patterns":[{"include":"#block-node"}]},"property":{"begin":"(?=[!\\\\&])","end":"(?!\\\\G)","name":"meta.property.yaml","patterns":[{"captures":{"1":{"name":"keyword.control.property.anchor.yaml"},"2":{"name":"punctuation.definition.anchor.yaml"},"3":{"name":"entity.name.type.anchor.yaml"},"4":{"name":"invalid.illegal.character.anchor.yaml"}},"match":"\\\\G((&))([^],/\\\\[{}\\\\s]+)(\\\\S+)?"},{"match":"\\\\G!(?:<(?:%\\\\h{2}|[]!#$\\\\&-;=?-\\\\[_a-z~])+>|(?:[-0-9A-Za-z]*!)?(?:%\\\\h{2}|[#$\\\\&-+\\\\--;=?-Z_a-z~])+|)(?=[\\\\t ]|$)","name":"storage.type.tag-handle.yaml"},{"match":"\\\\S+","name":"invalid.illegal.tag-handle.yaml"}]},"prototype":{"patterns":[{"include":"#comment"},{"include":"#property"}]}},"scopeName":"source.yaml","aliases":["yml"]}`))];export{t as n,n as t};
@@ -4,8 +4,11 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>ForgeRelay Diff</title>
7
- <script type="module" crossorigin src="./assets/workspace-app-Cm9EX5x4.js"></script>
8
- <link rel="stylesheet" crossorigin href="./assets/workspace-app-DHvE2ojW.css">
7
+ <script type="module" crossorigin src="./assets/workspace-app-DJmkPYJC.js"></script>
8
+ <link rel="modulepreload" crossorigin href="./assets/chunk-EyZ2wyi3.js">
9
+ <link rel="modulepreload" crossorigin href="./assets/workspace-app-DkAiSl_0.js">
10
+ <link rel="modulepreload" crossorigin href="./assets/workspace-app-QyauBrJX.js">
11
+ <link rel="stylesheet" crossorigin href="./assets/workspace-app-CcrHAUIn.css">
9
12
  </head>
10
13
  <body>
11
14
  <main id="app" class="shell">
@@ -0,0 +1,18 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>ForgeRelay Workspace Lifecycle</title>
7
+ <script type="module" crossorigin src="./assets/workspace-lifecycle-app-BIXEo53I.js"></script>
8
+ <link rel="modulepreload" crossorigin href="./assets/chunk-EyZ2wyi3.js">
9
+ <link rel="modulepreload" crossorigin href="./assets/workspace-app-DkAiSl_0.js">
10
+ <link rel="modulepreload" crossorigin href="./assets/workspace-app-QyauBrJX.js">
11
+ <link rel="stylesheet" crossorigin href="./assets/workspace-app-CcrHAUIn.css">
12
+ </head>
13
+ <body>
14
+ <main id="app" class="shell">
15
+ <section class="empty">Waiting for a workspace result.</section>
16
+ </main>
17
+ </body>
18
+ </html>
@@ -713,6 +713,17 @@ export class WorkspaceRegistry {
713
713
  return absolutePath;
714
714
  }
715
715
  resolveReadPath(workspace, inputPath) {
716
+ if (inputPath.startsWith("skills://")) {
717
+ const skillRead = resolveSkillReadPath(workspace.skills, workspace.activatedSkillDirs, inputPath);
718
+ if (!skillRead) {
719
+ throw new Error(`Skill resource is not readable before its skill is loaded: ${inputPath}. Read skills://<name> first.`);
720
+ }
721
+ return {
722
+ absolutePath: skillRead.absolutePath,
723
+ readRoots: [workspace.root, skillRead.skill.baseDir],
724
+ skillRead,
725
+ };
726
+ }
716
727
  try {
717
728
  return {
718
729
  absolutePath: this.resolvePath(workspace, inputPath),
@@ -30,7 +30,7 @@ npx @akira-tl/forgerelay init
30
30
  npx @akira-tl/forgerelay serve
31
31
  npx @akira-tl/forgerelay doctor
32
32
  npx @akira-tl/forgerelay config get
33
- npx @akira-tl/forgerelay config set publicBaseUrl https://forge.example.com
33
+ npx @akira-tl/forgerelay config set publicBaseUrl https://forge.example.com/forgerelay/main,https://forge-alt.example.com/relay
34
34
  ```
35
35
 
36
36
  ## Environment variable compatibility
@@ -55,7 +55,7 @@ When both are present, `FORGERELAY_*` wins.
55
55
  | `HOST` | Local bind host. Defaults to `127.0.0.1`. |
56
56
  | `PORT` | Local port. Defaults to `7676`. |
57
57
  | `FORGERELAY_ALLOWED_ROOTS` | Comma-separated roots that workspaces may open. |
58
- | `FORGERELAY_PUBLIC_BASE_URL` | Public origin, without `/mcp`. |
58
+ | `FORGERELAY_PUBLIC_BASE_URL` | One public base URL or a comma-separated list. Each URL may include its own routed path prefix; the first URL is canonical. All configured hostnames are added to the derived Host-header allowlist. |
59
59
  | `FORGERELAY_ALLOWED_HOSTS` | Optional Host-header allowlist override. |
60
60
  | `FORGERELAY_OAUTH_OWNER_TOKEN` | Owner password. Must be at least 16 characters. |
61
61
  | `FORGERELAY_STATE_DIR` | SQLite state directory. New default: `~/.local/share/forgerelay`. |
@@ -63,6 +63,31 @@ When both are present, `FORGERELAY_*` wins.
63
63
  | `FORGERELAY_WORKFLOW_INSTRUCTIONS` | Replace the built-in workflow policy while retaining the capability contract. |
64
64
  | `FORGERELAY_APPEND_INSTRUCTIONS` | Append project/operator workflow policy. |
65
65
 
66
+ ### Routed and multi-origin public deployments
67
+
68
+ `publicBaseUrl` stays the single deployment setting. Persist one URL as a string,
69
+ or multiple URLs as an array:
70
+
71
+ ```json
72
+ {
73
+ "publicBaseUrl": [
74
+ "https://forge.example.com/forgerelay/main",
75
+ "https://forge-alt.example.com/relay"
76
+ ]
77
+ }
78
+ ```
79
+
80
+ Each entry keeps its own route prefix. The first URL is canonical and is used for
81
+ generated OAuth/MCP URLs; every configured hostname is included in the derived
82
+ Host-header allowlist. MCP App `_meta.ui.domain` uses the canonical URL's origin,
83
+ while CSP resource/connect entries include every full public base URL. The full
84
+ ordered `publicBaseUrl` list also participates in the MCP App resource cache
85
+ identity, so changing any domain or route produces a new `ui://` resource URI.
86
+
87
+ A single persisted string remains fully supported, so existing configs require no
88
+ migration. For environment configuration, use a comma-separated list in
89
+ `FORGERELAY_PUBLIC_BASE_URL`.
90
+
66
91
  If an existing legacy state/worktree directory is present and the new default is
67
92
  not, ForgeRelay reuses the legacy location rather than orphaning stored state.
68
93
  Persisted `stateDir` and `worktreeRoot` values in `config.json` also continue to
@@ -334,10 +359,17 @@ regular Agent workflows should use the single `bash` process lifecycle.
334
359
 
335
360
  | Value | Behavior |
336
361
  | --- | --- |
337
- | `full` | Default. Attach UI to exposed workspace/file/edit/shell tools. |
338
- | `changes` | Attach UI to `open_workspace` and Capability Gateway review results from `review.changes`. |
362
+ | `full` | Default. Attach the single ForgeRelay Panel through `activity_panel(workspaceId)`; ordinary work tools remain data-only. |
363
+ | `changes` | Attach the same ForgeRelay Panel while retaining change-review checkpoint behavior. |
339
364
  | `off` | Disable widget UI. |
340
365
 
366
+ The Workspace Summary in the ForgeRelay Panel is always visible. While a Host Turn has no Activity, the Activity section is not rendered. After the first Activity appears, the Activity Panel starts collapsed by default. Set
367
+ `FORGERELAY_ACTIVITY_PANEL_EXPANDED=1` to start each new Host Turn expanded once Activity is present. The
368
+ same preference may be persisted as `activityPanelExpanded: true` in
369
+ `~/.forgerelay/config.json`; an explicit environment variable overrides the
370
+ persisted value. The preference is delivered only to the MCP App and does not
371
+ change the Activity snapshot/query contract.
372
+
341
373
  ## Lifecycle hooks
342
374
 
343
375
  Hooks v1 是自动生命周期规则。规则由用户或 Agent 主动写入;命中后 ForgeRelay 直接执行,不再增加批准步骤。
package/docs/debugging.md CHANGED
@@ -13,8 +13,17 @@ npm run dev
13
13
 
14
14
  `npm run debug:serve` is an explicit alias for the same command.
15
15
 
16
- The debug launcher uses [`scripts/debug/config.json`](../scripts/debug/config.json)
17
- and prints the generated Owner password when it starts. It binds only to:
16
+ The interactive debug launcher uses one dedicated persisted configuration at:
17
+
18
+ ```text
19
+ ~/.forgerelay/debug/config.json
20
+ ~/.forgerelay/debug/auth.json
21
+ ```
22
+
23
+ That configuration is independent from the normal `~/.forgerelay` production
24
+ configuration. Keep the debug public URL, allowed Hosts, roots, runtime state,
25
+ and Owner password there instead of relying on launcher-generated overrides. The
26
+ launcher binds according to that config; the standard local debug setup uses:
18
27
 
19
28
  ```text
20
29
  http://127.0.0.1:7677
@@ -29,17 +38,63 @@ http://127.0.0.1:7677/.well-known/oauth-authorization-server
29
38
  http://127.0.0.1:7677/mcp
30
39
  ```
31
40
 
32
- The debug server watches `src/` and restarts after source changes. One generated
33
- Owner password is kept for the lifetime of the launcher so restarts do not force
34
- a new debug credential.
41
+ The debug server watches `src/` and restarts after source changes. Its Owner
42
+ password comes from `~/.forgerelay/debug/auth.json`, so stopping and restarting
43
+ 7677 does not change Host credentials. If the debug endpoint should share the
44
+ production Owner password, copy that value once into the debug `auth.json`; the
45
+ launcher does not synchronize or rotate credentials implicitly.
46
+
47
+ To relocate the entire interactive debug config explicitly, use:
48
+
49
+ ```bash
50
+ FORGERELAY_DEBUG_CONFIG_DIR=/path/to/debug-config npm run dev
51
+ ```
52
+
53
+ ## Run a local MCP Apps Host
35
54
 
36
- To provide a stable local-only Owner password instead of the generated one:
55
+ Use MCP Inspector as the fast local Host for MCP App/resource iteration:
37
56
 
38
57
  ```bash
39
- FORGERELAY_DEBUG_OWNER_TOKEN="local-debug-password-at-least-16-chars" npm run dev
58
+ ./scripts/debug/host/run.sh
40
59
  ```
41
60
 
42
- Do not use that variable for a publicly reachable ForgeRelay deployment.
61
+ This launcher starts two owned processes and stops both when it exits:
62
+
63
+ 1. ForgeRelay on `127.0.0.1:7677`, using the persisted interactive debug Owner password while forcing the advertised public base URL back to loopback and enabling `widgets=full`;
64
+ 2. MCP Inspector Web plus its MCP Apps sandbox, pinned by default to `@modelcontextprotocol/inspector@2.3.0`.
65
+
66
+ The launcher prints and, when supported, opens an Inspector deep link gated by the
67
+ per-run Inspector token. That deep link targets the local ForgeRelay `/mcp`
68
+ endpoint directly, so the browser can complete ForgeRelay OAuth and then inspect
69
+ App tools/resources without a public tunnel or ChatGPT refresh cycle. Inspector
70
+ tokens are redacted from `logs/debug-host-inspector.log`; the ForgeRelay side is
71
+ written to `logs/debug-host-server.log`.
72
+
73
+ The canonical ports are:
74
+
75
+ ```text
76
+ ForgeRelay MCP 7677
77
+ Inspector Web 6274
78
+ Inspector App sandbox 6275
79
+ ```
80
+
81
+ The launcher never kills or silently reuses an existing listener on those ports.
82
+ A temporary ForgeRelay collision can be avoided for an isolated local check with
83
+ `FORGERELAY_DEBUG_HOST_PORT=<port>`; the repository's canonical debug port remains
84
+ `7677`. Inspector ports can similarly be overridden with
85
+ `MCP_INSPECTOR_CLIENT_PORT` and `MCP_INSPECTOR_SANDBOX_PORT`.
86
+
87
+ MCP Inspector v2 requires Node `>=22.19`. On this development setup its Web client
88
+ can crash in the current Node 26 runtime through a native dependency, while Node
89
+ 24 is stable. When the current Node major is 25 or newer, the launcher therefore
90
+ uses the newest installed NVM Node 24 runtime for Inspector when one is available;
91
+ ForgeRelay itself remains on the project's current Node runtime. Override this
92
+ selection explicitly with `MCP_INSPECTOR_NODE_DIR=/path/to/node/bin` when needed.
93
+
94
+ This local Host is the normal fast feedback path for MCP schema, OAuth, resources,
95
+ App rendering, and App-to-server tool calls. It does not replace final ChatGPT Web
96
+ acceptance for ChatGPT-specific iframe lifetime, caching, or Host notification
97
+ behavior.
43
98
 
44
99
  ## Run the end-to-end acceptance
45
100
 
@@ -47,8 +102,10 @@ Do not use that variable for a publicly reachable ForgeRelay deployment.
47
102
  npm run debug:accept
48
103
  ```
49
104
 
50
- The acceptance runner starts its own ForgeRelay process on `127.0.0.1:7677`,
51
- sends real HTTP requests with `curl`, and shuts the server down when it finishes.
105
+ The acceptance runner starts its own fully isolated ForgeRelay fixture on
106
+ `127.0.0.1:7677`, with its own generated Owner password and checked-in debug
107
+ configuration. It sends real HTTP requests with `curl` and shuts the server down
108
+ when it finishes.
52
109
  It refuses to start when port `7677` is already occupied so it cannot
53
110
  accidentally validate an older debug process.
54
111
 
@@ -100,16 +157,17 @@ console.
100
157
 
101
158
  ## Debug configuration
102
159
 
103
- The checked-in debug configuration is:
160
+ The checked-in acceptance-fixture configuration is:
104
161
 
105
162
  ```text
106
163
  scripts/debug/config.json
107
164
  ```
108
165
 
109
- It deliberately contains no Owner password. Runtime secrets are generated by
110
- the launcher and passed through the environment.
166
+ It deliberately contains no Owner password. `debug:accept` generates an isolated
167
+ credential and passes it through the environment. Interactive `debug:serve` does
168
+ not use this fixture config; it uses `~/.forgerelay/debug` instead.
111
169
 
112
- The config enables all Hooks v1 events with the local recorder at:
170
+ The acceptance fixture enables all Hooks v1 events with the local recorder at:
113
171
 
114
172
  ```text
115
173
  scripts/debug/hook-recorder.mjs
@@ -144,9 +202,9 @@ Acceptance runner 每次都会重建自己的 `acceptance/` 子目录。除了
144
202
  The debug workflow is intentionally explicit rather than hidden in ad-hoc shell
145
203
  commands:
146
204
 
147
- - `scripts/debug/config.json` — loopback `7677` configuration and hook setup;
148
- - `scripts/debug/runtime.mjs` — shared paths, generated credentials, and deterministic debug environment;
149
- - `scripts/debug/serve.mjs` — watched local debug server launcher;
205
+ - `scripts/debug/config.json` — isolated acceptance-fixture configuration and hook setup;
206
+ - `scripts/debug/runtime.mjs` — shared paths plus persisted interactive-debug and isolated acceptance environments;
207
+ - `scripts/debug/serve.mjs` — watched 7677 launcher that uses `~/.forgerelay/debug`;
150
208
  - `scripts/debug/accept.mjs` — real HTTP/OAuth/MCP acceptance runner;
151
209
  - `scripts/debug/hook-recorder.mjs` — sanitized JSONL lifecycle recorder.
152
210
 
package/docs/gotchas.md CHANGED
@@ -49,40 +49,46 @@ FORGERELAY_CONFIG_DIR="$HOME/.forgerelay" forgerelay init
49
49
  Do not delete the old directory until you have confirmed which persisted state,
50
50
  worktrees, skills, and profiles you still need.
51
51
 
52
- ## Public URL includes `/mcp`
52
+ ## Public base URL includes `/mcp`
53
53
 
54
- Store the public **origin**:
54
+ Store the public base URL *before* the final `/mcp`. A routed deployment keeps
55
+ its route inside the URL:
55
56
 
56
57
  ```text
57
- https://your-tunnel-host.example.com
58
+ publicBaseUrl: https://your-tunnel-host.example.com/forgerelay/main
58
59
  ```
59
60
 
60
- The MCP client uses:
61
+ The MCP client then uses:
61
62
 
62
63
  ```text
63
- https://your-tunnel-host.example.com/mcp
64
+ https://your-tunnel-host.example.com/forgerelay/main/mcp
64
65
  ```
65
66
 
66
- Fix a persisted URL with:
67
+ Fix persisted routing with:
67
68
 
68
69
  ```bash
69
- forgerelay config set publicBaseUrl https://your-tunnel-host.example.com
70
+ forgerelay config set publicBaseUrl https://your-tunnel-host.example.com/forgerelay/main
70
71
  ```
71
72
 
73
+ Do not include the final `/mcp` in `publicBaseUrl`.
74
+
72
75
  ## Tunnel URL changed
73
76
 
74
77
  For one run:
75
78
 
76
79
  ```bash
77
- FORGERELAY_PUBLIC_BASE_URL="https://new-tunnel.example.com" forgerelay serve
80
+ FORGERELAY_PUBLIC_BASE_URL="https://new-tunnel.example.com/forgerelay/main" forgerelay serve
78
81
  ```
79
82
 
80
83
  For a stable URL:
81
84
 
82
85
  ```bash
83
- forgerelay config set publicBaseUrl https://forge.example.com
86
+ forgerelay config set publicBaseUrl https://forge.example.com/forgerelay/main
84
87
  ```
85
88
 
89
+ When multiple public entries are valid, configure them as a list (or a
90
+ comma-separated environment/CLI value); each entry may use a different route.
91
+
86
92
  ## Host-header or 403 problems
87
93
 
88
94
  Run:
package/docs/setup.md CHANGED
@@ -22,8 +22,8 @@ Run:
22
22
  npx @akira-tl/forgerelay init
23
23
  ```
24
24
 
25
- The setup flow asks for the allowed project roots, local port, and public base
26
- URL.
25
+ The setup flow asks for the allowed project roots, local port, public domains,
26
+ and an optional routed path prefix.
27
27
 
28
28
  ### Project roots
29
29
 
@@ -59,16 +59,23 @@ Point your tunnel or reverse proxy at:
59
59
  http://127.0.0.1:7676
60
60
  ```
61
61
 
62
- Enter the public origin without `/mcp`:
62
+ Enter one or more public base URLs. Each URL may include its own route prefix;
63
+ the first URL is canonical:
63
64
 
64
65
  ```text
65
- https://your-tunnel-host.example.com
66
+ https://your-tunnel-host.example.com/forgerelay/main
66
67
  ```
67
68
 
68
- Configure the MCP client with:
69
+ For multiple public entries, separate them with commas during setup:
69
70
 
70
71
  ```text
71
- https://your-tunnel-host.example.com/mcp
72
+ https://forge.example.com/forgerelay/main, https://forge-alt.example.com/relay
73
+ ```
74
+
75
+ Configure the MCP client with the canonical base URL plus `/mcp`:
76
+
77
+ ```text
78
+ https://your-tunnel-host.example.com/forgerelay/main/mcp
72
79
  ```
73
80
 
74
81
  ## Start the server
@@ -77,17 +84,24 @@ https://your-tunnel-host.example.com/mcp
77
84
  npx @akira-tl/forgerelay serve
78
85
  ```
79
86
 
80
- For a one-run public URL override:
87
+ For a one-run public deployment override:
88
+
89
+ ```bash
90
+ FORGERELAY_PUBLIC_BASE_URL="https://new-tunnel.example.com/forgerelay/main" \
91
+ npx @akira-tl/forgerelay serve
92
+ ```
93
+
94
+ For multiple one-run URLs, use a comma-separated list:
81
95
 
82
96
  ```bash
83
- FORGERELAY_PUBLIC_BASE_URL="https://new-tunnel.example.com" \
97
+ FORGERELAY_PUBLIC_BASE_URL="https://forge.example.com/forgerelay/main,https://forge-alt.example.com/relay" \
84
98
  npx @akira-tl/forgerelay serve
85
99
  ```
86
100
 
87
- For a stable public URL:
101
+ For a stable public deployment:
88
102
 
89
103
  ```bash
90
- npx @akira-tl/forgerelay config set publicBaseUrl https://forge.example.com
104
+ npx @akira-tl/forgerelay config set publicBaseUrl https://forge.example.com/forgerelay/main,https://forge-alt.example.com/relay
91
105
  npx @akira-tl/forgerelay serve
92
106
  ```
93
107
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akira-tl/forgerelay",
3
- "version": "0.5.6",
3
+ "version": "0.6.0",
4
4
  "description": "Local development control plane for MCP coding agents.",
5
5
  "type": "module",
6
6
  "homepage": "https://github.com/Akira-TL/forgerelay#readme",
@@ -44,15 +44,16 @@
44
44
  "release:parity": "node scripts/release-parity.mjs",
45
45
  "postinstall": "node scripts/fix-node-pty-permissions.mjs",
46
46
  "start": "node dist/cli.js serve",
47
- "test": "node --test scripts/release-proof.test.mjs && tsx src/config.test.ts && tsx src/lsp/language-server-config.test.ts && tsx src/lsp/normalization/hover.test.ts && tsx src/lsp/references.server.test.ts && tsx src/lsp/operations/document-symbols.server.test.ts && tsx src/lsp/operations/workspace-symbols.server.test.ts && tsx src/lsp/operations/diagnostics-push.server.test.ts && tsx src/lsp/operations/diagnostics-pull.server.test.ts && tsx src/lsp/operations/request-hardening.server.test.ts && tsx src/lsp/operations/recovery.server.test.ts && tsx src/lsp/operations/lifecycle.server.test.ts && tsx src/lsp/runtime/semantic-requests.test.ts && tsx src/logger.test.ts && tsx src/proxy-trust.test.ts && tsx src/mcp-app-template.test.ts && tsx src/hooks.test.ts && tsx src/capability-registry.test.ts && tsx src/mcp/server-instructions.test.ts && tsx src/request-meta.test.ts && tsx src/incoming-artifacts.test.ts && tsx src/artifact-download.test.ts && tsx src/ui/card-types.test.ts && tsx src/ui/patch-display.test.ts && tsx src/ui/tool-display.test.ts && tsx src/apply-patch.test.ts && tsx src/process-platform.test.ts && tsx src/process-sessions.test.ts && tsx src/mcp-sessions.test.ts && tsx src/server-shutdown.test.ts && tsx src/local-agent-runtime.test.ts && tsx src/local-agent-adapters.test.ts && tsx src/local-agent-availability.test.ts && tsx src/local-agent-profiles.test.ts && tsx src/local-agent-targets.test.ts && tsx src/local-agent-store.test.ts && tsx src/roots.test.ts && tsx src/file-mutations.test.ts && tsx src/operations/edit-preflight.test.ts && tsx src/skills.test.ts && tsx src/db/migrations.test.ts && tsx src/workspace-store.test.ts && tsx src/activity/audit-store.test.ts && tsx src/activity/bash-output-store.test.ts && tsx src/activity/lifecycle.test.ts && tsx src/activity/query-service.test.ts && tsx src/operations/core-operation-executor.test.ts && tsx src/operations/bulk-mutation.test.ts && tsx src/operations/batch/scheduler.test.ts && tsx src/operations/batch/executor-policy.test.ts && tsx src/workspaces.test.ts && tsx src/workspace-conversation.test.ts && tsx src/review-checkpoints.test.ts && tsx src/lsp/code-intelligence.server.test.ts && tsx src/server.test.ts && tsx src/oauth-store.test.ts && tsx src/cli.test.ts",
47
+ "test": "node --test scripts/debug/runtime.test.mjs scripts/release-proof.test.mjs scripts/release/release-gate.test.mjs scripts/release/release-version.test.mjs && tsx src/oauth/router.test.ts && tsx src/config.test.ts && tsx src/lsp/language-server-config.test.ts && tsx src/lsp/normalization/hover.test.ts && tsx src/lsp/references.server.test.ts && tsx src/lsp/operations/document-symbols.server.test.ts && tsx src/lsp/operations/workspace-symbols.server.test.ts && tsx src/lsp/operations/diagnostics-push.server.test.ts && tsx src/lsp/operations/diagnostics-pull.server.test.ts && tsx src/lsp/operations/request-hardening.server.test.ts && tsx src/lsp/operations/recovery.server.test.ts && tsx src/lsp/operations/lifecycle.server.test.ts && tsx src/lsp/runtime/semantic-requests.test.ts && tsx src/logger.test.ts && tsx src/proxy-trust.test.ts && tsx src/mcp-app-template.test.ts && tsx src/hooks.test.ts && tsx src/capability-registry.test.ts && tsx src/mcp/server-instructions.test.ts && tsx src/request-meta.test.ts && tsx src/incoming-artifacts.test.ts && tsx src/artifact-download.test.ts && tsx src/ui/card-types.test.ts && tsx src/ui/workspace-lifecycle-app.test.ts && tsx src/ui/activity/model.test.ts && tsx src/ui/patch-display.test.ts && tsx src/ui/tool-display.test.ts && tsx src/apply-patch.test.ts && tsx src/process-platform.test.ts && tsx src/process-sessions.test.ts && tsx src/mcp-sessions.test.ts && tsx src/server-shutdown.test.ts && tsx src/local-agent-runtime.test.ts && tsx src/local-agent-adapters.test.ts && tsx src/local-agent-availability.test.ts && tsx src/local-agent-profiles.test.ts && tsx src/local-agent-targets.test.ts && tsx src/local-agent-store.test.ts && tsx src/roots.test.ts && tsx src/file-mutations.test.ts && tsx src/operations/edit-preflight.test.ts && tsx src/skills.test.ts && tsx src/db/migrations.test.ts && tsx src/workspace-store.test.ts && tsx src/activity/audit-store.test.ts && tsx src/activity/bash-output-store.test.ts && tsx src/activity/lifecycle.test.ts && tsx src/activity/query-service.test.ts && tsx src/operations/core-operation-executor.test.ts && tsx src/operations/bulk-mutation.test.ts && tsx src/operations/batch/scheduler.test.ts && tsx src/operations/batch/executor-policy.test.ts && tsx src/workspaces.test.ts && tsx src/workspace-conversation.test.ts && tsx src/review-checkpoints.test.ts && tsx src/lsp/code-intelligence.server.test.ts && npm run build:app && tsx src/server.test.ts && tsx src/oauth-store.test.ts && tsx src/cli.test.ts",
48
48
  "typecheck": "tsc -p tsconfig.json --noEmit",
49
49
  "release:check": "node scripts/release-version.mjs check",
50
50
  "release:tag-check": "node scripts/release-version.mjs tag",
51
+ "release:prepare": "node scripts/release-version.mjs prepare",
51
52
  "release:next": "node scripts/release-version.mjs next patch",
52
53
  "release:patch": "node scripts/release-version.mjs next patch",
53
54
  "release:minor": "node scripts/release-version.mjs next minor",
54
55
  "release:major": "node scripts/release-version.mjs next major",
55
- "release:verify": "npm run release:check && npm run typecheck && npm test && npm run build && npm run lsp:interop && npm run release:parity && node scripts/release-proof.mjs write"
56
+ "release:verify": "npm run release:parity && node scripts/release-proof.mjs write"
56
57
  },
57
58
  "keywords": [
58
59
  "mcp",