@akira-tl/forgerelay 0.2.1 → 0.2.3

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 (88) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/file-mutations.js +50 -0
  3. package/dist/mcp/server-instructions.js +15 -6
  4. package/dist/server.js +145 -2
  5. package/dist/ui/.vite/manifest.json +280 -280
  6. package/dist/ui/assets/{angular-html-CovppXt5.js → angular-html-CQmCUfkv.js} +1 -1
  7. package/dist/ui/assets/{angular-ts-0Y9l6YXu.js → angular-ts-BSbfxpMS.js} +1 -1
  8. package/dist/ui/assets/{apl-BmBhiklA.js → apl-CWCaH-E3.js} +1 -1
  9. package/dist/ui/assets/{astro-BAmqcqyV.js → astro-R_p4G0xA.js} +1 -1
  10. package/dist/ui/assets/{blade-BjFcmRJo.js → blade-irHensDY.js} +1 -1
  11. package/dist/ui/assets/{c-CaOJn4x0.js → c-_XEQUoq6.js} +1 -1
  12. package/dist/ui/assets/{cobol-DR4zWFMt.js → cobol-Css6VQjJ.js} +1 -1
  13. package/dist/ui/assets/{coffee-ReGSThmM.js → coffee-CpXUkyDm.js} +1 -1
  14. package/dist/ui/assets/{cpp-CnlQh6MO.js → cpp-BQHsPWwI.js} +1 -1
  15. package/dist/ui/assets/{crystal-BrpPbH1U.js → crystal-Cbv8J9Fm.js} +1 -1
  16. package/dist/ui/assets/{css-DRBEvyPU.js → css-D8DkrS3U.js} +1 -1
  17. package/dist/ui/assets/{edge-cfwpdvl9.js → edge-bBL_XDAG.js} +1 -1
  18. package/dist/ui/assets/{elixir-7owrJxb6.js → elixir-CQjsM9sA.js} +1 -1
  19. package/dist/ui/assets/{elm-udiOjODk.js → elm-DLFl-jEZ.js} +1 -1
  20. package/dist/ui/assets/{erb-8ctXHMkS.js → erb-BJjsdB_Q.js} +1 -1
  21. package/dist/ui/assets/{git-rebase-P0V_qK1w.js → git-rebase-CqP5A2s0.js} +1 -1
  22. package/dist/ui/assets/{glimmer-js-CZ14ED7U.js → glimmer-js-B5Hh_7xe.js} +1 -1
  23. package/dist/ui/assets/{glimmer-ts-DtBSFP-o.js → glimmer-ts-oaeSAC8s.js} +1 -1
  24. package/dist/ui/assets/{glsl-BX2BkZJK.js → glsl-BylkOpcF.js} +1 -1
  25. package/dist/ui/assets/{graphql-Dj_cPv4w.js → graphql-DsVRvP6S.js} +1 -1
  26. package/dist/ui/assets/{hack-DGRkd8xn.js → hack-D4N5abT_.js} +1 -1
  27. package/dist/ui/assets/{haml-BAPSvujW.js → haml-CIAJQIox.js} +1 -1
  28. package/dist/ui/assets/{handlebars-PYksdULG.js → handlebars-DDEZyNXR.js} +1 -1
  29. package/dist/ui/assets/{heavy-payload-BjE0LSUi.js → heavy-payload-DafM8yjB.js} +1 -1
  30. package/dist/ui/assets/{html-derivative-C6q86ZrS.js → html-derivative-CZ91Y2d5.js} +1 -1
  31. package/dist/ui/assets/{html-DloAPGZ1.js → html-zDy-3lvy.js} +1 -1
  32. package/dist/ui/assets/{http-fPvYDvHA.js → http-ezaodZRf.js} +1 -1
  33. package/dist/ui/assets/{hurl-Dbir4WvE.js → hurl-BmL0o7TO.js} +1 -1
  34. package/dist/ui/assets/{java-DvkqXg3z.js → java-Q2C0vwbH.js} +1 -1
  35. package/dist/ui/assets/{javascript-TONTV6Ty.js → javascript-UDhBkHE3.js} +1 -1
  36. package/dist/ui/assets/{jinja-OM1F5Gct.js → jinja-BWRskcYS.js} +1 -1
  37. package/dist/ui/assets/{jison-CBttugts.js → jison-B18BY9Ds.js} +1 -1
  38. package/dist/ui/assets/{json-Db5oY-7J.js → json-DNj7MpRr.js} +1 -1
  39. package/dist/ui/assets/{jsx-DKeJCgsc.js → jsx-CVpHJ6cr.js} +1 -1
  40. package/dist/ui/assets/{julia-NlIPhXaL.js → julia-CJBNBS9c.js} +1 -1
  41. package/dist/ui/assets/{just-BXBJB-mX.js → just-Bmu2JCQT.js} +1 -1
  42. package/dist/ui/assets/{latex-CGK-6yDy.js → latex-BB7F93KY.js} +1 -1
  43. package/dist/ui/assets/{liquid-D7waQ0MY.js → liquid-Btnomc6E.js} +1 -1
  44. package/dist/ui/assets/{lua-C_kkt4h1.js → lua-D0FYT9Vo.js} +1 -1
  45. package/dist/ui/assets/{marko-BokXuCts.js → marko-MHLw0ZlK.js} +1 -1
  46. package/dist/ui/assets/{mdc-Bk0nnUJA.js → mdc-CSr-suGy.js} +1 -1
  47. package/dist/ui/assets/{nginx-jM6NF9TV.js → nginx-ur1l6E-g.js} +1 -1
  48. package/dist/ui/assets/{nim-hYsL-WKb.js → nim-B2k0IugA.js} +1 -1
  49. package/dist/ui/assets/{perl-DBI_cUHJ.js → perl-BqOHxFDn.js} +1 -1
  50. package/dist/ui/assets/{php-BX_aQhFl.js → php-DzPK6O1_.js} +1 -1
  51. package/dist/ui/assets/{pug-DwFAYy1e.js → pug-D169OZkr.js} +1 -1
  52. package/dist/ui/assets/{qml-eLSwQUKt.js → qml-BtemJTC4.js} +1 -1
  53. package/dist/ui/assets/{r-BMnQsMLf.js → r-BGVHu0bd.js} +1 -1
  54. package/dist/ui/assets/{razor-CgciiMyw.js → razor-Diisjg1d.js} +1 -1
  55. package/dist/ui/assets/{regexp-ZrURNrn5.js → regexp-B2F5vMZ6.js} +1 -1
  56. package/dist/ui/assets/{review-payload-HGkpJjjm.js → review-payload-B-3I3Oj_.js} +1 -1
  57. package/dist/ui/assets/{rst-EoAOr3M6.js → rst-BxpeZwuT.js} +1 -1
  58. package/dist/ui/assets/{ruby-Dqx5_Rqw.js → ruby-DrCq4riN.js} +1 -1
  59. package/dist/ui/assets/{sas-Bf6xPLSX.js → sas-CI_2W-1n.js} +1 -1
  60. package/dist/ui/assets/{scrollbar-DX4Ujotb.js → scrollbar-DHsDF5w-.js} +3 -3
  61. package/dist/ui/assets/{scss-DDpW3yTd.js → scss-BxtyHZ1p.js} +1 -1
  62. package/dist/ui/assets/{shellscript-DayAQ-W9.js → shellscript-BY_YYrHT.js} +1 -1
  63. package/dist/ui/assets/{shellsession-jPr_lSnA.js → shellsession-C6uBrLmA.js} +1 -1
  64. package/dist/ui/assets/{soy-X9adks8G.js → soy-BHM9gdPh.js} +1 -1
  65. package/dist/ui/assets/{sql-Bmt09AIR.js → sql-XmhfEGz_.js} +1 -1
  66. package/dist/ui/assets/{stata-DVkNpH8r.js → stata-BbHY7NEo.js} +1 -1
  67. package/dist/ui/assets/{surrealql-eEXzMb8j.js → surrealql-CD49DZ3E.js} +1 -1
  68. package/dist/ui/assets/{svelte-CFoBxZF3.js → svelte-CbYsEYJY.js} +1 -1
  69. package/dist/ui/assets/{templ-Da_324JF.js → templ-B5JoUxEB.js} +1 -1
  70. package/dist/ui/assets/{tex-HAzlmKJ0.js → tex-DZcOfTZK.js} +1 -1
  71. package/dist/ui/assets/{ts-tags-7iLrNH8p.js → ts-tags-BeU-xqc0.js} +1 -1
  72. package/dist/ui/assets/{tsx-gZaXf8PJ.js → tsx-V7W1xGl3.js} +1 -1
  73. package/dist/ui/assets/{twig-CLpQ7p1N.js → twig-MIaJo5BU.js} +1 -1
  74. package/dist/ui/assets/{typescript-B2WWCRI2.js → typescript-C0WESuVc.js} +1 -1
  75. package/dist/ui/assets/{vue-No_8Jygd.js → vue-eJHwc9ra.js} +1 -1
  76. package/dist/ui/assets/{vue-html-kHJg98Kk.js → vue-html-CLmBujTU.js} +1 -1
  77. package/dist/ui/assets/{vue-vine-Df4cEYaN.js → vue-vine-BP5kjIGb.js} +1 -1
  78. package/dist/ui/assets/{workspace-app-C_wsC6VL.js → workspace-app-C1qR5cAY.js} +3 -3
  79. package/dist/ui/assets/{xml-DUZ05dpG.js → xml-j7pmyP48.js} +1 -1
  80. package/dist/ui/assets/{xsl-Bwp3w2OF.js → xsl-5VFHbg6o.js} +1 -1
  81. package/dist/ui/assets/{yaml-IA_-TEM1.js → yaml-DxFAt-KU.js} +1 -1
  82. package/dist/ui/workspace-app.html +1 -1
  83. package/docs/chatgpt-coding-workflow.md +12 -1
  84. package/docs/configuration.md +3 -3
  85. package/docs/debugging.md +4 -4
  86. package/docs/security.md +15 -0
  87. package/package.json +2 -2
  88. package/scripts/debug/accept.mjs +41 -2
