@akira-tl/forgerelay 0.9.3 → 0.10.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 (109) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +10 -4
  3. package/dist/cli/init.js +111 -24
  4. package/dist/cli/maintenance-prune.js +479 -0
  5. package/dist/cli/maintenance-retention.js +93 -0
  6. package/dist/cli/maintenance.js +598 -0
  7. package/dist/cli/setup-support.js +21 -0
  8. package/dist/cli/shell/setup.js +99 -0
  9. package/dist/cli.js +72 -16
  10. package/dist/mcp/hooks/hooks.js +6 -3
  11. package/dist/mcp/oauth/public-url.js +3 -0
  12. package/dist/mcp/oauth/router.js +14 -9
  13. package/dist/mcp/process/process-platform.js +24 -26
  14. package/dist/mcp/process/process-sessions.js +6 -3
  15. package/dist/mcp/server/transport/http-server.js +17 -9
  16. package/dist/mcp/server/workspace/runtime/workspace-open-presentation.js +6 -0
  17. package/dist/mcp/server/workspace/runtime/workspace-tools.js +1 -1
  18. package/dist/mcp/server-instructions.js +10 -1
  19. package/dist/runtime/config/config.js +60 -6
  20. package/dist/runtime/instructions/shell-instructions.js +100 -0
  21. package/dist/runtime/security/runtime-privilege.js +120 -0
  22. package/dist/runtime/shell/command-shell-runtime.js +235 -0
  23. package/dist/runtime/state/runtime-lease.js +109 -0
  24. package/dist/ui/.vite/manifest.json +276 -276
  25. package/dist/ui/activity-panel-app.html +2 -2
  26. package/dist/ui/assets/{activity-panel-app-Sl1Jro8v.js → activity-panel-app-BkODhDLg.js} +1 -1
  27. package/dist/ui/assets/{activity-panel-app-7Xe0alhm.css → activity-panel-app-DkfJzTZ3.css} +1 -1
  28. package/dist/ui/assets/{angular-html-B_yn91wW.js → angular-html-DjuELMdF.js} +1 -1
  29. package/dist/ui/assets/{angular-ts-DSgtloKz.js → angular-ts-2EXVZIIX.js} +1 -1
  30. package/dist/ui/assets/{apl-NatWtF8X.js → apl-Bb4IeT5V.js} +1 -1
  31. package/dist/ui/assets/{astro-BYFEVBuN.js → astro-Bjavu3nT.js} +1 -1
  32. package/dist/ui/assets/{blade-DoO7yvMR.js → blade-DKW2uHZo.js} +1 -1
  33. package/dist/ui/assets/{c-Rl2hMCcg.js → c-oLeHmzbj.js} +1 -1
  34. package/dist/ui/assets/{cobol-ByC5mWiB.js → cobol-CcqFMr5T.js} +1 -1
  35. package/dist/ui/assets/{coffee-Dez77Qov.js → coffee-BA20zqRF.js} +1 -1
  36. package/dist/ui/assets/{cpp-DtaAQT9h.js → cpp-D750WmDa.js} +1 -1
  37. package/dist/ui/assets/{crystal-Bgmbf8ec.js → crystal-Cv5I6OMI.js} +1 -1
  38. package/dist/ui/assets/{css-C1tjBtVN.js → css-CjPPWPeH.js} +1 -1
  39. package/dist/ui/assets/{edge-DeH6u8Wg.js → edge-aYRuudEZ.js} +1 -1
  40. package/dist/ui/assets/{elixir-_H3KnmWT.js → elixir-ChLitmz7.js} +1 -1
  41. package/dist/ui/assets/{elm-CsCe3U28.js → elm-Fs7L7u36.js} +1 -1
  42. package/dist/ui/assets/{erb-CbM-L2g8.js → erb-B-qXHxN1.js} +1 -1
  43. package/dist/ui/assets/{git-rebase-D0s5pDh9.js → git-rebase-DOVN5OEg.js} +1 -1
  44. package/dist/ui/assets/{glimmer-js-BfOToq_A.js → glimmer-js-BFt_vCTW.js} +1 -1
  45. package/dist/ui/assets/{glimmer-ts-CCUOkL2K.js → glimmer-ts-ufCHlR6C.js} +1 -1
  46. package/dist/ui/assets/{glsl-DH4ec9dE.js → glsl-Ex4JXGuC.js} +1 -1
  47. package/dist/ui/assets/{graphql-DilAMBoI.js → graphql-pQPXtBk5.js} +1 -1
  48. package/dist/ui/assets/{hack-BDkNDZlF.js → hack-B5hDguhd.js} +1 -1
  49. package/dist/ui/assets/{haml-D_QBp6K7.js → haml-BrNeI29U.js} +1 -1
  50. package/dist/ui/assets/{handlebars-DePUrTpC.js → handlebars-DCqTsL9-.js} +1 -1
  51. package/dist/ui/assets/{heavy-payload-DOwZpO6n.js → heavy-payload-DsmmHgvt.js} +3 -3
  52. package/dist/ui/assets/{html-By4dNnM4.js → html-D8k0CC9V.js} +1 -1
  53. package/dist/ui/assets/{html-derivative-DDw9Ef4Q.js → html-derivative-CC8flWmC.js} +1 -1
  54. package/dist/ui/assets/{http-B0QxWc9M.js → http-BYnWqNep.js} +1 -1
  55. package/dist/ui/assets/{hurl-vMQ4lda1.js → hurl-BND-z85s.js} +1 -1
  56. package/dist/ui/assets/{java-DYRe2lWG.js → java-Dug0oB9T.js} +1 -1
  57. package/dist/ui/assets/{javascript-CxyGqwcL.js → javascript-oDJ7WITC.js} +1 -1
  58. package/dist/ui/assets/{jinja-JUwV-fZt.js → jinja-Cv0t_F1U.js} +1 -1
  59. package/dist/ui/assets/{jison-7ZqCEvS8.js → jison-Car3MF55.js} +1 -1
  60. package/dist/ui/assets/{json-dbltgiiA.js → json-CEViCsf4.js} +1 -1
  61. package/dist/ui/assets/{jsx-oDopT7YQ.js → jsx-BfZ0zgSH.js} +1 -1
  62. package/dist/ui/assets/{julia-CkKiNSav.js → julia-CmX0b3Tn.js} +1 -1
  63. package/dist/ui/assets/{just-DuqCAKJ3.js → just-BuugLCVk.js} +1 -1
  64. package/dist/ui/assets/{latex-sudcRDSn.js → latex-FpTXqO03.js} +1 -1
  65. package/dist/ui/assets/{liquid-Di-08Js7.js → liquid-B37OzUFu.js} +1 -1
  66. package/dist/ui/assets/{lua-YlqdMoV0.js → lua-BHjcb8oq.js} +1 -1
  67. package/dist/ui/assets/{marko-CJRNyJDb.js → marko-CApj_fsH.js} +1 -1
  68. package/dist/ui/assets/{mdc-t12CzZHs.js → mdc-Ed5vQWq8.js} +1 -1
  69. package/dist/ui/assets/{nginx-57-b4XwT.js → nginx-u_rVEBox.js} +1 -1
  70. package/dist/ui/assets/{nim-BzrswYQa.js → nim-Ba9EdchT.js} +1 -1
  71. package/dist/ui/assets/{perl-D9JR_iIh.js → perl-BpU_6Wvz.js} +1 -1
  72. package/dist/ui/assets/{php-Py2gFHil.js → php-bKabofky.js} +1 -1
  73. package/dist/ui/assets/{pug-PzLLy0h1.js → pug-C_aLNkqe.js} +1 -1
  74. package/dist/ui/assets/{qml-By8fwgV4.js → qml-D9VisnRy.js} +1 -1
  75. package/dist/ui/assets/{r-CcezTbLq.js → r-CYqB1sLx.js} +1 -1
  76. package/dist/ui/assets/{razor-dG-vdhL_.js → razor-DNJKI8Rs.js} +1 -1
  77. package/dist/ui/assets/{regexp-BlsQ-N_8.js → regexp-DHrTHXkz.js} +1 -1
  78. package/dist/ui/assets/{rst-C2awDCat.js → rst-CbNdSFHv.js} +1 -1
  79. package/dist/ui/assets/{ruby-zA2W_49d.js → ruby-FyKG-pkF.js} +1 -1
  80. package/dist/ui/assets/{sas-D49bhyaN.js → sas-BbSPDl3X.js} +1 -1
  81. package/dist/ui/assets/{scss-BQb-cp01.js → scss-2nX9g6gD.js} +1 -1
  82. package/dist/ui/assets/{shellscript-Dga4H_Ni.js → shellscript-CmON6x2x.js} +1 -1
  83. package/dist/ui/assets/{shellsession-n3-5CqcF.js → shellsession-DtqIGlAX.js} +1 -1
  84. package/dist/ui/assets/{soy-XYBOf_BA.js → soy-BzUJMmJT.js} +1 -1
  85. package/dist/ui/assets/{sql-ET4u5Cpl.js → sql-CgVcFZmb.js} +1 -1
  86. package/dist/ui/assets/{stata-CLHcJHO_.js → stata-CNitlMot.js} +1 -1
  87. package/dist/ui/assets/{surrealql-BdjQ60T4.js → surrealql-BA8-xsRZ.js} +1 -1
  88. package/dist/ui/assets/{svelte-B2RPtKJe.js → svelte-El02yAxv.js} +1 -1
  89. package/dist/ui/assets/{templ-CrByPW_W.js → templ-DeUQ84aR.js} +1 -1
  90. package/dist/ui/assets/{tex-DZBkg363.js → tex-Cu-FqpPS.js} +1 -1
  91. package/dist/ui/assets/{ts-tags-DJR3Gphb.js → ts-tags-X42N6TGA.js} +1 -1
  92. package/dist/ui/assets/{tsx-CajzROyy.js → tsx-C1aPp9rY.js} +1 -1
  93. package/dist/ui/assets/{twig-BZjk5Zda.js → twig-Cj1Q4SQc.js} +1 -1
  94. package/dist/ui/assets/{typescript-B-EWToLj.js → typescript-Du9lVt1G.js} +1 -1
  95. package/dist/ui/assets/{vue-D_rHCCr8.js → vue-_uMGbFv8.js} +1 -1
  96. package/dist/ui/assets/{vue-html-CC4WlvVt.js → vue-html-D61naG-Q.js} +1 -1
  97. package/dist/ui/assets/{vue-vine-BgNMVgpk.js → vue-vine-CkFae4yV.js} +1 -1
  98. package/dist/ui/assets/{xml-BI86-WbH.js → xml-Cbwsc6ws.js} +1 -1
  99. package/dist/ui/assets/{xsl-DXeLZV4J.js → xsl-NyBx72XB.js} +1 -1
  100. package/dist/ui/assets/{yaml-60_PFlWa.js → yaml-Cgb6Uq9u.js} +1 -1
  101. package/dist/workspaces/context.js +32 -5
  102. package/dist/workspaces/presentation/workspace-presentation.js +1 -0
  103. package/dist/workspaces/sessions.js +2 -0
  104. package/dist/workspaces.js +2 -1
  105. package/docs/configuration.md +101 -14
  106. package/package.json +2 -2
  107. package/scripts/release/release-gate.test.mjs +1 -0
  108. package/scripts/release-proof.mjs +85 -9
  109. package/scripts/release-proof.test.mjs +79 -1
