@cotal-ai/connector-claude-code 0.8.3 → 0.9.1

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/hook.cjs CHANGED
@@ -16332,18 +16332,20 @@ var SYS_LIMITS = { ...BASE_LIMITS, mem_storage: 0, disk_storage: 0 };
16332
16332
  // ../../packages/core/dist/streams.js
16333
16333
  var import_jetstream = __toESM(require_mod4(), 1);
16334
16334
  var import_transport_node = __toESM(require_transport_node(), 1);
16335
+ var import_kv2 = __toESM(require_mod6(), 1);
16336
+
16337
+ // ../../packages/core/dist/acls.js
16335
16338
  var import_kv = __toESM(require_mod6(), 1);
16339
+
16340
+ // ../../packages/core/dist/streams.js
16336
16341
  var PLANE3_DEDUP_WINDOW_MS = 2 * 60 * 60 * 1e3;
16337
16342
  var MEMBERSHIP_MAX_BYTES = 64 * 1024 * 1024;
16338
16343
 
16339
16344
  // ../../packages/core/dist/channels.js
16340
- var import_kv2 = __toESM(require_mod6(), 1);
16345
+ var import_kv3 = __toESM(require_mod6(), 1);
16341
16346
  var import_transport_node2 = __toESM(require_transport_node(), 1);
16342
16347
 
16343
16348
  // ../../packages/core/dist/members.js
16344
- var import_kv3 = __toESM(require_mod6(), 1);
16345
-
16346
- // ../../packages/core/dist/acls.js
16347
16349
  var import_kv4 = __toESM(require_mod6(), 1);
16348
16350
 
16349
16351
  // ../../packages/core/dist/membership-feed.js
package/dist/mcp.cjs CHANGED
@@ -47533,7 +47533,56 @@ var SYS_LIMITS = { ...BASE_LIMITS, mem_storage: 0, disk_storage: 0 };
47533
47533
  // ../../packages/core/dist/streams.js
47534
47534
  var import_jetstream = __toESM(require_mod4(), 1);
47535
47535
  var import_transport_node = __toESM(require_transport_node(), 1);
47536
+ var import_kv2 = __toESM(require_mod6(), 1);
47537
+
47538
+ // ../../packages/core/dist/acls.js
47536
47539
  var import_kv = __toESM(require_mod6(), 1);
47540
+ async function openAclRegistry(nc, space, opts = {}) {
47541
+ const kvm = new import_kv.Kvm(nc);
47542
+ return opts.create ? kvm.create(aclBucket(space)) : kvm.open(aclBucket(space));
47543
+ }
47544
+ async function readAcl(kv, owner) {
47545
+ const e = await kv.get(aclKey(owner));
47546
+ if (!e || e.operation === "DEL" || e.operation === "PURGE")
47547
+ return void 0;
47548
+ try {
47549
+ const record2 = e.json();
47550
+ if (!Array.isArray(record2.allowSubscribe))
47551
+ return void 0;
47552
+ return { record: record2, revision: e.revision };
47553
+ } catch {
47554
+ return void 0;
47555
+ }
47556
+ }
47557
+ async function commitAcl(kv, owner, allowSubscribe) {
47558
+ const key = aclKey(owner);
47559
+ for (let attempt = 0; attempt < 5; attempt++) {
47560
+ const cur = await readAcl(kv, owner);
47561
+ const next = {
47562
+ allowSubscribe: [...allowSubscribe],
47563
+ revision: (cur?.record.revision ?? 0) + 1,
47564
+ updatedAt: Date.now()
47565
+ };
47566
+ const data = new TextEncoder().encode(JSON.stringify(next));
47567
+ if (!cur) {
47568
+ try {
47569
+ await kv.create(key, data);
47570
+ return next;
47571
+ } catch {
47572
+ continue;
47573
+ }
47574
+ }
47575
+ try {
47576
+ await kv.update(key, data, cur.revision);
47577
+ return next;
47578
+ } catch {
47579
+ continue;
47580
+ }
47581
+ }
47582
+ throw new Error(`acl CAS exhausted retries for ${owner}`);
47583
+ }
47584
+
47585
+ // ../../packages/core/dist/streams.js
47537
47586
  var MAX_MSGS_PER_SUBJECT = 1e3;
