@akira-tl/forgerelay 1.1.2 → 1.2.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 (170) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +14 -0
  3. package/dist/activity/runtime/mcp-query-tools.js +15 -5
  4. package/dist/cli/config/inspect.js +331 -0
  5. package/dist/cli/config/migrate.js +351 -0
  6. package/dist/cli/init/setup-config.js +41 -0
  7. package/dist/cli/init.js +128 -130
  8. package/dist/cli/maintenance.js +15 -5
  9. package/dist/cli/mcp/external-mcp.js +14 -10
  10. package/dist/cli/mcp/status.js +11 -6
  11. package/dist/cli.js +40 -7
  12. package/dist/lsp/language-server-config.js +66 -144
  13. package/dist/lsp/runtime/manager.js +35 -4
  14. package/dist/mcp/hooks/config.js +141 -0
  15. package/dist/mcp/hooks/external-mcp-transform.js +22 -13
  16. package/dist/mcp/hooks/hook-cli.js +62 -52
  17. package/dist/mcp/hooks/hooks.js +111 -85
  18. package/dist/mcp/operations/external-mcp/external-mcp-runtime.js +8 -5
  19. package/dist/mcp/operations/external-mcp/external-mcp.js +9 -2
  20. package/dist/mcp/server/core/capability-support.js +7 -0
  21. package/dist/runtime/config/config.js +142 -64
  22. package/dist/runtime/config/definition/catalog.js +12 -0
  23. package/dist/runtime/config/definition/definition.js +115 -0
  24. package/dist/runtime/config/definition/external-mcp.js +58 -0
  25. package/dist/runtime/config/definition/general-config.js +258 -0
  26. package/dist/runtime/config/definition/language-servers.js +116 -0
  27. package/dist/runtime/config/definition/schema.js +113 -0
  28. package/dist/runtime/config/definition/types.js +2 -0
  29. package/dist/runtime/config/external-mcp-auth-store.js +105 -29
  30. package/dist/runtime/config/external-mcp-config.js +39 -0
  31. package/dist/runtime/config/external-mcp-registry.js +284 -106
  32. package/dist/runtime/config/inspection/live.js +77 -0
  33. package/dist/runtime/config/resolution/general.js +93 -0
  34. package/dist/runtime/config/resolution/hooks.js +315 -0
  35. package/dist/runtime/config/resolution/language-servers.js +237 -0
  36. package/dist/runtime/config/resolution/project-sources.js +159 -0
  37. package/dist/runtime/config/resolution/resolver.js +485 -0
  38. package/dist/runtime/config/resolution/types.js +1 -0
  39. package/dist/runtime/config/runtime/config-runtime.js +74 -0
  40. package/dist/runtime/config/runtime/source-refresh.js +263 -0
  41. package/dist/runtime/config/user-config.js +38 -31
  42. package/dist/runtime/security/project-execution-trust.js +34 -0
  43. package/dist/runtime/testing/server-fixture.js +9 -8
  44. package/dist/server.js +10 -6
  45. package/dist/subagents/profiles.js +336 -53
  46. package/dist/subagents/sessions/execution.js +6 -35
  47. package/dist/subagents/sessions/manager.js +14 -2
  48. package/dist/ui/.vite/manifest.json +275 -275
  49. package/dist/ui/activity-panel-app.html +1 -1
  50. package/dist/ui/assets/{activity-panel-app-Bw7ZFX2g.js → activity-panel-app-BeDiwd7D.js} +3 -3
  51. package/dist/ui/assets/{angular-html-DeUNP12X.js → angular-html-DuoCE7nn.js} +1 -1
  52. package/dist/ui/assets/{angular-ts-B3v8FKi_.js → angular-ts-D5tGk0hL.js} +1 -1
  53. package/dist/ui/assets/{apl-Bs3iQm4P.js → apl-lciOTPbw.js} +1 -1
  54. package/dist/ui/assets/{astro-D6GHecBY.js → astro-vJbqfNnJ.js} +1 -1
  55. package/dist/ui/assets/{blade-BMNbVOHv.js → blade-C7655Q4K.js} +1 -1
  56. package/dist/ui/assets/{c-BquuA6bv.js → c-DdHp1Jrw.js} +1 -1
  57. package/dist/ui/assets/{cobol-BuZ6kfps.js → cobol-DgvzQxZP.js} +1 -1
  58. package/dist/ui/assets/{coffee-DgC5uBzL.js → coffee-BIjVUOUd.js} +1 -1
  59. package/dist/ui/assets/{cpp-BdvWqCaB.js → cpp-CU8tGzvI.js} +1 -1
  60. package/dist/ui/assets/{crystal-0Q5qBvNI.js → crystal-CUQAwsg9.js} +1 -1
  61. package/dist/ui/assets/{css-Be_T8idh.js → css-DtMTqD3F.js} +1 -1
  62. package/dist/ui/assets/{edge-DaGLdgh_.js → edge-DoCX9RnL.js} +1 -1
  63. package/dist/ui/assets/{elixir-CMgiFIzB.js → elixir-DJxV9_U6.js} +1 -1
  64. package/dist/ui/assets/{elm-B-ufMlMC.js → elm-DIgWqK4r.js} +1 -1
  65. package/dist/ui/assets/{erb-CaGiOZM-.js → erb-BHxP0c_e.js} +1 -1
  66. package/dist/ui/assets/{git-rebase-CpwUWCzK.js → git-rebase-HbI_Vo8d.js} +1 -1
  67. package/dist/ui/assets/{glimmer-js-BRxccvnE.js → glimmer-js-CthY4Ty_.js} +1 -1
  68. package/dist/ui/assets/{glimmer-ts-CgQbPzlT.js → glimmer-ts-B2-_A1Xz.js} +1 -1
  69. package/dist/ui/assets/{glsl-D7JmHFr0.js → glsl-D9V9gq98.js} +1 -1
  70. package/dist/ui/assets/{graphql-C8n0eUBK.js → graphql-CddeAaS3.js} +1 -1
  71. package/dist/ui/assets/{hack-lVN7KVQv.js → hack-D_loGkOT.js} +1 -1
  72. package/dist/ui/assets/{haml-h18lG0pS.js → haml-BoWDczd0.js} +1 -1
  73. package/dist/ui/assets/{handlebars-lRFjRPfj.js → handlebars-ZoSOvw9y.js} +1 -1
  74. package/dist/ui/assets/{heavy-payload-Cqx9MOkH.js → heavy-payload-DO34LwoZ.js} +3 -3
  75. package/dist/ui/assets/{html-DtILqTE1.js → html-CE-obXVo.js} +1 -1
  76. package/dist/ui/assets/{html-derivative-CSTSmPup.js → html-derivative-Cd-smAbW.js} +1 -1
  77. package/dist/ui/assets/{http-DNI8fsbY.js → http-CZrkbrSl.js} +1 -1
  78. package/dist/ui/assets/{hurl-DgRi60JG.js → hurl-CxTuxBt1.js} +1 -1
  79. package/dist/ui/assets/{java-CW9pZ5bh.js → java-BshLjCat.js} +1 -1
  80. package/dist/ui/assets/{javascript-Cvg2UrWL.js → javascript-D2pxQTiX.js} +1 -1
  81. package/dist/ui/assets/{jinja-CZw_S1FB.js → jinja-kbfPP7-F.js} +1 -1
  82. package/dist/ui/assets/{jison-C56u_FZv.js → jison-C2mt9l1M.js} +1 -1
  83. package/dist/ui/assets/{json-DW2UTv1q.js → json-DU_rg_AU.js} +1 -1
  84. package/dist/ui/assets/{jsx-Zj5gobdD.js → jsx-D_8aQMlx.js} +1 -1
  85. package/dist/ui/assets/{julia-Cvcrre-L.js → julia-BmefTaVV.js} +1 -1
  86. package/dist/ui/assets/{just-8CZ2u6Tj.js → just-DXV8vk1S.js} +1 -1
  87. package/dist/ui/assets/{latex-D289AXWG.js → latex-Cjm2MvGW.js} +1 -1
  88. package/dist/ui/assets/{liquid-CFEX3SkZ.js → liquid-DyQDlo0u.js} +1 -1
  89. package/dist/ui/assets/{lua-BKpJ0ybO.js → lua-B2A1vzzy.js} +1 -1
  90. package/dist/ui/assets/{marko-D9maZ0a6.js → marko-B9vOkXOU.js} +1 -1
  91. package/dist/ui/assets/{mdc-rM9l0qWR.js → mdc-D42m6spU.js} +1 -1
  92. package/dist/ui/assets/{nginx-C9w6p2C9.js → nginx-TpfVxSUY.js} +1 -1
  93. package/dist/ui/assets/{nim-BRePHk0J.js → nim-CJr5T1FK.js} +1 -1
  94. package/dist/ui/assets/{perl-CskTmiPQ.js → perl-cJZcsdm9.js} +1 -1
  95. package/dist/ui/assets/{php-DCU_FvNI.js → php-CSZL5KRT.js} +1 -1
  96. package/dist/ui/assets/{pug-XLaVxTvv.js → pug-B1eMKzuA.js} +1 -1
  97. package/dist/ui/assets/{qml-CaONKSl-.js → qml-Dl2_7zc9.js} +1 -1
  98. package/dist/ui/assets/{r-BCVR0ZE3.js → r-F0aaO9gG.js} +1 -1
  99. package/dist/ui/assets/{razor-DDnGXxnU.js → razor-BPnkSMCw.js} +1 -1
  100. package/dist/ui/assets/{regexp-DWGTYYVx.js → regexp-BnGHMFbv.js} +1 -1
  101. package/dist/ui/assets/{rst-Dz3GWvQm.js → rst-B3CO7WYO.js} +1 -1
  102. package/dist/ui/assets/{ruby-DC3jGtMY.js → ruby-B6VMzT1T.js} +1 -1
  103. package/dist/ui/assets/{sas-7mNpvsjZ.js → sas-Df2lHVuU.js} +1 -1
  104. package/dist/ui/assets/{scss-uBsoCJVy.js → scss-4XxI6sgu.js} +1 -1
  105. package/dist/ui/assets/{shellscript-BCN9N_Jf.js → shellscript-DYASCN4r.js} +1 -1
  106. package/dist/ui/assets/{shellsession-Hsw46VXV.js → shellsession-Br6AGJO_.js} +1 -1
  107. package/dist/ui/assets/{soy-D6KV69HU.js → soy-p3ZNq1We.js} +1 -1
  108. package/dist/ui/assets/{sql-CVzVQkJh.js → sql-CAdv2OXL.js} +1 -1
  109. package/dist/ui/assets/{stata-BwUjXNhI.js → stata-Dx7yUbG_.js} +1 -1
  110. package/dist/ui/assets/{surrealql-CgloWqRa.js → surrealql-6YsE8HQa.js} +1 -1
  111. package/dist/ui/assets/{svelte-DcC3n6IC.js → svelte-YgzedwpD.js} +1 -1
  112. package/dist/ui/assets/{templ-DOFfnWTJ.js → templ-Bahqx3uD.js} +1 -1
  113. package/dist/ui/assets/{tex-ln89VPaX.js → tex-o6fTQjkH.js} +1 -1
  114. package/dist/ui/assets/{ts-tags-CWMzCstH.js → ts-tags-BO-Co0Ju.js} +1 -1
  115. package/dist/ui/assets/{tsx-DgzfiGeK.js → tsx-DtQe5AoH.js} +1 -1
  116. package/dist/ui/assets/{twig-Bi2itZL9.js → twig-BcUs6Kqc.js} +1 -1
  117. package/dist/ui/assets/{typescript-CQ24f4zW.js → typescript-BPtM8h4u.js} +1 -1
  118. package/dist/ui/assets/{vue-BS8jE5u6.js → vue-5KkGUzJJ.js} +1 -1
  119. package/dist/ui/assets/{vue-html-o38xqhyB.js → vue-html-Df_Xfsz9.js} +1 -1
  120. package/dist/ui/assets/{vue-vine-D2NvKv50.js → vue-vine-hUIe_u_Y.js} +1 -1
  121. package/dist/ui/assets/{xml-_44rx9_2.js → xml-C3Jy7as5.js} +1 -1
  122. package/dist/ui/assets/{xsl-B5QWQPoi.js → xsl-BnF9OuFo.js} +1 -1
  123. package/dist/ui/assets/{yaml-CKL2pEWe.js → yaml-DyrFgCou.js} +1 -1
  124. package/dist/workspaces/conversation-test-support.js +3 -11
  125. package/dist/workspaces/sessions.js +2 -0
  126. package/dist/workspaces/state/project-context.js +221 -0
  127. package/dist/workspaces.js +3 -1
  128. package/docs/chatgpt-coding-workflow.md +8 -3
  129. package/docs/configuration.md +99 -41
  130. package/docs/gotchas.md +24 -5
  131. package/docs/security.md +14 -3
  132. package/docs/setup.md +12 -7
  133. package/package.json +12 -3
  134. package/schemas/v1/config.project-local.schema.json +14 -0
  135. package/schemas/v1/config.project.schema.json +14 -0
  136. package/schemas/v1/config.user.schema.json +538 -0
  137. package/schemas/v1/hooks.project-local.schema.json +118 -0
  138. package/schemas/v1/hooks.project.schema.json +118 -0
  139. package/schemas/v1/hooks.user.schema.json +118 -0
  140. package/schemas/v1/language-servers.project-local.schema.json +230 -0
  141. package/schemas/v1/language-servers.project.schema.json +230 -0
  142. package/schemas/v1/language-servers.user.schema.json +230 -0
  143. package/schemas/v1/mcp.project-local.schema.json +143 -0
  144. package/schemas/v1/mcp.project.schema.json +143 -0
  145. package/schemas/v1/mcp.user.schema.json +143 -0
  146. package/scripts/ci/architecture.mjs +54 -4
  147. package/scripts/ci/cmd-acceptance.mjs +9 -9
  148. package/scripts/ci/config-v2-product-acceptance.mjs +639 -0
  149. package/scripts/ci/gates/acceptance-artifact.mjs +66 -0
  150. package/scripts/ci/gates/core-contract.mjs +27 -0
  151. package/scripts/ci/gates/platform-tests.mjs +38 -0
  152. package/scripts/ci/gates/prepare-windows-product.mjs +57 -0
  153. package/scripts/ci/gates/test-shard.mjs +71 -0
  154. package/scripts/ci/powershell51-acceptance.mjs +9 -9
  155. package/scripts/ci/pwsh-acceptance.mjs +9 -9
  156. package/scripts/ci/verify.mjs +2 -0
  157. package/scripts/ci/windows-product-acceptance.mjs +9 -10
  158. package/scripts/config/schema-text.mjs +4 -0
  159. package/scripts/config/schema-text.test.mjs +18 -0
  160. package/scripts/config/schema.mjs +74 -0
  161. package/scripts/lsp/interop.mjs +4 -1
  162. package/scripts/release/pack.mjs +64 -4
  163. package/scripts/release/release-gate.test.mjs +93 -27
  164. package/scripts/release-parity.mjs +19 -2
  165. package/templates/instructions/cmd.md +12 -0
  166. package/templates/instructions/fish.md +11 -0
  167. package/templates/instructions/powershell.md +14 -0
  168. package/templates/instructions/pwsh.md +14 -0
  169. package/templates/instructions/zsh.md +11 -0
  170. package/dist/runtime/instructions/powershell-skill.js +0 -65
