@akira-tl/forgerelay 0.5.6 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +7 -3
  3. package/capabilities/host-integration/GUIDE.md +15 -9
  4. package/dist/activity/host-turn-store.js +9 -7
  5. package/dist/activity/lifecycle.js +1 -1
  6. package/dist/activity/mcp-query-tools.js +110 -18
  7. package/dist/activity/query-service.js +4 -4
  8. package/dist/activity/ui/contract.js +2 -0
  9. package/dist/cli.js +47 -32
  10. package/dist/config.js +31 -3
  11. package/dist/db/migrations.js +30 -0
  12. package/dist/db/schema.js +2 -0
  13. package/dist/logger.js +6 -5
  14. package/dist/lsp/test-support/server-fixture.js +1 -1
  15. package/dist/mcp/server-instructions.js +7 -6
  16. package/dist/mcp-app-template.js +108 -12
  17. package/dist/oauth/public-url.js +14 -0
  18. package/dist/oauth/router.js +49 -0
  19. package/dist/process-sessions.js +2 -1
  20. package/dist/request-meta.js +4 -0
  21. package/dist/server.js +250 -84
  22. package/dist/skills.js +58 -1
  23. package/dist/ui/.vite/manifest.json +360 -312
  24. package/dist/ui/activity-panel-app.html +17 -0
  25. package/dist/ui/assets/activity-panel-app-CjZVvVNc.js +2 -0
  26. package/dist/ui/assets/angular-html-BkgDQl-G.js +1 -0
  27. package/dist/ui/assets/{angular-ts-BwPE8YDt.js → angular-ts-Bxh4-O1-.js} +1 -1
  28. package/dist/ui/assets/{apl-CGbONVvU.js → apl-BmYHKQ6m.js} +1 -1
  29. package/dist/ui/assets/{astro-DIAPy7cj.js → astro-C51vqDKq.js} +1 -1
  30. package/dist/ui/assets/{blade-Cgtd19Ky.js → blade-CdhVsmwq.js} +1 -1
  31. package/dist/ui/assets/c-IBzBpxAO.js +1 -0
  32. package/dist/ui/assets/chunk-EyZ2wyi3.js +1 -0
  33. package/dist/ui/assets/{cobol-G-7HLVKW.js → cobol-Cf6azoN_.js} +1 -1
  34. package/dist/ui/assets/{coffee-DQFyKxEB.js → coffee-vVdGzlmt.js} +1 -1
  35. package/dist/ui/assets/cpp-CVHeO-Jk.js +1 -0
  36. package/dist/ui/assets/{crystal-DuiWhEO3.js → crystal-5UZy6KIX.js} +1 -1
  37. package/dist/ui/assets/css-DEfus9J5.js +1 -0
  38. package/dist/ui/assets/{edge-COkalhFi.js → edge-CESgo4ia.js} +1 -1
  39. package/dist/ui/assets/{elixir-cdlzbYR1.js → elixir-9FKfw4cJ.js} +1 -1
  40. package/dist/ui/assets/{elm-ZwDYuYpb.js → elm-Dv7A0aLa.js} +1 -1
  41. package/dist/ui/assets/{erb-C8WG9TtC.js → erb-DHFmDvM0.js} +1 -1
  42. package/dist/ui/assets/{git-rebase-CMlDVJBT.js → git-rebase-utbU6CzV.js} +1 -1
  43. package/dist/ui/assets/{glimmer-js-DeLOQlol.js → glimmer-js-t2kiCkyB.js} +1 -1
  44. package/dist/ui/assets/{glimmer-ts-DTEM04TK.js → glimmer-ts-F0Jv5okV.js} +1 -1
  45. package/dist/ui/assets/glsl-_ooCjaeB.js +1 -0
  46. package/dist/ui/assets/graphql-B9LqP-cY.js +1 -0
  47. package/dist/ui/assets/{hack-C14sh6Lh.js → hack-8yjdbaSA.js} +1 -1
  48. package/dist/ui/assets/haml-BU5EoZBn.js +1 -0
  49. package/dist/ui/assets/{handlebars-eS-J0O-M.js → handlebars-BBFEg4Lo.js} +1 -1
  50. package/dist/ui/assets/{heavy-payload-BKB0QDOI.js → heavy-payload-vGgBRvNX.js} +1 -1
  51. package/dist/ui/assets/html-D-C6YZk4.js +1 -0
  52. package/dist/ui/assets/{html-derivative-BlVZU2id.js → html-derivative-DJAQcZyc.js} +1 -1
  53. package/dist/ui/assets/{http-BmbZzA5x.js → http-Dg5LSYRK.js} +1 -1
  54. package/dist/ui/assets/{hurl-Dnd_YpOD.js → hurl-Y5uYzMZR.js} +1 -1
  55. package/dist/ui/assets/java-ppHvycj5.js +1 -0
  56. package/dist/ui/assets/javascript-DDTjKLlQ.js +1 -0
  57. package/dist/ui/assets/{jinja-DTvkZdHA.js → jinja-Bt30h8Ik.js} +1 -1
  58. package/dist/ui/assets/{jison-DUJG-tmh.js → jison-D5uZ1Nyo.js} +1 -1
  59. package/dist/ui/assets/json-Cw91r8h1.js +1 -0
  60. package/dist/ui/assets/jsx-04X2FT_1.js +1 -0
  61. package/dist/ui/assets/{julia-P5B4pHFa.js → julia-76hRaaGz.js} +1 -1
  62. package/dist/ui/assets/{just-DYaoh7C6.js → just-CDE7W0vW.js} +1 -1
  63. package/dist/ui/assets/{latex-CI5lnkWV.js → latex-CVO2Byab.js} +1 -1
  64. package/dist/ui/assets/{liquid-D3LnAs_z.js → liquid-CA-AS3EX.js} +1 -1
  65. package/dist/ui/assets/lua-CiyBp52Y.js +1 -0
  66. package/dist/ui/assets/{marko-CRDrjqfS.js → marko-_BWrPfny.js} +1 -1
  67. package/dist/ui/assets/{mdc-ZzwgmJVn.js → mdc-PyJv85eS.js} +1 -1
  68. package/dist/ui/assets/{nginx-BAvFXGSV.js → nginx-DAWVw8yu.js} +1 -1
  69. package/dist/ui/assets/{nim-BHIFawe9.js → nim-CKE1dzpU.js} +1 -1
  70. package/dist/ui/assets/{perl-C_f5AnLa.js → perl-BBhWva19.js} +1 -1
  71. package/dist/ui/assets/{php-DDqpegL5.js → php-ChIeaAoF.js} +1 -1
  72. package/dist/ui/assets/{pug-CSaAZXyd.js → pug-CMgI5afi.js} +1 -1
  73. package/dist/ui/assets/{qml-CNHvRs_z.js → qml-CjxTkcFH.js} +1 -1
  74. package/dist/ui/assets/r-DfFga4si.js +1 -0
  75. package/dist/ui/assets/{razor-BDfAPy7I.js → razor-i4DbHr8p.js} +1 -1
  76. package/dist/ui/assets/regexp-iC9_nbSI.js +1 -0
  77. package/dist/ui/assets/{review-payload-D7GIdYDj.js → review-payload-4erWKckt.js} +1 -1
  78. package/dist/ui/assets/{rst-BzPP2gle.js → rst-oy_97Kl4.js} +1 -1
  79. package/dist/ui/assets/{ruby-CQjzokzX.js → ruby-C5zYZIyl.js} +1 -1
  80. package/dist/ui/assets/{sas-Bp37KGr7.js → sas-BnMEh2S3.js} +1 -1
  81. package/dist/ui/assets/{scrollbar-HUMBdLLK.js → scrollbar-CaOPzUJd.js} +6 -6
  82. package/dist/ui/assets/scss-BfZXsAWQ.js +1 -0
  83. package/dist/ui/assets/shellscript-BC2srNaB.js +1 -0
  84. package/dist/ui/assets/{shellsession-CNc62UhY.js → shellsession-BpE5o7_3.js} +1 -1
  85. package/dist/ui/assets/{soy-CF44SpBo.js → soy-COesmhTY.js} +1 -1
  86. package/dist/ui/assets/sql-Ccv_yeUm.js +1 -0
  87. package/dist/ui/assets/{stata-DVeMA68W.js → stata-CGQEuSZq.js} +1 -1
  88. package/dist/ui/assets/{surrealql-52sF96Yv.js → surrealql-Bz4JbU-9.js} +1 -1
  89. package/dist/ui/assets/{svelte-ydwT7UbF.js → svelte-1jM2ejXj.js} +1 -1
  90. package/dist/ui/assets/{templ-BXcoVoGh.js → templ-C-VwELcp.js} +1 -1
  91. package/dist/ui/assets/{tex-COsYFp7O.js → tex-t1rUiQCm.js} +1 -1
  92. package/dist/ui/assets/{ts-tags-CF--LE1s.js → ts-tags-Bewoa6pS.js} +1 -1
  93. package/dist/ui/assets/tsx-CTXzrBkN.js +1 -0
  94. package/dist/ui/assets/{twig-YoM-DiI5.js → twig-DVg-vELl.js} +1 -1
  95. package/dist/ui/assets/typescript--ElHoFkw.js +1 -0
  96. package/dist/ui/assets/{vue-html-CPdGGk4T.js → vue-html-BHtJ8geX.js} +1 -1
  97. package/dist/ui/assets/{vue-vine-B5bjgk0a.js → vue-vine-CNSGAWwc.js} +1 -1
  98. package/dist/ui/assets/{vue-B5LDEy4l.js → vue-wPQ7UlMy.js} +1 -1
  99. package/dist/ui/assets/workspace-app-CcrHAUIn.css +1 -0
  100. package/dist/ui/assets/workspace-app-DJmkPYJC.js +1 -0
  101. package/dist/ui/assets/workspace-app-DkAiSl_0.js +111 -0
  102. package/dist/ui/assets/workspace-app-QyauBrJX.js +5 -0
  103. package/dist/ui/assets/workspace-lifecycle-app-BIXEo53I.js +1 -0
  104. package/dist/ui/assets/xml-JnmX6vyS.js +1 -0
  105. package/dist/ui/assets/{xsl-wls_CEK_.js → xsl-3_vJ27aE.js} +1 -1
  106. package/dist/ui/assets/yaml-OAcZkP-w.js +1 -0
  107. package/dist/ui/workspace-app.html +5 -2
  108. package/dist/ui/workspace-lifecycle-app.html +18 -0
  109. package/dist/workspaces.js +11 -0
  110. package/docs/configuration.md +36 -4
  111. package/docs/debugging.md +75 -17
  112. package/docs/gotchas.md +15 -9
  113. package/docs/setup.md +24 -10
  114. package/package.json +4 -3
  115. package/scripts/debug/accept.mjs +79 -27
  116. package/scripts/debug/host/run.sh +180 -0
  117. package/scripts/debug/host/serve.mjs +64 -0
  118. package/scripts/debug/runtime.mjs +57 -2
  119. package/scripts/debug/runtime.test.mjs +74 -0
  120. package/scripts/debug/serve.mjs +4 -5
  121. package/scripts/dev-server.mjs +32 -3
  122. package/scripts/release/release-gate.test.mjs +43 -0
  123. package/scripts/release/release-version.test.mjs +107 -0
  124. package/scripts/release-parity.mjs +70 -46
  125. package/scripts/release-proof.mjs +2 -2
  126. package/scripts/release-proof.test.mjs +18 -0
  127. package/scripts/release-version.mjs +17 -8
  128. package/dist/ui/assets/angular-html-BT2Z6jee.js +0 -1
  129. package/dist/ui/assets/c-acnvZ8tm.js +0 -1
  130. package/dist/ui/assets/cpp-UyrmHXan.js +0 -1
  131. package/dist/ui/assets/css-D_WCbY6m.js +0 -1
  132. package/dist/ui/assets/glsl-IJV4SB-M.js +0 -1
  133. package/dist/ui/assets/graphql-PM-WDnoB.js +0 -1
  134. package/dist/ui/assets/haml-B_5nS6Kx.js +0 -1
  135. package/dist/ui/assets/html-C3TPjrC5.js +0 -1
  136. package/dist/ui/assets/java-ne9HdIVn.js +0 -1
  137. package/dist/ui/assets/javascript-DpHT58rr.js +0 -1
  138. package/dist/ui/assets/json-DJmnBdxW.js +0 -1
  139. package/dist/ui/assets/jsx-BclJnZnN.js +0 -1
  140. package/dist/ui/assets/lua-dZC7ZQIY.js +0 -1
  141. package/dist/ui/assets/r-CAfoQND2.js +0 -1
  142. package/dist/ui/assets/regexp-Mug5jltQ.js +0 -1
  143. package/dist/ui/assets/scss-C_Z1DYnw.js +0 -1
  144. package/dist/ui/assets/shellscript-CLfJpn3I.js +0 -1
  145. package/dist/ui/assets/sql-CYnzfiQ1.js +0 -1
  146. package/dist/ui/assets/tsx-DLBt2-2f.js +0 -1
  147. package/dist/ui/assets/typescript-Ce9JGkNI.js +0 -1
  148. package/dist/ui/assets/workspace-app-Cm9EX5x4.js +0 -117
  149. package/dist/ui/assets/workspace-app-DHvE2ojW.css +0 -1
  150. package/dist/ui/assets/xml-Cun8xb0T.js +0 -1
  151. package/dist/ui/assets/yaml-BxuXn9OL.js +0 -1
  152. package/scripts/release/tag-local-ci.mjs +0 -144