47538
47587
  var PLANE3_DEDUP_WINDOW_MS = 2 * 60 * 60 * 1e3;
47539
47588
  var DINBOX_MAX_ACK_PENDING = 1e3;
@@ -47639,7 +47688,7 @@ function fanoutDurableConfig(space, opts = {}) {
47639
47688
  }
47640
47689
 
47641
47690
  // ../../packages/core/dist/channels.js
47642
- var import_kv2 = __toESM(require_mod6(), 1);
47691
+ var import_kv3 = __toESM(require_mod6(), 1);
47643
47692
  var import_transport_node2 = __toESM(require_transport_node(), 1);
47644
47693
  function parseDuration(s) {
47645
47694
  const m = /^(\d+)(s|m|h|d)$/.exec(s.trim());
@@ -47660,7 +47709,7 @@ function effectiveDeliveryClass(cfg, defaults) {
47660
47709
  return cfg?.deliveryClass ?? defaults?.deliveryClass ?? "durable";
47661
47710
  }
47662
47711
  async function openChannelRegistry(nc, space, opts = {}) {
47663
- const kvm = new import_kv2.Kvm(nc);
47712
+ const kvm = new import_kv3.Kvm(nc);
47664
47713
  return opts.create ? kvm.create(channelBucket(space)) : kvm.open(channelBucket(space));
47665
47714
  }
47666
47715
  async function readChannelConfig(kv, channel) {
@@ -47681,7 +47730,7 @@ async function decode3(kv, key) {
47681
47730
  }
47682
47731
 
47683
47732
  // ../../packages/core/dist/members.js
47684
- var import_kv3 = __toESM(require_mod6(), 1);
47733
+ var import_kv4 = __toESM(require_mod6(), 1);
47685
47734
  var StaleMembershipWrite = class extends Error {
47686
47735
  constructor(channel, owner, attempted, current) {
47687
47736
  super(`stale membership write for ${channel}/${owner}: generation ${attempted} < current ${current}`);
@@ -47689,7 +47738,7 @@ var StaleMembershipWrite = class extends Error {
47689
47738
  }
47690
47739
  };
47691
47740
  async function openMembersRegistry(nc, space, opts = {}) {
47692
- const kvm = new import_kv3.Kvm(nc);
47741
+ const kvm = new import_kv4.Kvm(nc);
47693
47742
  return opts.create ? kvm.create(membersBucket(space)) : kvm.open(membersBucket(space));
47694
47743
  }
47695
47744
  async function readMember(kv, channel, owner) {
@@ -47788,53 +47837,6 @@ function durableEligible(rec, seq) {
47788
47837
  return true;
47789
47838
  }
47790
47839
 
47791
- // ../../packages/core/dist/acls.js
47792
- var import_kv4 = __toESM(require_mod6(), 1);
47793
- async function openAclRegistry(nc, space, opts = {}) {
47794
- const kvm = new import_kv4.Kvm(nc);
47795
- return opts.create ? kvm.create(aclBucket(space)) : kvm.open(aclBucket(space));
47796
- }
47797
- async function readAcl(kv, owner) {
47798
- const e = await kv.get(aclKey(owner));
47799
- if (!e || e.operation === "DEL" || e.operation === "PURGE")
47800
- return void 0;
47801
- try {
47802
- const record2 = e.json();
47803
- if (!Array.isArray(record2.allowSubscribe))
47804
- return void 0;
47805
- return { record: record2, revision: e.revision };
47806
- } catch {
47807
- return void 0;
47808
- }
47809
- }
47810
- async function commitAcl(kv, owner, allowSubscribe) {
47811
- const key = aclKey(owner);
47812
- for (let attempt = 0; attempt < 5; attempt++) {
47813
- const cur = await readAcl(kv, owner);
47814
- const next = {
47815
- allowSubscribe: [...allowSubscribe],
47816
- revision: (cur?.record.revision ?? 0) + 1,
47817
- updatedAt: Date.now()
47818
- };
47819
- const data = new TextEncoder().encode(JSON.stringify(next));
47820
- if (!cur) {
47821
- try {
47822
- await kv.create(key, data);
47823
- return next;
47824
- } catch {
47825
- continue;
47826
- }
47827
- }
47828
- try {
47829
- await kv.update(key, data, cur.revision);
47830
- return next;
47831
- } catch {
47832
- continue;
47833
- }
47834
- }
47835
- throw new Error(`acl CAS exhausted retries for ${owner}`);
47836
- }
47837
-
47838
47840
  // ../../packages/core/dist/membership-feed.js
47839
47841
  var import_transport_node3 = __toESM(require_transport_node(), 1);
47840
47842
  var import_kv5 = __toESM(require_mod6(), 1);
@@ -47983,6 +47985,7 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
47983
47985
  ttlMs;
47984
47986
  doRegister;
47985
47987
  doWatch;
47988
+ doWatchChannels;
47986
47989
  doConsume;
47987
47990
  ackWaitMs;
47988
47991
  inactiveThresholdMs;
@@ -48098,6 +48101,7 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
48098
48101
  this.ttlMs = opts.ttlMs ?? 6e3;
48099
48102
  this.doRegister = opts.registerPresence ?? true;
48100
48103
  this.doWatch = opts.watchPresence ?? true;
48104
+ this.doWatchChannels = opts.watchChannels ?? true;
48101
48105
  this.doConsume = opts.consume ?? true;
48102
48106
  this.channelModes = opts.channelModes && Object.keys(opts.channelModes).length ? opts.channelModes : void 0;
48103
48107
  this.ackWaitMs = opts.ackWaitMs ?? 6e4;
@@ -48137,9 +48141,10 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
48137
48141
  await this.startPresenceWatch();
48138
48142
  this.sweepTimer = setInterval(() => this.sweep(), Math.max(500, Math.floor(this.ttlMs / 3)));
48139
48143
  }
48140
- if (this.doWatch || this.doConsume) {
48144
+ const watchChannels = this.doWatch && this.doWatchChannels;
48145
+ if (watchChannels || this.doConsume) {
48141
48146
  this.channelKv = await openChannelRegistry(this.nc, this.space, { create: !this.creds });
48142
- if (this.doWatch)
48147
+ if (watchChannels)
48143
48148
  await this.startChannelWatch();
48144
48149
  }
48145
48150
  if (this.doRegister) {
@@ -48430,8 +48435,10 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
48430
48435
  * PEER's reply lane (`ctl.delivery.<victim>.reply.<n>`) and turn the responder into a confused
48431
48436
  * deputy — the broker does NOT permission-check the requester's embedded reply subject. With it, a
48432
48437
  * 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.) */
48438
+ * (`${m.subject}.reply.…`), binding the reply to the broker-policed sender token. The manager's three
48439
+ * lifecycle tiers ALSO require it as of closure (i): they reply on bounded `ctl.<tier>.<caller>.reply.…`
48440
+ * (the manager cred holds the wildcard `ctl.<tier>.*.reply.>` pub — exactly the confused-deputy
48441
+ * condition above), so do NOT drop `boundReply` on them. */
48435
48442
  serveControl(service, handler, opts = {}) {
48436
48443
  if (!this.nc)
48437
48444
  throw new Error("endpoint not started");
@@ -48466,12 +48473,25 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
48466
48473
  })().catch((e) => this.emit("error", e));
48467
48474
  return sub;
48468
48475
  }
48469
- /** Send a control request to a service and await its reply (client side). */
48476
+ /** Send a control request to a service and await its reply (client side). Like {@link requestDelivery},
48477
+ * the reply rides a BOUNDED subject UNDER the request subject (`ctl.<service>.<id>.reply.<uuid>`), not
48478
+ * the per-id `_INBOX` — closure (i): this frees the manager's permission set from needing a position-1
48479
+ * inbox wildcard, so its publish surface can be an exact self-scoped allow-list (no message forging).
48480
+ * `noMux` lets us name the reply subject while keeping NoResponders detection. The random suffix is
48481
+ * defense-in-depth (a predictable suffix would let a peer target an in-flight named reply sub). The
48482
+ * reply sits under the sender's OWN request subject, so the responder's `boundReply` guard accepts it.
48483
+ *
48484
+ * CUTOVER (not backward-compatible): an agent cred minted BEFORE closure (i) lacks the
48485
+ * `ctl.<tier>.<id>.reply.>` sub grant — it can still publish the request but cannot subscribe the
48486
+ * reply, so its control calls (spawn/despawn/purge/definePersona, self-stop) hang. The per-user-auth
48487
+ * atomic cutover re-mints every agent; if this change ships ahead of that, agents must be RESPAWNED. */
48470
48488
  async requestControl(service, req, timeoutMs = 5e3) {
48471
48489
  if (!this.nc)
48472
48490
  throw new Error(this.notLiveMsg());
48491
+ const reqSubject = controlServiceSubject(this.space, service, this.card.id);
48492
+ const reply = `${reqSubject}.reply.${(0, import_node_crypto.randomUUID)()}`;
48473
48493
  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 });
48494
+ const m = await this.nc.request(reqSubject, JSON.stringify(body), { timeout: timeoutMs, noMux: true, reply });
48475
48495
  return m.json();
48476
48496
  }