@@ -1,7 +1,54 @@
1
1
  # Configuration Reference
2
2
 
3
3
  ForgeRelay can be configured through `forgerelay init`, persisted config files,
4
- or environment variables.
4
+ or environment variables. ForgeRelay v1.2 uses one Config System v2 model for General Config, External MCP, Language Servers, Lifecycle Hooks, and Subagent Profiles.
5
+
6
+ ## Config System v2
7
+
8
+ Canonical precedence is:
9
+
10
+ ```text
11
+ runtime > project-local > project > user > built-in
12
+ ```
13
+
14
+ Runtime CLI overrides environment values. A field participates only in scopes allowed by its Config Definition. Project Local is machine-private ForgeRelay state keyed by canonical Project identity; it is separate from Workspace identity and is not written into the checkout.
15
+
16
+ Canonical v1.2 sources are:
17
+
18
+ | Domain | User | Project | Project Local |
19
+ | --- | --- | --- | --- |
20
+ | General | `~/.forgerelay/config.json` | `<project>/.forgerelay/config.json` | `~/.forgerelay/projects/<project-id>/config.json` |
21
+ | External MCP | `~/.forgerelay/mcp.json` | `<project>/.forgerelay/mcp.json` | `~/.forgerelay/projects/<project-id>/mcp.json` |
22
+ | Language Servers | `~/.forgerelay/language-servers.json` | `<project>/.forgerelay/language-servers.json` | `~/.forgerelay/projects/<project-id>/language-servers.json` |
23
+ | Lifecycle Hooks | `~/.forgerelay/hooks/*.json` | `<project>/.forgerelay/hooks/*.json` | `~/.forgerelay/projects/<project-id>/hooks/*.json` |
24
+ | Subagent Profiles | `~/.forgerelay/subagents/*.md` | `<project>/.forgerelay/subagents/*.md` | `~/.forgerelay/projects/<project-id>/subagents/*.md` |
25
+
26
+ The active config directory replaces `~/.forgerelay` when `FORGERELAY_CONFIG_DIR` is set. Credentials such as `auth.json` and `mcp-auth.json` are separate from ordinary Config Resolver precedence.
27
+
28
+ Use the packaged v1 schemas under `schemas/v1/` for canonical JSON files. Supported sensitive fields may reference environment variables with `${ENV_NAME}`; interpolation is definition-controlled, not arbitrary string templating. Secret-safe diagnostics retain configured references where useful but redact resolved sensitive values.
29
+
30
+ Canonical MCP, Language Server, Hook, and Subagent sources refresh on demand from content fingerprints rather than mtime. A previously valid source that becomes invalid keeps its in-process last-known-good value until repaired; deleting the source clears that contribution. Restart-required General settings expose configured-versus-applied state and never auto-restart ForgeRelay.
31
+
32
+ Startup never rewrites legacy configuration. Inspect configuration with:
33
+
34
+ ```bash
35
+ forgerelay config check
36
+ forgerelay config sources
37
+ forgerelay config explain <logical-path>
38
+ ```
39
+
40
+ Use `--global`, `--project <path>`, and `--json` as needed. Explicit migration is separate:
41
+
42
+ ```bash
43
+ forgerelay config migrate --dry-run --global
44
+ forgerelay config migrate --dry-run --project /path/to/project
45
+ forgerelay config migrate --global
46
+ forgerelay config migrate --project /path/to/project
47
+ ```
48
+
49
+ Migration is limited to ForgeRelay-owned legacy formats, creates backups, uses atomic writes, and preserves canonical shadowing/effective behavior. It does not import private Claude, Codex, Cursor, or other product configuration, and it does not move ForgeRelay-owned Skills into `.agents/skills`.
50
+
51
+ Legacy ForgeRelay-owned parsers/paths remain readable with deprecation diagnostics through v1.2.x, receive stronger removal warnings in v1.3.x, and are removed in v1.4.0.
5
52
 
