lattice-talk 0.1.4 → 0.1.5

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 CHANGED
@@ -90,17 +90,25 @@ Run `lattice-talk bridge gemini` to spawn a Gemini agent into your configured wo
90
90
  | Codex | `codex app-server` — injects into an in-flight turn via `turn/steer` |
91
91
  | Windsurf | Not supported — Windsurf has no public programmatic session API |
92
92
 
93
- Two things to know about the bridge: the harness CLI must be installed and logged in on the machine running the bridge, and bridged sessions auto-approve tool permissions so the agent can work unattended — run it with the same trust you'd give a `--dangerously-skip-permissions` session.
93
+ Two things to know about the bridge: the harness CLI must be installed and logged in on the machine running the bridge (for Claude the bridge downloads the `claude-code-acp` adapter via `npx` on first run), and bridged sessions auto-approve tool permissions so the agent can work unattended — run it with the same trust you'd give a `--dangerously-skip-permissions` session.
94
94
 
95
95
  **Windsurf** stays on the MCP path: `mcp add windsurf` gives its agents `pull_messages` with `wait_ms`, which still wakes them the instant a message is published — it just requires the agent to ask.
96
96
 
97
+ ### Which delivery should I use?
98
+
99
+ - **`mcp add`** — every harness, any agent you run yourself. Near-instant delivery via wake-up polling.
100
+ - **`bridge`** — when you want an agent that receives messages *without asking*, e.g. an always-on coordinator or a reviewer you want to react to every message immediately.
101
+
102
+ Both can run side by side on the same workspace.
103
+
97
104
  ## Requirements
98
105
 
99
106
  | Requirement | Needed for |
100
107
  | --- | --- |
101
- | Node.js 20+ | The MCP server (`serve`) that harnesses run |
108
+ | Node.js 20+ | The MCP server (`serve`) and the bridge |
102
109
  | Redis | Sharing messages between agent processes — local, Docker, remote, or managed |
103
110
  | Bun, or Node.js 26.4+ | The interactive dashboard (OpenTUI renders via native FFI) |
111
+ | The harness CLI (`claude`, `codex`, `gemini`, or `agent`) | `lattice-talk bridge` for that harness — installed and logged in |
104
112
 
105
113
  The dashboard auto-detects a compatible runtime and tells you clearly if none is found. The MCP server itself needs only plain Node 20+.
106
114
 
package/dist/index.js CHANGED
@@ -21086,7 +21086,7 @@ init_esm_shims();
21086
21086
  // package.json
