@akira-tl/forgerelay 0.8.8 → 0.8.9

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 (246) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +10 -18
  3. package/capabilities/host-integration/GUIDE.md +2 -2
  4. package/dist/activity/{audit-store.js → history/audit-store.js} +129 -21
  5. package/dist/activity/history/bash-output-store.js +250 -0
  6. package/dist/activity/{host-turn-store.js → history/host-turn-store.js} +4 -1
  7. package/dist/activity/{query-service.js → history/query-service.js} +13 -7
  8. package/dist/activity/{lifecycle.js → runtime/lifecycle.js} +1 -1
  9. package/dist/activity/{mcp-query-tools.js → runtime/mcp-query-tools.js} +3 -3
  10. package/dist/activity/storage/history.js +12 -0
  11. package/dist/activity/storage/paths.js +56 -0
  12. package/dist/activity/storage/segmented-log.js +149 -0
  13. package/dist/cli/setup-support.js +116 -0
  14. package/dist/cli.js +18 -126
  15. package/dist/lsp/code-intelligence.js +1 -1
  16. package/dist/lsp/test-support/server-fixture.js +9 -9
  17. package/dist/mcp/filesystem/filesystem-tools.js +245 -0
  18. package/dist/mcp/hooks/command-runner.js +79 -0
  19. package/dist/{hook-cli.js → mcp/hooks/hook-cli.js} +1 -1
  20. package/dist/{hooks.js → mcp/hooks/hooks.js} +3 -80
  21. package/dist/{oauth-provider.js → mcp/oauth/oauth-provider.js} +1 -1
  22. package/dist/{oauth-store.js → mcp/oauth/oauth-store.js} +5 -4
  23. package/dist/{operations → mcp/operations}/native-bulk-mutations.js +2 -2
  24. package/dist/mcp/panel/app.js +143 -0
  25. package/dist/{mcp-app-template.js → mcp/panel/mcp-app-template.js} +2 -38
  26. package/dist/mcp/process/runtime.js +257 -0
  27. package/dist/mcp/process/tools.js +346 -0
  28. package/dist/mcp/server/core/activity-support.js +70 -0
  29. package/dist/{capabilities.js → mcp/server/core/capabilities.js} +5 -3
  30. package/dist/{capability-registry.js → mcp/server/core/capability-registry.js} +2 -2
  31. package/dist/mcp/server/core/capability-support.js +90 -0
  32. package/dist/mcp/server/core/schemas.js +216 -0
  33. package/dist/mcp/server/core/tool-support.js +207 -0
  34. package/dist/mcp/server/core/version.js +9 -0
  35. package/dist/mcp/server/operations/runtime/filesystem-tools.js +400 -0
  36. package/dist/mcp/server/operations/runtime/operation-runtime.js +523 -0
  37. package/dist/mcp/server/transport/http-server.js +301 -0
  38. package/dist/mcp/server/transport/http-support.js +43 -0
  39. package/dist/mcp/server/workspace/runtime/workspace-open-presentation.js +222 -0
  40. package/dist/mcp/server/workspace/runtime/workspace-open-schema.js +187 -0
  41. package/dist/mcp/server/workspace/runtime/workspace-open.js +552 -0
  42. package/dist/mcp/server/workspace/runtime/workspace-tools.js +601 -0
  43. package/dist/{config.js → runtime/config/config.js} +3 -3
  44. package/dist/{user-config.js → runtime/config/user-config.js} +14 -54
  45. package/dist/{db → runtime/state/db}/client.js +1 -1
  46. package/dist/{db → runtime/state/db}/migrations.js +34 -3
  47. package/dist/runtime/state/lock/file-lock.js +130 -0
  48. package/dist/runtime/testing/server-fixture.js +190 -0
  49. package/dist/server.js +116 -4202
  50. package/dist/subagents/providers/adapters/claude.js +86 -52
  51. package/dist/subagents/providers/adapters/codex.js +103 -39
  52. package/dist/subagents/providers/adapters/opencode.js +114 -84
  53. package/dist/subagents/providers/adapters/pi.js +59 -8
  54. package/dist/subagents/providers/availability.js +15 -30
  55. package/dist/subagents/providers/runtime/external-command.js +56 -0
  56. package/dist/subagents/sessions/capability.js +1 -1
  57. package/dist/subagents/sessions/execution.js +1 -1
  58. package/dist/subagents/sessions/mcp/activity-audit-test-support.js +30 -0
  59. package/dist/subagents/sessions/store.js +1 -1
  60. package/dist/ui/.vite/manifest.json +342 -410
  61. package/dist/ui/activity-panel-app.html +2 -4
  62. package/dist/ui/assets/activity-panel-app-7Xe0alhm.css +1 -0
  63. package/dist/ui/assets/activity-panel-app-Sl1Jro8v.js +115 -0
  64. package/dist/ui/assets/angular-html-B_yn91wW.js +1 -0
  65. package/dist/ui/assets/{angular-ts-Bxh4-O1-.js → angular-ts-DSgtloKz.js} +1 -1
  66. package/dist/ui/assets/{apl-BmYHKQ6m.js → apl-NatWtF8X.js} +1 -1
  67. package/dist/ui/assets/{astro-C51vqDKq.js → astro-BYFEVBuN.js} +1 -1
  68. package/dist/ui/assets/{blade-CdhVsmwq.js → blade-DoO7yvMR.js} +1 -1
  69. package/dist/ui/assets/c-Rl2hMCcg.js +1 -0
  70. package/dist/ui/assets/{cobol-Cf6azoN_.js → cobol-ByC5mWiB.js} +1 -1
  71. package/dist/ui/assets/{coffee-vVdGzlmt.js → coffee-Dez77Qov.js} +1 -1
  72. package/dist/ui/assets/cpp-DtaAQT9h.js +1 -0
  73. package/dist/ui/assets/{crystal-5UZy6KIX.js → crystal-Bgmbf8ec.js} +1 -1
  74. package/dist/ui/assets/css-C1tjBtVN.js +1 -0
  75. package/dist/ui/assets/{edge-CESgo4ia.js → edge-DeH6u8Wg.js} +1 -1
  76. package/dist/ui/assets/{elixir-9FKfw4cJ.js → elixir-_H3KnmWT.js} +1 -1
  77. package/dist/ui/assets/{elm-Dv7A0aLa.js → elm-CsCe3U28.js} +1 -1
  78. package/dist/ui/assets/{erb-DHFmDvM0.js → erb-CbM-L2g8.js} +1 -1
  79. package/dist/ui/assets/{git-rebase-utbU6CzV.js → git-rebase-D0s5pDh9.js} +1 -1
  80. package/dist/ui/assets/{glimmer-js-t2kiCkyB.js → glimmer-js-BfOToq_A.js} +1 -1
  81. package/dist/ui/assets/{glimmer-ts-F0Jv5okV.js → glimmer-ts-CCUOkL2K.js} +1 -1
  82. package/dist/ui/assets/glsl-DH4ec9dE.js +1 -0
  83. package/dist/ui/assets/graphql-DilAMBoI.js +1 -0
  84. package/dist/ui/assets/{hack-8yjdbaSA.js → hack-BDkNDZlF.js} +1 -1
  85. package/dist/ui/assets/haml-D_QBp6K7.js +1 -0
  86. package/dist/ui/assets/{handlebars-BBFEg4Lo.js → handlebars-DePUrTpC.js} +1 -1
  87. package/dist/ui/assets/heavy-payload-DOwZpO6n.js +290 -0
  88. package/dist/ui/assets/html-By4dNnM4.js +1 -0
  89. package/dist/ui/assets/{html-derivative-DJAQcZyc.js → html-derivative-DDw9Ef4Q.js} +1 -1
  90. package/dist/ui/assets/{http-Dg5LSYRK.js → http-B0QxWc9M.js} +1 -1
  91. package/dist/ui/assets/{hurl-Y5uYzMZR.js → hurl-vMQ4lda1.js} +1 -1
  92. package/dist/ui/assets/java-DYRe2lWG.js +1 -0
  93. package/dist/ui/assets/javascript-CxyGqwcL.js +1 -0
  94. package/dist/ui/assets/{jinja-Bt30h8Ik.js → jinja-JUwV-fZt.js} +1 -1
  95. package/dist/ui/assets/{jison-D5uZ1Nyo.js → jison-7ZqCEvS8.js} +1 -1
  96. package/dist/ui/assets/json-dbltgiiA.js +1 -0
  97. package/dist/ui/assets/jsx-oDopT7YQ.js +1 -0
  98. package/dist/ui/assets/{julia-76hRaaGz.js → julia-CkKiNSav.js} +1 -1
  99. package/dist/ui/assets/{just-CDE7W0vW.js → just-DuqCAKJ3.js} +1 -1
  100. package/dist/ui/assets/{latex-CVO2Byab.js → latex-sudcRDSn.js} +1 -1
  101. package/dist/ui/assets/{liquid-CA-AS3EX.js → liquid-Di-08Js7.js} +1 -1
  102. package/dist/ui/assets/lua-YlqdMoV0.js +1 -0
  103. package/dist/ui/assets/{marko-_BWrPfny.js → marko-CJRNyJDb.js} +1 -1
  104. package/dist/ui/assets/{mdc-PyJv85eS.js → mdc-t12CzZHs.js} +1 -1
  105. package/dist/ui/assets/{nginx-DAWVw8yu.js → nginx-57-b4XwT.js} +1 -1
  106. package/dist/ui/assets/{nim-CKE1dzpU.js → nim-BzrswYQa.js} +1 -1
  107. package/dist/ui/assets/{perl-BBhWva19.js → perl-D9JR_iIh.js} +1 -1
  108. package/dist/ui/assets/{php-ChIeaAoF.js → php-Py2gFHil.js} +1 -1
  109. package/dist/ui/assets/{pug-CMgI5afi.js → pug-PzLLy0h1.js} +1 -1
  110. package/dist/ui/assets/{qml-CjxTkcFH.js → qml-By8fwgV4.js} +1 -1
  111. package/dist/ui/assets/r-CcezTbLq.js +1 -0
  112. package/dist/ui/assets/{razor-i4DbHr8p.js → razor-dG-vdhL_.js} +1 -1
  113. package/dist/ui/assets/regexp-BlsQ-N_8.js +1 -0
  114. package/dist/ui/assets/{rst-oy_97Kl4.js → rst-C2awDCat.js} +1 -1
  115. package/dist/ui/assets/{ruby-C5zYZIyl.js → ruby-zA2W_49d.js} +1 -1
  116. package/dist/ui/assets/{sas-BnMEh2S3.js → sas-D49bhyaN.js} +1 -1
  117. package/dist/ui/assets/scss-BQb-cp01.js +1 -0
  118. package/dist/ui/assets/shellscript-Dga4H_Ni.js +1 -0
  119. package/dist/ui/assets/{shellsession-BpE5o7_3.js → shellsession-n3-5CqcF.js} +1 -1
  120. package/dist/ui/assets/{soy-COesmhTY.js → soy-XYBOf_BA.js} +1 -1
  121. package/dist/ui/assets/sql-ET4u5Cpl.js +1 -0
  122. package/dist/ui/assets/{stata-CGQEuSZq.js → stata-CLHcJHO_.js} +1 -1
  123. package/dist/ui/assets/{surrealql-Bz4JbU-9.js → surrealql-BdjQ60T4.js} +1 -1
  124. package/dist/ui/assets/{svelte-1jM2ejXj.js → svelte-B2RPtKJe.js} +1 -1
  125. package/dist/ui/assets/{templ-C-VwELcp.js → templ-CrByPW_W.js} +1 -1
  126. package/dist/ui/assets/{tex-t1rUiQCm.js → tex-DZBkg363.js} +1 -1
  127. package/dist/ui/assets/{ts-tags-Bewoa6pS.js → ts-tags-DJR3Gphb.js} +1 -1
  128. package/dist/ui/assets/tsx-CajzROyy.js +1 -0
  129. package/dist/ui/assets/{twig-DVg-vELl.js → twig-BZjk5Zda.js} +1 -1
  130. package/dist/ui/assets/typescript-B-EWToLj.js +1 -0
  131. package/dist/ui/assets/{vue-wPQ7UlMy.js → vue-D_rHCCr8.js} +1 -1
  132. package/dist/ui/assets/{vue-html-BHtJ8geX.js → vue-html-CC4WlvVt.js} +1 -1
  133. package/dist/ui/assets/{vue-vine-CNSGAWwc.js → vue-vine-BgNMVgpk.js} +1 -1
  134. package/dist/ui/assets/xml-BI86-WbH.js +1 -0
  135. package/dist/ui/assets/{xsl-3_vJ27aE.js → xsl-DXeLZV4J.js} +1 -1
  136. package/dist/ui/assets/yaml-60_PFlWa.js +1 -0
  137. package/dist/workspaces/bootstrap.js +72 -0
  138. package/dist/workspaces/context.js +302 -0
  139. package/dist/workspaces/conversation-test-support.js +86 -0
  140. package/dist/{git-worktrees.js → workspaces/git/git-worktrees.js} +1 -1
  141. package/dist/workspaces/inventory.js +131 -0
  142. package/dist/workspaces/paths.js +55 -0
  143. package/dist/{remote-auth.js → workspaces/relay/auth/remote-auth.js} +2 -2
  144. package/dist/workspaces/relay/result-support.js +111 -0
  145. package/dist/workspaces/relay/tests/test-support.js +203 -0
  146. package/dist/{remote-mcp-connection-pool.js → workspaces/relay/transport/remote-mcp-connection-pool.js} +1 -1
  147. package/dist/workspaces/relay/types.js +1 -0
  148. package/dist/{remote-workspace-relay.js → workspaces/relay/workspace-relay.js} +23 -172
  149. package/dist/workspaces/resources/skills.js +285 -0
  150. package/dist/{review-checkpoints.js → workspaces/review/review-checkpoints.js} +2 -2
  151. package/dist/workspaces/sessions.js +457 -0
  152. package/dist/{workspace-store.js → workspaces/state/workspace-store.js} +2 -2
  153. package/dist/workspaces.js +68 -995
  154. package/docs/chatgpt-coding-workflow.md +3 -11
  155. package/docs/configuration.md +12 -25
  156. package/docs/gotchas.md +0 -30
  157. package/docs/roadmap.md +6 -10
  158. package/docs/security.md +1 -5
  159. package/docs/setup.md +0 -11
  160. package/package.json +6 -8
  161. package/scripts/ci/architecture.mjs +109 -0
  162. package/scripts/ci/verify.mjs +5 -0
  163. package/scripts/debug/accept/bootstrap.mjs +326 -0
  164. package/scripts/debug/accept/harness.mjs +76 -0
  165. package/scripts/debug/accept/support.mjs +432 -0
  166. package/scripts/debug/accept.mjs +43 -806
  167. package/scripts/debug/relay-accept/support.mjs +135 -0
  168. package/scripts/debug/relay-accept.mjs +26 -115
  169. package/scripts/debug/traffic/support.mjs +167 -0
  170. package/scripts/debug/traffic/traffic-audit.mjs +4 -161
  171. package/scripts/{lsp-interop-support.test.mjs → lsp/interop-support.test.mjs} +1 -1
  172. package/scripts/{lsp-interop.mjs → lsp/interop.mjs} +3 -3
  173. package/scripts/wiki/sync.mjs +21 -10
  174. package/dist/activity/bash-output-store.js +0 -127
  175. package/dist/pi-tools.js +0 -110
  176. package/dist/skills.js +0 -127
  177. package/dist/ui/assets/activity-panel-app-7AckaxIR.js +0 -2
  178. package/dist/ui/assets/angular-html-BkgDQl-G.js +0 -1
  179. package/dist/ui/assets/c-IBzBpxAO.js +0 -1
  180. package/dist/ui/assets/chunk-EyZ2wyi3.js +0 -1
  181. package/dist/ui/assets/cpp-CVHeO-Jk.js +0 -1
  182. package/dist/ui/assets/css-DEfus9J5.js +0 -1
  183. package/dist/ui/assets/glsl-_ooCjaeB.js +0 -1
  184. package/dist/ui/assets/graphql-B9LqP-cY.js +0 -1
  185. package/dist/ui/assets/haml-BU5EoZBn.js +0 -1
  186. package/dist/ui/assets/heavy-payload-Bol1_mcs.js +0 -4
  187. package/dist/ui/assets/html-D-C6YZk4.js +0 -1
  188. package/dist/ui/assets/java-ppHvycj5.js +0 -1
  189. package/dist/ui/assets/javascript-DDTjKLlQ.js +0 -1
  190. package/dist/ui/assets/json-Cw91r8h1.js +0 -1
  191. package/dist/ui/assets/jsx-04X2FT_1.js +0 -1
  192. package/dist/ui/assets/lua-CiyBp52Y.js +0 -1
  193. package/dist/ui/assets/r-DfFga4si.js +0 -1
  194. package/dist/ui/assets/regexp-iC9_nbSI.js +0 -1
  195. package/dist/ui/assets/review-payload-BqJp0c5e.js +0 -1
  196. package/dist/ui/assets/scrollbar-CvE-I-jG.js +0 -287
  197. package/dist/ui/assets/scss-BfZXsAWQ.js +0 -1
  198. package/dist/ui/assets/shellscript-BC2srNaB.js +0 -1
  199. package/dist/ui/assets/sql-Ccv_yeUm.js +0 -1
  200. package/dist/ui/assets/tsx-CTXzrBkN.js +0 -1
  201. package/dist/ui/assets/typescript--ElHoFkw.js +0 -1
  202. package/dist/ui/assets/workspace-app-BLW7p6IZ.js +0 -114
  203. package/dist/ui/assets/workspace-app-BjNqR0en.js +0 -1
  204. package/dist/ui/assets/workspace-app-CmaYU4DW.js +0 -3
  205. package/dist/ui/assets/workspace-app-D2bJ5fjt.css +0 -1
  206. package/dist/ui/assets/workspace-lifecycle-app-BVbI2Ilf.js +0 -1
  207. package/dist/ui/assets/xml-JnmX6vyS.js +0 -1
  208. package/dist/ui/assets/yaml-OAcZkP-w.js +0 -1
  209. package/dist/ui/workspace-app.html +0 -18
  210. package/dist/ui/workspace-lifecycle-app.html +0 -18
  211. package/docs/agent-profile-schema.md +0 -114
  212. package/docs/artifact-exchange.md +0 -65
  213. package/docs/versioning.md +0 -205
  214. /package/capabilities/{managed-worktrees → workspace/managed-worktrees}/GUIDE.md +0 -0
  215. /package/capabilities/{workspace-tasks → workspace/workspace-tasks}/GUIDE.md +0 -0
  216. /package/dist/activity/{process-output-audit.js → runtime/process-output-audit.js} +0 -0
  217. /package/dist/{artifact-error.js → mcp/artifacts/artifact-error.js} +0 -0
  218. /package/dist/{artifact-tools.js → mcp/artifacts/artifact-tools.js} +0 -0
  219. /package/dist/{incoming-artifacts.js → mcp/artifacts/incoming-artifacts.js} +0 -0
  220. /package/dist/{advertised-files.js → mcp/filesystem/advertised-files.js} +0 -0
  221. /package/dist/{apply-patch.js → mcp/filesystem/apply-patch.js} +0 -0
  222. /package/dist/{file-mutations.js → mcp/filesystem/file-mutations.js} +0 -0
  223. /package/dist/{roots.js → mcp/filesystem/roots.js} +0 -0
  224. /package/dist/{oauth → mcp/oauth}/public-url.js +0 -0
  225. /package/dist/{oauth → mcp/oauth}/router.js +0 -0
  226. /package/dist/{operations → mcp/operations}/batch/executor.js +0 -0
  227. /package/dist/{operations → mcp/operations}/batch/scheduler.js +0 -0
  228. /package/dist/{operations → mcp/operations}/batch/types.js +0 -0
  229. /package/dist/{operations → mcp/operations}/bulk-mutation.js +0 -0
  230. /package/dist/{operations → mcp/operations}/bulk-read.js +0 -0
  231. /package/dist/{operations → mcp/operations}/core-operation-executor.js +0 -0
  232. /package/dist/{process-platform.js → mcp/process/process-platform.js} +0 -0
  233. /package/dist/{process-sessions.js → mcp/process/process-sessions.js} +0 -0
  234. /package/dist/{request-meta.js → mcp/request-meta.js} +0 -0
  235. /package/dist/{mcp-sessions.js → mcp/server/transport/mcp-sessions.js} +0 -0
  236. /package/dist/{server-shutdown.js → mcp/server/transport/server-shutdown.js} +0 -0
  237. /package/dist/{logger.js → runtime/logging/logger.js} +0 -0
  238. /package/dist/{db → runtime/state/db}/schema.js +0 -0
  239. /package/dist/{composite-activity.js → workspaces/composite/composite-activity.js} +0 -0
  240. /package/dist/{composite-workspaces.js → workspaces/composite/composite-workspaces.js} +0 -0
  241. /package/dist/{git.js → workspaces/git/git.js} +0 -0
  242. /package/dist/{workspace-presentation.js → workspaces/presentation/workspace-presentation.js} +0 -0
  243. /package/dist/{remote-transport.js → workspaces/relay/transport/remote-transport.js} +0 -0
  244. /package/dist/{workspace-task-reminders.js → workspaces/tasks/workspace-task-reminders.js} +0 -0
  245. /package/dist/{workspace-tasks.js → workspaces/tasks/workspace-tasks.js} +0 -0
  246. /package/scripts/{lsp-interop-support.mjs → lsp/interop-support.mjs} +0 -0
