@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.
- package/CHANGELOG.md +38 -0
- package/README.md +14 -0
- package/dist/activity/runtime/mcp-query-tools.js +15 -5
- package/dist/cli/config/inspect.js +331 -0
- package/dist/cli/config/migrate.js +351 -0
- package/dist/cli/init/setup-config.js +41 -0
- package/dist/cli/init.js +128 -130
- package/dist/cli/maintenance.js +15 -5
- package/dist/cli/mcp/external-mcp.js +14 -10
- package/dist/cli/mcp/status.js +11 -6
- package/dist/cli.js +40 -7
- package/dist/lsp/language-server-config.js +66 -144
- package/dist/lsp/runtime/manager.js +35 -4
- package/dist/mcp/hooks/config.js +141 -0
- package/dist/mcp/hooks/external-mcp-transform.js +22 -13
- package/dist/mcp/hooks/hook-cli.js +62 -52
- package/dist/mcp/hooks/hooks.js +111 -85
- package/dist/mcp/operations/external-mcp/external-mcp-runtime.js +8 -5
- package/dist/mcp/operations/external-mcp/external-mcp.js +9 -2
- package/dist/mcp/server/core/capability-support.js +7 -0
- package/dist/runtime/config/config.js +142 -64
- package/dist/runtime/config/definition/catalog.js +12 -0
- package/dist/runtime/config/definition/definition.js +115 -0
- package/dist/runtime/config/definition/external-mcp.js +58 -0
- package/dist/runtime/config/definition/general-config.js +258 -0
- package/dist/runtime/config/definition/language-servers.js +116 -0
- package/dist/runtime/config/definition/schema.js +113 -0
- package/dist/runtime/config/definition/types.js +2 -0
- package/dist/runtime/config/external-mcp-auth-store.js +105 -29
- package/dist/runtime/config/external-mcp-config.js +39 -0
- package/dist/runtime/config/external-mcp-registry.js +284 -106
- package/dist/runtime/config/inspection/live.js +77 -0
- package/dist/runtime/config/resolution/general.js +93 -0
- package/dist/runtime/config/resolution/hooks.js +315 -0
- package/dist/runtime/config/resolution/language-servers.js +237 -0
- package/dist/runtime/config/resolution/project-sources.js +159 -0
- package/dist/runtime/config/resolution/resolver.js +485 -0
- package/dist/runtime/config/resolution/types.js +1 -0
- package/dist/runtime/config/runtime/config-runtime.js +74 -0
- package/dist/runtime/config/runtime/source-refresh.js +263 -0
- package/dist/runtime/config/user-config.js +38 -31
- package/dist/runtime/security/project-execution-trust.js +34 -0
- package/dist/runtime/testing/server-fixture.js +9 -8
- package/dist/server.js +10 -6
- package/dist/subagents/profiles.js +336 -53
- package/dist/subagents/sessions/execution.js +6 -35
- package/dist/subagents/sessions/manager.js +14 -2
- package/dist/ui/.vite/manifest.json +275 -275
- package/dist/ui/activity-panel-app.html +1 -1
- package/dist/ui/assets/{activity-panel-app-Bw7ZFX2g.js → activity-panel-app-BeDiwd7D.js} +3 -3
- package/dist/ui/assets/{angular-html-DeUNP12X.js → angular-html-DuoCE7nn.js} +1 -1
- package/dist/ui/assets/{angular-ts-B3v8FKi_.js → angular-ts-D5tGk0hL.js} +1 -1
- package/dist/ui/assets/{apl-Bs3iQm4P.js → apl-lciOTPbw.js} +1 -1
- package/dist/ui/assets/{astro-D6GHecBY.js → astro-vJbqfNnJ.js} +1 -1
- package/dist/ui/assets/{blade-BMNbVOHv.js → blade-C7655Q4K.js} +1 -1
- package/dist/ui/assets/{c-BquuA6bv.js → c-DdHp1Jrw.js} +1 -1
- package/dist/ui/assets/{cobol-BuZ6kfps.js → cobol-DgvzQxZP.js} +1 -1
- package/dist/ui/assets/{coffee-DgC5uBzL.js → coffee-BIjVUOUd.js} +1 -1
- package/dist/ui/assets/{cpp-BdvWqCaB.js → cpp-CU8tGzvI.js} +1 -1
- package/dist/ui/assets/{crystal-0Q5qBvNI.js → crystal-CUQAwsg9.js} +1 -1
- package/dist/ui/assets/{css-Be_T8idh.js → css-DtMTqD3F.js} +1 -1
- package/dist/ui/assets/{edge-DaGLdgh_.js → edge-DoCX9RnL.js} +1 -1
- package/dist/ui/assets/{elixir-CMgiFIzB.js → elixir-DJxV9_U6.js} +1 -1
- package/dist/ui/assets/{elm-B-ufMlMC.js → elm-DIgWqK4r.js} +1 -1
- package/dist/ui/assets/{erb-CaGiOZM-.js → erb-BHxP0c_e.js} +1 -1
- package/dist/ui/assets/{git-rebase-CpwUWCzK.js → git-rebase-HbI_Vo8d.js} +1 -1
- package/dist/ui/assets/{glimmer-js-BRxccvnE.js → glimmer-js-CthY4Ty_.js} +1 -1
- package/dist/ui/assets/{glimmer-ts-CgQbPzlT.js → glimmer-ts-B2-_A1Xz.js} +1 -1
- package/dist/ui/assets/{glsl-D7JmHFr0.js → glsl-D9V9gq98.js} +1 -1
- package/dist/ui/assets/{graphql-C8n0eUBK.js → graphql-CddeAaS3.js} +1 -1
- package/dist/ui/assets/{hack-lVN7KVQv.js → hack-D_loGkOT.js} +1 -1
- package/dist/ui/assets/{haml-h18lG0pS.js → haml-BoWDczd0.js} +1 -1
- package/dist/ui/assets/{handlebars-lRFjRPfj.js → handlebars-ZoSOvw9y.js} +1 -1
- package/dist/ui/assets/{heavy-payload-Cqx9MOkH.js → heavy-payload-DO34LwoZ.js} +3 -3
- package/dist/ui/assets/{html-DtILqTE1.js → html-CE-obXVo.js} +1 -1
- package/dist/ui/assets/{html-derivative-CSTSmPup.js → html-derivative-Cd-smAbW.js} +1 -1
- package/dist/ui/assets/{http-DNI8fsbY.js → http-CZrkbrSl.js} +1 -1
- package/dist/ui/assets/{hurl-DgRi60JG.js → hurl-CxTuxBt1.js} +1 -1
- package/dist/ui/assets/{java-CW9pZ5bh.js → java-BshLjCat.js} +1 -1
- package/dist/ui/assets/{javascript-Cvg2UrWL.js → javascript-D2pxQTiX.js} +1 -1
- package/dist/ui/assets/{jinja-CZw_S1FB.js → jinja-kbfPP7-F.js} +1 -1
- package/dist/ui/assets/{jison-C56u_FZv.js → jison-C2mt9l1M.js} +1 -1
- package/dist/ui/assets/{json-DW2UTv1q.js → json-DU_rg_AU.js} +1 -1
- package/dist/ui/assets/{jsx-Zj5gobdD.js → jsx-D_8aQMlx.js} +1 -1
- package/dist/ui/assets/{julia-Cvcrre-L.js → julia-BmefTaVV.js} +1 -1
- package/dist/ui/assets/{just-8CZ2u6Tj.js → just-DXV8vk1S.js} +1 -1
- package/dist/ui/assets/{latex-D289AXWG.js → latex-Cjm2MvGW.js} +1 -1
- package/dist/ui/assets/{liquid-CFEX3SkZ.js → liquid-DyQDlo0u.js} +1 -1
- package/dist/ui/assets/{lua-BKpJ0ybO.js → lua-B2A1vzzy.js} +1 -1
- package/dist/ui/assets/{marko-D9maZ0a6.js → marko-B9vOkXOU.js} +1 -1
- package/dist/ui/assets/{mdc-rM9l0qWR.js → mdc-D42m6spU.js} +1 -1
- package/dist/ui/assets/{nginx-C9w6p2C9.js → nginx-TpfVxSUY.js} +1 -1
- package/dist/ui/assets/{nim-BRePHk0J.js → nim-CJr5T1FK.js} +1 -1
- package/dist/ui/assets/{perl-CskTmiPQ.js → perl-cJZcsdm9.js} +1 -1
- package/dist/ui/assets/{php-DCU_FvNI.js → php-CSZL5KRT.js} +1 -1
- package/dist/ui/assets/{pug-XLaVxTvv.js → pug-B1eMKzuA.js} +1 -1
- package/dist/ui/assets/{qml-CaONKSl-.js → qml-Dl2_7zc9.js} +1 -1
- package/dist/ui/assets/{r-BCVR0ZE3.js → r-F0aaO9gG.js} +1 -1
- package/dist/ui/assets/{razor-DDnGXxnU.js → razor-BPnkSMCw.js} +1 -1
- package/dist/ui/assets/{regexp-DWGTYYVx.js → regexp-BnGHMFbv.js} +1 -1
- package/dist/ui/assets/{rst-Dz3GWvQm.js → rst-B3CO7WYO.js} +1 -1
- package/dist/ui/assets/{ruby-DC3jGtMY.js → ruby-B6VMzT1T.js} +1 -1
- package/dist/ui/assets/{sas-7mNpvsjZ.js → sas-Df2lHVuU.js} +1 -1
- package/dist/ui/assets/{scss-uBsoCJVy.js → scss-4XxI6sgu.js} +1 -1
- package/dist/ui/assets/{shellscript-BCN9N_Jf.js → shellscript-DYASCN4r.js} +1 -1
- package/dist/ui/assets/{shellsession-Hsw46VXV.js → shellsession-Br6AGJO_.js} +1 -1
- package/dist/ui/assets/{soy-D6KV69HU.js → soy-p3ZNq1We.js} +1 -1
- package/dist/ui/assets/{sql-CVzVQkJh.js → sql-CAdv2OXL.js} +1 -1
- package/dist/ui/assets/{stata-BwUjXNhI.js → stata-Dx7yUbG_.js} +1 -1
- package/dist/ui/assets/{surrealql-CgloWqRa.js → surrealql-6YsE8HQa.js} +1 -1
- package/dist/ui/assets/{svelte-DcC3n6IC.js → svelte-YgzedwpD.js} +1 -1
- package/dist/ui/assets/{templ-DOFfnWTJ.js → templ-Bahqx3uD.js} +1 -1
- package/dist/ui/assets/{tex-ln89VPaX.js → tex-o6fTQjkH.js} +1 -1
- package/dist/ui/assets/{ts-tags-CWMzCstH.js → ts-tags-BO-Co0Ju.js} +1 -1
- package/dist/ui/assets/{tsx-DgzfiGeK.js → tsx-DtQe5AoH.js} +1 -1
- package/dist/ui/assets/{twig-Bi2itZL9.js → twig-BcUs6Kqc.js} +1 -1
- package/dist/ui/assets/{typescript-CQ24f4zW.js → typescript-BPtM8h4u.js} +1 -1
- package/dist/ui/assets/{vue-BS8jE5u6.js → vue-5KkGUzJJ.js} +1 -1
- package/dist/ui/assets/{vue-html-o38xqhyB.js → vue-html-Df_Xfsz9.js} +1 -1
- package/dist/ui/assets/{vue-vine-D2NvKv50.js → vue-vine-hUIe_u_Y.js} +1 -1
- package/dist/ui/assets/{xml-_44rx9_2.js → xml-C3Jy7as5.js} +1 -1
- package/dist/ui/assets/{xsl-B5QWQPoi.js → xsl-BnF9OuFo.js} +1 -1
- package/dist/ui/assets/{yaml-CKL2pEWe.js → yaml-DyrFgCou.js} +1 -1
- package/dist/workspaces/conversation-test-support.js +3 -11
- package/dist/workspaces/sessions.js +2 -0
- package/dist/workspaces/state/project-context.js +221 -0
- package/dist/workspaces.js +3 -1
- package/docs/chatgpt-coding-workflow.md +8 -3
- package/docs/configuration.md +99 -41
- package/docs/gotchas.md +24 -5
- package/docs/security.md +14 -3
- package/docs/setup.md +12 -7
- package/package.json +12 -3
- package/schemas/v1/config.project-local.schema.json +14 -0
- package/schemas/v1/config.project.schema.json +14 -0
- package/schemas/v1/config.user.schema.json +538 -0
- package/schemas/v1/hooks.project-local.schema.json +118 -0
- package/schemas/v1/hooks.project.schema.json +118 -0
- package/schemas/v1/hooks.user.schema.json +118 -0
- package/schemas/v1/language-servers.project-local.schema.json +230 -0
- package/schemas/v1/language-servers.project.schema.json +230 -0
- package/schemas/v1/language-servers.user.schema.json +230 -0
- package/schemas/v1/mcp.project-local.schema.json +143 -0
- package/schemas/v1/mcp.project.schema.json +143 -0
- package/schemas/v1/mcp.user.schema.json +143 -0
- package/scripts/ci/architecture.mjs +54 -4
- package/scripts/ci/cmd-acceptance.mjs +9 -9
- package/scripts/ci/config-v2-product-acceptance.mjs +639 -0
- package/scripts/ci/gates/acceptance-artifact.mjs +66 -0
- package/scripts/ci/gates/core-contract.mjs +27 -0
- package/scripts/ci/gates/platform-tests.mjs +38 -0
- package/scripts/ci/gates/prepare-windows-product.mjs +57 -0
- package/scripts/ci/gates/test-shard.mjs +71 -0
- package/scripts/ci/powershell51-acceptance.mjs +9 -9
- package/scripts/ci/pwsh-acceptance.mjs +9 -9
- package/scripts/ci/verify.mjs +2 -0
- package/scripts/ci/windows-product-acceptance.mjs +9 -10
- package/scripts/config/schema-text.mjs +4 -0
- package/scripts/config/schema-text.test.mjs +18 -0
- package/scripts/config/schema.mjs +74 -0
- package/scripts/lsp/interop.mjs +4 -1
- package/scripts/release/pack.mjs +64 -4
- package/scripts/release/release-gate.test.mjs +93 -27
- package/scripts/release-parity.mjs +19 -2
- package/templates/instructions/cmd.md +12 -0
- package/templates/instructions/fish.md +11 -0
- package/templates/instructions/powershell.md +14 -0
- package/templates/instructions/pwsh.md +14 -0
- package/templates/instructions/zsh.md +11 -0
- package/dist/runtime/instructions/powershell-skill.js +0 -65
|
@@ -40,33 +40,52 @@ test("optional release:verify records proof only after the cloud-equivalent pari
|
|
|
40
40
|
assert.equal(pkg.scripts["release:push-ready"], "node scripts/release/push-ready.mjs");
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
-
test("
|
|
43
|
+
test("Config schemas and ForgeRelay-owned runtime resources are gated in packaged verification", async () => {
|
|
44
|
+
const pkg = await readJson("package.json");
|
|
45
|
+
assert.ok(pkg.files.includes("schemas"));
|
|
46
|
+
assert.ok(pkg.files.includes("templates"));
|
|
47
|
+
assert.ok(pkg.files.includes("capabilities"));
|
|
48
|
+
assert.match(pkg.scripts.build, /config:schema:check/);
|
|
49
|
+
assert.equal(pkg.scripts["config:schema:generate"], "node --import tsx scripts/config/schema.mjs write");
|
|
50
|
+
assert.equal(pkg.scripts["config:schema:check"], "node --import tsx scripts/config/schema.mjs check");
|
|
51
|
+
assert.equal(pkg.scripts["config:product-accept"], "node scripts/ci/config-v2-product-acceptance.mjs");
|
|
52
|
+
|
|
53
|
+
const verify = await readFile(resolve(repoRoot, "scripts/ci/verify.mjs"), "utf8");
|
|
54
|
+
assert.match(verify, /\["run", "config:schema:check"\]/);
|
|
55
|
+
assert.match(verify, /\["run", "config:product-accept"\]/);
|
|
56
|
+
|
|
57
|
+
const pack = await readFile(resolve(repoRoot, "scripts/release/pack.mjs"), "utf8");
|
|
58
|
+
assert.match(pack, /schemas", "v1"/);
|
|
59
|
+
assert.match(pack, /release:pack omitted generated Config schemas/);
|
|
60
|
+
assert.match(pack, /templates/);
|
|
61
|
+
assert.match(pack, /capabilities/);
|
|
62
|
+
assert.match(pack, /release:pack omitted ForgeRelay-owned runtime resources/);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("cross-platform cloud CI splits shared tests from bounded platform acceptance", async () => {
|
|
44
66
|
const workflow = await readFile(resolve(repoRoot, ".github/workflows/ci.yml"), "utf8");
|
|
45
|
-
assert.match(workflow, /
|
|
46
|
-
assert.match(workflow, /
|
|
47
|
-
|
|
67
|
+
assert.match(workflow, /core-contract:/);
|
|
68
|
+
assert.match(workflow, /core-tests:/);
|
|
69
|
+
for (const shard of ["runtime-config", "workspace-mcp", "lsp", "subagent-ui-cli"]) {
|
|
70
|
+
assert.match(workflow, new RegExp(`\\b${shard}\\b`));
|
|
71
|
+
}
|
|
72
|
+
assert.match(workflow, /run:\s*npm run ci:contract/);
|
|
73
|
+
assert.match(workflow, /run:\s*npm run ci:test-shard -- \$\{\{ matrix\.shard \}\}/);
|
|
74
|
+
assert.match(workflow, /macos-platform:[\s\S]*run:\s*npm run ci:platform-tests/);
|
|
75
|
+
assert.match(workflow, /windows-platform:[\s\S]*run:\s*npm run ci:platform-tests/);
|
|
76
|
+
assert.match(workflow, /windows-platform:[\s\S]*timeout-minutes:\s*25/);
|
|
77
|
+
assert.doesNotMatch(workflow, /run:\s*npm run ci:verify/);
|
|
78
|
+
assert.doesNotMatch(workflow, /run:\s*npm test/);
|
|
48
79
|
assert.doesNotMatch(workflow, /shell:/);
|
|
49
80
|
assert.doesNotMatch(workflow, /run:\s*\|/);
|
|
50
|
-
for (const duplicatedCommand of [
|
|
51
|
-
"npm run release:check",
|
|
52
|
-
"npm run typecheck",
|
|
53
|
-
"npm test",
|
|
54
|
-
"npm run build",
|
|
55
|
-
"npm run lsp:interop",
|
|
56
|
-
"node dist/cli.js doctor",
|
|
57
|
-
]) {
|
|
58
|
-
assert.equal(
|
|
59
|
-
workflow.includes(`run: ${duplicatedCommand}`),
|
|
60
|
-
false,
|
|
61
|
-
`cloud CI must delegate ${duplicatedCommand} through ci:verify`,
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
81
|
});
|
|
65
82
|
|
|
66
|
-
test("architecture gate treats
|
|
83
|
+
test("architecture gate treats versioned public contract directories as explicit flat-path exceptions", async () => {
|
|
67
84
|
const architecture = await readFile(resolve(repoRoot, "scripts/ci/architecture.mjs"), "utf8");
|
|
68
85
|
assert.match(architecture, /DIRECT_FILE_LIMIT_EXEMPT_DIRS/);
|
|
69
86
|
assert.match(architecture, /"docs\/releases"/);
|
|
87
|
+
assert.match(architecture, /"schemas\/v1"/);
|
|
88
|
+
assert.match(architecture, /directory !== "\." && dirs > MAX_DIRECT_DIRS/);
|
|
70
89
|
});
|
|
71
90
|
|
|
72
91
|
test("release parity sandbox gives architecture an isolated non-empty Git index", async () => {
|
|
@@ -111,9 +130,6 @@ test("release runtime and local parity share the checked-in Node contract", asyn
|
|
|
111
130
|
const nodeVersion = (await readFile(resolve(repoRoot, ".nvmrc"), "utf8")).trim();
|
|
112
131
|
assert.equal(nodeVersion, "22.19.0");
|
|
113
132
|
|
|
114
|
-
const pkg = await readJson("package.json");
|
|
115
|
-
assert.equal(pkg.scripts["ci:verify"], "node scripts/ci/verify.mjs");
|
|
116
|
-
|
|
117
133
|
const source = await readFile(resolve(repoRoot, "scripts/release-parity.mjs"), "utf8");
|
|
118
134
|
assert.match(source, /readFileSync\(join\(repoRoot, "\.nvmrc"\), "utf8"\)/);
|
|
119
135
|
assert.match(source, /const NPM_VERSION = "11\.19\.1"/);
|
|
@@ -121,21 +137,67 @@ test("release runtime and local parity share the checked-in Node contract", asyn
|
|
|
121
137
|
const ciWorkflow = await readFile(resolve(repoRoot, ".github/workflows/ci.yml"), "utf8");
|
|
122
138
|
assert.match(ciWorkflow, /npm install --global npm@11\.19\.1/);
|
|
123
139
|
assert.ok(source.includes('["npm", "ci", "--no-audit", "--no-fund"]'));
|
|
124
|
-
assert.ok(source.includes('["npm", "run", "ci:
|
|
140
|
+
assert.ok(source.includes('["npm", "run", "ci:contract"]'));
|
|
141
|
+
for (const shard of ["runtime-config", "workspace-mcp", "lsp", "subagent-ui-cli"]) {
|
|
142
|
+
assert.match(source, new RegExp(`\\"${shard}\\"`));
|
|
143
|
+
}
|
|
144
|
+
assert.ok(source.includes('["npm", "run", "build"]'));
|
|
145
|
+
assert.ok(source.includes('["npm", "run", "traffic:audit"]'));
|
|
146
|
+
assert.ok(source.includes('["npm", "run", "lsp:interop"]'));
|
|
125
147
|
assert.ok(source.includes('["npm", "run", "release:pack"]'));
|
|
126
|
-
assert.
|
|
148
|
+
assert.ok(source.includes('["npm", "run", "config:product-accept"]'));
|
|
149
|
+
assert.match(source, /FORGERELAY_ACCEPTANCE_ARTIFACT_DIR:\s*"\.release-artifacts"/);
|
|
150
|
+
assert.doesNotMatch(source, /\["npm", "run", "ci:verify"\]/);
|
|
127
151
|
assert.doesNotMatch(source, /\["npm", "test"\]/);
|
|
128
152
|
});
|
|
129
153
|
|
|
130
|
-
test("cloud verification
|
|
154
|
+
test("cloud verification builds one npm artifact and reuses it across platform acceptance", async () => {
|
|
131
155
|
const workflow = await readFile(resolve(repoRoot, ".github/workflows/ci.yml"), "utf8");
|
|
132
|
-
assert.match(workflow, /
|
|
133
|
-
assert.match(
|
|
156
|
+
assert.match(workflow, /package:[\s\S]*needs:\s*core-contract[\s\S]*run:\s*npm run build[\s\S]*run:\s*npm run traffic:audit[\s\S]*run:\s*npm run lsp:interop[\s\S]*run:\s*npm run release:pack/);
|
|
157
|
+
assert.equal((workflow.match(/run:\s*npm run release:pack/g) ?? []).length, 1);
|
|
158
|
+
assert.equal((workflow.match(/uses:\s*actions\/upload-artifact@v7/g) ?? []).length, 1);
|
|
159
|
+
assert.equal((workflow.match(/uses:\s*actions\/download-artifact@v7/g) ?? []).length, 3);
|
|
160
|
+
assert.match(workflow, /FORGERELAY_ACCEPTANCE_ARTIFACT_DIR:\s*\.release-package/);
|
|
161
|
+
assert.match(workflow, /windows-platform:[\s\S]*FORGERELAY_ACCEPTANCE_PREFIX:\s*\.release-installed/);
|
|
162
|
+
assert.equal((workflow.match(/run:\s*npm run ci:prepare-windows-product/g) ?? []).length, 1);
|
|
163
|
+
assert.equal((workflow.match(/run:\s*npm run traffic:audit/g) ?? []).length, 1);
|
|
164
|
+
assert.equal((workflow.match(/run:\s*npm run lsp:interop/g) ?? []).length, 1);
|
|
134
165
|
assert.match(workflow, /name:\s*npm-package/);
|
|
135
166
|
assert.match(workflow, /include-hidden-files:\s*true/);
|
|
136
167
|
assert.match(workflow, /overwrite:\s*true/);
|
|
137
168
|
});
|
|
138
169
|
|
|
170
|
+
test("packaged acceptance scripts can consume the one downloaded release artifact", async () => {
|
|
171
|
+
const helper = await readFile(resolve(repoRoot, "scripts/ci/gates/acceptance-artifact.mjs"), "utf8");
|
|
172
|
+
assert.match(helper, /FORGERELAY_ACCEPTANCE_ARTIFACT_DIR/);
|
|
173
|
+
assert.match(helper, /FORGERELAY_ACCEPTANCE_PREFIX/);
|
|
174
|
+
assert.match(helper, /exactly one \.tgz package/);
|
|
175
|
+
|
|
176
|
+
const prepareWindows = await readFile(
|
|
177
|
+
resolve(repoRoot, "scripts/ci/gates/prepare-windows-product.mjs"),
|
|
178
|
+
"utf8",
|
|
179
|
+
);
|
|
180
|
+
assert.match(prepareWindows, /resolveAcceptancePrefix/);
|
|
181
|
+
assert.match(prepareWindows, /"install", "--global", "--prefix"/);
|
|
182
|
+
|
|
183
|
+
for (const relativePath of [
|
|
184
|
+
"scripts/ci/config-v2-product-acceptance.mjs",
|
|
185
|
+
"scripts/ci/windows-product-acceptance.mjs",
|
|
186
|
+
"scripts/ci/pwsh-acceptance.mjs",
|
|
187
|
+
"scripts/ci/powershell51-acceptance.mjs",
|
|
188
|
+
"scripts/ci/cmd-acceptance.mjs",
|
|
189
|
+
]) {
|
|
190
|
+
const source = await readFile(resolve(repoRoot, relativePath), "utf8");
|
|
191
|
+
assert.match(source, /resolveAcceptanceTarball/);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
test("Windows product acceptance uses the supported Skills environment seam rather than a removed config key", async () => {
|
|
196
|
+
const source = await readFile(resolve(repoRoot, "scripts/ci/windows-product-acceptance.mjs"), "utf8");
|
|
197
|
+
assert.match(source, /FORGERELAY_SKILLS:\s*"0"/);
|
|
198
|
+
assert.doesNotMatch(source, /skillsEnabled\s*:/);
|
|
199
|
+
});
|
|
200
|
+
|
|
139
201
|
test("release workflow is tag-only and promotes the verified npm artifact without rebuilding", async () => {
|
|
140
202
|
const workflow = await readFile(resolve(repoRoot, ".github/workflows/release.yml"), "utf8");
|
|
141
203
|
assert.doesNotMatch(workflow, /workflow_dispatch:/);
|
|
@@ -157,6 +219,10 @@ test("manual Windows shell acceptance can never publish a release", async () =>
|
|
|
157
219
|
);
|
|
158
220
|
assert.match(workflow, /workflow_dispatch:/);
|
|
159
221
|
assert.match(workflow, /runs-on:\s*windows-2022/);
|
|
222
|
+
assert.match(workflow, /FORGERELAY_ACCEPTANCE_ARTIFACT_DIR:\s*\.release-artifacts/);
|
|
223
|
+
assert.match(workflow, /FORGERELAY_ACCEPTANCE_PREFIX:\s*\.release-installed/);
|
|
224
|
+
assert.equal((workflow.match(/run:\s*npm run release:pack/g) ?? []).length, 1);
|
|
225
|
+
assert.equal((workflow.match(/run:\s*npm run ci:prepare-windows-product/g) ?? []).length, 1);
|
|
160
226
|
assert.match(workflow, /run:\s*npm run pwsh:accept/);
|
|
161
227
|
assert.doesNotMatch(workflow, /release:publish/);
|
|
162
228
|
assert.doesNotMatch(workflow, /npm publish/);
|
|
@@ -28,11 +28,28 @@ try {
|
|
|
28
28
|
["npm", "ci", "--no-audit", "--no-fund"],
|
|
29
29
|
`Node ${NODE_VERSION} / npm ${NPM_VERSION} install`,
|
|
30
30
|
);
|
|
31
|
-
runNodeNpm(sandbox, env, ["npm", "run", "ci:
|
|
31
|
+
runNodeNpm(sandbox, env, ["npm", "run", "ci:contract"], "Cloud core contract");
|
|
32
|
+
for (const shard of ["runtime-config", "workspace-mcp", "lsp", "subagent-ui-cli"]) {
|
|
33
|
+
runNodeNpm(
|
|
34
|
+
sandbox,
|
|
35
|
+
env,
|
|
36
|
+
["npm", "run", "ci:test-shard", "--", shard],
|
|
37
|
+
`Cloud core test shard: ${shard}`,
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
runNodeNpm(sandbox, env, ["npm", "run", "build"], "Cloud package build");
|
|
41
|
+
runNodeNpm(sandbox, env, ["npm", "run", "traffic:audit"], "Cloud traffic audit");
|
|
42
|
+
runNodeNpm(sandbox, env, ["npm", "run", "lsp:interop"], "Cloud LSP interoperability");
|
|
32
43
|
runNodeNpm(sandbox, env, ["npm", "run", "release:pack"], "Cloud release packaging");
|
|
44
|
+
runNodeNpm(
|
|
45
|
+
sandbox,
|
|
46
|
+
{ ...env, FORGERELAY_ACCEPTANCE_ARTIFACT_DIR: ".release-artifacts" },
|
|
47
|
+
["npm", "run", "config:product-accept"],
|
|
48
|
+
"Cloud Linux packaged product acceptance",
|
|
49
|
+
);
|
|
33
50
|
|
|
34
51
|
console.log(
|
|
35
|
-
`Release parity passed through
|
|
52
|
+
`Release parity passed through the split Linux cloud gates and release artifact acceptance on Node ${NODE_VERSION} / npm ${NPM_VERSION}.`,
|
|
36
53
|
);
|
|
37
54
|
} finally {
|
|
38
55
|
rmSync(sandbox, {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# ForgeRelay cmd.exe Instructions
|
|
2
|
+
|
|
3
|
+
ForgeRelay executes Agent commands and Hooks with `cmd.exe` for this runtime. Write cmd syntax, not PowerShell or Bash syntax.
|
|
4
|
+
|
|
5
|
+
- Environment variables use `%NAME%`; mutate them with cmd syntax such as `set NAME=value`.
|
|
6
|
+
- Preserve and inspect native process status with `%ERRORLEVEL%` when correctness depends on success.
|
|
7
|
+
- Command chaining, redirection, `%` expansion, `^` escaping, and parentheses are cmd-specific. Do not reuse Bash or PowerShell escaping rules.
|
|
8
|
+
- In compound or parenthesized command blocks, `%NAME%` may be expanded before later commands run. Use delayed expansion (`setlocal EnableDelayedExpansion` with `!NAME!`) only when needed, and remember that enabling it changes how literal `!` characters are handled.
|
|
9
|
+
- Quote executable paths and arguments using cmd semantics, especially when paths contain spaces or metacharacters.
|
|
10
|
+
- Do not emit PowerShell cmdlets such as `Get-ChildItem`, `$env:NAME`, or `&` unless explicitly launching PowerShell as a child process.
|
|
11
|
+
- Do not assume Unix aliases or utilities exist. Cross-platform executables such as `git`, `node`, `npm`, or `rg` may be invoked directly when installed.
|
|
12
|
+
- Do not silently switch to another shell merely because a command is easier there. The effective ForgeRelay command language remains cmd unless the owner changes the runtime configuration.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# ForgeRelay fish Instructions
|
|
2
|
+
|
|
3
|
+
ForgeRelay executes Agent commands and Hooks with fish for this runtime. Write fish syntax, not Bash or zsh syntax.
|
|
4
|
+
|
|
5
|
+
- Set shell variables with `set NAME value`; export environment variables with `set -gx NAME value` or another scope appropriate to the command.
|
|
6
|
+
- Inspect the previous command status with `$status`. Save it before another command runs if later logic depends on it.
|
|
7
|
+
- fish does not use Bash-style `VAR=value command`, `export NAME=value`, `$(...)`, or `[[ ... ]]` syntax. Use fish-native variable assignment, command substitution `(command)`, and conditionals.
|
|
8
|
+
- Use `and` / `or` or fish control flow deliberately; do not emit Bash-only chaining syntax when compatibility with the selected fish runtime matters.
|
|
9
|
+
- fish list variables and expansions differ from Bash arrays. Do not copy Bash array syntax.
|
|
10
|
+
- Quote paths and expansions when whitespace or wildcard interpretation would change the intended argument boundaries.
|
|
11
|
+
- ForgeRelay already inherits the server process environment. Do not source the user's interactive fish configuration, prompt, or plugins merely to recover PATH, aliases, or abbreviations.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# ForgeRelay Windows PowerShell 5.1 Instructions
|
|
2
|
+
|
|
3
|
+
ForgeRelay executes Agent commands and Hooks with Windows PowerShell 5.1 (`powershell.exe`) for this runtime. Use Windows PowerShell syntax, not Bash syntax and not PowerShell 7-only syntax.
|
|
4
|
+
|
|
5
|
+
- Environment variables use `$env:NAME`; do not use `export NAME=...`.
|
|
6
|
+
- Prefer explicit PowerShell cmdlets when semantics matter. Do not pass Unix flags to aliases such as `rm`, `ls`, or `cat`.
|
|
7
|
+
- Use `Get-Command` for command discovery and an explicit `.exe` name when native executable semantics matter.
|
|
8
|
+
- Use the call operator `&` for an executable stored in a variable or a quoted executable path.
|
|
9
|
+
- Windows PowerShell 5.1 does **not** support PowerShell 7 pipeline-chain operators `&&` and `||`. Use explicit control flow and inspect status instead.
|
|
10
|
+
- Native process success/failure is represented by `$LASTEXITCODE`; cmdlet errors use PowerShell error semantics. Do not conflate them.
|
|
11
|
+
- When cmdlet failure must stop execution, use terminating-error behavior deliberately rather than assuming every error terminates.
|
|
12
|
+
- Windows PowerShell 5.1 native argument parsing differs from modern PowerShell. Quote Windows paths and native arguments deliberately; do not copy Bash escaping rules.
|
|
13
|
+
- PowerShell pipelines pass objects between cmdlets. Be explicit when crossing into native executables.
|
|
14
|
+
- ForgeRelay inherits the server environment. Do not source the user's PowerShell profile merely to recover PATH, aliases, modules, or prompt configuration.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# ForgeRelay PowerShell 7 Instructions
|
|
2
|
+
|
|
3
|
+
ForgeRelay executes Agent commands and Hooks with PowerShell 7 (`pwsh`) for this runtime. Use PowerShell syntax, not Bash syntax.
|
|
4
|
+
|
|
5
|
+
- Environment variables use `$env:NAME`; do not use `export NAME=...`.
|
|
6
|
+
- Prefer explicit PowerShell cmdlets when semantics matter. Do not pass Unix flags to aliases such as `rm`, `ls`, or `cat`.
|
|
7
|
+
- Use `Get-Command` to discover commands. Use an explicit `.exe` name when native executable semantics matter.
|
|
8
|
+
- Use the call operator `&` for an executable stored in a variable or for a quoted executable path.
|
|
9
|
+
- Quote Windows paths deliberately. Do not copy Bash escaping rules into PowerShell native-command arguments.
|
|
10
|
+
- Native program success/failure is represented by `$LASTEXITCODE`; PowerShell cmdlet errors use PowerShell error semantics. Do not conflate the two.
|
|
11
|
+
- When cmdlet failure must stop the command, use terminating-error behavior deliberately rather than assuming every error terminates execution.
|
|
12
|
+
- PowerShell pipelines pass objects between cmdlets. Be explicit when crossing between object pipelines and native executables.
|
|
13
|
+
- PowerShell 7 supports pipeline-chain operators such as `&&` and `||`, but use them only when the reported runtime version supports them.
|
|
14
|
+
- ForgeRelay already inherits the server process environment. Do not source the user's PowerShell profile merely to recover PATH, aliases, modules, or prompt configuration.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# ForgeRelay zsh Instructions
|
|
2
|
+
|
|
3
|
+
ForgeRelay executes Agent commands and Hooks with zsh for this runtime. Use zsh syntax deliberately rather than assuming every Bash-specific construct behaves identically.
|
|
4
|
+
|
|
5
|
+
- Environment variables are exported with zsh/POSIX syntax such as `export NAME=value`; shell-local variables do not need `export`.
|
|
6
|
+
- Inspect command success with `$?` when it is needed, and preserve the relevant status before running another command.
|
|
7
|
+
- Quote parameter expansions unless zsh-specific splitting or globbing is intentionally required. Do not depend on Bash-only word-splitting behavior.
|
|
8
|
+
- zsh arrays are 1-indexed by default and have zsh-specific expansion semantics. Do not copy Bash array expressions without checking them.
|
|
9
|
+
- Use zsh conditionals, glob qualifiers, and parameter-expansion features only when they make the command clearer; prefer portable command-line tools when shell-specific syntax is unnecessary.
|
|
10
|
+
- Do not assume Bash-only builtins or options such as `shopt` exist.
|
|
11
|
+
- ForgeRelay already inherits the server process environment. Do not source the user's `.zshrc`, Oh My Zsh, prompt theme, plugins, or interactive profile merely to recover PATH or aliases.
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { constants as fsConstants } from "node:fs";
|
|
2
|
-
import { access, mkdir, writeFile } from "node:fs/promises";
|
|
3
|
-
import { join, resolve } from "node:path";
|
|
4
|
-
const TEMPLATE_REPOSITORY_RAW = "https://raw.githubusercontent.com/Akira-TL/forgerelay";
|
|
5
|
-
const POWERSHELL_SKILL_PATH = "templates/skills/powershell/SKILL.md";
|
|
6
|
-
export function powerShellSkillPath(configDir) {
|
|
7
|
-
return join(resolve(configDir), "skills", "powershell", "SKILL.md");
|
|
8
|
-
}
|
|
9
|
-
export function powerShellSkillTemplateUrl(version) {
|
|
10
|
-
const normalizedVersion = version.trim().replace(/^v/, "");
|
|
11
|
-
if (!normalizedVersion)
|
|
12
|
-
throw new Error("ForgeRelay version is required to fetch the PowerShell Skill.");
|
|
13
|
-
return `${TEMPLATE_REPOSITORY_RAW}/v${encodeURIComponent(normalizedVersion)}/${POWERSHELL_SKILL_PATH}`;
|
|
14
|
-
}
|
|
15
|
-
export async function seedPowerShellSkill(options) {
|
|
16
|
-
const path = powerShellSkillPath(options.configDir);
|
|
17
|
-
const sourceUrl = powerShellSkillTemplateUrl(options.version);
|
|
18
|
-
if (!options.reset && await fileExists(path)) {
|
|
19
|
-
return { path, status: "preserved", sourceUrl };
|
|
20
|
-
}
|
|
21
|
-
await mkdir(join(resolve(options.configDir), "skills", "powershell"), {
|
|
22
|
-
recursive: true,
|
|
23
|
-
mode: 0o700,
|
|
24
|
-
});
|
|
25
|
-
const fetchText = options.fetchText ?? fetchSkillText;
|
|
26
|
-
try {
|
|
27
|
-
const content = await fetchText(sourceUrl);
|
|
28
|
-
if (!content.trim())
|
|
29
|
-
throw new Error("template response was empty");
|
|
30
|
-
await writeFile(path, content.endsWith("\n") ? content : `${content}\n`, {
|
|
31
|
-
encoding: "utf8",
|
|
32
|
-
mode: 0o600,
|
|
33
|
-
flag: options.reset ? "w" : "wx",
|
|
34
|
-
});
|
|
35
|
-
return { path, status: "created", sourceUrl };
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
if (!options.reset && await fileExists(path)) {
|
|
39
|
-
return { path, status: "preserved", sourceUrl };
|
|
40
|
-
}
|
|
41
|
-
return {
|
|
42
|
-
path,
|
|
43
|
-
status: "failed",
|
|
44
|
-
sourceUrl,
|
|
45
|
-
error: error instanceof Error ? error.message : String(error),
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
async function fetchSkillText(url) {
|
|
50
|
-
const response = await fetch(url, {
|
|
51
|
-
headers: { "user-agent": "forgerelay-powershell-skill" },
|
|
52
|
-
});
|
|
53
|
-
if (!response.ok)
|
|
54
|
-
throw new Error(`HTTP ${response.status} while fetching ${url}`);
|
|
55
|
-
return response.text();
|
|
56
|
-
}
|
|
57
|
-
async function fileExists(path) {
|
|
58
|
-
try {
|
|
59
|
-
await access(path, fsConstants.F_OK);
|
|
60
|
-
return true;
|
|
61
|
-
}
|
|
62
|
-
catch {
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
}
|