@akira-tl/forgerelay 0.3.4 → 0.3.5

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 (94) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/capabilities/artifacts-review/GUIDE.md +2 -4
  3. package/dist/artifact-tools.js +0 -128
  4. package/dist/capabilities.js +2 -5
  5. package/dist/hooks.js +12 -0
  6. package/dist/mcp/server-instructions.js +4 -9
  7. package/dist/review-checkpoints.js +4 -4
  8. package/dist/server.js +5 -263
  9. package/dist/ui/.vite/manifest.json +280 -280
  10. package/dist/ui/assets/{angular-html-CQmCUfkv.js → angular-html-BT2Z6jee.js} +1 -1
  11. package/dist/ui/assets/{angular-ts-BSbfxpMS.js → angular-ts-BwPE8YDt.js} +1 -1
  12. package/dist/ui/assets/{apl-CWCaH-E3.js → apl-CGbONVvU.js} +1 -1
  13. package/dist/ui/assets/{astro-R_p4G0xA.js → astro-DIAPy7cj.js} +1 -1
  14. package/dist/ui/assets/{blade-irHensDY.js → blade-Cgtd19Ky.js} +1 -1
  15. package/dist/ui/assets/{c-_XEQUoq6.js → c-acnvZ8tm.js} +1 -1
  16. package/dist/ui/assets/{cobol-Css6VQjJ.js → cobol-G-7HLVKW.js} +1 -1
  17. package/dist/ui/assets/{coffee-CpXUkyDm.js → coffee-DQFyKxEB.js} +1 -1
  18. package/dist/ui/assets/{cpp-BQHsPWwI.js → cpp-UyrmHXan.js} +1 -1
  19. package/dist/ui/assets/{crystal-Cbv8J9Fm.js → crystal-DuiWhEO3.js} +1 -1
  20. package/dist/ui/assets/{css-D8DkrS3U.js → css-D_WCbY6m.js} +1 -1
  21. package/dist/ui/assets/{edge-bBL_XDAG.js → edge-COkalhFi.js} +1 -1
  22. package/dist/ui/assets/{elixir-CQjsM9sA.js → elixir-cdlzbYR1.js} +1 -1
  23. package/dist/ui/assets/{elm-DLFl-jEZ.js → elm-ZwDYuYpb.js} +1 -1
  24. package/dist/ui/assets/{erb-BJjsdB_Q.js → erb-C8WG9TtC.js} +1 -1
  25. package/dist/ui/assets/{git-rebase-CqP5A2s0.js → git-rebase-CMlDVJBT.js} +1 -1
  26. package/dist/ui/assets/{glimmer-js-B5Hh_7xe.js → glimmer-js-DeLOQlol.js} +1 -1
  27. package/dist/ui/assets/{glimmer-ts-oaeSAC8s.js → glimmer-ts-DTEM04TK.js} +1 -1
  28. package/dist/ui/assets/{glsl-BylkOpcF.js → glsl-IJV4SB-M.js} +1 -1
  29. package/dist/ui/assets/{graphql-DsVRvP6S.js → graphql-PM-WDnoB.js} +1 -1
  30. package/dist/ui/assets/{hack-D4N5abT_.js → hack-C14sh6Lh.js} +1 -1
  31. package/dist/ui/assets/{haml-CIAJQIox.js → haml-B_5nS6Kx.js} +1 -1
  32. package/dist/ui/assets/{handlebars-DDEZyNXR.js → handlebars-eS-J0O-M.js} +1 -1
  33. package/dist/ui/assets/{heavy-payload-DafM8yjB.js → heavy-payload-BKB0QDOI.js} +1 -1
  34. package/dist/ui/assets/{html-zDy-3lvy.js → html-C3TPjrC5.js} +1 -1
  35. package/dist/ui/assets/{html-derivative-CZ91Y2d5.js → html-derivative-BlVZU2id.js} +1 -1
  36. package/dist/ui/assets/{http-ezaodZRf.js → http-BmbZzA5x.js} +1 -1
  37. package/dist/ui/assets/{hurl-BmL0o7TO.js → hurl-Dnd_YpOD.js} +1 -1
  38. package/dist/ui/assets/{java-Q2C0vwbH.js → java-ne9HdIVn.js} +1 -1
  39. package/dist/ui/assets/{javascript-UDhBkHE3.js → javascript-DpHT58rr.js} +1 -1
  40. package/dist/ui/assets/{jinja-BWRskcYS.js → jinja-DTvkZdHA.js} +1 -1
  41. package/dist/ui/assets/{jison-B18BY9Ds.js → jison-DUJG-tmh.js} +1 -1
  42. package/dist/ui/assets/{json-DNj7MpRr.js → json-DJmnBdxW.js} +1 -1
  43. package/dist/ui/assets/{jsx-CVpHJ6cr.js → jsx-BclJnZnN.js} +1 -1
  44. package/dist/ui/assets/{julia-CJBNBS9c.js → julia-P5B4pHFa.js} +1 -1
  45. package/dist/ui/assets/{just-Bmu2JCQT.js → just-DYaoh7C6.js} +1 -1
  46. package/dist/ui/assets/{latex-BB7F93KY.js → latex-CI5lnkWV.js} +1 -1
  47. package/dist/ui/assets/{liquid-Btnomc6E.js → liquid-D3LnAs_z.js} +1 -1
  48. package/dist/ui/assets/{lua-D0FYT9Vo.js → lua-dZC7ZQIY.js} +1 -1
  49. package/dist/ui/assets/{marko-MHLw0ZlK.js → marko-CRDrjqfS.js} +1 -1
  50. package/dist/ui/assets/{mdc-CSr-suGy.js → mdc-ZzwgmJVn.js} +1 -1
  51. package/dist/ui/assets/{nginx-ur1l6E-g.js → nginx-BAvFXGSV.js} +1 -1
  52. package/dist/ui/assets/{nim-B2k0IugA.js → nim-BHIFawe9.js} +1 -1
  53. package/dist/ui/assets/{perl-BqOHxFDn.js → perl-C_f5AnLa.js} +1 -1
  54. package/dist/ui/assets/{php-DzPK6O1_.js → php-DDqpegL5.js} +1 -1
  55. package/dist/ui/assets/{pug-D169OZkr.js → pug-CSaAZXyd.js} +1 -1
  56. package/dist/ui/assets/{qml-BtemJTC4.js → qml-CNHvRs_z.js} +1 -1
  57. package/dist/ui/assets/{r-BGVHu0bd.js → r-CAfoQND2.js} +1 -1
  58. package/dist/ui/assets/{razor-Diisjg1d.js → razor-BDfAPy7I.js} +1 -1
  59. package/dist/ui/assets/{regexp-B2F5vMZ6.js → regexp-Mug5jltQ.js} +1 -1
  60. package/dist/ui/assets/{review-payload-B-3I3Oj_.js → review-payload-D7GIdYDj.js} +1 -1
  61. package/dist/ui/assets/{rst-BxpeZwuT.js → rst-BzPP2gle.js} +1 -1
  62. package/dist/ui/assets/{ruby-DrCq4riN.js → ruby-CQjzokzX.js} +1 -1
  63. package/dist/ui/assets/{sas-CI_2W-1n.js → sas-Bp37KGr7.js} +1 -1
  64. package/dist/ui/assets/{scrollbar-DHsDF5w-.js → scrollbar-HUMBdLLK.js} +3 -3
  65. package/dist/ui/assets/{scss-BxtyHZ1p.js → scss-C_Z1DYnw.js} +1 -1
  66. package/dist/ui/assets/{shellscript-BY_YYrHT.js → shellscript-CLfJpn3I.js} +1 -1
  67. package/dist/ui/assets/{shellsession-C6uBrLmA.js → shellsession-CNc62UhY.js} +1 -1
  68. package/dist/ui/assets/{soy-BHM9gdPh.js → soy-CF44SpBo.js} +1 -1
  69. package/dist/ui/assets/{sql-XmhfEGz_.js → sql-CYnzfiQ1.js} +1 -1
  70. package/dist/ui/assets/{stata-BbHY7NEo.js → stata-DVeMA68W.js} +1 -1
  71. package/dist/ui/assets/{surrealql-CD49DZ3E.js → surrealql-52sF96Yv.js} +1 -1
  72. package/dist/ui/assets/{svelte-CbYsEYJY.js → svelte-ydwT7UbF.js} +1 -1
  73. package/dist/ui/assets/{templ-B5JoUxEB.js → templ-BXcoVoGh.js} +1 -1
  74. package/dist/ui/assets/{tex-DZcOfTZK.js → tex-COsYFp7O.js} +1 -1
  75. package/dist/ui/assets/{ts-tags-BeU-xqc0.js → ts-tags-CF--LE1s.js} +1 -1
  76. package/dist/ui/assets/{tsx-V7W1xGl3.js → tsx-DLBt2-2f.js} +1 -1
  77. package/dist/ui/assets/{twig-MIaJo5BU.js → twig-YoM-DiI5.js} +1 -1
  78. package/dist/ui/assets/{typescript-C0WESuVc.js → typescript-Ce9JGkNI.js} +1 -1
  79. package/dist/ui/assets/{vue-eJHwc9ra.js → vue-B5LDEy4l.js} +1 -1
  80. package/dist/ui/assets/{vue-html-CLmBujTU.js → vue-html-CPdGGk4T.js} +1 -1
  81. package/dist/ui/assets/{vue-vine-BP5kjIGb.js → vue-vine-B5bjgk0a.js} +1 -1
  82. package/dist/ui/assets/{workspace-app-C1qR5cAY.js → workspace-app-Cm9EX5x4.js} +3 -3
  83. package/dist/ui/assets/{xml-j7pmyP48.js → xml-Cun8xb0T.js} +1 -1
  84. package/dist/ui/assets/{xsl-5VFHbg6o.js → xsl-wls_CEK_.js} +1 -1
  85. package/dist/ui/assets/{yaml-DxFAt-KU.js → yaml-BxuXn9OL.js} +1 -1
  86. package/dist/ui/workspace-app.html +1 -1
  87. package/docs/artifact-exchange.md +4 -3
  88. package/docs/chatgpt-coding-workflow.md +5 -3
  89. package/docs/configuration.md +12 -10
  90. package/docs/debugging.md +2 -2
  91. package/docs/gotchas.md +3 -3
  92. package/docs/security.md +3 -2
  93. package/package.json +1 -1
  94. package/scripts/debug/accept.mjs +53 -12