6
53
  ## Config directory
7
54
 
@@ -34,6 +81,10 @@ FORGERELAY_CONFIG_DIR=/path/to/config npx @akira-tl/forgerelay serve
34
81
  npx @akira-tl/forgerelay init
35
82
  npx @akira-tl/forgerelay serve
36
83
  npx @akira-tl/forgerelay doctor
84
+ npx @akira-tl/forgerelay config check
85
+ npx @akira-tl/forgerelay config sources
86
+ npx @akira-tl/forgerelay config explain <logical-path>
87
+ npx @akira-tl/forgerelay config migrate --dry-run --global
37
88
  npx @akira-tl/forgerelay config get
38
89
  npx @akira-tl/forgerelay config set publicBaseUrl https://forge.example.com/forgerelay/main,https://forge-alt.example.com/relay
39
90
  npx @akira-tl/forgerelay mcp list
@@ -184,13 +235,19 @@ New configuration uses a dedicated `mcp.json` file. The machine-wide registry is
184
235
  ~/.forgerelay/mcp.json
185
236
  ```
186
237
 
187
- or the equivalent path below `FORGERELAY_CONFIG_DIR`. A Workspace may add or override servers in:
238
+ or the equivalent path below `FORGERELAY_CONFIG_DIR`. A Project may add or override servers in:
188
239
 
189
240
  ```text
190
- <workspace>/.forgerelay/mcp.json
241
+ <project>/.forgerelay/mcp.json
242
+ ```
243
+
244
+ Machine-private Project Local overrides live in:
245
+
246
+ ```text
247
+ ~/.forgerelay/projects/<project-id>/mcp.json
191
248
  ```
192
249
 
193
- Both files use this shape:
250
+ All canonical MCP files use this shape:
194
251
 
195
252
  ```json
196
253
  {
@@ -213,9 +270,11 @@ Server names are stable lowercase identifiers matching `^[a-z][a-z0-9._-]{0,63}$
213
270
  Effective configuration is merged by server name in this order:
214
271
 
215
272
  ```text
216
- Project mcp.json > global mcp.json > legacy config.json.mcpServers
273
+ Project Local > Project > User > legacy config.json.mcpServers
217
274
  ```
218
275
 
276
+ Project Local lives under the ForgeRelay-private `projects/<project-id>/mcp.json` path and is never written into the checkout.
277
+
219
278
  A Project entry may explicitly hide an inherited server:
220
279
 
221
280
  ```json
@@ -228,15 +287,15 @@ A Project entry may explicitly hide an inherited server:
228
287
  }