48477
48497
  /** Send a durable-membership request to the SERVER-SIDE delivery daemon (`ctl.delivery`) and await its
@@ -48926,23 +48946,29 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
48926
48946
  return void 0;
48927
48947
  }
48928
48948
  }
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. */
48949
+ /** Ensure + bind the manager singleton-lease bucket. Mirrors the presence-bucket pattern (connectAndBind):
48950
+ * AUTH mode OPENs the bucket pre-created at `cotal up` (the scoped `supervisor` cred holds no
48951
+ * STREAM.CREATE and `open` binds direct=false, so the CAS-conflict `kv.get` inside `acquire` rides
48952
+ * STREAM.MSG.GET, the verb the supervisor grants, never DIRECT.GET). OPEN mode (no creds) create-firsts:
48953
+ * `Kvm.open` binds LAZILY it does NOT verify the stream exists or throw when it's missing (a fresh
48954
+ * bucket then fails 'stream not found' on the first write), so `create` is the ensure-exists call (it
48955
+ * makes the bucket or, when another endpoint already did, throws and we bind the existing one). Either
48956
+ * way the per-KEY CAS create stays the only single-flight gate, so a lost bucket-create race never reads
48957
+ * as "lease held". */
48936
48958
  async managerLeaseRegistry() {
48937
48959
  if (!this.nc)
48938
48960
  throw new Error("endpoint not started");
48939
48961
  if (this.managerLeaseKv)
48940
48962
  return this.managerLeaseKv;
48941
48963
  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 {
48964
+ if (this.creds) {
48945
48965
  this.managerLeaseKv = await kvm.open(managerBucket(this.space));
48966
+ } else {
48967
+ try {
48968
+ this.managerLeaseKv = await kvm.create(managerBucket(this.space), { ttl: MANAGER_LEASE_TTL_MS });
48969
+ } catch {
48970
+ this.managerLeaseKv = await kvm.open(managerBucket(this.space));
48971
+ }
48946
48972
  }
48947
48973
  return this.managerLeaseKv;
48948
48974
  }
@@ -50069,6 +50095,8 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
50069
50095
  this.applyPresence(e.key, p);
50070
50096
  }