@@ -0,0 +1,70 @@
1
+ import { runToolWithHooks } from "../../hooks/hooks.js";
2
+ import { toolResultIsError } from "./tool-support.js";
3
+ export function workspaceActivitySnapshot(workspace) {
4
+ return {
5
+ id: workspace.id,
6
+ root: workspace.root,
7
+ mode: workspace.mode,
8
+ ...(workspace.sourceRoot ? { sourceRoot: workspace.sourceRoot } : {}),
9
+ ...(workspace.worktree?.branch ? { branch: workspace.worktree.branch } : {}),
10
+ ...(workspace.worktree?.targetBranch ? { targetBranch: workspace.worktree.targetBranch } : {}),
11
+ };
12
+ }
13
+ export function activityFailureMessage(result) {
14
+ if (typeof result !== "object" || result === null)
15
+ return "Tool returned a failed result.";
16
+ const record = result;
17
+ if (Array.isArray(record.content)) {
18
+ const text = record.content
19
+ .map((entry) => {
20
+ if (typeof entry !== "object" || entry === null)
21
+ return "";
22
+ const value = entry.text;
23
+ return typeof value === "string" ? value : "";
24
+ })
25
+ .filter(Boolean)
26
+ .join("\n");
27
+ if (text)
28
+ return text;
29
+ }
30
+ if (typeof record.structuredContent === "object" && record.structuredContent !== null) {
31
+ const value = record.structuredContent.result;
32
+ if (typeof value === "string" && value)
33
+ return value;
34
+ }
35
+ return "Tool returned a failed result.";
36
+ }
37
+ export function standardActivityOutcome(result) {
38
+ return toolResultIsError(result)
39
+ ? { type: "failed", error: activityFailureMessage(result) }
40
+ : { type: "succeeded" };
41
+ }
42
+ export function activityRelationFor(context) {
43
+ return {
44
+ ...(context.parentActivityId ? { parentActivityId: context.parentActivityId } : {}),
45
+ ...(context.turnId ? { turnId: context.turnId } : {}),
46
+ };
47
+ }
48
+ export function activityRequestFor(input, context) {
49
+ if (!context.activityMember || !input || typeof input !== "object" || Array.isArray(input))
50
+ return input;
51
+ return {
52
+ ...input,
53
+ member: context.activityMember,
54
+ };
55
+ }
56
+ export function runActivityTool(lifecycle, workspace, conversationScopeId, tool, request, operation, outcome = standardActivityOutcome, relation = {}, auditResult) {
57
+ return lifecycle.run({
58
+ tool,
59
+ workspace: workspaceActivitySnapshot(workspace),
60
+ conversationScopeId,
61
+ request,
62
+ operation,
63
+ outcome,
64
+ ...(auditResult ? { auditResult } : {}),
65
+ ...relation,
66
+ });
67
+ }
68
+ export function runActivityToolWithHooks(lifecycle, hooks, workspace, conversationScopeId, request, hookOptions, relation = {}) {
69
+ return runActivityTool(lifecycle, workspace, conversationScopeId, hookOptions.tool, request, () => runToolWithHooks(hooks, hookOptions), standardActivityOutcome, relation);
70
+ }
@@ -1,6 +1,6 @@
1
1
  import { join } from "node:path";
