@cotal-ai/core 0.3.1 → 0.4.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 +11 -0
- package/dist/agent-file.d.ts +29 -5
- package/dist/agent-file.d.ts.map +1 -1
- package/dist/agent-file.js +64 -11
- package/dist/agent-file.js.map +1 -1
- package/dist/command.d.ts +24 -0
- package/dist/command.d.ts.map +1 -1
- package/dist/connector-config.d.ts +42 -0
- package/dist/connector-config.d.ts.map +1 -0
- package/dist/connector-config.js +103 -0
- package/dist/connector-config.js.map +1 -0
- package/dist/connector.d.ts +11 -0
- package/dist/connector.d.ts.map +1 -1
- package/dist/endpoint.d.ts +123 -8
- package/dist/endpoint.d.ts.map +1 -1
- package/dist/endpoint.js +466 -137
- package/dist/endpoint.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/provision.d.ts +33 -10
- package/dist/provision.d.ts.map +1 -1
- package/dist/provision.js +65 -26
- package/dist/provision.js.map +1 -1
- package/dist/resolve.d.ts +53 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +61 -0
- package/dist/resolve.js.map +1 -0
- package/dist/streams.d.ts +23 -0
- package/dist/streams.d.ts.map +1 -1
- package/dist/streams.js +36 -4
- package/dist/streams.js.map +1 -1
- package/dist/subjects.d.ts +42 -2
- package/dist/subjects.d.ts.map +1 -1
- package/dist/subjects.js +61 -3
- package/dist/subjects.js.map +1 -1
- package/package.json +4 -2
package/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# @cotal-ai/core
|
|
2
|
+
|
|
3
|
+
The Cotal protocol: the endpoint, subjects, and message types, plus the NATS client layer and
|
|
4
|
+
the extension contracts (`Connector`, `Command`, `Runtime`) and the `Registry` they
|
|
5
|
+
self-register into.
|
|
6
|
+
|
|
7
|
+
**Tier:** `packages/` (the standard). Everything depends on core; core depends on nothing else
|
|
8
|
+
in the repo.
|
|
9
|
+
|
|
10
|
+
See the [root AGENTS.md](../../AGENTS.md) for the tier rules, [SPEC.md](../../SPEC.md) for the
|
|
11
|
+
normative wire contract, and [docs/](../../docs/) for the protocol.
|
package/dist/agent-file.d.ts
CHANGED
|
@@ -5,13 +5,32 @@ export interface AgentDef {
|
|
|
5
5
|
kind?: EndpointKind;
|
|
6
6
|
description?: string;
|
|
7
7
|
tags?: string[];
|
|
8
|
-
channels
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
/** The *active* read set: channels this agent subscribes to at boot (the live chat-durable
|
|
9
|
+
* filter; mutable at runtime via join/leave). Must be ⊆ {@link allowSubscribe}. Default `[general]`. */
|
|
10
|
+
subscribe?: string[];
|
|
11
|
+
/** The read **ACL**: channels this agent *may* read (auth mode → minted as per-channel
|
|
12
|
+
* history-consumer create grants; the live durable's filter is also held within it). Entries
|
|
13
|
+
* may be wildcard subtrees (`team.>`). Omitted ⇒ defaults to {@link subscribe} — it can read
|
|
14
|
+
* exactly what it subscribes to. */
|
|
15
|
+
allowSubscribe?: string[];
|
|
16
|
+
/** The post **ACL**: channels this agent may publish to (auth mode → minted into pub-allow
|
|
17
|
+
* ACLs). Entries may be wildcard subtrees (`team.>`). Omitted ⇒ **deny** (default-deny):
|
|
18
|
+
* publishing is the dangerous capability, so it must be declared explicitly. */
|
|
19
|
+
allowPublish?: string[];
|
|
13
20
|
/** Model override handed to the agent CLI (e.g. `claude --model`). */
|
|
14
21
|
model?: string;
|
|
22
|
+
/** Capabilities this agent may exercise on the control plane (auth mode → minted into the
|
|
23
|
+
* cred's publish allow-list). Today `spawn` is the only one: it grants publish to the
|
|
24
|
+
* privileged control subject (start/purge/definePersona/named stop). Default-deny when
|
|
25
|
+
* absent — nats-server, not a handler, is the boundary. Granting authority is operator-level
|
|
26
|
+
* (`definePersona` is itself privileged), so no peer can self-grant via its own agent file. */
|
|
27
|
+
capabilities?: string[];
|
|
28
|
+
/** Authenticated id of the agent that first defined this persona via `definePersona` (P6). A
|
|
29
|
+
* POLICY field, not content: the privileged tier may *redefine* an existing file only if its
|
|
30
|
+
* `owner` equals the caller; everyone else needs the admin tier. Fail-closed — an ownerless
|
|
31
|
+
* file (legacy / operator-written) is admin-only, and a caller can never claim ownership of an
|
|
32
|
+
* existing file. Set once at creation (owner = creator), preserved on every later redefine. */
|
|
33
|
+
owner?: string;
|
|
15
34
|
/** Frontmatter keys not modelled above, kept verbatim so a connector can read its own launcher
|
|
16
35
|
* hints without core knowing about each one (e.g. the OpenCode face viewer's `face:` avatar id). */
|
|
17
36
|
meta?: Record<string, string>;
|
|
@@ -29,4 +48,9 @@ export declare function saveAgentFile(path: string, def: AgentDef): void;
|
|
|
29
48
|
* or ends in `.md`) is used as given; a bare name maps to the directory
|
|
30
49
|
* convention `<root>/.cotal/agents/<name>.md`. */
|
|
31
50
|
export declare function agentFilePath(root: string, nameOrPath: string): string;
|
|
51
|
+
/** First free name in the series `base`, `base-2`, `base-3`, … — the first candidate for which
|
|
52
|
+
* `taken` returns false. The single source of the spawn auto-numbering scheme, shared by the
|
|
53
|
+
* manager's funnel (checked against its live + reserved slots) and `cotal spawn` (checked against
|
|
54
|
+
* the live mesh roster), so a colliding name numbers up identically whichever path spawns it. */
|
|
55
|
+
export declare function firstFreeName(base: string, taken: (name: string) => boolean): string;
|
|
32
56
|
//# sourceMappingURL=agent-file.d.ts.map
|
package/dist/agent-file.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-file.d.ts","sourceRoot":"","sources":["../src/agent-file.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent-file.d.ts","sourceRoot":"","sources":["../src/agent-file.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;6GACyG;IACzG,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB;;;yCAGqC;IACrC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;qFAEiF;IACjF,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;oGAIgG;IAChG,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB;;;;oGAIgG;IAChG,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;yGACqG;IACrG,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmCD,8EAA8E;AAC9E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CA4EpD;AAED;;;8CAG8C;AAC9C,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,GAAG,IAAI,CAmB/D;AAmBD;;mDAEmD;AACnD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAItE;AAED;;;kGAGkG;AAClG,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,GAAG,MAAM,CAMpF"}
|
package/dist/agent-file.js
CHANGED
|
@@ -3,13 +3,15 @@
|
|
|
3
3
|
*
|
|
4
4
|
* .cotal/agents/<name>.md
|
|
5
5
|
* ---
|
|
6
|
-
* name: builder
|
|
6
|
+
* name: builder # AgentCard-shaped identity in the frontmatter
|
|
7
7
|
* role: builder
|
|
8
8
|
* description: …
|
|
9
9
|
* tags: [edit, test]
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* subscribe: [general] # channels this agent actively reads at boot (the live set)
|
|
11
|
+
* allowSubscribe: [general] # read ACL — channels it MAY read; omit ⇒ same as `subscribe`
|
|
12
|
+
* allowPublish: [general] # post ACL — channels it may publish to; omit ⇒ DENY (default-deny)
|
|
13
|
+
* model: opus # optional CLI/model override
|
|
14
|
+
* capabilities: [spawn] # control-plane capabilities (spawn → may start/despawn others)
|
|
13
15
|
* face: sven # any unmodelled key is kept verbatim in AgentDef.meta — e.g. the
|
|
14
16
|
* # OpenCode connector reads meta.face for its avatar viewer
|
|
15
17
|
* ---
|
|
@@ -22,6 +24,8 @@
|
|
|
22
24
|
*/
|
|
23
25
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
24
26
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
27
|
+
import { assertValidName } from "./resolve.js";
|
|
28
|
+
import { assertValidChannel, channelInAllow } from "./subjects.js";
|
|
25
29
|
/** Strip wrapping quotes from a scalar value. */
|
|
26
30
|
function unquote(v) {
|
|
27
31
|
if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'")))
|
|
@@ -80,12 +84,38 @@ export function loadAgentFile(path) {
|
|
|
80
84
|
const name = str("name");
|
|
81
85
|
if (!name)
|
|
82
86
|
throw new Error(`agent file ${path}: "name" is required`);
|
|
87
|
+
assertValidName(name);
|
|
83
88
|
const kind = str("kind");
|
|
84
89
|
if (kind && kind !== "agent" && kind !== "endpoint")
|
|
85
90
|
throw new Error(`agent file ${path}: "kind" must be "agent" or "endpoint"`);
|
|
91
|
+
// The pre-ACL field names were renamed (channels→subscribe, publish→allowPublish, +allowSubscribe).
|
|
92
|
+
// Fail loud on the old names rather than silently sweeping them into meta and ignoring them —
|
|
93
|
+
// an unmigrated file would otherwise lose its read/post scope without warning (no silent degrade).
|
|
94
|
+
for (const old of ["channels", "publish"])
|
|
95
|
+
if (old in fm)
|
|
96
|
+
throw new Error(`agent file ${path}: "${old}" was renamed — use "subscribe"/"allowSubscribe" (read) and "allowPublish" (post)`);
|
|
97
|
+
const subscribe = list("subscribe");
|
|
98
|
+
const allowSubscribe = list("allowSubscribe");
|
|
99
|
+
const allowPublish = list("allowPublish");
|
|
100
|
+
// Reject channel names the wire layer would silently rewrite — a policy name must equal its wire
|
|
101
|
+
// token, or the ACL aliases (see assertValidChannel). Covers all three scope fields.
|
|
102
|
+
for (const ch of [...(subscribe ?? []), ...(allowSubscribe ?? []), ...(allowPublish ?? [])])
|
|
103
|
+
try {
|
|
104
|
+
assertValidChannel(ch);
|
|
105
|
+
}
|
|
106
|
+
catch (e) {
|
|
107
|
+
throw new Error(`agent file ${path}: ${e.message}`);
|
|
108
|
+
}
|
|
109
|
+
// Invariant (fail-loud at load): the active read set must be within the read ACL. Defaults:
|
|
110
|
+
// subscribe ⇒ [general]; allowSubscribe ⇒ subscribe (read exactly what you subscribe to).
|
|
111
|
+
const effSubscribe = subscribe?.length ? subscribe : ["general"];
|
|
112
|
+
const effAllow = allowSubscribe?.length ? allowSubscribe : effSubscribe;
|
|
113
|
+
for (const ch of effSubscribe)
|
|
114
|
+
if (!channelInAllow(effAllow, ch))
|
|
115
|
+
throw new Error(`agent file ${path}: subscribe channel "${ch}" is not within allowSubscribe [${effAllow.join(", ")}]`);
|
|
86
116
|
// Sweep every scalar frontmatter key we don't model into meta, verbatim — connector hints
|
|
87
117
|
// (face, etc.) ride here so core stays ignorant of surface-specific keys.
|
|
88
|
-
const known = new Set(["name", "role", "kind", "description", "tags", "
|
|
118
|
+
const known = new Set(["name", "role", "kind", "description", "tags", "subscribe", "allowSubscribe", "allowPublish", "model", "capabilities", "owner"]);
|
|
89
119
|
const meta = {};
|
|
90
120
|
for (const [k, v] of Object.entries(fm))
|
|
91
121
|
if (!known.has(k) && typeof v === "string")
|
|
@@ -96,9 +126,12 @@ export function loadAgentFile(path) {
|
|
|
96
126
|
kind: kind,
|
|
97
127
|
description: str("description"),
|
|
98
128
|
tags: list("tags"),
|
|
99
|
-
|
|
100
|
-
|
|
129
|
+
subscribe,
|
|
130
|
+
allowSubscribe,
|
|
131
|
+
allowPublish,
|
|
101
132
|
model: str("model"),
|
|
133
|
+
capabilities: list("capabilities"),
|
|
134
|
+
owner: str("owner"),
|
|
102
135
|
meta: Object.keys(meta).length ? meta : undefined,
|
|
103
136
|
persona: persona || undefined,
|
|
104
137
|
};
|
|
@@ -110,6 +143,7 @@ export function loadAgentFile(path) {
|
|
|
110
143
|
export function saveAgentFile(path, def) {
|
|
111
144
|
if (!def.name)
|
|
112
145
|
throw new Error('saveAgentFile: "name" is required');
|
|
146
|
+
assertValidName(def.name);
|
|
113
147
|
const lines = ["---", `name: ${fmScalar(def.name)}`];
|
|
114
148
|
if (def.role)
|
|
115
149
|
lines.push(`role: ${fmScalar(def.role)}`);
|
|
@@ -119,12 +153,18 @@ export function saveAgentFile(path, def) {
|
|
|
119
153
|
lines.push(`description: ${fmScalar(def.description)}`);
|
|
120
154
|
if (def.tags?.length)
|
|
121
155
|
lines.push(`tags: [${def.tags.map(fmItem).join(", ")}]`);
|
|
122
|
-
if (def.
|
|
123
|
-
lines.push(`
|
|
124
|
-
if (def.
|
|
125
|
-
lines.push(`
|
|
156
|
+
if (def.subscribe?.length)
|
|
157
|
+
lines.push(`subscribe: [${def.subscribe.map(fmItem).join(", ")}]`);
|
|
158
|
+
if (def.allowSubscribe?.length)
|
|
159
|
+
lines.push(`allowSubscribe: [${def.allowSubscribe.map(fmItem).join(", ")}]`);
|
|
160
|
+
if (def.allowPublish?.length)
|
|
161
|
+
lines.push(`allowPublish: [${def.allowPublish.map(fmItem).join(", ")}]`);
|
|
126
162
|
if (def.model)
|
|
127
163
|
lines.push(`model: ${fmScalar(def.model)}`);
|
|
164
|
+
if (def.capabilities?.length)
|
|
165
|
+
lines.push(`capabilities: [${def.capabilities.map(fmItem).join(", ")}]`);
|
|
166
|
+
if (def.owner)
|
|
167
|
+
lines.push(`owner: ${fmScalar(def.owner)}`);
|
|
128
168
|
if (def.meta)
|
|
129
169
|
for (const [k, v] of Object.entries(def.meta))
|
|
130
170
|
lines.push(`${k}: ${fmScalar(v)}`);
|
|
@@ -163,4 +203,17 @@ export function agentFilePath(root, nameOrPath) {
|
|
|
163
203
|
return resolve(root, nameOrPath);
|
|
164
204
|
return join(root, ".cotal", "agents", `${nameOrPath}.md`);
|
|
165
205
|
}
|
|
206
|
+
/** First free name in the series `base`, `base-2`, `base-3`, … — the first candidate for which
|
|
207
|
+
* `taken` returns false. The single source of the spawn auto-numbering scheme, shared by the
|
|
208
|
+
* manager's funnel (checked against its live + reserved slots) and `cotal spawn` (checked against
|
|
209
|
+
* the live mesh roster), so a colliding name numbers up identically whichever path spawns it. */
|
|
210
|
+
export function firstFreeName(base, taken) {
|
|
211
|
+
if (!taken(base))
|
|
212
|
+
return base;
|
|
213
|
+
for (let n = 2;; n++) {
|
|
214
|
+
const candidate = `${base}-${n}`;
|
|
215
|
+
if (!taken(candidate))
|
|
216
|
+
return candidate;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
166
219
|
//# sourceMappingURL=agent-file.js.map
|
package/dist/agent-file.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-file.js","sourceRoot":"","sources":["../src/agent-file.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"agent-file.js","sourceRoot":"","sources":["../src/agent-file.ts"],"names":[],"mappings":"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"}
|
package/dist/command.d.ts
CHANGED
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
import type { Extension } from "./registry.js";
|
|
2
|
+
/** One shell-completion candidate. `value` is inserted on the command line; `description`
|
|
3
|
+
* is a one-line hint shown by shells that support it (zsh, fish) and ignored by bash. */
|
|
4
|
+
export interface CompletionItem {
|
|
5
|
+
value: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
}
|
|
8
|
+
/** What a command's {@link Command.complete} returns for the current cursor position: the
|
|
9
|
+
* candidates, plus a directive telling the shell glue how to treat them.
|
|
10
|
+
* - `nofiles` (the norm for our completions): don't fall back to filename completion.
|
|
11
|
+
* - `nospace`: don't append a trailing space (the value is a prefix, e.g. `owner/`).
|
|
12
|
+
* - `default`: normal behaviour (a trailing space is added; files may be offered). */
|
|
13
|
+
export interface CompletionResult {
|
|
14
|
+
items: CompletionItem[];
|
|
15
|
+
directive?: "default" | "nospace" | "nofiles";
|
|
16
|
+
}
|
|
2
17
|
/**
|
|
3
18
|
* The contract for a composable CLI command — an {@link Extension} of kind
|
|
4
19
|
* `"command"`. An implementation (the mesh CLI, the manager …) self-registers its
|
|
@@ -10,6 +25,15 @@ export interface Command extends Extension {
|
|
|
10
25
|
readonly summary: string;
|
|
11
26
|
/** Help grouping header (e.g. "Mesh", "Control plane"). Defaults to "Commands". */
|
|
12
27
|
readonly group?: string;
|
|
28
|
+
/** One-line usage shown by `cotal <cmd> --help` and on an invalid-argument error.
|
|
29
|
+
* Falls back to `summary` when unset. */
|
|
30
|
+
readonly usage?: string;
|
|
13
31
|
run(argv: string[]): Promise<void>;
|
|
32
|
+
/** Optional shell-completion provider, owned by the command exactly as `run` is. Given the
|
|
33
|
+
* args typed so far (everything after the command name; the last element is the word being
|
|
34
|
+
* completed, possibly empty), returns the candidates for that position. Runs on every <TAB>
|
|
35
|
+
* via the hidden `__complete` dispatcher, so it MUST be import-light and side-effect-free —
|
|
36
|
+
* no network, no spawns. Omit it to offer no argument completion for this command. */
|
|
37
|
+
complete?(argv: string[]): CompletionResult | Promise<CompletionResult>;
|
|
14
38
|
}
|
|
15
39
|
//# sourceMappingURL=command.d.ts.map
|
package/dist/command.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;;;;GAIG;AACH,MAAM,WAAW,OAAQ,SAAQ,SAAS;IACxC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../src/command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;0FAC0F;AAC1F,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;uFAIuF;AACvF,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;CAC/C;AAED;;;;GAIG;AACH,MAAM,WAAW,OAAQ,SAAQ,SAAS;IACxC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mFAAmF;IACnF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;8CAC0C;IAC1C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC;;;;2FAIuF;IACvF,QAAQ,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;CACzE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** One MCP server, in the de-facto `.mcp.json` shape. Secrets belong in `env` (or `headers`) as
|
|
2
|
+
* `${VAR}` references, resolved from the operator's environment at launch. Remote-transport fields
|
|
3
|
+
* (`type`/`url`/`headers`) are carried verbatim for connectors that support them. Any other
|
|
4
|
+
* `.mcp.json` key an operator copies in (e.g. `timeout`) passes through to the rendered config
|
|
5
|
+
* unchanged but gets NO `${VAR}` expansion — Claude only expands command/args/env/url/headers,
|
|
6
|
+
* which is exactly the set {@link mcpServerEnvKeys} scans for secret names to forward. */
|
|
7
|
+
export interface McpServerSpec {
|
|
8
|
+
command?: string;
|
|
9
|
+
args?: string[];
|
|
10
|
+
env?: Record<string, string>;
|
|
11
|
+
type?: string;
|
|
12
|
+
url?: string;
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
/** Pass-through for any other `.mcp.json` key (carried verbatim, no env expansion). */
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
/** Per-connector settings. `mcpServers` are the operator servers SHARED with agents this connector
|
|
18
|
+
* spawns, keyed by server name (`.mcp.json`-style). */
|
|
19
|
+
export interface ConnectorConfig {
|
|
20
|
+
mcpServers?: Record<string, McpServerSpec>;
|
|
21
|
+
}
|
|
22
|
+
/** The parsed cotal config file: a section per connector, keyed by connector name ("claude", …). */
|
|
23
|
+
export interface CotalConfig {
|
|
24
|
+
connectors?: Record<string, ConnectorConfig>;
|
|
25
|
+
}
|
|
26
|
+
/** Operator-level config path: `$XDG_CONFIG_HOME/cotal/config.json`, else `~/.config/cotal/config.json`. */
|
|
27
|
+
export declare function globalConfigPath(): string;
|
|
28
|
+
/** Space-local config path: `<root>/.cotal/config.json`. */
|
|
29
|
+
export declare function spaceConfigPath(root: string): string;
|
|
30
|
+
/** Load the merged cotal config: the operator-level file as the base, the space-local file layered
|
|
31
|
+
* on top (more specific wins, per connector + server name). */
|
|
32
|
+
export declare function loadCotalConfig(root: string): CotalConfig;
|
|
33
|
+
/** The MCP servers a connector should share with an agent it spawns, after applying an optional
|
|
34
|
+
* per-spawn `selection` (the parsed `--share-tools` value):
|
|
35
|
+
* `undefined` → every server declared for the connector (the config default)
|
|
36
|
+
* `[]` → none (e.g. `--share-tools none`)
|
|
37
|
+
* `[a, b]` → only those named, which MUST be declared (throws otherwise — no silent drop). */
|
|
38
|
+
export declare function connectorServers(config: CotalConfig, connector: string, selection?: readonly string[]): Record<string, McpServerSpec>;
|
|
39
|
+
/** Parse a `--share-tools` flag value into a selection for {@link connectorServers}: flag absent
|
|
40
|
+
* → `undefined` (share all declared); `none` or empty → `[]` (share nothing); else the comma list. */
|
|
41
|
+
export declare function parseShareSelection(value: string | undefined): readonly string[] | undefined;
|
|
42
|
+
//# sourceMappingURL=connector-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connector-config.d.ts","sourceRoot":"","sources":["../src/connector-config.ts"],"names":[],"mappings":"AA4BA;;;;;2FAK2F;AAC3F,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,uFAAuF;IACvF,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;wDACwD;AACxD,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CAC5C;AAED,oGAAoG;AACpG,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAC9C;AAED,4GAA4G;AAC5G,wBAAgB,gBAAgB,IAAI,MAAM,CAGzC;AAED,4DAA4D;AAC5D,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AA+BD;gEACgE;AAChE,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAEzD;AAED;;;;oGAIoG;AACpG,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,WAAW,EACnB,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAC5B,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAc/B;AAED;uGACuG;AACvG,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAQ5F"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The cotal config file — per-connector launch settings, the first general config notion in
|
|
3
|
+
* the repo (alongside `.cotal/{auth,agents,creds}`, which are about identity, not settings).
|
|
4
|
+
*
|
|
5
|
+
* ~/.config/cotal/config.json (operator-level, every space) ← base layer
|
|
6
|
+
* <root>/.cotal/config.json (space-local override) ← higher precedence
|
|
7
|
+
*
|
|
8
|
+
* Today it carries one thing: which of the operator's personal MCP servers a connector should
|
|
9
|
+
* SHARE with the agents it spawns. By default a spawned agent gets none — the Claude connector
|
|
10
|
+
* launches with `--strict-mcp-config`, dropping every operator server, because they're heavy
|
|
11
|
+
* (a headless Chromium server alone can climb past a gigabyte) and useless to a meshed teammate.
|
|
12
|
+
* This file is the explicit opt-in to pass named ones through.
|
|
13
|
+
*
|
|
14
|
+
* Each server is written in the de-facto `.mcp.json` shape, so an operator can copy an entry
|
|
15
|
+
* straight out of their own Claude / VS Code / Cursor config. Secrets ride as `${VAR}` references
|
|
16
|
+
* resolved from the operator's environment at launch — never literals — so the file stays safe to
|
|
17
|
+
* keep in `~/.config` or a gitignored `.cotal/`.
|
|
18
|
+
*
|
|
19
|
+
* This is deliberately NOT in the agent file ({@link AgentDef}): that's the connector-agnostic
|
|
20
|
+
* identity, portable across Claude Code / OpenCode / Hermes, and MCP-passthrough isn't a shared
|
|
21
|
+
* concept (Claude uses `--mcp-config`, OpenCode inherits via a merge layer, Hermes has no MCP).
|
|
22
|
+
* The caller (both spawn paths) resolves this once and hands the chosen servers to the connector,
|
|
23
|
+
* which renders them into its own host format.
|
|
24
|
+
*/
|
|
25
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
26
|
+
import { homedir } from "node:os";
|
|
27
|
+
import { join } from "node:path";
|
|
28
|
+
/** Operator-level config path: `$XDG_CONFIG_HOME/cotal/config.json`, else `~/.config/cotal/config.json`. */
|
|
29
|
+
export function globalConfigPath() {
|
|
30
|
+
const base = process.env.XDG_CONFIG_HOME?.trim() || join(homedir(), ".config");
|
|
31
|
+
return join(base, "cotal", "config.json");
|
|
32
|
+
}
|
|
33
|
+
/** Space-local config path: `<root>/.cotal/config.json`. */
|
|
34
|
+
export function spaceConfigPath(root) {
|
|
35
|
+
return join(root, ".cotal", "config.json");
|
|
36
|
+
}
|
|
37
|
+
/** Parse one config file. A missing file is empty (no config is a valid state); malformed JSON or a
|
|
38
|
+
* non-object top level throws — a typo in your settings should be loud, not silently ignored. */
|
|
39
|
+
function readConfigFile(path) {
|
|
40
|
+
if (!existsSync(path))
|
|
41
|
+
return {};
|
|
42
|
+
let parsed;
|
|
43
|
+
try {
|
|
44
|
+
parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
throw new Error(`cotal config ${path}: invalid JSON — ${e.message}`);
|
|
48
|
+
}
|
|
49
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
50
|
+
throw new Error(`cotal config ${path}: top level must be a JSON object`);
|
|
51
|
+
return parsed;
|
|
52
|
+
}
|
|
53
|
+
/** Layer `over` onto `base`: per connector, a server in `over` replaces the same-named server in
|
|
54
|
+
* `base` (whole-spec replace, by name — the same merge the MCP clients do); servers/connectors
|
|
55
|
+
* present in only one side are kept. */
|
|
56
|
+
function mergeConfig(base, over) {
|
|
57
|
+
const connectors = {};
|
|
58
|
+
const names = new Set([...Object.keys(base.connectors ?? {}), ...Object.keys(over.connectors ?? {})]);
|
|
59
|
+
for (const name of names) {
|
|
60
|
+
const b = base.connectors?.[name];
|
|
61
|
+
const o = over.connectors?.[name];
|
|
62
|
+
connectors[name] = { ...b, ...o, mcpServers: { ...(b?.mcpServers ?? {}), ...(o?.mcpServers ?? {}) } };
|
|
63
|
+
}
|
|
64
|
+
return { connectors };
|
|
65
|
+
}
|
|
66
|
+
/** Load the merged cotal config: the operator-level file as the base, the space-local file layered
|
|
67
|
+
* on top (more specific wins, per connector + server name). */
|
|
68
|
+
export function loadCotalConfig(root) {
|
|
69
|
+
return mergeConfig(readConfigFile(globalConfigPath()), readConfigFile(spaceConfigPath(root)));
|
|
70
|
+
}
|
|
71
|
+
/** The MCP servers a connector should share with an agent it spawns, after applying an optional
|
|
72
|
+
* per-spawn `selection` (the parsed `--share-tools` value):
|
|
73
|
+
* `undefined` → every server declared for the connector (the config default)
|
|
74
|
+
* `[]` → none (e.g. `--share-tools none`)
|
|
75
|
+
* `[a, b]` → only those named, which MUST be declared (throws otherwise — no silent drop). */
|
|
76
|
+
export function connectorServers(config, connector, selection) {
|
|
77
|
+
const declared = config.connectors?.[connector]?.mcpServers ?? {};
|
|
78
|
+
if (selection === undefined)
|
|
79
|
+
return { ...declared };
|
|
80
|
+
const chosen = {};
|
|
81
|
+
for (const name of selection) {
|
|
82
|
+
const spec = declared[name];
|
|
83
|
+
if (!spec)
|
|
84
|
+
throw new Error(`--share-tools: "${name}" is not a shared server for connector "${connector}" ` +
|
|
85
|
+
`(declared: ${Object.keys(declared).join(", ") || "none"})`);
|
|
86
|
+
chosen[name] = spec;
|
|
87
|
+
}
|
|
88
|
+
return chosen;
|
|
89
|
+
}
|
|
90
|
+
/** Parse a `--share-tools` flag value into a selection for {@link connectorServers}: flag absent
|
|
91
|
+
* → `undefined` (share all declared); `none` or empty → `[]` (share nothing); else the comma list. */
|
|
92
|
+
export function parseShareSelection(value) {
|
|
93
|
+
if (value === undefined)
|
|
94
|
+
return undefined;
|
|
95
|
+
const trimmed = value.trim();
|
|
96
|
+
if (trimmed === "" || trimmed.toLowerCase() === "none")
|
|
97
|
+
return [];
|
|
98
|
+
return trimmed
|
|
99
|
+
.split(",")
|
|
100
|
+
.map((s) => s.trim())
|
|
101
|
+
.filter(Boolean);
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=connector-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connector-config.js","sourceRoot":"","sources":["../src/connector-config.ts"],"names":[],"mappings":"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"}
|
package/dist/connector.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Extension } from "./registry.js";
|
|
2
|
+
import type { McpServerSpec } from "./connector-config.js";
|
|
2
3
|
/** Identity + mesh coordinates the manager hands a connector to launch an agent. */
|
|
3
4
|
export interface LaunchOpts {
|
|
4
5
|
space: string;
|
|
@@ -20,6 +21,16 @@ export interface LaunchOpts {
|
|
|
20
21
|
* that support an auto-submitted first prompt (Claude Code) deliver it; others
|
|
21
22
|
* ignore it. Used to make a driving session greet the operator on launch. */
|
|
22
23
|
prompt?: string;
|
|
24
|
+
/** Mirror this session's transcript to `tr-<name>` so peers/observers can read what
|
|
25
|
+
* the agent actually did (sets `COTAL_TRANSCRIPT`). Defaults to OFF; set `true` to
|
|
26
|
+
* opt in — surfaced as the `--transcript` flag on `cotal spawn` / `cotal start`. */
|
|
27
|
+
transcript?: boolean;
|
|
28
|
+
/** Operator MCP servers to SHARE with this agent, resolved from the cotal config by the caller
|
|
29
|
+
* (see {@link connectorServers}). Keyed by server name, `.mcp.json`-shaped, with `${VAR}`
|
|
30
|
+
* secret refs intact. A connector renders them into its own host format; the default is none
|
|
31
|
+
* (Claude launches isolated with `--strict-mcp-config`). Connectors that don't support sharing
|
|
32
|
+
* throw on a non-empty map rather than silently dropping it. */
|
|
33
|
+
mcpServers?: Record<string, McpServerSpec>;
|
|
23
34
|
}
|
|
24
35
|
/** A recipe for starting an agent as a mesh node — command, args, and extra env. */
|
|
25
36
|
export interface LaunchSpec {
|
package/dist/connector.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../src/connector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"connector.d.ts","sourceRoot":"","sources":["../src/connector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,oFAAoF;AACpF,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;8EAE0E;IAC1E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;mDAC+C;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;wEAEoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;kFAE8E;IAC9E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;yFAEqF;IACrF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;qEAIiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CAC5C;AAED,oFAAoF;AACpF,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B;;;+CAG2C;IAC3C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,SAAU,SAAQ,SAAS;IAC1C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;IAC1C;;;+DAG2D;IAC3D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B"}
|