@macula-io/mcp 0.4.1 → 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 CHANGED
@@ -20,8 +20,8 @@ Continue, and anything else that speaks MCP.
20
20
  // .mcp.json (or your harness's MCP config)
21
21
  {
22
22
  "mcpServers": {
23
- "macula": { "command": "macula-mcp" }
24
- }
23
+ "macula": { "command": "macula-mcp" },
24
+ },
25
25
  }
26
26
  ```
27
27
 
@@ -40,7 +40,7 @@ of its own.
40
40
  ```
41
41
  ┌───────────────┐ MCP/stdio ┌────────────┐ spawns, parses stdout ┌────────────┐ QUIC ┌──────────────┐
42
42
  │ agent harness │ ────────────▶ │ macula-mcp │ ──────────────────────▶ │ macula-cli │ ─────────▶│ Macula mesh │
43
- └───────────────┘ └────────────┘ └────────────┘ └──────────────┘
43
+ └───────────────┘ └────────────┘ └────────────┘ └──────────────┘
44
44
  ```
45
45
 
46
46
  **Reworked 2026-08-29** from an earlier design that proxied to a local
@@ -64,36 +64,67 @@ QUIC/DHT wire protocol, not a mock.
64
64
 
65
65
  ## Tools
66
66
 
67
- | Tool | Primitive | What it does |
68
- |---|---|---|
69
- | `mesh_call` | RPC | Invoke a capability a peer advertises (build, test, search, deploy) over the mesh. Returns the result + `duration_ms`. |
70
- | `mesh_put` | Content Sharing | Publish a content-addressed artifact; returns its MCID hex. |
71
- | `mesh_get` | Content Sharing | Fetch a content-addressed artifact by MCID hex. |
72
- | `mesh_publish` | Pub/Sub | Emit an integration fact to a topic (business verbs only, never CRUD). Returns `topic`/`seq`. |
73
- | `mesh_watch` | Pub/Sub | Watch a topic for up to `duration_seconds` (max 120) and return whatever arrived. **Blocks for the call's duration** — there's no standing background subscription; call again to keep watching. |
67
+ | Tool | Primitive | What it does |
68
+ | -------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
69
+ | `mesh_call` | RPC | Invoke a capability a peer advertises (build, test, search, deploy) over the mesh. Returns the result + `duration_ms`. |
70
+ | `mesh_put` | Content Sharing | Publish a content-addressed artifact; returns its MCID hex. |
71
+ | `mesh_get` | Content Sharing | Fetch a content-addressed artifact by MCID hex. |
72
+ | `mesh_publish` | Pub/Sub | Emit an integration fact to a topic (business verbs only, never CRUD). Returns `topic`/`seq`. |
73
+ | `mesh_watch` | Pub/Sub | Watch a topic for up to `duration_seconds` (max 120) and return whatever arrived. **Blocks for the call's duration** — there's no standing background subscription; call again to keep watching. |
74
+ | `mesh_hello` | Presence | Announce this agent on the mesh: prints a welcome banner, publishes an `agent.hello` immediately, and starts a periodic heartbeat (default 60s) plus a durable subscription to everyone else's hellos. A deliberate action, not automatic on startup — see [Presence](#presence). |
75
+ | `mesh_agents` | Presence | A paged list of agents seen via `agent.hello`, sorted most-recently-seen first. Reads a local cache; only reflects agents heard from while this process has been running. |
76
+ | `mesh_goodbye` | Presence | Leave deliberately: publishes one `agent.goodbye` (so others drop this node immediately, not on a staleness timeout), then stops the heartbeat and subscription started by `mesh_hello`. |
74
77
 
75
78
  Every tool takes an optional `host` (`"host[:port]"`) to pick which station
76
79
  to connect through; all default to `MACULA_MESH_STATION` (see
77
80
  [Environment](#environment)).
78
81
 
82
+ ### Presence
83
+
84
+ `mesh_hello`/`mesh_agents`/`mesh_goodbye` are the one deliberate exception
85
+ to "every tool is a one-shot `macula-cli` subprocess call": together they
86
+ manage this server's own standing presence, backed by one internally-managed
87
+ `macula-cli daemon` (see that repo's own README's Daemon mode section) held
88
+ open for as long as this process runs. This reverses `mesh_watch`'s own
89
+ earlier design note that a standing subscription wasn't built because
90
+ `macula-cli` had no daemon at the time — it does now, and presence is this
91
+ server narrowly taking that fork back up, scoped to exactly this one use.
92
+
93
+ The roster (`mesh_agents`' data) persists to a local SQLite database (via
94
+ `better-sqlite3`, not kept in memory), so a restart doesn't forget everyone
95
+ seen minutes ago — `$HOME/.macula-mcp/roster.sqlite3` by default, overridable
96
+ with `MACULA_MCP_ROSTER_DB`. Each row carries `last_seen_at`; `mesh_agents`
97
+ prunes entries unseen for 15 minutes on every read, and an explicit
98
+ `agent.goodbye` removes its sender immediately rather than waiting on that
99
+ window. The heartbeat itself is an ordinary one-shot `pubsub publish` on a
100
+ timer, not routed through the daemon — `macula-cli`'s daemon protocol has
101
+ no publish-via-daemon method, only call/serve/subscribe.
102
+
103
+ Customize what a hello carries with `MACULA_MCP_OPERATOR_NAME` (a
104
+ human-readable name for whoever's behind this agent), `MACULA_MCP_HELLO_MESSAGE`
105
+ (a default greeting/status), and `MACULA_MCP_BANNER_FILE` (a path to custom
106
+ ASCII art, falling back to a small bundled default). Both env vars are
107
+ overridable per call via `mesh_hello`'s own `operator_name`/`message`
108
+ arguments.
109
+
79
110
  ## Resources
80
111
 
81
- | Resource | Content |
82
- |---|---|
83
- | `mesh://identity` | This macula-mcp server process's own Ed25519 identity (node ID) — minted fresh per process since v0.4.0, not the same as running `macula-cli` by hand. |
112
+ | Resource | Content |
113
+ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
114
+ | `mesh://identity` | This macula-mcp server process's own Ed25519 identity (node ID) — minted fresh per process since v0.4.0, not the same as running `macula-cli` by hand. |
84
115
  | `mesh://etiquette` | The reasoning and receipts behind the mesh-citizenship rules also condensed into this server's MCP `instructions` (wire-format limits, naming norms, what this server deliberately doesn't do). |
