@cotal-ai/connector-opencode 0.81.1 → 0.82.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.
@@ -1 +1 @@
1
- {"version":3,"file":"plugin2.d.ts","sourceRoot":"","sources":["../src/plugin2.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,gBAAgB,EAAkB,MAAM,sBAAsB,CAAC;AAiB7E;;;;;;8EAM8E;AAC9E,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAoC3C,4CAA4C;AAC5C,wBAAsB,UAAU,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAiW7F"}
1
+ {"version":3,"file":"plugin2.d.ts","sourceRoot":"","sources":["../src/plugin2.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,gBAAgB,EAAkB,MAAM,sBAAsB,CAAC;AAiB7E;;;;;;8EAM8E;AAC9E,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAoC3C,4CAA4C;AAC5C,wBAAsB,UAAU,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CA2W7F"}
package/dist/serve.js CHANGED
@@ -3,7 +3,7 @@ import { execFileSync, spawn } from "node:child_process";
3
3
  import { createServer } from "node:net";
4
4
  import { once } from "node:events";
5
5
  import { randomBytes } from "node:crypto";
6
- import { existsSync, mkdirSync, readFileSync, rmdirSync, rmSync, writeFileSync } from "node:fs";
6
+ import { existsSync, mkdirSync, readdirSync, readFileSync, rmdirSync, rmSync, writeFileSync } from "node:fs";
7
7
  import { delimiter, join } from "node:path";
8
8
 
9
9
  // src/opencode-line.ts
@@ -93,27 +93,35 @@ async function launch(tuiArgv, serveEnv) {
93
93
  if (!dataRoot) throw new Error("COTAL_OPENCODE_HOME is not set \u2014 the connector must pin the agent's data root");
94
94
  const agentHome = join(dataRoot, ".cotal", "opencode", name);
95
95
  const dbPath = join(agentHome, "opencode.db");
96
- const pidFile = join(agentHome, "serve.pid");
97
- let recorded;
96
+ let records = [];
98
97
  try {
99
- try {
100
- recorded = readFileSync(pidFile, "utf8");
101
- } catch (e) {
102
- if (e.code !== "EISDIR") throw e;
103
- rmdirSync(pidFile);
104
- }
98
+ records = readdirSync(agentHome).filter((file) => /^serve(?:\.[0-9a-f]{32})?\.pid$/.test(file));
105
99
  } catch (e) {
106
100
  if (e.code !== "ENOENT") throw e;
107
101
  }
108
- if (recorded !== void 0) {
102
+ for (const file of records) {
103
+ const record = join(agentHome, file);
104
+ let recorded;
105
+ try {
106
+ try {
107
+ recorded = readFileSync(record, "utf8");
108
+ } catch (e) {
109
+ if (e.code !== "EISDIR") throw e;
110
+ rmdirSync(record);
111
+ }
112
+ } catch (e) {
113
+ if (e.code !== "ENOENT") throw e;
114
+ }
115
+ if (recorded === void 0) continue;
109
116
  const pid = Number(recorded);
110
117
  if (isLiveOpencodeServe(pid))
111
118
  throw new Error(`agent "${name}" is already running (opencode serve pid ${pid}) \u2014 kill it first`);
112
- rmSync(pidFile, { force: true });
119
+ rmSync(record, { force: true });
113
120
  }
114
121
  const versionRaw = execFileSync(BIN, ["--version"], { encoding: "utf8" }).trim();
115
122
  const line = opencodeLine(versionRaw, BIN);
116
123
  mkdirSync(agentHome, { recursive: true });
124
+ const pidFile = join(agentHome, `serve.${randomBytes(16).toString("hex")}.pid`);
117
125
  const serveArgv = [BIN, "serve", "--hostname", "127.0.0.1", "--port", port];
118
126
  const [serveCommand, ...serveArgs] = process.platform === "win32" ? serveArgv : ["/bin/sh", "-c", RECORD_THEN_EXEC, "cotal-serve", pidFile, ...serveArgv];
119
127
  const serve = spawn(serveCommand, serveArgs, {
@@ -130,6 +138,12 @@ async function launch(tuiArgv, serveEnv) {
130
138
  });
131
139
  if (process.platform === "win32") writeFileSync(pidFile, String(serve.pid));
132
140
  serve.on("exit", () => rmSync(pidFile, { force: true }));
141
+ let tui;
142
+ for (const sig of ["SIGINT", "SIGTERM"])
143
+ process.on(sig, () => {
144
+ void terminate(serve);
145
+ if (tui) void terminate(tui);
146
+ });
133
147
  let sessionId;
134
148
  let attached = false;
135
149
  let onSession;
@@ -175,8 +189,6 @@ async function launch(tuiArgv, serveEnv) {
175
189
  if (process.env.COTAL_SERVE_HEADLESS?.trim() === "1") {
176
190
  process.stdout.write(`[cotal-serve] ${JSON.stringify({ port: Number(port), session: id })}
177
191
  `);
178
- for (const sig of ["SIGINT", "SIGTERM"])
179
- process.on(sig, () => void terminate(serve).then(() => process.exit(0)));
180
192
  return;
181
193
  }
182
194
  const tuiEnv = {
@@ -189,12 +201,7 @@ async function launch(tuiArgv, serveEnv) {
189
201
  for (const k of Object.keys(tuiEnv)) if (k.startsWith("COTAL_")) delete tuiEnv[k];
190
202
  attached = true;
191
203
  const [command, ...args] = tuiArgv({ url, session: id, line });
192
- const tui = spawn(command, args, { env: tuiEnv, stdio: "inherit" });
193
- for (const sig of ["SIGINT", "SIGTERM"])
194
- process.on(sig, () => {
195
- tui.kill(sig);
196
- serve.kill(sig);
197
- });
204
+ tui = spawn(command, args, { env: tuiEnv, stdio: "inherit" });
198
205
  serve.on("exit", () => void terminate(tui));
199
206
  tui.on("exit", (code, signal) => {
200
207
  void terminate(serve).then(() => process.exit(code ?? (signal ? 1 : 0)));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cotal-ai/connector-opencode",
3
3
  "description": "Cotal connector for OpenCode: a native in-process plugin that joins a session to the mesh.",
4
- "version": "0.81.1",
4
+ "version": "0.82.0",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -21,8 +21,8 @@
21
21
  "@cotal-ai/core": ">=0.1.0"
22
22
  },
23
23
  "devDependencies": {
24
- "@cotal-ai/connector-core": "0.81.1",
25
- "@cotal-ai/core": "0.81.1",
24
+ "@cotal-ai/connector-core": "0.82.0",
25
+ "@cotal-ai/core": "0.82.0",
26
26
  "@cotal-ai/smoke-kit": "0.0.0",
27
27
  "@nats-io/transport-node": "^3.4.0",
28
28
  "@opencode-ai/plugin": "^1.16.2",