squadrant 0.16.0 → 0.16.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.
@@ -430,13 +430,14 @@ var FAILURE_RETRY_MS = 60 * 60 * 1e3;
430
430
 
431
431
  // packages/shared/dist/lib/git-worktree.js
432
432
  import { execFileSync as execFileSync2 } from "child_process";
433
+ import fs4 from "fs";
433
434
  import path4 from "path";
434
435
 
435
436
  // packages/shared/dist/lib/resolve-text-input.js
436
- import fs4 from "fs";
437
+ import fs5 from "fs";
437
438
 
438
439
  // packages/shared/dist/lib/runtime-sync.js
439
- import fs5 from "fs";
440
+ import fs6 from "fs";
440
441
  import path5 from "path";
441
442
 
442
443
  // packages/shared/dist/lib/tool-compat.js
@@ -471,12 +472,12 @@ function checkToolCompat(name, rawVersion, entry) {
471
472
  }
472
473
 
473
474
  // packages/shared/dist/lib/canonical-source.js
474
- import fs6 from "fs";
475
+ import fs7 from "fs";
475
476
  import path6 from "path";
476
477
 
477
478
  // packages/shared/dist/lib/daily-logs.js
478
479
  import { execSync } from "child_process";
479
- import fs7 from "fs";
480
+ import fs8 from "fs";
480
481
  import path7 from "path";
481
482
  import matter from "gray-matter";
482
483
 
@@ -1019,7 +1020,7 @@ function createDaemon(deps) {
1019
1020
  }
1020
1021
 
1021
1022
  // packages/core/dist/mailbox.js
1022
- import { promises as fs8 } from "fs";
1023
+ import { promises as fs9 } from "fs";
1023
1024
  import { join as join5 } from "path";
1024
1025
  import { randomUUID } from "crypto";
