@cotal-ai/connector-claude-code 0.8.0 → 0.8.2
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/dist/extension.d.ts.map +1 -1
- package/dist/extension.js +13 -4
- package/dist/extension.js.map +1 -1
- package/dist/hook.cjs +15 -272
- package/dist/mcp.cjs +159 -40
- package/dist/mcp.js +29 -18
- package/dist/mcp.js.map +1 -1
- package/package.json +3 -3
package/dist/extension.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"AAIA,OAAO,
|
|
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,SAyG7B,CAAC"}
|
package/dist/extension.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { mkdtempSync
|
|
1
|
+
import { mkdtempSync } from "node:fs";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { loadAgentFile, registry } from "@cotal-ai/core";
|
|
6
|
-
import { aclEnv, launchEnv, mcpServerEnvKeys } from "@cotal-ai/connector-core";
|
|
5
|
+
import { hardenPrivate, loadAgentFile, registry, writeSecretFile } from "@cotal-ai/core";
|
|
6
|
+
import { aclEnv, controlEndpoint, launchEnv, mcpServerEnvKeys } from "@cotal-ai/connector-core";
|
|
7
7
|
/** Name the cotal MCP server is registered under via --mcp-config (see buildLaunch). */
|
|
8
8
|
const MCP_SERVER_NAME = "cotal";
|
|
9
9
|
/** Channel ref for `--dangerously-load-development-channels`, which turns on the cotal MCP server's
|
|
@@ -37,6 +37,11 @@ export const claudeConnector = {
|
|
|
37
37
|
// The OS allow-list (PATH/HOME/TERM/…) is the only thing inherited from the manager env, plus
|
|
38
38
|
// — only when a shared server declares them via `${VAR}` — the named secrets it needs (mcpKeys,
|
|
39
39
|
// by name). The operator's unrelated secrets don't reach the child (P3).
|
|
40
|
+
// The session's local control endpoint: the in-process MCP server LISTENS on it (auth), and the
|
|
41
|
+
// lifecycle hooks (child processes of `claude`, which inherit this env) CONNECT to it. Both read
|
|
42
|
+
// path+token from the env — never recomputed from public identity — and the manager keeps the
|
|
43
|
+
// pair (returned as `control` below) to drive a cooperative shutdown on Windows.
|
|
44
|
+
const control = controlEndpoint(opts.space, opts.name);
|
|
40
45
|
const env = {
|
|
41
46
|
...launchEnv({ mcpKeys: mcpServerEnvKeys(shared) }),
|
|
42
47
|
...aclEnv(opts),
|
|
@@ -45,6 +50,8 @@ export const claudeConnector = {
|
|
|
45
50
|
// Force the connector to emit channel wake-nudges: Claude doesn't advertise the
|
|
46
51
|
// `claude/channel` capability back over MCP, so auto-detection would see it "off".
|
|
47
52
|
COTAL_CHANNEL: "1",
|
|
53
|
+
COTAL_CONTROL_SOCKET: control.path,
|
|
54
|
+
COTAL_CONTROL_TOKEN: control.token, // env only — never argv/logs/persisted (token hygiene)
|
|
48
55
|
};
|
|
49
56
|
// A session can mirror its own transcript to `tr-<name>` so peers can read what the
|
|
50
57
|
// agent actually did — OFF by default (transcripts are verbose and may carry sensitive
|
|
@@ -97,8 +104,9 @@ export const claudeConnector = {
|
|
|
97
104
|
// overwrite). Left for the OS to reap: the file must outlive this call (Claude reads it at
|
|
98
105
|
// startup and on /mcp reconnect), and buildLaunch doesn't own the child's lifecycle.
|
|
99
106
|
const dir = mkdtempSync(join(tmpdir(), "cotal-mcp-"));
|
|
107
|
+
hardenPrivate(dir, "dir"); // win32: mkdtemp's 0700 is a no-op — harden the ACL before the config lands
|
|
100
108
|
mcpConfig = join(dir, "mcp.json");
|
|
101
|
-
|
|
109
|
+
writeSecretFile(mcpConfig, JSON.stringify({ mcpServers }, null, 2));
|
|
102
110
|
}
|
|
103
111
|
args.push("--strict-mcp-config", "--mcp-config", mcpConfig);
|
|
104
112
|
// An agent file carries identity (read in-session via COTAL_AGENT_FILE) plus
|
|
@@ -122,6 +130,7 @@ export const claudeConnector = {
|
|
|
122
130
|
// The dev-channels flag shows a one-time "Enter to confirm" prompt; the
|
|
123
131
|
// manager auto-clears it so a supervised launch needs no human keypress.
|
|
124
132
|
confirm: "Enter to confirm",
|
|
133
|
+
control,
|
|
125
134
|
};
|
|
126
135
|
},
|
|
127
136
|
};
|
package/dist/extension.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"}
|
package/dist/hook.cjs
CHANGED
|
@@ -14704,87 +14704,6 @@ var require_mod6 = __commonJS({
|
|
|
14704
14704
|
}
|
|
14705
14705
|
});
|
|
14706
14706
|
|
|
14707
|
-
// ../connector-core/dist/config.js
|
|
14708
|
-
var import_node_os = require("node:os");
|
|
14709
|
-
var import_node_fs2 = require("node:fs");
|
|
14710
|
-
|
|
14711
|
-
// ../../packages/core/dist/subjects.js
|
|
14712
|
-
function isConcreteChannel(channel) {
|
|
14713
|
-
return !channel.split(".").some((s) => s.trim() === "*" || s.trim() === ">");
|
|
14714
|
-
}
|
|
14715
|
-
function subjectMatches(pattern, subject) {
|
|
14716
|
-
const p = pattern.split(".");
|
|
14717
|
-
const s = subject.split(".");
|
|
14718
|
-
for (let i = 0; i < p.length; i++) {
|
|
14719
|
-
if (p[i] === ">")
|
|
14720
|
-
return i < s.length;
|
|
14721
|
-
if (i >= s.length)
|
|
14722
|
-
return false;
|
|
14723
|
-
if (p[i] === "*")
|
|
14724
|
-
continue;
|
|
14725
|
-
if (p[i] !== s[i])
|
|
14726
|
-
return false;
|
|
14727
|
-
}
|
|
14728
|
-
return p.length === s.length;
|
|
14729
|
-
}
|
|
14730
|
-
function assertValidChannel(channel) {
|
|
14731
|
-
const segs = channel.split(".");
|
|
14732
|
-
if (!channel.length || segs.some((s) => s.length === 0))
|
|
14733
|
-
throw new Error(`invalid channel "${channel}": empty segment (no leading/trailing/double dots)`);
|
|
14734
|
-
segs.forEach((s, i) => {
|
|
14735
|
-
if (s === ">") {
|
|
14736
|
-
if (i !== segs.length - 1)
|
|
14737
|
-
throw new Error(`invalid channel "${channel}": '>' is only valid as the last segment`);
|
|
14738
|
-
return;
|
|
14739
|
-
}
|
|
14740
|
-
if (s === "*")
|
|
14741
|
-
return;
|
|
14742
|
-
if (!/^[A-Za-z0-9_-]+$/.test(s))
|
|
14743
|
-
throw new Error(`invalid channel "${channel}": segment "${s}" must be a NATS-safe token ([A-Za-z0-9_-]), '*', or '>' \u2014 policy channel names can't contain characters the wire layer would rewrite`);
|
|
14744
|
-
});
|
|
14745
|
-
return channel;
|
|
14746
|
-
}
|
|
14747
|
-
function channelInAllow(allow, channel) {
|
|
14748
|
-
return allow.some((a) => subjectMatches(a, channel));
|
|
14749
|
-
}
|
|
14750
|
-
|
|
14751
|
-
// ../../packages/core/dist/resolve.js
|
|
14752
|
-
function assertValidName(name) {
|
|
14753
|
-
if (name.length === 0 || name !== name.trim())
|
|
14754
|
-
throw new Error(`invalid name ${JSON.stringify(name)}: must be non-empty with no surrounding whitespace`);
|
|
14755
|
-
if (/[\r\n]/.test(name))
|
|
14756
|
-
throw new Error(`invalid name ${JSON.stringify(name)}: must be a single line`);
|
|
14757
|
-
if (name.includes("/"))
|
|
14758
|
-
throw new Error(`invalid name ${JSON.stringify(name)}: "/" is reserved (the owner/name separator)`);
|
|
14759
|
-
}
|
|
14760
|
-
|
|
14761
|
-
// ../../packages/core/dist/link.js
|
|
14762
|
-
function parseJoinLink(link) {
|
|
14763
|
-
const tls = link.startsWith("cotals://");
|
|
14764
|
-
if (!tls && !link.startsWith("cotal://"))
|
|
14765
|
-
throw new Error(`not a Cotal link (expected cotal:// or cotals://): ${link}`);
|
|
14766
|
-
const u = new URL(link.replace(/^cotals?:\/\//, tls ? "https://" : "http://"));
|
|
14767
|
-
if (!u.hostname)
|
|
14768
|
-
throw new Error(`Cotal link has no host: ${link}`);
|
|
14769
|
-
const space = decodeURIComponent(u.pathname.replace(/^\/+/, "").split("/")[0] ?? "");
|
|
14770
|
-
if (!space)
|
|
14771
|
-
throw new Error(`Cotal link has no space (cotal://host/<space>): ${link}`);
|
|
14772
|
-
const chParam = u.searchParams.get("channels") ?? u.searchParams.get("channel");
|
|
14773
|
-
const channels = chParam ? chParam.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
|
|
14774
|
-
const user = u.username ? decodeURIComponent(u.username) : void 0;
|
|
14775
|
-
const pass = u.password ? decodeURIComponent(u.password) : void 0;
|
|
14776
|
-
return {
|
|
14777
|
-
servers: `nats://${u.hostname}:${u.port || "4222"}`,
|
|
14778
|
-
space,
|
|
14779
|
-
channels,
|
|
14780
|
-
tls,
|
|
14781
|
-
// userinfo with no ':' is a bare token; with ':' it's user/password.
|
|
14782
|
-
token: user && !pass ? user : void 0,
|
|
14783
|
-
user: pass ? user : void 0,
|
|
14784
|
-
pass: pass || void 0
|
|
14785
|
-
};
|
|
14786
|
-
}
|
|
14787
|
-
|
|
14788
14707
|
// ../../packages/core/dist/identity.js
|
|
14789
14708
|
var import_nkeys = __toESM(require_mod(), 1);
|
|
14790
14709
|
|
|
@@ -16435,123 +16354,13 @@ var import_kv5 = __toESM(require_mod6(), 1);
|
|
|
16435
16354
|
var import_kv6 = __toESM(require_mod6(), 1);
|
|
16436
16355
|
var import_transport_node4 = __toESM(require_transport_node(), 1);
|
|
16437
16356
|
|
|
16438
|
-
// ../../packages/core/dist/
|
|
16439
|
-
var
|
|
16440
|
-
function unquote(v) {
|
|
16441
|
-
if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'"))
|
|
16442
|
-
return v.slice(1, -1);
|
|
16443
|
-
return v;
|
|
16444
|
-
}
|
|
16445
|
-
function parseFrontmatter(src) {
|
|
16446
|
-
const out = {};
|
|
16447
|
-
for (const raw of src.split("\n")) {
|
|
16448
|
-
const line = raw.trim();
|
|
16449
|
-
if (!line || line.startsWith("#"))
|
|
16450
|
-
continue;
|
|
16451
|
-
const colon = line.indexOf(":");
|
|
16452
|
-
if (colon < 1)
|
|
16453
|
-
throw new Error(`agent file: unparseable frontmatter line "${raw}"`);
|
|
16454
|
-
const key = line.slice(0, colon).trim();
|
|
16455
|
-
const val = line.slice(colon + 1).trim();
|
|
16456
|
-
if (val.startsWith("[")) {
|
|
16457
|
-
if (!val.endsWith("]"))
|
|
16458
|
-
throw new Error(`agent file: unterminated list for "${key}"`);
|
|
16459
|
-
out[key] = val.slice(1, -1).split(",").map((s) => unquote(s.trim())).filter(Boolean);
|
|
16460
|
-
} else {
|
|
16461
|
-
out[key] = unquote(val);
|
|
16462
|
-
}
|
|
16463
|
-
}
|
|
16464
|
-
return out;
|
|
16465
|
-
}
|
|
16466
|
-
function loadAgentFile(path) {
|
|
16467
|
-
const src = (0, import_node_fs.readFileSync)(path, "utf8");
|
|
16468
|
-
const m = /^---\n([\s\S]*?)\n---\n?([\s\S]*)$/.exec(src);
|
|
16469
|
-
if (!m)
|
|
16470
|
-
throw new Error(`agent file ${path}: missing "---" frontmatter block`);
|
|
16471
|
-
const fm = parseFrontmatter(m[1]);
|
|
16472
|
-
const persona = m[2].trim();
|
|
16473
|
-
const str = (k) => {
|
|
16474
|
-
const v = fm[k];
|
|
16475
|
-
if (Array.isArray(v))
|
|
16476
|
-
throw new Error(`agent file ${path}: "${k}" must be a scalar`);
|
|
16477
|
-
return v;
|
|
16478
|
-
};
|
|
16479
|
-
const list = (k) => {
|
|
16480
|
-
const v = fm[k];
|
|
16481
|
-
if (v === void 0)
|
|
16482
|
-
return void 0;
|
|
16483
|
-
return Array.isArray(v) ? v : [v];
|
|
16484
|
-
};
|
|
16485
|
-
const name = str("name");
|
|
16486
|
-
if (!name)
|
|
16487
|
-
throw new Error(`agent file ${path}: "name" is required`);
|
|
16488
|
-
assertValidName(name);
|
|
16489
|
-
const kind = str("kind");
|
|
16490
|
-
if (kind && kind !== "agent" && kind !== "endpoint")
|
|
16491
|
-
throw new Error(`agent file ${path}: "kind" must be "agent" or "endpoint"`);
|
|
16492
|
-
for (const old of ["channels", "publish"])
|
|
16493
|
-
if (old in fm)
|
|
16494
|
-
throw new Error(`agent file ${path}: "${old}" was renamed \u2014 use "subscribe"/"allowSubscribe" (read) and "allowPublish" (post)`);
|
|
16495
|
-
const subscribe = list("subscribe");
|
|
16496
|
-
const allowSubscribe = list("allowSubscribe");
|
|
16497
|
-
const allowPublish = list("allowPublish");
|
|
16498
|
-
const quiet = list("quiet");
|
|
16499
|
-
const muted = list("muted");
|
|
16500
|
-
for (const ch of [...subscribe ?? [], ...allowSubscribe ?? [], ...allowPublish ?? []])
|
|
16501
|
-
try {
|
|
16502
|
-
assertValidChannel(ch);
|
|
16503
|
-
} catch (e) {
|
|
16504
|
-
throw new Error(`agent file ${path}: ${e.message}`);
|
|
16505
|
-
}
|
|
16506
|
-
const effSubscribe = subscribe?.length ? subscribe : ["general"];
|
|
16507
|
-
const effAllow = allowSubscribe?.length ? allowSubscribe : effSubscribe;
|
|
16508
|
-
for (const ch of effSubscribe)
|
|
16509
|
-
if (!channelInAllow(effAllow, ch))
|
|
16510
|
-
throw new Error(`agent file ${path}: subscribe channel "${ch}" is not within allowSubscribe [${effAllow.join(", ")}]`);
|
|
16511
|
-
const both = (quiet ?? []).filter((c) => (muted ?? []).includes(c));
|
|
16512
|
-
if (both.length)
|
|
16513
|
-
throw new Error(`agent file ${path}: channel(s) [${both.join(", ")}] are in both quiet and muted \u2014 pick one`);
|
|
16514
|
-
for (const [field, chans] of [["quiet", quiet], ["muted", muted]])
|
|
16515
|
-
for (const ch of chans ?? []) {
|
|
16516
|
-
try {
|
|
16517
|
-
assertValidChannel(ch);
|
|
16518
|
-
} catch (e) {
|
|
16519
|
-
throw new Error(`agent file ${path}: ${e.message}`);
|
|
16520
|
-
}
|
|
16521
|
-
if (!isConcreteChannel(ch))
|
|
16522
|
-
throw new Error(`agent file ${path}: ${field} channel "${ch}" must be a concrete channel (no wildcard)`);
|
|
16523
|
-
if (!channelInAllow(effAllow, ch))
|
|
16524
|
-
throw new Error(`agent file ${path}: ${field} channel "${ch}" is not within your read ACL / allowSubscribe [${effAllow.join(", ")}]`);
|
|
16525
|
-
}
|
|
16526
|
-
const known = /* @__PURE__ */ new Set(["name", "role", "kind", "description", "tags", "subscribe", "allowSubscribe", "allowPublish", "quiet", "muted", "model", "capabilities", "owner"]);
|
|
16527
|
-
const meta = {};
|
|
16528
|
-
for (const [k, v] of Object.entries(fm))
|
|
16529
|
-
if (!known.has(k) && typeof v === "string")
|
|
16530
|
-
meta[k] = v;
|
|
16531
|
-
return {
|
|
16532
|
-
name,
|
|
16533
|
-
role: str("role"),
|
|
16534
|
-
kind,
|
|
16535
|
-
description: str("description"),
|
|
16536
|
-
tags: list("tags"),
|
|
16537
|
-
subscribe,
|
|
16538
|
-
allowSubscribe,
|
|
16539
|
-
allowPublish,
|
|
16540
|
-
quiet,
|
|
16541
|
-
muted,
|
|
16542
|
-
model: str("model"),
|
|
16543
|
-
capabilities: list("capabilities"),
|
|
16544
|
-
owner: str("owner"),
|
|
16545
|
-
meta: Object.keys(meta).length ? meta : void 0,
|
|
16546
|
-
persona: persona || void 0
|
|
16547
|
-
};
|
|
16548
|
-
}
|
|
16357
|
+
// ../../packages/core/dist/secret-fs.js
|
|
16358
|
+
var isWin = process.platform === "win32";
|
|
16549
16359
|
|
|
16550
16360
|
// ../../packages/core/dist/endpoint.js
|
|
16551
16361
|
var import_transport_node5 = __toESM(require_transport_node(), 1);
|
|
16552
16362
|
var import_jetstream2 = __toESM(require_mod4(), 1);
|
|
16553
16363
|
var import_kv7 = __toESM(require_mod6(), 1);
|
|
16554
|
-
var DEFAULT_SERVER = "nats://127.0.0.1:4222";
|
|
16555
16364
|
|
|
16556
16365
|
// ../../packages/core/dist/spaces.js
|
|
16557
16366
|
var import_transport_node6 = __toESM(require_transport_node(), 1);
|
|
@@ -16585,86 +16394,12 @@ var Registry = class {
|
|
|
16585
16394
|
var registry = new Registry();
|
|
16586
16395
|
|
|
16587
16396
|
// ../connector-core/dist/config.js
|
|
16588
|
-
function splitList(v) {
|
|
16589
|
-
if (!v)
|
|
16590
|
-
return [];
|
|
16591
|
-
return v.split(",").map((s) => s.trim()).filter(Boolean);
|
|
16592
|
-
}
|
|
16593
16397
|
function hasIdentity(env = process.env) {
|
|
16594
16398
|
return Boolean(env.COTAL_NAME?.trim() || env.COTAL_LINK?.trim() || env.COTAL_AGENT_FILE?.trim());
|
|
16595
16399
|
}
|
|
16596
|
-
function configFromEnv(env = process.env) {
|
|
16597
|
-
const link = env.COTAL_LINK?.trim() ? parseJoinLink(env.COTAL_LINK.trim()) : void 0;
|
|
16598
|
-
const def = env.COTAL_AGENT_FILE?.trim() ? loadAgentFile(env.COTAL_AGENT_FILE.trim()) : void 0;
|
|
16599
|
-
const name = env.COTAL_NAME?.trim() || def?.name || (link ? (0, import_node_os.userInfo)().username : void 0);
|
|
16600
|
-
if (!name)
|
|
16601
|
-
throw new Error("COTAL_NAME, COTAL_AGENT_FILE or COTAL_LINK is required \u2014 a Cotal session needs an explicit identity from its launcher");
|
|
16602
|
-
const subscribe = splitList(env.COTAL_SUBSCRIBE);
|
|
16603
|
-
const resolvedSubscribe = subscribe.length ? subscribe : def?.subscribe ?? link?.channels ?? ["general"];
|
|
16604
|
-
const allowSub = splitList(env.COTAL_ALLOW_SUBSCRIBE);
|
|
16605
|
-
const resolvedAllowSub = allowSub.length ? allowSub : def?.allowSubscribe ?? resolvedSubscribe;
|
|
16606
|
-
for (const ch of resolvedSubscribe)
|
|
16607
|
-
if (!channelInAllow(resolvedAllowSub, ch))
|
|
16608
|
-
throw new Error(`COTAL config: subscribe channel "${ch}" is not within allowSubscribe [${resolvedAllowSub.join(", ")}]`);
|
|
16609
|
-
const allowPub = splitList(env.COTAL_ALLOW_PUBLISH);
|
|
16610
|
-
const resolvedAllowPub = allowPub.length ? allowPub : def?.allowPublish ?? [];
|
|
16611
|
-
for (const ch of [...resolvedSubscribe, ...resolvedAllowSub, ...resolvedAllowPub])
|
|
16612
|
-
assertValidChannel(ch);
|
|
16613
|
-
const qEnv = splitList(env.COTAL_QUIET), mEnv = splitList(env.COTAL_MUTED);
|
|
16614
|
-
const resolvedQuiet = qEnv.length ? qEnv : def?.quiet ?? [];
|
|
16615
|
-
const resolvedMuted = mEnv.length ? mEnv : def?.muted ?? [];
|
|
16616
|
-
const bothModes = resolvedQuiet.filter((c) => resolvedMuted.includes(c));
|
|
16617
|
-
if (bothModes.length)
|
|
16618
|
-
throw new Error(`COTAL config: channel(s) [${bothModes.join(", ")}] are in both quiet and muted`);
|
|
16619
|
-
for (const [field, chans] of [["quiet", resolvedQuiet], ["muted", resolvedMuted]])
|
|
16620
|
-
for (const ch of chans) {
|
|
16621
|
-
assertValidChannel(ch);
|
|
16622
|
-
if (!isConcreteChannel(ch))
|
|
16623
|
-
throw new Error(`COTAL config: ${field} channel "${ch}" must be concrete (no wildcard)`);
|
|
16624
|
-
if (!channelInAllow(resolvedAllowSub, ch))
|
|
16625
|
-
throw new Error(`COTAL config: ${field} channel "${ch}" is not within allowSubscribe [${resolvedAllowSub.join(", ")}]`);
|
|
16626
|
-
}
|
|
16627
|
-
const credsPath = env.COTAL_CREDS?.trim();
|
|
16628
|
-
return {
|
|
16629
|
-
space: env.COTAL_SPACE?.trim() || link?.space || "demo",
|
|
16630
|
-
id: env.COTAL_ID?.trim() || void 0,
|
|
16631
|
-
creds: credsPath ? (0, import_node_fs2.readFileSync)(credsPath, "utf8") : void 0,
|
|
16632
|
-
name,
|
|
16633
|
-
role: env.COTAL_ROLE?.trim() || def?.role || void 0,
|
|
16634
|
-
description: def?.description,
|
|
16635
|
-
tags: def?.tags,
|
|
16636
|
-
meta: def?.meta,
|
|
16637
|
-
capabilities: def?.capabilities,
|
|
16638
|
-
model: env.COTAL_MODEL?.trim() || def?.model || void 0,
|
|
16639
|
-
servers: env.COTAL_SERVERS?.trim() || link?.servers || DEFAULT_SERVER,
|
|
16640
|
-
subscribe: resolvedSubscribe,
|
|
16641
|
-
allowSubscribe: resolvedAllowSub,
|
|
16642
|
-
// Post ACL is default-DENY: only what's explicitly declared (env > agent-file). The broker
|
|
16643
|
-
// enforces it under auth; in open mode posting is unrestricted regardless.
|
|
16644
|
-
allowPublish: resolvedAllowPub,
|
|
16645
|
-
quiet: resolvedQuiet,
|
|
16646
|
-
muted: resolvedMuted,
|
|
16647
|
-
kind: env.COTAL_KIND?.trim() || def?.kind || "agent",
|
|
16648
|
-
token: env.COTAL_TOKEN?.trim() || link?.token,
|
|
16649
|
-
user: link?.user,
|
|
16650
|
-
pass: link?.pass,
|
|
16651
|
-
tls: env.COTAL_TLS?.trim() === "1" || link?.tls || false,
|
|
16652
|
-
feedbackKey: env.COTAL_FEEDBACK_KEY?.trim() || void 0,
|
|
16653
|
-
feedbackUrl: env.COTAL_FEEDBACK_URL?.trim() || void 0
|
|
16654
|
-
};
|
|
16655
|
-
}
|
|
16656
16400
|
|
|
16657
|
-
// ../connector-core/dist/
|
|
16658
|
-
var
|
|
16659
|
-
var import_node_path = require("node:path");
|
|
16660
|
-
var ILLEGAL = /[^A-Za-z0-9_-]/g;
|
|
16661
|
-
function tok(s) {
|
|
16662
|
-
const t = s.trim().replace(ILLEGAL, "_");
|
|
16663
|
-
return t.length ? t.slice(0, 40) : "_";
|
|
16664
|
-
}
|
|
16665
|
-
function controlSocketPath(space, name) {
|
|
16666
|
-
return (0, import_node_path.join)((0, import_node_os2.tmpdir)(), `cotal-${tok(space)}-${tok(name)}.sock`);
|
|
16667
|
-
}
|
|
16401
|
+
// ../connector-core/dist/control.js
|
|
16402
|
+
var MAX_FRAME_BYTES = 1 << 20;
|
|
16668
16403
|
|
|
16669
16404
|
// ../connector-core/dist/relay.js
|
|
16670
16405
|
var import_node_net = require("node:net");
|
|
@@ -16690,9 +16425,17 @@ function done(out) {
|
|
|
16690
16425
|
async function runHookRelay() {
|
|
16691
16426
|
if (!hasIdentity())
|
|
16692
16427
|
return done("");
|
|
16428
|
+
const path = process.env.COTAL_CONTROL_SOCKET;
|
|
16429
|
+
const token2 = process.env.COTAL_CONTROL_TOKEN;
|
|
16430
|
+
if (!path || !token2)
|
|
16431
|
+
return done("");
|
|
16693
16432
|
const raw = (await readStdin()).trim() || "{}";
|
|
16694
|
-
|
|
16695
|
-
|
|
16433
|
+
let event = {};
|
|
16434
|
+
try {
|
|
16435
|
+
event = JSON.parse(raw);
|
|
16436
|
+
} catch {
|
|
16437
|
+
}
|
|
16438
|
+
const sock = (0, import_node_net.connect)(path);
|
|
16696
16439
|
let reply = "";
|
|
16697
16440
|
let settled = false;
|
|
16698
16441
|
const finish = (out) => {
|
|
@@ -16707,7 +16450,7 @@ async function runHookRelay() {
|
|
|
16707
16450
|
};
|
|
16708
16451
|
const timer = setTimeout(() => finish(""), TIMEOUT_MS);
|
|
16709
16452
|
sock.setEncoding("utf8");
|
|
16710
|
-
sock.on("connect", () => sock.write(
|
|
16453
|
+
sock.on("connect", () => sock.write(JSON.stringify({ token: token2, event }) + "\n"));
|
|
16711
16454
|
sock.on("data", (d) => {
|
|
16712
16455
|
reply += d;
|
|
16713
16456
|
const nl = reply.indexOf("\n");
|
package/dist/mcp.cjs
CHANGED
|
@@ -45774,6 +45774,10 @@ function deliveryBucket(space) {
|
|
|
45774
45774
|
function leaseKey(shardIndex) {
|
|
45775
45775
|
return `lease.${shardIndex}`;
|
|
45776
45776
|
}
|
|
45777
|
+
function managerBucket(space) {
|
|
45778
|
+
return `cotal_manager_${token(space)}`;
|
|
45779
|
+
}
|
|
45780
|
+
var MANAGER_LEASE_KEY = "lease";
|
|
45777
45781
|
function chatStream(space) {
|
|
45778
45782
|
return `CHAT_${token(space)}`;
|
|
45779
45783
|
}
|
|
@@ -45858,6 +45862,8 @@ function assertValidName(name) {
|
|
|
45858
45862
|
throw new Error(`invalid name ${JSON.stringify(name)}: must be a single line`);
|
|
45859
45863
|
if (name.includes("/"))
|
|
45860
45864
|
throw new Error(`invalid name ${JSON.stringify(name)}: "/" is reserved (the owner/name separator)`);
|
|
45865
|
+
if (name.includes("\\"))
|
|
45866
|
+
throw new Error(`invalid name ${JSON.stringify(name)}: "\\" is reserved (a Windows path separator)`);
|
|
45861
45867
|
}
|
|
45862
45868
|
|
|
45863
45869
|
// ../../packages/core/dist/link.js
|
|
@@ -47531,6 +47537,7 @@ var import_kv = __toESM(require_mod6(), 1);
|
|
|
47531
47537
|
var MAX_MSGS_PER_SUBJECT = 1e3;
|
|
47532
47538
|
var PLANE3_DEDUP_WINDOW_MS = 2 * 60 * 60 * 1e3;
|
|
47533
47539
|
var DINBOX_MAX_ACK_PENDING = 1e3;
|
|
47540
|
+
var MANAGER_LEASE_TTL_MS = 1e4;
|
|
47534
47541
|
var MEMBERSHIP_MAX_BYTES = 64 * 1024 * 1024;
|
|
47535
47542
|
async function createSpaceStreams(jsm, space) {
|
|
47536
47543
|
const p = spacePrefix(space);
|
|
@@ -47951,6 +47958,9 @@ function loadAgentFile(path) {
|
|
|
47951
47958
|
};
|
|
47952
47959
|
}
|
|
47953
47960
|
|
|
47961
|
+
// ../../packages/core/dist/secret-fs.js
|
|
47962
|
+
var isWin = process.platform === "win32";
|
|
47963
|
+
|
|
47954
47964
|
// ../../packages/core/dist/endpoint.js
|
|
47955
47965
|
var import_node_events = require("node:events");
|
|
47956
47966
|
var import_node_crypto = require("node:crypto");
|
|
@@ -47986,6 +47996,7 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
|
|
|
47986
47996
|
membersKv;
|
|
47987
47997
|
aclKv;
|
|
47988
47998
|
deliveryKv;
|
|
47999
|
+
managerLeaseKv;
|
|
47989
48000
|
membershipKv;
|
|
47990
48001
|
/** The live `ctl.delivery` serve subscription (delivery daemon) — re-created on every (re)connect by
|
|
47991
48002
|
* {@link armDeliveryControl}; tracked so the stale one is dropped on reconnect. */
|
|
@@ -48915,6 +48926,68 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
|
|
|
48915
48926
|
return void 0;
|
|
48916
48927
|
}
|
|
48917
48928
|
}
|
|
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. */
|
|
48936
|
+
async managerLeaseRegistry() {
|
|
48937
|
+
if (!this.nc)
|
|
48938
|
+
throw new Error("endpoint not started");
|
|
48939
|
+
if (this.managerLeaseKv)
|
|
48940
|
+
return this.managerLeaseKv;
|
|
48941
|
+
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 {
|
|
48945
|
+
this.managerLeaseKv = await kvm.open(managerBucket(this.space));
|
|
48946
|
+
}
|
|
48947
|
+
return this.managerLeaseKv;
|
|
48948
|
+
}
|
|
48949
|
+
encodeManagerLease(info) {
|
|
48950
|
+
return new TextEncoder().encode(JSON.stringify(info));
|
|
48951
|
+
}
|
|
48952
|
+
/** Acquire the singleton manager lease via ATOMIC CAS create. THROWS if a live lease exists (a loud
|
|
48953
|
+
* refusal-to-start, never a retry) so two managers never split control. A crashed holder's lease
|
|
48954
|
+
* auto-expires (bucket TTL). Returns the lease revision (for renew). */
|
|
48955
|
+
async acquireManagerLease(info) {
|
|
48956
|
+
return (await this.managerLeaseRegistry()).create(MANAGER_LEASE_KEY, this.encodeManagerLease({ ...info, since: Date.now() }));
|
|
48957
|
+
}
|
|
48958
|
+
/** Renew the held lease (CAS update against `revision`) before the bucket TTL expires it. Throws if the
|
|
48959
|
+
* revision moved (lost the lease). Returns the new revision. */
|
|
48960
|
+
async renewManagerLease(info, revision) {
|
|
48961
|
+
return (await this.managerLeaseRegistry()).update(MANAGER_LEASE_KEY, this.encodeManagerLease({ ...info, since: Date.now() }), revision);
|
|
48962
|
+
}
|
|
48963
|
+
/** Release the held lease on clean shutdown so a replacement manager acquires immediately. CAS-guarded
|
|
48964
|
+
* by `revision`: if we already LOST the lease (renew gap / another manager took over) the stored
|
|
48965
|
+
* revision has moved, the conditional delete no-ops, and we never delete the replacement's live lease. */
|
|
48966
|
+
async releaseManagerLease(revision) {
|
|
48967
|
+
try {
|
|
48968
|
+
const kv = await this.managerLeaseRegistry();
|
|
48969
|
+
if (revision === void 0)
|
|
48970
|
+
await kv.delete(MANAGER_LEASE_KEY);
|
|
48971
|
+
else
|
|
48972
|
+
await kv.delete(MANAGER_LEASE_KEY, { previousSeq: revision });
|
|
48973
|
+
} catch {
|
|
48974
|
+
}
|
|
48975
|
+
}
|
|
48976
|
+
/** Read the live manager lease, or undefined if none (bucket absent / key deleted/expired). Open-only —
|
|
48977
|
+
* never creates the bucket, so a probe that finds no manager leaves none behind. */
|
|
48978
|
+
async readManagerLease() {
|
|
48979
|
+
if (!this.nc)
|
|
48980
|
+
return void 0;
|
|
48981
|
+
try {
|
|
48982
|
+
const kv = await new import_kv7.Kvm(this.nc).open(managerBucket(this.space));
|
|
48983
|
+
const e = await kv.get(MANAGER_LEASE_KEY);
|
|
48984
|
+
if (!e || e.operation === "DEL" || e.operation === "PURGE")
|
|
48985
|
+
return void 0;
|
|
48986
|
+
return e.json();
|
|
48987
|
+
} catch {
|
|
48988
|
+
return void 0;
|
|
48989
|
+
}
|
|
48990
|
+
}
|
|
48918
48991
|
/** Privileged: one owner's NON-TOMBSTONED durable memberships as `{channel, generation, activated}` —
|
|
48919
48992
|
* the server-side delivery daemon serves this to a connecting agent (the `listMemberships` op on
|
|
48920
48993
|
* `ctl.delivery`). The agent seeds its leave mirror from the ACTIVATED ones (the confirmed backstops),
|
|
@@ -50558,14 +50631,15 @@ var MeshAgent = class extends import_node_events2.EventEmitter {
|
|
|
50558
50631
|
/** Ask the manager to spawn a new teammate into this space (its `start` op).
|
|
50559
50632
|
* How it lands — a detached PTY, a tmux window, a cmux tab — is the manager's
|
|
50560
50633
|
* runtime; from here it just joins the mesh as a lateral peer. `opts.agent` picks
|
|
50561
|
-
* the harness (default the manager's `cotal`/Claude)
|
|
50562
|
-
* persona file's `model
|
|
50634
|
+
* the harness (default the manager's `cotal`/Claude), `opts.model` overrides the
|
|
50635
|
+
* persona file's `model:`, and `opts.cwd` roots the new peer at a different folder/repo
|
|
50636
|
+
* than the manager's workspace — the same knobs the operator's `cotal start` carries, so
|
|
50563
50637
|
* the agent and operator spawn doors share one control-op contract. */
|
|
50564
50638
|
async spawn(name, role, opts) {
|
|
50565
50639
|
this.assertConnected();
|
|
50566
50640
|
return this.ep.requestControl(CONTROL_PRIVILEGED, {
|
|
50567
50641
|
op: "start",
|
|
50568
|
-
args: { name, role, agent: opts?.agent, model: opts?.model }
|
|
50642
|
+
args: { name, role, agent: opts?.agent, model: opts?.model, cwd: opts?.cwd }
|
|
50569
50643
|
});
|
|
50570
50644
|
}
|
|
50571
50645
|
/** Ask the manager to tear a teammate down (its `stop` op). Graceful by default —
|
|
@@ -50740,18 +50814,6 @@ ${lines.join("\n")}`;
|
|
|
50740
50814
|
}
|
|
50741
50815
|
};
|
|
50742
50816
|
|
|
50743
|
-
// ../connector-core/dist/runtime.js
|
|
50744
|
-
var import_node_os2 = require("node:os");
|
|
50745
|
-
var import_node_path = require("node:path");
|
|
50746
|
-
var ILLEGAL2 = /[^A-Za-z0-9_-]/g;
|
|
50747
|
-
function tok(s) {
|
|
50748
|
-
const t = s.trim().replace(ILLEGAL2, "_");
|
|
50749
|
-
return t.length ? t.slice(0, 40) : "_";
|
|
50750
|
-
}
|
|
50751
|
-
function controlSocketPath(space, name) {
|
|
50752
|
-
return (0, import_node_path.join)((0, import_node_os2.tmpdir)(), `cotal-${tok(space)}-${tok(name)}.sock`);
|
|
50753
|
-
}
|
|
50754
|
-
|
|
50755
50817
|
// ../connector-core/dist/tool-specs.js
|
|
50756
50818
|
var import_node_child_process = require("node:child_process");
|
|
50757
50819
|
|
|
@@ -51154,11 +51216,12 @@ ${info}${caught}`);
|
|
|
51154
51216
|
name: external_exports.string().describe("Which persona to spawn \u2014 the persona FILENAME in .cotal/agents (e.g. `review-critic`), without the .md. The new peer joins under the persona's own `name:` (auto-numbered, e.g. socrates-2, if that's taken). Fails if no such persona file exists \u2014 spawn an existing persona, don't invent a name."),
|
|
51155
51217
|
role: external_exports.string().optional().describe("Optional role for the new peer (e.g. worker, reviewer); overrides the persona file's role."),
|
|
51156
51218
|
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)."),
|
|
51157
|
-
model: external_exports.string().optional().describe("Optional model override (e.g. opus, sonnet) \u2014 wins over the persona file's model:.")
|
|
51219
|
+
model: external_exports.string().optional().describe("Optional model override (e.g. opus, sonnet) \u2014 wins over the persona file's model:."),
|
|
51220
|
+
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.")
|
|
51158
51221
|
},
|
|
51159
|
-
async run(agent, _config, { name, role, agent: agentType, model }) {
|
|
51222
|
+
async run(agent, _config, { name, role, agent: agentType, model, cwd }) {
|
|
51160
51223
|
try {
|
|
51161
|
-
const reply = await agent.spawn(name, role, { agent: agentType, model });
|
|
51224
|
+
const reply = await agent.spawn(name, role, { agent: agentType, model, cwd });
|
|
51162
51225
|
if (!reply.ok)
|
|
51163
51226
|
return err(`Couldn't spawn ${name}: ${reply.error ?? "manager refused"}`);
|
|
51164
51227
|
const d = reply.data;
|
|
@@ -51293,6 +51356,14 @@ function registerCotalTools(server, agent, config2, source) {
|
|
|
51293
51356
|
// ../connector-core/dist/control.js
|
|
51294
51357
|
var import_node_net = require("node:net");
|
|
51295
51358
|
var import_node_fs3 = require("node:fs");
|
|
51359
|
+
var import_node_crypto2 = require("node:crypto");
|
|
51360
|
+
var MAX_FRAME_BYTES = 1 << 20;
|
|
51361
|
+
var AUTH_DEADLINE_MS = 5e3;
|
|
51362
|
+
function tokenMatches(presented, digest) {
|
|
51363
|
+
if (typeof presented !== "string")
|
|
51364
|
+
return false;
|
|
51365
|
+
return (0, import_node_crypto2.timingSafeEqual)((0, import_node_crypto2.createHash)("sha256").update(presented).digest(), digest);
|
|
51366
|
+
}
|
|
51296
51367
|
function who(i) {
|
|
51297
51368
|
return i.fromRole ? `${i.fromName}/${i.fromRole}` : i.fromName;
|
|
51298
51369
|
}
|
|
@@ -51313,26 +51384,53 @@ function formatInjection(items) {
|
|
|
51313
51384
|
${items.map(fmtItem2).join("\n")}
|
|
51314
51385
|
${tail}`;
|
|
51315
51386
|
}
|
|
51316
|
-
function startControlServer(agent,
|
|
51317
|
-
|
|
51387
|
+
function startControlServer(agent, endpoint, handle, opts = {}) {
|
|
51388
|
+
const { path } = endpoint;
|
|
51389
|
+
const digest = (0, import_node_crypto2.createHash)("sha256").update(endpoint.token).digest();
|
|
51390
|
+
if (process.platform !== "win32" && (0, import_node_fs3.existsSync)(path)) {
|
|
51318
51391
|
try {
|
|
51319
|
-
(0, import_node_fs3.unlinkSync)(
|
|
51392
|
+
(0, import_node_fs3.unlinkSync)(path);
|
|
51320
51393
|
} catch {
|
|
51321
51394
|
}
|
|
51322
51395
|
}
|
|
51323
51396
|
const server = (0, import_node_net.createServer)((sock) => {
|
|
51324
51397
|
let buf = "";
|
|
51398
|
+
let handled = false;
|
|
51325
51399
|
sock.setEncoding("utf8");
|
|
51400
|
+
const deadline = setTimeout(() => sock.destroy(), AUTH_DEADLINE_MS);
|
|
51401
|
+
deadline.unref?.();
|
|
51402
|
+
sock.on("close", () => clearTimeout(deadline));
|
|
51326
51403
|
sock.on("data", async (d) => {
|
|
51404
|
+
if (handled)
|
|
51405
|
+
return;
|
|
51327
51406
|
buf += d;
|
|
51407
|
+
if (buf.length > MAX_FRAME_BYTES) {
|
|
51408
|
+
sock.destroy();
|
|
51409
|
+
return;
|
|
51410
|
+
}
|
|
51328
51411
|
const nl = buf.indexOf("\n");
|
|
51329
51412
|
if (nl < 0)
|
|
51330
51413
|
return;
|
|
51331
|
-
|
|
51414
|
+
handled = true;
|
|
51415
|
+
clearTimeout(deadline);
|
|
51416
|
+
let frame = {};
|
|
51332
51417
|
try {
|
|
51333
|
-
|
|
51418
|
+
frame = JSON.parse(buf.slice(0, nl) || "{}");
|
|
51334
51419
|
} catch {
|
|
51335
51420
|
}
|
|
51421
|
+
if (!tokenMatches(frame.token, digest)) {
|
|
51422
|
+
sock.destroy();
|
|
51423
|
+
return;
|
|
51424
|
+
}
|
|
51425
|
+
if (frame.op === "shutdown") {
|
|
51426
|
+
try {
|
|
51427
|
+
sock.end(JSON.stringify({ ok: true }) + "\n");
|
|
51428
|
+
} catch {
|
|
51429
|
+
}
|
|
51430
|
+
opts.onShutdown?.();
|
|
51431
|
+
return;
|
|
51432
|
+
}
|
|
51433
|
+
const ev = frame.event ?? {};
|
|
51336
51434
|
const reply = await handle(agent, ev);
|
|
51337
51435
|
try {
|
|
51338
51436
|
sock.end(JSON.stringify(reply) + "\n");
|
|
@@ -51342,10 +51440,18 @@ function startControlServer(agent, socketPath, handle) {
|
|
|
51342
51440
|
sock.on("error", () => {
|
|
51343
51441
|
});
|
|
51344
51442
|
});
|
|
51345
|
-
|
|
51346
|
-
|
|
51347
|
-
|
|
51348
|
-
`)
|
|
51443
|
+
let bound = false;
|
|
51444
|
+
server.on("error", (e) => {
|
|
51445
|
+
process.stderr.write(`[cotal-connector] control server error: ${e.message}
|
|
51446
|
+
`);
|
|
51447
|
+
if (opts.fatalBind && !bound)
|
|
51448
|
+
process.exit(1);
|
|
51449
|
+
});
|
|
51450
|
+
server.listen(path, () => {
|
|
51451
|
+
bound = true;
|
|
51452
|
+
process.stderr.write(`[cotal-connector] control socket: ${path}
|
|
51453
|
+
`);
|
|
51454
|
+
});
|
|
51349
51455
|
return server;
|
|
51350
51456
|
}
|
|
51351
51457
|
|
|
@@ -51579,8 +51685,32 @@ async function main() {
|
|
|
51579
51685
|
agent.start();
|
|
51580
51686
|
if (/^(1|true|yes|on)$/i.test(process.env.COTAL_TRANSCRIPT ?? ""))
|
|
51581
51687
|
mirror = new TranscriptMirror(agent, transcriptChannel(config2.name));
|
|
51582
|
-
const
|
|
51583
|
-
const
|
|
51688
|
+
const controlPath = process.env.COTAL_CONTROL_SOCKET;
|
|
51689
|
+
const controlToken = process.env.COTAL_CONTROL_TOKEN;
|
|
51690
|
+
if (!controlPath || !controlToken) {
|
|
51691
|
+
process.stderr.write(
|
|
51692
|
+
"[cotal-connector] managed session missing COTAL_CONTROL_SOCKET/COTAL_CONTROL_TOKEN \u2014 cannot serve the control plane\n"
|
|
51693
|
+
);
|
|
51694
|
+
process.exit(1);
|
|
51695
|
+
}
|
|
51696
|
+
let controlServer;
|
|
51697
|
+
const shutdown = async () => {
|
|
51698
|
+
try {
|
|
51699
|
+
controlServer?.close();
|
|
51700
|
+
} catch {
|
|
51701
|
+
}
|
|
51702
|
+
try {
|
|
51703
|
+
await agent.stop();
|
|
51704
|
+
} finally {
|
|
51705
|
+
process.exit(0);
|
|
51706
|
+
}
|
|
51707
|
+
};
|
|
51708
|
+
controlServer = startControlServer(
|
|
51709
|
+
agent,
|
|
51710
|
+
{ path: controlPath, token: controlToken },
|
|
51711
|
+
claudeHandle,
|
|
51712
|
+
{ fatalBind: true, onShutdown: () => void shutdown() }
|
|
51713
|
+
);
|
|
51584
51714
|
const server = new McpServer(
|
|
51585
51715
|
{ name: "cotal", version: "0.0.0" },
|
|
51586
51716
|
{
|
|
@@ -51613,17 +51743,6 @@ async function main() {
|
|
|
51613
51743
|
(item) => nudge(item, `You were mentioned by ${fmtFrom(item)} on #${item.channel ?? "?"} \u2014 pull it with cotal_inbox.`)
|
|
51614
51744
|
);
|
|
51615
51745
|
agent.on("wake", () => nudge());
|
|
51616
|
-
const shutdown = async () => {
|
|
51617
|
-
try {
|
|
51618
|
-
controlServer.close();
|
|
51619
|
-
} catch {
|
|
51620
|
-
}
|
|
51621
|
-
try {
|
|
51622
|
-
await agent.stop();
|
|
51623
|
-
} finally {
|
|
51624
|
-
process.exit(0);
|
|
51625
|
-
}
|
|
51626
|
-
};
|
|
51627
51746
|
process.on("SIGINT", () => void shutdown());
|
|
51628
51747
|
process.on("SIGTERM", () => void shutdown());
|
|
51629
51748
|
const transport = new StdioServerTransport();
|
package/dist/mcp.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
12
12
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
13
|
-
import { configFromEnv, hasIdentity, MeshAgent,
|
|
13
|
+
import { configFromEnv, hasIdentity, MeshAgent, startControlServer, registerCotalTools, feedbackLine, ORIENTATION_BOOTSTRAP, formatInjection, fmtFrom, channelMeta, } from "@cotal-ai/connector-core";
|
|
14
14
|
import { TranscriptMirror, transcriptChannel } from "./transcript.js";
|
|
15
15
|
/** Mirrors this session's transcript to `tr-<name>` — set in main() iff COTAL_TRANSCRIPT
|
|
16
16
|
* is on (buildLaunch sets it for managed sessions; personal sessions never mirror). */
|
|
@@ -119,9 +119,34 @@ async function main() {
|
|
|
119
119
|
agent.start(); // background connect with retry — never blocks tool serving
|
|
120
120
|
if (/^(1|true|yes|on)$/i.test(process.env.COTAL_TRANSCRIPT ?? ""))
|
|
121
121
|
mirror = new TranscriptMirror(agent, transcriptChannel(config.name));
|
|
122
|
-
// Local control plane for the lifecycle hooks (presence + message injection)
|
|
123
|
-
|
|
124
|
-
|
|
122
|
+
// Local control plane for the lifecycle hooks (presence + message injection) and the manager's
|
|
123
|
+
// cooperative shutdown. Path + token come from the launch env (buildLaunch set them, and the hooks
|
|
124
|
+
// inherit this process's env) — a managed session without them is misconfigured, so fail loud
|
|
125
|
+
// rather than serve an unauthenticated/no control plane.
|
|
126
|
+
const controlPath = process.env.COTAL_CONTROL_SOCKET;
|
|
127
|
+
const controlToken = process.env.COTAL_CONTROL_TOKEN;
|
|
128
|
+
if (!controlPath || !controlToken) {
|
|
129
|
+
process.stderr.write("[cotal-connector] managed session missing COTAL_CONTROL_SOCKET/COTAL_CONTROL_TOKEN — cannot serve the control plane\n");
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
// Defined before the server so it can be the cooperative-shutdown handler; only ever CALLED after
|
|
133
|
+
// `controlServer` is assigned (on a signal or an authed `{op:"shutdown"}`), so the forward ref is safe.
|
|
134
|
+
let controlServer;
|
|
135
|
+
const shutdown = async () => {
|
|
136
|
+
try {
|
|
137
|
+
controlServer?.close();
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
/* ignore */
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
await agent.stop();
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
process.exit(0);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
controlServer = startControlServer(agent, { path: controlPath, token: controlToken }, claudeHandle, { fatalBind: true, onShutdown: () => void shutdown() });
|
|
125
150
|
const server = new McpServer({ name: "cotal", version: "0.0.0" }, {
|
|
126
151
|
// `claude/channel` makes this MCP server a Claude Code *channel*: peer
|
|
127
152
|
// messages can be pushed straight into the session (waking it if idle).
|
|
@@ -190,20 +215,6 @@ async function main() {
|
|
|
190
215
|
// — F4=B (wake-only). Its body isn't injected; cotal_inbox recalls it.
|
|
191
216
|
agent.on("mention-wake", (item) => nudge(item, `You were mentioned by ${fmtFrom(item)} on #${item.channel ?? "?"} — pull it with cotal_inbox.`));
|
|
192
217
|
agent.on("wake", () => nudge());
|
|
193
|
-
const shutdown = async () => {
|
|
194
|
-
try {
|
|
195
|
-
controlServer.close();
|
|
196
|
-
}
|
|
197
|
-
catch {
|
|
198
|
-
/* ignore */
|
|
199
|
-
}
|
|
200
|
-
try {
|
|
201
|
-
await agent.stop();
|
|
202
|
-
}
|
|
203
|
-
finally {
|
|
204
|
-
process.exit(0);
|
|
205
|
-
}
|
|
206
|
-
};
|
|
207
218
|
process.on("SIGINT", () => void shutdown());
|
|
208
219
|
process.on("SIGTERM", () => void shutdown());
|
|
209
220
|
const transport = new StdioServerTransport();
|
package/dist/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACL,aAAa,EACb,WAAW,EACX,SAAS,EACT,
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
|
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.
|
|
4
|
+
"version": "0.8.2",
|
|
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.
|
|
22
|
+
"@cotal-ai/connector-core": "0.8.2"
|
|
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.
|
|
30
|
+
"@cotal-ai/core": "0.8.2"
|
|
31
31
|
},
|
|
32
32
|
"files": [
|
|
33
33
|
"dist",
|