229
288
  ```
230
289
 
231
- `disabled` defaults to `false` and normally does not need to be written. Removing the Project entry exposes the lower-precedence global/legacy server again. A complete server entry may also contain `"disabled": true`; ForgeRelay validates the entry but does not activate it.
290
+ `disabled` defaults to `false` and normally does not need to be written. Removing a higher-scope entry exposes the lower-precedence Project/User/legacy server again. A complete server entry may also contain `"disabled": true`; ForgeRelay validates the entry but does not activate it.
232
291
 
233
- The historical `config.json -> mcpServers` object remains a deprecated read-compatible source. New configuration and documentation use `mcp.json`; the legacy source is retained for at least the next two feature-release compatibility windows and should not be used for new setups.
292
+ The historical `config.json -> mcpServers` object remains a deprecated read-compatible source. New configuration and documentation use `mcp.json`. It remains readable with deprecation diagnostics in v1.2.x, receives stronger removal warnings in v1.3.x, and its legacy parser/path is removed in v1.4.0.
234
293
 
235
- ForgeRelay reloads global and Project `mcp.json` on demand before External MCP operations. A valid changed file becomes visible to the next `servers`, `tools`, or `call` operation without restarting ForgeRelay. Each operation uses one immutable snapshot, so an in-flight call is not switched underneath itself. If a previously valid source becomes invalid, that running ForgeRelay process keeps the whole previous valid source as last-known-good and reports a bounded diagnostic; no partially parsed subset is activated. A fresh CLI process cannot reconstruct another process's in-memory last-known-good snapshot, so it reports the invalid source while noting that an existing runtime may still be using its prior valid snapshot.
294
+ ForgeRelay reloads canonical User, Project, and Project Local `mcp.json` sources on demand before External MCP operations. A valid changed file becomes visible to the next `servers`, `tools`, or `call` operation without restarting ForgeRelay. Each operation uses one immutable snapshot, so an in-flight call is not switched underneath itself. If a previously valid source becomes invalid, that running ForgeRelay process keeps the whole previous valid source as last-known-good and reports a bounded diagnostic; no partially parsed subset is activated. A fresh CLI process cannot reconstruct another process's in-memory last-known-good snapshot, so it reports the invalid source while noting that an existing runtime may still be using its prior valid snapshot.
236
295
 
237
296
  ### External MCP transports and authentication
238
297
 
239
- A stdio server supports `command`, optional `args`, `env`, and `cwd`. It is launched directly, not through a shell. Its process still runs with the operating-system authority of the user running ForgeRelay. A Project `.forgerelay/mcp.json` can therefore introduce executable project configuration; opening an allowed project is the trust boundary, and ForgeRelay does not add a second per-server approval prompt.
298
+ A stdio server supports `command`, optional `args`, `env`, and `cwd`. It is launched directly, not through a shell. Its process still runs with the operating-system authority of the user running ForgeRelay. A Project `.forgerelay/mcp.json` can therefore introduce executable project configuration. Allowed roots grant filesystem/Workspace authority, not Project Trust approval. v1.2.0 routes this execution through the shared Project trust seam under compatibility-allow; there is no second per-server prompt and no claim of a complete interactive Project Trust UX.
240
299
 
241
300
  A Streamable HTTP server supports `url` and optional static `headers`:
242
301
 
@@ -260,7 +319,7 @@ ForgeRelay does not require every HTTP MCP server to use OAuth. The effective mo
260
319
  - static credentials: user-managed `headers` for HTTP or `env` for stdio;
261
320
  - interactive OAuth: explicitly initiated by a human through the CLI.
262
321
 
263
- Do not commit static secrets in Project `mcp.json`. ForgeRelay does not move project-defined header/env secrets into a separate secret manager in v1.1.1.
322
+ Do not commit static secrets in Project `mcp.json`. Config v2 supports definition-controlled `${ENV_NAME}` references in supported sensitive fields, but ForgeRelay does not turn arbitrary project-defined header/env values into a separate secret manager.
264
323
 
265
324
  Interactive OAuth state is stored only in the machine-private:
266
325
 
@@ -319,7 +378,7 @@ forgerelay mcp test <server>
319
378
  forgerelay doctor
320
379
  ```
321
380
 
322
- `mcp list` is passive: it reports the resolved Project/global/legacy sources, disabled entries, authentication state, credential-store health, and invalid/last-known-good configuration diagnostics. With no explicit scope it uses the active Workspace root when supplied by ForgeRelay, otherwise walks upward from the current directory for the nearest `.forgerelay/mcp.json`; `--project` selects a Project explicitly and `--global` excludes Project configuration.
381
+ `mcp list` is passive: it reports the resolved Project Local/Project/User/legacy sources, disabled entries, authentication state, credential-store health, and invalid/last-known-good configuration diagnostics. With no explicit scope it uses the active Workspace root when supplied by ForgeRelay, otherwise walks upward from the current directory for the nearest `.forgerelay/mcp.json`; `--project` selects a Project explicitly and `--global` excludes Project and Project Local configuration.
323
382
 
324
383
  `mcp test` is the active probe. It connects to the selected server and performs tool discovery, reporting source, transport, auth state, negotiated MCP era/version, tool count, and actionable failures such as authentication required, unreachable transport, or tool discovery failure.
325
384
 
@@ -458,12 +517,14 @@ while semantic work is active. Debug `runtime_resources` telemetry includes only
458
517
  aggregate Language-service/process/request/document/diagnostic/stderr counts; it
459
518
  does not log source contents or source paths.
460
519
 
461
- Effective Language-server definitions resolve in this order:
520
+ Effective Language-server definitions resolve through Config v2 in this order:
521
+
522
+ 1. Project Local `projects/<project-id>/language-servers.json`;
523
+ 2. Project `.forgerelay/language-servers.json`;
524
+ 3. User `language-servers.json` in the active ForgeRelay config directory;
525
+ 4. built-in discovery for known executables.
462
526
 
463
- 1. project configuration in `.forgerelay/language-servers.json`;
464
- 2. global definitions from the `languageServers` object in
465
- `~/.forgerelay/config.json`;
466
- 3. built-in discovery for known executables.
527
+ Legacy `config.json.languageServers` remains read-compatible with deprecation diagnostics in v1.2.x and is removed in v1.4.0.
467
528
 
468
529
  A project configuration file is an object keyed by definition name. Definitions
469
530
  use structured process launch and never go through a shell:
@@ -487,25 +548,11 @@ use structured process launch and never go through a shell:
487
548
  }
488
549
  ```
489
550
 
490
- Global configuration uses the same definition shape under `languageServers`. ForgeRelay can also keep optional npm-managed Language Servers under its private config directory. Agent-triggered installation is disabled by default and must be explicitly enabled:
491
-
492
- ```json
493
- {
494
- "languageServers": {
495
- "typescript": {
496
- "command": "/absolute/path/to/typescript-language-server",
497
- "args": ["--stdio"]
498
- }
499
- },
500
- "allowAgentLanguageServerInstall": false
501
- }
502
- ```
551
+ User configuration uses the same definition shape in the active config directory's `language-servers.json`. ForgeRelay can also keep optional npm-managed Language Servers under its private config directory. Agent-triggered installation is disabled by default and must be explicitly enabled through General Config, for example `"allowAgentLanguageServerInstall": false` in `config.json`.
503
552
 
504
- `forgerelay init` can manage TypeScript/JavaScript and Pyright installations without touching global npm. When `allowAgentLanguageServerInstall` is `true`, an Agent may use `code.intelligence` operations `managed.status` and `managed.install`; successful installs become discoverable by the same running ForgeRelay process on the next semantic request, with no restart required. Rust Analyzer, `gopls`, and `clangd` remain external toolchain/system installations.
553
+ `forgerelay init --advanced` can manage TypeScript/JavaScript and Pyright installations without touching global npm. Basic `forgerelay init` does not install Language Servers. When `allowAgentLanguageServerInstall` is `true`, an Agent may use `code.intelligence` operations `managed.status` and `managed.install`; successful installs become discoverable by the same running ForgeRelay process on the next semantic request, with no restart required. Rust Analyzer, `gopls`, and `clangd` remain external toolchain/system installations.
505
554
 
506
- Explicit configuration can set `"enabled": false` to suppress the matching
507
- built-in definition. Project values override global values, and both override
508
- built-in defaults. ForgeRelay resolves a Language project by walking ancestors of
555
+ Explicit legacy configuration can still normalize historical `"enabled": false`; canonical keyed definitions use the current Config v2 shape and scope semantics. Project Local overrides Project, Project overrides User, and all canonical explicit definitions override built-in defaults. ForgeRelay resolves a Language project by walking ancestors of
509
556
  the requested source file according to that definition's `projectMarkers`; it does
510
557
  not recursively scan the Workspace.
511
558
 
@@ -703,7 +750,7 @@ change the Activity snapshot/query contract.
703
750
 
704
751
  ## Lifecycle hooks
705
752
 
706
- Hooks v1 是自动生命周期规则。规则由用户或 Agent 主动写入;命中后 ForgeRelay 直接执行,不再增加批准步骤。
753
+ Hooks v1.2 是自动生命周期规则。规则由用户或 Agent 主动写入;Project Hook 属于 executable project configuration,并在 v1.2.0 通过统一 Project execution trust seam 后按 compatibility-allow 执行。当前版本没有完整交互式 Project Trust approval UI。
707
754
 
708
755
  首选格式是 **一个 Hook 一个 JSON 文件**。全局 Hook 放在当前 ForgeRelay 配置目录的 `hooks/` 下,新安装通常是:
709
756
 
@@ -711,15 +758,21 @@ Hooks v1 是自动生命周期规则。规则由用户或 Agent 主动写入;
711
758
  ~/.forgerelay/hooks/<hook-name>.json
712
759
  ```
