magenta-canon 0.1.2 → 0.1.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.
- package/package.json +1 -1
- package/scripts/demo.mjs +22 -7
- package/scripts/mcp-demo-drive.mjs +4 -1
- package/scripts/win-paths.mjs +19 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "magenta-canon",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"description": "A verifiable MCP accountability gateway for AI-agent tool calls: allows authorized calls, blocks unauthorized calls, records both, and produces cryptographic evidence anyone can verify.",
|
package/scripts/demo.mjs
CHANGED
|
@@ -127,17 +127,23 @@ const capture = (cmd, args, opts = {}) =>
|
|
|
127
127
|
const isWindows = process.platform === "win32";
|
|
128
128
|
const runDriver = (configPath, env) =>
|
|
129
129
|
new Promise((resolve) => {
|
|
130
|
-
|
|
130
|
+
// Resolve the driver as an absolute, spawn-safe native path (cwd-independent
|
|
131
|
+
// and correct under the npm-cache _npx path on Windows).
|
|
132
|
+
const driverPath = path.join(ROOT, "scripts", "mcp-demo-drive.mjs");
|
|
133
|
+
const ch = spawn(process.execPath, [driverPath, configPath], {
|
|
131
134
|
// `detached` only buys us a process group on POSIX; skip it on Windows.
|
|
132
|
-
|
|
135
|
+
// Capture stderr too, so a child failure surfaces a real cause instead of
|
|
136
|
+
// an opaque "MCP driver failed".
|
|
137
|
+
cwd: ROOT, detached: !isWindows, stdio: ["ignore", "pipe", "pipe"], env,
|
|
133
138
|
});
|
|
134
|
-
let out = "";
|
|
139
|
+
let out = "", err = "";
|
|
135
140
|
ch.stdout.on("data", (d) => (out += d));
|
|
141
|
+
ch.stderr.on("data", (d) => (err += d));
|
|
136
142
|
const cleanup = () => killChildTree(ch);
|
|
137
|
-
const watchdog = setTimeout(() => { cleanup(); resolve({ code: 124, out }); }, 30_000);
|
|
143
|
+
const watchdog = setTimeout(() => { cleanup(); resolve({ code: 124, out, err }); }, 30_000);
|
|
138
144
|
ch.on("exit", (code) => {
|
|
139
145
|
clearTimeout(watchdog);
|
|
140
|
-
setTimeout(() => { cleanup(); resolve({ code: code ?? 0, out }); }, 150);
|
|
146
|
+
setTimeout(() => { cleanup(); resolve({ code: code ?? 0, out, err }); }, 150);
|
|
141
147
|
});
|
|
142
148
|
});
|
|
143
149
|
|
|
@@ -199,6 +205,15 @@ async function main() {
|
|
|
199
205
|
// ephemeral control plane. Semantics (capabilities, tool map) are unchanged.
|
|
200
206
|
const base = JSON.parse(readFileSync(path.join(ROOT, "examples/magenta-gateway.demo.config.json"), "utf8"));
|
|
201
207
|
base.controlPlane = { url: URL, internalKey: INTERNAL_KEY };
|
|
208
|
+
// Make the downstream command absolute and launch it with the current Node
|
|
209
|
+
// (process.execPath) rather than a bare "node" + relative arg — cwd-independent
|
|
210
|
+
// and correct under the npm-cache _npx path, including on Windows.
|
|
211
|
+
if (base.downstream && Array.isArray(base.downstream.args)) {
|
|
212
|
+
base.downstream.command = process.execPath;
|
|
213
|
+
base.downstream.args = base.downstream.args.map((a) =>
|
|
214
|
+
a.endsWith(".mjs") || a.endsWith(".js") ? path.join(ROOT, a) : a,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
202
217
|
writeFileSync(F.config, JSON.stringify(base, null, 2));
|
|
203
218
|
|
|
204
219
|
const drive = await runDriver(F.config, {
|
|
@@ -208,8 +223,8 @@ async function main() {
|
|
|
208
223
|
MAGENTA_TSX_CLI: TSX_CLI,
|
|
209
224
|
PATH: `${path.join(ROOT, "node_modules", ".bin")}${path.delimiter}${process.env.PATH}`,
|
|
210
225
|
});
|
|
211
|
-
if (drive.code !== 0) die("MCP driver failed.", drive.out);
|
|
212
|
-
if (!/HANDSHAKE_OK/.test(drive.out)) die("MCP handshake did not complete.", drive.out);
|
|
226
|
+
if (drive.code !== 0) die("MCP driver failed.", [drive.out, drive.err].filter(Boolean).join("\n"));
|
|
227
|
+
if (!/HANDSHAKE_OK/.test(drive.out)) die("MCP handshake did not complete.", [drive.out, drive.err].filter(Boolean).join("\n"));
|
|
213
228
|
for (const line of drive.out.trim().split("\n")) {
|
|
214
229
|
if (!line.trim()) continue;
|
|
215
230
|
const colored = line.startsWith("ALLOWED") ? grn(line)
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { spawn } from "node:child_process";
|
|
10
10
|
import readline from "node:readline";
|
|
11
|
+
import { siblingPath } from "./win-paths.mjs";
|
|
11
12
|
|
|
12
13
|
const cfg = process.argv[2];
|
|
13
14
|
if (!cfg) { console.error("usage: node scripts/mcp-demo-drive.mjs <config>"); process.exit(2); }
|
|
@@ -15,7 +16,9 @@ if (!cfg) { console.error("usage: node scripts/mcp-demo-drive.mjs <config>"); pr
|
|
|
15
16
|
// Launch the gateway. When MAGENTA_TSX_CLI is provided (by the demo orchestrator,
|
|
16
17
|
// incl. the installed-package CLI) run it as `node <tsxCli> mcp-gateway.ts`;
|
|
17
18
|
// otherwise fall back to `npx tsx` for the documented manual flow.
|
|
18
|
-
|
|
19
|
+
// NOTE: use fileURLToPath (via siblingPath), NOT URL.pathname — the latter yields
|
|
20
|
+
// `/C:/…` on Windows, which tsx/node cannot open (broke step 3/7 on Windows).
|
|
21
|
+
const gatewayPath = siblingPath(import.meta.url, "./mcp-gateway.ts");
|
|
19
22
|
const gw = process.env.MAGENTA_TSX_CLI
|
|
20
23
|
? spawn(process.execPath, [process.env.MAGENTA_TSX_CLI, gatewayPath, cfg], { stdio: ["pipe", "pipe", "inherit"] })
|
|
21
24
|
: spawn("npx", ["tsx", gatewayPath, cfg], { stdio: ["pipe", "pipe", "inherit"] });
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Windows-safe path helpers for the demo's child-process wiring.
|
|
3
|
+
*
|
|
4
|
+
* The MCP demo driver spawns the gateway script by resolving a sibling file from
|
|
5
|
+
* `import.meta.url`. The naive `new URL("./x.ts", import.meta.url).pathname`
|
|
6
|
+
* returns a POSIX-style string with a spurious leading slash before the drive
|
|
7
|
+
* letter on Windows (e.g. `/C:/Users/.../x.ts`), which Node/tsx cannot open —
|
|
8
|
+
* this broke `npx magenta-canon demo` at step 3/7 on Windows. `fileURLToPath`
|
|
9
|
+
* produces the correct native path on every platform (`C:\Users\...\x.ts` on
|
|
10
|
+
* Windows, `/home/.../x.ts` on POSIX).
|
|
11
|
+
*
|
|
12
|
+
* Pure; no process/verifier/witness/evidence/gateway semantics.
|
|
13
|
+
*/
|
|
14
|
+
import { fileURLToPath } from "node:url";
|
|
15
|
+
|
|
16
|
+
/** Resolve a sibling file next to `metaUrl` as a spawn-safe, native absolute path. */
|
|
17
|
+
export function siblingPath(metaUrl, name) {
|
|
18
|
+
return fileURLToPath(new URL(name, metaUrl));
|
|
19
|
+
}
|