@@ -83,6 +83,11 @@ try {
83
83
  assert.equal(initialized.message.result.serverInfo.name, "forgerelay");
84
84
  assert.equal(initialized.message.result.serverInfo.title, "ForgeRelay");
85
85
  assert.equal(initialized.message.result.serverInfo.version, packageJson.version);
86
+ const serverInstructions = initialized.message.result.instructions ?? "";
87
+ assert.match(serverInstructions, /Shell commands may modify ordinary project files/);
88
+ assert.match(serverInstructions, /\/etc\/sudoers/);
89
+ assert.match(serverInstructions, /configuration files through shell only when the user's request explicitly calls for that configuration change/);
90
+ assert.doesNotMatch(serverInstructions, /Do not create or modify files with bash/);
86
91
  pass(
87
92
  "MCP initialize",
88
93
  JSON.stringify(initialized.message.result.serverInfo),
@@ -103,9 +108,13 @@ try {
103
108
  params: {},
104
109
  }).message.result.tools;
105
110
  const toolNames = tools.map((tool) => tool.name);
106
- for (const expected of ["open_workspace", "close_worktree", "read", "write", "edit", "grep", "glob", "ls", "bash"]) {
111
+ for (const expected of ["open_workspace", "close_worktree", "read", "write", "edit", "rename", "delete", "grep", "glob", "ls", "bash"]) {
107
112
  assert.ok(toolNames.includes(expected), `missing debug tool ${expected}`);
108
113
  }
114
+ const bashTool = tools.find((tool) => tool.name === "bash");
115
+ assert.match(bashTool?.description ?? "", /may modify ordinary project files/);
116
+ assert.match(bashTool?.description ?? "", /\/etc\/sudoers/);
117
+ assert.doesNotMatch(bashTool?.description ?? "", /Do not use bash to create, move, rename, or delete project files/);
109
118
  pass("MCP tools/list", `${toolNames.length} tools: ${toolNames.join(", ")}`);
110
119
 
111
120
  const opened = callTool(oauth.accessToken, sessionId, 3, "open_workspace", {
@@ -146,6 +155,21 @@ try {
146
155
  assert.equal(failedEdit.isError, true);
147
156
  pass("failed tool path", "edit returned isError=true and triggered AfterToolFailure");
148
157
 
158
+ const renamedWorkspaceFile = callTool(oauth.accessToken, sessionId, 74, "rename", {
159
+ workspaceId,
160
+ path: "acceptance.txt",
161
+ newPath: "renamed-acceptance.txt",
162
+ });
163
+ assert.equal(renamedWorkspaceFile.isError, undefined);
164
+ assert.equal(readFileSync(join(checkoutWorkspace, "renamed-acceptance.txt"), "utf8"), "forgerelay 7677 acceptance\n");
165
+ const deletedWorkspaceFile = callTool(oauth.accessToken, sessionId, 75, "delete", {
166
+ workspaceId,
167
+ path: "renamed-acceptance.txt",
168
+ });
169
+ assert.equal(deletedWorkspaceFile.isError, undefined);
170
+ assert.equal(existsSync(join(checkoutWorkspace, "renamed-acceptance.txt")), false);
171
+ pass("rename + delete", "workspace file renamed and deleted through MCP");
172
+
149
173
  mkdirSync(tempAcceptanceRoot, { recursive: true });
150
174
  const tempFile = join(tempAcceptanceRoot, "mcp-temp.txt");
151
175
  const tempWritten = callTool(oauth.accessToken, sessionId, 70, "write", {
@@ -169,13 +193,28 @@ try {
169
193
  assert.equal(tempEdited.isError, undefined);
170
194
  assert.equal(readFileSync(tempFile, "utf8"), "forgerelay temp after edit\n");
171
195
 
196
+ const renamedTempFile = join(tempAcceptanceRoot, "mcp-temp-renamed.txt");
197
+ const tempRenamed = callTool(oauth.accessToken, sessionId, 76, "rename", {
198
+ workspaceId,
199
+ path: tempFile,
200
+ newPath: renamedTempFile,
201
+ });
202
+ assert.equal(tempRenamed.isError, undefined);
203
+ assert.equal(readFileSync(renamedTempFile, "utf8"), "forgerelay temp after edit\n");
204
+ const tempDeleted = callTool(oauth.accessToken, sessionId, 77, "delete", {
205
+ workspaceId,
206
+ path: renamedTempFile,
207
+ });
208
+ assert.equal(tempDeleted.isError, undefined);
209
+ assert.equal(existsSync(renamedTempFile), false);
210
+
172
211
  const outsideRoots = callTool(oauth.accessToken, sessionId, 73, "read", {
173
212
  workspaceId,
174
213
  path: join(homedir(), "forgerelay-debug-outside-roots.txt"),
175
214
  });
176
215
  assert.equal(outsideRoots.isError, true);
177
216
  assert.match(toolText(outsideRoots), /outside allowed roots/i);
178
- pass("OS temp file tools", "write + read + edit passed; arbitrary home path rejected");
217
+ pass("OS temp file tools", "write + read + edit + rename + delete passed; arbitrary home path rejected");
179
218
 
180
219
  setupGitProject(gitProject);
181
220
  const worktreeOpened = callTool(oauth.accessToken, sessionId, 8, "open_workspace", {