@macula-io/mcp 0.4.0 → 0.5.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/README.md +94 -35
- package/dist/bin/doctor.js +30 -2
- package/dist/bin/doctor.js.map +1 -1
- package/dist/bin/install.js +2 -2
- package/dist/bin/install.js.map +1 -1
- package/dist/bin/status.js +2 -2
- package/dist/bin/status.js.map +1 -1
- package/dist/bin/uninstall.js +1 -1
- package/dist/index.js +31 -14
- package/dist/index.js.map +1 -1
- package/dist/macula_cli.d.ts +71 -0
- package/dist/macula_cli.js +153 -20
- package/dist/macula_cli.js.map +1 -1
- package/dist/mesh_agents.d.ts +2 -0
- package/dist/mesh_agents.js +47 -0
- package/dist/mesh_agents.js.map +1 -0
- package/dist/mesh_etiquette.js +36 -7
- package/dist/mesh_etiquette.js.map +1 -1
- package/dist/mesh_goodbye.d.ts +2 -0
- package/dist/mesh_goodbye.js +24 -0
- package/dist/mesh_goodbye.js.map +1 -0
- package/dist/mesh_hello.d.ts +2 -0
- package/dist/mesh_hello.js +73 -0
- package/dist/mesh_hello.js.map +1 -0
- package/dist/mesh_help.js +22 -7
- package/dist/mesh_help.js.map +1 -1
- package/dist/presence.d.ts +22 -0
- package/dist/presence.js +217 -0
- package/dist/presence.js.map +1 -0
- package/dist/roster.d.ts +26 -0
- package/dist/roster.js +93 -0
- package/dist/roster.js.map +1 -0
- package/package.json +3 -1
package/dist/macula_cli.js
CHANGED
|
@@ -24,9 +24,25 @@ export function defaultStation() {
|
|
|
24
24
|
return process.env.MACULA_MESH_STATION ?? "station-de-frankfurt.macula.io:4433";
|
|
25
25
|
}
|
|
26
26
|
/** Name/path of the macula-cli binary; override for testing or a non-PATH install. */
|
|
27
|
-
function binPath() {
|
|
27
|
+
export function binPath() {
|
|
28
28
|
return process.env.MACULA_CLI_BIN ?? "macula-cli";
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Cleanup hooks run once, synchronously, before this process actually
|
|
32
|
+
* exits -- registered here rather than each module adding its own
|
|
33
|
+
* process.on(SIGINT/SIGTERM) listener, since Node calls every listener
|
|
34
|
+
* for the same signal in registration order and the FIRST one
|
|
35
|
+
* registered below already calls process.exit() itself. A second,
|
|
36
|
+
* independently-registered listener (e.g. presence.ts's own child
|
|
37
|
+
* process cleanup) racing to run before that exit actually happens is
|
|
38
|
+
* not something to depend on -- this registry makes the ordering
|
|
39
|
+
* deterministic instead: everything registered here is guaranteed to
|
|
40
|
+
* run first, regardless of which module imported this one when.
|
|
41
|
+
*/
|
|
42
|
+
const shutdownHooks = [];
|
|
43
|
+
export function onShutdown(fn) {
|
|
44
|
+
shutdownHooks.push(fn);
|
|
45
|
+
}
|
|
30
46
|
/**
|
|
31
47
|
* Per-server-process identities, freshly minted (temp dir, deleted on
|
|
32
48
|
* exit) rather than macula-cli's own shared machine-wide default.
|
|
@@ -89,8 +105,19 @@ process.on("exit", () => {
|
|
|
89
105
|
// Node doesn't fire "exit" on a bare SIGINT/SIGTERM unless the process
|
|
90
106
|
// actually exits; without this, Ctrl-C or a client-initiated shutdown
|
|
91
107
|
// would skip the cleanup above and leak a temp identity file per run.
|
|
108
|
+
// shutdownHooks run first and synchronously -- see onShutdown's own doc.
|
|
92
109
|
for (const sig of ["SIGINT", "SIGTERM"]) {
|
|
93
|
-
process.on(sig, () =>
|
|
110
|
+
process.on(sig, () => {
|
|
111
|
+
for (const fn of shutdownHooks) {
|
|
112
|
+
try {
|
|
113
|
+
fn();
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// best effort -- a hook failing shouldn't block the others or the exit
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
process.exit(0);
|
|
120
|
+
});
|
|
94
121
|
}
|
|
95
122
|
let cachedDefaultIdentityPath;
|
|
96
123
|
/** Exported for mesh_identity.ts (the mesh://identity resource) and for tests. */
|
|
@@ -99,6 +126,21 @@ export function defaultIdentityPath() {
|
|
|
99
126
|
return process.env.MACULA_MCP_IDENTITY;
|
|
100
127
|
return (cachedDefaultIdentityPath ??= mintIdentityPath("default"));
|
|
101
128
|
}
|
|
129
|
+
let cachedPresenceIdentityPath;
|
|
130
|
+
/**
|
|
131
|
+
* A THIRD identity, dedicated to presence.ts's own daemon (agent.hello/
|
|
132
|
+
* agent.goodbye subscriptions) -- separate from "default" and "watch"
|
|
133
|
+
* for the same reason those two are already separate from each other:
|
|
134
|
+
* two connections sharing one node ID get the second one kicked by the
|
|
135
|
+
* station (see watchIdentityPath's own doc). The presence daemon holds
|
|
136
|
+
* a connection open for as long as this process runs, so it must never
|
|
137
|
+
* share an identity with anything else that might connect concurrently.
|
|
138
|
+
*/
|
|
139
|
+
export function presenceIdentityPath() {
|
|
140
|
+
if (process.env.MACULA_MCP_PRESENCE_IDENTITY)
|
|
141
|
+
return process.env.MACULA_MCP_PRESENCE_IDENTITY;
|
|
142
|
+
return (cachedPresenceIdentityPath ??= mintIdentityPath("presence"));
|
|
143
|
+
}
|
|
102
144
|
let cachedWatchIdentityPath;
|
|
103
145
|
/** Exported for tests only -- no other module needs it, mesh_watch calls watch() directly. */
|
|
104
146
|
export function watchIdentityPath() {
|
|
@@ -162,6 +204,81 @@ function execFile(bin, args) {
|
|
|
162
204
|
child.on("close", (code) => resolve({ stdout, stderr, code }));
|
|
163
205
|
});
|
|
164
206
|
}
|
|
207
|
+
/**
|
|
208
|
+
* The oldest macula-cli release this macula-mcp version is known to work
|
|
209
|
+
* correctly against. macula-mcp shells out to a SEPARATELY installed
|
|
210
|
+
* macula-cli binary (see this file's own top-of-file comment) rather
|
|
211
|
+
* than vendoring one of the Go/Rust/.NET SDKs directly -- a deliberate
|
|
212
|
+
* choice (avoids native-binding packaging complexity for a Node.js
|
|
213
|
+
* package), but it means a real macula-cli bug fix landing upstream does
|
|
214
|
+
* NOT reach an macula-mcp user until they separately update their
|
|
215
|
+
* installed macula-cli binary. That gap was real, not hypothetical: on
|
|
216
|
+
* 2026-08-29, macula-cli v0.1.2 (and everything before v0.1.3) shipped a
|
|
217
|
+
* PUBLISH-then-Close race that could silently drop a `pubsub publish`
|
|
218
|
+
* call -- exactly the shape `mesh_publish` uses -- with zero error
|
|
219
|
+
* surfaced anywhere. Bump this constant whenever a macula-cli fix this
|
|
220
|
+
* server's own tools depend on ships in a new release.
|
|
221
|
+
*
|
|
222
|
+
* Bumped to 0.2.0 for presence.ts: mesh_hello/mesh_goodbye/mesh_agents
|
|
223
|
+
* depend on `macula-cli daemon` and `pubsub watch -daemon`/-subscribe,
|
|
224
|
+
* both new in that release -- v0.1.x has no daemon subcommand at all.
|
|
225
|
+
*/
|
|
226
|
+
export const MIN_MACULA_CLI_VERSION = "0.2.0";
|
|
227
|
+
/**
|
|
228
|
+
* Parses "X.Y.Z" (optionally "vX.Y.Z") out of an arbitrary string;
|
|
229
|
+
* undefined if none found. Exported standalone so this parsing can be
|
|
230
|
+
* unit-tested without spawning a real subprocess -- same rationale as
|
|
231
|
+
* parseWatchOutput above.
|
|
232
|
+
*/
|
|
233
|
+
export function extractSemver(s) {
|
|
234
|
+
const m = /v?(\d+)\.(\d+)\.(\d+)/.exec(s);
|
|
235
|
+
return m ? `${m[1]}.${m[2]}.${m[3]}` : undefined;
|
|
236
|
+
}
|
|
237
|
+
/** True if `a` is older than `b`, comparing "X.Y.Z" strings numerically per segment. */
|
|
238
|
+
export function isOlder(a, b) {
|
|
239
|
+
const pa = a.split(".").map(Number);
|
|
240
|
+
const pb = b.split(".").map(Number);
|
|
241
|
+
for (let i = 0; i < 3; i++) {
|
|
242
|
+
if (pa[i] !== pb[i])
|
|
243
|
+
return pa[i] < pb[i];
|
|
244
|
+
}
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Checks the installed macula-cli binary's version against
|
|
249
|
+
* MIN_MACULA_CLI_VERSION. Does not throw -- a version problem is
|
|
250
|
+
* something a caller reports, not a hard failure of whatever operation
|
|
251
|
+
* triggered the check, since an old-but-still-functional binary should
|
|
252
|
+
* degrade to a warning, not block every tool call.
|
|
253
|
+
*/
|
|
254
|
+
export async function checkCliVersion() {
|
|
255
|
+
const bin = binPath();
|
|
256
|
+
let stdout;
|
|
257
|
+
try {
|
|
258
|
+
({ stdout } = await execFile(bin, ["--version"]));
|
|
259
|
+
}
|
|
260
|
+
catch (e) {
|
|
261
|
+
return {
|
|
262
|
+
ok: false,
|
|
263
|
+
required: MIN_MACULA_CLI_VERSION,
|
|
264
|
+
error: e instanceof Error ? e.message : String(e),
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
const raw = stdout.trim();
|
|
268
|
+
const installed = extractSemver(raw);
|
|
269
|
+
if (!installed) {
|
|
270
|
+
// A "dev" build (no -ldflags version injection, e.g. `go build`
|
|
271
|
+
// straight from source) is a legitimate thing to develop against --
|
|
272
|
+
// warn, don't fail, since there's no version to actually compare.
|
|
273
|
+
return { ok: true, raw, required: MIN_MACULA_CLI_VERSION };
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
ok: !isOlder(installed, MIN_MACULA_CLI_VERSION),
|
|
277
|
+
raw,
|
|
278
|
+
installed,
|
|
279
|
+
required: MIN_MACULA_CLI_VERSION,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
165
282
|
/** The identity every mesh_call/mesh_put/mesh_get/mesh_publish call uses -- see the comment above defaultIdentityPath(). */
|
|
166
283
|
export const identity = () => run(argv(["identity"], ["--identity", defaultIdentityPath()], []));
|
|
167
284
|
export const call = (args) => {
|
|
@@ -185,27 +302,43 @@ export const publish = (args) => run(argv(["pubsub", "publish"], ["--identity",
|
|
|
185
302
|
* Exported standalone so this parsing can be unit-tested without
|
|
186
303
|
* spawning a real subprocess.
|
|
187
304
|
*/
|
|
305
|
+
/**
|
|
306
|
+
* Parses ONE line of `pubsub watch --json` output -- the same per-line
|
|
307
|
+
* shape parseWatchOutput batch-parses after a bounded watch's process
|
|
308
|
+
* exits, factored out so presence.ts's long-lived subscription (which
|
|
309
|
+
* never exits under normal operation, so there's no final stdout
|
|
310
|
+
* string to batch-parse) can apply it incrementally as lines stream
|
|
311
|
+
* in. Returns null for a blank line or a trailing {"ok":true,...}
|
|
312
|
+
* envelope (not expected in this format, but skipped rather than
|
|
313
|
+
* misparsed as an event); throws MaculaCliError on a trailing
|
|
314
|
+
* {"ok":false,...} failure envelope.
|
|
315
|
+
*/
|
|
316
|
+
export function parseWatchLine(line) {
|
|
317
|
+
const trimmed = line.trim();
|
|
318
|
+
if (!trimmed)
|
|
319
|
+
return null;
|
|
320
|
+
let parsed;
|
|
321
|
+
try {
|
|
322
|
+
parsed = JSON.parse(trimmed);
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
return null; // not JSON at all; ignore this line
|
|
326
|
+
}
|
|
327
|
+
if (parsed !== null && typeof parsed === "object" && "ok" in parsed) {
|
|
328
|
+
const envelope = parsed;
|
|
329
|
+
if (envelope.ok === false) {
|
|
330
|
+
throw new MaculaCliError(envelope.error?.message ?? "pubsub watch failed");
|
|
331
|
+
}
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
return parsed;
|
|
335
|
+
}
|
|
188
336
|
export function parseWatchOutput(stdout) {
|
|
189
337
|
const events = [];
|
|
190
338
|
for (const line of stdout.split("\n")) {
|
|
191
|
-
const
|
|
192
|
-
if (
|
|
193
|
-
|
|
194
|
-
let parsed;
|
|
195
|
-
try {
|
|
196
|
-
parsed = JSON.parse(trimmed);
|
|
197
|
-
}
|
|
198
|
-
catch {
|
|
199
|
-
continue; // not JSON at all; ignore this line
|
|
200
|
-
}
|
|
201
|
-
if (parsed !== null && typeof parsed === "object" && "ok" in parsed) {
|
|
202
|
-
const envelope = parsed;
|
|
203
|
-
if (envelope.ok === false) {
|
|
204
|
-
throw new MaculaCliError(envelope.error?.message ?? "pubsub watch failed");
|
|
205
|
-
}
|
|
206
|
-
continue; // an {"ok":true,...} envelope line isn't expected here, but skip rather than misparse it as an event
|
|
207
|
-
}
|
|
208
|
-
events.push(parsed);
|
|
339
|
+
const evt = parseWatchLine(line);
|
|
340
|
+
if (evt)
|
|
341
|
+
events.push(evt);
|
|
209
342
|
}
|
|
210
343
|
return events;
|
|
211
344
|
}
|
package/dist/macula_cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"macula_cli.js","sourceRoot":"","sources":["../src/macula_cli.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,EAAE;AACF,sEAAsE;AACtE,yEAAyE;AACzE,sEAAsE;AACtE,sEAAsE;AACtE,oEAAoE;AACpE,EAAE;AACF,uGAAuG;AACvG,EAAE;AACF,wEAAwE;AACxE,sEAAsE;AACtE,uEAAuE;AACvE,kEAAkE;AAClE,8CAA8C;AAE9C,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,4EAA4E;AAC5E,MAAM,UAAU,cAAc;IAC5B,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,qCAAqC,CAAC;AAClF,CAAC;AAED,sFAAsF;AACtF,
|
|
1
|
+
{"version":3,"file":"macula_cli.js","sourceRoot":"","sources":["../src/macula_cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// Tool: mesh_agents — a paged list of agents seen via agent.hello.
|
|
2
|
+
//
|
|
3
|
+
// Reads purely from the local roster (roster.ts) built by presence.ts's
|
|
4
|
+
// subscription -- no mesh round-trip, so this only ever reflects
|
|
5
|
+
// whoever has said hello (and this process has been running long
|
|
6
|
+
// enough to hear it) via mesh_hello, not "every agent on the mesh"
|
|
7
|
+
// universally.
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { identity } from "./macula_cli.js";
|
|
10
|
+
import { errorContent, jsonContent } from "./reply.js";
|
|
11
|
+
import { listAgents, pruneStale } from "./roster.js";
|
|
12
|
+
const DEFAULT_PAGE_SIZE = 20;
|
|
13
|
+
const MAX_PAGE_SIZE = 100;
|
|
14
|
+
/** Drop agents not heard from in this long -- generous relative to the default 60s heartbeat. */
|
|
15
|
+
const STALE_AFTER_SECONDS = 15 * 60;
|
|
16
|
+
export function registerMeshAgents(server) {
|
|
17
|
+
server.tool("mesh_agents", "List agents seen on the mesh via their agent.hello heartbeats (started with mesh_hello). " +
|
|
18
|
+
"Reads a local cache, not a live mesh query -- only reflects agents heard from while this " +
|
|
19
|
+
"process has been running. Sorted most-recently-seen first.", {
|
|
20
|
+
page: z.number().int().positive().default(1).describe("1-based page number."),
|
|
21
|
+
page_size: z.number().int().positive().max(MAX_PAGE_SIZE).default(DEFAULT_PAGE_SIZE),
|
|
22
|
+
}, async ({ page, page_size }) => {
|
|
23
|
+
try {
|
|
24
|
+
pruneStale(STALE_AFTER_SECONDS);
|
|
25
|
+
const { node_id: selfNodeId } = await identity();
|
|
26
|
+
const { total, agents } = listAgents(page, page_size);
|
|
27
|
+
return jsonContent({
|
|
28
|
+
total,
|
|
29
|
+
page,
|
|
30
|
+
page_size,
|
|
31
|
+
agents: agents.map((a) => ({
|
|
32
|
+
node_id: a.node_id,
|
|
33
|
+
operator_name: a.operator_name ?? undefined,
|
|
34
|
+
message: a.message ?? undefined,
|
|
35
|
+
first_seen: a.first_seen_at,
|
|
36
|
+
last_seen: a.last_seen_at,
|
|
37
|
+
seconds_since_seen: Math.round((Date.now() - Date.parse(a.last_seen_at)) / 1000),
|
|
38
|
+
is_self: a.node_id === selfNodeId,
|
|
39
|
+
})),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
return errorContent(e instanceof Error ? e.message : String(e));
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=mesh_agents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh_agents.js","sourceRoot":"","sources":["../src/mesh_agents.ts"],"names":[],"mappings":"AAAA,mEAAmE;AACnE,EAAE;AACF,wEAAwE;AACxE,iEAAiE;AACjE,iEAAiE;AACjE,mEAAmE;AACnE,eAAe;AAGf,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAErD,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAC7B,MAAM,aAAa,GAAG,GAAG,CAAC;AAC1B,iGAAiG;AACjG,MAAM,mBAAmB,GAAG,EAAE,GAAG,EAAE,CAAC;AAEpC,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,aAAa,EACb,2FAA2F;QACzF,2FAA2F;QAC3F,4DAA4D,EAC9D;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QAC7E,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC;KACrF,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE;QAC5B,IAAI,CAAC;YACH,UAAU,CAAC,mBAAmB,CAAC,CAAC;YAChC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,QAAQ,EAAE,CAAC;YACjD,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YACtD,OAAO,WAAW,CAAC;gBACjB,KAAK;gBACL,IAAI;gBACJ,SAAS;gBACT,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBACzB,OAAO,EAAE,CAAC,CAAC,OAAO;oBAClB,aAAa,EAAE,CAAC,CAAC,aAAa,IAAI,SAAS;oBAC3C,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,SAAS;oBAC/B,UAAU,EAAE,CAAC,CAAC,aAAa;oBAC3B,SAAS,EAAE,CAAC,CAAC,YAAY;oBACzB,kBAAkB,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC;oBAChF,OAAO,EAAE,CAAC,CAAC,OAAO,KAAK,UAAU;iBAClC,CAAC,CAAC;aACJ,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,YAAY,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAClE,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
package/dist/mesh_etiquette.js
CHANGED
|
@@ -59,17 +59,46 @@ commons infrastructure, not a platform you're renting.
|
|
|
59
59
|
- Read \`mesh://identity\` before you publish or call anything, so you know
|
|
60
60
|
which node ID you're acting as -- it's minted fresh per macula-mcp server
|
|
61
61
|
process (not the same as running \`macula-cli\` by hand on the same
|
|
62
|
-
machine, and not the same as mesh_watch's own separate identity
|
|
62
|
+
machine, and not the same as mesh_watch's own separate identity, or
|
|
63
|
+
presence's own third one -- see below).
|
|
63
64
|
- Don't assume continuity: a fresh Claude Code session, or a subagent with
|
|
64
|
-
its own macula-mcp connection, is a different identity from this one
|
|
65
|
+
its own macula-mcp connection, is a different identity from this one --
|
|
66
|
+
and by default so is the SAME session after a restart, unless
|
|
67
|
+
\`MACULA_MCP_IDENTITY\` pins a fixed path. This matters for presence:
|
|
68
|
+
\`mesh_agents\`' roster is keyed by node ID, so an unpinned identity looks
|
|
69
|
+
like a brand-new agent to everyone else on every restart. \`operator_name\`
|
|
70
|
+
is the stable, human-facing label over an identity that's often
|
|
71
|
+
ephemeral by design -- set it if you want to be recognizable across
|
|
72
|
+
restarts, don't rely on node ID for that.
|
|
73
|
+
|
|
74
|
+
## Presence -- mesh_hello / mesh_agents / mesh_goodbye
|
|
75
|
+
|
|
76
|
+
This is the ONE deliberate exception to "one-shot subprocess, no standing
|
|
77
|
+
state" below. Announcing yourself on a shared mesh is a decision, not a
|
|
78
|
+
default:
|
|
79
|
+
|
|
80
|
+
- **Don't call \`mesh_hello\` reflexively on every connection.** It starts a
|
|
81
|
+
recurring heartbeat that keeps running (and keeps a station connection
|
|
82
|
+
open) until \`mesh_goodbye\` is called or this process exits -- call it
|
|
83
|
+
because you actually want to be discoverable, not as a habit.
|
|
84
|
+
- **Say goodbye.** \`mesh_goodbye\` removes you from other agents' rosters
|
|
85
|
+
immediately; without it, you just age out of their view after several
|
|
86
|
+
missed heartbeats. Both work, but an explicit goodbye is the polite one
|
|
87
|
+
when you know you're done.
|
|
88
|
+
- **The heartbeat interval has a floor (10s) enforced in code, not just a
|
|
89
|
+
suggestion** -- a wire-level guard against hammering a shared demo
|
|
90
|
+
station, the same spirit as the no-bool rule above.
|
|
91
|
+
- \`mesh_agents\` reflects who has said hello and how recently, not "every
|
|
92
|
+
agent on the mesh" -- treat an empty or short list as "nobody's
|
|
93
|
+
announced themselves yet," not "the mesh is empty."
|
|
65
94
|
|
|
66
95
|
## What this server deliberately does not do
|
|
67
96
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
97
|
+
Beyond presence's own narrow exception above: no local audit log or inbox,
|
|
98
|
+
no peer listing beyond \`mesh_agents\`' own hello-based roster, and every
|
|
99
|
+
OTHER tool call is exactly one \`macula-cli\` subprocess: connect, do the one
|
|
100
|
+
thing, exit. If something isn't in the tool list, it's not a gap you're
|
|
101
|
+
missing context on -- it genuinely isn't there, on purpose.
|
|
73
102
|
`;
|
|
74
103
|
export function registerEtiquette(server) {
|
|
75
104
|
server.resource("mesh-etiquette", "mesh://etiquette", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mesh_etiquette.js","sourceRoot":"","sources":["../src/mesh_etiquette.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,wCAAwC;AACxC,EAAE;AACF,qEAAqE;AACrE,wEAAwE;AACxE,uEAAuE;AACvE,wEAAwE;AACxE,qEAAqE;AACrE,uEAAuE;AACvE,+CAA+C;AAC/C,EAAE;AACF,uEAAuE;AACvE,wEAAwE;AACxE,wEAAwE;AACxE,oEAAoE;AACpE,kDAAkD;AAIlD,MAAM,SAAS,GAAG
|
|
1
|
+
{"version":3,"file":"mesh_etiquette.js","sourceRoot":"","sources":["../src/mesh_etiquette.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,wCAAwC;AACxC,EAAE;AACF,qEAAqE;AACrE,wEAAwE;AACxE,uEAAuE;AACvE,wEAAwE;AACxE,qEAAqE;AACrE,uEAAuE;AACvE,+CAA+C;AAC/C,EAAE;AACF,uEAAuE;AACvE,wEAAwE;AACxE,wEAAwE;AACxE,oEAAoE;AACpE,kDAAkD;AAIlD,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqFjB,CAAC;AAEF,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,MAAM,CAAC,QAAQ,CACb,gBAAgB,EAChB,kBAAkB,EAClB;QACE,WAAW,EACT,iQAAiQ;QACnQ,QAAQ,EAAE,eAAe;KAC1B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QACd,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;KAC1E,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Tool: mesh_goodbye — the deliberate counterpart to mesh_hello.
|
|
2
|
+
//
|
|
3
|
+
// Publishes one agent.goodbye fact (so anyone else's roster drops this
|
|
4
|
+
// node immediately rather than waiting for its heartbeat to simply go
|
|
5
|
+
// stale), then stops the heartbeat and the durable subscriptions. A
|
|
6
|
+
// no-op if mesh_hello was never called.
|
|
7
|
+
import { describeCliError, errorContent, jsonContent } from "./reply.js";
|
|
8
|
+
import * as presence from "./presence.js";
|
|
9
|
+
export function registerMeshGoodbye(server) {
|
|
10
|
+
server.tool("mesh_goodbye", "Leave the mesh deliberately: publishes one agent.goodbye fact, then stops the agent.hello " +
|
|
11
|
+
"heartbeat and the roster subscription started by mesh_hello. No-op if mesh_hello was never called.", {}, async () => {
|
|
12
|
+
try {
|
|
13
|
+
if (!presence.isActive()) {
|
|
14
|
+
return jsonContent({ was_active: false, said_goodbye: false });
|
|
15
|
+
}
|
|
16
|
+
const result = await presence.stop();
|
|
17
|
+
return jsonContent({ was_active: true, ...result });
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
return errorContent(describeCliError("mesh_goodbye failed", e));
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=mesh_goodbye.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh_goodbye.js","sourceRoot":"","sources":["../src/mesh_goodbye.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,uEAAuE;AACvE,sEAAsE;AACtE,oEAAoE;AACpE,wCAAwC;AAGxC,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C,MAAM,UAAU,mBAAmB,CAAC,MAAiB;IACnD,MAAM,CAAC,IAAI,CACT,cAAc,EACd,4FAA4F;QAC1F,oGAAoG,EACtG,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC;gBACzB,OAAO,WAAW,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;YACjE,CAAC;YACD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACrC,OAAO,WAAW,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;QACtD,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,73 @@
|
|
|
1
|
+
// Tool: mesh_hello — announce this agent's presence on the mesh.
|
|
2
|
+
//
|
|
3
|
+
// Deliberately explicit rather than automatic on every macula-mcp
|
|
4
|
+
// startup: broadcasting onto a real shared mesh (the default station
|
|
5
|
+
// is macula.io's public demo fleet, not a sandbox) should be something
|
|
6
|
+
// an agent decides to do, not a side effect of merely connecting.
|
|
7
|
+
//
|
|
8
|
+
// First call: prints a welcome banner, publishes one agent.hello
|
|
9
|
+
// immediately, and starts a periodic heartbeat (see presence.ts) that
|
|
10
|
+
// keeps republishing it -- plus a durable subscription to everyone
|
|
11
|
+
// else's agent.hello/agent.goodbye, feeding mesh_agents' roster. A
|
|
12
|
+
// later call while already active just updates operator_name/message
|
|
13
|
+
// for future heartbeats, without restarting anything.
|
|
14
|
+
import { readFileSync } from "node:fs";
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
import { defaultStation } from "./macula_cli.js";
|
|
17
|
+
import { describeCliError, errorContent, jsonContent } from "./reply.js";
|
|
18
|
+
import * as presence from "./presence.js";
|
|
19
|
+
const DEFAULT_BANNER = `
|
|
20
|
+
__ __ _____ ___ _ _ _ _
|
|
21
|
+
| \\/ ||_ _| / __|| | | || | /_\\
|
|
22
|
+
| |\\/| | | | | (__ | |_| || |__ / _ \\
|
|
23
|
+
|_| |_| |_| \\___| \\___/ |____/_/ \\_\\
|
|
24
|
+
macula mesh -- an agent just said hello
|
|
25
|
+
`;
|
|
26
|
+
function banner() {
|
|
27
|
+
const path = process.env.MACULA_MCP_BANNER_FILE;
|
|
28
|
+
if (!path)
|
|
29
|
+
return DEFAULT_BANNER;
|
|
30
|
+
try {
|
|
31
|
+
return readFileSync(path, "utf8");
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return DEFAULT_BANNER; // a missing/unreadable custom banner falls back quietly, same spirit as identity's load-or-generate
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export function registerMeshHello(server) {
|
|
38
|
+
server.tool("mesh_hello", "Announce this agent's presence on the mesh: prints a welcome banner and starts a periodic " +
|
|
39
|
+
"agent.hello heartbeat (default every 60s) plus a durable subscription to other agents' " +
|
|
40
|
+
"hellos, feeding mesh_agents' roster. Calling this again while already active just updates " +
|
|
41
|
+
"operator_name/message for future heartbeats. Pair with mesh_goodbye to leave deliberately.", {
|
|
42
|
+
operator_name: z.string().optional().describe("Customizable human-readable name for whoever's behind this agent."),
|
|
43
|
+
message: z.string().optional().describe("A short greeting or status, sent with every heartbeat."),
|
|
44
|
+
interval_seconds: z
|
|
45
|
+
.number()
|
|
46
|
+
.int()
|
|
47
|
+
.positive()
|
|
48
|
+
.optional()
|
|
49
|
+
.describe("Heartbeat interval in seconds (default 60, minimum 10)."),
|
|
50
|
+
host: z
|
|
51
|
+
.string()
|
|
52
|
+
.optional()
|
|
53
|
+
.describe(`Station to connect through, "host[:port]". Defaults to ${defaultStation()}.`),
|
|
54
|
+
}, async ({ operator_name, message, interval_seconds, host }) => {
|
|
55
|
+
try {
|
|
56
|
+
const result = await presence.start({
|
|
57
|
+
host,
|
|
58
|
+
// Explicit args win; MACULA_MCP_OPERATOR_NAME/HELLO_MESSAGE are
|
|
59
|
+
// an operator's standing default so an agent doesn't have to
|
|
60
|
+
// type them on every call, same spirit as MACULA_MCP_IDENTITY
|
|
61
|
+
// pinning a default elsewhere in this server.
|
|
62
|
+
operatorName: operator_name ?? process.env.MACULA_MCP_OPERATOR_NAME,
|
|
63
|
+
message: message ?? process.env.MACULA_MCP_HELLO_MESSAGE,
|
|
64
|
+
intervalSeconds: interval_seconds,
|
|
65
|
+
});
|
|
66
|
+
return jsonContent({ banner: banner(), ...result });
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
return errorContent(describeCliError("mesh_hello failed", e));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=mesh_hello.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mesh_hello.js","sourceRoot":"","sources":["../src/mesh_hello.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,EAAE;AACF,kEAAkE;AAClE,qEAAqE;AACrE,uEAAuE;AACvE,kEAAkE;AAClE,EAAE;AACF,iEAAiE;AACjE,sEAAsE;AACtE,mEAAmE;AACnE,mEAAmE;AACnE,qEAAqE;AACrE,sDAAsD;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzE,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C,MAAM,cAAc,GAAG;;;;;;CAMtB,CAAC;AAEF,SAAS,MAAM;IACb,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC;IAChD,IAAI,CAAC,IAAI;QAAE,OAAO,cAAc,CAAC;IACjC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,cAAc,CAAC,CAAC,oGAAoG;IAC7H,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,MAAM,CAAC,IAAI,CACT,YAAY,EACZ,4FAA4F;QAC1F,yFAAyF;QACzF,4FAA4F;QAC5F,4FAA4F,EAC9F;QACE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mEAAmE,CAAC;QAClH,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;QACjG,gBAAgB,EAAE,CAAC;aAChB,MAAM,EAAE;aACR,GAAG,EAAE;aACL,QAAQ,EAAE;aACV,QAAQ,EAAE;aACV,QAAQ,CAAC,yDAAyD,CAAC;QACtE,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,0DAA0D,cAAc,EAAE,GAAG,CAAC;KAC3F,EACD,KAAK,EAAE,EAAE,aAAa,EAAE,OAAO,EAAE,gBAAgB,EAAE,IAAI,EAAE,EAAE,EAAE;QAC3D,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC;gBAClC,IAAI;gBACJ,gEAAgE;gBAChE,6DAA6D;gBAC7D,8DAA8D;gBAC9D,8CAA8C;gBAC9C,YAAY,EAAE,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB;gBACnE,OAAO,EAAE,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB;gBACxD,eAAe,EAAE,gBAAgB;aAClC,CAAC,CAAC;YACH,OAAO,WAAW,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;QACtD,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/mesh_help.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// what it already has loaded (tool descriptions, instructions,
|
|
11
11
|
// mesh://etiquette), tailored to whichever topic was picked.
|
|
12
12
|
//
|
|
13
|
-
//
|
|
13
|
+
// Six separate zero-argument prompts, not one `help` prompt with an
|
|
14
14
|
// optional `topic` argument -- found live: @modelcontextprotocol/sdk
|
|
15
15
|
// 1.30.0 (the latest at the time) throws "Invalid arguments ... Required"
|
|
16
16
|
// on getPrompt when a prompt's args are ALL optional and the caller
|
|
@@ -28,17 +28,19 @@ const TOPICS = [
|
|
|
28
28
|
name: "help",
|
|
29
29
|
description: "Quick-start help for the Macula mesh tools in this conversation -- overview, examples, gotchas.",
|
|
30
30
|
ask: "Give me a quick, example-driven overview of the Macula mesh tools available in this " +
|
|
31
|
-
"conversation: mesh_call, mesh_put, mesh_get, mesh_publish, mesh_watch,
|
|
32
|
-
"mesh://identity and mesh://etiquette resources. Show
|
|
33
|
-
"tool and the top 3 gotchas to avoid.",
|
|
31
|
+
"conversation: mesh_call, mesh_put, mesh_get, mesh_publish, mesh_watch, mesh_hello, " +
|
|
32
|
+
"mesh_agents, mesh_goodbye, plus the mesh://identity and mesh://etiquette resources. Show " +
|
|
33
|
+
"one realistic example call per tool and the top 3 gotchas to avoid.",
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
name: "help_identity",
|
|
37
37
|
description: "Explain how mesh identity works in this conversation (mesh_watch vs. every other tool).",
|
|
38
38
|
ask: "Explain how identity works for the Macula mesh tools in this conversation: what " +
|
|
39
|
-
"mesh://identity shows, why mesh_watch
|
|
40
|
-
"
|
|
41
|
-
"
|
|
39
|
+
"mesh://identity shows, why mesh_watch (and separately, presence -- mesh_hello/" +
|
|
40
|
+
"mesh_agents/mesh_goodbye) each use their own identity distinct from the other tools, " +
|
|
41
|
+
"and how to pin any of them to a fixed path with MACULA_MCP_IDENTITY / " +
|
|
42
|
+
"MACULA_MCP_WATCH_IDENTITY / MACULA_MCP_PRESENCE_IDENTITY if a stable node ID across " +
|
|
43
|
+
"restarts is needed.",
|
|
42
44
|
},
|
|
43
45
|
{
|
|
44
46
|
name: "help_wire_format",
|
|
@@ -55,6 +57,19 @@ const TOPICS = [
|
|
|
55
57
|
"issued as a second call in the same turn, and what it's actually good for (catching " +
|
|
56
58
|
"facts already in flight from someone else, not synchronizing with your own send).",
|
|
57
59
|
},
|
|
60
|
+
{
|
|
61
|
+
name: "help_presence",
|
|
62
|
+
description: "Explain mesh_hello/mesh_agents/mesh_goodbye -- what presence is for and how it persists.",
|
|
63
|
+
ask: "Explain the presence tools in this conversation: what mesh_hello actually starts (a " +
|
|
64
|
+
"periodic agent.hello heartbeat plus a durable subscription to other agents' hellos, " +
|
|
65
|
+
"backed by a daemon this server manages internally, not a one-shot call like every other " +
|
|
66
|
+
"tool here), what mesh_agents shows (a persistent SQLite roster, not an in-memory list, " +
|
|
67
|
+
"so it survives a restart) and how staleness/pruning works, and why mesh_goodbye matters " +
|
|
68
|
+
"(removes you from others' rosters immediately instead of waiting for your heartbeat to " +
|
|
69
|
+
"simply stop). Mention operator_name as the stable human-facing label over what's often " +
|
|
70
|
+
"an ephemeral node ID, and that mesh_hello shouldn't be called reflexively -- it's a " +
|
|
71
|
+
"deliberate decision to be discoverable, not a connection side effect.",
|
|
72
|
+
},
|
|
58
73
|
{
|
|
59
74
|
name: "help_install",
|
|
60
75
|
description: "Explain how to install macula-mcp, register it, and verify it's actually working.",
|
package/dist/mesh_help.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mesh_help.js","sourceRoot":"","sources":["../src/mesh_help.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,sEAAsE;AACtE,wEAAwE;AACxE,sEAAsE;AACtE,yEAAyE;AACzE,yEAAyE;AACzE,wEAAwE;AACxE,yEAAyE;AACzE,+DAA+D;AAC/D,6DAA6D;AAC7D,EAAE;AACF,
|
|
1
|
+
{"version":3,"file":"mesh_help.js","sourceRoot":"","sources":["../src/mesh_help.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,sEAAsE;AACtE,wEAAwE;AACxE,sEAAsE;AACtE,yEAAyE;AACzE,yEAAyE;AACzE,wEAAwE;AACxE,yEAAyE;AACzE,+DAA+D;AAC/D,6DAA6D;AAC7D,EAAE;AACF,oEAAoE;AACpE,qEAAqE;AACrE,0EAA0E;AAC1E,oEAAoE;AACpE,0DAA0D;AAC1D,uEAAuE;AACvE,wEAAwE;AACxE,oEAAoE;AACpE,sEAAsE;AACtE,yEAAyE;AACzE,kEAAkE;AAClE,mEAAmE;AACnE,yEAAyE;AAUzE,MAAM,MAAM,GAAgB;IAC1B;QACE,IAAI,EAAE,MAAM;QACZ,WAAW,EACT,iGAAiG;QACnG,GAAG,EACD,sFAAsF;YACtF,qFAAqF;YACrF,2FAA2F;YAC3F,qEAAqE;KACxE;IACD;QACE,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,yFAAyF;QACtG,GAAG,EACD,kFAAkF;YAClF,gFAAgF;YAChF,uFAAuF;YACvF,wEAAwE;YACxE,sFAAsF;YACtF,qBAAqB;KACxB;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,WAAW,EAAE,uFAAuF;QACpG,GAAG,EACD,yFAAyF;YACzF,uFAAuF;YACvF,yFAAyF;YACzF,0FAA0F;KAC7F;IACD;QACE,IAAI,EAAE,YAAY;QAClB,WAAW,EAAE,gFAAgF;QAC7F,GAAG,EACD,uFAAuF;YACvF,sFAAsF;YACtF,mFAAmF;KACtF;IACD;QACE,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,0FAA0F;QACvG,GAAG,EACD,sFAAsF;YACtF,sFAAsF;YACtF,0FAA0F;YAC1F,yFAAyF;YACzF,0FAA0F;YAC1F,yFAAyF;YACzF,yFAAyF;YACzF,sFAAsF;YACtF,uEAAuE;KAC1E;IACD;QACE,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,mFAAmF;QAChG,GAAG,EACD,mFAAmF;YACnF,sFAAsF;YACtF,oDAAoD;KACvD;CACF,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,MAAiB;IAC5C,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC;YAClD,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,EAAE,EAAE,CAAC;SACzE,CAAC,CAAC,CAAC;IACN,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare const HELLO_TOPIC = "agent.hello";
|
|
2
|
+
export declare const GOODBYE_TOPIC = "agent.goodbye";
|
|
3
|
+
export declare function isActive(): boolean;
|
|
4
|
+
export interface StartArgs {
|
|
5
|
+
host?: string;
|
|
6
|
+
operatorName?: string;
|
|
7
|
+
message?: string;
|
|
8
|
+
intervalSeconds?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface StartResult {
|
|
11
|
+
node_id: string;
|
|
12
|
+
connected_to: string;
|
|
13
|
+
interval_seconds: number;
|
|
14
|
+
already_active: boolean;
|
|
15
|
+
}
|
|
16
|
+
/** Idempotent: a second call just updates operatorName/message for future heartbeats. */
|
|
17
|
+
export declare function start(args: StartArgs): Promise<StartResult>;
|
|
18
|
+
export interface StopResult {
|
|
19
|
+
said_goodbye: boolean;
|
|
20
|
+
}
|
|
21
|
+
/** Publishes agent.goodbye, then tears everything down. No-op if not active. */
|
|
22
|
+
export declare function stop(): Promise<StopResult>;
|