@cotal-ai/connector-claude-code 0.8.3 → 0.9.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.
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"AAIA,OAAO,EAA2D,KAAK,SAAS,EAAoC,MAAM,gBAAgB,CAAC;AAoB3I;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,SA0G7B,CAAC"}
1
+ {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"AAIA,OAAO,EAA2D,KAAK,SAAS,EAAoC,MAAM,gBAAgB,CAAC;AAoB3I;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,SAmH7B,CAAC"}
package/dist/extension.js CHANGED
@@ -31,6 +31,7 @@ export const claudeConnector = {
31
31
  transcriptChannel, // the shared `tr-<name>` convention (connector-core), exposed via the contract
32
32
  pluginRoot: PLUGIN_ROOT,
33
33
  requires: ["claude"],
34
+ supportsResume: true, // renders `--resume <id> --fork-session` (fork-from, never hijack) — see buildLaunch
34
35
  buildLaunch(opts) {
35
36
  // Operator MCP servers shared with this agent (default none — see the --mcp-config block).
36
37
  const shared = opts.mcpServers ?? {};
@@ -124,6 +125,13 @@ export const claudeConnector = {
124
125
  // The `--model` flag wins over the agent file, and applies even with no agent file.
125
126
  if (model)
126
127
  args.push("--model", model);
128
+ // Fork an existing session INTO the mesh (opts.resume, an opaque host-local id). `--fork-session`
129
+ // is pushed in the SAME branch — resume here is fork-only, never a hijack: claude mints a NEW
130
+ // session id from that transcript and leaves the original untouched. The id is a single argv
131
+ // token (no shell), so a hostile-looking id can't inject. The persona `--append-system-prompt`
132
+ // above still applies, so the forked context runs under the current mesh persona.
133
+ if (opts.resume)
134
+ args.push("--resume", opts.resume, "--fork-session");
127
135
  return {
128
136
  command: "claude",
129
137
  args,
@@ -1 +1 @@
1
- {"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"}
package/dist/mcp.cjs CHANGED
@@ -47983,6 +47983,7 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
47983
47983
  ttlMs;
47984
47984
  doRegister;
47985
47985
  doWatch;
47986
+ doWatchChannels;
47986
47987
  doConsume;
47987
47988
  ackWaitMs;
47988
47989
  inactiveThresholdMs;
@@ -48098,6 +48099,7 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
48098
48099
  this.ttlMs = opts.ttlMs ?? 6e3;
48099
48100
  this.doRegister = opts.registerPresence ?? true;
48100
48101
  this.doWatch = opts.watchPresence ?? true;
48102
+ this.doWatchChannels = opts.watchChannels ?? true;
48101
48103
  this.doConsume = opts.consume ?? true;
48102
48104
  this.channelModes = opts.channelModes && Object.keys(opts.channelModes).length ? opts.channelModes : void 0;
48103
48105
  this.ackWaitMs = opts.ackWaitMs ?? 6e4;
@@ -48137,9 +48139,10 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
48137
48139
  await this.startPresenceWatch();
48138
48140
  this.sweepTimer = setInterval(() => this.sweep(), Math.max(500, Math.floor(this.ttlMs / 3)));
48139
48141
  }
48140
- if (this.doWatch || this.doConsume) {
48142
+ const watchChannels = this.doWatch && this.doWatchChannels;
48143
+ if (watchChannels || this.doConsume) {
48141
48144
  this.channelKv = await openChannelRegistry(this.nc, this.space, { create: !this.creds });
48142
- if (this.doWatch)
48145
+ if (watchChannels)
48143
48146
  await this.startChannelWatch();
48144
48147
  }
48145
48148
  if (this.doRegister) {
@@ -48430,8 +48433,10 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
48430
48433
  * PEER's reply lane (`ctl.delivery.<victim>.reply.<n>`) and turn the responder into a confused
48431
48434
  * deputy — the broker does NOT permission-check the requester's embedded reply subject. With it, a
48432
48435
  * reply is published only when `m.reply` is under the AUTHENTICATED request subject
48433
- * (`${m.subject}.reply.…`), binding the reply to the broker-policed sender token. (The manager's
48434
- * tiers reply into the per-id `_INBOX` and leave it off.) */
48436
+ * (`${m.subject}.reply.…`), binding the reply to the broker-policed sender token. The manager's three
48437
+ * lifecycle tiers ALSO require it as of closure (i): they reply on bounded `ctl.<tier>.<caller>.reply.…`
48438
+ * (the manager cred holds the wildcard `ctl.<tier>.*.reply.>` pub — exactly the confused-deputy
48439
+ * condition above), so do NOT drop `boundReply` on them. */
48435
48440
  serveControl(service, handler, opts = {}) {
48436
48441
  if (!this.nc)
48437
48442
  throw new Error("endpoint not started");
@@ -48466,12 +48471,25 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
48466
48471
  })().catch((e) => this.emit("error", e));
48467
48472
  return sub;
48468
48473
  }
48469
- /** Send a control request to a service and await its reply (client side). */
48474
+ /** Send a control request to a service and await its reply (client side). Like {@link requestDelivery},
48475
+ * the reply rides a BOUNDED subject UNDER the request subject (`ctl.<service>.<id>.reply.<uuid>`), not
48476
+ * the per-id `_INBOX` — closure (i): this frees the manager's permission set from needing a position-1
48477
+ * inbox wildcard, so its publish surface can be an exact self-scoped allow-list (no message forging).
48478
+ * `noMux` lets us name the reply subject while keeping NoResponders detection. The random suffix is
48479
+ * defense-in-depth (a predictable suffix would let a peer target an in-flight named reply sub). The
48480
+ * reply sits under the sender's OWN request subject, so the responder's `boundReply` guard accepts it.
48481
+ *
48482
+ * CUTOVER (not backward-compatible): an agent cred minted BEFORE closure (i) lacks the
48483
+ * `ctl.<tier>.<id>.reply.>` sub grant — it can still publish the request but cannot subscribe the
48484
+ * reply, so its control calls (spawn/despawn/purge/definePersona, self-stop) hang. The per-user-auth
48485
+ * atomic cutover re-mints every agent; if this change ships ahead of that, agents must be RESPAWNED. */
48470
48486
  async requestControl(service, req, timeoutMs = 5e3) {
48471
48487
  if (!this.nc)
48472
48488
  throw new Error(this.notLiveMsg());
48489
+ const reqSubject = controlServiceSubject(this.space, service, this.card.id);
48490
+ const reply = `${reqSubject}.reply.${(0, import_node_crypto.randomUUID)()}`;
48473
48491
  const body = { ...req, from: req.from ?? this.ref() };
48474
- const m = await this.nc.request(controlServiceSubject(this.space, service, this.card.id), JSON.stringify(body), { timeout: timeoutMs });
48492
+ const m = await this.nc.request(reqSubject, JSON.stringify(body), { timeout: timeoutMs, noMux: true, reply });
48475
48493
  return m.json();
48476
48494
  }
48477
48495
  /** Send a durable-membership request to the SERVER-SIDE delivery daemon (`ctl.delivery`) and await its
@@ -48926,23 +48944,29 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
48926
48944
  return void 0;
48927
48945
  }
48928
48946
  }
48929
- /** Ensure + bind the manager singleton-lease bucket. NOTE: `Kvm.open` binds LAZILY — it does NOT
48930
- * verify the stream exists or throw when it's missing, so it can't "create if absent" (a fresh bucket
48931
- * then fails 'stream not found' on the first write — unlike the delivery bucket, which is pre-created
48932
- * at `cotal up`). `create` is the ensure-exists call: it makes the bucket (bucket-level TTL) or, when
48933
- * another manager already did, throws and we bind the now-existing one. Either way the per-KEY CAS
48934
- * create stays the only single-flight gate, so a lost bucket-create race never reads as "lease held".
48935
- * The manager is allow-all, so it may create. */
48947
+ /** Ensure + bind the manager singleton-lease bucket. Mirrors the presence-bucket pattern (connectAndBind):
48948
+ * AUTH mode OPENs the bucket pre-created at `cotal up` (the scoped `supervisor` cred holds no
48949
+ * STREAM.CREATE and `open` binds direct=false, so the CAS-conflict `kv.get` inside `acquire` rides
48950
+ * STREAM.MSG.GET, the verb the supervisor grants, never DIRECT.GET). OPEN mode (no creds) create-firsts:
48951
+ * `Kvm.open` binds LAZILY it does NOT verify the stream exists or throw when it's missing (a fresh
48952
+ * bucket then fails 'stream not found' on the first write), so `create` is the ensure-exists call (it
48953
+ * makes the bucket or, when another endpoint already did, throws and we bind the existing one). Either
48954
+ * way the per-KEY CAS create stays the only single-flight gate, so a lost bucket-create race never reads
48955
+ * as "lease held". */
48936
48956
  async managerLeaseRegistry() {
48937
48957
  if (!this.nc)
48938
48958
  throw new Error("endpoint not started");
48939
48959
  if (this.managerLeaseKv)
48940
48960
  return this.managerLeaseKv;
48941
48961
  const kvm = new import_kv7.Kvm(this.nc);
48942
- try {
48943
- this.managerLeaseKv = await kvm.create(managerBucket(this.space), { ttl: MANAGER_LEASE_TTL_MS });
48944
- } catch {
48962
+ if (this.creds) {
48945
48963
  this.managerLeaseKv = await kvm.open(managerBucket(this.space));
48964
+ } else {
48965
+ try {
48966
+ this.managerLeaseKv = await kvm.create(managerBucket(this.space), { ttl: MANAGER_LEASE_TTL_MS });
48967
+ } catch {
48968
+ this.managerLeaseKv = await kvm.open(managerBucket(this.space));
48969
+ }
48946
48970
  }
48947
48971
  return this.managerLeaseKv;
48948
48972
  }
@@ -50069,6 +50093,8 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
50069
50093
  this.applyPresence(e.key, p);
50070
50094
  }
50071
50095
  applyPresence(id, raw) {
50096
+ if (raw.card?.id !== id)
50097
+ return;
50072
50098
  const prev = this.roster.get(id);
50073
50099
  const stale = Date.now() - raw.ts > this.ttlMs;
50074
50100
  const p = stale || raw.status === "offline" ? this.toOffline(raw) : raw;
@@ -50634,7 +50660,9 @@ var MeshAgent = class extends import_node_events2.EventEmitter {
50634
50660
  * the harness (default the manager's `cotal`/Claude), `opts.model` overrides the
50635
50661
  * persona file's `model:`, and `opts.cwd` roots the new peer at a different folder/repo
50636
50662
  * than the manager's workspace — the same knobs the operator's `cotal start` carries, so
50637
- * the agent and operator spawn doors share one control-op contract. */
50663
+ * the agent and operator spawn doors share one control-op contract. (Session `resume` is
50664
+ * intentionally NOT forwarded here: forking a host-local `~/.claude` transcript is an
50665
+ * operator-local intent, kept off the peer-facing spawn door — see #159.) */
50638
50666
  async spawn(name, role, opts) {
50639
50667
  this.assertConnected();
50640
50668
  return this.ep.requestControl(CONTROL_PRIVILEGED, {
@@ -50896,8 +50924,6 @@ function controlFailure(action, e) {
50896
50924
  function statusGlyph(s) {
50897
50925
  return s === "working" ? "\u25CF" : s === "waiting" ? "\u25D0" : s === "idle" ? "\u25CB" : "\xB7";
50898
50926
  }
50899
- var FACE_TAG_RE = /\[\[\s*face\s*:\s*[\w-]+\s*\]\]\s?/gi;
50900
- var stripFaceTags = (text) => text.replace(FACE_TAG_RE, "");
50901
50927
  var ATTENTION_DESC = {
50902
50928
  open: "open \u2014 you receive everything; untagged channel chatter wakes you when idle",
50903
50929
  dnd: "dnd \u2014 channel chatter no longer wakes you (it still arrives in your next turn); DMs, anycast, and @mentions still wake you",
@@ -51042,7 +51068,7 @@ ${all.map(fmtItem).join("\n")}`);
51042
51068
  },
51043
51069
  async run(agent, _config, { text: msg, channel, mentions }) {
51044
51070
  try {
51045
- const m = await agent.send(stripFaceTags(msg), channel, mentions);
51071
+ const m = await agent.send(msg, channel, mentions);
51046
51072
  return ok(`Sent to #${m.channel}${m.mentions?.length ? ` (mentioned @${m.mentions.join(", @")})` : ""}.`);
51047
51073
  } catch (e) {
51048
51074
  return err(`Couldn't send: ${e.message}`);
@@ -51059,7 +51085,7 @@ ${all.map(fmtItem).join("\n")}`);
51059
51085
  },
51060
51086
  async run(agent, _config, { to, text: msg }) {
51061
51087
  try {
51062
- const { peer } = await agent.dm(to, stripFaceTags(msg));
51088
+ const { peer } = await agent.dm(to, msg);
51063
51089
  return ok(`DM sent to ${peer.card.name}.`);
51064
51090
  } catch (e) {
51065
51091
  if (e instanceof AmbiguousPeerError) {
@@ -51081,7 +51107,7 @@ ${who2}`);
51081
51107
  },
51082
51108
  async run(agent, _config, { role, text: msg }) {
51083
51109
  try {
51084
- await agent.anycast(role, stripFaceTags(msg));
51110
+ await agent.anycast(role, msg);
51085
51111
  return ok(`Sent to one @${role}.`);
51086
51112
  } catch (e) {
51087
51113
  return err(`Couldn't send: ${e.message}`);
@@ -51223,6 +51249,11 @@ ${info}${caught}`);
51223
51249
  agent: external_exports.string().optional().describe("Optional harness the new peer runs on \u2014 the agent/connector type (claude, opencode, hermes), NOT the persona to spawn (that's `name`). Defaults to the manager's default (Claude)."),
51224
51250
  model: external_exports.string().optional().describe("Optional model override (e.g. opus, sonnet) \u2014 wins over the persona file's model:."),
51225
51251
  cwd: external_exports.string().optional().describe("Optional working directory to root the new peer at (e.g. a different repo). A relative path resolves against the manager's workspace; omitted \u2192 it shares the manager's workspace.")
51252
+ // NOTE: session `resume` is deliberately NOT exposed here. Forking a host-local `~/.claude`
51253
+ // transcript is an operator-local intent; letting a spawn-capable mesh PEER name a host
51254
+ // session id would expand `spawn` into host-transcript disclosure with no broker-enforced
51255
+ // boundary. Resume lives only on the operator CLI (`cotal spawn --resume` / `cotal start
51256
+ // --resume`); a peer-facing, capability-gated resume is deferred (see #159).
51226
51257
  },
51227
51258
  async run(agent, _config, { name, role, agent: agentType, model, cwd }) {
51228
51259
  try {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cotal-ai/connector-claude-code",
3
3
  "description": "Cotal connector for Claude Code: an installed plugin that joins a session to the mesh.",
4
- "version": "0.8.3",
4
+ "version": "0.9.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "dependencies": {
21
21
  "@modelcontextprotocol/sdk": "^1.29.0",
22
- "@cotal-ai/connector-core": "0.8.3"
22
+ "@cotal-ai/connector-core": "0.9.0"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "@cotal-ai/core": ">=0.1.0"
@@ -27,7 +27,7 @@
27
27
  "devDependencies": {
28
28
  "esbuild": "^0.28.0",
29
29
  "tsx": "^4.22.4",
30
- "@cotal-ai/core": "0.8.3"
30
+ "@cotal-ai/core": "0.9.0"
31
31
  },
32
32
  "files": [
33
33
  "dist",