713
760
 
714
- 项目 Hook 放在工作区根目录:
761
+ Project Hook 放在项目根目录:
762
+
763
+ ```text
764
+ <project>/.forgerelay/hooks/<hook-name>.json
765
+ ```
766
+
767
+ Project Local Hook 位于机器私有:
715
768
 
716
769
  ```text
717
- <workspace>/.forgerelay/hooks/<hook-name>.json
770
+ ~/.forgerelay/projects/<project-id>/hooks/<hook-name>.json
718
771
  ```
719
772
 
720
773
  文件名去掉 `.json` 后就是 Hook 名,也是日志和 Agent-visible report 中显示的名称。例如 `release-tag-gate.json` 会显示为 `release-tag-gate`。目录内按文件名字典序执行;需要显式排序时可以使用 `10-release-verify.json`、`20-package-inspection.json` 这样的前缀。ForgeRelay 只读取普通 `*.json` 文件,所以临时停用某条 Hook 时可以把扩展名改掉。
721
774
 
722
- 全局 Hook server 启动时读取,修改后需要重启 ForgeRelay;项目目录在每次事件时重新读取,所以 Agent 修改项目 Hook 后不需要重启。全局规则先执行,项目规则随后执行,两边都只做追加,不互相覆盖。
775
+ Canonical User / Project / Project Local Hook sources all refresh on demand in v1.2. Changes do not require a ForgeRelay restart. Resolution follows Config v2 scope precedence, while directory entries keep deterministic file ordering. A previously valid Hook file that becomes invalid keeps its per-file in-process last-known-good until repaired; deleting the file removes that contribution.
723
776
 
724
777
  每个独立 Hook 文件只描述一条规则:
725
778
 
@@ -750,7 +803,7 @@ Hooks v1 是自动生命周期规则。规则由用户或 Agent 主动写入;
750
803
 
751
804
  独立文件不写 `name`:文件名就是唯一的 Hook 名。一个逻辑 Hook 如果需要多个独立步骤,拆成多个文件;这样可以单独启停、重命名、排序和审查每一步。
752
805
 
753
- 为兼容已有配置,ForgeRelay 仍接受旧的 `config.json -> hooks`、全局 `hooks.json` 和项目 `.forgerelay/hooks.json` 聚合格式。执行顺序是旧配置在前、`hooks/*.json` 独立文件在后。新配置应优先使用独立文件。
806
+ 为兼容已有配置,ForgeRelay 在 v1.2.x 仍接受旧的 `config.json -> hooks`、全局 `hooks.json` 和项目 `.forgerelay/hooks.json` 聚合格式,并通过同一个 Config Resolver 规范化后产生 deprecation diagnostics;canonical `hooks/*.json` 在同 scope 下优先于对应 legacy source。v1.3.x 会加强 removal warning,legacy parser/path 在 v1.4.0 移除。新配置应只使用独立文件。
754
807
 
755
808
  若某个项目 Hook 文件 JSON 或 schema 无效,ForgeRelay 会返回 `Project hooks config` diagnostic,同时继续加载其他有效项目 Hook,并保持 workspace/tool 可用,让 Agent 可以直接修复出错文件。
756
809
 
@@ -868,12 +921,17 @@ Standard Agent Skills are discovered in precedence order from:
868
921
  - `FORGERELAY_AGENT_DIR/skills`
869
922
  - paths from `FORGERELAY_SKILL_PATHS`
870
923
 
924
+ The ownership boundaries are different even though all of these are readable Skill sources. Project/global `.agents/skills` belong to the open Agent Skills ecosystem and may contain files or symlinks installed by other Agent tooling. ForgeRelay-owned Skills stay under the active ForgeRelay config directory (`~/.forgerelay/skills` by default); ForgeRelay does not migrate or install its private Skills into `~/.agents/skills`.
925
+
871
926
  When the same Skill name appears in more than one source, the first source wins. Project Skills therefore override same-named global `~/.agents/skills` entries, matching ForgeRelay's project-over-global configuration model.
872
927
 
873
- When subagents are enabled, profiles are discovered from:
928
+ When subagents are enabled, canonical v1.2 profiles are discovered from:
929
+
930
+ - the active ForgeRelay config directory's `subagents/*.md`;
931
+ - project `.forgerelay/subagents/*.md`;
932
+ - machine-private Project Local `projects/<project-id>/subagents/*.md`.
874
933
 
875
- - the active ForgeRelay config directory's `agents/*.md`;
876
- - project `.forgerelay/agents/*.md`.
934
+ Legacy `agents/*.md` remains read-compatible in v1.2.x with deprecation diagnostics and is scheduled for removal in v1.4.0. ForgeRelay does not import provider-private profile/config directories.
877
935
 
878
936
 
879
937
  ForgeRelay does not install or bundle coding-agent executors. Subagent providers
package/docs/gotchas.md CHANGED
@@ -120,6 +120,20 @@ Regenerate setup intentionally with:
120
120
  forgerelay init --force
121
121
  ```
122
122
 
123
+ ## Config v2 says a value is invalid, shadowed, or missing
124
+
125
+ Use the Config v2 inspection surface before editing files by guesswork:
126
+
127
+ ```bash
128
+ forgerelay config check --project /path/to/project
129
+ forgerelay config sources --project /path/to/project
130
+ forgerelay config explain <logical-path> --project /path/to/project
131
+ ```
132
+
133
+ Project Local sources are machine-private under the ForgeRelay config directory and can override Project/User sources without appearing in the checkout. Running ForgeRelay may keep an in-memory last-known-good value for a hot-reload source that has since become invalid; a fresh offline CLI process cannot reconstruct another process's LKG.
134
+
135
+ Startup does not rewrite old formats. Preview migration with `forgerelay config migrate --dry-run --global` or `--project <path>`, then run the same command without `--dry-run` only after reviewing the backup-preserving plan. ForgeRelay-owned legacy parsers/paths remain in v1.2.x, warn more strongly in v1.3.x, and are removed in v1.4.0.
136
+
123
137
  ## Unknown `workspaceId`
124
138
 
125
139
  Reopen the project with `open_workspace` and use the returned ID. Active
@@ -180,12 +194,14 @@ FORGERELAY_SKILLS=1 forgerelay serve
180
194
 
181
195
  Standard paths include:
182
196
 
183
- - `~/.agents/skills`
184
197
  - project `.agents/skills`
185
- - active ForgeRelay config `skills` directory
198
+ - `~/.agents/skills`
199
+ - active ForgeRelay config `skills` directory (`~/.forgerelay/skills` by default)
186
200
  - `FORGERELAY_AGENT_DIR/skills`
187
201
  - additional `FORGERELAY_SKILL_PATHS`
188
202
 
203
+ `.agents/skills` is an external/open Agent Skill source and may contain symlinks managed by other Agent tooling. ForgeRelay-owned Skills belong under its own config `skills` directory and must not be migrated into `.agents/skills`.
204
+
189
205
  ## Subagent profiles do not appear
190
206
 
191
207
  Enable subagents:
@@ -194,13 +210,16 @@ Enable subagents:
194
210
  FORGERELAY_SUBAGENTS=1 forgerelay serve
195
211
  ```
196
212
 
197
- New profile locations include:
213
+ Canonical v1.2 profile locations are:
198
214
 
199
215
  ```text
200
- ~/.forgerelay/agents/*.md
201
- .forgerelay/agents/*.md
216
+ ~/.forgerelay/subagents/*.md
217
+ <project>/.forgerelay/subagents/*.md
218
+ ~/.forgerelay/projects/<project-id>/subagents/*.md
202
219
  ```
203
220
 