@@ -0,0 +1,43 @@
1
+ import assert from "node:assert/strict";
2
+ import { readFile } from "node:fs/promises";
3
+ import { dirname, resolve } from "node:path";
4
+ import test from "node:test";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "../..");
8
+
9
+ async function readJson(relativePath) {
10
+ return JSON.parse(await readFile(resolve(repoRoot, relativePath), "utf8"));
11
+ }
12
+
13
+ test("release tag Hook is a fast proof gate, not a multi-minute CI runner", async () => {
14
+ const hook = await readJson(".forgerelay/hooks/release-tag-local-ci.json");
15
+ assert.equal(hook.event, "BeforeTool");
16
+ assert.equal(hook.command, "node scripts/release-proof.mjs check-hook");
17
+ assert.ok(hook.timeoutSeconds <= 30);
18
+ });
19
+
20
+ test("release:verify records proof only after the cloud-equivalent parity gate", async () => {
21
+ const pkg = await readJson("package.json");
22
+ assert.equal(
23
+ pkg.scripts["release:verify"],
24
+ "npm run release:parity && node scripts/release-proof.mjs write",
25
+ );
26
+ });
27
+
28
+ test("release parity mirrors the cloud CI command surface on Node 22.19 and npm 10.9", async () => {
29
+ const source = await readFile(resolve(repoRoot, "scripts/release-parity.mjs"), "utf8");
30
+ assert.match(source, /const NODE_VERSION = "22\.19\.0"/);
31
+ assert.match(source, /const NPM_VERSION = "10\.9\.3"/);
32
+ for (const command of [
33
+ '["npm", "ci", "--no-audit", "--no-fund"]',
34
+ '["npm", "run", "release:check"]',
35
+ '["npm", "run", "typecheck"]',
36
+ '["npm", "test"]',
37
+ '["npm", "run", "build"]',
38
+ '["npm", "run", "lsp:interop"]',
39
+ '["dist/cli.js", "doctor"]',
40
+ ]) {
41
+ assert.ok(source.includes(command), `release parity is missing ${command}`);
42
+ }
43
+ });
@@ -0,0 +1,107 @@
1
+ import assert from "node:assert/strict";
2
+ import { execFile } from "node:child_process";
3
+ import { cp, mkdtemp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
4
+ import { tmpdir } from "node:os";
5
+ import { dirname, join } from "node:path";
6
+ import test from "node:test";
7
+ import { fileURLToPath } from "node:url";
8
+ import { promisify } from "node:util";
9
+
10
+ const execFileAsync = promisify(execFile);
11
+ const sourceScript = fileURLToPath(new URL("../release-version.mjs", import.meta.url));
12
+
13
+ async function createFixture(t) {
14
+ const root = await mkdtemp(join(tmpdir(), "forgerelay-release-version-"));
15
+ t.after(() => rm(root, { recursive: true, force: true }));
16
+ await mkdir(join(root, "scripts"), { recursive: true });
17
+ await cp(sourceScript, join(root, "scripts", "release-version.mjs"));
18
+
19
+ const pkg = {
20
+ name: "@akira-tl/forgerelay",
21
+ version: "0.5.7",
22
+ repository: { type: "git", url: "git+https://github.com/Akira-TL/forgerelay.git" },
23
+ homepage: "https://github.com/Akira-TL/forgerelay#readme",
24
+ bugs: { url: "https://github.com/Akira-TL/forgerelay/issues" },
25
+ publishConfig: { access: "public", tag: "latest" },
26
+ bin: { forgerelay: "dist/cli.js" },
27
+ files: ["NOTICE.md"],
28
+ };
29
+ const lock = {
30
+ name: pkg.name,
31
+ version: pkg.version,
32
+ lockfileVersion: 3,
33
+ packages: {
34
+ "": {
35
+ name: pkg.name,
36
+ version: pkg.version,
37
+ },
38
+ },
39
+ };
40
+
41
+ await Promise.all([
42
+ writeFile(join(root, "package.json"), `${JSON.stringify(pkg, null, 2)}\n`),
43
+ writeFile(join(root, "package-lock.json"), `${JSON.stringify(lock, null, 2)}\n`),
44
+ writeFile(join(root, "CHANGELOG.md"), [
45
+ "# Changelog",
46
+ "",
47
+ "## [Unreleased]",
48
+ "",
49
+ "### Added",
50
+ "",
51
+ "- Release candidate behavior.",
52
+ "",
53
+ "## [0.5.7] - 2026-08-19",
54
+ "",
55
+ "### Fixed",
56
+ "",
57
+ "- Previous release.",
58
+ "",
59
+ ].join("\n")),
60
+ writeFile(join(root, "NOTICE.md"), "https://github.com/Waishnav/devspace\nindependently maintained by Akira-TL\n"),
61
+ writeFile(join(root, "LICENSE"), "Copyright (c) 2026 Waishnav\nCopyright (c) 2026 Akira-TL, modifications\n"),
62
+ ]);
63
+
64
+ return root;
65
+ }
66
+
67
+ async function runRelease(root, ...args) {
68
+ return execFileAsync(process.execPath, [join(root, "scripts", "release-version.mjs"), ...args], {
69
+ cwd: root,
70
+ });
71
+ }
72
+
73
+ test("release version tooling prepares and validates an rc release", async (t) => {
74
+ const root = await createFixture(t);
75
+
76
+ const prepared = await runRelease(root, "prepare", "0.6.0-rc.1");
77
+ assert.match(prepared.stdout, /0\.5\.7 -> 0\.6\.0-rc\.1/);
78
+
79
+ const pkg = JSON.parse(await readFile(join(root, "package.json"), "utf8"));
80
+ const lock = JSON.parse(await readFile(join(root, "package-lock.json"), "utf8"));
81
+ const changelog = await readFile(join(root, "CHANGELOG.md"), "utf8");
82
+ assert.equal(pkg.version, "0.6.0-rc.1");
83
+ assert.equal(lock.version, "0.6.0-rc.1");
84
+ assert.equal(lock.packages[""].version, "0.6.0-rc.1");
85
+ assert.match(changelog, /## \[0\.6\.0-rc\.1\] - \d{4}-\d{2}-\d{2}/);
86
+ assert.match(changelog, /### Added\n\n- Release candidate behavior\./);
87
+
88
+ const checked = await runRelease(root, "check");
89
+ assert.match(checked.stdout, /release metadata is consistent at 0\.6\.0-rc\.1/);
90
+
91
+ const tagged = await runRelease(root, "tag", "v0.6.0-rc.1");
92
+ assert.match(tagged.stdout, /release tag v0\.6\.0-rc\.1 matches package version and changelog/);
93
+
94
+ const notes = await runRelease(root, "notes", "v0.6.0-rc.1");
95
+ assert.match(notes.stdout, /Release candidate behavior/);
96
+ });
97
+
98
+ test("release version tooling rejects unsupported prerelease identifiers", async (t) => {
99
+ const root = await createFixture(t);
100
+ await assert.rejects(
101
+ () => runRelease(root, "prepare", "0.6.0-beta.1"),
102
+ (error) => {
103
+ assert.match(String(error.stderr ?? error), /prepare X\.Y\.Z\[-rc\.N\]/);
104
+ return true;
105
+ },
106
+ );
107
+ });
@@ -1,52 +1,44 @@
1
- import { spawnSync } from "node:child_process";
1
+ #!/usr/bin/env node
2
+
3
+ import { execFileSync, spawnSync } from "node:child_process";
2
4
  import { cpSync, mkdirSync, mkdtempSync, rmSync } from "node:fs";
3
5
  import { dirname, join, resolve } from "node:path";
4
6
  import { fileURLToPath } from "node:url";
5
7
 
6
- const minimumNode = "22.19.0";
7
- const npmVersion = "11";
8
+ const NODE_VERSION = "22.19.0";
9
+ const NPM_VERSION = "10.9.3";
8
10
  const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
9
11
  const debugRoot = join(repoRoot, ".forgerelay-debug");
10
12
  const sandbox = mkdtempSync(join(ensureDirectory(debugRoot), "release-parity-node22-"));
11
13
  const npx = process.platform === "win32" ? "npx.cmd" : "npx";
12
- const highRiskTests = [
13
- "scripts/lsp-interop-support.test.mjs",
14
- "src/lsp/language-server-config.test.ts",
15
- "src/lsp/runtime/semantic-requests.test.ts",
16
- "src/lsp/operations/request-hardening.server.test.ts",
17
- "src/lsp/operations/recovery.server.test.ts",
18
- "src/lsp/operations/lifecycle.server.test.ts",
19
- ];
14
+
15
+ assertCleanReleaseHead();
20
16
 
21
17
  try {
22
- copy("package.json");
23
- copy("package-lock.json");
24
- copy("tsconfig.json");
25
- copy("src");
26
- copy("scripts");
27
- copy("capabilities");
18
+ copyTrackedTree(sandbox);
19
+ const env = {
20
+ ...process.env,
21
+ FORGERELAY_ALLOWED_ROOTS: sandbox,
22
+ FORGERELAY_OAUTH_OWNER_TOKEN: "ci-owner-token-that-is-long-enough",
23
+ FORGERELAY_PUBLIC_BASE_URL: "http://127.0.0.1:7676",
24
+ };
28
25
 
29
- run(
30
- ["--yes", "-p", `node@${minimumNode}`, "-p", `npm@${npmVersion}`, "--", "npm", "ci", "--no-audit", "--no-fund"],
31
- `Node ${minimumNode} isolated npm ci`,
26
+ runNodeNpm(
32
27
  sandbox,
28
+ env,
29
+ ["npm", "ci", "--no-audit", "--no-fund"],
30
+ `Node ${NODE_VERSION} / npm ${NPM_VERSION} install`,
33
31
  );
32
+ runNodeNpm(sandbox, env, ["npm", "run", "release:check"], "Release metadata");
33
+ runNodeNpm(sandbox, env, ["npm", "run", "typecheck"], "Typecheck");
34
+ runNodeNpm(sandbox, env, ["npm", "test"], "Full test suite");
35
+ runNodeNpm(sandbox, env, ["npm", "run", "build"], "Build");
36
+ runNodeNpm(sandbox, env, ["npm", "run", "lsp:interop"], "Optional LSP interoperability");
37
+ runNode(sandbox, env, ["dist/cli.js", "doctor"], "Doctor");
34
38
 
35
- run(
36
- [
37
- "--yes",
38
- `node@${minimumNode}`,
39
- "--import",
40
- "tsx",
41
- "--test",
42
- "--test-concurrency=1",
43
- ...highRiskTests,
44
- ],
45
- `Node ${minimumNode} high-risk parity tests`,
46
- sandbox,
39
+ console.log(
40
+ `Release parity passed with the cloud CI command surface on Node ${NODE_VERSION} / npm ${NPM_VERSION}.`,
47
41
  );
48
-
49
- console.log(`Release parity passed in an isolated Node ${minimumNode} sandbox.`);
50
42
  } finally {
51
43
  rmSync(sandbox, {
52
44
  recursive: true,
@@ -56,30 +48,62 @@ try {
56
48
  });
57
49
  }
58
50
 
51
+ function git(args) {
52
+ return execFileSync("git", args, {
53
+ cwd: repoRoot,
54
+ encoding: "utf8",
55
+ stdio: ["ignore", "pipe", "pipe"],
56
+ }).trim();
57
+ }
58
+
59
+ function assertCleanReleaseHead() {
60
+ const status = git(["status", "--porcelain", "--untracked-files=all"]);
61
+ if (status) {
62
+ throw new Error(
63
+ "release parity requires a clean committed release HEAD; commit or remove every release input first",
64
+ );
65
+ }
66
+ }
67
+
59
68
  function ensureDirectory(path) {
60
69
  mkdirSync(path, { recursive: true });
61
70
  return `${path}/`;
62
71
  }
63
72
 
64
- function copy(relativePath) {
65
- cpSync(join(repoRoot, relativePath), join(sandbox, relativePath), {
66
- recursive: true,
67
- force: true,
68
- });
73
+ function copyTrackedTree(destinationRoot) {
74
+ const files = execFileSync("git", ["ls-files", "-z"], {
75
+ cwd: repoRoot,
76
+ encoding: "utf8",
77
+ }).split("\0").filter(Boolean);
78
+ for (const relativePath of files) {
79
+ const source = join(repoRoot, relativePath);
80
+ const destination = join(destinationRoot, relativePath);
81
+ mkdirSync(dirname(destination), { recursive: true });
82
+ cpSync(source, destination, { recursive: true, force: true });
83
+ }
69
84
  }
70
85
 
71
- function run(args, label, cwd) {
86
+ function runNodeNpm(cwd, env, command, label) {
87
+ run(
88
+ cwd,
89
+ env,
90
+ ["--yes", "-p", `node@${NODE_VERSION}`, "-p", `npm@${NPM_VERSION}`, "--", ...command],
91
+ label,
92
+ );
93
+ }
94
+
95
+ function runNode(cwd, env, args, label) {
96
+ run(cwd, env, ["--yes", `node@${NODE_VERSION}`, ...args], label);
97
+ }
98
+
99
+ function run(cwd, env, args, label) {
72
100
  console.log(`\n== ${label} ==`);
73
101
  const result = spawnSync(npx, args, {
74
102
  cwd,
75
- env: process.env,
103
+ env,
76
104
  stdio: "inherit",
77
105
  windowsHide: true,
78
106
  });
79
107
  if (result.error) throw result.error;
80
- if (result.status !== 0) {
81
- console.error(`${label} failed with exit ${result.status ?? "unknown"}.`);
82
- process.exitCode = result.status ?? 1;
83
- throw new Error(`${label} failed.`);
84
- }
108
+ if (result.status !== 0) throw new Error(`${label} failed with exit ${result.status ?? "unknown"}`);
85
109
  }
@@ -91,9 +91,9 @@ function hookTag() {
91
91
  throw new Error("FORGERELAY_HOOK_PAYLOAD is not valid JSON");
92
92
  }
93
93
  const command = typeof payload.command === "string" ? payload.command : "";
94
- const match = /git\s+push\s+origin\s+(v\d+\.\d+\.\d+)/.exec(command);
94
+ const match = /git\s+push\s+origin\s+(v\d+\.\d+\.\d+(?:-rc\.\d+)?)/.exec(command);
95
95
  if (!match?.[1]) {
96
- throw new Error("release Hook payload does not contain a stable tag push");
96
+ throw new Error("release Hook payload does not contain a release tag push");
97
97
  }
98
98
  return match[1];
99
99
  }
@@ -77,6 +77,24 @@ test("release proof binds a successful local verification to the exact tag HEAD"
77
77
  );
78
78
  });
79
79
 
80
+ test("release proof accepts an rc tag for the verified package version", async (t) => {
81
+ const root = await mkdtemp(join(tmpdir(), "forgerelay-release-proof-"));
82
+ t.after(() => rm(root, { recursive: true, force: true }));
83
+ await writeFile(join(root, "package.json"), JSON.stringify({ version: "0.6.0-rc.1" }) + "\n");
84
+ await git(root, ["init"]);
85
+ await git(root, ["config", "user.email", "proof@example.com"]);
86
+ await git(root, ["config", "user.name", "Release Proof Test"]);
87
+ await git(root, ["add", "."]);
88
+ await git(root, ["commit", "-m", "release 0.6.0-rc.1"]);
89
+ await runProof(root, "write");
90
+ await git(root, ["tag", "v0.6.0-rc.1"]);
91
+
92
+ const checked = await runProof(root, "check-hook", {
93
+ FORGERELAY_HOOK_PAYLOAD: JSON.stringify({ command: "git push origin v0.6.0-rc.1" }),
94
+ });
95
+ assert.match(checked.stdout, /Release proof OK: v0\.6\.0-rc\.1/);
96
+ });
97
+
80
98
  test("release proof rejects a mismatched tag without invoking a remote", async (t) => {
81
99
  const root = await mkdtemp(join(tmpdir(), "forgerelay-release-proof-"));
82
100
  t.after(() => rm(root, { recursive: true, force: true }));
@@ -9,6 +9,7 @@ const changelogPath = resolve(repoRoot, "CHANGELOG.md");
9
9
  const noticePath = resolve(repoRoot, "NOTICE.md");
10
10
  const licensePath = resolve(repoRoot, "LICENSE");
11
11
  const stableVersionPattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
12
+ const releaseVersionPattern = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-rc\.(0|[1-9]\d*))?$/;
12
13
  const expectedPackageName = "@akira-tl/forgerelay";
13
14
  const expectedRepositoryUrl = "git+https://github.com/Akira-TL/forgerelay.git";
14
15
  const expectedHomepage = "https://github.com/Akira-TL/forgerelay#readme";
@@ -26,7 +27,7 @@ switch (command) {
26
27
  break;
27
28
  case "tag": {
28
29
  checkState(state);
29
- if (!value) fail("usage: node scripts/release-version.mjs tag vX.Y.Z");
30
+ if (!value) fail("usage: node scripts/release-version.mjs tag vX.Y.Z[-rc.N]");
30
31
  if (getUnreleasedBody(state.changelog)) {
31
32
  fail("CHANGELOG.md still has Unreleased changes; prepare the next version before creating a release tag");
32
33
  }
@@ -37,6 +38,14 @@ switch (command) {
37
38
  console.log(`release tag ${value} matches package version and changelog`);
38
39
  break;
39
40
  }
41
+ case "prepare": {
42
+ checkState(state);
43
+ if (!value || !releaseVersionPattern.test(value)) {
44
+ fail("usage: node scripts/release-version.mjs prepare X.Y.Z[-rc.N] [--dry-run]");
45
+ }
46
+ await prepareRelease(state, value, dryRun);
47
+ break;
48
+ }
40
49
  case "next": {
41
50
  checkState(state);
42
51
  const bump = value ?? "patch";
@@ -48,10 +57,10 @@ switch (command) {
48
57
  }
49
58
  case "notes": {
50
59
  checkState(state);
51
- if (!value) fail("usage: node scripts/release-version.mjs notes vX.Y.Z");
60
+ if (!value) fail("usage: node scripts/release-version.mjs notes vX.Y.Z[-rc.N]");
52
61
  const version = value.startsWith("v") ? value.slice(1) : value;
53
- if (!stableVersionPattern.test(version)) {
54
- fail(`release notes version ${JSON.stringify(value)} must be vX.Y.Z or X.Y.Z`);
62
+ if (!releaseVersionPattern.test(version)) {
63
+ fail(`release notes version ${JSON.stringify(value)} must be vX.Y.Z[-rc.N] or X.Y.Z[-rc.N]`);
55
64
  }
56
65
  const body = getReleaseBody(state.changelog, version);
57
66
  if (!body) fail(`CHANGELOG.md has no release notes for ${version}`);
@@ -59,7 +68,7 @@ switch (command) {
59
68
  break;
60
69
  }
61
70
  default:
62
- fail(`unknown release command ${JSON.stringify(command)}; expected check, tag, next, or notes`);
71
+ fail(`unknown release command ${JSON.stringify(command)}; expected check, tag, prepare, next, or notes`);
63
72
  }
64
73
 
65
74
  async function readState() {
@@ -87,8 +96,8 @@ function checkState(state) {
87
96
  if (state.pkg.name !== expectedPackageName) {
88
97
  fail(`unexpected package name ${JSON.stringify(state.pkg.name)}; expected ${expectedPackageName}`);
89
98
  }
90
- if (typeof version !== "string" || !stableVersionPattern.test(version)) {
91
- fail(`package version ${JSON.stringify(version)} must be a stable X.Y.Z version`);
99
+ if (typeof version !== "string" || !releaseVersionPattern.test(version)) {
100
+ fail(`package version ${JSON.stringify(version)} must be X.Y.Z or X.Y.Z-rc.N`);
92
101
  }
93
102
  if (state.pkg.repository?.url !== expectedRepositoryUrl) {
94
103
  fail(`package repository.url must be ${expectedRepositoryUrl} for GitHub/npm trusted publishing`);
@@ -162,7 +171,7 @@ async function prepareRelease(state, nextVersion, dryRun) {
162
171
 
163
172
  console.log(`${state.pkg.version} -> ${nextVersion}`);
164
173
  console.log("updated package.json, package-lock.json, and CHANGELOG.md");
165
- console.log("next: review the diff, commit the release-ready tree, run npm run release:verify on that clean HEAD, then push the matching vX.Y.Z tag");
174
+ console.log("next: review the diff, commit the release-ready tree, run npm run release:verify on that clean HEAD, then push the matching release tag");
166
175
  }
167
176
 
168
177
  function promoteUnreleased(changelog, nextVersion) {
@@ -1 +0,0 @@
1
- import{d as e}from"./workspace-app-Cm9EX5x4.js";import{t}from"./html-C3TPjrC5.js";var n=[Object.freeze(JSON.parse('{"injectionSelector":"L:text.html -comment","name":"angular-expression","patterns":[{"include":"#ngExpression"}],"repository":{"arrayLiteral":{"begin":"\\\\[","beginCaptures":{"0":{"name":"meta.brace.square.ts"}},"end":"]","endCaptures":{"0":{"name":"meta.brace.square.ts"}},"name":"meta.array.literal.ts","patterns":[{"include":"#ngExpression"},{"include":"#punctuationComma"}]},"booleanLiteral":{"patterns":[{"match":"(?<![$.])\\\\btrue\\\\b(?!\\\\$)","name":"constant.language.boolean.true.ts"},{"match":"(?<![$.])\\\\bfalse\\\\b(?!\\\\$)","name":"constant.language.boolean.false.ts"}]},"expressionOperator":{"patterns":[{"captures":{"1":{"name":"keyword.operator.logical.ts"},"2":{"name":"entity.name.function.pipe.ng"}},"match":"((?<!\\\\|)\\\\|(?!\\\\|))\\\\s?([-$0-9A-Z_a-z]*)"},{"match":"(?<![$.])\\\\b(let)\\\\b(?!\\\\$)","name":"storage.type.ts"},{"match":"(?<![$.])\\\\b(await)\\\\b(?!\\\\$)","name":"keyword.control.flow.ts"},{"match":"(?<![$.])\\\\bdelete\\\\b(?!\\\\$)","name":"keyword.operator.expression.delete.ts"},{"match":"(?<![$.])\\\\bin\\\\b(?!\\\\$)","name":"keyword.operator.expression.in.ts"},{"match":"(?<![$.])\\\\bof\\\\b(?!\\\\$)","name":"keyword.operator.expression.of.ts"},{"match":"(?<![$.])\\\\bif\\\\b(?!\\\\$)","name":"keyword.control.if.ts"},{"match":"(?<![$.])\\\\belse\\\\b(?!\\\\$)","name":"keyword.control.else.ts"},{"match":"(?<![$.])\\\\bthen\\\\b(?!\\\\$)","name":"keyword.control.then.ts"},{"match":"(?<![$.])\\\\binstanceof\\\\b(?!\\\\$)","name":"keyword.operator.expression.instanceof.ts"},{"match":"(?<![$.])\\\\bnew\\\\b(?!\\\\$)","name":"keyword.operator.new.ts"},{"match":"(?<![$.])\\\\bvoid\\\\b(?!\\\\$)","name":"keyword.operator.expression.void.ts"},{"begin":"(?<![$.])\\\\bas\\\\b(?!\\\\$)","beginCaptures":{"0":{"name":"storage.type.as.ts"}},"end":"(?=$|[]\\"\'),:;}])","patterns":[{"include":"#type"}]},{"match":"(?:\\\\*|(?<!\\\\()/|[-%+])=","name":"keyword.operator.assignment.compound.ts"},{"match":"(?:[\\\\&^]|<<|>>>??|\\\\|)=","name":"keyword.operator.assignment.compound.bitwise.ts"},{"match":"<<|>>>?","name":"keyword.operator.bitwise.shift.ts"},{"match":"[!=]==?","name":"keyword.operator.comparison.ts"},{"match":"<=|>=|<>|[<>]","name":"keyword.operator.relational.ts"},{"match":"!|&&|\\\\?\\\\?|\\\\|\\\\|","name":"keyword.operator.logical.ts"},{"match":"[\\\\&^|~]","name":"keyword.operator.bitwise.ts"},{"match":"=","name":"keyword.operator.assignment.ts"},{"match":"--","name":"keyword.operator.decrement.ts"},{"match":"\\\\+\\\\+","name":"keyword.operator.increment.ts"},{"match":"[-%*+/]","name":"keyword.operator.arithmetic.ts"},{"captures":{"1":{"name":"keyword.operator.arithmetic.ts"}},"match":"(?<=[$_[:alnum:]])\\\\s*(/)(?![*/])"},{"include":"#typeofOperator"}]},"functionCall":{"begin":"(?=(\\\\??\\\\.\\\\s*)?([$_[:alpha:]][$_[:alnum:]]*)\\\\s*(<([^<>]|<[^<>]+>)+>\\\\s*)?\\\\()","end":"(?<=\\\\))(?!(\\\\??\\\\.\\\\s*)?([$_[:alpha:]][$_[:alnum:]]*)\\\\s*(<([^<>]|<[^<>]+>)+>\\\\s*)?\\\\()","patterns":[{"match":"\\\\?","name":"punctuation.accessor.ts"},{"match":"\\\\.","name":"punctuation.accessor.ts"},{"match":"([$_[:alpha:]][$_[:alnum:]]*)","name":"entity.name.function.ts"},{"begin":"<","beginCaptures":{"0":{"name":"punctuation.definition.typeparameters.begin.ts"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.typeparameters.end.ts"}},"name":"meta.type.parameters.ts","patterns":[{"include":"#type"},{"include":"#punctuationComma"}]},{"include":"#parenExpression"}]},"functionParameters":{"begin":"\\\\(","beginCaptures":{"0":{"name":"punctuation.definition.parameters.begin.ts"}},"end":"\\\\)","endCaptures":{"0":{"name":"punctuation.definition.parameters.end.ts"}},"name":"meta.parameters.ts","patterns":[{"include":"#decorator"},{"include":"#parameterName"},{"include":"#variableInitializer"},{"match":",","name":"punctuation.separator.parameter.ts"}]},"identifiers":{"patterns":[{"match":"([$_[:alpha:]][$_[:alnum:]]*)(?=\\\\s*\\\\.\\\\s*prototype\\\\b(?!\\\\$))","name":"support.class.ts"},{"captures":{"1":{"name":"punctuation.accessor.ts"},"2":{"name":"constant.other.object.property.ts"},"3":{"name":"variable.other.object.property.ts"}},"match":"([!?]?\\\\.)\\\\s*(?:(\\\\p{upper}[$_\\\\d[:upper:]]*)|([$_[:alpha:]][$_[:alnum:]]*))(?=\\\\s*\\\\.\\\\s*[$_[:alpha:]][$_[:alnum:]]*)"},{"captures":{"1":{"name":"punctuation.accessor.ts"},"2":{"name":"entity.name.function.ts"}},"match":"(?:([!?]?\\\\.)\\\\s*)?([$_[:alpha:]][$_[:alnum:]]*)(?=\\\\s*=\\\\s*((async\\\\s+)|(function\\\\s*[(<])|(function\\\\s+)|([$_[:alpha:]][$_[:alnum:]]*\\\\s*=>)|((<([^<>]|<[^<>]+>)+>\\\\s*)?\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)(\\\\s*:\\\\s*(.)*)?\\\\s*=>)))"},{"captures":{"1":{"name":"punctuation.accessor.ts"},"2":{"name":"constant.other.property.ts"}},"match":"([!?]?\\\\.)\\\\s*(\\\\p{upper}[$_\\\\d[:upper:]]*)(?![$_[:alnum:]])"},{"captures":{"1":{"name":"punctuation.accessor.ts"},"2":{"name":"variable.other.property.ts"}},"match":"([!?]?\\\\.)\\\\s*([$_[:alpha:]][$_[:alnum:]]*)"},{"captures":{"1":{"name":"constant.other.object.ts"},"2":{"name":"variable.other.object.ts"}},"match":"(?:(\\\\p{upper}[$_\\\\d[:upper:]]*)|([$_[:alpha:]][$_[:alnum:]]*))(?=\\\\s*\\\\.\\\\s*[$_[:alpha:]][$_[:alnum:]]*)"},{"match":"(\\\\p{upper}[$_\\\\d[:upper:]]*)(?![$_[:alnum:]])","name":"constant.character.other"},{"match":"[$_[:alpha:]][$_[:alnum:]]*","name":"variable.other.readwrite.ts"}]},"literal":{"name":"literal.ts","patterns":[{"include":"#numericLiteral"},{"include":"#booleanLiteral"},{"include":"#nullLiteral"},{"include":"#undefinedLiteral"},{"include":"#numericConstantLiteral"},{"include":"#arrayLiteral"},{"include":"#thisLiteral"}]},"ngExpression":{"name":"meta.expression.ng","patterns":[{"include":"#string"},{"include":"#literal"},{"include":"#ternaryExpression"},{"include":"#expressionOperator"},{"include":"#functionCall"},{"include":"#identifiers"},{"include":"#parenExpression"},{"include":"#punctuationComma"},{"include":"#punctuationSemicolon"},{"include":"#punctuationAccessor"}]},"nullLiteral":{"match":"(?<![$.])\\\\bnull\\\\b(?!\\\\$)","name":"constant.language.null.ts"},"numericConstantLiteral":{"patterns":[{"match":"(?<![$.])\\\\bNaN\\\\b(?!\\\\$)","name":"constant.language.nan.ts"},{"match":"(?<![$.])\\\\bInfinity\\\\b(?!\\\\$)","name":"constant.language.infinity.ts"}]},"numericLiteral":{"patterns":[{"match":"\\\\b(?<!\\\\$)0([Xx])\\\\h+\\\\b(?!\\\\$)","name":"constant.numeric.hex.ts"},{"match":"\\\\b(?<!\\\\$)0([Bb])[01]+\\\\b(?!\\\\$)","name":"constant.numeric.binary.ts"},{"match":"\\\\\\\\b(?<!\\\\$)0([Oo])?[0-7]+\\\\b(?!\\\\$)","name":"constant.numeric.octal.ts"},{"captures":{"0":{"name":"constant.numeric.decimal.ts"},"1":{"name":"meta.delimiter.decimal.period.ts"},"2":{"name":"meta.delimiter.decimal.period.ts"},"3":{"name":"meta.delimiter.decimal.period.ts"},"4":{"name":"meta.delimiter.decimal.period.ts"},"5":{"name":"meta.delimiter.decimal.period.ts"},"6":{"name":"meta.delimiter.decimal.period.ts"}},"match":"(?<!\\\\$)(?:\\\\b[0-9]+(\\\\.)[0-9]+[Ee][-+]?[0-9]+\\\\b|\\\\b[0-9]+(\\\\.)[Ee][-+]?[0-9]+\\\\b|\\\\B(\\\\.)[0-9]+[Ee][-+]?[0-9]+\\\\b|\\\\b[0-9]+[Ee][-+]?[0-9]+\\\\b|\\\\b[0-9]+(\\\\.)\\\\B|\\\\B(\\\\.)[0-9]+\\\\b|\\\\b[0-9]+\\\\b(?!\\\\.))(?!\\\\$)"}]},"parameterName":{"patterns":[{"captures":{"1":{"name":"storage.modifier.ts"},"2":{"name":"storage.modifier.ts"},"3":{"name":"keyword.operator.rest.ts"},"4":{"name":"entity.name.function.ts"},"5":{"name":"keyword.operator.optional.ts"}},"match":"(?:\\\\s*\\\\b(readonly)\\\\s+)?(?:\\\\s*\\\\b(p(?:ublic|rivate|rotected))\\\\s+)?(\\\\.\\\\.\\\\.)?\\\\s*(?<![:=])([$_[:alpha:]][$_[:alnum:]]*)\\\\s*(\\\\??)(?=\\\\s*(=\\\\s*((async\\\\s+)|(function\\\\s*[(<])|(function\\\\s+)|([$_[:alpha:]][$_[:alnum:]]*\\\\s*=>)|((<([^<>]|<[^<>]+>)+>\\\\s*)?\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)(\\\\s*:\\\\s*(.)*)?\\\\s*=>)))|(:\\\\s*((<)|(\\\\(\\\\s*((\\\\))|(\\\\.\\\\.\\\\.)|([$_[:alnum:]]+\\\\s*(([,:=?])|(\\\\)\\\\s*=>))))))))"},{"captures":{"1":{"name":"storage.modifier.ts"},"2":{"name":"storage.modifier.ts"},"3":{"name":"keyword.operator.rest.ts"},"4":{"name":"variable.parameter.ts"},"5":{"name":"keyword.operator.optional.ts"}},"match":"(?:\\\\s*\\\\b(readonly)\\\\s+)?(?:\\\\s*\\\\b(p(?:ublic|rivate|rotected))\\\\s+)?(\\\\.\\\\.\\\\.)?\\\\s*(?<![:=])([$_[:alpha:]][$_[:alnum:]]*)\\\\s*(\\\\??)"}]},"parenExpression":{"begin":"\\\\(","beginCaptures":{"0":{"name":"meta.brace.round.ts"}},"end":"\\\\)","endCaptures":{"0":{"name":"meta.brace.round.ts"}},"patterns":[{"include":"#ngExpression"},{"include":"#punctuationComma"}]},"punctuationAccessor":{"match":"(?:\\\\?|!?)\\\\.","name":"punctuation.accessor.ts"},"punctuationComma":{"match":",","name":"punctuation.separator.comma.ts"},"punctuationSemicolon":{"match":";","name":"punctuation.terminator.statement.ts"},"qstringDouble":{"begin":"\\"","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.ts"}},"end":"(\\")|([^\\\\n\\\\\\\\])$","endCaptures":{"1":{"name":"punctuation.definition.string.end.ts"},"2":{"name":"invalid.illegal.newline.ts"}},"name":"string.quoted.double.ts","patterns":[{"include":"#stringCharacterEscape"}]},"qstringSingle":{"begin":"\'","beginCaptures":{"0":{"name":"punctuation.definition.string.begin.ts"}},"end":"(\')|([^\\\\n\\\\\\\\])$","endCaptures":{"1":{"name":"punctuation.definition.string.end.ts"},"2":{"name":"invalid.illegal.newline.ts"}},"name":"string.quoted.single.ts","patterns":[{"include":"#stringCharacterEscape"}]},"string":{"patterns":[{"include":"#qstringSingle"},{"include":"#qstringDouble"},{"include":"#templateLiteral"}]},"stringCharacterEscape":{"match":"\\\\\\\\(x\\\\h{2}|[012][0-7]{0,2}|3[0-6][0-7]?|37[0-7]?|[4-7][0-7]?|.|$)","name":"constant.character.escape.ts"},"templateLiteral":{"patterns":[{"include":"#templateLiteralCall"},{"begin":"([$_[:alpha:]][$_[:alnum:]]*)?(`)","beginCaptures":{"1":{"name":"entity.name.function.tagged-template.ts"},"2":{"name":"string.template.ts punctuation.definition.string.template.begin.ts"}},"contentName":"string.template.ts","end":"`","endCaptures":{"0":{"name":"string.template.ts punctuation.definition.string.template.end.ts"}},"patterns":[{"include":"#templateLiteralSubstitutionElement"},{"include":"#stringCharacterEscape"}]}]},"templateLiteralCall":{"patterns":[{"begin":"(?=(([$_[:alpha:]][$_[:alnum:]]*\\\\s*\\\\??\\\\.\\\\s*)*|(\\\\??\\\\.\\\\s*)?)([$_[:alpha:]][$_[:alnum:]]*)(<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>|<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))(([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>|<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>)*(?<!=)>))*(?<!=)>)*(?<!=)>\\\\s*)?`)","end":"(?=`)","patterns":[{"begin":"(?=(([$_[:alpha:]][$_[:alnum:]]*\\\\s*\\\\??\\\\.\\\\s*)*|(\\\\??\\\\.\\\\s*)?)([$_[:alpha:]][$_[:alnum:]]*))","end":"(?=(<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>|<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))(([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>|<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>)*(?<!=)>))*(?<!=)>)*(?<!=)>\\\\s*)?`)","patterns":[{"include":"#support-function-call-identifiers"},{"match":"([$_[:alpha:]][$_[:alnum:]]*)","name":"entity.name.function.tagged-template.ts"}]},{"include":"#typeArguments"}]},{"begin":"([$_[:alpha:]][$_[:alnum:]]*)?\\\\s*(?=(<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>|<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))(([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>|<\\\\s*(((keyof|infer|typeof|readonly)\\\\s+)|(([$_[:alpha:]][$_[:alnum:]]*|(\\\\{([^{}]|(\\\\{([^{}]|\\\\{[^{}]*})*}))*})|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(\\\\[([^]\\\\[]|(\\\\[([^]\\\\[]|\\\\[[^]\\\\[]*])*]))*])|(\'([^\'\\\\\\\\]|\\\\\\\\.)*\')|(\\"([^\\"\\\\\\\\]|\\\\\\\\.)*\\")|(`([^\\\\\\\\`]|\\\\\\\\.)*`))(?=\\\\s*([,.<>\\\\[]|=>|&(?!&)|\\\\|(?!\\\\|)))))([^(<>]|(\\\\(([^()]|(\\\\(([^()]|\\\\([^()]*\\\\))*\\\\)))*\\\\))|(?<==)>)*(?<!=)>))*(?<!=)>)*(?<!=)>\\\\s*)`)","beginCaptures":{"1":{"name":"entity.name.function.tagged-template.ts"}},"end":"(?=`)","patterns":[{"include":"#typeArguments"}]}]},"templateLiteralSubstitutionElement":{"begin":"\\\\$\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.template-expression.begin.ts"}},"contentName":"meta.embedded.line.ts","end":"}","endCaptures":{"0":{"name":"punctuation.definition.template-expression.end.ts"}},"name":"meta.template.expression.ts","patterns":[{"include":"#ngExpression"}]},"ternaryExpression":{"begin":"(?!\\\\?\\\\.\\\\s*\\\\D)(\\\\?)(?!\\\\?)","beginCaptures":{"1":{"name":"keyword.operator.ternary.ts"}},"end":"\\\\s*(:)","endCaptures":{"1":{"name":"keyword.operator.ternary.ts"}},"patterns":[{"include":"#ngExpression"}]},"thisLiteral":{"match":"(?<![$.])\\\\bthis\\\\b(?!\\\\$)","name":"variable.language.this.ts"},"type":{"name":"meta.type.ts","patterns":[{"include":"#string"},{"include":"#numericLiteral"},{"include":"#typeBuiltinLiterals"},{"include":"#typeTuple"},{"include":"#typeObject"},{"include":"#typeOperators"},{"include":"#typeFnTypeParameters"},{"include":"#typeParenOrFunctionParameters"},{"include":"#typeName"}]},"typeAnnotation":{"begin":":","beginCaptures":{"0":{"name":"keyword.operator.type.annotation.ts"}},"end":"(?=$|[]),;}]|//|\\")|(?==[^>])|(?<=[]$)>_}[:alpha:]])\\\\s*(?=\\\\{)","name":"meta.type.annotation.ts","patterns":[{"include":"#type"}]},"typeArguments":{"begin":"<","beginCaptures":{"0":{"name":"punctuation.definition.typeparameters.begin.ts"}},"end":">","endCaptures":{"0":{"name":"punctuation.definition.typeparameters.end.ts"}},"name":"meta.type.parameters.ts","patterns":[{"include":"#typeArgumentsBody"}]},"typeArgumentsBody":{"patterns":[{"captures":{"0":{"name":"keyword.operator.type.ts"}},"match":"(?<![$_[:alnum:]])(?:(?<=\\\\.\\\\.\\\\.)|(?<!\\\\.))(_)(?![$_[:alnum:]])(?:(?=\\\\.\\\\.\\\\.)|(?!\\\\.))"},{"include":"#type"},{"include":"#punctuationComma"}]},"typeBuiltinLiterals":{"match":"(?<![$.])\\\\b(this|true|false|undefined|null)\\\\b(?!\\\\$)","name":"support.type.builtin.ts"},"typeFnTypeParameters":{"patterns":[{"captures":{"1":{"name":"keyword.control.new.ts"}},"match":"(?<![$.])\\\\b(new)\\\\b(?=\\\\s*<)","name":"meta.type.constructor.ts"},{"begin":"(?<![$.])\\\\b(new)\\\\b\\\\s*(?=\\\\()","beginCaptures":{"1":{"name":"keyword.control.new.ts"}},"end":"(?<=\\\\))","name":"meta.type.constructor.ts","patterns":[{"include":"#functionParameters"}]},{"begin":"(?<=>)\\\\s*(?=\\\\()","end":"(?<=\\\\))","include":"#typeofOperator","name":"meta.type.function.ts","patterns":[{"include":"#functionParameters"}]},{"begin":"((?=\\\\(\\\\s*((\\\\))|(\\\\.\\\\.\\\\.)|([$_[:alnum:]]+\\\\s*(([,:=?])|(\\\\)\\\\s*=>))))))","end":"(?<=\\\\))","name":"meta.type.function.ts","patterns":[{"include":"#functionParameters"}]}]},"typeName":{"patterns":[{"captures":{"1":{"name":"entity.name.type.module.ts"},"2":{"name":"punctuation.accessor.ts"}},"match":"([$_[:alpha:]][$_[:alnum:]]*)\\\\s*([!?]?\\\\.)"},{"match":"[$_[:alpha:]][$_[:alnum:]]*","name":"entity.name.type.ts"}]},"typeObject":{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.block.ts"}},"end":"}","endCaptures":{"0":{"name":"punctuation.definition.block.ts"}},"name":"meta.object.type.ts","patterns":[{"include":"#typeObjectMembers"}]},"typeObjectMembers":{"patterns":[{"include":"#typeAnnotation"},{"include":"#punctuationComma"},{"include":"#punctuationSemicolon"}]},"typeOperators":{"patterns":[{"include":"#typeofOperator"},{"match":"[\\\\&|]","name":"keyword.operator.type.ts"},{"match":"(?<![$.])\\\\bkeyof\\\\b(?!\\\\$)","name":"keyword.operator.expression.keyof.ts"}]},"typeParenOrFunctionParameters":{"begin":"\\\\(","beginCaptures":{"0":{"name":"meta.brace.round.ts"}},"end":"\\\\)","endCaptures":{"0":{"name":"meta.brace.round.ts"}},"name":"meta.type.paren.cover.ts","patterns":[{"include":"#type"},{"include":"#functionParameters"}]},"typeTuple":{"begin":"\\\\[","beginCaptures":{"0":{"name":"meta.brace.square.ts"}},"end":"]","endCaptures":{"0":{"name":"meta.brace.square.ts"}},"name":"meta.type.tuple.ts","patterns":[{"include":"#type"},{"include":"#punctuationComma"}]},"typeofOperator":{"match":"(?<![$.])\\\\btypeof\\\\b(?!\\\\$)","name":"keyword.operator.expression.typeof.ts"},"undefinedLiteral":{"match":"(?<![$.])\\\\bundefined\\\\b(?!\\\\$)","name":"constant.language.undefined.ts"},"variableInitializer":{"begin":"(?<![!=])(=)(?!=)","beginCaptures":{"1":{"name":"keyword.operator.assignment.ts"}},"end":"(?=$|[]),;}])","patterns":[{"include":"#ngExpression"}]}},"scopeName":"expression.ng"}'))],r=Object.freeze(JSON.parse(`{"injectTo":["text.html.derivative","text.html.derivative.ng","source.ts.ng"],"injectionSelector":"L:text.html -comment -expression.ng -meta.tag -source.css -source.js","name":"angular-let-declaration","patterns":[{"include":"#letDeclaration"}],"repository":{"letDeclaration":{"begin":"(@let)\\\\s+([$_[:alpha:]][$_[:alnum:]]*)\\\\s*(=)?","beginCaptures":{"1":{"name":"storage.type.ng"},"2":{"name":"variable.other.constant.ng"},"3":{"name":"keyword.operator.assignment.ng"}},"end":"(?<=;)","name":"meta.definition.variable.ng","patterns":[{"include":"#letInitializer"}]},"letInitializer":{"begin":"\\\\s*","beginCaptures":{"0":{"name":"keyword.operator.assignment.ng"}},"contentName":"meta.definition.variable.initializer.ng","end":";","endCaptures":{"0":{"name":"punctuation.terminator.statement.ng"}},"patterns":[{"include":"expression.ng"}]}},"scopeName":"template.let.ng","embeddedLangs":["angular-expression"]}`)),i=[...n,r],a=Object.freeze(JSON.parse(`{"injectTo":["text.html.derivative","text.html.derivative.ng","source.ts.ng"],"injectionSelector":"L:text.html -comment","name":"angular-template","patterns":[{"include":"#interpolation"}],"repository":{"interpolation":{"begin":"\\\\{\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.block.ts"}},"contentName":"expression.ng","end":"}}","endCaptures":{"0":{"name":"punctuation.definition.block.ts"}},"patterns":[{"include":"expression.ng"}]}},"scopeName":"template.ng","embeddedLangs":["angular-expression"]}`)),o=[...n,a],s=Object.freeze(JSON.parse(`{"injectTo":["text.html.derivative","text.html.derivative.ng","source.ts.ng"],"injectionSelector":"L:text.html -comment -expression.ng -meta.tag -source.css -source.js","name":"angular-template-blocks","patterns":[{"include":"#block"}],"repository":{"block":{"begin":"(@)(if|else if|else|defer|placeholder|loading|error|switch|case|default|for|empty)\\\\s*","beginCaptures":{"1":{"patterns":[{"include":"#transition"}]},"2":{"name":"keyword.control.block.kind.ng"}},"end":"(?<=})","name":"control.block.ng","patterns":[{"include":"#blockExpression"},{"include":"#blockBody"}]},"blockBody":{"begin":"\\\\{","beginCaptures":{"0":{"name":"punctuation.definition.block.ts"}},"contentName":"control.block.body.ng","end":"}","endCaptures":{"0":{"name":"punctuation.definition.block.ts"}},"patterns":[{"include":"text.html.derivative.ng"},{"include":"template.ng"}]},"blockExpression":{"begin":"\\\\(","beginCaptures":{"0":{"name":"meta.brace.round.ts"}},"contentName":"control.block.expression.ng","end":"\\\\)","endCaptures":{"0":{"name":"meta.brace.round.ts"}},"patterns":[{"include":"#blockExpressionOfClause"},{"include":"#blockExpressionLetBinding"},{"include":"#blockExpressionTrackClause"},{"include":"expression.ng"}]},"blockExpressionLetBinding":{"begin":"\\\\blet\\\\b","beginCaptures":{"0":{"name":"storage.type.ng"}},"end":"(?=[$)])|(?<=;)","patterns":[{"include":"expression.ng"}]},"blockExpressionOfClause":{"begin":"([$_[:alpha:]][$_[:alnum:]]*)\\\\s+(of)\\\\b","beginCaptures":{"1":{"name":"variable.other.constant.ng"},"2":{"name":"keyword.operator.expression.of.ng"}},"end":"(?=[$)])|(?<=;)","patterns":[{"include":"expression.ng"}]},"blockExpressionTrackClause":{"begin":"\\\\btrack\\\\b","beginCaptures":{"0":{"name":"keyword.control.track.ng"}},"end":"(?=[$)])|(?<=;)","patterns":[{"include":"expression.ng"}]},"transition":{"match":"@","name":"keyword.control.block.transition.ng"}},"scopeName":"template.blocks.ng","embeddedLangs":["angular-expression","angular-template"]}`)),c=[...n,...o,s],l=e({default:()=>d}),u=Object.freeze(JSON.parse(`{"displayName":"Angular HTML","injections":{"R:text.html - (comment.block, text.html meta.embedded, meta.tag.*.*.html, meta.tag.*.*.*.html, meta.tag.*.*.*.*.html)":{"patterns":[{"match":"<","name":"invalid.illegal.bad-angle-bracket.html"}]}},"name":"angular-html","patterns":[{"include":"text.html.basic#core-minus-invalid"},{"begin":"(</?)(\\\\w[^>\\\\s]*)(?<!/)","beginCaptures":{"1":{"name":"punctuation.definition.tag.begin.html"},"2":{"name":"entity.name.tag.html"}},"end":"((?: ?/)?>)","endCaptures":{"1":{"name":"punctuation.definition.tag.end.html"}},"name":"meta.tag.other.unrecognized.html.derivative","patterns":[{"include":"text.html.basic#attribute"}]}],"scopeName":"text.html.derivative.ng","embeddedLangs":["html","angular-expression","angular-let-declaration","angular-template","angular-template-blocks"]}`)),d=[...t,...n,...i,...o,...c,u];export{i as a,o as i,l as n,n as o,c as r,d as t};