squadrant 0.15.0 → 0.16.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.
- package/dist/index.js +3902 -497
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +162 -117
- package/dist/squadrantd.js.map +1 -1
- package/package.json +1 -1
package/dist/squadrantd.js
CHANGED
|
@@ -233,22 +233,22 @@ var MINIMAL_TEMPLATE = [
|
|
|
233
233
|
``
|
|
234
234
|
].join("\n");
|
|
235
235
|
function ensureSocketAutomation(opts = {}) {
|
|
236
|
-
const
|
|
237
|
-
if (!existsSync(
|
|
238
|
-
mkdirSync(dirname(
|
|
239
|
-
writeFileSync(
|
|
240
|
-
return { path:
|
|
236
|
+
const path19 = opts.path ?? defaultCmuxConfigPath();
|
|
237
|
+
if (!existsSync(path19)) {
|
|
238
|
+
mkdirSync(dirname(path19), { recursive: true });
|
|
239
|
+
writeFileSync(path19, MINIMAL_TEMPLATE);
|
|
240
|
+
return { path: path19, changed: true, alreadySet: false };
|
|
241
241
|
}
|
|
242
|
-
const text = readFileSync(
|
|
242
|
+
const text = readFileSync(path19, "utf-8");
|
|
243
243
|
const current = parse(text)?.automation?.socketControlMode;
|
|
244
244
|
if (current === AUTOMATION_MODE) {
|
|
245
|
-
return { path:
|
|
245
|
+
return { path: path19, changed: false, alreadySet: true };
|
|
246
246
|
}
|
|
247
247
|
const edits = modify(text, [...SOCKET_CONTROL_MODE_PATH], AUTOMATION_MODE, {
|
|
248
248
|
formattingOptions: { insertSpaces: true, tabSize: 2 }
|
|
249
249
|
});
|
|
250
|
-
writeFileSync(
|
|
251
|
-
return { path:
|
|
250
|
+
writeFileSync(path19, applyEdits(text, edits));
|
|
251
|
+
return { path: path19, changed: true, alreadySet: false };
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
// packages/shared/dist/lib/cmux-probe.js
|
|
@@ -370,9 +370,9 @@ function sleep(ms) {
|
|
|
370
370
|
function defaultStatePath() {
|
|
371
371
|
return join4(homedir3(), ".config", "squadrant", "state", "cmux-autoconfig.json");
|
|
372
372
|
}
|
|
373
|
-
function readState(
|
|
373
|
+
function readState(path19) {
|
|
374
374
|
try {
|
|
375
|
-
return JSON.parse(readFileSync4(
|
|
375
|
+
return JSON.parse(readFileSync4(path19, "utf-8"));
|
|
376
376
|
} catch {
|
|
377
377
|
return {};
|
|
378
378
|
}
|
|
@@ -419,16 +419,26 @@ var compatManifest = {
|
|
|
419
419
|
}
|
|
420
420
|
};
|
|
421
421
|
|
|
422
|
+
// packages/shared/dist/lib/update-check.js
|
|
423
|
+
import fs3 from "fs";
|
|
424
|
+
import path3 from "path";
|
|
425
|
+
import os3 from "os";
|
|
426
|
+
import https from "https";
|
|
427
|
+
var UPDATE_CHECK_STATE_PATH = path3.join(os3.homedir(), ".config", "squadrant", "update-check.json");
|
|
428
|
+
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
429
|
+
var FAILURE_RETRY_MS = 60 * 60 * 1e3;
|
|
430
|
+
|
|
422
431
|
// packages/shared/dist/lib/git-worktree.js
|
|
423
432
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
424
|
-
import
|
|
433
|
+
import fs4 from "fs";
|
|
434
|
+
import path4 from "path";
|
|
425
435
|
|
|
426
436
|
// packages/shared/dist/lib/resolve-text-input.js
|
|
427
|
-
import
|
|
437
|
+
import fs5 from "fs";
|
|
428
438
|
|
|
429
439
|
// packages/shared/dist/lib/runtime-sync.js
|
|
430
|
-
import
|
|
431
|
-
import
|
|
440
|
+
import fs6 from "fs";
|
|
441
|
+
import path5 from "path";
|
|
432
442
|
|
|
433
443
|
// packages/shared/dist/lib/tool-compat.js
|
|
434
444
|
function parseSemVer(v) {
|
|
@@ -462,13 +472,13 @@ function checkToolCompat(name, rawVersion, entry) {
|
|
|
462
472
|
}
|
|
463
473
|
|
|
464
474
|
// packages/shared/dist/lib/canonical-source.js
|
|
465
|
-
import
|
|
466
|
-
import
|
|
475
|
+
import fs7 from "fs";
|
|
476
|
+
import path6 from "path";
|
|
467
477
|
|
|
468
478
|
// packages/shared/dist/lib/daily-logs.js
|
|
469
479
|
import { execSync } from "child_process";
|
|
470
|
-
import
|
|
471
|
-
import
|
|
480
|
+
import fs8 from "fs";
|
|
481
|
+
import path7 from "path";
|
|
472
482
|
import matter from "gray-matter";
|
|
473
483
|
|
|
474
484
|
// packages/core/dist/state-machine.js
|
|
@@ -629,7 +639,7 @@ function formatMessage(rec, event) {
|
|
|
629
639
|
return `CREW STALLED ${tag}: no heartbeat in ${rec.heartbeatBudgetMs}ms`;
|
|
630
640
|
}
|
|
631
641
|
case "awaiting-input":
|
|
632
|
-
return `CREW IDLE ${tag}: turn ended
|
|
642
|
+
return `CREW IDLE ${tag}: turn ended, awaiting your reply.`;
|
|
633
643
|
default:
|
|
634
644
|
return null;
|
|
635
645
|
}
|
|
@@ -1010,7 +1020,7 @@ function createDaemon(deps) {
|
|
|
1010
1020
|
}
|
|
1011
1021
|
|
|
1012
1022
|
// packages/core/dist/mailbox.js
|
|
1013
|
-
import { promises as
|
|
1023
|
+
import { promises as fs9 } from "fs";
|
|
1014
1024
|
import { join as join5 } from "path";
|
|
1015
1025
|
import { randomUUID } from "crypto";
|
|
1016
1026
|
function inboxDir(stateRoot) {
|
|
@@ -1027,7 +1037,7 @@ async function listRotatedOldestFirst(stateRoot, project) {
|
|
|
1027
1037
|
const dir = inboxDir(stateRoot);
|
|
1028
1038
|
let entries;
|
|
1029
1039
|
try {
|
|
1030
|
-
entries = await
|
|
1040
|
+
entries = await fs9.readdir(dir);
|
|
1031
1041
|
} catch {
|
|
1032
1042
|
return [];
|
|
1033
1043
|
}
|
|
@@ -1036,7 +1046,7 @@ async function listRotatedOldestFirst(stateRoot, project) {
|
|
|
1036
1046
|
}
|
|
1037
1047
|
async function readMaxSeqFromFile(file) {
|
|
1038
1048
|
try {
|
|
1039
|
-
const buf = await
|
|
1049
|
+
const buf = await fs9.readFile(file, "utf-8");
|
|
1040
1050
|
if (!buf.trim())
|
|
1041
1051
|
return 0;
|
|
1042
1052
|
const lines = buf.trim().split("\n");
|
|
@@ -1078,12 +1088,12 @@ function withProjectLock(project, fn) {
|
|
|
1078
1088
|
function appendEntry(stateRoot, project, build) {
|
|
1079
1089
|
return withProjectLock(project, async () => {
|
|
1080
1090
|
const dir = inboxDir(stateRoot);
|
|
1081
|
-
await
|
|
1091
|
+
await fs9.mkdir(dir, { recursive: true });
|
|
1082
1092
|
const file = logPath(stateRoot, project);
|
|
1083
1093
|
const lastSeq = await readMaxSeq(stateRoot, project);
|
|
1084
1094
|
const seq = lastSeq + 1;
|
|
1085
1095
|
const entry = build(seq);
|
|
1086
|
-
await
|
|
1096
|
+
await fs9.appendFile(file, JSON.stringify(entry) + "\n", { encoding: "utf-8" });
|
|
1087
1097
|
return seq;
|
|
1088
1098
|
});
|
|
1089
1099
|
}
|
|
@@ -1114,7 +1124,7 @@ function cursorPath(stateRoot, project, subscriber) {
|
|
|
1114
1124
|
async function readCursor(opts) {
|
|
1115
1125
|
let buf;
|
|
1116
1126
|
try {
|
|
1117
|
-
buf = await
|
|
1127
|
+
buf = await fs9.readFile(cursorPath(opts.stateRoot, opts.project, opts.subscriber), "utf-8");
|
|
1118
1128
|
} catch (e) {
|
|
1119
1129
|
if (e.code === "ENOENT")
|
|
1120
1130
|
return null;
|
|
@@ -1129,7 +1139,7 @@ async function readCursor(opts) {
|
|
|
1129
1139
|
}
|
|
1130
1140
|
}
|
|
1131
1141
|
async function writeCursor(opts) {
|
|
1132
|
-
await
|
|
1142
|
+
await fs9.mkdir(inboxDir(opts.stateRoot), { recursive: true });
|
|
1133
1143
|
const dest = cursorPath(opts.stateRoot, opts.project, opts.subscriber);
|
|
1134
1144
|
const tmp = `${dest}.${process.pid}.${randomUUID()}.tmp`;
|
|
1135
1145
|
const data = {
|
|
@@ -1137,7 +1147,7 @@ async function writeCursor(opts) {
|
|
|
1137
1147
|
subscriber: opts.subscriber,
|
|
1138
1148
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1139
1149
|
};
|
|
1140
|
-
const handle = await
|
|
1150
|
+
const handle = await fs9.open(tmp, "w");
|
|
1141
1151
|
try {
|
|
1142
1152
|
await handle.writeFile(JSON.stringify(data), { encoding: "utf-8" });
|
|
1143
1153
|
await handle.sync();
|
|
@@ -1145,9 +1155,9 @@ async function writeCursor(opts) {
|
|
|
1145
1155
|
await handle.close();
|
|
1146
1156
|
}
|
|
1147
1157
|
try {
|
|
1148
|
-
await
|
|
1158
|
+
await fs9.rename(tmp, dest);
|
|
1149
1159
|
} catch (e) {
|
|
1150
|
-
await
|
|
1160
|
+
await fs9.unlink(tmp).catch(() => {
|
|
1151
1161
|
});
|
|
1152
1162
|
throw e;
|
|
1153
1163
|
}
|
|
@@ -1158,7 +1168,7 @@ async function* readFromCursor(opts) {
|
|
|
1158
1168
|
for (const file of files) {
|
|
1159
1169
|
let buf;
|
|
1160
1170
|
try {
|
|
1161
|
-
buf = await
|
|
1171
|
+
buf = await fs9.readFile(file, "utf-8");
|
|
1162
1172
|
} catch (e) {
|
|
1163
1173
|
if (e.code === "ENOENT")
|
|
1164
1174
|
continue;
|
|
@@ -1184,7 +1194,7 @@ async function mailboxStats(stateRoot, project) {
|
|
|
1184
1194
|
let sizeBytes = 0;
|
|
1185
1195
|
for (const f of [file, ...rotated]) {
|
|
1186
1196
|
try {
|
|
1187
|
-
sizeBytes += (await
|
|
1197
|
+
sizeBytes += (await fs9.stat(f)).size;
|
|
1188
1198
|
} catch (e) {
|
|
1189
1199
|
if (e.code !== "ENOENT")
|
|
1190
1200
|
throw e;
|
|
@@ -1200,7 +1210,7 @@ async function mailboxStats(stateRoot, project) {
|
|
|
1200
1210
|
}
|
|
1201
1211
|
async function oldestEntryAgeMs(file) {
|
|
1202
1212
|
try {
|
|
1203
|
-
const buf = await
|
|
1213
|
+
const buf = await fs9.readFile(file, "utf-8");
|
|
1204
1214
|
const firstLine = buf.split("\n").find((l) => l.trim());
|
|
1205
1215
|
if (!firstLine)
|
|
1206
1216
|
return 0;
|
|
@@ -1215,7 +1225,7 @@ async function rotateIfNeeded(opts) {
|
|
|
1215
1225
|
const file = logPath(opts.stateRoot, opts.project);
|
|
1216
1226
|
let size = 0;
|
|
1217
1227
|
try {
|
|
1218
|
-
size = (await
|
|
1228
|
+
size = (await fs9.stat(file)).size;
|
|
1219
1229
|
} catch (e) {
|
|
1220
1230
|
if (e.code === "ENOENT")
|
|
1221
1231
|
return { rotated: false };
|
|
@@ -1231,22 +1241,22 @@ async function rotateIfNeeded(opts) {
|
|
|
1231
1241
|
const dst = `${file}.${n + 1}`;
|
|
1232
1242
|
if (n + 1 > opts.keepCount) {
|
|
1233
1243
|
try {
|
|
1234
|
-
await
|
|
1244
|
+
await fs9.unlink(src);
|
|
1235
1245
|
} catch (e) {
|
|
1236
1246
|
if (e.code !== "ENOENT")
|
|
1237
1247
|
throw e;
|
|
1238
1248
|
}
|
|
1239
1249
|
} else {
|
|
1240
1250
|
try {
|
|
1241
|
-
await
|
|
1251
|
+
await fs9.rename(src, dst);
|
|
1242
1252
|
} catch (e) {
|
|
1243
1253
|
if (e.code !== "ENOENT")
|
|
1244
1254
|
throw e;
|
|
1245
1255
|
}
|
|
1246
1256
|
}
|
|
1247
1257
|
}
|
|
1248
|
-
await
|
|
1249
|
-
await
|
|
1258
|
+
await fs9.rename(file, `${file}.1`);
|
|
1259
|
+
await fs9.writeFile(file, "", { encoding: "utf-8" });
|
|
1250
1260
|
return { rotated: true, from: file, to: `${file}.1` };
|
|
1251
1261
|
});
|
|
1252
1262
|
}
|
|
@@ -2158,29 +2168,38 @@ async function runLivenessTick(deps) {
|
|
|
2158
2168
|
return;
|
|
2159
2169
|
}
|
|
2160
2170
|
const seen = /* @__PURE__ */ new Set();
|
|
2171
|
+
const byProject = /* @__PURE__ */ new Map();
|
|
2161
2172
|
for (const r of records) {
|
|
2162
2173
|
if (r.role !== "captain")
|
|
2163
2174
|
continue;
|
|
2164
|
-
|
|
2175
|
+
let arr = byProject.get(r.project);
|
|
2176
|
+
if (!arr) {
|
|
2177
|
+
arr = [];
|
|
2178
|
+
byProject.set(r.project, arr);
|
|
2179
|
+
}
|
|
2180
|
+
arr.push(r);
|
|
2181
|
+
}
|
|
2182
|
+
for (const [project, recs] of byProject) {
|
|
2183
|
+
seen.add(project);
|
|
2184
|
+
const winner = recs.find((r) => r.pid == null || deps.isPidAlive(r.pid)) ?? recs[0];
|
|
2165
2185
|
const entry = {
|
|
2166
|
-
project
|
|
2186
|
+
project,
|
|
2167
2187
|
role: "captain",
|
|
2168
|
-
pid:
|
|
2169
|
-
sessionId:
|
|
2188
|
+
pid: winner.pid,
|
|
2189
|
+
sessionId: winner.sessionId,
|
|
2170
2190
|
startedAt: now,
|
|
2171
2191
|
lastState: "start",
|
|
2172
2192
|
lastSeenAt: now,
|
|
2173
|
-
pidAlive:
|
|
2174
|
-
// pid:null hibernated → alive-unknown
|
|
2193
|
+
pidAlive: winner.pid != null ? deps.isPidAlive(winner.pid) : true,
|
|
2175
2194
|
source: "runtime"
|
|
2176
2195
|
};
|
|
2177
|
-
const prev = deps.registry.get(
|
|
2196
|
+
const prev = deps.registry.get(project);
|
|
2178
2197
|
if (prev && prev.lastState === "start")
|
|
2179
2198
|
entry.startedAt = prev.startedAt;
|
|
2180
2199
|
deps.registry.apply(entry);
|
|
2181
|
-
if (
|
|
2182
|
-
deps.registry.setPidAlive(
|
|
2183
|
-
logEntry(deps.log,
|
|
2200
|
+
if (winner.pid != null)
|
|
2201
|
+
deps.registry.setPidAlive(project, deps.isPidAlive(winner.pid), now);
|
|
2202
|
+
logEntry(deps.log, project, deps.registry.get(project));
|
|
2184
2203
|
}
|
|
2185
2204
|
for (const e of deps.registry.all()) {
|
|
2186
2205
|
if (e.role === "captain" && e.lastState === "start" && !seen.has(e.project)) {
|
|
@@ -2244,11 +2263,12 @@ function createDelivery(ctx, daemonCmux) {
|
|
|
2244
2263
|
const allProjects = [.../* @__PURE__ */ new Set([
|
|
2245
2264
|
...Object.keys(cfg.projects ?? {}),
|
|
2246
2265
|
...Object.keys(injectedSurfaces),
|
|
2247
|
-
...store.listAll().map((t) => t.project)
|
|
2266
|
+
...store.listAll().map((t) => t.project),
|
|
2267
|
+
cfg.commandName
|
|
2248
2268
|
])];
|
|
2249
2269
|
for (const project of allProjects) {
|
|
2250
2270
|
const projCfg = cfg.projects?.[project];
|
|
2251
|
-
const captainTitle = projCfg?.captainName ?? `${project}-captain`;
|
|
2271
|
+
const captainTitle = project === cfg.commandName ? cfg.commandName : projCfg?.captainName ?? `${project}-captain`;
|
|
2252
2272
|
const wsId = cmux2.findWorkspaceId ? await cmux2.findWorkspaceId(captainTitle) : null;
|
|
2253
2273
|
let surface = null;
|
|
2254
2274
|
if (wsId) {
|
|
@@ -2272,11 +2292,16 @@ function createDelivery(ctx, daemonCmux) {
|
|
|
2272
2292
|
for await (const entry of readFromCursor({ stateRoot, project, fromSeq: lastAcked + 1 })) {
|
|
2273
2293
|
if (new Date(entry.ts).getTime() < sessionStartMs - STALE_THRESHOLD_MS) {
|
|
2274
2294
|
if (!TERMINAL_KINDS.has(entry.kind)) {
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2295
|
+
const isExemptMessage = entry.kind === "captain.message" && entry.payload?.source !== "daemon";
|
|
2296
|
+
if (!isExemptMessage) {
|
|
2297
|
+
log(`delivery seq=${entry.seq} kind=${entry.kind} outcome=stale-skipped`);
|
|
2298
|
+
await writeCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER, lastAckedSeq: entry.seq });
|
|
2299
|
+
continue;
|
|
2300
|
+
}
|
|
2301
|
+
log(`delivery seq=${entry.seq} kind=${entry.kind} outcome=stale-exempt-deliver`);
|
|
2302
|
+
} else {
|
|
2303
|
+
log(`delivery seq=${entry.seq} kind=${entry.kind} outcome=stale-terminal-deliver`);
|
|
2278
2304
|
}
|
|
2279
|
-
log(`delivery seq=${entry.seq} kind=${entry.kind} outcome=stale-terminal-deliver`);
|
|
2280
2305
|
}
|
|
2281
2306
|
const result = await d.deliver(entry, (text, sendOpts) => cmux2.send(surface, text, sendOpts));
|
|
2282
2307
|
if ("delivered" in result) {
|
|
@@ -2389,10 +2414,10 @@ function distBuiltAt() {
|
|
|
2389
2414
|
return 0;
|
|
2390
2415
|
}
|
|
2391
2416
|
}
|
|
2392
|
-
function gatherLogStats(
|
|
2417
|
+
function gatherLogStats(path19, now, windowMs) {
|
|
2393
2418
|
let sizeBytes = 0;
|
|
2394
2419
|
try {
|
|
2395
|
-
sizeBytes = statSync2(
|
|
2420
|
+
sizeBytes = statSync2(path19).size;
|
|
2396
2421
|
} catch {
|
|
2397
2422
|
return { errorCount: 0, sizeBytes: 0, windowMs };
|
|
2398
2423
|
}
|
|
@@ -2403,7 +2428,7 @@ function gatherLogStats(path18, now, windowMs) {
|
|
|
2403
2428
|
const len = sizeBytes - start;
|
|
2404
2429
|
let text = "";
|
|
2405
2430
|
try {
|
|
2406
|
-
const fd = openSync2(
|
|
2431
|
+
const fd = openSync2(path19, "r");
|
|
2407
2432
|
try {
|
|
2408
2433
|
const buf = Buffer.alloc(len);
|
|
2409
2434
|
readSync(fd, buf, 0, len, start);
|
|
@@ -2635,7 +2660,7 @@ function startDaemon(ctx, opts, pkgVersion) {
|
|
|
2635
2660
|
}
|
|
2636
2661
|
})();
|
|
2637
2662
|
const server = createServer2(ctx, { buildHealth, gatherSnapshotInputs, cancelPromotionsFor, broadcast });
|
|
2638
|
-
log(`
|
|
2663
|
+
log(`boot pid=${process.pid} version=${pkgVersion} socket=${ctx.sockPath} stateRoot=${stateRoot}`);
|
|
2639
2664
|
let deliveryTick = initialDeliveryTick;
|
|
2640
2665
|
let probeTick;
|
|
2641
2666
|
if (daemonCmux) {
|
|
@@ -2696,7 +2721,8 @@ function startDaemon(ctx, opts, pkgVersion) {
|
|
|
2696
2721
|
rotationTimer.unref?.();
|
|
2697
2722
|
}
|
|
2698
2723
|
return {
|
|
2699
|
-
stop() {
|
|
2724
|
+
stop(reason = "requested") {
|
|
2725
|
+
log(`exit pid=${process.pid} reason=${reason}`);
|
|
2700
2726
|
if (deliveryTimer)
|
|
2701
2727
|
clearInterval(deliveryTimer);
|
|
2702
2728
|
if (probeTimer)
|
|
@@ -2720,7 +2746,7 @@ function startDaemon(ctx, opts, pkgVersion) {
|
|
|
2720
2746
|
for (const kill of ctx.activeHeadlessKills)
|
|
2721
2747
|
kill();
|
|
2722
2748
|
return new Promise((resolve2) => server.close(() => {
|
|
2723
|
-
log(
|
|
2749
|
+
log(`exit-complete pid=${process.pid}`);
|
|
2724
2750
|
resolve2();
|
|
2725
2751
|
}));
|
|
2726
2752
|
},
|
|
@@ -2731,8 +2757,8 @@ function startDaemon(ctx, opts, pkgVersion) {
|
|
|
2731
2757
|
|
|
2732
2758
|
// packages/core/dist/session-freshness.js
|
|
2733
2759
|
import crypto from "crypto";
|
|
2734
|
-
import
|
|
2735
|
-
import
|
|
2760
|
+
import fs10 from "fs";
|
|
2761
|
+
import path8 from "path";
|
|
2736
2762
|
|
|
2737
2763
|
// packages/core/dist/crew-protocol.js
|
|
2738
2764
|
function buildCompletionProtocol(taskId, project) {
|
|
@@ -2987,17 +3013,17 @@ function formatInbound(text) {
|
|
|
2987
3013
|
}
|
|
2988
3014
|
|
|
2989
3015
|
// packages/core/dist/telegram/state.js
|
|
2990
|
-
import
|
|
2991
|
-
import
|
|
3016
|
+
import fs11 from "fs";
|
|
3017
|
+
import path9 from "path";
|
|
2992
3018
|
function statePath(stateRoot) {
|
|
2993
|
-
return
|
|
3019
|
+
return path9.join(stateRoot, "telegram-state.json");
|
|
2994
3020
|
}
|
|
2995
3021
|
function topicKey(project, scope = "project") {
|
|
2996
3022
|
return `${project}::${scope}`;
|
|
2997
3023
|
}
|
|
2998
3024
|
function loadState(stateRoot) {
|
|
2999
3025
|
try {
|
|
3000
|
-
const raw =
|
|
3026
|
+
const raw = fs11.readFileSync(statePath(stateRoot), "utf-8");
|
|
3001
3027
|
const data = JSON.parse(raw);
|
|
3002
3028
|
const result = {
|
|
3003
3029
|
offset: typeof data.offset === "number" ? data.offset : 0,
|
|
@@ -3012,8 +3038,8 @@ function loadState(stateRoot) {
|
|
|
3012
3038
|
}
|
|
3013
3039
|
}
|
|
3014
3040
|
function saveState(stateRoot, s) {
|
|
3015
|
-
|
|
3016
|
-
|
|
3041
|
+
fs11.mkdirSync(stateRoot, { recursive: true });
|
|
3042
|
+
fs11.writeFileSync(statePath(stateRoot), JSON.stringify(s, null, 2) + "\n");
|
|
3017
3043
|
}
|
|
3018
3044
|
function setTopic(stateRoot, project, topicId, scope = "project") {
|
|
3019
3045
|
const s = loadState(stateRoot);
|
|
@@ -3103,8 +3129,8 @@ function createTelegramClient(opts) {
|
|
|
3103
3129
|
}
|
|
3104
3130
|
|
|
3105
3131
|
// packages/core/dist/telegram/bridge.js
|
|
3106
|
-
import
|
|
3107
|
-
import
|
|
3132
|
+
import os4 from "os";
|
|
3133
|
+
import path10 from "path";
|
|
3108
3134
|
|
|
3109
3135
|
// packages/core/dist/telegram/panels.js
|
|
3110
3136
|
var mark = (on, label) => on ? `\u2022 ${label}` : label;
|
|
@@ -3209,7 +3235,7 @@ function notifyToggle(text) {
|
|
|
3209
3235
|
}
|
|
3210
3236
|
function createTelegramBridge(opts) {
|
|
3211
3237
|
const { cfg, stateRoot, client, appendCaptainMessage: appendCaptainMessage2, log, ensureCaptainAlive, runCommand, sendReply } = opts;
|
|
3212
|
-
const configRoot = opts.configRoot ??
|
|
3238
|
+
const configRoot = opts.configRoot ?? path10.join(os4.homedir(), ".config", "squadrant");
|
|
3213
3239
|
const pollMs = cfg.pollMs ?? 1e3;
|
|
3214
3240
|
let running = false;
|
|
3215
3241
|
let lastSuccessfulPollAt = null;
|
|
@@ -3334,14 +3360,14 @@ function createTelegramBridge(opts) {
|
|
|
3334
3360
|
}
|
|
3335
3361
|
function currentEffort() {
|
|
3336
3362
|
try {
|
|
3337
|
-
return loadConfig(
|
|
3363
|
+
return loadConfig(path10.join(configRoot, "config.json")).defaults.effort ?? "balance";
|
|
3338
3364
|
} catch {
|
|
3339
3365
|
return "balance";
|
|
3340
3366
|
}
|
|
3341
3367
|
}
|
|
3342
3368
|
function projectNames() {
|
|
3343
3369
|
try {
|
|
3344
|
-
return Object.keys(loadConfig(
|
|
3370
|
+
return Object.keys(loadConfig(path10.join(configRoot, "config.json")).projects);
|
|
3345
3371
|
} catch {
|
|
3346
3372
|
return [];
|
|
3347
3373
|
}
|
|
@@ -3548,7 +3574,7 @@ function createTelegramBridge(opts) {
|
|
|
3548
3574
|
}
|
|
3549
3575
|
|
|
3550
3576
|
// packages/core/dist/telegram/setup.js
|
|
3551
|
-
import
|
|
3577
|
+
import fs12 from "fs";
|
|
3552
3578
|
|
|
3553
3579
|
// packages/core/dist/restart-daemon.js
|
|
3554
3580
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
@@ -3564,14 +3590,14 @@ import { join as join12 } from "path";
|
|
|
3564
3590
|
var DEFAULT_SOCK_PATH2 = join12(homedir7(), ".config", "squadrant", "squadrant.sock");
|
|
3565
3591
|
|
|
3566
3592
|
// packages/core/dist/side-session.js
|
|
3567
|
-
import
|
|
3593
|
+
import fs13 from "fs";
|
|
3568
3594
|
|
|
3569
3595
|
// packages/core/dist/crew-spawn.js
|
|
3570
|
-
import
|
|
3571
|
-
import
|
|
3572
|
-
import
|
|
3573
|
-
var TEMPLATES_DIR =
|
|
3574
|
-
var STATE_ROOT =
|
|
3596
|
+
import fs14 from "fs";
|
|
3597
|
+
import os5 from "os";
|
|
3598
|
+
import path11 from "path";
|
|
3599
|
+
var TEMPLATES_DIR = path11.join(os5.homedir(), ".config", "squadrant", "templates");
|
|
3600
|
+
var STATE_ROOT = path11.join(os5.homedir(), ".config", "squadrant", "state");
|
|
3575
3601
|
|
|
3576
3602
|
// packages/core/dist/lifecycle-source.js
|
|
3577
3603
|
function reduceLifecycle(prev, next) {
|
|
@@ -3603,28 +3629,28 @@ import { execSync as execSync4 } from "child_process";
|
|
|
3603
3629
|
import { execSync as execSync5 } from "child_process";
|
|
3604
3630
|
|
|
3605
3631
|
// packages/agents/dist/drivers/launch-cmd.js
|
|
3606
|
-
import
|
|
3607
|
-
import
|
|
3632
|
+
import fs15 from "fs";
|
|
3633
|
+
import path12 from "path";
|
|
3608
3634
|
|
|
3609
3635
|
// packages/agents/dist/projection/cursor.js
|
|
3610
3636
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
3611
|
-
import
|
|
3612
|
-
import
|
|
3637
|
+
import path13 from "path";
|
|
3638
|
+
import os6 from "os";
|
|
3613
3639
|
|
|
3614
3640
|
// packages/agents/dist/projection/codex.js
|
|
3615
3641
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
3616
|
-
import
|
|
3617
|
-
import
|
|
3642
|
+
import path14 from "path";
|
|
3643
|
+
import os7 from "os";
|
|
3618
3644
|
|
|
3619
3645
|
// packages/agents/dist/projection/gemini.js
|
|
3620
3646
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
3621
|
-
import
|
|
3622
|
-
import
|
|
3647
|
+
import path15 from "path";
|
|
3648
|
+
import os8 from "os";
|
|
3623
3649
|
|
|
3624
3650
|
// packages/agents/dist/projection/opencode.js
|
|
3625
3651
|
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
3626
|
-
import
|
|
3627
|
-
import
|
|
3652
|
+
import path16 from "path";
|
|
3653
|
+
import os9 from "os";
|
|
3628
3654
|
|
|
3629
3655
|
// packages/agents/dist/codex/app-server-client.js
|
|
3630
3656
|
import { EventEmitter } from "events";
|
|
@@ -5053,9 +5079,9 @@ var RuntimeRegistry = class {
|
|
|
5053
5079
|
import { execFileSync as execFileSync6, execSync as execSync7 } from "child_process";
|
|
5054
5080
|
|
|
5055
5081
|
// packages/workspaces/dist/workspaces/obsidian.js
|
|
5056
|
-
import
|
|
5082
|
+
import fs16 from "fs/promises";
|
|
5057
5083
|
import { existsSync as existsSync9 } from "fs";
|
|
5058
|
-
import
|
|
5084
|
+
import path17 from "path";
|
|
5059
5085
|
|
|
5060
5086
|
// packages/workspaces/dist/cmux-daemon/events-bridge.js
|
|
5061
5087
|
import { spawn as nodeSpawn2 } from "child_process";
|
|
@@ -5482,9 +5508,9 @@ function defaultListFiles(dir) {
|
|
|
5482
5508
|
return [];
|
|
5483
5509
|
}
|
|
5484
5510
|
}
|
|
5485
|
-
function defaultReadFile(
|
|
5511
|
+
function defaultReadFile(path19) {
|
|
5486
5512
|
try {
|
|
5487
|
-
return readFileSync11(
|
|
5513
|
+
return readFileSync11(path19, "utf-8");
|
|
5488
5514
|
} catch {
|
|
5489
5515
|
return void 0;
|
|
5490
5516
|
}
|
|
@@ -5659,16 +5685,16 @@ function extractDetail(sub, payload) {
|
|
|
5659
5685
|
}
|
|
5660
5686
|
return void 0;
|
|
5661
5687
|
}
|
|
5662
|
-
function defaultReadFile2(
|
|
5688
|
+
function defaultReadFile2(path19) {
|
|
5663
5689
|
try {
|
|
5664
|
-
return readFileSync12(
|
|
5690
|
+
return readFileSync12(path19, "utf-8");
|
|
5665
5691
|
} catch {
|
|
5666
5692
|
return void 0;
|
|
5667
5693
|
}
|
|
5668
5694
|
}
|
|
5669
|
-
function defaultWriteFile(
|
|
5670
|
-
mkdirSync6(
|
|
5671
|
-
writeFileSync8(
|
|
5695
|
+
function defaultWriteFile(path19, content) {
|
|
5696
|
+
mkdirSync6(path19.replace(/\/[^/]+$/, ""), { recursive: true });
|
|
5697
|
+
writeFileSync8(path19, content, "utf-8");
|
|
5672
5698
|
}
|
|
5673
5699
|
|
|
5674
5700
|
// packages/workspaces/dist/crew-pane.js
|
|
@@ -5694,6 +5720,9 @@ async function settleInputBox(runtime, pane) {
|
|
|
5694
5720
|
}
|
|
5695
5721
|
async function confirmedSendToPane(runtime, pane, message) {
|
|
5696
5722
|
const preSendScreen = await runtime.readPaneScreen(pane) ?? "";
|
|
5723
|
+
if (hasModalOptionList(preSendScreen)) {
|
|
5724
|
+
return { delivered: false, blockedByModal: true };
|
|
5725
|
+
}
|
|
5697
5726
|
await runtime.pasteToPane(pane, message);
|
|
5698
5727
|
let sawDraft = await settleInputBox(runtime, pane);
|
|
5699
5728
|
await runtime.sendKeyToPane(pane, "Enter");
|
|
@@ -5736,17 +5765,17 @@ async function resendCrewFirstTurn(runtime, captainName, project, name, message)
|
|
|
5736
5765
|
}
|
|
5737
5766
|
|
|
5738
5767
|
// packages/cli/src/lib/daemon-restart-broadcast.ts
|
|
5739
|
-
import
|
|
5740
|
-
import
|
|
5768
|
+
import fs17 from "fs";
|
|
5769
|
+
import path18 from "path";
|
|
5741
5770
|
function statePath2(stateRoot) {
|
|
5742
|
-
return
|
|
5771
|
+
return path18.join(stateRoot, "daemon-restart-state.json");
|
|
5743
5772
|
}
|
|
5744
5773
|
function computeRestartSignature(version, buildMtimeMs) {
|
|
5745
5774
|
return `${version}::${buildMtimeMs}`;
|
|
5746
5775
|
}
|
|
5747
5776
|
function readPersistedRestartSignature(stateRoot) {
|
|
5748
5777
|
try {
|
|
5749
|
-
const raw =
|
|
5778
|
+
const raw = fs17.readFileSync(statePath2(stateRoot), "utf-8");
|
|
5750
5779
|
const data = JSON.parse(raw);
|
|
5751
5780
|
return typeof data.signature === "string" ? data.signature : null;
|
|
5752
5781
|
} catch {
|
|
@@ -5754,20 +5783,21 @@ function readPersistedRestartSignature(stateRoot) {
|
|
|
5754
5783
|
}
|
|
5755
5784
|
}
|
|
5756
5785
|
function writePersistedRestartSignature(stateRoot, signature) {
|
|
5757
|
-
|
|
5758
|
-
|
|
5786
|
+
fs17.mkdirSync(stateRoot, { recursive: true });
|
|
5787
|
+
fs17.writeFileSync(statePath2(stateRoot), JSON.stringify({ signature }, null, 2) + "\n");
|
|
5759
5788
|
}
|
|
5760
5789
|
function restartNotice(version, isDevRebuild) {
|
|
5761
5790
|
const suffix = isDevRebuild ? " (dev build)" : "";
|
|
5762
5791
|
return `\u26A0\uFE0F Daemon restarted \u2192 v${version}${suffix} (control-plane bounced). Re-verify in-flight crews \u2014 a crew mid-first-turn may need a crew send.`;
|
|
5763
5792
|
}
|
|
5764
|
-
async function notifyCaptainsOfDaemonRestart(version, config, driver, isDevRebuild = false) {
|
|
5793
|
+
async function notifyCaptainsOfDaemonRestart(version, config, driver, isDevRebuild = false, appendCaptainMessage2) {
|
|
5765
5794
|
const notice = restartNotice(version, isDevRebuild);
|
|
5766
|
-
for (const [
|
|
5795
|
+
for (const [projName] of Object.entries(config.projects)) {
|
|
5767
5796
|
try {
|
|
5797
|
+
const proj = config.projects[projName];
|
|
5768
5798
|
const ref = await driver.status(proj.captainName);
|
|
5769
5799
|
if (ref) {
|
|
5770
|
-
await
|
|
5800
|
+
await appendCaptainMessage2(projName, notice);
|
|
5771
5801
|
}
|
|
5772
5802
|
} catch {
|
|
5773
5803
|
}
|
|
@@ -5775,12 +5805,12 @@ async function notifyCaptainsOfDaemonRestart(version, config, driver, isDevRebui
|
|
|
5775
5805
|
}
|
|
5776
5806
|
async function maybeBroadcastDaemonRestart(opts) {
|
|
5777
5807
|
try {
|
|
5778
|
-
const { version, buildMtimeMs, stateRoot, config, driver } = opts;
|
|
5808
|
+
const { version, buildMtimeMs, stateRoot, config, driver, appendCaptainMessage: appendCaptainMessage2 } = opts;
|
|
5779
5809
|
const signature = computeRestartSignature(version, buildMtimeMs);
|
|
5780
5810
|
const previous = readPersistedRestartSignature(stateRoot);
|
|
5781
5811
|
if (previous === signature) return;
|
|
5782
5812
|
const isDevRebuild = previous !== null && previous.split("::")[0] === version;
|
|
5783
|
-
await notifyCaptainsOfDaemonRestart(version, config, driver, isDevRebuild);
|
|
5813
|
+
await notifyCaptainsOfDaemonRestart(version, config, driver, isDevRebuild, appendCaptainMessage2);
|
|
5784
5814
|
writePersistedRestartSignature(stateRoot, signature);
|
|
5785
5815
|
} catch {
|
|
5786
5816
|
}
|
|
@@ -6041,14 +6071,15 @@ ${buildCompletionProtocol(rec.id, rec.project)}`;
|
|
|
6041
6071
|
buildMtimeMs,
|
|
6042
6072
|
stateRoot,
|
|
6043
6073
|
config: restartConfig,
|
|
6044
|
-
driver: registry.global(restartConfig)
|
|
6074
|
+
driver: registry.global(restartConfig),
|
|
6075
|
+
appendCaptainMessage: (project, text) => appendCaptainMessage({ stateRoot, project, text, source: "daemon" })
|
|
6045
6076
|
});
|
|
6046
6077
|
} catch (e) {
|
|
6047
6078
|
log(`daemon-restart broadcast setup failed: ${e.message}`);
|
|
6048
6079
|
}
|
|
6049
6080
|
}
|
|
6050
6081
|
const origStop = h.stop.bind(h);
|
|
6051
|
-
h.stop = async () => {
|
|
6082
|
+
h.stop = async (reason) => {
|
|
6052
6083
|
try {
|
|
6053
6084
|
cmuxStoreSource.stop();
|
|
6054
6085
|
} catch {
|
|
@@ -6061,11 +6092,24 @@ ${buildCompletionProtocol(rec.id, rec.project)}`;
|
|
|
6061
6092
|
codexAppServerSource.stop();
|
|
6062
6093
|
} catch {
|
|
6063
6094
|
}
|
|
6064
|
-
return origStop();
|
|
6095
|
+
return origStop(reason);
|
|
6065
6096
|
};
|
|
6066
6097
|
return h;
|
|
6067
6098
|
}
|
|
6099
|
+
function logCrashMarker(kind, err) {
|
|
6100
|
+
const message = err instanceof Error ? err.stack ?? err.message : String(err);
|
|
6101
|
+
process.stderr.write(`[squadrantd] ${(/* @__PURE__ */ new Date()).toISOString()} ${kind} pid=${process.pid} error=${message}
|
|
6102
|
+
`);
|
|
6103
|
+
}
|
|
6068
6104
|
if (process.argv[1] && process.argv[1].endsWith("squadrantd.js")) {
|
|
6105
|
+
process.on("uncaughtException", (err) => {
|
|
6106
|
+
logCrashMarker("uncaughtException", err);
|
|
6107
|
+
process.exit(1);
|
|
6108
|
+
});
|
|
6109
|
+
process.on("unhandledRejection", (reason) => {
|
|
6110
|
+
logCrashMarker("unhandledRejection", reason);
|
|
6111
|
+
process.exit(1);
|
|
6112
|
+
});
|
|
6069
6113
|
void (async () => {
|
|
6070
6114
|
const arg = process.argv[2];
|
|
6071
6115
|
if (arg === "--help" || arg === "-h" || arg === "--version" || arg === "-v") {
|
|
@@ -6079,10 +6123,11 @@ if (process.argv[1] && process.argv[1].endsWith("squadrantd.js")) {
|
|
|
6079
6123
|
process.exit(0);
|
|
6080
6124
|
}
|
|
6081
6125
|
const h = startSquadrantd({ sweepMs: 3e4 });
|
|
6082
|
-
|
|
6083
|
-
h.stop();
|
|
6084
|
-
|
|
6085
|
-
|
|
6126
|
+
const shutdown = (signal) => {
|
|
6127
|
+
void h.stop(signal).finally(() => process.exit(0));
|
|
6128
|
+
};
|
|
6129
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
6130
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
6086
6131
|
})();
|
|
6087
6132
|
}
|
|
6088
6133
|
export {
|