221
+ Legacy `agents/*.md` remains read-compatible in v1.2.x with deprecation diagnostics and is removed in v1.4.0.
222
+
204
223
  `forgerelay agents ls` lists sessions, not profile definitions. The compact
205
224
  profile catalog is returned through `open_workspace`.
206
225
 
package/docs/security.md CHANGED
@@ -39,6 +39,17 @@ Capability Guides are ForgeRelay-owned, versioned package documentation. Their
39
39
  paths are surfaced by the running server rather than guessed by the Agent. This
40
40
  keeps progressive disclosure from becoming a general arbitrary-file read escape.
41
41
 
42
+ Allowed roots are filesystem/Workspace authority, not a Project Trust approval.
43
+ They determine which projects ForgeRelay may open; they do not by themselves mean
44
+ that executable project configuration has passed a separate trust prompt.
45
+
46
+ v1.2.0 routes executable Project Hooks, stdio External MCP entries, Project
47
+ Language Servers, and Project Subagent Profiles through one Project execution
48
+ trust seam. The initial policy is deliberately **compatibility-allow**: v1.2.0
49
+ does not ship a full interactive Project Trust approval UI. Later v1.2.x work can
50
+ strengthen approval/enforcement at this seam without giving each execution
51
+ subsystem a different trust model.
52
+
42
53
  ## Owner-password OAuth
43
54
 
44
55
  New installations store local configuration in:
@@ -149,9 +160,9 @@ policy because they are lifecycle gates rather than user-command execution.
149
160
 
150
161
  ## External MCP configuration and credentials
151
162
 
152
- External MCP extends the same local-authority model rather than creating a sandbox. Machine-wide servers live in the ForgeRelay config directory's `mcp.json`; Project servers may live in `<workspace>/.forgerelay/mcp.json`. A Project stdio entry can launch a configured executable with the same operating-system user authority as ForgeRelay, so Project MCP configuration is executable project configuration. ForgeRelay does not add a second per-server approval prompt after the operator has allowed and opened that project root.
163
+ External MCP extends the same local-authority model rather than creating a sandbox. Machine-wide servers live in the ForgeRelay config directory's `mcp.json`; Project servers may live in `<workspace>/.forgerelay/mcp.json`, while Project Local servers stay under ForgeRelay-private `projects/<project-id>/mcp.json`. A Project stdio entry can launch a configured executable with the same operating-system user authority as ForgeRelay, so Project MCP configuration is executable project configuration. In v1.2.0 it passes through the shared Project trust seam under compatibility-allow; ForgeRelay does not add a second per-server prompt, and this must not be confused with a full Project Trust approval UX.
153
164
 
154
- Static HTTP headers and stdio environment values are user-managed configuration. Do not commit secrets in Project `mcp.json`; v1.1.1 does not automatically extract project-defined secrets into a secret manager.
165
+ Static HTTP headers and stdio environment values are user-managed configuration. Do not commit secrets in Project `mcp.json`. Config v2 supports definition-controlled `${ENV_NAME}` references for supported sensitive fields, but it does not turn project-defined secrets into a general secret manager.
155
166
 
156
167
  Interactive External MCP OAuth credentials are different. They are kept in the machine-private ForgeRelay config directory:
157
168
 
@@ -169,7 +180,7 @@ External MCP result references are not implicitly dereferenced. Paths, URLs and
169
180
 
170
181
  Hook command 是本地代码执行,使用与 ForgeRelay 相同的操作系统用户权限并继承进程环境。
171
182
 
172
- Hooks v1 有两个自动作用域:当前 ForgeRelay 配置目录中的 `hooks/<hook-name>.json` 全局规则,以及 workspace 根目录的 `.forgerelay/hooks/<hook-name>.json` 项目规则。项目规则不需要额外批准;打开允许根目录中的项目时,ForgeRelay 会把这些 Hook 当作该开发环境的执行约定直接使用,`WorkspaceOpen` 也可以立即触发命令。因此 allowed roots 不只是文件访问边界,也界定了你愿意让 ForgeRelay 操作的本地项目环境。
183
+ Hooks v1.2 有三个 canonical scope:当前 ForgeRelay 配置目录中的 `hooks/<hook-name>.json` User 规则、Project 根目录的 `.forgerelay/hooks/<hook-name>.json`,以及 ForgeRelay-private `projects/<project-id>/hooks/<hook-name>.json` Project Local 规则。Project Hook 属于可执行项目配置;v1.2.0 通过统一 Project trust seam 后采用 compatibility-allow。Allowed roots 仍只是文件系统/Workspace authority,不能描述成 Project Trust approval。
173
184
 
174
185
  每个独立 Hook 文件只声明一个 event、可选 matcher 和一个 command,以及 timeout/report。文件名只决定 Hook 名和排序,不能扩大 allowed roots、修改 OAuth 配置或删除全局规则。全局与项目规则采用组合关系。若某个项目 Hook 文件损坏,ForgeRelay 返回可见 diagnostic、跳过该无效文件并继续加载其他有效 Hook,同时保持工具可用,便于 Agent 修复。旧聚合格式仍兼容。
175
186
 
package/docs/setup.md CHANGED
@@ -8,7 +8,7 @@ projects through ForgeRelay.
8
8
  - Node `>=22.19 <27`
9
9
  - npm
10
10
  - Git
11
- - Bash, including Git Bash or WSL on Windows
11
+ - a supported Command Shell Runtime: Bash/zsh/POSIX sh on Unix-like systems, or PowerShell 7 / Windows PowerShell 5.1 / `cmd.exe` on Windows
12
12
  - a public HTTPS URL when the MCP host cannot connect directly to localhost
13
13
 
14
14
  ForgeRelay does not create the public tunnel for you. Use Cloudflare Tunnel,
@@ -22,8 +22,11 @@ Run:
22
22
  npx @akira-tl/forgerelay init
23
23
  ```
24
24
 
25
- The setup flow asks for the allowed project roots, local port, public domains,
26
- and an optional routed path prefix.
25
+ Basic setup asks only for the allowed project roots and how clients reach this ForgeRelay instance (local, SSH relay, direct LAN, or HTTPS proxy/tunnel). It asks connection-specific details only when that mode requires them.
26
+
27
+ Use `npx @akira-tl/forgerelay init --advanced` for the small set of common advanced choices: port, Command Shell Runtime, Runtime Shell Instructions opt-in, ForgeRelay-managed Language Servers, and whether Agents may install managed Language Servers on demand. Runtime Shell Instructions are disabled unless explicitly enabled.
28
+
29
+ `init --force` updates setup-owned fields only. It does not migrate legacy configuration or erase unrelated advanced settings.
27
30
 
28
31
  ### Project roots
29
32
 
@@ -123,12 +126,14 @@ Keep `auth.json` private.
123
126
 
124
127
  ```bash
125
128
  npx @akira-tl/forgerelay doctor