85
116
 
86
117
  ## Prompts
87
118
 
88
119
  For a HUMAN in the conversation, not the agent — surfaces as a slash command in clients that support MCP prompts (e.g. `/mcp__macula__help` in Claude Code). Five zero-argument prompts rather than one with a topic argument: `@modelcontextprotocol/sdk` 1.30.0 errors on a bare invocation (no `arguments` field at all — the normal way to invoke a plain slash command) of a prompt whose args are all optional, so separate prompts sidestep it.
89
120
 
90
- | Prompt | Asks the model to explain |
91
- |---|---|
92
- | `help` | Full quick-start: tool overview, one example each, top gotchas. |
93
- | `help_identity` | How identity works, `mesh_watch`'s separate identity, pinning with env vars. |
94
- | `help_wire_format` | The no-bool / naming rules, with a valid and invalid example. |
95
- | `help_watch` | What `mesh_watch` is actually for, and the mistake to avoid. |
96
- | `help_install` | Install, register, verify (`doctor`), what a failure means. |
121
+ | Prompt | Asks the model to explain |
122
+ | ------------------ | ---------------------------------------------------------------------------- |
123
+ | `help` | Full quick-start: tool overview, one example each, top gotchas. |
124
+ | `help_identity` | How identity works, `mesh_watch`'s separate identity, pinning with env vars. |
125
+ | `help_wire_format` | The no-bool / naming rules, with a valid and invalid example. |
126
+ | `help_watch` | What `mesh_watch` is actually for, and the mistake to avoid. |
127
+ | `help_install` | Install, register, verify (`doctor`), what a failure means. |
97
128
 