21087
21087
  var package_default = {
21088
21088
  name: "lattice-talk",
21089
- version: "0.1.4",
21089
+ version: "0.1.5",
21090
21090
  description: "Lattice \u2014 Cross-Harness MCP Session Bus. Shared sessions, DMs, rooms, memory, and OpenTelemetry for agents across Claude Code, Cursor, Codex, and custom harnesses.",
21091
21091
  type: "module",
21092
21092
  main: "./dist/index.js",
@@ -22442,11 +22442,17 @@ var NdjsonRpc = class {
22442
22442
  const errRl = createInterface({ input: this.proc.stderr });
22443
22443
  errRl.on("line", (line) => opts.onStderr(line));
22444
22444
  }
22445
- this.proc.on("exit", (code) => {
22445
+ const failAll = (err2) => {
22446
22446
  this.closed = true;
22447
- const err2 = new Error(`process exited with code ${code}`);
22448
22447
  for (const p of this.pending.values()) p.reject(err2);
22449
22448
  this.pending.clear();
22449
+ };
22450
+ this.proc.on("error", (e) => {
22451
+ failAll(e);
22452
+ opts.onExit?.(null);
22453
+ });
22454
+ this.proc.on("exit", (code) => {
22455
+ failAll(new Error(`process exited with code ${code}`));
22450
22456
  opts.onExit?.(code);
22451
22457
  });
22452
22458
  }
@@ -22579,7 +22585,10 @@ var AcpDriver = class {
22579
22585
  env: opts.env,
22580
22586
  shell: this.shell,
22581
22587
  onStderr: (line) => onEvent(`[${this.id}] ${line}`),
22582
- onExit: (code) => onEvent(`[${this.id}] exited (code ${code ?? "?"})`)
22588
+ onExit: (code) => {
22589
+ onEvent(`[${this.id}] exited (code ${code ?? "?"})`);
22590
+ opts.onExit?.(code);
22591
+ }
22583
22592
  });
22584
22593
  this.rpc = rpc;
22585
22594
  rpc.onRequest("session/request_permission", (params) => {
@@ -22609,15 +22618,16 @@ var AcpDriver = class {
22609
22618
  if (text) onEvent(`[${this.id}] ${text}`);
22610
22619
  }
22611
22620
  });
22612
- const init = await rpc.request("initialize", {
22613
- protocolVersion: ACP_PROTOCOL_VERSION,
22614
- clientCapabilities: {
22615
- fs: { readTextFile: false, writeTextFile: false },
22616
- terminal: false
22617
- },
22618
- clientInfo: { name: "lattice-talk-bridge", version: "0" }
22619
- });
22621
+ let init;
22620
22622
  try {
22623
+ init = await rpc.request("initialize", {
22624
+ protocolVersion: ACP_PROTOCOL_VERSION,
22625
+ clientCapabilities: {
22626
+ fs: { readTextFile: false, writeTextFile: false },
22627
+ terminal: false
22628
+ },
22629
+ clientInfo: { name: "lattice-talk-bridge", version: "0" }
22630
+ });
22621
22631
  const res = await rpc.request("session/new", {
22622
22632
  cwd: opts.cwd,
22623
22633
  mcpServers: opts.mcpServers.map(serializeMcpServer)
@@ -22685,7 +22695,10 @@ var CodexDriver = class {
22685
22695
  env: opts.env,
22686
22696
  shell: this.shell,
22687
22697
  onStderr: (line) => onEvent(`[codex] ${line}`),
22688
- onExit: (code) => onEvent(`[codex] exited (code ${code ?? "?"})`)
22698
+ onExit: (code) => {
22699
+ onEvent(`[codex] exited (code ${code ?? "?"})`);
22700
+ opts.onExit?.(code);
22701
+ }
22689
22702
  });
22690
22703
  this.rpc = rpc;
22691
22704
  rpc.onNotification("turn/started", (params) => {
@@ -22899,7 +22912,11 @@ async function runBridge(opts) {
22899
22912
  suggestedAgentId: opts.agentId,
22900
22913
  tokenProtected: Boolean(opts.conn.joinToken)
22901
22914
  }),
22902
- onEvent: log2
22915
+ onEvent: log2,
22916
+ onExit: (code) => {
22917
+ log2(`[bridge] agent process exited (code ${code ?? "?"}) \u2014 shutting down.`);
22918
+ stop.abort();
22919
+ }
22903
22920
  });
22904
22921
  log2(`[bridge] ${opts.harness} session up \u2014 injecting room "${roomId}" traffic into it.`);
22905
22922
  if (bridgedAgentId) {
@@ -22922,13 +22939,15 @@ async function runBridge(opts) {
22922
22939
  }
22923
22940
  }
22924
22941
  );
22942
+ await sweep();
22925
22943
  const sweepTimer = setInterval(() => void sweep(), SWEEP_MS);
22926
- const discoveryTimer = setTimeout(
22927
- () => log2(
22928
- "[bridge] still waiting for the agent to join the workspace \u2014 check that it ran join_session."
22929
- ),
22930
- DISCOVERY_TIMEOUT_MS
22931
- );
22944
+ const discoveryTimer = setTimeout(() => {
22945
+ if (!bridgedAgentId) {
22946
+ log2(
22947
+ "[bridge] still waiting for the agent to join the workspace \u2014 check that it ran join_session."
22948
+ );
22949
+ }
22950
+ }, DISCOVERY_TIMEOUT_MS);
22932
22951
  const onSignal = () => stop.abort();
22933
22952
  process.on("SIGINT", onSignal);
22934
22953
  process.on("SIGTERM", onSignal);