50071
50097
  applyPresence(id, raw) {
50098
+ if (raw.card?.id !== id)
50099
+ return;
50072
50100
  const prev = this.roster.get(id);
50073
50101
  const stale = Date.now() - raw.ts > this.ttlMs;
50074
50102
  const p = stale || raw.status === "offline" ? this.toOffline(raw) : raw;
@@ -50634,7 +50662,9 @@ var MeshAgent = class extends import_node_events2.EventEmitter {
50634
50662
  * the harness (default the manager's `cotal`/Claude), `opts.model` overrides the
50635
50663
  * persona file's `model:`, and `opts.cwd` roots the new peer at a different folder/repo
50636
50664
  * 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. */
50665
+ * the agent and operator spawn doors share one control-op contract. (Session `resume` is
50666
+ * intentionally NOT forwarded here: forking a host-local `~/.claude` transcript is an
50667
+ * operator-local intent, kept off the peer-facing spawn door — see #159.) */
50638
50668
  async spawn(name, role, opts) {
50639
50669
  this.assertConnected();
50640
50670
  return this.ep.requestControl(CONTROL_PRIVILEGED, {
@@ -50896,8 +50926,6 @@ function controlFailure(action, e) {
50896
50926
  function statusGlyph(s) {
50897
50927
  return s === "working" ? "\u25CF" : s === "waiting" ? "\u25D0" : s === "idle" ? "\u25CB" : "\xB7";
50898
50928
  }
50899
- var FACE_TAG_RE = /\[\[\s*face\s*:\s*[\w-]+\s*\]\]\s?/gi;
50900
- var stripFaceTags = (text) => text.replace(FACE_TAG_RE, "");
50901
50929
  var ATTENTION_DESC = {
50902
50930
  open: "open \u2014 you receive everything; untagged channel chatter wakes you when idle",
50903
50931
  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 +51070,7 @@ ${all.map(fmtItem).join("\n")}`);
51042
51070
  },
51043
51071
  async run(agent, _config, { text: msg, channel, mentions }) {
51044
51072
  try {
51045
- const m = await agent.send(stripFaceTags(msg), channel, mentions);
51073
+ const m = await agent.send(msg, channel, mentions);
51046
51074
  return ok(`Sent to #${m.channel}${m.mentions?.length ? ` (mentioned @${m.mentions.join(", @")})` : ""}.`);
51047
51075
  } catch (e) {
51048
51076
  return err(`Couldn't send: ${e.message}`);
@@ -51059,7 +51087,7 @@ ${all.map(fmtItem).join("\n")}`);
51059
51087
  },
51060
51088
  async run(agent, _config, { to, text: msg }) {
51061
51089
  try {
51062
- const { peer } = await agent.dm(to, stripFaceTags(msg));
51090
+ const { peer } = await agent.dm(to, msg);
51063
51091
  return ok(`DM sent to ${peer.card.name}.`);
51064
51092
  } catch (e) {
51065
51093
  if (e instanceof AmbiguousPeerError) {
@@ -51081,7 +51109,7 @@ ${who2}`);
51081
51109
  },
51082
51110
  async run(agent, _config, { role, text: msg }) {
51083
51111
  try {
51084
- await agent.anycast(role, stripFaceTags(msg));
51112
+ await agent.anycast(role, msg);
51085
51113
  return ok(`Sent to one @${role}.`);
51086
51114
  } catch (e) {
51087
51115
  return err(`Couldn't send: ${e.message}`);
@@ -51223,6 +51251,11 @@ ${info}${caught}`);
51223
51251
  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
51252
  model: external_exports.string().optional().describe("Optional model override (e.g. opus, sonnet) \u2014 wins over the persona file's model:."),
51225
51253
  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.")
51254
+ // NOTE: session `resume` is deliberately NOT exposed here. Forking a host-local `~/.claude`
51255
+ // transcript is an operator-local intent; letting a spawn-capable mesh PEER name a host
51256
+ // session id would expand `spawn` into host-transcript disclosure with no broker-enforced
51257
+ // boundary. Resume lives only on the operator CLI (`cotal spawn --resume` / `cotal start
51258
+ // --resume`); a peer-facing, capability-gated resume is deferred (see #159).
51226
51259
  },
51227
51260
  async run(agent, _config, { name, role, agent: agentType, model, cwd }) {
51228
51261
  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.1",
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.1"
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.1"
31
31
  },
32
32
  "files": [
33
33
  "dist",