129
+ npx @akira-tl/forgerelay config check
130
+ npx @akira-tl/forgerelay config sources
131
+ npx @akira-tl/forgerelay config explain <logical-path>
126
132
  ```
127
133
 
128
- The doctor command reports the resolved config, Node runtime, platform, Git,
129
- Bash, public URL, allowed hosts, native SQLite dependency status, and the MCP
130
- shape ForgeRelay will expose: tool mode, widget mode, one-hop proxy trust, and
131
- whether optional artifact, subagent, and Skill capabilities are enabled.
134
+ `doctor` reports the runtime and deployment summary. Config v2's `check`, `sources`, and `explain` commands validate the selected scope and show provenance without executing Hooks, starting Language Servers/stdio MCP servers, or exposing resolved sensitive values.
135
+
136
+ ForgeRelay never rewrites old configuration during startup. Preview an explicit migration with `forgerelay config migrate --dry-run --global` or `--project <path>` before applying it. ForgeRelay-owned legacy sources remain compatible in v1.2.x and are removed in v1.4.0.
132
137
 
133
138
  ## Running from a local checkout
134
139
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akira-tl/forgerelay",
3
- "version": "1.1.2",
3
+ "version": "1.2.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",
@@ -24,6 +24,8 @@
24
24
  "examples",
25
25
  "scripts",
26
26
  "capabilities",
27
+ "templates",
28
+ "schemas",
27
29
  "README.md",
28
30
  "CHANGELOG.md",
29
31
  "NOTICE.md"
@@ -34,7 +36,9 @@
34
36
  },
35
37
  "scripts": {
36
38
  "clean": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
37
- "build": "npm run clean && npm run build:app && tsc -p tsconfig.build.json && node scripts/ensure-cli-executable.mjs",
39
+ "build": "npm run config:schema:check && npm run clean && npm run build:app && tsc -p tsconfig.build.json && node scripts/ensure-cli-executable.mjs",
40
+ "config:schema:generate": "node --import tsx scripts/config/schema.mjs write",
41
+ "config:schema:check": "node --import tsx scripts/config/schema.mjs check",
38
42
  "build:app": "vite build",
39
43
  "dev": "node scripts/debug/serve.mjs",
40
44
  "debug:serve": "node scripts/debug/serve.mjs",
@@ -48,9 +52,14 @@
48
52
  "powershell51:accept": "node scripts/ci/powershell51-acceptance.mjs",
49
53
  "cmd:accept": "node scripts/ci/cmd-acceptance.mjs",
50
54
  "windows:product-accept": "node scripts/ci/windows-product-acceptance.mjs",
55
+ "config:product-accept": "node scripts/ci/config-v2-product-acceptance.mjs",
51
56
  "wiki:check": "node scripts/wiki/sync.mjs check",
52
57
  "wiki:publish": "node scripts/wiki/sync.mjs publish",
53
58
  "architecture:check": "node scripts/ci/architecture.mjs",
59
+ "ci:contract": "node scripts/ci/gates/core-contract.mjs",
60
+ "ci:test-shard": "node scripts/ci/gates/test-shard.mjs",
61
+ "ci:platform-tests": "node scripts/ci/gates/platform-tests.mjs",
62
+ "ci:prepare-windows-product": "node scripts/ci/gates/prepare-windows-product.mjs",
54
63
  "ci:verify": "node scripts/ci/verify.mjs",
55
64
  "release:parity": "node scripts/release-parity.mjs",
56
65
  "release:pack": "node scripts/release/pack.mjs",
@@ -58,7 +67,7 @@
58
67
  "release:push-ready": "node scripts/release/push-ready.mjs",
59
68
  "postinstall": "node scripts/fix-node-pty-permissions.mjs",
60
69
  "start": "node dist/cli.js serve",
61
- "test": "node --test scripts/debug/runtime.test.mjs scripts/release-proof.test.mjs scripts/release/release-gate.test.mjs scripts/release/push-ready.test.mjs scripts/release/release-version.test.mjs && tsx src/mcp/oauth/router.test.ts && tsx src/workspaces/relay/auth/remote-auth-cli.test.ts && tsx src/workspaces/relay/auth/remote-ssh-auth-cli.test.ts && tsx src/workspaces/relay/tests/lifecycle.test.ts && tsx src/workspaces/relay/tests/routing.test.ts && tsx src/workspaces/relay/tests/ssh.test.ts && tsx src/workspaces/relay/tests/process.test.ts && tsx src/workspaces/relay/tests/recovery.test.ts && tsx src/workspaces/relay/tests/checkpoint.test.ts && tsx src/runtime/config/config.test.ts && tsx src/runtime/config/external-mcp-registry.test.ts && tsx src/runtime/config/external-mcp-auth-store.test.ts && tsx src/mcp/operations/external-mcp/external-mcp-oauth.test.ts && tsx src/cli/mcp/status.test.ts && tsx src/cli/mcp/diagnostics.test.ts && tsx src/cli/mcp/external-mcp.test.ts && tsx src/runtime/shell/command-shell-runtime.test.ts && tsx src/runtime/instructions/shell-instructions.test.ts && tsx src/runtime/instructions/powershell-skill.test.ts && tsx src/cli/shell/setup.test.ts && tsx src/lsp/language-server-config.test.ts && tsx src/lsp/runtime/managed-language-servers.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/runtime/logging/logger.test.ts && tsx src/runtime/logging/proxy-trust.test.ts && tsx src/runtime/state/lock/file-lock.test.ts && tsx src/runtime/state/runtime-lease.test.ts && tsx src/mcp/panel/mcp-app-template.test.ts && tsx src/mcp/hooks/hooks.test.ts && tsx src/mcp/server/core/capability-registry.test.ts && tsx src/mcp/server-instructions.test.ts && tsx src/mcp/request-context.test.ts && tsx src/mcp/request-meta.test.ts && tsx src/mcp/artifacts/incoming-artifacts.test.ts && tsx src/mcp/artifacts/artifact-download.test.ts && tsx src/ui/core/card-types.test.ts && tsx src/ui/activity/model.test.ts && tsx src/ui/activity/detail-card.test.ts && tsx src/ui/review/patch-display.test.ts && tsx src/ui/core/tool-display.test.ts && tsx src/mcp/filesystem/apply-patch.test.ts && tsx src/mcp/process/process-platform.test.ts && tsx src/mcp/process/process-sessions.test.ts && tsx src/mcp/server/transport/mcp-sessions.test.ts && tsx src/mcp/server/transport/server-shutdown.test.ts && tsx src/mcp/server/operations/mutation-diagnostics.test.ts && tsx src/mcp/server/operations/hooks.test.ts && tsx src/subagents/providers/adapters/codex.test.ts && tsx src/subagents/providers/adapters/pi.test.ts && tsx src/subagents/providers/registry.test.ts && tsx src/subagents/providers/availability.test.ts && tsx src/subagents/profiles.test.ts && tsx src/subagents/cli-target.test.ts && tsx src/subagents/sessions/store.test.ts && tsx src/subagents/sessions/manager.test.ts && tsx src/subagents/sessions/mcp/capability.server.test.ts && tsx src/subagents/sessions/mcp/continuation.server.test.ts && tsx src/subagents/sessions/mcp/lifecycle.server.test.ts && tsx src/subagents/sessions/mcp/reconciliation.server.test.ts && tsx src/subagents/sessions/mcp/routing.server.test.ts && tsx src/mcp/filesystem/roots.test.ts && tsx src/mcp/filesystem/file-mutations.test.ts && tsx src/mcp/operations/edit-preflight.test.ts && tsx src/workspaces/resources/skills.test.ts && tsx src/runtime/state/db/migrations.test.ts && tsx src/workspaces/state/workspace-store.test.ts && tsx src/workspaces/tasks/workspace-tasks.test.ts && tsx src/workspaces/tasks/workspace-task-reminders.test.ts && tsx src/activity/history/audit-store.test.ts && tsx src/activity/history/bash-output-store.test.ts && tsx src/activity/runtime/lifecycle.test.ts && tsx src/activity/history/query-service.test.ts && tsx src/mcp/operations/core-operation-executor.test.ts && tsx src/mcp/operations/bulk-mutation.test.ts && tsx src/mcp/operations/batch/scheduler.test.ts && tsx src/mcp/operations/batch/executor-policy.test.ts && tsx src/workspaces.test.ts && tsx src/workspaces/conversation-checkout.test.ts && tsx src/workspaces/conversation-worktree.test.ts && tsx src/workspaces/git/worktree-recovery.test.ts && tsx src/mcp/server/workspace/workspace-inventory.test.ts && tsx src/mcp/server/workspace/workspace-recovery.test.ts && tsx src/mcp/server/workspace/workspace-checkpoint.test.ts && tsx src/workspaces/review/review-checkpoints.test.ts && tsx src/lsp/code-intelligence.server.test.ts && npm run build:app && tsx src/mcp/process/server.test.ts && tsx src/mcp/panel/server.test.ts && tsx src/mcp/server/server.test.ts && tsx src/mcp/oauth/oauth-store.test.ts && tsx src/cli/maintenance.test.ts && tsx src/cli/maintenance-prune.test.ts && tsx src/cli/cli.test.ts",
70
+ "test": "node --test scripts/debug/runtime.test.mjs scripts/config/schema-text.test.mjs scripts/release-proof.test.mjs scripts/release/release-gate.test.mjs scripts/release/push-ready.test.mjs scripts/release/release-version.test.mjs && tsx src/mcp/oauth/router.test.ts && tsx src/workspaces/relay/auth/remote-auth-cli.test.ts && tsx src/workspaces/relay/auth/remote-ssh-auth-cli.test.ts && tsx src/workspaces/relay/tests/lifecycle.test.ts && tsx src/workspaces/relay/tests/routing.test.ts && tsx src/workspaces/relay/tests/ssh.test.ts && tsx src/workspaces/relay/tests/process.test.ts && tsx src/workspaces/relay/tests/recovery.test.ts && tsx src/workspaces/relay/tests/checkpoint.test.ts && tsx src/runtime/config/definition/schema.test.ts && tsx src/runtime/config/resolution/resolver.test.ts && tsx src/runtime/security/project-execution-trust.test.ts && tsx src/runtime/config/resolution/hooks.test.ts && tsx src/workspaces/state/project-context.test.ts && tsx src/runtime/config/config.test.ts && tsx src/runtime/config/external-mcp-registry.test.ts && tsx src/runtime/config/external-mcp-auth-store.test.ts && tsx src/mcp/operations/external-mcp/external-mcp-oauth.test.ts && tsx src/cli/mcp/status.test.ts && tsx src/cli/mcp/diagnostics.test.ts && tsx src/cli/mcp/external-mcp.test.ts && tsx src/runtime/shell/command-shell-runtime.test.ts && tsx src/runtime/instructions/shell-instructions.test.ts && tsx src/runtime/instructions/powershell-skill.test.ts && tsx src/cli/shell/setup.test.ts && tsx src/lsp/language-server-config.test.ts && tsx src/lsp/runtime/managed-language-servers.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/operations/project-trust.server.test.ts && tsx src/lsp/runtime/semantic-requests.test.ts && tsx src/runtime/logging/logger.test.ts && tsx src/runtime/logging/proxy-trust.test.ts && tsx src/runtime/state/lock/file-lock.test.ts && tsx src/runtime/state/runtime-lease.test.ts && tsx src/mcp/panel/mcp-app-template.test.ts && tsx src/mcp/hooks/hooks.test.ts && tsx src/mcp/hooks/hooks-trust.test.ts && tsx src/mcp/operations/external-mcp/external-mcp-transform.test.ts && tsx src/mcp/hooks/external-mcp-transform-trust.test.ts && tsx src/mcp/operations/external-mcp/external-mcp-trust.test.ts && tsx src/mcp/server/core/capability-registry.test.ts && tsx src/mcp/server-instructions.test.ts && tsx src/mcp/request-context.test.ts && tsx src/mcp/request-meta.test.ts && tsx src/mcp/artifacts/incoming-artifacts.test.ts && tsx src/mcp/artifacts/artifact-download.test.ts && tsx src/ui/core/card-types.test.ts && tsx src/ui/activity/model.test.ts && tsx src/ui/activity/detail-card.test.ts && tsx src/ui/review/patch-display.test.ts && tsx src/ui/core/tool-display.test.ts && tsx src/mcp/filesystem/apply-patch.test.ts && tsx src/mcp/process/process-platform.test.ts && tsx src/mcp/process/process-sessions.test.ts && tsx src/mcp/server/transport/mcp-sessions.test.ts && tsx src/mcp/server/transport/server-shutdown.test.ts && tsx src/mcp/server/operations/mutation-diagnostics.test.ts && tsx src/mcp/server/operations/hooks.test.ts && tsx src/subagents/providers/adapters/codex.test.ts && tsx src/subagents/providers/adapters/pi.test.ts && tsx src/subagents/providers/registry.test.ts && tsx src/subagents/providers/availability.test.ts && tsx src/subagents/profiles.test.ts && tsx src/subagents/cli-target.test.ts && tsx src/subagents/sessions/store.test.ts && tsx src/subagents/sessions/manager.test.ts && tsx src/subagents/sessions/project-trust.test.ts && tsx src/subagents/sessions/mcp/capability.server.test.ts && tsx src/subagents/sessions/mcp/continuation.server.test.ts && tsx src/subagents/sessions/mcp/lifecycle.server.test.ts && tsx src/subagents/sessions/mcp/reconciliation.server.test.ts && tsx src/subagents/sessions/mcp/routing.server.test.ts && tsx src/mcp/filesystem/roots.test.ts && tsx src/mcp/filesystem/file-mutations.test.ts && tsx src/mcp/operations/edit-preflight.test.ts && tsx src/workspaces/resources/skills.test.ts && tsx src/runtime/state/db/migrations.test.ts && tsx src/workspaces/state/workspace-store.test.ts && tsx src/workspaces/tasks/workspace-tasks.test.ts && tsx src/workspaces/tasks/workspace-task-reminders.test.ts && tsx src/activity/history/audit-store.test.ts && tsx src/activity/history/bash-output-store.test.ts && tsx src/activity/runtime/lifecycle.test.ts && tsx src/activity/history/query-service.test.ts && tsx src/mcp/operations/core-operation-executor.test.ts && tsx src/mcp/operations/bulk-mutation.test.ts && tsx src/mcp/operations/batch/scheduler.test.ts && tsx src/mcp/operations/batch/executor-policy.test.ts && tsx src/workspaces.test.ts && tsx src/workspaces/conversation-checkout.test.ts && tsx src/workspaces/conversation-worktree.test.ts && tsx src/workspaces/git/worktree-recovery.test.ts && tsx src/mcp/server/workspace/workspace-inventory.test.ts && tsx src/mcp/server/workspace/workspace-recovery.test.ts && tsx src/mcp/server/workspace/workspace-checkpoint.test.ts && tsx src/workspaces/review/review-checkpoints.test.ts && tsx src/lsp/code-intelligence.server.test.ts && npm run build:app && tsx src/mcp/process/server.test.ts && tsx src/mcp/panel/server.test.ts && tsx src/mcp/server/server.test.ts && tsx src/mcp/oauth/oauth-store.test.ts && tsx src/cli/maintenance.test.ts && tsx src/cli/maintenance-prune.test.ts && tsx src/cli/cli.test.ts",
62
71
  "typecheck": "tsc -p tsconfig.json --noEmit",
63
72
  "release:check": "node scripts/release-version.mjs check",
64
73
  "release:tag-check": "node scripts/release-version.mjs tag",
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "properties": {
5
+ "$schema": {
6
+ "description": "Editor-only JSON Schema URL. Ignored by ForgeRelay resolution.",
7
+ "type": "string"
8
+ }
9
+ },
10
+ "additionalProperties": false,
11
+ "$id": "https://raw.githubusercontent.com/Akira-TL/forgerelay/main/schemas/v1/config.project-local.schema.json",
12
+ "title": "ForgeRelay general configuration (project-local)",
13
+ "description": "Canonical ForgeRelay general configuration. Domain-specific MCP, Language Server, Hook, Subagent, and credential settings use separate sources."
14
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "type": "object",
4
+ "properties": {
5
+ "$schema": {
6
+ "description": "Editor-only JSON Schema URL. Ignored by ForgeRelay resolution.",
7
+ "type": "string"
8
+ }
9
+ },
10
+ "additionalProperties": false,
11
+ "$id": "https://raw.githubusercontent.com/Akira-TL/forgerelay/main/schemas/v1/config.project.schema.json",
12
+ "title": "ForgeRelay general configuration (project)",
13
+ "description": "Canonical ForgeRelay general configuration. Domain-specific MCP, Language Server, Hook, Subagent, and credential settings use separate sources."
14
+ }