@@ -37,14 +37,16 @@ assertCurlAvailable();
37
37
  await assertDebugPortFree();
38
38
  rmSync(acceptanceRoot, { recursive: true, force: true });
39
39
  mkdirSync(acceptanceRoot, { recursive: true });
40
+ setupGitProject(checkoutWorkspace);
40
41
 
41
42
  const { env } = createDebugEnvironment({
42
43
  ownerToken,
43
44
  stateDir,
44
45
  worktreeRoot,
45
46
  hookLog,
46
- widgets: "full",
47
+ widgets: "changes",
47
48
  });
49
+ env.FORGERELAY_ARTIFACTS = "1";
48
50
  const doctor = spawnSync(process.execPath, ["--import", "tsx", "src/cli.ts", "doctor"], {
49
51
  cwd: repoRoot,
50
52
  env,
@@ -53,7 +55,7 @@ const doctor = spawnSync(process.execPath, ["--import", "tsx", "src/cli.ts", "do
53
55
  assert.equal(doctor.status, 0, doctor.stderr);
54
56
  assert.match(doctor.stdout, /Public base URL: http:\/\/127\.0\.0\.1:7677/);
55
57
  assert.match(doctor.stdout, /Tool mode: full/);
56
- assert.match(doctor.stdout, /Widgets: full/);
58
+ assert.match(doctor.stdout, /Widgets: changes/);
57
59
  assert.match(doctor.stdout, /Trust proxy: off/);
58
60
  pass("doctor resolved MCP shape", "public URL + tool/widgets/proxy state");
59
61
 
@@ -129,11 +131,17 @@ try {
129
131
  params: {},
130
132
  }).message.result.tools;
131
133
  const toolNames = tools.map((tool) => tool.name);
132
- for (const expected of ["open_workspace", "close_workspace", "read", "write", "edit", "rename", "delete", "grep", "glob", "ls", "bash", "capability"]) {
133
- assert.ok(toolNames.includes(expected), `missing debug tool ${expected}`);
134
- }
135
- assert.equal(toolNames.includes("close_worktree"), false);
136
- assert.equal(toolNames.includes("write_stdin"), false);
134
+ assert.deepEqual(toolNames, [
135
+ "open_workspace",
136
+ "capability",
137
+ "close_workspace",
138
+ "read",
139
+ "write",
140
+ "edit",
141
+ "rename",
142
+ "delete",
143
+ "bash",
144
+ ]);
137
145
  const bashTool = tools.find((tool) => tool.name === "bash");
138
146
  assert.match(bashTool?.description ?? "", /local user's authority/);
139
147
  assert.doesNotMatch(bashTool?.description ?? "", /may modify ordinary project files/);
@@ -152,14 +160,16 @@ try {
152
160
  assert.ok(openWorkspaceTool?.outputSchema?.properties?.capabilityFingerprint);
153
161
  assert.ok(openWorkspaceTool?.outputSchema?.properties?.capabilityCatalog);
154
162
  assert.ok(openWorkspaceTool?.outputSchema?.properties?.capabilityGuides);
155
- const templateUri = bashTool?._meta?.ui?.resourceUri;
163
+ const capabilityTool = tools.find((tool) => tool.name === "capability");
164
+ assert.deepEqual(capabilityTool?._meta?.["openai/fileParams"], ["file"]);
165
+ const templateUri = capabilityTool?._meta?.ui?.resourceUri;
156
166
  assert.match(
157
167
  templateUri ?? "",
158
168
  /^ui:\/\/forgerelay\/workspace-app-[0-9a-f]{12}\.html$/,
159
169
  JSON.stringify(bashTool ?? {}),
160
170
  );
161
- assert.deepEqual(bashTool?._meta?.ui?.visibility, ["model", "app"]);
162
- assert.equal(bashTool?._meta?.["openai/outputTemplate"], templateUri);
171
+ assert.deepEqual(capabilityTool?._meta?.ui?.visibility, ["model", "app"]);
172
+ assert.equal(capabilityTool?._meta?.["openai/outputTemplate"], templateUri);
163
173
  pass("MCP tools/list", `${toolNames.length} tools: ${toolNames.join(", ")}`);
164
174
 
165
175
  const resources = mcpRequest(oauth.accessToken, sessionId, {
@@ -231,12 +241,17 @@ try {
231
241
  "process.lifecycle",
232
242
  "hooks.lifecycle",
233
243
  "capability-guides.read",
234
- "inspection.search-tools",
244
+ ...(process.platform === "linux" ? ["artifact.native-download"] : []),
235
245
  "ui.mcp-app",
246
+ "review.changes",
236
247
  ],
237
248
  });
238
249
  const capabilityCatalog = opened.structuredContent.capabilityCatalog;
239
- assert.deepEqual(capabilityCatalog.map((entry) => entry.name), ["hooks.check"]);
250
+ assert.deepEqual(capabilityCatalog.map((entry) => entry.name), [
251
+ "hooks.check",
252
+ "review.changes",
253
+ ...(process.platform === "linux" ? ["artifact.download"] : []),
254
+ ]);
240
255
  assert.equal(capabilityCatalog[0].available, true);
241
256
  assert.equal(capabilityCatalog[0].guide.name, "lifecycle-hooks");
242
257
  const directCapability = callTool(oauth.accessToken, sessionId, 79, "capability", {
@@ -255,6 +270,18 @@ try {
255
270
  assert.equal(describedCapability.isError, undefined);
256
271
  assert.equal(describedCapability.structuredContent.capability.guide.name, "lifecycle-hooks");
257
272
  assert.equal(describedCapability.structuredContent.capability.inputSchema.type, "object");
273
+ if (process.platform === "linux") {
274
+ const describedArtifact = callTool(oauth.accessToken, sessionId, 82, "capability", {
275
+ workspaceId,
276
+ name: "artifact.download",
277
+ action: "describe",
278
+ });
279
+ assert.equal(describedArtifact.isError, undefined);
280
+ assert.deepEqual(describedArtifact.structuredContent.capability.transport, {
281
+ nativeFileArgument: "file",
282
+ gatewayParameter: "file",
283
+ });
284
+ }
258
285
  const unknownCapability = callTool(oauth.accessToken, sessionId, 81, "capability", {
259
286
  workspaceId,
260
287
  name: "unknown.capability",
@@ -267,6 +294,7 @@ try {
267
294
  assert.deepEqual(capabilityGuides.map((guide) => guide.name), [
268
295
  "lifecycle-hooks",
269
296
  "managed-worktrees",
297
+ "artifacts-review",
270
298
  "host-integration",
271
299
  "shell-processes",
272
300
  ]);
@@ -292,6 +320,19 @@ try {
292
320
  assert.match(read.structuredContent.result, /forgerelay 7677 acceptance/);
293
321
  pass("write + read", JSON.stringify(read.structuredContent));
294
322
 
323
+ const reviewed = callTool(oauth.accessToken, sessionId, 83, "capability", {
324
+ workspaceId,
325
+ name: "review.changes",
326
+ action: "run",
327
+ arguments: {},
328
+ });
329
+ assert.equal(reviewed.isError, undefined);
330
+ assert.match(reviewed.structuredContent.result.result, /Changed 1 file/);
331
+ assert.equal(reviewed._meta?.tool, "capability");
332
+ assert.equal(reviewed._meta?.card?.capabilityName, "review.changes");
333
+ assert.match(reviewed._meta?.card?.payload?.patch ?? "", /acceptance\.txt/);
334
+ pass("review.changes", "Capability Gateway produced the aggregate review card");
335
+
295
336
  const shell = callTool(oauth.accessToken, sessionId, 6, "bash", {
296
337
  workspaceId,
297
338
  command: "printf debug-bash-ok",