2
2
  import { fileURLToPath } from "node:url";
3
- import { markAdvertisedFileSourceActivated, resolveAdvertisedFileReadPath, } from "./advertised-files.js";
3
+ import { markAdvertisedFileSourceActivated, resolveAdvertisedFileReadPath, } from "../../filesystem/advertised-files.js";
4
4
  const CAPABILITY_GUIDE_DEFINITIONS = [
5
5
  {
6
6
  name: "lifecycle-hooks",
@@ -9,6 +9,7 @@ const CAPABILITY_GUIDE_DEFINITIONS = [
9
9
  },
10
10
  {
11
11
  name: "managed-worktrees",
12
+ directory: "workspace/managed-worktrees",
12
13
  description: "Managed-worktree lifecycle, close safety, and recovery.",
13
14
  whenToRead: "Read for advanced mode=\"worktree\" flows.",
14
15
  },
@@ -41,6 +42,7 @@ const CAPABILITY_GUIDE_DEFINITIONS = [
41
42
  },
42
43
  {
43
44
  name: "workspace-tasks",
45
+ directory: "workspace/workspace-tasks",
44
46
  description: "Persistent Task Lists owned by the current Workspace.",
45
47
  whenToRead: "Read before creating or maintaining Workspace Tasks.",
46
48
  },
@@ -52,14 +54,14 @@ const CAPABILITY_GUIDE_DEFINITIONS = [
52
54
  },
53
55
  ];
54
56
  function capabilityGuidesDir() {
55
- return fileURLToPath(new URL("../capabilities", import.meta.url));
57
+ return fileURLToPath(new URL("../../../../capabilities", import.meta.url));
56
58
  }
57
59
  export function loadCapabilityGuides(config) {
58
60
  const root = capabilityGuidesDir();
59
61
  return CAPABILITY_GUIDE_DEFINITIONS
60
62
  .filter((definition) => definition.enabled?.(config) ?? true)
61
63
  .map((definition) => {
62
- const baseDir = join(root, definition.name);
64
+ const baseDir = join(root, definition.directory ?? definition.name);
63
65
  return {
64
66
  name: definition.name,
65
67
  description: definition.description,
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
- import { MAX_CODE_INTELLIGENCE_RESULT_LIMIT, } from "./lsp/code-intelligence-types.js";
3
- import { batchExecuteInputSchema, } from "./operations/batch/types.js";
2
+ import { MAX_CODE_INTELLIGENCE_RESULT_LIMIT, } from "../../../lsp/code-intelligence-types.js";
3
+ import { batchExecuteInputSchema, } from "../../operations/batch/types.js";
4
4
  export class CapabilityError extends Error {
5
5
  code;
6
6
  constructor(code, message) {
@@ -0,0 +1,90 @@
1
+ import { CapabilityError } from "./capability-registry.js";
2
+ import { formatPathForPrompt } from "../../../workspaces/resources/skills.js";
3
+ export function workspaceHookInvocation(workspace) {
4
+ return {
5
+ workspaceId: workspace.id,
6
+ workspaceRoot: workspace.root,
7
+ workspaceMode: workspace.mode,
8
+ sourceRoot: workspace.sourceRoot,
9
+ };
10
+ }
11
+ export function capabilityContextFor(workspace) {
12
+ return {
13
+ workspaceId: workspace.id,
14
+ workspaceKind: "workspace",
15
+ workspaceRoot: workspace.root,
16
+ guides: workspace.capabilityGuides.map((guide) => ({
17
+ name: guide.name,
18
+ description: guide.description,
19
+ whenToRead: guide.whenToRead,
20
+ path: formatPathForPrompt(guide.filePath),
21
+ })),
22
+ };
23
+ }
24
+ export function compositeCapabilityContext(workspaceId, guides) {
25
+ return {
26
+ workspaceId,
27
+ workspaceKind: "composite",
28
+ guides: guides.map((guide) => ({
29
+ name: guide.name,
30
+ description: guide.description,
31
+ whenToRead: guide.whenToRead,
32
+ path: formatPathForPrompt(guide.filePath),
33
+ })),
34
+ };
35
+ }
36
+ export function requireCapabilityWorkspaceRoot(context) {
37
+ if (!context.workspaceRoot) {
38
+ throw new CapabilityError("capability_unavailable", `Capability execution requires a filesystem-backed Workspace; ${context.workspaceId} is ${context.workspaceKind}.`);
39
+ }
40
+ return context.workspaceRoot;
41
+ }
42
+ export function runWorkspaceTasksCapability(store, workspaceId, input) {
43
+ switch (input.operation) {
44
+ case "get":
45
+ if (input.level === "headers")
46
+ return store.readHeaders(workspaceId, input.listId);
47
+ if (input.level === "detail")
48
+ return store.readTaskDetail(workspaceId, input.listId, input.taskId);
49
+ return store.readSummary(workspaceId);
50
+ case "list.create":
51
+ store.createList(workspaceId, { name: input.name, position: input.position });
52
+ return store.readSummary(workspaceId);
53
+ case "list.update":
54
+ store.updateList(workspaceId, input.listId, {
55
+ name: input.name,
56
+ state: input.state,
57
+ position: input.position,
58
+ });
59
+ return store.readSummary(workspaceId);
60
+ case "list.delete":
61
+ store.deleteList(workspaceId, input.listId);
62
+ return store.readSummary(workspaceId);
63
+ case "task.create":
64
+ store.createTask(workspaceId, input.listId, {
65
+ subject: input.subject,
66
+ content: input.content,
67
+ status: input.status,
68
+ position: input.position,
69
+ });
70
+ return store.readHeaders(workspaceId, input.listId);
71
+ case "task.update":
72
+ store.updateTask(workspaceId, input.listId, input.taskId, {
73
+ subject: input.subject,
74
+ content: input.content,
75
+ status: input.status,
76
+ position: input.position,
77
+ });
78
+ return store.readHeaders(workspaceId, input.listId);
79
+ case "task.delete":
80
+ store.deleteTask(workspaceId, input.listId, input.taskId);
81
+ return store.readHeaders(workspaceId, input.listId);
82
+ }
83
+ }
84
+ export async function reviewWorkspaceChanges(reviewCheckpoints, workspace) {
85
+ return reviewCheckpoints.reviewChanges({
86
+ workspaceId: workspace.id,
87
+ root: workspace.root,
88
+ markReviewed: true,
89
+ });
90
+ }
@@ -0,0 +1,216 @@
1
+ import * as z from "zod/v4";
2
+ export function resultOutputSchema(extra = {}) {
3
+ return {
4
+ result: z
5
+ .string()
6
+ .describe("Model-readable result text for follow-up reasoning and plain MCP hosts."),
7
+ ...extra,
8
+ };
9
+ }
10
+ export const workspaceSkillOutputSchema = z.object({
11
+ name: z.string(),
12
+ description: z.string(),
13
+ });
14
+ export const workspaceSkillDiagnosticOutputSchema = z.object({
15
+ type: z.enum(["warning", "error", "collision"]),
16
+ message: z.string(),
17
+ collision: z.object({
18
+ resourceType: z.enum(["extension", "skill", "prompt", "theme"]),
19
+ name: z.string(),
20
+ }).optional(),
21
+ });
22
+ export function redactSkillDiagnosticPaths(diagnostics) {
23
+ return diagnostics.map((diagnostic) => {
24
+ let message = diagnostic.message;
25
+ const hiddenPaths = [
26
+ diagnostic.path,
27
+ diagnostic.collision?.winnerPath,
28
+ diagnostic.collision?.loserPath,
29
+ ].filter((path) => Boolean(path));
30
+ for (const path of hiddenPaths) {
31
+ message = message.split(path).join("<skill-path>");
32
+ }
33
+ return {
34
+ type: diagnostic.type,
35
+ message,
36
+ ...(diagnostic.collision
37
+ ? {
38
+ collision: {
39
+ resourceType: diagnostic.collision.resourceType,
40
+ name: diagnostic.collision.name,
41
+ },
42
+ }
43
+ : {}),
44
+ };
45
+ });
46
+ }
47
+ export const capabilityFingerprintOutputSchema = z.object({
48
+ version: z.string(),
49
+ toolMode: z.enum(["minimal", "full", "codex"]),
50
+ capabilities: z.array(z.string()),
51
+ });
52
+ export const capabilityGuideOutputSchema = z.object({
53
+ name: z.string(),
54
+ description: z.string(),
55
+ whenToRead: z.string(),
56
+ path: z.string(),
57
+ });
58
+ export const capabilityCatalogGuideOutputSchema = z.object({
59
+ name: z.string(),
60
+ path: z.string(),
61
+ readBeforeFirstUse: z.boolean(),
62
+ });
63
+ export const capabilityCatalogOutputSchema = z.object({
64
+ name: z.string(),
65
+ description: z.string(),
66
+ available: z.boolean(),
67
+ unavailableReason: z.string().optional(),
68
+ batchPolicy: z.enum(["parallel", "serial", "unsupported"]),
69
+ guide: capabilityCatalogGuideOutputSchema,
70
+ });
71
+ export const capabilityErrorOutputSchema = z.object({
72
+ code: z.string(),
73
+ message: z.string(),
74
+ });
75
+ export const workspaceAgentsFileOutputSchema = z.object({
76
+ path: z.string(),
77
+ content: z.string(),
78
+ });
79
+ export const workspaceLocalAgentOutputSchema = z.object({
80
+ name: z.string(),
81
+ description: z.string(),
82
+ provider: z.string(),
83
+ model: z.string().optional(),
84
+ thinking: z.string().optional(),
85
+ providerAvailable: z.boolean().optional(),
86
+ providerUnavailableReason: z.string().optional(),
87
+ });
88
+ export const workspaceSubagentProviderOutputSchema = z.object({
89
+ name: z.string(),
90
+ available: z.boolean(),
91
+ continuationSupported: z.boolean(),
92
+ reason: z.string().optional(),
93
+ });
94
+ export const workspaceAvailableAgentsFileOutputSchema = z.object({
95
+ path: z.string(),
96
+ });
97
+ export const workspaceInventoryEntryOutputSchema = z.object({
98
+ label: z.string(),
99
+ workspaceId: z.string(),
100
+ root: z.string(),
101
+ status: z.string(),
102
+ state: z.enum(["active", "stale", "invalid", "closed"]),
103
+ mode: z.enum(["checkout", "worktree"]),
104
+ sourceRoot: z.string().optional(),
105
+ branch: z.string().optional(),
106
+ targetBranch: z.string().optional(),
107
+ managed: z.boolean(),
108
+ createdAt: z.string(),
109
+ lastUsedAt: z.string(),
110
+ idleMs: z.number().nonnegative(),
111
+ rootValid: z.boolean(),
112
+ current: z.boolean(),
113
+ });
114
+ export const workspaceInventorySummaryOutputSchema = z.object({
115
+ total: z.number().int().nonnegative(),
116
+ matching: z.number().int().nonnegative(),
117
+ active: z.number().int().nonnegative(),
118
+ stale: z.number().int().nonnegative(),
119
+ invalid: z.number().int().nonnegative(),
120
+ closed: z.number().int().nonnegative(),
121
+ });
122
+ export const workspaceInventoryPageOutputSchema = z.object({
123
+ offset: z.number().int().nonnegative(),
124
+ limit: z.number().int().positive(),
125
+ hasMore: z.boolean(),
126
+ });
127
+ export const workspaceTaskInspectionSummaryOutputSchema = z.object({
128
+ level: z.literal("summary"),
129
+ version: z.literal(1),
130
+ revision: z.number().int().nonnegative(),
131
+ lists: z.array(z.object({
132
+ id: z.string(),
133
+ name: z.string(),
134
+ state: z.enum(["active", "archived"]),
135
+ revision: z.number().int().positive(),
136
+ taskCount: z.number().int().nonnegative(),
137
+ unfinishedTaskCount: z.number().int().nonnegative(),
138
+ })),
139
+ });
140
+ export const workspaceInspectionMemberOutputSchema = z.object({
141
+ name: z.string(),
142
+ purpose: z.string(),
143
+ workspaceId: z.string(),
144
+ known: z.boolean(),
145
+ location: z.enum(["local", "relay"]).optional(),
146
+ state: z.enum(["active", "stale", "invalid", "closed"]).optional(),
147
+ status: z.string().optional(),
148
+ routeState: z.literal("known").optional(),
149
+ mode: z.enum(["checkout", "worktree"]).optional(),
150
+ rootValid: z.boolean().optional(),
151
+ });
152
+ export const workspaceInspectionOutputSchema = z.union([
153
+ z.object({
154
+ workspaceId: z.string(),
155
+ kind: z.literal("workspace"),
156
+ location: z.literal("local"),
157
+ label: z.string(),
158
+ root: z.string(),
159
+ status: z.string(),
160
+ state: z.enum(["active", "stale", "invalid", "closed"]),
161
+ mode: z.enum(["checkout", "worktree"]),
162
+ sourceRoot: z.string().optional(),
163
+ branch: z.string().optional(),
164
+ targetBranch: z.string().optional(),
165
+ managed: z.boolean(),
166
+ createdAt: z.string(),
167
+ lastUsedAt: z.string(),
168
+ idleMs: z.number().nonnegative(),
169
+ rootValid: z.boolean(),
170
+ taskSummary: workspaceTaskInspectionSummaryOutputSchema.optional(),
171
+ }),
172
+ z.object({
173
+ workspaceId: z.string(),
174
+ kind: z.literal("workspace"),
175
+ location: z.literal("relay"),
176
+ root: z.string(),
177
+ routeState: z.literal("known"),
178
+ status: z.string().optional(),
179
+ state: z.enum(["active", "stale", "invalid", "closed"]).optional(),
180
+ mode: z.enum(["checkout", "worktree"]),
181
+ sourceRoot: z.string().optional(),
182
+ branch: z.string().optional(),
183
+ targetBranch: z.string().optional(),
184
+ managed: z.boolean().optional(),
185
+ createdAt: z.string().optional(),
186
+ lastUsedAt: z.string().optional(),
187
+ idleMs: z.number().nonnegative().optional(),
188
+ rootValid: z.boolean().optional(),
189
+ taskSummary: workspaceTaskInspectionSummaryOutputSchema.optional(),
190
+ relay: z.string(),
191
+ executionLocation: z.string(),
192
+ }),
193
+ z.object({
194
+ workspaceId: z.string(),
195
+ kind: z.literal("composite"),
196
+ name: z.string(),
197
+ status: z.enum(["active", "closed"]),
198
+ state: z.enum(["active", "closed"]),
199
+ createdAt: z.string(),
200
+ lastUsedAt: z.string(),
201
+ members: z.array(workspaceInspectionMemberOutputSchema),
202
+ taskSummary: workspaceTaskInspectionSummaryOutputSchema.optional(),
203
+ }),
204
+ ]);
205
+ export const reviewFileOutputSchema = z.object({
206
+ path: z.string(),
207
+ previousPath: z.string().optional(),
208
+ type: z.enum(["change", "rename-pure", "rename-changed", "new", "deleted"]),
209
+ additions: z.number(),
210
+ removals: z.number(),
211
+ });
212
+ export const reviewSummaryOutputSchema = z.object({
213
+ files: z.number(),
214
+ additions: z.number(),
215
+ removals: z.number(),
216
+ });
@@ -0,0 +1,207 @@
1
+ import { resolve } from "node:path";
2
+ import { commandPreview, logEvent, workspaceLogLabel } from "../../../runtime/logging/logger.js";
3
+ import { formatAgentsPath } from "../../../workspaces.js";
4
+ export function workspaceLogContext(workspace, _transportSessionId) {
5
+ return {
6
+ workspaceId: workspace.id,
7
+ workspace: workspaceLogLabel(workspace.root, workspace.id),
8
+ };
9
+ }
10
+ export function formatDiscoveredWorkspaceInstructions(files, workspaceRoot) {
11
+ return [
12
+ "Workspace instructions discovered for this path. Apply them to follow-up work under their directories:",
13
+ ...files.flatMap((file) => [
14
+ `--- ${formatAgentsPath(file.path, workspaceRoot)} ---`,
15
+ file.content.trimEnd(),
16
+ ]),
17
+ ].join("\n");
18
+ }
19
+ export async function assertWorkspaceInstructionsLoadedBeforeSideEffect(workspaces, workspace, paths) {
20
+ const discovered = new Map();
21
+ for (const path of paths) {
22
+ const absolutePath = resolve(workspace.root, path);
23
+ for (const file of await workspaces.discoverPathInstructions(workspace, absolutePath)) {
24
+ discovered.set(file.path, file);
25
+ }
26
+ }
27
+ if (discovered.size === 0)
28
+ return;
29
+ throw new Error([
30
+ formatDiscoveredWorkspaceInstructions([...discovered.values()], workspace.root),
31
+ "Apply these instructions, then retry this tool call. No mutation or command was executed.",
32
+ ].join("\n"));
33
+ }
34
+ export function logToolCall(config, fields) {
35
+ if (!config.logging.toolCalls)
36
+ return;
37
+ const { command, ...safeFields } = fields;
38
+ logEvent(config.logging, fields.success ? "info" : "warn", "tool_call", {
39
+ ...safeFields,
40
+ commandPreview: config.logging.shellCommands && command ? commandPreview(command) : undefined,
41
+ });
42
+ }
43
+ export function contentText(content) {
44
+ return content
45
+ .filter((item) => item.type === "text")
46
+ .map((item) => item.text)
47
+ .join("\n");
48
+ }
49
+ export function toolErrorPreview(content) {
50
+ const text = contentText(content).replace(/\s+/g, " ").trim();
51
+ if (!text)
52
+ return undefined;
53
+ return text.length > 240 ? `${text.slice(0, 237)}...` : text;
54
+ }
55
+ export function logFailedToolResponse(config, fields, content, startedAt) {
56
+ logToolCall(config, {
57
+ ...fields,
58
+ success: false,
59
+ durationMs: Math.round(performance.now() - startedAt),
60
+ error: toolErrorPreview(content),
61
+ });
62
+ }
63
+ export function textBlock(text) {
64
+ return { type: "text", text };
65
+ }
66
+ export function attachWorkspaceTaskReminder(result, reminder) {
67
+ if (!reminder || toolResultIsError(result) || typeof result !== "object" || result === null)
68
+ return result;
69
+ const content = result.content;
70
+ if (!Array.isArray(content))
71
+ return result;
72
+ return {
73
+ ...result,
74
+ content: [...content, textBlock(reminder)],
75
+ };
76
+ }
77
+ export function textSummary(content) {
78
+ const text = contentText(content);
79
+ return {
80
+ lines: text.length === 0 ? 0 : text.split("\n").length,
81
+ characters: text.length,
82
+ };
83
+ }
84
+ export function contentLineCount(content) {
85
+ if (content.length === 0)
86
+ return 0;
87
+ return content.endsWith("\n")
88
+ ? content.slice(0, -1).split("\n").length
89
+ : content.split("\n").length;
90
+ }
91
+ export function countDiffStats(diff) {
92
+ if (!diff)
93
+ return { additions: 0, removals: 0 };
94
+ let additions = 0;
95
+ let removals = 0;
96
+ for (const line of diff.split("\n")) {
97
+ if (line.startsWith("+") && !line.startsWith("+++"))
98
+ additions++;
99
+ if (line.startsWith("-") && !line.startsWith("---"))
100
+ removals++;
101
+ }
102
+ return { additions, removals };
103
+ }
104
+ export function newFilePatch(path, content) {
105
+ const lines = content.length === 0
106
+ ? []
107
+ : content.endsWith("\n")
108
+ ? content.slice(0, -1).split("\n")
109
+ : content.split("\n");
110
+ const hunkLength = lines.length;
111
+ const hunkRange = hunkLength === 0 ? "+0,0" : `+1,${hunkLength}`;
112
+ const body = lines.map((line) => `+${line}`).join("\n");
113
+ return [
114
+ `diff --git a/${path} b/${path}`,
115
+ "new file mode 100644",
116
+ "index 0000000..0000000",
117
+ "--- /dev/null",
118
+ `+++ b/${path}`,
119
+ `@@ -0,0 ${hunkRange} @@`,
120
+ body,
121
+ ]
122
+ .filter((line) => line.length > 0)
123
+ .join("\n");
124
+ }
125
+ export function toolResultIsError(result) {
126
+ return typeof result === "object" && result !== null && result.isError === true;
127
+ }
128
+ export function toolResultText(result) {
129
+ if (typeof result !== "object" || result === null)
130
+ return String(result ?? "");
131
+ const record = result;
132
+ if (Array.isArray(record.content)) {
133
+ const text = record.content
134
+ .map((entry) => {
135
+ if (typeof entry !== "object" || entry === null)
136
+ return "";
137
+ const value = entry.text;
138
+ return typeof value === "string" ? value : "";
139
+ })
140
+ .filter(Boolean)
141
+ .join("\n");
142
+ if (text)
143
+ return text;
144
+ }
145
+ if (typeof record.structuredContent === "object" && record.structuredContent !== null) {
146
+ const value = record.structuredContent.result;
147
+ if (typeof value === "string")
148
+ return value;
149
+ }
150
+ return "";
151
+ }
152
+ export function toolResultContent(result) {
153
+ if (typeof result !== "object" || result === null)
154
+ return [];
155
+ const content = result.content;
156
+ return Array.isArray(content) ? content : [];
157
+ }
158
+ export function remapCompositeToolResult(result, executionWorkspaceId, compositeWorkspaceId, member) {
159
+ if (typeof result !== "object" || result === null)
160
+ return result;
161
+ const record = result;
162
+ const remapped = replaceWorkspaceIdentity(record, executionWorkspaceId, compositeWorkspaceId);
163
+ const meta = typeof remapped._meta === "object" && remapped._meta !== null
164
+ ? { ...remapped._meta }
165
+ : undefined;
166
+ if (meta) {
167
+ const card = typeof meta.card === "object" && meta.card !== null
168
+ ? { ...meta.card, workspaceId: compositeWorkspaceId, member }
169
+ : undefined;
170
+ if (card)
171
+ meta.card = card;
172
+ remapped._meta = meta;
173
+ }
174
+ const structured = typeof remapped.structuredContent === "object" && remapped.structuredContent !== null
175
+ ? { ...remapped.structuredContent, member }
176
+ : undefined;
177
+ if (structured)
178
+ remapped.structuredContent = structured;
179
+ return remapped;
180
+ }
181
+ export function replaceWorkspaceIdentity(value, from, to) {
182
+ if (typeof value === "string")
183
+ return value.split(from).join(to);
184
+ if (Array.isArray(value))
185
+ return value.map((entry) => replaceWorkspaceIdentity(entry, from, to));
186
+ if (!value || typeof value !== "object")
187
+ return value;
188
+ return Object.fromEntries(Object.entries(value)
189
+ .map(([key, entry]) => [key, replaceWorkspaceIdentity(entry, from, to)]));
190
+ }
191
+ export function toolResultAgentsFiles(result) {
192
+ if (typeof result !== "object" || result === null)
193
+ return [];
194
+ const structured = result.structuredContent;
195
+ if (typeof structured !== "object" || structured === null)
196
+ return [];
197
+ const agentsFiles = structured.agentsFiles;
198
+ if (!Array.isArray(agentsFiles))
199
+ return [];
200
+ return agentsFiles.flatMap((entry) => {
201
+ if (typeof entry !== "object" || entry === null)
202
+ return [];
203
+ const path = entry.path;
204
+ const content = entry.content;
205
+ return typeof path === "string" && typeof content === "string" ? [{ path, content }] : [];
206
+ });
207
+ }
@@ -0,0 +1,9 @@
1
+ import { readFileSync } from "node:fs";
2
+ export const FORGERELAY_VERSION = readForgeRelayVersion();
3
+ function readForgeRelayVersion() {
4
+ const packageJson = JSON.parse(readFileSync(new URL("../../../../package.json", import.meta.url), "utf8"));
5
+ if (typeof packageJson.version !== "string" || packageJson.version.length === 0) {
6
+ throw new Error("Unable to read ForgeRelay package version.");
7
+ }
8
+ return packageJson.version;
9
+ }