@supermux/core 0.1.0 → 0.14.1

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.
@@ -137,6 +137,9 @@ async function main() {
137
137
  const currentAttacherRequestIds = new Set();
138
138
  let shuttingDown = false;
139
139
  let exitedKeeper = false;
140
+ // Whether a client has attached yet, and, while none has, the wait for it after the agent exited (see 'close').
141
+ let attachedOnce = false;
142
+ let awaitingFirstClient;
140
143
  let journalRewrites = 0;
141
144
  let statusTimer;
142
145
  let lastFlushedKeys = { agentPid: 0, agentExited: undefined, metaKey: '', error: undefined, firstSeq: 1 };
@@ -342,13 +345,21 @@ async function main() {
342
345
  agent.on('close', (code, signal) => {
343
346
  agentExited = code ?? (signal ? 1 : 0);
344
347
  writeStatus(true);
345
- sendClient(client, { type: 'exit', code: agentExited });
346
- finish();
348
+ if (client || attachedOnce || shuttingDown) {
349
+ sendClient(client, { type: 'exit', code: agentExited });
350
+ finish();
351
+ return;
352
+ }
353
+ // No client has attached yet: the one that started this keeper is still on its way, and an agent that fails as it
354
+ // starts (a refused login, an ineligible account) is gone within milliseconds. That client gets the agent's output
355
+ // and exit when it attaches (attach); a keeper no client attaches to within connectTimeoutMs goes.
356
+ awaitingFirstClient = setTimeout(finish, limits.connectTimeoutMs);
347
357
  });
348
358
  function finish() {
349
359
  if (exitedKeeper)
350
360
  return;
351
361
  exitedKeeper = true;
362
+ clearTimeout(awaitingFirstClient);
352
363
  try {
353
364
  server.close();
354
365
  }
@@ -390,6 +401,7 @@ async function main() {
390
401
  catch { /* */ }
391
402
  }
392
403
  client = sock;
404
+ attachedOnce = true;
393
405
  currentAttacherRequestIds.clear();
394
406
  sendClient(sock, {
395
407
  type: 'welcome',
@@ -426,6 +438,12 @@ async function main() {
426
438
  for (const p of [...parked.values()].sort((a, b) => a.seq - b.seq)) {
427
439
  sendClient(sock, { type: 'parked', seq: p.seq, line: p.line });
428
440
  }
441
+ if (agentExited !== undefined) {
442
+ // The agent went before this first client came (see 'close'): after its output, its exit, as a client attached
443
+ // all along would have had them; the keeper goes once they are written.
444
+ sendClient(sock, { type: 'exit', code: agentExited });
445
+ sock.end(() => finish());
446
+ }
429
447
  }
430
448
  function onClientLine(sock, raw) {
431
449
  let msg;
@@ -498,6 +516,9 @@ async function main() {
498
516
  sendClient(sock, { type: 'error', message: 'invalid frame' });
499
517
  return;
500
518
  }
519
+ // An agent that exited reads nothing: its stdin is closed, and writing there would only fail.
520
+ if (agentExited !== undefined)
521
+ return;
501
522
  const line = msg.line.endsWith('\n') ? msg.line.slice(0, -1) : msg.line;
502
523
  const bytes = Buffer.byteLength(line + '\n');
503
524
  if (bytes > limits.maxFrameBytes) {
package/dist/version.d.ts CHANGED
@@ -2,4 +2,4 @@
2
2
  * The version of this package, announced to agents as the `clientInfo` version of their handshake.
3
3
  * Keep it equal to `version` in package.json: tests/alias.test.ts fails when they differ.
4
4
  */
5
- export declare const LIBRARY_VERSION = "0.1.0";
5
+ export declare const LIBRARY_VERSION = "0.14.1";
package/dist/version.js CHANGED
@@ -2,4 +2,4 @@
2
2
  * The version of this package, announced to agents as the `clientInfo` version of their handshake.
3
3
  * Keep it equal to `version` in package.json: tests/alias.test.ts fails when they differ.
4
4
  */
5
- export const LIBRARY_VERSION = "0.1.0";
5
+ export const LIBRARY_VERSION = "0.14.1";
package/package.json CHANGED
@@ -1,14 +1,33 @@
1
1
  {
2
2
  "name": "@supermux/core",
3
- "version": "0.1.0",
3
+ "version": "0.14.1",
4
4
  "type": "module",
5
5
  "description": "Build your own app on Claude Code, Codex, Cursor, OpenCode, Grok Build and Antigravity: one TypeScript API for sessions, events and permission prompts.",
6
- "keywords": ["claude-code", "codex", "cursor", "opencode", "grok", "antigravity", "coding-agents", "acp", "agent-sdk", "sessions"],
6
+ "keywords": [
7
+ "claude-code",
8
+ "codex",
9
+ "cursor",
10
+ "opencode",
11
+ "grok",
12
+ "antigravity",
13
+ "coding-agents",
14
+ "acp",
15
+ "agent-sdk",
16
+ "sessions"
17
+ ],
7
18
  "homepage": "https://github.com/UstaLabs/supermux/tree/main/packages/supermux-core#readme",
8
- "bugs": { "url": "https://github.com/UstaLabs/supermux/issues" },
19
+ "bugs": {
20
+ "url": "https://github.com/UstaLabs/supermux/issues"
21
+ },
9
22
  "license": "MIT",
10
- "repository": { "type": "git", "url": "git+https://github.com/UstaLabs/supermux.git", "directory": "packages/supermux-core" },
11
- "publishConfig": { "access": "public" },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/UstaLabs/supermux.git",
26
+ "directory": "packages/supermux-core"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
12
31
  "exports": {
13
32
  ".": {
14
33
  "types": "./dist/index.d.ts",