98
129
  ## Prerequisites
99
130
 
@@ -130,7 +161,7 @@ Then verify it actually works, not just that the config file has the
130
161
  entry:
131
162
 
132
163
  ```bash
133
- npx @macula-io/mcp doctor
164
+ macula-mcp-doctor
134
165
  ```
135
166
 
136
167
  To uninstall (unregisters from every MCP client, then removes the `npm`
@@ -160,15 +191,35 @@ and troubleshooting.
160
191
 
161
192
  ## Environment
162
193
 
163
- | Variable | Purpose | Default |
164
- |---|---|---|
165
- | `MACULA_CLI_BIN` | Override the `macula-cli` binary path/name. | `macula-cli` (resolved via `PATH`) |
166
- | `MACULA_MESH_STATION` | Default station every tool connects through when a call doesn't override `host`. | `station-de-frankfurt.macula.io:4433` |
167
- | `MACULA_MCP_IDENTITY` | Pin the identity `mesh_call`/`mesh_put`/`mesh_get`/`mesh_publish` use to a fixed path, instead of a fresh one minted per process. | fresh temp file per process, deleted on exit |
168
- | `MACULA_MCP_WATCH_IDENTITY` | Same, for `mesh_watch`'s identity (kept separate from every other tool's — see the [guide](guides/HOWTO.md) §2). | fresh temp file per process, deleted on exit |
194
+ | Variable | Purpose | Default |
195
+ | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
196
+ | `MACULA_CLI_BIN` | Override the `macula-cli` binary path/name. | `macula-cli` (resolved via `PATH`) |
197
+ | `MACULA_MESH_STATION` | Default station every tool connects through when a call doesn't override `host`. | `station-de-frankfurt.macula.io:4433` |
198
+ | `MACULA_MCP_IDENTITY` | Pin the identity `mesh_call`/`mesh_put`/`mesh_get`/`mesh_publish` use to a fixed path, instead of a fresh one minted per process. | fresh temp file per process, deleted on exit |
199
+ | `MACULA_MCP_WATCH_IDENTITY` | Same, for `mesh_watch`'s identity (kept separate from every other tool's — see the [guide](guides/HOWTO.md) §2). | fresh temp file per process, deleted on exit |
200
+ | `MACULA_MCP_PRESENCE_IDENTITY` | Same, for the internal daemon `mesh_hello`/`mesh_agents`/`mesh_goodbye` hold open (a third identity, separate from both of the above for the same collision reason). | fresh temp file per process, deleted on exit |
201
+ | `MACULA_MCP_ROSTER_DB` | Where `mesh_agents`' SQLite roster lives. | `$HOME/.macula-mcp/roster.sqlite3` |
202
+ | `MACULA_MCP_OPERATOR_NAME` | Default `operator_name` for `mesh_hello`, when the agent doesn't pass one explicitly. | none |
203
+ | `MACULA_MCP_HELLO_MESSAGE` | Default `message` for `mesh_hello`, when the agent doesn't pass one explicitly. | none |
204
+ | `MACULA_MCP_BANNER_FILE` | Path to a custom ASCII banner `mesh_hello` prints. | a small bundled default |
169
205
 
170
206
  ## Status
171
207
 
208
+ **v0.5.0 — mesh_hello/mesh_agents/mesh_goodbye, real presence, 2026-08-30.** The first
209
+ tools that aren't a bare one-shot `macula-cli` subprocess call: an
210
+ internally-managed `macula-cli daemon` (new in that repo's own v0.2.0, which
211
+ this raises `MIN_MACULA_CLI_VERSION` to) backs a periodic `agent.hello`
212
+ heartbeat and a durable subscription to everyone else's, feeding a
213
+ SQLite-backed roster (`better-sqlite3`, not in-memory — a restart doesn't
214
+ forget who was seen minutes ago). Verified live end to end against the real
215
+ demo fleet: two independent processes each see the other's hello in their
216
+ own roster within one heartbeat, and an explicit `mesh_goodbye` removes its
217
+ sender from the other's roster immediately (confirmed against the wall-clock
218
+ timing of when it was actually sent, not just "eventually disappeared").
219
+ Also fixed in the same pass: a version-string drift where the MCP server
220
+ itself reported `0.4.0` to clients while `package.json` already said
221
+ `0.4.1`.
222
+
172
223
  **v0.4.0 — per-process identity, MCP `instructions`, `doctor`, in-conversation help, 2026-08-29.**
