@macula-io/mcp 0.3.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.
- package/LICENSE +201 -0
- package/README.md +192 -0
- package/dist/bin/install.d.ts +2 -0
- package/dist/bin/install.js +146 -0
- package/dist/bin/install.js.map +1 -0
- package/dist/bin/status.d.ts +2 -0
- package/dist/bin/status.js +86 -0
- package/dist/bin/status.js.map +1 -0
- package/dist/bin/uninstall.d.ts +2 -0
- package/dist/bin/uninstall.js +81 -0
- package/dist/bin/uninstall.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/dist/install/config_merge.d.ts +24 -0
- package/dist/install/config_merge.js +141 -0
- package/dist/install/config_merge.js.map +1 -0
- package/dist/install/existing_cli.d.ts +6 -0
- package/dist/install/existing_cli.js +24 -0
- package/dist/install/existing_cli.js.map +1 -0
- package/dist/install/mcp_clients/claude_code.d.ts +7 -0
- package/dist/install/mcp_clients/claude_code.js +51 -0
- package/dist/install/mcp_clients/claude_code.js.map +1 -0
- package/dist/install/mcp_clients/claude_desktop.d.ts +7 -0
- package/dist/install/mcp_clients/claude_desktop.js +40 -0
- package/dist/install/mcp_clients/claude_desktop.js.map +1 -0
- package/dist/install/mcp_clients/cursor.d.ts +7 -0
- package/dist/install/mcp_clients/cursor.js +30 -0
- package/dist/install/mcp_clients/cursor.js.map +1 -0
- package/dist/install/mcp_clients/index.d.ts +11 -0
- package/dist/install/mcp_clients/index.js +12 -0
- package/dist/install/mcp_clients/index.js.map +1 -0
- package/dist/install/mcp_clients/windsurf.d.ts +7 -0
- package/dist/install/mcp_clients/windsurf.js +30 -0
- package/dist/install/mcp_clients/windsurf.js.map +1 -0
- package/dist/install/platform.d.ts +9 -0
- package/dist/install/platform.js +34 -0
- package/dist/install/platform.js.map +1 -0
- package/dist/macula_cli.d.ts +88 -0
- package/dist/macula_cli.js +189 -0
- package/dist/macula_cli.js.map +1 -0
- package/dist/mesh_artifact.d.ts +2 -0
- package/dist/mesh_artifact.js +63 -0
- package/dist/mesh_artifact.js.map +1 -0
- package/dist/mesh_call.d.ts +2 -0
- package/dist/mesh_call.js +45 -0
- package/dist/mesh_call.js.map +1 -0
- package/dist/mesh_identity.d.ts +2 -0
- package/dist/mesh_identity.js +28 -0
- package/dist/mesh_identity.js.map +1 -0
- package/dist/mesh_publish.d.ts +2 -0
- package/dist/mesh_publish.js +33 -0
- package/dist/mesh_publish.js.map +1 -0
- package/dist/mesh_watch.d.ts +2 -0
- package/dist/mesh_watch.js +53 -0
- package/dist/mesh_watch.js.map +1 -0
- package/dist/reply.d.ts +16 -0
- package/dist/reply.js +24 -0
- package/dist/reply.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/install/platform.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,gEAAgE;AAChE,oEAAoE;AACpE,4BAA4B;AAE5B,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAYzC,MAAM,UAAU,MAAM;IACpB,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,OAAO,GAAG,IAAI,EAAE,CAAC;IAEvB,MAAM,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IACxB,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE7B,OAAO;QACL,EAAE;QACF,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,GAAG,EAAE,IAAI,GAAG,EAAE;KACtB,CAAC;AACJ,CAAC;AAED,SAAS,KAAK,CAAC,CAAkB;IAC/B,IAAI,CAAC,KAAK,OAAO;QAAE,OAAO,OAAO,CAAC;IAClC,IAAI,CAAC,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACpC,IAAI,CAAC,KAAK,OAAO;QAAE,OAAO,OAAO,CAAC;IAClC,MAAM,IAAI,KAAK,CACb,yBAAyB,CAAC,0CAA0C;QAClE,kEAAkE,CAAC,GAAG,CACzE,CAAC;AACJ,CAAC;AAED,SAAS,OAAO,CAAC,CAAS;IACxB,IAAI,CAAC,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAC9B,IAAI,CAAC,KAAK,OAAO;QAAE,OAAO,OAAO,CAAC;IAClC,MAAM,IAAI,KAAK,CACb,qBAAqB,CAAC,kCAAkC,CACzD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/** The station this server targets when a tool call doesn't override it. */
|
|
2
|
+
export declare function defaultStation(): string;
|
|
3
|
+
export declare class MaculaCliUnavailable extends Error {
|
|
4
|
+
}
|
|
5
|
+
export declare class MaculaCliError extends Error {
|
|
6
|
+
readonly bolt4Code?: number | undefined;
|
|
7
|
+
readonly bolt4Name?: string | undefined;
|
|
8
|
+
readonly retryable?: boolean | undefined;
|
|
9
|
+
constructor(message: string, bolt4Code?: number | undefined, bolt4Name?: string | undefined, retryable?: boolean | undefined);
|
|
10
|
+
}
|
|
11
|
+
export interface IdentityResult {
|
|
12
|
+
node_id: string;
|
|
13
|
+
path: string;
|
|
14
|
+
generated: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare const identity: () => Promise<IdentityResult>;
|
|
17
|
+
export interface CallResult {
|
|
18
|
+
procedure: string;
|
|
19
|
+
responded_by: string;
|
|
20
|
+
payload: unknown;
|
|
21
|
+
duration_ms: number;
|
|
22
|
+
}
|
|
23
|
+
export declare const call: (args: {
|
|
24
|
+
host?: string;
|
|
25
|
+
procedure: string;
|
|
26
|
+
callArgs?: Record<string, unknown>;
|
|
27
|
+
timeoutMs?: number;
|
|
28
|
+
}) => Promise<CallResult>;
|
|
29
|
+
export interface PublishResult {
|
|
30
|
+
topic: string;
|
|
31
|
+
seq: number;
|
|
32
|
+
duration_ms: number;
|
|
33
|
+
}
|
|
34
|
+
export declare const publish: (args: {
|
|
35
|
+
host?: string;
|
|
36
|
+
topic: string;
|
|
37
|
+
fact: Record<string, unknown>;
|
|
38
|
+
}) => Promise<PublishResult>;
|
|
39
|
+
export interface WatchEvent {
|
|
40
|
+
topic: string;
|
|
41
|
+
publisher: string;
|
|
42
|
+
seq: number;
|
|
43
|
+
payload: unknown;
|
|
44
|
+
delivered_via: string;
|
|
45
|
+
received_at: string;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parses `macula-cli pubsub watch --json`'s stdout: one WatchEvent per
|
|
49
|
+
* line (NDJSON, not a single envelope -- run() assumes exactly one
|
|
50
|
+
* envelope and doesn't fit this shape). A real failure mid-watch (e.g.
|
|
51
|
+
* the connection drops after some events already arrived) prints as a
|
|
52
|
+
* trailing `{"ok":false,...}` envelope line -- checked by the presence
|
|
53
|
+
* of an "ok" key, not by JSON.parse throwing, since a wrong-shape
|
|
54
|
+
* object is still perfectly valid JSON and would otherwise silently
|
|
55
|
+
* end up in the events array instead of being surfaced as a failure.
|
|
56
|
+
* Exported standalone so this parsing can be unit-tested without
|
|
57
|
+
* spawning a real subprocess.
|
|
58
|
+
*/
|
|
59
|
+
export declare function parseWatchOutput(stdout: string): WatchEvent[];
|
|
60
|
+
/**
|
|
61
|
+
* Watches a topic for up to durationSeconds and returns whatever
|
|
62
|
+
* arrived. Bounded and synchronous -- the MCP tool call itself blocks
|
|
63
|
+
* for the duration, which is the honest shape of a one-shot CLI with no
|
|
64
|
+
* background process to keep a standing subscription alive between
|
|
65
|
+
* calls.
|
|
66
|
+
*/
|
|
67
|
+
export declare const watch: (args: {
|
|
68
|
+
host?: string;
|
|
69
|
+
topic: string;
|
|
70
|
+
durationSeconds: number;
|
|
71
|
+
count?: number;
|
|
72
|
+
}) => Promise<WatchEvent[]>;
|
|
73
|
+
export interface ArtifactPutResult {
|
|
74
|
+
mcid_hex: string;
|
|
75
|
+
size_bytes: number;
|
|
76
|
+
}
|
|
77
|
+
export declare const artifactPut: (args: {
|
|
78
|
+
host?: string;
|
|
79
|
+
contentBase64: string;
|
|
80
|
+
}) => Promise<ArtifactPutResult>;
|
|
81
|
+
export interface ArtifactGetResult {
|
|
82
|
+
content: string;
|
|
83
|
+
size_bytes: number;
|
|
84
|
+
}
|
|
85
|
+
export declare const artifactGet: (args: {
|
|
86
|
+
host?: string;
|
|
87
|
+
mcidHex: string;
|
|
88
|
+
}) => Promise<ArtifactGetResult>;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
// Subprocess client for the `macula-cli` binary (macula-io/macula-cli).
|
|
2
|
+
//
|
|
3
|
+
// macula-mcp does NOT speak QUIC, DHT, or Macula RPC directly, and no
|
|
4
|
+
// longer proxies to a local hecate-daemon (treated as obsolete -- it was
|
|
5
|
+
// a leftover of an abandoned local browser/UI plan). It shells out to
|
|
6
|
+
// macula-cli, a one-shot scriptable CLI built for exactly this: every
|
|
7
|
+
// command takes --json and returns {ok, data} or {ok:false, error}.
|
|
8
|
+
//
|
|
9
|
+
// agent harness --MCP/stdio--> macula-mcp --spawns, parses stdout--> macula-cli --QUIC--> mesh
|
|
10
|
+
//
|
|
11
|
+
// This is a deliberately lean rework (see macula-cli's own README/HOWTO
|
|
12
|
+
// guide for the command set): no standing subscriptions, no activity/
|
|
13
|
+
// inbox audit log, no peer listing -- macula-cli is a one-shot process
|
|
14
|
+
// with no daemon and no storage, so none of those persist between
|
|
15
|
+
// invocations. Point-in-time operations only.
|
|
16
|
+
import { spawn } from "node:child_process";
|
|
17
|
+
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
18
|
+
import { tmpdir, homedir } from "node:os";
|
|
19
|
+
import { join } from "node:path";
|
|
20
|
+
/** The station this server targets when a tool call doesn't override it. */
|
|
21
|
+
export function defaultStation() {
|
|
22
|
+
return process.env.MACULA_MESH_STATION ?? "station-de-frankfurt.macula.io:4433";
|
|
23
|
+
}
|
|
24
|
+
/** Name/path of the macula-cli binary; override for testing or a non-PATH install. */
|
|
25
|
+
function binPath() {
|
|
26
|
+
return process.env.MACULA_CLI_BIN ?? "macula-cli";
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A dedicated, persisted identity for mesh_watch, separate from
|
|
30
|
+
* macula-cli's own default identity (used by every other tool here).
|
|
31
|
+
*
|
|
32
|
+
* Found live (2026-08-29): a station kicks a connection the moment a
|
|
33
|
+
* SECOND connection arrives under the same node ID -- a real
|
|
34
|
+
* anti-duplicate-session guard, not a bug (see macula-cli's own HOWTO
|
|
35
|
+
* guide §1). mesh_watch holds a connection open for up to
|
|
36
|
+
* MAX_DURATION_SECONDS; any OTHER tool call (mesh_call, mesh_publish,
|
|
37
|
+
* ...) that fires while a watch is in flight would otherwise share the
|
|
38
|
+
* same default identity and silently kill the watcher's connection.
|
|
39
|
+
* A separate persisted identity for watch is the minimum fix that
|
|
40
|
+
* covers the common case (watch running alongside other calls) without
|
|
41
|
+
* paying a fresh puzzle-grind on every single tool call the way a
|
|
42
|
+
* per-invocation ephemeral identity would. Two CONCURRENT mesh_watch
|
|
43
|
+
* calls would still collide with each other -- not solved here, a
|
|
44
|
+
* known limitation, not a silent one.
|
|
45
|
+
*/
|
|
46
|
+
function watchIdentityPath() {
|
|
47
|
+
return process.env.MACULA_MCP_WATCH_IDENTITY ?? join(homedir(), ".macula-mcp", "watch-identity.seed");
|
|
48
|
+
}
|
|
49
|
+
export class MaculaCliUnavailable extends Error {
|
|
50
|
+
}
|
|
51
|
+
export class MaculaCliError extends Error {
|
|
52
|
+
bolt4Code;
|
|
53
|
+
bolt4Name;
|
|
54
|
+
retryable;
|
|
55
|
+
constructor(message, bolt4Code, bolt4Name, retryable) {
|
|
56
|
+
super(message);
|
|
57
|
+
this.bolt4Code = bolt4Code;
|
|
58
|
+
this.bolt4Name = bolt4Name;
|
|
59
|
+
this.retryable = retryable;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Builds a macula-cli argv: subcommand words, then --json and any other
|
|
64
|
+
* flags, then positionals -- in that order, always. Go's `flag` package
|
|
65
|
+
* stops parsing flags at the first non-flag argument, so a flag placed
|
|
66
|
+
* after a positional (a host, a procedure name, ...) is silently treated
|
|
67
|
+
* as an extra positional instead and the command fails its arg-count
|
|
68
|
+
* check. This bit macula-cli's own README/HOWTO guide enough to document
|
|
69
|
+
* as a top-line gotcha -- and bit this file too, appending --json at the
|
|
70
|
+
* very end, until caught running the built MCP server for real against a
|
|
71
|
+
* live macula-cli rather than just typechecking against it. One place to
|
|
72
|
+
* get the ordering right, not one per call site.
|
|
73
|
+
*/
|
|
74
|
+
function argv(subcommand, flags, positionals) {
|
|
75
|
+
return [...subcommand, "--json", ...flags, ...positionals];
|
|
76
|
+
}
|
|
77
|
+
/** Runs a macula-cli argv() and parses its JSON envelope. */
|
|
78
|
+
async function run(args) {
|
|
79
|
+
const { stdout, stderr, code } = await execFile(binPath(), args);
|
|
80
|
+
let parsed;
|
|
81
|
+
try {
|
|
82
|
+
parsed = JSON.parse(stdout);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
throw new MaculaCliUnavailable(`macula-cli produced no parseable JSON (exit ${code}). stderr: ${stderr.trim() || "(empty)"}. ` +
|
|
86
|
+
`Is macula-cli installed and on PATH? See MACULA_CLI_BIN to point at a specific binary.`);
|
|
87
|
+
}
|
|
88
|
+
if (!parsed.ok) {
|
|
89
|
+
const e = parsed.error;
|
|
90
|
+
throw new MaculaCliError(e?.message ?? "macula-cli reported failure with no message", e?.bolt4_code, e?.bolt4_name, e?.retryable);
|
|
91
|
+
}
|
|
92
|
+
return parsed.data;
|
|
93
|
+
}
|
|
94
|
+
function execFile(bin, args) {
|
|
95
|
+
return new Promise((resolve, reject) => {
|
|
96
|
+
const child = spawn(bin, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
97
|
+
let stdout = "";
|
|
98
|
+
let stderr = "";
|
|
99
|
+
child.stdout.on("data", (c) => (stdout += c.toString("utf8")));
|
|
100
|
+
child.stderr.on("data", (c) => (stderr += c.toString("utf8")));
|
|
101
|
+
child.on("error", (e) => reject(new MaculaCliUnavailable(`could not run '${bin}': ${e.message}. Install it (curl -fsSL https://raw.githubusercontent.com/macula-io/macula-cli/master/install.sh | bash) or set MACULA_CLI_BIN.`)));
|
|
102
|
+
child.on("close", (code) => resolve({ stdout, stderr, code }));
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
export const identity = () => run(argv(["identity"], [], []));
|
|
106
|
+
export const call = (args) => {
|
|
107
|
+
const flags = [];
|
|
108
|
+
if (args.timeoutMs)
|
|
109
|
+
flags.push("--timeout", `${Math.max(1, Math.round(args.timeoutMs / 1000))}s`);
|
|
110
|
+
if (args.callArgs !== undefined)
|
|
111
|
+
flags.push("--args", JSON.stringify(args.callArgs));
|
|
112
|
+
return run(argv(["call"], flags, [args.host ?? defaultStation(), args.procedure]));
|
|
113
|
+
};
|
|
114
|
+
export const publish = (args) => run(argv(["pubsub", "publish"], ["--payload", JSON.stringify(args.fact)], [args.host ?? defaultStation(), args.topic]));
|
|
115
|
+
/**
|
|
116
|
+
* Parses `macula-cli pubsub watch --json`'s stdout: one WatchEvent per
|
|
117
|
+
* line (NDJSON, not a single envelope -- run() assumes exactly one
|
|
118
|
+
* envelope and doesn't fit this shape). A real failure mid-watch (e.g.
|
|
119
|
+
* the connection drops after some events already arrived) prints as a
|
|
120
|
+
* trailing `{"ok":false,...}` envelope line -- checked by the presence
|
|
121
|
+
* of an "ok" key, not by JSON.parse throwing, since a wrong-shape
|
|
122
|
+
* object is still perfectly valid JSON and would otherwise silently
|
|
123
|
+
* end up in the events array instead of being surfaced as a failure.
|
|
124
|
+
* Exported standalone so this parsing can be unit-tested without
|
|
125
|
+
* spawning a real subprocess.
|
|
126
|
+
*/
|
|
127
|
+
export function parseWatchOutput(stdout) {
|
|
128
|
+
const events = [];
|
|
129
|
+
for (const line of stdout.split("\n")) {
|
|
130
|
+
const trimmed = line.trim();
|
|
131
|
+
if (!trimmed)
|
|
132
|
+
continue;
|
|
133
|
+
let parsed;
|
|
134
|
+
try {
|
|
135
|
+
parsed = JSON.parse(trimmed);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
continue; // not JSON at all; ignore this line
|
|
139
|
+
}
|
|
140
|
+
if (parsed !== null && typeof parsed === "object" && "ok" in parsed) {
|
|
141
|
+
const envelope = parsed;
|
|
142
|
+
if (envelope.ok === false) {
|
|
143
|
+
throw new MaculaCliError(envelope.error?.message ?? "pubsub watch failed");
|
|
144
|
+
}
|
|
145
|
+
continue; // an {"ok":true,...} envelope line isn't expected here, but skip rather than misparse it as an event
|
|
146
|
+
}
|
|
147
|
+
events.push(parsed);
|
|
148
|
+
}
|
|
149
|
+
return events;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Watches a topic for up to durationSeconds and returns whatever
|
|
153
|
+
* arrived. Bounded and synchronous -- the MCP tool call itself blocks
|
|
154
|
+
* for the duration, which is the honest shape of a one-shot CLI with no
|
|
155
|
+
* background process to keep a standing subscription alive between
|
|
156
|
+
* calls.
|
|
157
|
+
*/
|
|
158
|
+
export const watch = async (args) => {
|
|
159
|
+
const flags = ["--identity", watchIdentityPath(), "--duration", `${Math.max(1, Math.round(args.durationSeconds))}s`];
|
|
160
|
+
if (args.count)
|
|
161
|
+
flags.push("--count", String(args.count));
|
|
162
|
+
const full = argv(["pubsub", "watch"], flags, [args.host ?? defaultStation(), args.topic]);
|
|
163
|
+
const { stdout, stderr, code } = await execFile(binPath(), full);
|
|
164
|
+
const events = parseWatchOutput(stdout);
|
|
165
|
+
if (events.length === 0 && code !== 0 && stderr.trim()) {
|
|
166
|
+
throw new MaculaCliUnavailable(`macula-cli pubsub watch failed: ${stderr.trim()}`);
|
|
167
|
+
}
|
|
168
|
+
return events;
|
|
169
|
+
};
|
|
170
|
+
export const artifactPut = async (args) => {
|
|
171
|
+
const dir = await mkdtemp(join(tmpdir(), "macula-mcp-put-"));
|
|
172
|
+
const filePath = join(dir, "artifact");
|
|
173
|
+
try {
|
|
174
|
+
await writeFile(filePath, Buffer.from(args.contentBase64, "base64"));
|
|
175
|
+
const result = await run(argv(["content", "put"], [], [args.host ?? defaultStation(), filePath]));
|
|
176
|
+
return { mcid_hex: result.mcid, size_bytes: result.size_bytes };
|
|
177
|
+
}
|
|
178
|
+
finally {
|
|
179
|
+
await rm(dir, { recursive: true, force: true });
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
export const artifactGet = async (args) => {
|
|
183
|
+
const result = await run(argv(["content", "get"], [], [args.host ?? defaultStation(), args.mcidHex]));
|
|
184
|
+
if (!result.content_base64) {
|
|
185
|
+
throw new MaculaCliUnavailable("macula-cli content get returned no content_base64 (unexpected)");
|
|
186
|
+
}
|
|
187
|
+
return { content: result.content_base64, size_bytes: result.size_bytes };
|
|
188
|
+
};
|
|
189
|
+
//# sourceMappingURL=macula_cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"macula_cli.js","sourceRoot":"","sources":["../src/macula_cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Tools: mesh_put / mesh_get — content-addressed artifact exchange.
|
|
2
|
+
//
|
|
3
|
+
// The Content Sharing primitive. An agent produces something (a build
|
|
4
|
+
// output, a generated module, a dataset slice), puts it on the mesh, gets
|
|
5
|
+
// back an MCID (Macula Content ID, 34-byte content hash, surfaced as
|
|
6
|
+
// 68 hex chars). Another node's agent fetches it by that hex MCID.
|
|
7
|
+
//
|
|
8
|
+
// mesh_put writes the base64 content to a temp file and runs
|
|
9
|
+
// `macula-cli content put`, deleting the temp file after -- macula-cli's
|
|
10
|
+
// own put command is file-based (composable, scriptable, testable from a
|
|
11
|
+
// real terminal too), while MCP's put tool hands over in-memory base64
|
|
12
|
+
// bytes; the temp file is the bridge between those two shapes. mesh_get
|
|
13
|
+
// needs no such bridge: `macula-cli content get --json` already returns
|
|
14
|
+
// content_base64 directly in its envelope.
|
|
15
|
+
//
|
|
16
|
+
// No accountable fact_id anymore (that was hecate-daemon's ReckonDB audit
|
|
17
|
+
// trail, dropped with the daemon).
|
|
18
|
+
//
|
|
19
|
+
// Caveat (memory: project_inter_station_routing_unshipped): DHT
|
|
20
|
+
// replication is not fully shipped cross-station -- same-station
|
|
21
|
+
// put/get is reliable, cross-station is best-effort.
|
|
22
|
+
import { z } from "zod";
|
|
23
|
+
import { artifactGet, artifactPut, defaultStation } from "./macula_cli.js";
|
|
24
|
+
import { describeCliError, errorContent, jsonContent } from "./reply.js";
|
|
25
|
+
export function registerMeshArtifact(server) {
|
|
26
|
+
server.tool("mesh_put", "Publish a content-addressed artifact to the mesh. Returns its 68-hex-char MCID. " +
|
|
27
|
+
`Fetch it elsewhere with mesh_get. Defaults to ${defaultStation()} if host isn't given.`, {
|
|
28
|
+
content: z.string().describe("Artifact bytes, base64-encoded."),
|
|
29
|
+
host: z
|
|
30
|
+
.string()
|
|
31
|
+
.optional()
|
|
32
|
+
.describe(`Station to connect through, "host[:port]". Defaults to ${defaultStation()}.`),
|
|
33
|
+
}, async ({ content, host }) => {
|
|
34
|
+
try {
|
|
35
|
+
const res = await artifactPut({ host, contentBase64: content });
|
|
36
|
+
return jsonContent({ mcid_hex: res.mcid_hex, size_bytes: res.size_bytes });
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
return errorContent(describeCliError("mesh_put failed", e));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
server.tool("mesh_get", "Fetch a content-addressed artifact from the mesh by its hex MCID (68 chars, " +
|
|
43
|
+
`as returned by mesh_put). Returns base64 content. Defaults to ${defaultStation()} if host isn't given.`, {
|
|
44
|
+
mcid_hex: z
|
|
45
|
+
.string()
|
|
46
|
+
.length(68)
|
|
47
|
+
.regex(/^[0-9a-fA-F]+$/, "must be hex")
|
|
48
|
+
.describe("MCID returned by mesh_put."),
|
|
49
|
+
host: z
|
|
50
|
+
.string()
|
|
51
|
+
.optional()
|
|
52
|
+
.describe(`Station to connect through, "host[:port]". Defaults to ${defaultStation()}.`),
|
|
53
|
+
}, async ({ mcid_hex, host }) => {
|
|
54
|
+
try {
|
|
55
|
+
const res = await artifactGet({ host, mcidHex: mcid_hex });
|
|
56
|
+
return jsonContent({ content: res.content, size_bytes: res.size_bytes });
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
return errorContent(describeCliError("mesh_get failed", e));
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=mesh_artifact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh_artifact.js","sourceRoot":"","sources":["../src/mesh_artifact.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,EAAE;AACF,sEAAsE;AACtE,0EAA0E;AAC1E,qEAAqE;AACrE,mEAAmE;AACnE,EAAE;AACF,6DAA6D;AAC7D,yEAAyE;AACzE,yEAAyE;AACzE,uEAAuE;AACvE,wEAAwE;AACxE,wEAAwE;AACxE,2CAA2C;AAC3C,EAAE;AACF,0EAA0E;AAC1E,mCAAmC;AACnC,EAAE;AACF,gEAAgE;AAChE,iEAAiE;AACjE,qDAAqD;AAGrD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,MAAM,CAAC,IAAI,CACT,UAAU,EACV,kFAAkF;QAChF,iDAAiD,cAAc,EAAE,uBAAuB,EAC1F;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC;QAC/D,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,0DAA0D,cAAc,EAAE,GAAG,CAAC;KAC3F,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;QAC1B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC;YAChE,OAAO,WAAW,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;QAC7E,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,YAAY,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,UAAU,EACV,8EAA8E;QAC5E,iEAAiE,cAAc,EAAE,uBAAuB,EAC1G;QACE,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,MAAM,CAAC,EAAE,CAAC;aACV,KAAK,CAAC,gBAAgB,EAAE,aAAa,CAAC;aACtC,QAAQ,CAAC,4BAA4B,CAAC;QACzC,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,0DAA0D,cAAc,EAAE,GAAG,CAAC;KAC3F,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE;QAC3B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC3D,OAAO,WAAW,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;QAC3E,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,YAAY,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Tool: mesh_call — invoke a procedure advertised on the mesh (REQUESTER).
|
|
2
|
+
//
|
|
3
|
+
// The agent's hands. A peer advertises a procedure; the agent calls it
|
|
4
|
+
// over the mesh instead of a local sandbox or a US SaaS runner.
|
|
5
|
+
// macula-cli does the actual macula:call over QUIC as a one-shot
|
|
6
|
+
// subprocess (connect, call, exit) and returns the RESULT payload or a
|
|
7
|
+
// BOLT#4-vocabulary error.
|
|
8
|
+
//
|
|
9
|
+
// Unlike the old daemon-backed version, this needs a target station:
|
|
10
|
+
// macula-cli isn't already connected to one the way a standing daemon
|
|
11
|
+
// was. `host` defaults to MACULA_MESH_STATION (or macula-cli's own
|
|
12
|
+
// well-known demo station) so most callers never need to think about it.
|
|
13
|
+
import { z } from "zod";
|
|
14
|
+
import { call, defaultStation } from "./macula_cli.js";
|
|
15
|
+
import { describeCliError, errorContent, jsonContent } from "./reply.js";
|
|
16
|
+
export function registerMeshCall(server) {
|
|
17
|
+
server.tool("mesh_call", "Invoke a procedure advertised on the mesh (build, test, search, deploy on commons hardware). " +
|
|
18
|
+
"Macula RPC is procedure-addressed: the target station routes to a peer that advertises it. " +
|
|
19
|
+
`Returns the peer's result plus duration_ms. Defaults to ${defaultStation()} if host isn't given.`, {
|
|
20
|
+
procedure: z.string().describe("Procedure URI, e.g. mri:proc:realm:build."),
|
|
21
|
+
args: z
|
|
22
|
+
.record(z.unknown())
|
|
23
|
+
.optional()
|
|
24
|
+
.describe("Structured arguments for the procedure (plain JSON; macula-cli encodes the wire)."),
|
|
25
|
+
timeout_ms: z
|
|
26
|
+
.number()
|
|
27
|
+
.int()
|
|
28
|
+
.positive()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Deadline in milliseconds for the connect + call."),
|
|
31
|
+
host: z
|
|
32
|
+
.string()
|
|
33
|
+
.optional()
|
|
34
|
+
.describe(`Station to connect through, "host[:port]". Defaults to ${defaultStation()}.`),
|
|
35
|
+
}, async ({ procedure, args, timeout_ms, host }) => {
|
|
36
|
+
try {
|
|
37
|
+
const res = await call({ host, procedure, callArgs: args, timeoutMs: timeout_ms });
|
|
38
|
+
return jsonContent({ result: res.payload, responded_by: res.responded_by, duration_ms: res.duration_ms });
|
|
39
|
+
}
|
|
40
|
+
catch (e) {
|
|
41
|
+
return errorContent(describeCliError("mesh_call failed", e));
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=mesh_call.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh_call.js","sourceRoot":"","sources":["../src/mesh_call.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,EAAE;AACF,uEAAuE;AACvE,gEAAgE;AAChE,iEAAiE;AACjE,uEAAuE;AACvE,2BAA2B;AAC3B,EAAE;AACF,qEAAqE;AACrE,sEAAsE;AACtE,mEAAmE;AACnE,yEAAyE;AAGzE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,MAAM,CAAC,IAAI,CACT,WAAW,EACX,+FAA+F;QAC7F,6FAA6F;QAC7F,2DAA2D,cAAc,EAAE,uBAAuB,EACpG;QACE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;QAC3E,IAAI,EAAE,CAAC;aACJ,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;aACnB,QAAQ,EAAE;aACV,QAAQ,CAAC,mFAAmF,CAAC;QAChG,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,GAAG,EAAE;aACL,QAAQ,EAAE;aACV,QAAQ,EAAE;aACV,QAAQ,CAAC,kDAAkD,CAAC;QAC/D,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,0DAA0D,cAAc,EAAE,GAAG,CAAC;KAC3F,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE;QAC9C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;YACnF,OAAO,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;QAC5G,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,YAAY,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Resource: who am I on the mesh.
|
|
2
|
+
//
|
|
3
|
+
// An agent SHOULD read this before it acts. macula-cli's identity is a
|
|
4
|
+
// bare Ed25519 node ID -- no realm, no membership state, since macula-cli
|
|
5
|
+
// is a raw wire-protocol client, not a realm-joined daemon (that concept
|
|
6
|
+
// belonged to hecate-daemon, now dropped). Report what's actually true
|
|
7
|
+
// rather than fake the fields the old daemon-backed shape had.
|
|
8
|
+
//
|
|
9
|
+
// mesh://peers was dropped, not reworked: it was already an admitted
|
|
10
|
+
// stub even under the old daemon-backed design ("v1 surfaces an empty
|
|
11
|
+
// list until hecate_mesh:get_peers/0 returns real data"), and
|
|
12
|
+
// macula-go-sdk has no peer-listing API for macula-cli to wrap either.
|
|
13
|
+
// A real stub in both directions isn't worth keeping around.
|
|
14
|
+
import { identity } from "./macula_cli.js";
|
|
15
|
+
export function registerIdentity(server) {
|
|
16
|
+
server.resource("mesh-identity", "mesh://identity", {
|
|
17
|
+
description: "This node's Ed25519 identity (node ID), minted and persisted locally by macula-cli.",
|
|
18
|
+
mimeType: "application/json",
|
|
19
|
+
}, async (uri) => {
|
|
20
|
+
const id = await identity();
|
|
21
|
+
return {
|
|
22
|
+
contents: [
|
|
23
|
+
{ uri: uri.href, mimeType: "application/json", text: JSON.stringify(id, null, 2) },
|
|
24
|
+
],
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=mesh_identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh_identity.js","sourceRoot":"","sources":["../src/mesh_identity.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,uEAAuE;AACvE,0EAA0E;AAC1E,yEAAyE;AACzE,uEAAuE;AACvE,+DAA+D;AAC/D,EAAE;AACF,qEAAqE;AACrE,sEAAsE;AACtE,8DAA8D;AAC9D,uEAAuE;AACvE,6DAA6D;AAG7D,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,MAAM,CAAC,QAAQ,CACb,eAAe,EACf,iBAAiB,EACjB;QACE,WAAW,EAAE,qFAAqF;QAClG,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,EAAE,GAAG,MAAM,QAAQ,EAAE,CAAC;QAC5B,OAAO;YACL,QAAQ,EAAE;gBACR,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,kBAAkB,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;aACnF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Tool: mesh_publish — emit an integration fact to a mesh topic.
|
|
2
|
+
//
|
|
3
|
+
// One-shot: macula-cli connects, publishes, exits. No delivery
|
|
4
|
+
// confirmation beyond the wire send succeeding -- PUBLISH has no ack on
|
|
5
|
+
// this protocol -- and no accountable event/fact_id anymore, since that
|
|
6
|
+
// was hecate-daemon's own ReckonDB-backed audit trail, dropped along with
|
|
7
|
+
// the daemon itself. `seq` is macula-cli's own current-time-millis
|
|
8
|
+
// (see its README) since nothing here persists a real sequence counter
|
|
9
|
+
// between one-shot invocations.
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { defaultStation, publish } from "./macula_cli.js";
|
|
12
|
+
import { describeCliError, errorContent, jsonContent } from "./reply.js";
|
|
13
|
+
export function registerMeshPublish(server) {
|
|
14
|
+
server.tool("mesh_publish", "Publish an integration fact to a mesh topic so other parties' agents can react. " +
|
|
15
|
+
"Use a business verb for the fact type (e.g. 'module_generated', 'capability_announced'), " +
|
|
16
|
+
`never CRUD. Returns the topic and seq macula-cli reported. Defaults to ${defaultStation()} if host isn't given.`, {
|
|
17
|
+
topic: z.string().describe("Topic name (e.g. 'agents.module_generated')."),
|
|
18
|
+
fact: z.record(z.unknown()).describe("The integration fact payload (plain JSON; macula-cli encodes the wire)."),
|
|
19
|
+
host: z
|
|
20
|
+
.string()
|
|
21
|
+
.optional()
|
|
22
|
+
.describe(`Station to connect through, "host[:port]". Defaults to ${defaultStation()}.`),
|
|
23
|
+
}, async ({ topic, fact, host }) => {
|
|
24
|
+
try {
|
|
25
|
+
const res = await publish({ host, topic, fact });
|
|
26
|
+
return jsonContent({ topic: res.topic, seq: res.seq, duration_ms: res.duration_ms });
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
return errorContent(describeCliError("mesh_publish failed", e));
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=mesh_publish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh_publish.js","sourceRoot":"","sources":["../src/mesh_publish.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,+DAA+D;AAC/D,wEAAwE;AACxE,wEAAwE;AACxE,0EAA0E;AAC1E,mEAAmE;AACnE,uEAAuE;AACvE,gCAAgC;AAGhC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,UAAU,mBAAmB,CAAC,MAAiB;IACnD,MAAM,CAAC,IAAI,CACT,cAAc,EACd,kFAAkF;QAChF,2FAA2F;QAC3F,0EAA0E,cAAc,EAAE,uBAAuB,EACnH;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;QAC1E,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,yEAAyE,CAAC;QAC/G,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,0DAA0D,cAAc,EAAE,GAAG,CAAC;KAC3F,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE;QAC9B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACjD,OAAO,WAAW,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;QACvF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,YAAY,CAAC,gBAAgB,CAAC,qBAAqB,EAAE,CAAC,CAAC,CAAC,CAAC;QAClE,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Tool: mesh_watch — bounded, synchronous replacement for the old
|
|
2
|
+
// mesh_subscribe / mesh_unsubscribe / mesh_subscriptions / mesh_inbox
|
|
3
|
+
// quartet.
|
|
4
|
+
//
|
|
5
|
+
// Those four tools leaned entirely on hecate-daemon's own event-sourced
|
|
6
|
+
// state: a standing subscription that outlived any one HTTP call, and a
|
|
7
|
+
// ReckonDB-backed inbox an agent could poll later. macula-cli has no
|
|
8
|
+
// daemon and no storage -- nothing persists between invocations -- so
|
|
9
|
+
// there is no honest way to preserve "register once, poll the inbox
|
|
10
|
+
// later" without macula-mcp itself becoming a stateful daemon (a real
|
|
11
|
+
// design fork, deliberately not taken here; see macula-io/macula-cli's
|
|
12
|
+
// own project memory for the tradeoff that was weighed).
|
|
13
|
+
//
|
|
14
|
+
// mesh_watch is the shape that IS honest for a one-shot subprocess: the
|
|
15
|
+
// tool call blocks for up to duration_seconds and returns whatever
|
|
16
|
+
// arrived. An agent that wants "keep listening" calls it again.
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
import { defaultStation, watch } from "./macula_cli.js";
|
|
19
|
+
import { describeCliError, errorContent, jsonContent } from "./reply.js";
|
|
20
|
+
const MAX_DURATION_SECONDS = 120;
|
|
21
|
+
export function registerMeshWatch(server) {
|
|
22
|
+
server.tool("mesh_watch", "Watch a mesh topic for inbound facts for up to duration_seconds, then return whatever " +
|
|
23
|
+
"arrived. This call BLOCKS for the full duration (or until count events arrive, " +
|
|
24
|
+
"whichever is first) -- there is no standing/background subscription to poll later; " +
|
|
25
|
+
`call this again to keep watching. Defaults to ${defaultStation()} if host isn't given.`, {
|
|
26
|
+
topic: z.string().describe("Topic name (e.g. 'chat.demo')."),
|
|
27
|
+
duration_seconds: z
|
|
28
|
+
.number()
|
|
29
|
+
.positive()
|
|
30
|
+
.max(MAX_DURATION_SECONDS)
|
|
31
|
+
.default(10)
|
|
32
|
+
.describe(`How long to watch, in seconds (max ${MAX_DURATION_SECONDS}).`),
|
|
33
|
+
count: z
|
|
34
|
+
.number()
|
|
35
|
+
.int()
|
|
36
|
+
.positive()
|
|
37
|
+
.optional()
|
|
38
|
+
.describe("Stop early once this many events have arrived."),
|
|
39
|
+
host: z
|
|
40
|
+
.string()
|
|
41
|
+
.optional()
|
|
42
|
+
.describe(`Station to connect through, "host[:port]". Defaults to ${defaultStation()}.`),
|
|
43
|
+
}, async ({ topic, duration_seconds, count, host }) => {
|
|
44
|
+
try {
|
|
45
|
+
const events = await watch({ host, topic, durationSeconds: duration_seconds, count });
|
|
46
|
+
return jsonContent({ topic, event_count: events.length, events });
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
return errorContent(describeCliError("mesh_watch failed", e));
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=mesh_watch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh_watch.js","sourceRoot":"","sources":["../src/mesh_watch.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,sEAAsE;AACtE,WAAW;AACX,EAAE;AACF,wEAAwE;AACxE,wEAAwE;AACxE,qEAAqE;AACrE,sEAAsE;AACtE,oEAAoE;AACpE,sEAAsE;AACtE,uEAAuE;AACvE,yDAAyD;AACzD,EAAE;AACF,wEAAwE;AACxE,mEAAmE;AACnE,gEAAgE;AAGhE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAEjC,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,MAAM,CAAC,IAAI,CACT,YAAY,EACZ,wFAAwF;QACtF,iFAAiF;QACjF,qFAAqF;QACrF,iDAAiD,cAAc,EAAE,uBAAuB,EAC1F;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC;QAC5D,gBAAgB,EAAE,CAAC;aAChB,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,GAAG,CAAC,oBAAoB,CAAC;aACzB,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CAAC,sCAAsC,oBAAoB,IAAI,CAAC;QAC3E,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,EAAE;aACL,QAAQ,EAAE;aACV,QAAQ,EAAE;aACV,QAAQ,CAAC,gDAAgD,CAAC;QAC7D,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,0DAA0D,cAAc,EAAE,GAAG,CAAC;KAC3F,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE;QACjD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,KAAK,EAAE,CAAC,CAAC;YACtF,OAAO,WAAW,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QACpE,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,YAAY,CAAC,gBAAgB,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAAC,CAAC;QAChE,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/dist/reply.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type ToolReply = {
|
|
2
|
+
content: {
|
|
3
|
+
type: "text";
|
|
4
|
+
text: string;
|
|
5
|
+
}[];
|
|
6
|
+
isError?: boolean;
|
|
7
|
+
};
|
|
8
|
+
export declare function jsonContent(value: unknown): ToolReply;
|
|
9
|
+
export declare function errorContent(message: string): ToolReply;
|
|
10
|
+
/**
|
|
11
|
+
* Formats an error caught from a macula_cli.ts call, surfacing the
|
|
12
|
+
* BOLT#4 code/name/retryable when present rather than a bare message —
|
|
13
|
+
* every tool that shells out to macula-cli wants this same shape.
|
|
14
|
+
*/
|
|
15
|
+
export declare function describeCliError(prefix: string, e: unknown): string;
|
|
16
|
+
export {};
|
package/dist/reply.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Small helpers for shaping MCP tool replies. Not a "utils" junk drawer —
|
|
2
|
+
// just the reply shapes every tool returns.
|
|
3
|
+
import { MaculaCliError } from "./macula_cli.js";
|
|
4
|
+
export function jsonContent(value) {
|
|
5
|
+
return { content: [{ type: "text", text: JSON.stringify(value, null, 2) }] };
|
|
6
|
+
}
|
|
7
|
+
export function errorContent(message) {
|
|
8
|
+
return { content: [{ type: "text", text: message }], isError: true };
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Formats an error caught from a macula_cli.ts call, surfacing the
|
|
12
|
+
* BOLT#4 code/name/retryable when present rather than a bare message —
|
|
13
|
+
* every tool that shells out to macula-cli wants this same shape.
|
|
14
|
+
*/
|
|
15
|
+
export function describeCliError(prefix, e) {
|
|
16
|
+
if (e instanceof MaculaCliError) {
|
|
17
|
+
const bolt4 = e.bolt4Name
|
|
18
|
+
? ` (bolt4=${e.bolt4Name}${e.retryable !== undefined ? `, retryable=${e.retryable}` : ""})`
|
|
19
|
+
: "";
|
|
20
|
+
return `${prefix}: ${e.message}${bolt4}`;
|
|
21
|
+
}
|
|
22
|
+
return `${prefix}: ${e instanceof Error ? e.message : String(e)}`;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=reply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reply.js","sourceRoot":"","sources":["../src/reply.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,4CAA4C;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACvE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,CAAU;IACzD,IAAI,CAAC,YAAY,cAAc,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,CAAC,CAAC,SAAS;YACvB,CAAC,CAAC,WAAW,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG;YAC3F,CAAC,CAAC,EAAE,CAAC;QACP,OAAO,GAAG,MAAM,KAAK,CAAC,CAAC,OAAO,GAAG,KAAK,EAAE,CAAC;IAC3C,CAAC;IACD,OAAO,GAAG,MAAM,KAAK,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;AACpE,CAAC"}
|