@@ -0,0 +1,109 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { closeSync, constants as fsConstants, mkdirSync, openSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
3
+ import { join } from "node:path";
4
+ const RUNTIME_LEASE_FILE = "forgerelay-runtime.lock";
5
+ export function runtimeLeasePath(stateDir) {
6
+ return join(stateDir, RUNTIME_LEASE_FILE);
7
+ }
8
+ export function acquireRuntimeLease(stateDir) {
9
+ mkdirSync(stateDir, { recursive: true, mode: 0o700 });
10
+ const path = runtimeLeasePath(stateDir);
11
+ const record = {
12
+ pid: process.pid,
13
+ token: randomBytes(16).toString("hex"),
14
+ startedAt: new Date().toISOString(),
15
+ };
16
+ const serialized = `${JSON.stringify(record)}\n`;
17
+ for (let attempt = 0; attempt < 2; attempt += 1) {
18
+ let fd;
19
+ try {
20
+ fd = openSync(path, fsConstants.O_CREAT | fsConstants.O_EXCL | fsConstants.O_WRONLY, 0o600);
21
+ writeFileSync(fd, serialized, "utf8");
22
+ closeSync(fd);
23
+ fd = undefined;
24
+ return {
25
+ path,
26
+ pid: record.pid,
27
+ release: () => releaseRuntimeLease(path, record),
28
+ };
29
+ }
30
+ catch (error) {
31
+ if (fd !== undefined)
32
+ closeSync(fd);
33
+ if (!isErrno(error, "EEXIST"))
34
+ throw error;
35
+ const inspection = inspectRuntimeLease(stateDir);
36
+ if (inspection.active || inspection.malformed) {
37
+ const owner = inspection.pid === undefined ? "an unknown process" : `PID ${inspection.pid}`;
38
+ throw new Error(`ForgeRelay state is already in use by ${owner}: ${path}`);
39
+ }
40
+ rmSync(path, { force: true });
41
+ }
42
+ }
43
+ throw new Error(`Unable to acquire ForgeRelay runtime lease: ${path}`);
44
+ }
45
+ export function inspectRuntimeLease(stateDir) {
46
+ const path = runtimeLeasePath(stateDir);
47
+ let raw;
48
+ try {
49
+ raw = readFileSync(path, "utf8");
50
+ }
51
+ catch (error) {
52
+ if (isErrno(error, "ENOENT")) {
53
+ return { path, active: false, stale: false, malformed: false };
54
+ }
55
+ throw error;
56
+ }
57
+ const record = parseRecord(raw);
58
+ if (!record)
59
+ return { path, active: true, stale: false, malformed: true };
60
+ const active = processIsAlive(record.pid);
61
+ return {
62
+ path,
63
+ active,
64
+ stale: !active,
65
+ pid: record.pid,
66
+ malformed: false,
67
+ };
68
+ }
69
+ function releaseRuntimeLease(path, expected) {
70
+ let current;
71
+ try {
72
+ current = parseRecord(readFileSync(path, "utf8"));
73
+ }
74
+ catch (error) {
75
+ if (isErrno(error, "ENOENT"))
76
+ return;
77
+ throw error;
78
+ }
79
+ if (!current || current.pid !== expected.pid || current.token !== expected.token)
80
+ return;
81
+ rmSync(path, { force: true });
82
+ }
83
+ function parseRecord(raw) {
84
+ try {
85
+ const value = JSON.parse(raw);
86
+ if (!Number.isSafeInteger(value.pid) || (value.pid ?? 0) <= 0)
87
+ return undefined;
88
+ if (typeof value.token !== "string" || value.token.length < 16)
89
+ return undefined;
90
+ if (typeof value.startedAt !== "string" || !Number.isFinite(Date.parse(value.startedAt)))
91
+ return undefined;
92
+ return { pid: value.pid, token: value.token, startedAt: value.startedAt };
93
+ }
94
+ catch {
95
+ return undefined;
96
+ }
97
+ }
98
+ function processIsAlive(pid) {
99
+ try {
100
+ process.kill(pid, 0);
101
+ return true;
102
+ }
103
+ catch (error) {
104
+ return !isErrno(error, "ESRCH");
105
+ }
106
+ }
107
+ function isErrno(error, code) {
108
+ return error instanceof Error && "code" in error && error.code === code;
109
+ }