173
224
  Re-verified live from inside a real Claude Code session (the actual
174
225
  `mcp__macula__*` tools, not just a bare MCP `Client`) and found a real
@@ -196,16 +247,22 @@ wrong-shape-but-valid-JSON error envelope from a real event, so it needs
196
247
  an explicit shape check.
197
248
 
198
249
  **Dropped in this rework, not carried over from the daemon-backed
199
- design** — `macula-cli` is a one-shot process with no daemon and no
200
- storage, so none of these have an honest equivalent without `macula-mcp`
201
- itself becoming a stateful daemon (a real design fork that was deliberately
202
- not taken; see `macula-io/macula-cli`'s own project memory for the
203
- tradeoff):
250
+ design** — at the time (`macula-cli` was a one-shot process with no daemon
251
+ and no storage), none of these had an honest equivalent without `macula-mcp`
252
+ itself becoming a stateful daemon, a fork deliberately not taken then (see
253
+ `macula-io/macula-cli`'s own project memory for that tradeoff). `macula-cli`
254
+ gained a real daemon later (v0.2.0) — presence (`mesh_hello`/`mesh_agents`/
255
+ `mesh_goodbye`, see [Presence](#presence)) is this server narrowly taking
256
+ that fork back up for exactly one use, not a reversal of the rework below:
257
+
204
258
  - **Standing subscriptions + inbox.** The old `mesh_subscribe`/
205
259
  `mesh_unsubscribe`/`mesh_subscriptions`/`mesh_inbox` quartet relied on
206
260
  the daemon's own event-sourced background subscription that outlived any
207
261
  one call. Replaced by `mesh_watch`, which blocks for a bounded duration
208
- and returns what arrived — call it again to keep watching.
262
+ and returns what arrived — call it again to keep watching. (Presence's
263
+ own `agent.hello`/`agent.goodbye` subscription is the one exception, and
264
+ exists for a narrower reason: feeding `mesh_agents`' roster, not a
265
+ general-purpose standing watch on an arbitrary topic.)
209
266
  - **Activity audit log** (`mesh://activity/{realm}`, `fact_id` on every
210
267
  write). That was hecate-daemon's own ReckonDB-backed accountability
211
268
  trail. Writes still happen for real on the mesh; there's just no local
@@ -222,9 +279,11 @@ best-effort cross-station.
222
279
 
223
280
  ## Documentation
224
281
 
225
- | Guide | Description |
226
- |---|---|
282
+ | Guide | Description |
283
+ | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
227
284
  | [HOW-TO Guide](guides/HOWTO.md) | Install/uninstall env var reference, each tool's exact behavior, troubleshooting a failed tool call, the two real gotchas found live-testing this rework |
285
+ | [CHANGELOG](CHANGELOG.md) | What changed in each released version, and what's on `main` but not yet tagged |
286
+ | [CONTRIBUTING](CONTRIBUTING.md) | Build/test/verify locally, the native-dependency gotcha, how a release actually gets published |
228
287
 
229
288
  ## License
230
289
 
@@ -37,7 +37,7 @@ function parseArgs(argv) {
37
37
  function help() {
38
38
  console.log(`macula-mcp doctor ${VERSION}
39
39
 
40
- Usage: npx @macula-io/mcp doctor [--only <client[,client,...]>]
40
+ Usage: macula-mcp-doctor [--only <client[,client,...]>]
41
41
 
42
42
  Real smoke test, not a config-file check: reads each configured client's
43
43
  recorded macula entry, spawns the EXACT command it would run, connects a
@@ -48,7 +48,7 @@ function parseArgs(argv) {
48
48
  function help() {
49
49
  console.log(`macula-mcp install ${VERSION}
50
50
 
51
- Usage: npx @macula-io/mcp install [--force] [--only <client[,client,...]>]
51
+ Usage: macula-mcp-install [--force] [--only <client[,client,...]>]
52
52
 
53
53
  Detects installed MCP clients and registers the 'macula' MCP server,
54
54
  which shells out to macula-cli for mesh operations. Idempotent;
@@ -155,7 +155,7 @@ async function main() {
155
155
  ok("done.");
156
156
  console.log(`\nRestart your MCP client(s), then verify the entry actually works (not just that\n` +
157
157
  `the config file has it) with:\n` +
158
- ` npx @macula-io/mcp doctor\n` +
158
+ ` macula-mcp-doctor\n` +
159
159
  `\nOr ask your LLM directly:\n` +
160
160
  ` "Read the mesh://identity resource and tell me my node ID."\n`);
161
161
  }
@@ -1 +1 @@
1
- {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/bin/install.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/bin/install.ts"],"names":[],"mappings":"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"}
@@ -15,7 +15,7 @@ const VERSION = "0.4.0";
15
15
  function help() {
16
16
  console.log(`macula-mcp status ${VERSION}
17
17
 
18
- Usage: npx @macula-io/mcp status
18
+ Usage: macula-mcp-status
19
19
 
20
20
  Read-only diagnostic. Reports macula-cli availability and MCP-client
21
21
  configuration state.
@@ -45,7 +45,7 @@ async function main() {
45
45
  await reportClient(client);
46
46
  }
47
47
  console.log("\n\"registered\" above means the config file has the right entry -- it does not");
48
- console.log("prove the entry actually runs. Run `npx @macula-io/mcp doctor` for a real check.");
48
+ console.log("prove the entry actually runs. Run `macula-mcp-doctor` for a real check.");
49
49
  }
50
50
  async function reportClient(c) {
51
51
  const installed = c.isInstalled();
@@ -1 +1 @@
1
- {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/bin/status.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/bin/status.ts"],"names":[],"mappings":"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"}
@@ -24,7 +24,7 @@ function parseArgs(argv) {
24
24
  function help() {
25
25
  console.log(`macula-mcp uninstall ${VERSION}
26
26
 
27
- Usage: npx @macula-io/mcp uninstall [--all]
27
+ Usage: macula-mcp-uninstall [--all]
28
28
 
29
29
  Removes the 'macula' MCP server entry from every detected MCP
30
30
  client's config. The macula-cli binary and your persisted identity
package/dist/index.js CHANGED
@@ -3,22 +3,26 @@
3
3
  // any agent harness (Claude Code, Cursor, Cline, Continue, ...).
4
4
  //
5
5
  // Topology: thin client. macula-mcp speaks MCP over stdio to the agent, and
6
- // shells out to macula-cli (macula-io/macula-cli), a one-shot scriptable CLI
7
- // built directly on macula-go-sdk. macula-mcp owns no mesh logic of its
8
- // own -- macula-cli does the QUIC handshake/call/publish/watch/content
9
- // transfer as a subprocess per tool call.
6
+ // shells out to macula-cli (macula-io/macula-cli), a scriptable CLI built
7
+ // directly on macula-go. macula-mcp owns no mesh logic of its own -- macula-cli
8
+ // does the QUIC handshake/call/publish/watch/content transfer, either as a
9
+ // one-shot subprocess per tool call, or (mesh_hello/mesh_goodbye/mesh_agents
10
+ // only, via presence.ts) as one long-lived `macula-cli daemon` this server
11
+ // manages internally for as long as it runs.
10
12
  //
11
13
  // agent harness --MCP/stdio--> macula-mcp --spawns, parses stdout--> macula-cli --QUIC--> mesh
12
14
  //
13
15
  // Reworked 2026-08-29 from a hecate-daemon-backed design (HTTP over a
14
- // local Unix socket) to this one: hecate-daemon is a leftover of an
15
- // abandoned local browser/UI plan and is no longer something this server
16
- // should depend on. This is a deliberately LEAN rework, not a like-for-
17
- // like swap -- macula-cli is a one-shot process with no daemon and no
18
- // storage, so standing subscriptions, an activity/inbox audit log, and
19
- // peer listing don't carry over; mesh_watch (bounded, synchronous)
20
- // replaces the old subscribe/unsubscribe/subscriptions/inbox quartet.
21
- // See macula-io/macula-cli's own project memory for the fuller tradeoff.
16
+ // local Unix socket) to a one-shot-subprocess-per-call one: hecate-daemon is
17
+ // a leftover of an abandoned local browser/UI plan and is no longer
18
+ // something this server should depend on. That rework's own doc comment
19
+ // (see mesh_watch.ts) explained why a standing subscription wasn't rebuilt
20
+ // on top of macula-cli: it had no daemon of its own at the time, so
21
+ // mesh_watch (bounded, synchronous) replaced the old subscribe/unsubscribe/
22
+ // subscriptions/inbox quartet instead. macula-cli gained a real daemon mode
23
+ // later (2026-08-30) -- presence.ts is this server narrowly taking that
24
+ // fork back up, scoped to exactly one use (agent-presence heartbeat +
25
+ // roster), not a wholesale return to the old design.
22
26
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
23
27
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
24
28
  import { registerIdentity } from "./mesh_identity.js";
@@ -28,6 +32,9 @@ import { registerMeshCall } from "./mesh_call.js";
28
32
  import { registerMeshArtifact } from "./mesh_artifact.js";
29
33
  import { registerMeshPublish } from "./mesh_publish.js";
30
34
  import { registerMeshWatch } from "./mesh_watch.js";
35
+ import { registerMeshHello } from "./mesh_hello.js";
36
+ import { registerMeshGoodbye } from "./mesh_goodbye.js";
37
+ import { registerMeshAgents } from "./mesh_agents.js";
31
38
  // Surfaced by every MCP client at connect time (the SDK's own
32
39
  // ServerOptions.instructions), not something a model has to think to go
33
40
  // read -- this is the mechanism for baking mesh-citizenship norms into
@@ -45,8 +52,11 @@ a response.
45
52
  - Read mesh://identity first so you know which node ID you're acting as. Read mesh://etiquette \
46
53
  for the full reasoning behind these rules. A person in this conversation can also ask for \
47
54
  help directly (/mcp__macula__help and friends -- help_identity, help_wire_format, help_watch, \
48
- help_install -- if their client supports MCP prompts).`;
49
- const server = new McpServer({ name: "macula-mcp", version: "0.4.0" }, { instructions: INSTRUCTIONS });
55
+ help_presence, help_install -- if their client supports MCP prompts).
56
+ - mesh_hello announces this agent's presence (a periodic heartbeat plus a live roster of other \
57
+ agents heard from) -- call it once if you want to be discoverable, then mesh_agents to see who \
58
+ else is around. Call mesh_goodbye to leave deliberately rather than just going quiet.`;
59
+ const server = new McpServer({ name: "macula-mcp", version: "0.5.0" }, { instructions: INSTRUCTIONS });
50
60
  // Resources — read-only context an agent should consult before acting.
51
61
  registerIdentity(server);
52
62
  registerEtiquette(server);
@@ -58,6 +68,13 @@ registerMeshCall(server);
58
68
  registerMeshArtifact(server);
59
69
  registerMeshPublish(server);
60
70
  registerMeshWatch(server);
71
+ // mesh_hello/mesh_goodbye are the one exception to "one-shot": together
72
+ // they manage this process's own standing presence (heartbeat +
73
+ // subscriptions), see presence.ts's own doc comment for why that's a
74
+ // deliberate, narrow departure from every other tool here.
75
+ registerMeshHello(server);
76
+ registerMeshGoodbye(server);
77
+ registerMeshAgents(server);
61
78
  async function main() {
62
79
  const transport = new StdioServerTransport();
63
80
  await server.connect(transport);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,+EAA+E;AAC/E,iEAAiE;AACjE,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,wEAAwE;AACxE,uEAAuE;AACvE,0CAA0C;AAC1C,EAAE;AACF,uGAAuG;AACvG,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,yEAAyE;AACzE,wEAAwE;AACxE,sEAAsE;AACtE,uEAAuE;AACvE,mEAAmE;AACnE,sEAAsE;AACtE,yEAAyE;AAEzE,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEpD,8DAA8D;AAC9D,wEAAwE;AACxE,uEAAuE;AACvE,sEAAsE;AACtE,sEAAsE;AACtE,iEAAiE;AACjE,MAAM,YAAY,GAAG;;;;;;;;;;;uDAWkC,CAAC;AAExD,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,EACxC,EAAE,YAAY,EAAE,YAAY,EAAE,CAC/B,CAAC;AAEF,uEAAuE;AACvE,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACzB,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAE1B,uEAAuE;AACvE,8DAA8D;AAC9D,YAAY,CAAC,MAAM,CAAC,CAAC;AAErB,+DAA+D;AAC/D,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACzB,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAC7B,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC5B,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAE1B,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,6CAA6C;IAC7C,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;AAC5C,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;IACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,+EAA+E;AAC/E,iEAAiE;AACjE,EAAE;AACF,4EAA4E;AAC5E,0EAA0E;AAC1E,gFAAgF;AAChF,2EAA2E;AAC3E,6EAA6E;AAC7E,2EAA2E;AAC3E,6CAA6C;AAC7C,EAAE;AACF,uGAAuG;AACvG,EAAE;AACF,sEAAsE;AACtE,6EAA6E;AAC7E,oEAAoE;AACpE,wEAAwE;AACxE,2EAA2E;AAC3E,oEAAoE;AACpE,4EAA4E;AAC5E,4EAA4E;AAC5E,wEAAwE;AACxE,sEAAsE;AACtE,qDAAqD;AAErD,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,8DAA8D;AAC9D,wEAAwE;AACxE,uEAAuE;AACvE,sEAAsE;AACtE,sEAAsE;AACtE,iEAAiE;AACjE,MAAM,YAAY,GAAG;;;;;;;;;;;;;;sFAciE,CAAC;AAEvF,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,EACxC,EAAE,YAAY,EAAE,YAAY,EAAE,CAC/B,CAAC;AAEF,uEAAuE;AACvE,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACzB,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAE1B,uEAAuE;AACvE,8DAA8D;AAC9D,YAAY,CAAC,MAAM,CAAC,CAAC;AAErB,+DAA+D;AAC/D,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACzB,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAC7B,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC5B,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAE1B,wEAAwE;AACxE,gEAAgE;AAChE,qEAAqE;AACrE,2DAA2D;AAC3D,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAC1B,mBAAmB,CAAC,MAAM,CAAC,CAAC;AAC5B,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAE3B,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,6CAA6C;IAC7C,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;AAC5C,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;IACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -1,7 +1,20 @@
1
1
  /** The station this server targets when a tool call doesn't override it. */
2
2
  export declare function defaultStation(): string;
3
+ /** Name/path of the macula-cli binary; override for testing or a non-PATH install. */
4
+ export declare function binPath(): string;
5
+ export declare function onShutdown(fn: () => void): void;
3
6
  /** Exported for mesh_identity.ts (the mesh://identity resource) and for tests. */
4
7
  export declare function defaultIdentityPath(): string;
8
+ /**
9
+ * A THIRD identity, dedicated to presence.ts's own daemon (agent.hello/
10
+ * agent.goodbye subscriptions) -- separate from "default" and "watch"
11
+ * for the same reason those two are already separate from each other:
12
+ * two connections sharing one node ID get the second one kicked by the
13
+ * station (see watchIdentityPath's own doc). The presence daemon holds
14
+ * a connection open for as long as this process runs, so it must never
15
+ * share an identity with anything else that might connect concurrently.
16
+ */
17
+ export declare function presenceIdentityPath(): string;
5
18
  /** Exported for tests only -- no other module needs it, mesh_watch calls watch() directly. */
6
19
  export declare function watchIdentityPath(): string;
7
20
  export declare class MaculaCliUnavailable extends Error {
@@ -26,8 +39,12 @@ export declare class MaculaCliError extends Error {
26
39
  * call -- exactly the shape `mesh_publish` uses -- with zero error
27
40
  * surfaced anywhere. Bump this constant whenever a macula-cli fix this
28
41
  * server's own tools depend on ships in a new release.
42
+ *
43
+ * Bumped to 0.2.0 for presence.ts: mesh_hello/mesh_goodbye/mesh_agents
44
+ * depend on `macula-cli daemon` and `pubsub watch -daemon`/-subscribe,
45
+ * both new in that release -- v0.1.x has no daemon subcommand at all.
29
46
  */
30
- export declare const MIN_MACULA_CLI_VERSION = "0.1.3";
47
+ export declare const MIN_MACULA_CLI_VERSION = "0.2.0";
31
48
  export interface CliVersionCheck {
32
49
  ok: boolean;
33
50
  /** The raw `macula-cli --version` output, or undefined if it couldn't be run at all. */
@@ -103,6 +120,18 @@ export interface WatchEvent {
103
120
  * Exported standalone so this parsing can be unit-tested without
104
121
  * spawning a real subprocess.
105
122
  */
123
+ /**
124
+ * Parses ONE line of `pubsub watch --json` output -- the same per-line
125
+ * shape parseWatchOutput batch-parses after a bounded watch's process
126
+ * exits, factored out so presence.ts's long-lived subscription (which
127
+ * never exits under normal operation, so there's no final stdout
128
+ * string to batch-parse) can apply it incrementally as lines stream
129
+ * in. Returns null for a blank line or a trailing {"ok":true,...}
130
+ * envelope (not expected in this format, but skipped rather than
131
+ * misparsed as an event); throws MaculaCliError on a trailing
132
+ * {"ok":false,...} failure envelope.
133
+ */
134
+ export declare function parseWatchLine(line: string): WatchEvent | null;
106
135
  export declare function parseWatchOutput(stdout: string): WatchEvent[];
107
136
  /**
108
137
  * Watches a topic for up to durationSeconds and returns whatever
@@ -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, () => process.exit(0));
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() {
@@ -176,8 +218,12 @@ function execFile(bin, args) {
176
218
  * call -- exactly the shape `mesh_publish` uses -- with zero error
177
219
  * surfaced anywhere. Bump this constant whenever a macula-cli fix this
178
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.
179
225
  */
180
- export const MIN_MACULA_CLI_VERSION = "0.1.3";
226
+ export const MIN_MACULA_CLI_VERSION = "0.2.0";
181
227
  /**
182
228
  * Parses "X.Y.Z" (optionally "vX.Y.Z") out of an arbitrary string;
183
229
  * undefined if none found. Exported standalone so this parsing can be
@@ -256,27 +302,43 @@ export const publish = (args) => run(argv(["pubsub", "publish"], ["--identity",
256
302
  * Exported standalone so this parsing can be unit-tested without
257
303
  * spawning a real subprocess.
258
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
+ }
259
336
  export function parseWatchOutput(stdout) {
260
337
  const events = [];
261
338
  for (const line of stdout.split("\n")) {
262
- const trimmed = line.trim();
263
- if (!trimmed)
264
- continue;
265
- let parsed;
266
- try {
267
- parsed = JSON.parse(trimmed);
268
- }
269
- catch {
270
- continue; // not JSON at all; ignore this line
271
- }
272
- if (parsed !== null && typeof parsed === "object" && "ok" in parsed) {
273
- const envelope = parsed;
274
- if (envelope.ok === false) {
275
- throw new MaculaCliError(envelope.error?.message ?? "pubsub watch failed");
276
- }
277
- continue; // an {"ok":true,...} envelope line isn't expected here, but skip rather than misparse it as an event
278
- }
279
- events.push(parsed);
339
+ const evt = parseWatchLine(line);
340
+ if (evt)
341
+ events.push(evt);
280
342
  }
281
343
  return events;
282
344
  }