@cotal-ai/connector-hermes 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.
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"AACA,OAAO,EAA2B,KAAK,SAAS,EAAoC,MAAM,gBAAgB,CAAC;AAW3G;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,SA6B7B,CAAC"}
1
+ {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"AACA,OAAO,EAA2B,KAAK,SAAS,EAAoC,MAAM,gBAAgB,CAAC;AAW3G;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,SAkC7B,CAAC"}
package/dist/extension.js CHANGED
@@ -23,6 +23,11 @@ export const hermesConnector = {
23
23
  name: "hermes",
24
24
  requires: ["hermes"],
25
25
  buildLaunch(opts) {
26
+ // Hermes is Unix-only: its sidecar bridge + hook relay use AF_UNIX `.sock` paths and a Python
27
+ // sidecar, none of which are ported to Windows. Fail loud rather than launch a half-wired agent
28
+ // the manager can't drive (no Windows named-pipe bridge, no cooperative shutdown). No fallback.
29
+ if (process.platform === "win32")
30
+ throw new Error("the Hermes connector is Unix-only (AF_UNIX bridge + Python sidecar) — not supported on Windows");
26
31
  // OS allow-list + the named model-provider key (Hermes is model-agnostic; any one unlocks a
27
32
  // provider), forwarded BY NAME — never `...process.env` — so the operator's unrelated secrets
28
33
  // don't reach the gateway child (P3).
@@ -1 +1 @@
1
- {"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAoD,MAAM,gBAAgB,CAAC;AAC3G,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAElF;;;2DAG2D;AAC3D,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACnE,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,0BAA0B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAChF,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,YAAY,SAAS,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAEtF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAc;IACxC,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,QAAQ,CAAC;IACpB,WAAW,CAAC,IAAgB;QAC1B,4FAA4F;QAC5F,8FAA8F;QAC9F,sCAAsC;QACtC,MAAM,GAAG,GAA2B;YAClC,GAAG,SAAS,CAAC,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC;YACnD,GAAG,MAAM,CAAC,IAAI,CAAC;YACf,WAAW,EAAE,IAAI,CAAC,KAAK;YACvB,UAAU,EAAE,IAAI,CAAC,IAAI;SACtB,CAAC;QACF,IAAI,IAAI,CAAC,IAAI;YAAE,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC;QAC1C,IAAI,IAAI,CAAC,EAAE;YAAE,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,KAAK;YAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC;QAC7C,IAAI,IAAI,CAAC,OAAO;YAAE,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC;QACnD,wFAAwF;QACxF,mFAAmF;QACnF,IAAI,IAAI,CAAC,UAAU;YAAE,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC,UAAU,CAAC;QAC5D,gGAAgG;QAChG,8FAA8F;QAC9F,2FAA2F;QAC3F,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QACrF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;QAClE,IAAI,KAAK;YAAE,GAAG,CAAC,YAAY,GAAG,KAAK,CAAC;QACpC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC;IACrD,CAAC;CACF,CAAC;AAEF,QAAQ,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC"}
1
+ {"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAoD,MAAM,gBAAgB,CAAC;AAC3G,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAElF;;;2DAG2D;AAC3D,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACnE,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,0BAA0B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAChF,MAAM,YAAY,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,YAAY,SAAS,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAEtF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,eAAe,GAAc;IACxC,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,QAAQ,CAAC;IACpB,WAAW,CAAC,IAAgB;QAC1B,8FAA8F;QAC9F,gGAAgG;QAChG,gGAAgG;QAChG,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;YAC9B,MAAM,IAAI,KAAK,CAAC,gGAAgG,CAAC,CAAC;QACpH,4FAA4F;QAC5F,8FAA8F;QAC9F,sCAAsC;QACtC,MAAM,GAAG,GAA2B;YAClC,GAAG,SAAS,CAAC,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC;YACnD,GAAG,MAAM,CAAC,IAAI,CAAC;YACf,WAAW,EAAE,IAAI,CAAC,KAAK;YACvB,UAAU,EAAE,IAAI,CAAC,IAAI;SACtB,CAAC;QACF,IAAI,IAAI,CAAC,IAAI;YAAE,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC;QAC1C,IAAI,IAAI,CAAC,EAAE;YAAE,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,KAAK;YAAE,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC;QAC7C,IAAI,IAAI,CAAC,OAAO;YAAE,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC;QACnD,wFAAwF;QACxF,mFAAmF;QACnF,IAAI,IAAI,CAAC,UAAU;YAAE,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC,UAAU,CAAC;QAC5D,gGAAgG;QAChG,8FAA8F;QAC9F,2FAA2F;QAC3F,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QACrF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;QAClE,IAAI,KAAK;YAAE,GAAG,CAAC,YAAY,GAAG,KAAK,CAAC;QACpC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,YAAY,CAAC,EAAE,GAAG,EAAE,CAAC;IACrD,CAAC;CACF,CAAC;AAEF,QAAQ,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC"}
package/dist/launch.js CHANGED
@@ -19,7 +19,7 @@ import { tmpdir } from "node:os";
19
19
  import { join } from "node:path";
20
20
  import { fileURLToPath } from "node:url";
21
21
  import { loadAgentFile } from "@cotal-ai/core";
22
- import { hasIdentity, configFromEnv, controlSocketPath, ORIENTATION_BOOTSTRAP } from "@cotal-ai/connector-core";
22
+ import { hasIdentity, configFromEnv, controlEndpoint, ORIENTATION_BOOTSTRAP } from "@cotal-ai/connector-core";
23
23
  import { startSidecar } from "./sidecar.js";
24
24
  /** Hermes API line this connector is written + pinned against (see pyproject.toml). A different
25
25
  * major.minor may move the plugin/platform/hook signatures, so we assert and fail loudly. */
@@ -96,10 +96,11 @@ async function main() {
96
96
  setupProfile(home, { model: process.env.HERMES_MODEL, persona });
97
97
  // Paths shared by the sidecar and the gateway child — set in our env so startSidecar reads
98
98
  // them, and forwarded verbatim to the child so the plugin connects to the same sockets/file.
99
- const controlSock = controlSocketPath(config.space, config.name);
99
+ const control = controlEndpoint(config.space, config.name);
100
100
  const bridgeSock = bridgeSocketPath(config.space, config.name);
101
101
  const toolsFile = join(home, "cotal-tools.json");
102
- process.env.COTAL_CONTROL_SOCKET = controlSock;
102
+ process.env.COTAL_CONTROL_SOCKET = control.path;
103
+ process.env.COTAL_CONTROL_TOKEN = control.token; // first-frame auth, shared sidecar↔plugin via env
103
104
  process.env.COTAL_BRIDGE_SOCKET = bridgeSock;
104
105
  process.env.COTAL_TOOLS_FILE = toolsFile;
105
106
  const sidecar = startSidecar();
@@ -108,7 +109,8 @@ async function main() {
108
109
  const childEnv = {
109
110
  ...process.env,
110
111
  HERMES_HOME: home,
111
- COTAL_CONTROL_SOCKET: controlSock,
112
+ COTAL_CONTROL_SOCKET: control.path,
113
+ COTAL_CONTROL_TOKEN: control.token,
112
114
  COTAL_BRIDGE_SOCKET: bridgeSock,
113
115
  COTAL_TOOLS_FILE: toolsFile,
114
116
  };
@@ -1 +1 @@
1
- {"version":3,"file":"launch.js","sourceRoot":"","sources":["../src/launch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"launch.js","sourceRoot":"","sources":["../src/launch.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"sidecar.d.ts","sourceRoot":"","sources":["../src/sidecar.ts"],"names":[],"mappings":"AAgBA,OAAO,EAEL,SAAS,EAET,KAAK,WAAW,EACjB,MAAM,0BAA0B,CAAC;AAKlC,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAQD;gGACgG;AAChG,wBAAgB,YAAY,IAAI,OAAO,CAiCtC"}
1
+ {"version":3,"file":"sidecar.d.ts","sourceRoot":"","sources":["../src/sidecar.ts"],"names":[],"mappings":"AAgBA,OAAO,EAEL,SAAS,EAET,KAAK,WAAW,EACjB,MAAM,0BAA0B,CAAC;AAKlC,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,WAAW,CAAC;IACpB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAQD;gGACgG;AAChG,wBAAgB,YAAY,IAAI,OAAO,CAwCtC"}
package/dist/sidecar.js CHANGED
@@ -32,9 +32,11 @@ export function startSidecar() {
32
32
  const agent = new MeshAgent(config);
33
33
  agent.start(); // background connect with retry
34
34
  const controlSock = need("COTAL_CONTROL_SOCKET");
35
+ const controlToken = need("COTAL_CONTROL_TOKEN");
35
36
  const bridgeSock = need("COTAL_BRIDGE_SOCKET");
36
37
  const toolsFile = need("COTAL_TOOLS_FILE");
37
- const controlServer = startControlServer(agent, controlSock, hermesHookHandle);
38
+ // Managed listener: own the endpoint (fatal bind) and authenticate every frame against the token.
39
+ const controlServer = startControlServer(agent, { path: controlSock, token: controlToken }, hermesHookHandle, { fatalBind: true });
38
40
  const bridge = startBridgeServer(agent, config, bridgeSock);
39
41
  // The plugin reads this at register(ctx) time to declare the cotal_* tools (full shared parity).
40
42
  writeFileSync(toolsFile, JSON.stringify(hermesToolDescriptors(config)));
@@ -1 +1 @@
1
- {"version":3,"file":"sidecar.js","sourceRoot":"","sources":["../src/sidecar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EACL,aAAa,EACb,SAAS,EACT,kBAAkB,GAEnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAQzD,SAAS,IAAI,CAAC,IAAY;IACxB,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,wEAAwE,CAAC,CAAC;IACzG,OAAO,CAAC,CAAC;AACX,CAAC;AAED;gGACgG;AAChG,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,MAAM,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC,+DAA+D;IAC5F,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;IACpC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,gCAAgC;IAE/C,MAAM,WAAW,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACjD,MAAM,UAAU,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAE3C,MAAM,aAAa,GAAG,kBAAkB,CAAC,KAAK,EAAE,WAAW,EAAE,gBAAgB,CAAC,CAAC;IAC/E,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IAE5D,iGAAiG;IACjG,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAExE,OAAO;QACL,KAAK;QACL,MAAM;QACN,KAAK,CAAC,IAAI;YACR,IAAI,CAAC;gBACH,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,CAAC;YAAC,MAAM,CAAC;gBACP,YAAY;YACd,CAAC;YACD,IAAI,CAAC;gBACH,aAAa,CAAC,KAAK,EAAE,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACP,YAAY;YACd,CAAC;YACD,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QACrB,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"sidecar.js","sourceRoot":"","sources":["../src/sidecar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EACL,aAAa,EACb,SAAS,EACT,kBAAkB,GAEnB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAQzD,SAAS,IAAI,CAAC,IAAY;IACxB,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,wEAAwE,CAAC,CAAC;IACzG,OAAO,CAAC,CAAC;AACX,CAAC;AAED;gGACgG;AAChG,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,MAAM,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC,+DAA+D;IAC5F,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;IACpC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,gCAAgC;IAE/C,MAAM,WAAW,GAAG,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACjD,MAAM,YAAY,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACjD,MAAM,UAAU,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,kBAAkB,CAAC,CAAC;IAE3C,kGAAkG;IAClG,MAAM,aAAa,GAAG,kBAAkB,CACtC,KAAK,EACL,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,EAC1C,gBAAgB,EAChB,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAC;IACF,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;IAE5D,iGAAiG;IACjG,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAExE,OAAO;QACL,KAAK;QACL,MAAM;QACN,KAAK,CAAC,IAAI;YACR,IAAI,CAAC;gBACH,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,CAAC;YAAC,MAAM,CAAC;gBACP,YAAY;YACd,CAAC;YACD,IAAI,CAAC;gBACH,aAAa,CAAC,KAAK,EAAE,CAAC;YACxB,CAAC;YAAC,MAAM,CAAC;gBACP,YAAY;YACd,CAAC;YACD,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QACrB,CAAC;KACF,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cotal-ai/connector-hermes",
3
3
  "description": "Cotal connector for the Hermes (Nous Research) agent.",
4
- "version": "0.8.0",
4
+ "version": "0.8.2",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -23,14 +23,14 @@
23
23
  "dependencies": {
24
24
  "tsx": "^4.22.4",
25
25
  "zod": "^4.4.3",
26
- "@cotal-ai/connector-core": "0.8.0"
26
+ "@cotal-ai/connector-core": "0.8.2"
27
27
  },
28
28
  "peerDependencies": {
29
29
  "@cotal-ai/core": ">=0.1.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "esbuild": "^0.28.0",
33
- "@cotal-ai/core": "0.8.0"
33
+ "@cotal-ai/core": "0.8.2"
34
34
  },
35
35
  "files": [
36
36
  "bin",
@@ -16,6 +16,7 @@ in the environment. Two run modes:
16
16
  from __future__ import annotations
17
17
 
18
18
  import os
19
+ import secrets
19
20
  import shutil
20
21
  import subprocess
21
22
  import tempfile
@@ -99,6 +100,10 @@ def _bootstrap_standalone_sidecar() -> None:
99
100
  space = os.environ.get("COTAL_SPACE") or "(from COTAL_LINK)"
100
101
  os.environ.setdefault("COTAL_BRIDGE_SOCKET", str(run_dir / "bridge.sock"))
101
102
  os.environ.setdefault("COTAL_CONTROL_SOCKET", str(run_dir / "control.sock"))
103
+ # The sidecar (listener) and the lifecycle hooks (this process) authenticate the control plane
104
+ # with a shared first-frame token. Managed mode gets it from the launcher; standalone mints one
105
+ # here so both sides — they share this env — agree on it.
106
+ os.environ.setdefault("COTAL_CONTROL_TOKEN", secrets.token_urlsafe(32))
102
107
  os.environ.setdefault("COTAL_TOOLS_FILE", str(run_dir / "cotal-tools.json"))
103
108
 
104
109
  sidecar = _resolve_sidecar_js()
@@ -14858,6 +14858,10 @@ function deliveryBucket(space) {
14858
14858
  function leaseKey(shardIndex) {
14859
14859
  return `lease.${shardIndex}`;
14860
14860
  }
14861
+ function managerBucket(space) {
14862
+ return `cotal_manager_${token(space)}`;
14863
+ }
14864
+ var MANAGER_LEASE_KEY = "lease";
14861
14865
  function chatStream(space) {
14862
14866
  return `CHAT_${token(space)}`;
14863
14867
  }
@@ -14942,6 +14946,8 @@ function assertValidName(name) {
14942
14946
  throw new Error(`invalid name ${JSON.stringify(name)}: must be a single line`);
14943
14947
  if (name.includes("/"))
14944
14948
  throw new Error(`invalid name ${JSON.stringify(name)}: "/" is reserved (the owner/name separator)`);
14949
+ if (name.includes("\\"))
14950
+ throw new Error(`invalid name ${JSON.stringify(name)}: "\\" is reserved (a Windows path separator)`);
14945
14951
  }
14946
14952
 
14947
14953
  // ../../packages/core/dist/link.js
@@ -16615,6 +16621,7 @@ var import_kv = __toESM(require_mod6(), 1);
16615
16621
  var MAX_MSGS_PER_SUBJECT = 1e3;
16616
16622
  var PLANE3_DEDUP_WINDOW_MS = 2 * 60 * 60 * 1e3;
16617
16623
  var DINBOX_MAX_ACK_PENDING = 1e3;
16624
+ var MANAGER_LEASE_TTL_MS = 1e4;
16618
16625
  var MEMBERSHIP_MAX_BYTES = 64 * 1024 * 1024;
16619
16626
  async function createSpaceStreams(jsm, space) {
16620
16627
  const p = spacePrefix(space);
@@ -17035,6 +17042,9 @@ function loadAgentFile(path) {
17035
17042
  };
17036
17043
  }
17037
17044
 
17045
+ // ../../packages/core/dist/secret-fs.js
17046
+ var isWin = process.platform === "win32";
17047
+
17038
17048
  // ../../packages/core/dist/endpoint.js
17039
17049
  var import_node_events = require("node:events");
17040
17050
  var import_node_crypto = require("node:crypto");
@@ -17070,6 +17080,7 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
17070
17080
  membersKv;
17071
17081
  aclKv;
17072
17082
  deliveryKv;
17083
+ managerLeaseKv;
17073
17084
  membershipKv;
17074
17085
  /** The live `ctl.delivery` serve subscription (delivery daemon) — re-created on every (re)connect by
17075
17086
  * {@link armDeliveryControl}; tracked so the stale one is dropped on reconnect. */
@@ -17999,6 +18010,68 @@ var CotalEndpoint = class extends import_node_events.EventEmitter {
17999
18010
  return void 0;
18000
18011
  }
18001
18012
  }
18013
+ /** Ensure + bind the manager singleton-lease bucket. NOTE: `Kvm.open` binds LAZILY — it does NOT
18014
+ * verify the stream exists or throw when it's missing, so it can't "create if absent" (a fresh bucket
18015
+ * then fails 'stream not found' on the first write — unlike the delivery bucket, which is pre-created
18016
+ * at `cotal up`). `create` is the ensure-exists call: it makes the bucket (bucket-level TTL) or, when
18017
+ * another manager already did, throws — and we bind the now-existing one. Either way the per-KEY CAS
18018
+ * create stays the only single-flight gate, so a lost bucket-create race never reads as "lease held".
18019
+ * The manager is allow-all, so it may create. */
18020
+ async managerLeaseRegistry() {
18021
+ if (!this.nc)
18022
+ throw new Error("endpoint not started");
18023
+ if (this.managerLeaseKv)
18024
+ return this.managerLeaseKv;
18025
+ const kvm = new import_kv7.Kvm(this.nc);
18026
+ try {
18027
+ this.managerLeaseKv = await kvm.create(managerBucket(this.space), { ttl: MANAGER_LEASE_TTL_MS });
18028
+ } catch {
18029
+ this.managerLeaseKv = await kvm.open(managerBucket(this.space));
18030
+ }
18031
+ return this.managerLeaseKv;
18032
+ }
18033
+ encodeManagerLease(info) {
18034
+ return new TextEncoder().encode(JSON.stringify(info));
18035
+ }
18036
+ /** Acquire the singleton manager lease via ATOMIC CAS create. THROWS if a live lease exists (a loud
18037
+ * refusal-to-start, never a retry) so two managers never split control. A crashed holder's lease
18038
+ * auto-expires (bucket TTL). Returns the lease revision (for renew). */
18039
+ async acquireManagerLease(info) {
18040
+ return (await this.managerLeaseRegistry()).create(MANAGER_LEASE_KEY, this.encodeManagerLease({ ...info, since: Date.now() }));
18041
+ }
18042
+ /** Renew the held lease (CAS update against `revision`) before the bucket TTL expires it. Throws if the
18043
+ * revision moved (lost the lease). Returns the new revision. */
18044
+ async renewManagerLease(info, revision) {
18045
+ return (await this.managerLeaseRegistry()).update(MANAGER_LEASE_KEY, this.encodeManagerLease({ ...info, since: Date.now() }), revision);
18046
+ }
18047
+ /** Release the held lease on clean shutdown so a replacement manager acquires immediately. CAS-guarded
18048
+ * by `revision`: if we already LOST the lease (renew gap / another manager took over) the stored
18049
+ * revision has moved, the conditional delete no-ops, and we never delete the replacement's live lease. */
18050
+ async releaseManagerLease(revision) {
18051
+ try {
18052
+ const kv = await this.managerLeaseRegistry();
18053
+ if (revision === void 0)
18054
+ await kv.delete(MANAGER_LEASE_KEY);
18055
+ else
18056
+ await kv.delete(MANAGER_LEASE_KEY, { previousSeq: revision });
18057
+ } catch {
18058
+ }
18059
+ }
18060
+ /** Read the live manager lease, or undefined if none (bucket absent / key deleted/expired). Open-only —
18061
+ * never creates the bucket, so a probe that finds no manager leaves none behind. */
18062
+ async readManagerLease() {
18063
+ if (!this.nc)
18064
+ return void 0;
18065
+ try {
18066
+ const kv = await new import_kv7.Kvm(this.nc).open(managerBucket(this.space));
18067
+ const e = await kv.get(MANAGER_LEASE_KEY);
18068
+ if (!e || e.operation === "DEL" || e.operation === "PURGE")
18069
+ return void 0;
18070
+ return e.json();
18071
+ } catch {
18072
+ return void 0;
18073
+ }
18074
+ }
18002
18075
  /** Privileged: one owner's NON-TOMBSTONED durable memberships as `{channel, generation, activated}` —
18003
18076
  * the server-side delivery daemon serves this to a connecting agent (the `listMemberships` op on
18004
18077
  * `ctl.delivery`). The agent seeds its leave mirror from the ACTIVATED ones (the confirmed backstops),
@@ -19635,14 +19708,15 @@ var MeshAgent = class extends import_node_events2.EventEmitter {
19635
19708
  /** Ask the manager to spawn a new teammate into this space (its `start` op).
19636
19709
  * How it lands — a detached PTY, a tmux window, a cmux tab — is the manager's
19637
19710
  * runtime; from here it just joins the mesh as a lateral peer. `opts.agent` picks
19638
- * the harness (default the manager's `cotal`/Claude) and `opts.model` overrides the
19639
- * persona file's `model:` the same knobs the operator's `cotal start` carries, so
19711
+ * the harness (default the manager's `cotal`/Claude), `opts.model` overrides the
19712
+ * persona file's `model:`, and `opts.cwd` roots the new peer at a different folder/repo
19713
+ * than the manager's workspace — the same knobs the operator's `cotal start` carries, so
19640
19714
  * the agent and operator spawn doors share one control-op contract. */
19641
19715
  async spawn(name, role, opts) {
19642
19716
  this.assertConnected();
19643
19717
  return this.ep.requestControl(CONTROL_PRIVILEGED, {
19644
19718
  op: "start",
19645
- args: { name, role, agent: opts?.agent, model: opts?.model }
19719
+ args: { name, role, agent: opts?.agent, model: opts?.model, cwd: opts?.cwd }
19646
19720
  });
19647
19721
  }
19648
19722
  /** Ask the manager to tear a teammate down (its `stop` op). Graceful by default —
@@ -34718,11 +34792,12 @@ ${info}${caught}`);
34718
34792
  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."),
34719
34793
  role: external_exports.string().optional().describe("Optional role for the new peer (e.g. worker, reviewer); overrides the persona file's role."),
34720
34794
  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)."),
34721
- model: external_exports.string().optional().describe("Optional model override (e.g. opus, sonnet) \u2014 wins over the persona file's model:.")
34795
+ model: external_exports.string().optional().describe("Optional model override (e.g. opus, sonnet) \u2014 wins over the persona file's model:."),
34796
+ 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.")
34722
34797
  },
34723
- async run(agent, _config, { name, role, agent: agentType, model }) {
34798
+ async run(agent, _config, { name, role, agent: agentType, model, cwd }) {
34724
34799
  try {
34725
- const reply = await agent.spawn(name, role, { agent: agentType, model });
34800
+ const reply = await agent.spawn(name, role, { agent: agentType, model, cwd });
34726
34801
  if (!reply.ok)
34727
34802
  return err(`Couldn't spawn ${name}: ${reply.error ?? "manager refused"}`);
34728
34803
  const d = reply.data;
@@ -34842,26 +34917,61 @@ ${info}${caught}`);
34842
34917
  // ../connector-core/dist/control.js
34843
34918
  var import_node_net = require("node:net");
34844
34919
  var import_node_fs3 = require("node:fs");
34845
- function startControlServer(agent, socketPath, handle) {
34846
- if ((0, import_node_fs3.existsSync)(socketPath)) {
34920
+ var import_node_crypto2 = require("node:crypto");
34921
+ var MAX_FRAME_BYTES = 1 << 20;
34922
+ var AUTH_DEADLINE_MS = 5e3;
34923
+ function tokenMatches(presented, digest) {
34924
+ if (typeof presented !== "string")
34925
+ return false;
34926
+ return (0, import_node_crypto2.timingSafeEqual)((0, import_node_crypto2.createHash)("sha256").update(presented).digest(), digest);
34927
+ }
34928
+ function startControlServer(agent, endpoint, handle, opts = {}) {
34929
+ const { path } = endpoint;
34930
+ const digest = (0, import_node_crypto2.createHash)("sha256").update(endpoint.token).digest();
34931
+ if (process.platform !== "win32" && (0, import_node_fs3.existsSync)(path)) {
34847
34932
  try {
34848
- (0, import_node_fs3.unlinkSync)(socketPath);
34933
+ (0, import_node_fs3.unlinkSync)(path);
34849
34934
  } catch {
34850
34935
  }
34851
34936
  }
34852
34937
  const server = (0, import_node_net.createServer)((sock) => {
34853
34938
  let buf = "";
34939
+ let handled = false;
34854
34940
  sock.setEncoding("utf8");
34941
+ const deadline = setTimeout(() => sock.destroy(), AUTH_DEADLINE_MS);
34942
+ deadline.unref?.();
34943
+ sock.on("close", () => clearTimeout(deadline));
34855
34944
  sock.on("data", async (d) => {
34945
+ if (handled)
34946
+ return;
34856
34947
  buf += d;
34948
+ if (buf.length > MAX_FRAME_BYTES) {
34949
+ sock.destroy();
34950
+ return;
34951
+ }
34857
34952
  const nl = buf.indexOf("\n");
34858
34953
  if (nl < 0)
34859
34954
  return;
34860
- let ev = {};
34955
+ handled = true;
34956
+ clearTimeout(deadline);
34957
+ let frame = {};
34861
34958
  try {
34862
- ev = JSON.parse(buf.slice(0, nl) || "{}");
34959
+ frame = JSON.parse(buf.slice(0, nl) || "{}");
34863
34960
  } catch {
34864
34961
  }
34962
+ if (!tokenMatches(frame.token, digest)) {
34963
+ sock.destroy();
34964
+ return;
34965
+ }
34966
+ if (frame.op === "shutdown") {
34967
+ try {
34968
+ sock.end(JSON.stringify({ ok: true }) + "\n");
34969
+ } catch {
34970
+ }
34971
+ opts.onShutdown?.();
34972
+ return;
34973
+ }
34974
+ const ev = frame.event ?? {};
34865
34975
  const reply = await handle(agent, ev);
34866
34976
  try {
34867
34977
  sock.end(JSON.stringify(reply) + "\n");
@@ -34871,10 +34981,18 @@ function startControlServer(agent, socketPath, handle) {
34871
34981
  sock.on("error", () => {
34872
34982
  });
34873
34983
  });
34874
- server.on("error", (e) => process.stderr.write(`[cotal-connector] control server error: ${e.message}
34875
- `));
34876
- server.listen(socketPath, () => process.stderr.write(`[cotal-connector] control socket: ${socketPath}
34877
- `));
34984
+ let bound = false;
34985
+ server.on("error", (e) => {
34986
+ process.stderr.write(`[cotal-connector] control server error: ${e.message}
34987
+ `);
34988
+ if (opts.fatalBind && !bound)
34989
+ process.exit(1);
34990
+ });
34991
+ server.listen(path, () => {
34992
+ bound = true;
34993
+ process.stderr.write(`[cotal-connector] control socket: ${path}
34994
+ `);
34995
+ });
34878
34996
  return server;
34879
34997
  }
34880
34998
 
@@ -35091,9 +35209,15 @@ function startSidecar() {
35091
35209
  const agent = new MeshAgent(config2);
35092
35210
  agent.start();
35093
35211
  const controlSock = need("COTAL_CONTROL_SOCKET");
35212
+ const controlToken = need("COTAL_CONTROL_TOKEN");
35094
35213
  const bridgeSock = need("COTAL_BRIDGE_SOCKET");
35095
35214
  const toolsFile = need("COTAL_TOOLS_FILE");
35096
- const controlServer = startControlServer(agent, controlSock, hermesHookHandle);
35215
+ const controlServer = startControlServer(
35216
+ agent,
35217
+ { path: controlSock, token: controlToken },
35218
+ hermesHookHandle,
35219
+ { fatalBind: true }
35220
+ );
35097
35221
  const bridge = startBridgeServer(agent, config2, bridgeSock);
35098
35222
  (0, import_node_fs5.writeFileSync)(toolsFile, JSON.stringify(hermesToolDescriptors(config2)));
35099
35223
  return {
@@ -1,9 +1,11 @@
1
1
  """Hermes lifecycle hooks → Cotal presence (the relay.ts pattern, in Python).
2
2
 
3
3
  Each hook makes a one-shot connection to connector-core's control socket
4
- (``COTAL_CONTROL_SOCKET``), sends ``{"hook_event_name": ...}``, and ignores the reply — the TS
5
- ``hermesHookHandle`` turns it into a presence change. Hooks must never block the gateway, so the
6
- connection has a short timeout and every error is swallowed.
4
+ (``COTAL_CONTROL_SOCKET``), sends ``{"token": ..., "event": {"hook_event_name": ...}}``, and
5
+ ignores the reply — the TS ``hermesHookHandle`` turns it into a presence change. The control server
6
+ validates ``token`` (constant-time) before doing anything, so a frame without it is dropped. Both
7
+ the path and token come from the launch env (shared with the sidecar). Hooks must never block the
8
+ gateway, so the connection has a short timeout and every error is swallowed.
7
9
 
8
10
  Hermes hook callback signatures vary by version; these take ``*args, **kwargs`` and best-effort
9
11
  extract what they need, so a signature change degrades to "no detail" rather than an exception.
@@ -21,9 +23,10 @@ _TIMEOUT_S = 2.0
21
23
  def relay(event_name: str, **fields: Any) -> None:
22
24
  """Forward one lifecycle event to the connector's control socket; fire-and-forget."""
23
25
  path = os.environ.get("COTAL_CONTROL_SOCKET")
24
- if not path:
26
+ token = os.environ.get("COTAL_CONTROL_TOKEN")
27
+ if not path or not token:
25
28
  return
26
- payload = {"hook_event_name": event_name, **fields}
29
+ payload = {"token": token, "event": {"hook_event_name": event_name, **fields}}
27
30
  try:
28
31
  s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
29
32
  s.settimeout(_TIMEOUT_S)