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