squadrant 0.17.1 → 0.18.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 +1261 -809
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +263 -139
- package/dist/squadrantd.js.map +1 -1
- package/package.json +1 -1
- package/plugin/skills/captain-ops/SKILL.md +1 -1
- package/plugin/skills/handback/SKILL.md +8 -0
- package/plugin/skills/takeover/SKILL.md +11 -0
- package/templates/captain.claude.md +1 -0
- package/templates/captain.generic.md +1 -0
package/dist/squadrantd.js
CHANGED
|
@@ -60,22 +60,90 @@ var init_snapshot = __esm({
|
|
|
60
60
|
});
|
|
61
61
|
|
|
62
62
|
// packages/cli/src/squadrantd.ts
|
|
63
|
-
import { join as join19, dirname as
|
|
63
|
+
import { join as join19, dirname as dirname4 } from "path";
|
|
64
64
|
import { homedir as homedir14 } from "os";
|
|
65
65
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
66
|
-
import { readFileSync as
|
|
66
|
+
import { readFileSync as readFileSync13, statSync as statSync4, existsSync as existsSync12 } from "fs";
|
|
67
67
|
|
|
68
68
|
// packages/shared/dist/config.js
|
|
69
|
-
import
|
|
70
|
-
import path from "path";
|
|
69
|
+
import path2 from "path";
|
|
71
70
|
import os from "os";
|
|
72
71
|
import chalk from "chalk";
|
|
73
|
-
|
|
74
|
-
|
|
72
|
+
|
|
73
|
+
// packages/shared/dist/lib/config-io.js
|
|
74
|
+
import fs from "fs";
|
|
75
|
+
import path from "path";
|
|
76
|
+
var didLogMigration = false;
|
|
77
|
+
var migrationRun = false;
|
|
78
|
+
function tightenModeSync(p, expectedMode) {
|
|
79
|
+
try {
|
|
80
|
+
if (!fs.existsSync(p))
|
|
81
|
+
return;
|
|
82
|
+
const stat = fs.statSync(p);
|
|
83
|
+
const currentMode = stat.mode & 4095;
|
|
84
|
+
if ((currentMode & ~expectedMode) !== 0) {
|
|
85
|
+
fs.chmodSync(p, expectedMode);
|
|
86
|
+
if (!didLogMigration) {
|
|
87
|
+
console.warn(`\x1B[33m\u26A0\x1B[0m squadrant: tightened config file permissions (security fix #668)`);
|
|
88
|
+
didLogMigration = true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} catch {
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function writeConfigFileSync(filePath, content) {
|
|
95
|
+
ensureDirSync(path.dirname(filePath));
|
|
96
|
+
fs.writeFileSync(filePath, content, { mode: 384 });
|
|
97
|
+
tightenModeSync(filePath, 384);
|
|
98
|
+
}
|
|
99
|
+
function ensureDirSync(dirPath) {
|
|
100
|
+
if (dirPath !== CONFIG_DIR && !dirPath.startsWith(CONFIG_DIR + path.sep)) {
|
|
101
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
fs.mkdirSync(dirPath, { recursive: true, mode: 448 });
|
|
105
|
+
let current = dirPath;
|
|
106
|
+
while (current === CONFIG_DIR || current.startsWith(CONFIG_DIR + path.sep)) {
|
|
107
|
+
tightenModeSync(current, 448);
|
|
108
|
+
if (current === CONFIG_DIR)
|
|
109
|
+
break;
|
|
110
|
+
const parent = path.dirname(current);
|
|
111
|
+
if (parent === current)
|
|
112
|
+
break;
|
|
113
|
+
current = parent;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function readConfigFileSync(filePath) {
|
|
117
|
+
return fs.readFileSync(filePath, "utf-8");
|
|
118
|
+
}
|
|
119
|
+
function migrateConfigPermsSync() {
|
|
120
|
+
if (migrationRun)
|
|
121
|
+
return;
|
|
122
|
+
migrationRun = true;
|
|
123
|
+
tightenModeSync(CONFIG_DIR, 448);
|
|
124
|
+
tightenModeSync(path.join(CONFIG_DIR, "config.json"), 384);
|
|
125
|
+
const projectsDir = path.join(CONFIG_DIR, "projects");
|
|
126
|
+
tightenModeSync(projectsDir, 448);
|
|
127
|
+
try {
|
|
128
|
+
if (fs.existsSync(projectsDir)) {
|
|
129
|
+
const files = fs.readdirSync(projectsDir);
|
|
130
|
+
for (const file of files) {
|
|
131
|
+
if (file.endsWith(".json")) {
|
|
132
|
+
tightenModeSync(path.join(projectsDir, file), 384);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
} catch {
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// packages/shared/dist/config.js
|
|
141
|
+
var DEFAULT_CONFIG_PATH = process.env.SQUADRANT_CONFIG || path2.join(os.homedir(), ".config", "squadrant", "config.json");
|
|
142
|
+
var CONFIG_DIR = path2.dirname(DEFAULT_CONFIG_PATH);
|
|
75
143
|
function getDefaultConfig() {
|
|
76
144
|
return {
|
|
77
145
|
commandName: "\u{1F3DB}\uFE0F command",
|
|
78
|
-
hubVault:
|
|
146
|
+
hubVault: path2.join(os.homedir(), "squadrant-hub"),
|
|
79
147
|
projects: {},
|
|
80
148
|
agents: {
|
|
81
149
|
claude: { cli: "claude", driver: "claude" }
|
|
@@ -119,13 +187,14 @@ function getDefaultConfig() {
|
|
|
119
187
|
},
|
|
120
188
|
metrics: {
|
|
121
189
|
enabled: true,
|
|
122
|
-
path:
|
|
190
|
+
path: path2.join(CONFIG_DIR, "metrics.json")
|
|
123
191
|
}
|
|
124
192
|
};
|
|
125
193
|
}
|
|
126
194
|
function loadConfig(configPath = DEFAULT_CONFIG_PATH) {
|
|
195
|
+
migrateConfigPermsSync();
|
|
127
196
|
try {
|
|
128
|
-
const raw =
|
|
197
|
+
const raw = readConfigFileSync(configPath);
|
|
129
198
|
const config = JSON.parse(raw);
|
|
130
199
|
if (config.defaults.models && !config.defaults.roles) {
|
|
131
200
|
const m = config.defaults.models;
|
|
@@ -150,27 +219,24 @@ function loadConfig(configPath = DEFAULT_CONFIG_PATH) {
|
|
|
150
219
|
}
|
|
151
220
|
}
|
|
152
221
|
function saveConfig(config, configPath = DEFAULT_CONFIG_PATH) {
|
|
153
|
-
|
|
154
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
155
|
-
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
222
|
+
writeConfigFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
156
223
|
}
|
|
157
224
|
function resolveHome(p) {
|
|
158
225
|
return p.startsWith("~") ? p.replace("~", os.homedir()) : p;
|
|
159
226
|
}
|
|
160
227
|
|
|
161
228
|
// packages/shared/dist/project-config.js
|
|
162
|
-
import fs2 from "fs";
|
|
163
229
|
import os2 from "os";
|
|
164
|
-
import
|
|
230
|
+
import path3 from "path";
|
|
165
231
|
function defaultRoot() {
|
|
166
|
-
return
|
|
232
|
+
return path3.join(os2.homedir(), ".config", "squadrant");
|
|
167
233
|
}
|
|
168
234
|
function projectConfigPath(name, root = defaultRoot()) {
|
|
169
|
-
return
|
|
235
|
+
return path3.join(root, "projects", `${name}.json`);
|
|
170
236
|
}
|
|
171
237
|
function loadProjectOverride(name, root = defaultRoot()) {
|
|
172
238
|
try {
|
|
173
|
-
return JSON.parse(
|
|
239
|
+
return JSON.parse(readConfigFileSync(projectConfigPath(name, root)));
|
|
174
240
|
} catch {
|
|
175
241
|
return {};
|
|
176
242
|
}
|
|
@@ -187,8 +253,7 @@ function deepMerge(base, patch) {
|
|
|
187
253
|
function saveProjectOverride(name, patch, root = defaultRoot()) {
|
|
188
254
|
const merged = deepMerge(loadProjectOverride(name, root), patch);
|
|
189
255
|
const file = projectConfigPath(name, root);
|
|
190
|
-
|
|
191
|
-
fs2.writeFileSync(file, JSON.stringify(merged, null, 2) + "\n");
|
|
256
|
+
writeConfigFileSync(file, JSON.stringify(merged, null, 2) + "\n");
|
|
192
257
|
}
|
|
193
258
|
var DEFAULT_NOTIFY = { active: false, cap: true, crew: "alert_only" };
|
|
194
259
|
function resolveNotify(globalNotify, override) {
|
|
@@ -208,9 +273,9 @@ var TERMINAL_STATES = /* @__PURE__ */ new Set([
|
|
|
208
273
|
]);
|
|
209
274
|
|
|
210
275
|
// packages/shared/dist/lib/cmux-autoconfig.js
|
|
211
|
-
import { existsSync as existsSync4,
|
|
276
|
+
import { existsSync as existsSync4, rmSync as rmSync2 } from "fs";
|
|
212
277
|
import { homedir as homedir3 } from "os";
|
|
213
|
-
import {
|
|
278
|
+
import { join as join4 } from "path";
|
|
214
279
|
|
|
215
280
|
// packages/shared/dist/lib/cmux-config.js
|
|
216
281
|
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
@@ -233,22 +298,22 @@ var MINIMAL_TEMPLATE = [
|
|
|
233
298
|
``
|
|
234
299
|
].join("\n");
|
|
235
300
|
function ensureSocketAutomation(opts = {}) {
|
|
236
|
-
const
|
|
237
|
-
if (!existsSync(
|
|
238
|
-
mkdirSync(dirname(
|
|
239
|
-
writeFileSync(
|
|
240
|
-
return { path:
|
|
301
|
+
const path20 = opts.path ?? defaultCmuxConfigPath();
|
|
302
|
+
if (!existsSync(path20)) {
|
|
303
|
+
mkdirSync(dirname(path20), { recursive: true });
|
|
304
|
+
writeFileSync(path20, MINIMAL_TEMPLATE);
|
|
305
|
+
return { path: path20, changed: true, alreadySet: false };
|
|
241
306
|
}
|
|
242
|
-
const text = readFileSync(
|
|
307
|
+
const text = readFileSync(path20, "utf-8");
|
|
243
308
|
const current = parse(text)?.automation?.socketControlMode;
|
|
244
309
|
if (current === AUTOMATION_MODE) {
|
|
245
|
-
return { path:
|
|
310
|
+
return { path: path20, changed: false, alreadySet: true };
|
|
246
311
|
}
|
|
247
312
|
const edits = modify(text, [...SOCKET_CONTROL_MODE_PATH], AUTOMATION_MODE, {
|
|
248
313
|
formattingOptions: { insertSpaces: true, tabSize: 2 }
|
|
249
314
|
});
|
|
250
|
-
writeFileSync(
|
|
251
|
-
return { path:
|
|
315
|
+
writeFileSync(path20, applyEdits(text, edits));
|
|
316
|
+
return { path: path20, changed: true, alreadySet: false };
|
|
252
317
|
}
|
|
253
318
|
|
|
254
319
|
// packages/shared/dist/lib/cmux-probe.js
|
|
@@ -370,9 +435,9 @@ function sleep(ms) {
|
|
|
370
435
|
function defaultStatePath() {
|
|
371
436
|
return join4(homedir3(), ".config", "squadrant", "state", "cmux-autoconfig.json");
|
|
372
437
|
}
|
|
373
|
-
function readState(
|
|
438
|
+
function readState(path20) {
|
|
374
439
|
try {
|
|
375
|
-
return JSON.parse(
|
|
440
|
+
return JSON.parse(readConfigFileSync(path20));
|
|
376
441
|
} catch {
|
|
377
442
|
return {};
|
|
378
443
|
}
|
|
@@ -388,8 +453,7 @@ async function ensureCmuxAutoConfig(opts = {}) {
|
|
|
388
453
|
if (needsRestart) {
|
|
389
454
|
const already = readState(statePath3).promptedRestart === true;
|
|
390
455
|
if (!already) {
|
|
391
|
-
|
|
392
|
-
writeFileSync3(statePath3, JSON.stringify({ promptedRestart: true }));
|
|
456
|
+
writeConfigFileSync(statePath3, JSON.stringify({ promptedRestart: true }));
|
|
393
457
|
promptedThisRun = true;
|
|
394
458
|
}
|
|
395
459
|
} else if (verdict === "reachable") {
|
|
@@ -420,25 +484,25 @@ var compatManifest = {
|
|
|
420
484
|
};
|
|
421
485
|
|
|
422
486
|
// packages/shared/dist/lib/update-check.js
|
|
423
|
-
import
|
|
424
|
-
import
|
|
487
|
+
import fs2 from "fs";
|
|
488
|
+
import path4 from "path";
|
|
425
489
|
import os3 from "os";
|
|
426
490
|
import https from "https";
|
|
427
|
-
var UPDATE_CHECK_STATE_PATH =
|
|
491
|
+
var UPDATE_CHECK_STATE_PATH = path4.join(os3.homedir(), ".config", "squadrant", "update-check.json");
|
|
428
492
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
429
493
|
var FAILURE_RETRY_MS = 60 * 60 * 1e3;
|
|
430
494
|
|
|
431
495
|
// packages/shared/dist/lib/git-worktree.js
|
|
432
496
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
433
|
-
import
|
|
434
|
-
import
|
|
497
|
+
import fs3 from "fs";
|
|
498
|
+
import path5 from "path";
|
|
435
499
|
|
|
436
500
|
// packages/shared/dist/lib/resolve-text-input.js
|
|
437
|
-
import
|
|
501
|
+
import fs4 from "fs";
|
|
438
502
|
|
|
439
503
|
// packages/shared/dist/lib/runtime-sync.js
|
|
440
|
-
import
|
|
441
|
-
import
|
|
504
|
+
import fs5 from "fs";
|
|
505
|
+
import path6 from "path";
|
|
442
506
|
|
|
443
507
|
// packages/shared/dist/lib/tool-compat.js
|
|
444
508
|
function parseSemVer(v) {
|
|
@@ -472,13 +536,13 @@ function checkToolCompat(name, rawVersion, entry) {
|
|
|
472
536
|
}
|
|
473
537
|
|
|
474
538
|
// packages/shared/dist/lib/canonical-source.js
|
|
475
|
-
import
|
|
476
|
-
import
|
|
539
|
+
import fs6 from "fs";
|
|
540
|
+
import path7 from "path";
|
|
477
541
|
|
|
478
542
|
// packages/shared/dist/lib/daily-logs.js
|
|
479
543
|
import { execSync } from "child_process";
|
|
480
|
-
import
|
|
481
|
-
import
|
|
544
|
+
import fs7 from "fs";
|
|
545
|
+
import path8 from "path";
|
|
482
546
|
import matter from "gray-matter";
|
|
483
547
|
|
|
484
548
|
// packages/core/dist/state-machine.js
|
|
@@ -507,7 +571,21 @@ function nextPendingMonitor(current, ev, now) {
|
|
|
507
571
|
}
|
|
508
572
|
function reduce(rec, ev, now) {
|
|
509
573
|
if (ev.type === "task.reopened") {
|
|
510
|
-
return { ...rec, state: "working", question: void 0, error: void 0, lastHeartbeat: now, lastEvent: ev.type };
|
|
574
|
+
return { ...rec, state: "working", question: void 0, error: void 0, lastHeartbeat: now, lastEvent: ev.type, workingStretchStartedAt: now };
|
|
575
|
+
}
|
|
576
|
+
if (ev.type === "crew.takeover.started") {
|
|
577
|
+
if (rec.operatorHold)
|
|
578
|
+
return { ...rec, lastHeartbeat: now, lastEvent: ev.type };
|
|
579
|
+
return {
|
|
580
|
+
...rec,
|
|
581
|
+
operatorHold: { since: now, ...ev.note !== void 0 ? { note: ev.note } : {} },
|
|
582
|
+
lastHeartbeat: now,
|
|
583
|
+
lastEvent: ev.type
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
if (ev.type === "crew.takeover.ended") {
|
|
587
|
+
const { operatorHold: _dropped, ...rest } = rec;
|
|
588
|
+
return { ...rest, lastHeartbeat: now, lastEvent: ev.type };
|
|
511
589
|
}
|
|
512
590
|
if (TERMINAL_STATES.has(rec.state))
|
|
513
591
|
return rec;
|
|
@@ -523,8 +601,9 @@ function reduce(rec, ev, now) {
|
|
|
523
601
|
// resuming after a blocked→reply clears the question
|
|
524
602
|
pendingTool: void 0,
|
|
525
603
|
// #354: a new turn closes any prior tool window
|
|
526
|
-
pendingMonitor: void 0
|
|
604
|
+
pendingMonitor: void 0,
|
|
527
605
|
// #594a: same reset — a new turn moots any prior watch
|
|
606
|
+
workingStretchStartedAt: now
|
|
528
607
|
};
|
|
529
608
|
case "task.progress": {
|
|
530
609
|
const pendingTool = nextPendingTool(rec.pendingTool, ev, now);
|
|
@@ -693,6 +772,8 @@ function firePush(deps, project, prev, next, event, lastCaptainTurnAt) {
|
|
|
693
772
|
return;
|
|
694
773
|
if (!ATTENTION_STATES.has(next.state))
|
|
695
774
|
return;
|
|
775
|
+
if (next.operatorHold)
|
|
776
|
+
return;
|
|
696
777
|
if (next.state === "awaiting-input" && lastCaptainTurnAt != null && deps.now() - lastCaptainTurnAt <= IDLE_DEBOUNCE_MS) {
|
|
697
778
|
return;
|
|
698
779
|
}
|
|
@@ -744,8 +825,11 @@ var KNOWN_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
|
744
825
|
"task.reconcile-failed",
|
|
745
826
|
"task.cancelled",
|
|
746
827
|
"task.session.ended",
|
|
747
|
-
"task.first-turn.confirmed"
|
|
828
|
+
"task.first-turn.confirmed",
|
|
748
829
|
// #466: delivery confirmation
|
|
830
|
+
"crew.takeover.started",
|
|
831
|
+
"crew.takeover.ended"
|
|
832
|
+
// #649: operator takeover
|
|
749
833
|
]);
|
|
750
834
|
function createDaemon(deps) {
|
|
751
835
|
const { store, now } = deps;
|
|
@@ -927,9 +1011,32 @@ function createDaemon(deps) {
|
|
|
927
1011
|
store.delete(r.project, r.id);
|
|
928
1012
|
continue;
|
|
929
1013
|
}
|
|
1014
|
+
if (r.operatorHold) {
|
|
1015
|
+
const threshold = (deps.takeoverNudgeHours ?? 6) * 36e5;
|
|
1016
|
+
const holdAge = t - r.operatorHold.since;
|
|
1017
|
+
if (holdAge > threshold) {
|
|
1018
|
+
const timeSinceLastNudge = t - (r.operatorHold.lastNudgeAt ?? 0);
|
|
1019
|
+
if (timeSinceLastNudge > threshold) {
|
|
1020
|
+
const hrs = Math.round(holdAge / 36e5);
|
|
1021
|
+
const tag = crewTag(r);
|
|
1022
|
+
const message = `CREW HELD-LONG ${tag} \u2014 held ${hrs}h. Ask the operator whether it is still in use. Do not release it yourself.`;
|
|
1023
|
+
store.put({ ...r, operatorHold: { ...r.operatorHold, lastNudgeAt: t } });
|
|
1024
|
+
if (deps.notify) {
|
|
1025
|
+
try {
|
|
1026
|
+
const p = deps.notify({ project: r.project, message, record: r, event: { type: "task.progress", id: r.id } });
|
|
1027
|
+
if (p && typeof p.catch === "function")
|
|
1028
|
+
p.catch(() => {
|
|
1029
|
+
});
|
|
1030
|
+
} catch {
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
930
1036
|
if (!TERMINAL_STATES.has(r.state) && !isStickyAttention(r.state)) {
|
|
931
1037
|
const ceiling = deps.taskTimeoutMs ?? DEFAULT_TASK_TIMEOUT_MS;
|
|
932
|
-
|
|
1038
|
+
const refTime = r.workingStretchStartedAt ?? r.createdAt;
|
|
1039
|
+
if (t - refTime > ceiling) {
|
|
933
1040
|
const prevState = r.state;
|
|
934
1041
|
const tag = crewTag(r);
|
|
935
1042
|
const hrs = Math.round(ceiling / 36e5);
|
|
@@ -1048,7 +1155,7 @@ function createDaemon(deps) {
|
|
|
1048
1155
|
}
|
|
1049
1156
|
|
|
1050
1157
|
// packages/core/dist/mailbox.js
|
|
1051
|
-
import { promises as
|
|
1158
|
+
import { promises as fs8 } from "fs";
|
|
1052
1159
|
import { join as join5 } from "path";
|
|
1053
1160
|
import { randomUUID } from "crypto";
|
|
1054
1161
|
function inboxDir(stateRoot) {
|
|
@@ -1065,7 +1172,7 @@ async function listRotatedOldestFirst(stateRoot, project) {
|
|
|
1065
1172
|
const dir = inboxDir(stateRoot);
|
|
1066
1173
|
let entries;
|
|
1067
1174
|
try {
|
|
1068
|
-
entries = await
|
|
1175
|
+
entries = await fs8.readdir(dir);
|
|
1069
1176
|
} catch {
|
|
1070
1177
|
return [];
|
|
1071
1178
|
}
|
|
@@ -1074,7 +1181,7 @@ async function listRotatedOldestFirst(stateRoot, project) {
|
|
|
1074
1181
|
}
|
|
1075
1182
|
async function readMaxSeqFromFile(file) {
|
|
1076
1183
|
try {
|
|
1077
|
-
const buf = await
|
|
1184
|
+
const buf = await fs8.readFile(file, "utf-8");
|
|
1078
1185
|
if (!buf.trim())
|
|
1079
1186
|
return 0;
|
|
1080
1187
|
const lines = buf.trim().split("\n");
|
|
@@ -1116,12 +1223,12 @@ function withProjectLock(project, fn) {
|
|
|
1116
1223
|
function appendEntry(stateRoot, project, build) {
|
|
1117
1224
|
return withProjectLock(project, async () => {
|
|
1118
1225
|
const dir = inboxDir(stateRoot);
|
|
1119
|
-
await
|
|
1226
|
+
await fs8.mkdir(dir, { recursive: true });
|
|
1120
1227
|
const file = logPath(stateRoot, project);
|
|
1121
1228
|
const lastSeq = await readMaxSeq(stateRoot, project);
|
|
1122
1229
|
const seq = lastSeq + 1;
|
|
1123
1230
|
const entry = build(seq);
|
|
1124
|
-
await
|
|
1231
|
+
await fs8.appendFile(file, JSON.stringify(entry) + "\n", { encoding: "utf-8" });
|
|
1125
1232
|
return seq;
|
|
1126
1233
|
});
|
|
1127
1234
|
}
|
|
@@ -1152,7 +1259,7 @@ function cursorPath(stateRoot, project, subscriber) {
|
|
|
1152
1259
|
async function readCursor(opts) {
|
|
1153
1260
|
let buf;
|
|
1154
1261
|
try {
|
|
1155
|
-
buf = await
|
|
1262
|
+
buf = await fs8.readFile(cursorPath(opts.stateRoot, opts.project, opts.subscriber), "utf-8");
|
|
1156
1263
|
} catch (e) {
|
|
1157
1264
|
if (e.code === "ENOENT")
|
|
1158
1265
|
return null;
|
|
@@ -1167,7 +1274,7 @@ async function readCursor(opts) {
|
|
|
1167
1274
|
}
|
|
1168
1275
|
}
|
|
1169
1276
|
async function writeCursor(opts) {
|
|
1170
|
-
await
|
|
1277
|
+
await fs8.mkdir(inboxDir(opts.stateRoot), { recursive: true });
|
|
1171
1278
|
const dest = cursorPath(opts.stateRoot, opts.project, opts.subscriber);
|
|
1172
1279
|
const tmp = `${dest}.${process.pid}.${randomUUID()}.tmp`;
|
|
1173
1280
|
const data = {
|
|
@@ -1175,7 +1282,7 @@ async function writeCursor(opts) {
|
|
|
1175
1282
|
subscriber: opts.subscriber,
|
|
1176
1283
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1177
1284
|
};
|
|
1178
|
-
const handle = await
|
|
1285
|
+
const handle = await fs8.open(tmp, "w");
|
|
1179
1286
|
try {
|
|
1180
1287
|
await handle.writeFile(JSON.stringify(data), { encoding: "utf-8" });
|
|
1181
1288
|
await handle.sync();
|
|
@@ -1183,9 +1290,9 @@ async function writeCursor(opts) {
|
|
|
1183
1290
|
await handle.close();
|
|
1184
1291
|
}
|
|
1185
1292
|
try {
|
|
1186
|
-
await
|
|
1293
|
+
await fs8.rename(tmp, dest);
|
|
1187
1294
|
} catch (e) {
|
|
1188
|
-
await
|
|
1295
|
+
await fs8.unlink(tmp).catch(() => {
|
|
1189
1296
|
});
|
|
1190
1297
|
throw e;
|
|
1191
1298
|
}
|
|
@@ -1196,7 +1303,7 @@ async function* readFromCursor(opts) {
|
|
|
1196
1303
|
for (const file of files) {
|
|
1197
1304
|
let buf;
|
|
1198
1305
|
try {
|
|
1199
|
-
buf = await
|
|
1306
|
+
buf = await fs8.readFile(file, "utf-8");
|
|
1200
1307
|
} catch (e) {
|
|
1201
1308
|
if (e.code === "ENOENT")
|
|
1202
1309
|
continue;
|
|
@@ -1222,7 +1329,7 @@ async function mailboxStats(stateRoot, project) {
|
|
|
1222
1329
|
let sizeBytes = 0;
|
|
1223
1330
|
for (const f of [file, ...rotated]) {
|
|
1224
1331
|
try {
|
|
1225
|
-
sizeBytes += (await
|
|
1332
|
+
sizeBytes += (await fs8.stat(f)).size;
|
|
1226
1333
|
} catch (e) {
|
|
1227
1334
|
if (e.code !== "ENOENT")
|
|
1228
1335
|
throw e;
|
|
@@ -1238,7 +1345,7 @@ async function mailboxStats(stateRoot, project) {
|
|
|
1238
1345
|
}
|
|
1239
1346
|
async function oldestEntryAgeMs(file) {
|
|
1240
1347
|
try {
|
|
1241
|
-
const buf = await
|
|
1348
|
+
const buf = await fs8.readFile(file, "utf-8");
|
|
1242
1349
|
const firstLine = buf.split("\n").find((l) => l.trim());
|
|
1243
1350
|
if (!firstLine)
|
|
1244
1351
|
return 0;
|
|
@@ -1253,7 +1360,7 @@ async function rotateIfNeeded(opts) {
|
|
|
1253
1360
|
const file = logPath(opts.stateRoot, opts.project);
|
|
1254
1361
|
let size = 0;
|
|
1255
1362
|
try {
|
|
1256
|
-
size = (await
|
|
1363
|
+
size = (await fs8.stat(file)).size;
|
|
1257
1364
|
} catch (e) {
|
|
1258
1365
|
if (e.code === "ENOENT")
|
|
1259
1366
|
return { rotated: false };
|
|
@@ -1269,29 +1376,29 @@ async function rotateIfNeeded(opts) {
|
|
|
1269
1376
|
const dst = `${file}.${n + 1}`;
|
|
1270
1377
|
if (n + 1 > opts.keepCount) {
|
|
1271
1378
|
try {
|
|
1272
|
-
await
|
|
1379
|
+
await fs8.unlink(src);
|
|
1273
1380
|
} catch (e) {
|
|
1274
1381
|
if (e.code !== "ENOENT")
|
|
1275
1382
|
throw e;
|
|
1276
1383
|
}
|
|
1277
1384
|
} else {
|
|
1278
1385
|
try {
|
|
1279
|
-
await
|
|
1386
|
+
await fs8.rename(src, dst);
|
|
1280
1387
|
} catch (e) {
|
|
1281
1388
|
if (e.code !== "ENOENT")
|
|
1282
1389
|
throw e;
|
|
1283
1390
|
}
|
|
1284
1391
|
}
|
|
1285
1392
|
}
|
|
1286
|
-
await
|
|
1287
|
-
await
|
|
1393
|
+
await fs8.rename(file, `${file}.1`);
|
|
1394
|
+
await fs8.writeFile(file, "", { encoding: "utf-8" });
|
|
1288
1395
|
return { rotated: true, from: file, to: `${file}.1` };
|
|
1289
1396
|
});
|
|
1290
1397
|
}
|
|
1291
1398
|
|
|
1292
1399
|
// packages/core/dist/protocol.js
|
|
1293
1400
|
import { createServer, createConnection } from "net";
|
|
1294
|
-
import { existsSync as existsSync5, unlinkSync } from "fs";
|
|
1401
|
+
import { existsSync as existsSync5, unlinkSync, chmodSync } from "fs";
|
|
1295
1402
|
var PROTOCOL_VERSION = 1;
|
|
1296
1403
|
function encodeMsg(obj) {
|
|
1297
1404
|
return JSON.stringify(obj) + "\n";
|
|
@@ -1405,6 +1512,12 @@ function startServer(sockPath, handlerOrCallbacks, onListenError = defaultListen
|
|
|
1405
1512
|
});
|
|
1406
1513
|
});
|
|
1407
1514
|
server.on("error", onListenError);
|
|
1515
|
+
server.on("listening", () => {
|
|
1516
|
+
try {
|
|
1517
|
+
chmodSync(sockPath, 384);
|
|
1518
|
+
} catch {
|
|
1519
|
+
}
|
|
1520
|
+
});
|
|
1408
1521
|
server.listen(sockPath);
|
|
1409
1522
|
return server;
|
|
1410
1523
|
}
|
|
@@ -1548,7 +1661,7 @@ function reconcileLiveness(prev, next) {
|
|
|
1548
1661
|
}
|
|
1549
1662
|
|
|
1550
1663
|
// packages/core/dist/store.js
|
|
1551
|
-
import { mkdirSync as
|
|
1664
|
+
import { mkdirSync as mkdirSync2, readFileSync as readFileSync4, readdirSync, renameSync, writeFileSync as writeFileSync3, existsSync as existsSync6, rmSync as rmSync3, statSync } from "fs";
|
|
1552
1665
|
import { join as join6, resolve, sep } from "path";
|
|
1553
1666
|
function safeSegment(kind, s) {
|
|
1554
1667
|
if (typeof s !== "string" || s.length === 0) {
|
|
@@ -1574,10 +1687,10 @@ function createStore(root) {
|
|
|
1574
1687
|
const taskFile = (p, id) => assertUnderRoot(join6(projDir(p), `${safeSegment("id", id)}.json`));
|
|
1575
1688
|
return {
|
|
1576
1689
|
put(rec) {
|
|
1577
|
-
|
|
1690
|
+
mkdirSync2(projDir(rec.project), { recursive: true });
|
|
1578
1691
|
const dest = taskFile(rec.project, rec.id);
|
|
1579
1692
|
const tmp = `${dest}.tmp`;
|
|
1580
|
-
|
|
1693
|
+
writeFileSync3(tmp, JSON.stringify(rec, null, 2));
|
|
1581
1694
|
renameSync(tmp, dest);
|
|
1582
1695
|
},
|
|
1583
1696
|
get(project, id) {
|
|
@@ -1585,7 +1698,7 @@ function createStore(root) {
|
|
|
1585
1698
|
if (!existsSync6(f))
|
|
1586
1699
|
return void 0;
|
|
1587
1700
|
try {
|
|
1588
|
-
return JSON.parse(
|
|
1701
|
+
return JSON.parse(readFileSync4(f, "utf-8"));
|
|
1589
1702
|
} catch {
|
|
1590
1703
|
return void 0;
|
|
1591
1704
|
}
|
|
@@ -1596,7 +1709,7 @@ function createStore(root) {
|
|
|
1596
1709
|
return [];
|
|
1597
1710
|
return readdirSync(d).filter((n) => n.endsWith(".json")).map((n) => {
|
|
1598
1711
|
try {
|
|
1599
|
-
return JSON.parse(
|
|
1712
|
+
return JSON.parse(readFileSync4(join6(d, n), "utf-8"));
|
|
1600
1713
|
} catch {
|
|
1601
1714
|
return void 0;
|
|
1602
1715
|
}
|
|
@@ -1630,7 +1743,7 @@ function createStore(root) {
|
|
|
1630
1743
|
import { homedir as homedir4 } from "os";
|
|
1631
1744
|
import { join as join7, resolve as resolve2, sep as sep2 } from "path";
|
|
1632
1745
|
import { randomBytes } from "crypto";
|
|
1633
|
-
import { mkdirSync as
|
|
1746
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync5, readdirSync as readdirSync2, renameSync as renameSync2, writeFileSync as writeFileSync4, existsSync as existsSync7, rmSync as rmSync4, statSync as statSync2 } from "fs";
|
|
1634
1747
|
var WORK_ITEM_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
1635
1748
|
|
|
1636
1749
|
// packages/core/dist/index.js
|
|
@@ -1638,9 +1751,9 @@ init_snapshot();
|
|
|
1638
1751
|
|
|
1639
1752
|
// packages/core/dist/launchd.js
|
|
1640
1753
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
1641
|
-
import { mkdirSync as
|
|
1754
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync5, readFileSync as readFileSync6, existsSync as existsSync8, openSync, writeSync, closeSync, unlinkSync as unlinkSync2, constants } from "fs";
|
|
1642
1755
|
import { homedir as homedir5 } from "os";
|
|
1643
|
-
import { dirname as
|
|
1756
|
+
import { dirname as dirname2, join as join8 } from "path";
|
|
1644
1757
|
import { fileURLToPath } from "url";
|
|
1645
1758
|
|
|
1646
1759
|
// packages/core/dist/crew-pane-reader.js
|
|
@@ -1711,10 +1824,10 @@ function makeGate(opts) {
|
|
|
1711
1824
|
import { homedir as homedir6 } from "os";
|
|
1712
1825
|
import { join as join9 } from "path";
|
|
1713
1826
|
import { spawn as realSpawn } from "child_process";
|
|
1714
|
-
import { writeFileSync as
|
|
1827
|
+
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync5 } from "fs";
|
|
1715
1828
|
|
|
1716
1829
|
// packages/core/dist/daemon/liveness-registry.js
|
|
1717
|
-
import { writeFileSync as
|
|
1830
|
+
import { writeFileSync as writeFileSync6, readFileSync as readFileSync7, renameSync as renameSync3 } from "fs";
|
|
1718
1831
|
var LivenessRegistry = class {
|
|
1719
1832
|
path;
|
|
1720
1833
|
readFile;
|
|
@@ -1724,13 +1837,13 @@ var LivenessRegistry = class {
|
|
|
1724
1837
|
this.path = opts.path;
|
|
1725
1838
|
this.readFile = opts.readFile ?? ((p) => {
|
|
1726
1839
|
try {
|
|
1727
|
-
return
|
|
1840
|
+
return readFileSync7(p, "utf-8");
|
|
1728
1841
|
} catch {
|
|
1729
1842
|
return void 0;
|
|
1730
1843
|
}
|
|
1731
1844
|
});
|
|
1732
1845
|
this.writeFile = opts.writeFile ?? ((p, c) => {
|
|
1733
|
-
|
|
1846
|
+
writeFileSync6(`${p}.tmp`, c);
|
|
1734
1847
|
renameSync3(`${p}.tmp`, p);
|
|
1735
1848
|
});
|
|
1736
1849
|
}
|
|
@@ -1791,14 +1904,16 @@ function buildContext(opts) {
|
|
|
1791
1904
|
const sockPath = opts.sockPath ?? join9(homedir6(), ".config", "squadrant", "squadrant.sock");
|
|
1792
1905
|
const store = createStore(stateRoot);
|
|
1793
1906
|
const bootedAt = Date.now();
|
|
1794
|
-
const
|
|
1907
|
+
const config = loadConfig();
|
|
1908
|
+
const taskTimeoutMs = config.defaults.taskTimeoutMs;
|
|
1909
|
+
const takeoverNudgeHours = config.defaults.takeoverNudgeHours;
|
|
1795
1910
|
const isPidAlive = opts.isPidAlive ?? defaultIsPidAlive;
|
|
1796
1911
|
const spawn2 = opts.spawn ?? realSpawn;
|
|
1797
1912
|
const resultsDir = join9(stateRoot, "_results");
|
|
1798
|
-
|
|
1913
|
+
mkdirSync5(resultsDir, { recursive: true });
|
|
1799
1914
|
const writeResult = (id, payload) => {
|
|
1800
1915
|
const p = join9(resultsDir, `${id}.txt`);
|
|
1801
|
-
|
|
1916
|
+
writeFileSync7(p, payload);
|
|
1802
1917
|
return p;
|
|
1803
1918
|
};
|
|
1804
1919
|
const log = (m) => process.stderr.write(`[squadrantd] ${(/* @__PURE__ */ new Date()).toISOString()} ${m}
|
|
@@ -1811,6 +1926,7 @@ function buildContext(opts) {
|
|
|
1811
1926
|
bootedAt,
|
|
1812
1927
|
lastSweepAt: { value: null },
|
|
1813
1928
|
taskTimeoutMs,
|
|
1929
|
+
takeoverNudgeHours,
|
|
1814
1930
|
isPidAlive,
|
|
1815
1931
|
spawn: spawn2,
|
|
1816
1932
|
resultsDir,
|
|
@@ -1898,7 +2014,7 @@ function createAttach(ctx) {
|
|
|
1898
2014
|
}
|
|
1899
2015
|
|
|
1900
2016
|
// packages/core/dist/daemon/start.js
|
|
1901
|
-
import { join as join11, dirname as
|
|
2017
|
+
import { join as join11, dirname as dirname3 } from "path";
|
|
1902
2018
|
import { readdir } from "fs/promises";
|
|
1903
2019
|
|
|
1904
2020
|
// packages/core/dist/daemon/interactive-probe.js
|
|
@@ -2492,7 +2608,7 @@ function createServer2(ctx, handlers) {
|
|
|
2492
2608
|
// packages/core/dist/daemon/snapshot-gather.js
|
|
2493
2609
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2494
2610
|
import { join as join10 } from "path";
|
|
2495
|
-
import { statSync as statSync3, openSync as openSync2, readSync, closeSync as closeSync2, readdirSync as readdirSync3, readFileSync as
|
|
2611
|
+
import { statSync as statSync3, openSync as openSync2, readSync, closeSync as closeSync2, readdirSync as readdirSync3, readFileSync as readFileSync8 } from "fs";
|
|
2496
2612
|
var SELF_PATH = fileURLToPath2(import.meta.url);
|
|
2497
2613
|
function distBuiltAt() {
|
|
2498
2614
|
try {
|
|
@@ -2501,10 +2617,10 @@ function distBuiltAt() {
|
|
|
2501
2617
|
return 0;
|
|
2502
2618
|
}
|
|
2503
2619
|
}
|
|
2504
|
-
function gatherLogStats(
|
|
2620
|
+
function gatherLogStats(path20, now, windowMs) {
|
|
2505
2621
|
let sizeBytes = 0;
|
|
2506
2622
|
try {
|
|
2507
|
-
sizeBytes = statSync3(
|
|
2623
|
+
sizeBytes = statSync3(path20).size;
|
|
2508
2624
|
} catch {
|
|
2509
2625
|
return { errorCount: 0, sizeBytes: 0, windowMs };
|
|
2510
2626
|
}
|
|
@@ -2515,7 +2631,7 @@ function gatherLogStats(path19, now, windowMs) {
|
|
|
2515
2631
|
const len = sizeBytes - start;
|
|
2516
2632
|
let text = "";
|
|
2517
2633
|
try {
|
|
2518
|
-
const fd = openSync2(
|
|
2634
|
+
const fd = openSync2(path20, "r");
|
|
2519
2635
|
try {
|
|
2520
2636
|
const buf = Buffer.alloc(len);
|
|
2521
2637
|
readSync(fd, buf, 0, len, start);
|
|
@@ -2556,7 +2672,7 @@ function gatherStoreStats(store, stateRoot, project) {
|
|
|
2556
2672
|
if (!n.endsWith(".json"))
|
|
2557
2673
|
continue;
|
|
2558
2674
|
try {
|
|
2559
|
-
JSON.parse(
|
|
2675
|
+
JSON.parse(readFileSync8(join10(dir, n), "utf-8"));
|
|
2560
2676
|
} catch {
|
|
2561
2677
|
corruptCount++;
|
|
2562
2678
|
}
|
|
@@ -2605,6 +2721,7 @@ function startDaemon(ctx, opts, pkgVersion) {
|
|
|
2605
2721
|
isPidAlive,
|
|
2606
2722
|
notify,
|
|
2607
2723
|
taskTimeoutMs,
|
|
2724
|
+
takeoverNudgeHours: ctx.takeoverNudgeHours,
|
|
2608
2725
|
isSurfaceAlive: surfaceProbe,
|
|
2609
2726
|
resendFirstTurn: ctx.resendFirstTurn,
|
|
2610
2727
|
launchHeadless: opts.launchHeadless,
|
|
@@ -2660,7 +2777,7 @@ function startDaemon(ctx, opts, pkgVersion) {
|
|
|
2660
2777
|
return out;
|
|
2661
2778
|
}
|
|
2662
2779
|
async function gatherSnapshotInputs(now) {
|
|
2663
|
-
const logPath2 = join11(
|
|
2780
|
+
const logPath2 = join11(dirname3(stateRoot), "squadrantd.log");
|
|
2664
2781
|
const tier2Projects = opts.registeredProjects ?? Object.keys(loadConfig().projects);
|
|
2665
2782
|
const projects = await Promise.all(tier2Projects.map(async (project) => {
|
|
2666
2783
|
const cursor = await readCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER2 });
|
|
@@ -2849,8 +2966,8 @@ function startDaemon(ctx, opts, pkgVersion) {
|
|
|
2849
2966
|
|
|
2850
2967
|
// packages/core/dist/session-freshness.js
|
|
2851
2968
|
import crypto from "crypto";
|
|
2852
|
-
import
|
|
2853
|
-
import
|
|
2969
|
+
import fs9 from "fs";
|
|
2970
|
+
import path9 from "path";
|
|
2854
2971
|
|
|
2855
2972
|
// packages/core/dist/crew-protocol.js
|
|
2856
2973
|
function buildCompletionProtocol(taskId, project) {
|
|
@@ -3112,17 +3229,16 @@ function formatInbound(text) {
|
|
|
3112
3229
|
}
|
|
3113
3230
|
|
|
3114
3231
|
// packages/core/dist/telegram/state.js
|
|
3115
|
-
import
|
|
3116
|
-
import path9 from "path";
|
|
3232
|
+
import path10 from "path";
|
|
3117
3233
|
function statePath(stateRoot) {
|
|
3118
|
-
return
|
|
3234
|
+
return path10.join(stateRoot, "telegram-state.json");
|
|
3119
3235
|
}
|
|
3120
3236
|
function topicKey(project, scope = "project") {
|
|
3121
3237
|
return `${project}::${scope}`;
|
|
3122
3238
|
}
|
|
3123
3239
|
function loadState(stateRoot) {
|
|
3124
3240
|
try {
|
|
3125
|
-
const raw =
|
|
3241
|
+
const raw = readConfigFileSync(statePath(stateRoot));
|
|
3126
3242
|
const data = JSON.parse(raw);
|
|
3127
3243
|
const result = {
|
|
3128
3244
|
offset: typeof data.offset === "number" ? data.offset : 0,
|
|
@@ -3137,8 +3253,7 @@ function loadState(stateRoot) {
|
|
|
3137
3253
|
}
|
|
3138
3254
|
}
|
|
3139
3255
|
function saveState(stateRoot, s) {
|
|
3140
|
-
|
|
3141
|
-
fs11.writeFileSync(statePath(stateRoot), JSON.stringify(s, null, 2) + "\n");
|
|
3256
|
+
writeConfigFileSync(statePath(stateRoot), JSON.stringify(s, null, 2) + "\n");
|
|
3142
3257
|
}
|
|
3143
3258
|
function setTopic(stateRoot, project, topicId, scope = "project") {
|
|
3144
3259
|
const s = loadState(stateRoot);
|
|
@@ -3229,7 +3344,7 @@ function createTelegramClient(opts) {
|
|
|
3229
3344
|
|
|
3230
3345
|
// packages/core/dist/telegram/bridge.js
|
|
3231
3346
|
import os4 from "os";
|
|
3232
|
-
import
|
|
3347
|
+
import path11 from "path";
|
|
3233
3348
|
|
|
3234
3349
|
// packages/core/dist/telegram/panels.js
|
|
3235
3350
|
var mark = (on, label) => on ? `\u2022 ${label}` : label;
|
|
@@ -3335,7 +3450,7 @@ function notifyToggle(text) {
|
|
|
3335
3450
|
}
|
|
3336
3451
|
function createTelegramBridge(opts) {
|
|
3337
3452
|
const { cfg, stateRoot, client, appendCaptainMessage: appendCaptainMessage2, log, ensureCaptainAlive, runCommand, sendReply } = opts;
|
|
3338
|
-
const configRoot = opts.configRoot ??
|
|
3453
|
+
const configRoot = opts.configRoot ?? path11.join(os4.homedir(), ".config", "squadrant");
|
|
3339
3454
|
const pollMs = cfg.pollMs ?? 1e3;
|
|
3340
3455
|
let running = false;
|
|
3341
3456
|
let lastSuccessfulPollAt = null;
|
|
@@ -3466,14 +3581,14 @@ function createTelegramBridge(opts) {
|
|
|
3466
3581
|
}
|
|
3467
3582
|
function currentEffort() {
|
|
3468
3583
|
try {
|
|
3469
|
-
return loadConfig(
|
|
3584
|
+
return loadConfig(path11.join(configRoot, "config.json")).defaults.effort ?? "balance";
|
|
3470
3585
|
} catch {
|
|
3471
3586
|
return "balance";
|
|
3472
3587
|
}
|
|
3473
3588
|
}
|
|
3474
3589
|
function projectNames() {
|
|
3475
3590
|
try {
|
|
3476
|
-
return Object.keys(loadConfig(
|
|
3591
|
+
return Object.keys(loadConfig(path11.join(configRoot, "config.json")).projects);
|
|
3477
3592
|
} catch {
|
|
3478
3593
|
return [];
|
|
3479
3594
|
}
|
|
@@ -3685,7 +3800,7 @@ function createTelegramBridge(opts) {
|
|
|
3685
3800
|
}
|
|
3686
3801
|
|
|
3687
3802
|
// packages/core/dist/telegram/setup.js
|
|
3688
|
-
import
|
|
3803
|
+
import fs10 from "fs";
|
|
3689
3804
|
|
|
3690
3805
|
// packages/core/dist/restart-daemon.js
|
|
3691
3806
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
@@ -3701,14 +3816,14 @@ import { join as join13 } from "path";
|
|
|
3701
3816
|
var DEFAULT_SOCK_PATH2 = join13(homedir8(), ".config", "squadrant", "squadrant.sock");
|
|
3702
3817
|
|
|
3703
3818
|
// packages/core/dist/side-session.js
|
|
3704
|
-
import
|
|
3819
|
+
import fs11 from "fs";
|
|
3705
3820
|
|
|
3706
3821
|
// packages/core/dist/crew-spawn.js
|
|
3707
|
-
import
|
|
3822
|
+
import fs12 from "fs";
|
|
3708
3823
|
import os5 from "os";
|
|
3709
|
-
import
|
|
3710
|
-
var TEMPLATES_DIR =
|
|
3711
|
-
var STATE_ROOT =
|
|
3824
|
+
import path12 from "path";
|
|
3825
|
+
var TEMPLATES_DIR = path12.join(os5.homedir(), ".config", "squadrant", "templates");
|
|
3826
|
+
var STATE_ROOT = path12.join(os5.homedir(), ".config", "squadrant", "state");
|
|
3712
3827
|
|
|
3713
3828
|
// packages/core/dist/lifecycle-source.js
|
|
3714
3829
|
function reduceLifecycle(prev, next) {
|
|
@@ -3740,27 +3855,27 @@ import { execSync as execSync4 } from "child_process";
|
|
|
3740
3855
|
import { execSync as execSync5 } from "child_process";
|
|
3741
3856
|
|
|
3742
3857
|
// packages/agents/dist/drivers/launch-cmd.js
|
|
3743
|
-
import
|
|
3744
|
-
import
|
|
3858
|
+
import fs13 from "fs";
|
|
3859
|
+
import path13 from "path";
|
|
3745
3860
|
|
|
3746
3861
|
// packages/agents/dist/projection/cursor.js
|
|
3747
3862
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
3748
|
-
import
|
|
3863
|
+
import path14 from "path";
|
|
3749
3864
|
import os6 from "os";
|
|
3750
3865
|
|
|
3751
3866
|
// packages/agents/dist/projection/codex.js
|
|
3752
3867
|
import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
3753
|
-
import
|
|
3868
|
+
import path15 from "path";
|
|
3754
3869
|
import os7 from "os";
|
|
3755
3870
|
|
|
3756
3871
|
// packages/agents/dist/projection/gemini.js
|
|
3757
3872
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
3758
|
-
import
|
|
3873
|
+
import path16 from "path";
|
|
3759
3874
|
import os8 from "os";
|
|
3760
3875
|
|
|
3761
3876
|
// packages/agents/dist/projection/opencode.js
|
|
3762
3877
|
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
3763
|
-
import
|
|
3878
|
+
import path17 from "path";
|
|
3764
3879
|
import os9 from "os";
|
|
3765
3880
|
|
|
3766
3881
|
// packages/agents/dist/codex/app-server-client.js
|
|
@@ -4528,7 +4643,7 @@ var OpencodeSseBridge = class {
|
|
|
4528
4643
|
|
|
4529
4644
|
// packages/agents/dist/interactive/claude.js
|
|
4530
4645
|
import { execSync as execSync6 } from "child_process";
|
|
4531
|
-
import { readFileSync as
|
|
4646
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
4532
4647
|
import { homedir as homedir10 } from "os";
|
|
4533
4648
|
import { join as join15 } from "path";
|
|
4534
4649
|
var nextAskUserQuestionRequestId = Date.now();
|
|
@@ -5287,9 +5402,9 @@ var NotifierRegistry = class {
|
|
|
5287
5402
|
};
|
|
5288
5403
|
|
|
5289
5404
|
// packages/workspaces/dist/workspaces/obsidian.js
|
|
5290
|
-
import
|
|
5405
|
+
import fs14 from "fs/promises";
|
|
5291
5406
|
import { existsSync as existsSync10 } from "fs";
|
|
5292
|
-
import
|
|
5407
|
+
import path18 from "path";
|
|
5293
5408
|
|
|
5294
5409
|
// packages/workspaces/dist/cmux-daemon/events-bridge.js
|
|
5295
5410
|
import { spawn as nodeSpawn2 } from "child_process";
|
|
@@ -5426,7 +5541,7 @@ var CmuxEventsBridge = class {
|
|
|
5426
5541
|
};
|
|
5427
5542
|
|
|
5428
5543
|
// packages/workspaces/dist/cmux-daemon/daemon-cmux.js
|
|
5429
|
-
import { readdirSync as readdirSync4, readFileSync as
|
|
5544
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync10 } from "fs";
|
|
5430
5545
|
import { join as join16 } from "path";
|
|
5431
5546
|
import { homedir as homedir11 } from "os";
|
|
5432
5547
|
|
|
@@ -5555,14 +5670,14 @@ var DaemonCmux = class {
|
|
|
5555
5670
|
} catch (e) {
|
|
5556
5671
|
throw new Error(`liveness: could not read cmux state dir ${dir}: ${e.message}`);
|
|
5557
5672
|
}
|
|
5558
|
-
return readLivenessSnapshot(files, (f) =>
|
|
5673
|
+
return readLivenessSnapshot(files, (f) => readFileSync10(join16(dir, f), "utf-8"), projects);
|
|
5559
5674
|
}
|
|
5560
5675
|
};
|
|
5561
5676
|
|
|
5562
5677
|
// packages/workspaces/dist/cmux-daemon/cmux-store-source.js
|
|
5563
5678
|
import { join as join17 } from "path";
|
|
5564
5679
|
import { homedir as homedir12 } from "os";
|
|
5565
|
-
import { watch, readdirSync as readdirSync5, readFileSync as
|
|
5680
|
+
import { watch, readdirSync as readdirSync5, readFileSync as readFileSync11, existsSync as existsSync11 } from "fs";
|
|
5566
5681
|
var CmuxStoreSource = class {
|
|
5567
5682
|
name = "cmux-store";
|
|
5568
5683
|
stateDir;
|
|
@@ -5716,9 +5831,9 @@ function defaultListFiles(dir) {
|
|
|
5716
5831
|
return [];
|
|
5717
5832
|
}
|
|
5718
5833
|
}
|
|
5719
|
-
function defaultReadFile(
|
|
5834
|
+
function defaultReadFile(path20) {
|
|
5720
5835
|
try {
|
|
5721
|
-
return
|
|
5836
|
+
return readFileSync11(path20, "utf-8");
|
|
5722
5837
|
} catch {
|
|
5723
5838
|
return void 0;
|
|
5724
5839
|
}
|
|
@@ -5735,7 +5850,7 @@ function defaultWatchDir(dir, cb) {
|
|
|
5735
5850
|
// packages/workspaces/dist/native-hooks/native-hook-source.js
|
|
5736
5851
|
import { join as join18 } from "path";
|
|
5737
5852
|
import { homedir as homedir13 } from "os";
|
|
5738
|
-
import { mkdirSync as
|
|
5853
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "fs";
|
|
5739
5854
|
var CLAUDE_HOOK_EVENTS = [
|
|
5740
5855
|
["SessionStart", "session-start"],
|
|
5741
5856
|
["UserPromptSubmit", "prompt-submit"],
|
|
@@ -5915,16 +6030,16 @@ function extractDetail(sub, payload) {
|
|
|
5915
6030
|
}
|
|
5916
6031
|
return void 0;
|
|
5917
6032
|
}
|
|
5918
|
-
function defaultReadFile2(
|
|
6033
|
+
function defaultReadFile2(path20) {
|
|
5919
6034
|
try {
|
|
5920
|
-
return
|
|
6035
|
+
return readFileSync12(path20, "utf-8");
|
|
5921
6036
|
} catch {
|
|
5922
6037
|
return void 0;
|
|
5923
6038
|
}
|
|
5924
6039
|
}
|
|
5925
|
-
function defaultWriteFile(
|
|
5926
|
-
|
|
5927
|
-
|
|
6040
|
+
function defaultWriteFile(path20, content) {
|
|
6041
|
+
mkdirSync6(path20.replace(/\/[^/]+$/, ""), { recursive: true });
|
|
6042
|
+
writeFileSync8(path20, content, "utf-8");
|
|
5928
6043
|
}
|
|
5929
6044
|
|
|
5930
6045
|
// packages/workspaces/dist/crew-pane.js
|
|
@@ -5995,17 +6110,16 @@ async function resendCrewFirstTurn(runtime, captainName, project, name, message)
|
|
|
5995
6110
|
}
|
|
5996
6111
|
|
|
5997
6112
|
// packages/cli/src/lib/daemon-restart-broadcast.ts
|
|
5998
|
-
import
|
|
5999
|
-
import path18 from "path";
|
|
6113
|
+
import path19 from "path";
|
|
6000
6114
|
function statePath2(stateRoot) {
|
|
6001
|
-
return
|
|
6115
|
+
return path19.join(stateRoot, "daemon-restart-state.json");
|
|
6002
6116
|
}
|
|
6003
6117
|
function computeRestartSignature(version, buildMtimeMs) {
|
|
6004
6118
|
return `${version}::${buildMtimeMs}`;
|
|
6005
6119
|
}
|
|
6006
6120
|
function readPersistedRestartSignature(stateRoot) {
|
|
6007
6121
|
try {
|
|
6008
|
-
const raw =
|
|
6122
|
+
const raw = readConfigFileSync(statePath2(stateRoot));
|
|
6009
6123
|
const data = JSON.parse(raw);
|
|
6010
6124
|
return typeof data.signature === "string" ? data.signature : null;
|
|
6011
6125
|
} catch {
|
|
@@ -6013,8 +6127,7 @@ function readPersistedRestartSignature(stateRoot) {
|
|
|
6013
6127
|
}
|
|
6014
6128
|
}
|
|
6015
6129
|
function writePersistedRestartSignature(stateRoot, signature) {
|
|
6016
|
-
|
|
6017
|
-
fs17.writeFileSync(statePath2(stateRoot), JSON.stringify({ signature }, null, 2) + "\n");
|
|
6130
|
+
writeConfigFileSync(statePath2(stateRoot), JSON.stringify({ signature }, null, 2) + "\n");
|
|
6018
6131
|
}
|
|
6019
6132
|
function restartNotice(version, isDevRebuild) {
|
|
6020
6133
|
const suffix = isDevRebuild ? " (dev build)" : "";
|
|
@@ -6048,12 +6161,12 @@ async function maybeBroadcastDaemonRestart(opts) {
|
|
|
6048
6161
|
|
|
6049
6162
|
// packages/cli/src/squadrantd.ts
|
|
6050
6163
|
var SELF_PATH2 = fileURLToPath3(import.meta.url);
|
|
6051
|
-
var CLI_BIN = join19(
|
|
6164
|
+
var CLI_BIN = join19(dirname4(SELF_PATH2), "index.js");
|
|
6052
6165
|
var DAEMON_SOCK = join19(homedir14(), ".config", "squadrant", "squadrant.sock");
|
|
6053
6166
|
function readPkgVersion() {
|
|
6054
6167
|
try {
|
|
6055
|
-
const pkgPath = join19(
|
|
6056
|
-
return JSON.parse(
|
|
6168
|
+
const pkgPath = join19(dirname4(SELF_PATH2), "..", "package.json");
|
|
6169
|
+
return JSON.parse(readFileSync13(pkgPath, "utf-8")).version ?? "unknown";
|
|
6057
6170
|
} catch {
|
|
6058
6171
|
return "unknown";
|
|
6059
6172
|
}
|
|
@@ -6075,7 +6188,7 @@ function buildTelegramBridge(cfg, stateRoot, log) {
|
|
|
6075
6188
|
return createTelegramBridge({
|
|
6076
6189
|
cfg,
|
|
6077
6190
|
stateRoot,
|
|
6078
|
-
configRoot:
|
|
6191
|
+
configRoot: dirname4(stateRoot),
|
|
6079
6192
|
client,
|
|
6080
6193
|
appendCaptainMessage,
|
|
6081
6194
|
log,
|
|
@@ -6343,6 +6456,9 @@ function logCrashMarker(kind, err) {
|
|
|
6343
6456
|
process.stderr.write(`[squadrantd] ${(/* @__PURE__ */ new Date()).toISOString()} ${kind} pid=${process.pid} error=${message}
|
|
6344
6457
|
`);
|
|
6345
6458
|
}
|
|
6459
|
+
function isMonorepoCheckout(scriptPath, dirExists = existsSync12) {
|
|
6460
|
+
return dirExists(join19(dirname4(scriptPath), "..", "packages"));
|
|
6461
|
+
}
|
|
6346
6462
|
if (process.argv[1] && process.argv[1].endsWith("squadrantd.js")) {
|
|
6347
6463
|
process.on("uncaughtException", (err) => {
|
|
6348
6464
|
logCrashMarker("uncaughtException", err);
|
|
@@ -6358,6 +6474,13 @@ if (process.argv[1] && process.argv[1].endsWith("squadrantd.js")) {
|
|
|
6358
6474
|
process.stdout.write("squadrantd: launchd-managed daemon entry (no CLI args). Use `squadrant` for commands.\n");
|
|
6359
6475
|
process.exit(0);
|
|
6360
6476
|
}
|
|
6477
|
+
if (isMonorepoCheckout(process.argv[1])) {
|
|
6478
|
+
process.stderr.write(
|
|
6479
|
+
`[squadrantd] refusing to start: '${process.argv[1]}' is a monorepo/worktree checkout, not an installed copy \u2014 it must never become the shared production daemon (#670). This entry takes no CLI flags/sockPath override; for local testing, import startSquadrantd({ sockPath, ... }) programmatically instead of running this entry directly, or run the test suite (\`pnpm test\`).
|
|
6480
|
+
`
|
|
6481
|
+
);
|
|
6482
|
+
process.exit(1);
|
|
6483
|
+
}
|
|
6361
6484
|
const sock = join19(homedir14(), ".config", "squadrant", "squadrant.sock");
|
|
6362
6485
|
if (await isDaemonSocketLive(sock)) {
|
|
6363
6486
|
process.stderr.write(`[squadrantd] refusing to start: a live daemon already owns ${sock}
|
|
@@ -6375,6 +6498,7 @@ if (process.argv[1] && process.argv[1].endsWith("squadrantd.js")) {
|
|
|
6375
6498
|
export {
|
|
6376
6499
|
defaultIsPidAlive,
|
|
6377
6500
|
discoverCaptainSurface,
|
|
6501
|
+
isMonorepoCheckout,
|
|
6378
6502
|
startSquadrantd
|
|
6379
6503
|
};
|
|
6380
6504
|
//# sourceMappingURL=squadrantd.js.map
|