1025
1026
  function inboxDir(stateRoot) {
@@ -1036,7 +1037,7 @@ async function listRotatedOldestFirst(stateRoot, project) {
1036
1037
  const dir = inboxDir(stateRoot);
1037
1038
  let entries;
1038
1039
  try {
1039
- entries = await fs8.readdir(dir);
1040
+ entries = await fs9.readdir(dir);
1040
1041
  } catch {
1041
1042
  return [];
1042
1043
  }
@@ -1045,7 +1046,7 @@ async function listRotatedOldestFirst(stateRoot, project) {
1045
1046
  }
1046
1047
  async function readMaxSeqFromFile(file) {
1047
1048
  try {
1048
- const buf = await fs8.readFile(file, "utf-8");
1049
+ const buf = await fs9.readFile(file, "utf-8");
1049
1050
  if (!buf.trim())
1050
1051
  return 0;
1051
1052
  const lines = buf.trim().split("\n");
@@ -1087,12 +1088,12 @@ function withProjectLock(project, fn) {
1087
1088
  function appendEntry(stateRoot, project, build) {
1088
1089
  return withProjectLock(project, async () => {
1089
1090
  const dir = inboxDir(stateRoot);
1090
- await fs8.mkdir(dir, { recursive: true });
1091
+ await fs9.mkdir(dir, { recursive: true });
1091
1092
  const file = logPath(stateRoot, project);
1092
1093
  const lastSeq = await readMaxSeq(stateRoot, project);
1093
1094
  const seq = lastSeq + 1;
1094
1095
  const entry = build(seq);
1095
- await fs8.appendFile(file, JSON.stringify(entry) + "\n", { encoding: "utf-8" });
1096
+ await fs9.appendFile(file, JSON.stringify(entry) + "\n", { encoding: "utf-8" });
1096
1097
  return seq;
1097
1098
  });
1098
1099
  }
@@ -1109,7 +1110,7 @@ async function appendToMailbox(opts) {
1109
1110
  }));
1110
1111
  }
1111
1112
  async function appendCaptainMessage(opts) {
1112
- await appendEntry(opts.stateRoot, opts.project, (seq) => ({
1113
+ return appendEntry(opts.stateRoot, opts.project, (seq) => ({
1113
1114
  seq,
1114
1115
  ts: (/* @__PURE__ */ new Date()).toISOString(),
1115
1116
  kind: "captain.message",
@@ -1123,7 +1124,7 @@ function cursorPath(stateRoot, project, subscriber) {
1123
1124
  async function readCursor(opts) {
1124
1125
  let buf;
1125
1126
  try {
1126
- buf = await fs8.readFile(cursorPath(opts.stateRoot, opts.project, opts.subscriber), "utf-8");
1127
+ buf = await fs9.readFile(cursorPath(opts.stateRoot, opts.project, opts.subscriber), "utf-8");
1127
1128
  } catch (e) {
1128
1129
  if (e.code === "ENOENT")
1129
1130
  return null;
@@ -1138,7 +1139,7 @@ async function readCursor(opts) {
1138
1139
  }
1139
1140
  }
1140
1141
  async function writeCursor(opts) {
1141
- await fs8.mkdir(inboxDir(opts.stateRoot), { recursive: true });
1142
+ await fs9.mkdir(inboxDir(opts.stateRoot), { recursive: true });
1142
1143
  const dest = cursorPath(opts.stateRoot, opts.project, opts.subscriber);
1143
1144
  const tmp = `${dest}.${process.pid}.${randomUUID()}.tmp`;
1144
1145
  const data = {
@@ -1146,7 +1147,7 @@ async function writeCursor(opts) {
1146
1147
  subscriber: opts.subscriber,
1147
1148
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
1148
1149
  };
1149
- const handle = await fs8.open(tmp, "w");
1150
+ const handle = await fs9.open(tmp, "w");
1150
1151
  try {
1151
1152
  await handle.writeFile(JSON.stringify(data), { encoding: "utf-8" });
1152
1153
  await handle.sync();
@@ -1154,9 +1155,9 @@ async function writeCursor(opts) {
1154
1155
  await handle.close();
1155
1156
  }
1156
1157
  try {
1157
- await fs8.rename(tmp, dest);
1158
+ await fs9.rename(tmp, dest);
1158
1159
  } catch (e) {
1159
- await fs8.unlink(tmp).catch(() => {
1160
+ await fs9.unlink(tmp).catch(() => {
1160
1161
  });
1161
1162
  throw e;
1162
1163
  }
@@ -1167,7 +1168,7 @@ async function* readFromCursor(opts) {
1167
1168
  for (const file of files) {
1168
1169
  let buf;
1169
1170
  try {
1170
- buf = await fs8.readFile(file, "utf-8");
1171
+ buf = await fs9.readFile(file, "utf-8");
1171
1172
  } catch (e) {
1172
1173
  if (e.code === "ENOENT")
1173
1174
  continue;
@@ -1193,7 +1194,7 @@ async function mailboxStats(stateRoot, project) {
1193
1194
  let sizeBytes = 0;
1194
1195
  for (const f of [file, ...rotated]) {
1195
1196
  try {
1196
- sizeBytes += (await fs8.stat(f)).size;
1197
+ sizeBytes += (await fs9.stat(f)).size;
1197
1198
  } catch (e) {
1198
1199
  if (e.code !== "ENOENT")
1199
1200
  throw e;
@@ -1209,7 +1210,7 @@ async function mailboxStats(stateRoot, project) {
1209
1210
  }
1210
1211
  async function oldestEntryAgeMs(file) {
1211
1212
  try {
1212
- const buf = await fs8.readFile(file, "utf-8");
1213
+ const buf = await fs9.readFile(file, "utf-8");
1213
1214
  const firstLine = buf.split("\n").find((l) => l.trim());
1214
1215
  if (!firstLine)
1215
1216
  return 0;
@@ -1224,7 +1225,7 @@ async function rotateIfNeeded(opts) {
1224
1225
  const file = logPath(opts.stateRoot, opts.project);
1225
1226
  let size = 0;
1226
1227
  try {
1227
- size = (await fs8.stat(file)).size;
1228
+ size = (await fs9.stat(file)).size;
1228
1229
  } catch (e) {
1229
1230
  if (e.code === "ENOENT")
1230
1231
  return { rotated: false };
@@ -1240,22 +1241,22 @@ async function rotateIfNeeded(opts) {
1240
1241
  const dst = `${file}.${n + 1}`;
1241
1242
  if (n + 1 > opts.keepCount) {
1242
1243
  try {
1243
- await fs8.unlink(src);
1244
+ await fs9.unlink(src);
1244
1245
  } catch (e) {
1245
1246
  if (e.code !== "ENOENT")
1246
1247
  throw e;
1247
1248
  }
1248
1249
  } else {
1249
1250
  try {
1250
- await fs8.rename(src, dst);
1251
+ await fs9.rename(src, dst);
1251
1252
  } catch (e) {
1252
1253
  if (e.code !== "ENOENT")
1253
1254
  throw e;
1254
1255
  }
1255
1256
  }
1256
1257
  }
1257
- await fs8.rename(file, `${file}.1`);
1258
- await fs8.writeFile(file, "", { encoding: "utf-8" });
1258
+ await fs9.rename(file, `${file}.1`);
1259
+ await fs9.writeFile(file, "", { encoding: "utf-8" });
1259
1260
  return { rotated: true, from: file, to: `${file}.1` };
1260
1261
  });
1261
1262
  }
@@ -1511,6 +1512,9 @@ function reconcileLiveness(prev, next) {
1511
1512
  }
1512
1513
  if (next.startedAt >= prev.startedAt || next.lastState === "end")
1513
1514
  return next;
1515
+ const prevAlive = prev.lastState === "start" && prev.pidAlive;
1516
+ if (!prevAlive && next.lastState === "start" && next.pidAlive)
1517
+ return next;
1514
1518
  return prev;
1515
1519
  }
1516
1520
 
@@ -2167,9 +2171,15 @@ async function runLivenessTick(deps) {
2167
2171
  return;
2168
2172
  }
2169
2173
  const seen = /* @__PURE__ */ new Set();
2174
+ const knownCaptainSessions = /* @__PURE__ */ new Map();
2175
+ for (const e of deps.registry.all()) {
2176
+ if (e.role === "captain")
2177
+ knownCaptainSessions.set(e.sessionId, e.project);
2178
+ }
2170
2179
  const byProject = /* @__PURE__ */ new Map();
2171
2180
  for (const r of records) {
2172
- if (r.role !== "captain")
2181
+ const role = r.role === "captain" || knownCaptainSessions.get(r.sessionId) === r.project ? "captain" : r.role;
2182
+ if (role !== "captain")
2173
2183
  continue;
2174
2184
  let arr = byProject.get(r.project);
2175
2185
  if (!arr) {
@@ -2201,10 +2211,14 @@ async function runLivenessTick(deps) {
2201
2211
  logEntry(deps.log, project, deps.registry.get(project));
2202
2212
  }
2203
2213
  for (const e of deps.registry.all()) {
2204
- if (e.role === "captain" && e.lastState === "start" && !seen.has(e.project)) {
2205
- deps.registry.markEnded(e.project, now);
2206
- logEntry(deps.log, e.project, deps.registry.get(e.project));
2214
+ if (e.role !== "captain" || e.lastState !== "start" || seen.has(e.project))
2215
+ continue;
2216
+ if (e.pid == null || deps.isPidAlive(e.pid)) {
2217
+ deps.log?.(`[${e.role}/runtime] ${e.project} pid=${e.pid} missing from snapshot but not confirmed dead \u2014 leaving alive`);
2218
+ continue;
2207
2219
  }
2220
+ deps.registry.markEnded(e.project, now);
2221
+ logEntry(deps.log, e.project, deps.registry.get(e.project));
2208
2222
  }
2209
2223
  if (deps.reap) {
2210
2224
  for (const e of deps.registry.all()) {
@@ -2756,7 +2770,7 @@ function startDaemon(ctx, opts, pkgVersion) {
2756
2770
 
2757
2771
  // packages/core/dist/session-freshness.js
2758
2772
  import crypto from "crypto";
2759
- import fs9 from "fs";
2773
+ import fs10 from "fs";
2760
2774
  import path8 from "path";
2761
2775
 
2762
2776
  // packages/core/dist/crew-protocol.js
@@ -3012,7 +3026,7 @@ function formatInbound(text) {
3012
3026
  }
3013
3027
 
3014
3028
  // packages/core/dist/telegram/state.js
3015
- import fs10 from "fs";
3029
+ import fs11 from "fs";
3016
3030
  import path9 from "path";
3017
3031
  function statePath(stateRoot) {
3018
3032
  return path9.join(stateRoot, "telegram-state.json");
@@ -3022,7 +3036,7 @@ function topicKey(project, scope = "project") {
3022
3036
  }
3023
3037
  function loadState(stateRoot) {
3024
3038
  try {
3025
- const raw = fs10.readFileSync(statePath(stateRoot), "utf-8");
3039
+ const raw = fs11.readFileSync(statePath(stateRoot), "utf-8");
3026
3040
  const data = JSON.parse(raw);
3027
3041
  const result = {
3028
3042
  offset: typeof data.offset === "number" ? data.offset : 0,
@@ -3037,8 +3051,8 @@ function loadState(stateRoot) {
3037
3051
  }
3038
3052
  }
3039
3053
  function saveState(stateRoot, s) {
3040
- fs10.mkdirSync(stateRoot, { recursive: true });
3041
- fs10.writeFileSync(statePath(stateRoot), JSON.stringify(s, null, 2) + "\n");
3054
+ fs11.mkdirSync(stateRoot, { recursive: true });
3055
+ fs11.writeFileSync(statePath(stateRoot), JSON.stringify(s, null, 2) + "\n");
3042
3056
  }
3043
3057
  function setTopic(stateRoot, project, topicId, scope = "project") {
3044
3058
  const s = loadState(stateRoot);
@@ -3573,7 +3587,7 @@ function createTelegramBridge(opts) {
3573
3587
  }
3574
3588
 
3575
3589
  // packages/core/dist/telegram/setup.js
3576
- import fs11 from "fs";
3590
+ import fs12 from "fs";
3577
3591
 
3578
3592
  // packages/core/dist/restart-daemon.js
3579
3593
  import { execFileSync as execFileSync4 } from "child_process";
@@ -3589,10 +3603,10 @@ import { join as join12 } from "path";
3589
3603
  var DEFAULT_SOCK_PATH2 = join12(homedir7(), ".config", "squadrant", "squadrant.sock");
3590
3604
 
3591
3605
  // packages/core/dist/side-session.js
3592
- import fs12 from "fs";
3606
+ import fs13 from "fs";
3593
3607
 
3594
3608
  // packages/core/dist/crew-spawn.js
3595
- import fs13 from "fs";
3609
+ import fs14 from "fs";
3596
3610
  import os5 from "os";
3597
3611
  import path11 from "path";
3598
3612
  var TEMPLATES_DIR = path11.join(os5.homedir(), ".config", "squadrant", "templates");
@@ -3628,7 +3642,7 @@ import { execSync as execSync4 } from "child_process";
3628
3642
  import { execSync as execSync5 } from "child_process";
3629
3643
 
3630
3644
  // packages/agents/dist/drivers/launch-cmd.js
3631
- import fs14 from "fs";
3645
+ import fs15 from "fs";
3632
3646
  import path12 from "path";
3633
3647
 
3634
3648
  // packages/agents/dist/projection/cursor.js
@@ -5078,7 +5092,7 @@ var RuntimeRegistry = class {
5078
5092
  import { execFileSync as execFileSync6, execSync as execSync7 } from "child_process";
5079
5093
 
5080
5094
  // packages/workspaces/dist/workspaces/obsidian.js
5081
- import fs15 from "fs/promises";
5095
+ import fs16 from "fs/promises";
5082
5096
  import { existsSync as existsSync9 } from "fs";
5083
5097
  import path17 from "path";
5084
5098
 
@@ -5764,7 +5778,7 @@ async function resendCrewFirstTurn(runtime, captainName, project, name, message)
5764
5778
  }
5765
5779
 
5766
5780
  // packages/cli/src/lib/daemon-restart-broadcast.ts
5767
- import fs16 from "fs";
5781
+ import fs17 from "fs";
5768
5782
  import path18 from "path";
5769
5783
  function statePath2(stateRoot) {
5770
5784
  return path18.join(stateRoot, "daemon-restart-state.json");
@@ -5774,7 +5788,7 @@ function computeRestartSignature(version, buildMtimeMs) {
5774
5788
  }
5775
5789
  function readPersistedRestartSignature(stateRoot) {
5776
5790
  try {
5777
- const raw = fs16.readFileSync(statePath2(stateRoot), "utf-8");
5791
+ const raw = fs17.readFileSync(statePath2(stateRoot), "utf-8");
5778
5792
  const data = JSON.parse(raw);
5779
5793
  return typeof data.signature === "string" ? data.signature : null;
5780
5794
  } catch {
@@ -5782,8 +5796,8 @@ function readPersistedRestartSignature(stateRoot) {
5782
5796
  }
5783
5797
  }
5784
5798
  function writePersistedRestartSignature(stateRoot, signature) {
5785
- fs16.mkdirSync(stateRoot, { recursive: true });
5786
- fs16.writeFileSync(statePath2(stateRoot), JSON.stringify({ signature }, null, 2) + "\n");
5799
+ fs17.mkdirSync(stateRoot, { recursive: true });
5800
+ fs17.writeFileSync(statePath2(stateRoot), JSON.stringify({ signature }, null, 2) + "\n");
5787
5801
  }
5788
5802
  function restartNotice(version, isDevRebuild) {
5789
5803
  const suffix = isDevRebuild ? " (dev build)" : "";