squadrant 0.19.2 → 0.19.4
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 +232 -29
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +138 -18
- package/dist/squadrantd.js.map +1 -1
- package/package.json +1 -1
package/dist/squadrantd.js
CHANGED
|
@@ -2322,6 +2322,26 @@ function parseProgramArgs(plistXml) {
|
|
|
2322
2322
|
return null;
|
|
2323
2323
|
return { nodeBin: xmlUnescape(m[1]), daemonEntry: xmlUnescape(m[2]) };
|
|
2324
2324
|
}
|
|
2325
|
+
function isVersionUpgrade(registeredEntry, thisEntry) {
|
|
2326
|
+
const a = registeredEntry.split("/");
|
|
2327
|
+
const b = thisEntry.split("/");
|
|
2328
|
+
if (a.length !== b.length)
|
|
2329
|
+
return false;
|
|
2330
|
+
let diffIndex = -1;
|
|
2331
|
+
for (let i = 0; i < a.length; i++) {
|
|
2332
|
+
if (a[i] !== b[i]) {
|
|
2333
|
+
if (diffIndex !== -1)
|
|
2334
|
+
return false;
|
|
2335
|
+
diffIndex = i;
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
if (diffIndex === -1)
|
|
2339
|
+
return false;
|
|
2340
|
+
const versionedSegment = /^(.+)@([^@]+)$/;
|
|
2341
|
+
const ma = a[diffIndex].match(versionedSegment);
|
|
2342
|
+
const mb = b[diffIndex].match(versionedSegment);
|
|
2343
|
+
return ma !== null && mb !== null && ma[1] === mb[1] && ma[2] !== mb[2];
|
|
2344
|
+
}
|
|
2325
2345
|
function detectForeignInstall(parsed, thisEntry, registeredEntryExists) {
|
|
2326
2346
|
if (!parsed)
|
|
2327
2347
|
return null;
|
|
@@ -2329,7 +2349,11 @@ function detectForeignInstall(parsed, thisEntry, registeredEntryExists) {
|
|
|
2329
2349
|
return null;
|
|
2330
2350
|
if (!registeredEntryExists)
|
|
2331
2351
|
return null;
|
|
2332
|
-
return {
|
|
2352
|
+
return {
|
|
2353
|
+
registeredEntry: parsed.daemonEntry,
|
|
2354
|
+
thisEntry,
|
|
2355
|
+
isUpgrade: isVersionUpgrade(parsed.daemonEntry, thisEntry)
|
|
2356
|
+
};
|
|
2333
2357
|
}
|
|
2334
2358
|
function sanitizePathForPlist(path21) {
|
|
2335
2359
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -2496,7 +2520,7 @@ function forceKickstartAndVerify(target, opts = {}) {
|
|
|
2496
2520
|
const pollDelayMs = opts.pollDelayMs ?? 300;
|
|
2497
2521
|
const kickstartRetries = opts.kickstartRetries ?? 10;
|
|
2498
2522
|
const kickstartRetryDelayMs = opts.kickstartRetryDelayMs ?? 300;
|
|
2499
|
-
const pidBefore = getDaemonPid(target);
|
|
2523
|
+
const pidBefore = opts.pidBefore !== void 0 ? opts.pidBefore : getDaemonPid(target);
|
|
2500
2524
|
let kickstartError = null;
|
|
2501
2525
|
for (let i = 0; i < kickstartRetries; i++) {
|
|
2502
2526
|
try {
|
|
@@ -2533,6 +2557,9 @@ function forceKickstartAndVerify(target, opts = {}) {
|
|
|
2533
2557
|
function isOperatorInitiatedCommand(topLevelArg) {
|
|
2534
2558
|
return topLevelArg !== void 0 && OPERATOR_INITIATED_COMMANDS.has(topLevelArg);
|
|
2535
2559
|
}
|
|
2560
|
+
function isReadOnlyCrewCommand(argv) {
|
|
2561
|
+
return argv[2] === "crew" && argv[3] !== void 0 && READ_ONLY_CREW_SUBCOMMANDS.has(argv[3]);
|
|
2562
|
+
}
|
|
2536
2563
|
function ensureDaemon(nodeBin = process.execPath, opts = {}) {
|
|
2537
2564
|
if (restartInFlight)
|
|
2538
2565
|
return;
|
|
@@ -2553,8 +2580,10 @@ function ensureDaemon(nodeBin = process.execPath, opts = {}) {
|
|
|
2553
2580
|
try {
|
|
2554
2581
|
const drift = computeDaemonDrift(nodeBin);
|
|
2555
2582
|
if (drift.foreignInstall) {
|
|
2556
|
-
|
|
2557
|
-
|
|
2583
|
+
const decision = decideForeignInstall(drift.foreignInstall);
|
|
2584
|
+
process.stderr.write(decision.message);
|
|
2585
|
+
if (!decision.proceed)
|
|
2586
|
+
return;
|
|
2558
2587
|
}
|
|
2559
2588
|
applyDaemonDrift(drift);
|
|
2560
2589
|
} catch (e) {
|
|
@@ -2564,6 +2593,12 @@ function ensureDaemon(nodeBin = process.execPath, opts = {}) {
|
|
|
2564
2593
|
releaseDaemonLock();
|
|
2565
2594
|
}
|
|
2566
2595
|
}
|
|
2596
|
+
function decideForeignInstall(foreign) {
|
|
2597
|
+
if (foreign.isUpgrade) {
|
|
2598
|
+
return { proceed: true, message: printVersionUpgradeNotice(foreign) };
|
|
2599
|
+
}
|
|
2600
|
+
return { proceed: false, message: printForeignInstallError(foreign) };
|
|
2601
|
+
}
|
|
2567
2602
|
function printForeignInstallError(foreign) {
|
|
2568
2603
|
return `[squadrant] refusing to restart the daemon: the registered launchd config belongs to a DIFFERENT squadrant install than this one.
|
|
2569
2604
|
registered install: ${foreign.registeredEntry}
|
|
@@ -2571,14 +2606,19 @@ function printForeignInstallError(foreign) {
|
|
|
2571
2606
|
Two squadrant installs on this machine will keep fighting over the daemon (#670). Uninstall the one you don't use, then run \`squadrant heal daemon\` to reconcile.
|
|
2572
2607
|
`;
|
|
2573
2608
|
}
|
|
2609
|
+
function printVersionUpgradeNotice(foreign) {
|
|
2610
|
+
return `[squadrant] upgraded plist: ${foreign.registeredEntry} -> ${foreign.thisEntry}
|
|
2611
|
+
`;
|
|
2612
|
+
}
|
|
2574
2613
|
function reregisterDaemon(nodeBin = process.execPath, kickstartOpts = {}) {
|
|
2575
2614
|
if (!tryAcquireDaemonLock()) {
|
|
2576
2615
|
throw new Error("could not acquire the daemon lock \u2014 another squadrant process is already restarting the daemon");
|
|
2577
2616
|
}
|
|
2578
2617
|
try {
|
|
2579
2618
|
const drift = computeDaemonDrift(nodeBin);
|
|
2619
|
+
const pidBeforeReconcile = getDaemonPid(drift.target);
|
|
2580
2620
|
reconcilePlistAndService(drift);
|
|
2581
|
-
const result = forceKickstartAndVerify(drift.target, kickstartOpts);
|
|
2621
|
+
const result = forceKickstartAndVerify(drift.target, { ...kickstartOpts, pidBefore: pidBeforeReconcile });
|
|
2582
2622
|
if (!result.restarted) {
|
|
2583
2623
|
throw new Error(`daemon did not restart (pid before=${result.pidBefore ?? "none"}, after=${result.pidAfter ?? "none"}) \u2014 \`launchctl kickstart -k ${drift.target}\` ran but the pid never changed`);
|
|
2584
2624
|
}
|
|
@@ -2587,13 +2627,14 @@ function reregisterDaemon(nodeBin = process.execPath, kickstartOpts = {}) {
|
|
|
2587
2627
|
releaseDaemonLock();
|
|
2588
2628
|
}
|
|
2589
2629
|
}
|
|
2590
|
-
var LABEL, AGENT_BINS, restartInFlight, OPERATOR_INITIATED_COMMANDS;
|
|
2630
|
+
var LABEL, AGENT_BINS, restartInFlight, OPERATOR_INITIATED_COMMANDS, READ_ONLY_CREW_SUBCOMMANDS;
|
|
2591
2631
|
var init_launchd = __esm({
|
|
2592
2632
|
"packages/core/dist/launchd.js"() {
|
|
2593
2633
|
LABEL = "com.squadrant.daemon";
|
|
2594
2634
|
AGENT_BINS = ["cmux", "claude", "opencode", "codex", "gemini", "node"];
|
|
2595
2635
|
restartInFlight = false;
|
|
2596
2636
|
OPERATOR_INITIATED_COMMANDS = /* @__PURE__ */ new Set(["launch", "init"]);
|
|
2637
|
+
READ_ONLY_CREW_SUBCOMMANDS = /* @__PURE__ */ new Set(["list", "read", "tasks"]);
|
|
2597
2638
|
}
|
|
2598
2639
|
});
|
|
2599
2640
|
|
|
@@ -3290,6 +3331,51 @@ var init_captain_delivery = __esm({
|
|
|
3290
3331
|
}
|
|
3291
3332
|
});
|
|
3292
3333
|
|
|
3334
|
+
// packages/core/dist/daemon/down-alert.js
|
|
3335
|
+
function pad2(n) {
|
|
3336
|
+
return String(n).padStart(2, "0");
|
|
3337
|
+
}
|
|
3338
|
+
function formatLocalDateTime(d) {
|
|
3339
|
+
return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())} ${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
|
|
3340
|
+
}
|
|
3341
|
+
function formatTzOffset(d) {
|
|
3342
|
+
const offMin = -d.getTimezoneOffset();
|
|
3343
|
+
const sign = offMin >= 0 ? "+" : "-";
|
|
3344
|
+
const abs = Math.abs(offMin);
|
|
3345
|
+
const hh = pad2(Math.floor(abs / 60));
|
|
3346
|
+
const mm = abs % 60;
|
|
3347
|
+
return mm === 0 ? `${sign}${hh}` : `${sign}${hh}:${pad2(mm)}`;
|
|
3348
|
+
}
|
|
3349
|
+
function formatDownAlertText(opts) {
|
|
3350
|
+
const start = new Date(opts.startTs);
|
|
3351
|
+
const end = new Date(opts.endTs);
|
|
3352
|
+
return `\u26A0\uFE0F daemon was down ${formatLocalDateTime(start)} \u2192 ${formatLocalDateTime(end)} (${formatTzOffset(end)}), ${opts.minutes} min (last exit reason=${opts.reasonText})`;
|
|
3353
|
+
}
|
|
3354
|
+
function formatRelative(ms) {
|
|
3355
|
+
const minutes = Math.round(ms / 6e4);
|
|
3356
|
+
if (minutes < 60)
|
|
3357
|
+
return `${minutes} min`;
|
|
3358
|
+
const hours = Math.floor(minutes / 60);
|
|
3359
|
+
const remMinutes = minutes % 60;
|
|
3360
|
+
if (hours < 24)
|
|
3361
|
+
return remMinutes > 0 ? `${hours}h ${remMinutes}m` : `${hours}h`;
|
|
3362
|
+
const days = Math.floor(hours / 24);
|
|
3363
|
+
const remHours = hours % 24;
|
|
3364
|
+
return remHours > 0 ? `${days}d ${remHours}h` : `${days}d`;
|
|
3365
|
+
}
|
|
3366
|
+
function stalePrefix(generatedAtMs, deliveredAtMs) {
|
|
3367
|
+
const ageMs = deliveredAtMs - generatedAtMs;
|
|
3368
|
+
if (ageMs <= STALE_ALERT_THRESHOLD_MS)
|
|
3369
|
+
return null;
|
|
3370
|
+
return `[stale \u2014 generated ${formatRelative(ageMs)} ago] `;
|
|
3371
|
+
}
|
|
3372
|
+
var STALE_ALERT_THRESHOLD_MS;
|
|
3373
|
+
var init_down_alert = __esm({
|
|
3374
|
+
"packages/core/dist/daemon/down-alert.js"() {
|
|
3375
|
+
STALE_ALERT_THRESHOLD_MS = 60 * 60 * 1e3;
|
|
3376
|
+
}
|
|
3377
|
+
});
|
|
3378
|
+
|
|
3293
3379
|
// packages/core/dist/control-channel.js
|
|
3294
3380
|
function fallsBackToPane(o) {
|
|
3295
3381
|
return o.status === "gone" || o.status === "unsupported";
|
|
@@ -3437,12 +3523,25 @@ import fs9 from "fs";
|
|
|
3437
3523
|
import os4 from "os";
|
|
3438
3524
|
import path9 from "path";
|
|
3439
3525
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
3440
|
-
|
|
3441
|
-
|
|
3526
|
+
function ensureSocksDir(dir = CC_SOCKS_DIR) {
|
|
3527
|
+
fs9.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3528
|
+
if ((fs9.statSync(dir).mode & 511) !== 448)
|
|
3529
|
+
fs9.chmodSync(dir, 448);
|
|
3530
|
+
}
|
|
3531
|
+
async function pollFirstTurnConfirmedAt(getTaskRecord, project, id, scrapeSettled, cancel) {
|
|
3532
|
+
let scrapeSettledAt;
|
|
3533
|
+
const markSettled = () => {
|
|
3534
|
+
scrapeSettledAt ??= Date.now();
|
|
3535
|
+
};
|
|
3536
|
+
scrapeSettled.then(markSettled, markSettled);
|
|
3537
|
+
const hardDeadline = Date.now() + FIRST_TURN_HOOK_CONFIRM_MAX_MS;
|
|
3442
3538
|
for (; ; ) {
|
|
3539
|
+
if (cancel.stopped)
|
|
3540
|
+
return false;
|
|
3443
3541
|
const rec = await getTaskRecord(project, id).catch(() => void 0);
|
|
3444
3542
|
if (rec?.firstTurnConfirmedAt)
|
|
3445
3543
|
return true;
|
|
3544
|
+
const deadline = scrapeSettledAt !== void 0 ? Math.min(hardDeadline, scrapeSettledAt + FIRST_TURN_HOOK_CONFIRM_GRACE_MS) : hardDeadline;
|
|
3446
3545
|
if (Date.now() >= deadline)
|
|
3447
3546
|
return false;
|
|
3448
3547
|
await new Promise((r) => setTimeout(r, FIRST_TURN_HOOK_POLL_INTERVAL_MS));
|
|
@@ -3574,7 +3673,7 @@ async function runCrewSpawn(input, config, deps) {
|
|
|
3574
3673
|
deps.onModelResolved?.({ agentName, model: crewModel });
|
|
3575
3674
|
}
|
|
3576
3675
|
if (agentName === "claude") {
|
|
3577
|
-
|
|
3676
|
+
ensureSocksDir();
|
|
3578
3677
|
const messagingSocketPath = path9.join(CC_SOCKS_DIR, `squadrant-${randomUUID3()}.sock`);
|
|
3579
3678
|
const rec = await deps.dispatchCrew({
|
|
3580
3679
|
provider: "claude",
|
|
@@ -3624,7 +3723,9 @@ async function runCrewSpawn(input, config, deps) {
|
|
|
3624
3723
|
|
|
3625
3724
|
${buildCompletionProtocol(rec.id, input.project)}`, preLaunchScreen);
|
|
3626
3725
|
const scrapeDelivered = sendPromise.then((r) => r.delivered).catch(() => false);
|
|
3627
|
-
const
|
|
3726
|
+
const cancelHookPoll = { stopped: false };
|
|
3727
|
+
const delivered = hooksInstalled && deps.getTaskRecord ? await firstTrueOrBothFalse(scrapeDelivered, pollFirstTurnConfirmedAt(deps.getTaskRecord, input.project, rec.id, scrapeDelivered, cancelHookPoll)) : await scrapeDelivered;
|
|
3728
|
+
cancelHookPoll.stopped = true;
|
|
3628
3729
|
if (!delivered) {
|
|
3629
3730
|
process.stderr.write(`\u26A0\uFE0F First turn not delivered for crew '${name}' \u2014 use 'squadrant crew send ${input.project} ${name}' to re-send the task.
|
|
3630
3731
|
`);
|
|
@@ -3906,7 +4007,7 @@ async function runCrewList(project, runtime, workspaceId) {
|
|
|
3906
4007
|
surfaceId: c.surfaceId
|
|
3907
4008
|
}));
|
|
3908
4009
|
}
|
|
3909
|
-
var CC_SOCKS_DIR, FIRST_TURN_INLINE_MAX_BYTES, TEMPLATES_DIR, STATE_ROOT,
|
|
4010
|
+
var CC_SOCKS_DIR, FIRST_TURN_INLINE_MAX_BYTES, TEMPLATES_DIR, STATE_ROOT, FIRST_TURN_HOOK_CONFIRM_GRACE_MS, FIRST_TURN_HOOK_CONFIRM_MAX_MS, FIRST_TURN_HOOK_POLL_INTERVAL_MS, CLOSE_LOOKUP_RETRIES, CLOSE_LOOKUP_RETRY_DELAY_MS;
|
|
3910
4011
|
var init_crew_spawn = __esm({
|
|
3911
4012
|
"packages/core/dist/crew-spawn.js"() {
|
|
3912
4013
|
init_control_channel();
|
|
@@ -3918,7 +4019,8 @@ var init_crew_spawn = __esm({
|
|
|
3918
4019
|
FIRST_TURN_INLINE_MAX_BYTES = 1200;
|
|
3919
4020
|
TEMPLATES_DIR = path9.join(os4.homedir(), ".config", "squadrant", "templates");
|
|
3920
4021
|
STATE_ROOT = path9.join(os4.homedir(), ".config", "squadrant", "state");
|
|
3921
|
-
|
|
4022
|
+
FIRST_TURN_HOOK_CONFIRM_GRACE_MS = 15e3;
|
|
4023
|
+
FIRST_TURN_HOOK_CONFIRM_MAX_MS = 18e4;
|
|
3922
4024
|
FIRST_TURN_HOOK_POLL_INTERVAL_MS = 2e3;
|
|
3923
4025
|
CLOSE_LOOKUP_RETRIES = 3;
|
|
3924
4026
|
CLOSE_LOOKUP_RETRY_DELAY_MS = 150;
|
|
@@ -4164,7 +4266,13 @@ function createDelivery(ctx, daemonCmux, isSurfaceAlive) {
|
|
|
4164
4266
|
log(`delivery seq=${entry.seq} kind=${entry.kind} outcome=stale-terminal-deliver`);
|
|
4165
4267
|
}
|
|
4166
4268
|
}
|
|
4167
|
-
|
|
4269
|
+
let deliverEntry = entry;
|
|
4270
|
+
if (entry.kind === "captain.message" && entry.payload?.source === "daemon" && entry.message) {
|
|
4271
|
+
const prefix = stalePrefix(new Date(entry.ts).getTime(), Date.now());
|
|
4272
|
+
if (prefix)
|
|
4273
|
+
deliverEntry = { ...entry, message: `${prefix}${entry.message}` };
|
|
4274
|
+
}
|
|
4275
|
+
const result = await d.deliver(deliverEntry, async (text, sendOpts) => {
|
|
4168
4276
|
let handledByChannel = false;
|
|
4169
4277
|
try {
|
|
4170
4278
|
const mode = ctx.captainChannelMode?.() ?? "off";
|
|
@@ -4256,6 +4364,7 @@ var init_delivery_loop = __esm({
|
|
|
4256
4364
|
init_defer_delivery();
|
|
4257
4365
|
init_dist();
|
|
4258
4366
|
init_interactive_probe();
|
|
4367
|
+
init_down_alert();
|
|
4259
4368
|
init_liveness2();
|
|
4260
4369
|
init_captain_channel();
|
|
4261
4370
|
CURSOR_SUBSCRIBER = "captain";
|
|
@@ -4690,8 +4799,8 @@ function startDaemon(ctx, opts, pkgVersion) {
|
|
|
4690
4799
|
log(`boot pid=${process.pid} version=${pkgVersion} socket=${ctx.sockPath} stateRoot=${stateRoot}`);
|
|
4691
4800
|
const bootTs = (/* @__PURE__ */ new Date()).toISOString();
|
|
4692
4801
|
{
|
|
4693
|
-
const sendDownAlert = (minutes, reasonText) => {
|
|
4694
|
-
const text =
|
|
4802
|
+
const sendDownAlert = (startTs, endTs, minutes, reasonText) => {
|
|
4803
|
+
const text = formatDownAlertText({ startTs, endTs, minutes, reasonText });
|
|
4695
4804
|
const alertProjects = opts.registeredProjects ?? Object.keys(loadConfig().projects);
|
|
4696
4805
|
for (const project of alertProjects) {
|
|
4697
4806
|
appendCaptainMessage({ stateRoot, project, text, source: "daemon" }).catch((e) => log(`boot-gap alert failed project=${project}: ${e.message}`));
|
|
@@ -4702,13 +4811,13 @@ function startDaemon(ctx, opts, pkgVersion) {
|
|
|
4702
4811
|
if (marker) {
|
|
4703
4812
|
log(`previous exit ts=${marker.ts} reason=${marker.reason} gap=${((gapMs ?? 0) / 1e3).toFixed(1)}s`);
|
|
4704
4813
|
if ((gapMs ?? 0) > 6e4)
|
|
4705
|
-
sendDownAlert(Math.round((gapMs ?? 0) / 6e4), marker.reason);
|
|
4814
|
+
sendDownAlert(marker.ts, bootTs, Math.round((gapMs ?? 0) / 6e4), marker.reason);
|
|
4706
4815
|
} else if (prevRunning) {
|
|
4707
4816
|
const lastHeartbeatMs = new Date(prevRunning.lastHeartbeatTs).getTime();
|
|
4708
4817
|
const uncleanGapMs = Math.max(0, Date.now() - lastHeartbeatMs);
|
|
4709
4818
|
log(`previous exit: UNCLEAN (no marker; last heartbeat ${prevRunning.lastHeartbeatTs}, gap=${(uncleanGapMs / 1e3).toFixed(1)}s)`);
|
|
4710
4819
|
if (uncleanGapMs > 6e4) {
|
|
4711
|
-
sendDownAlert(Math.round(uncleanGapMs / 6e4), "unclean/unknown \u2014 no exit marker, likely SIGKILL/OOM/power-loss");
|
|
4820
|
+
sendDownAlert(prevRunning.lastHeartbeatTs, bootTs, Math.round(uncleanGapMs / 6e4), "unclean/unknown \u2014 no exit marker, likely SIGKILL/OOM/power-loss");
|
|
4712
4821
|
}
|
|
4713
4822
|
} else {
|
|
4714
4823
|
log("previous exit: none (clean or first boot)");
|
|
@@ -4830,6 +4939,7 @@ var init_start = __esm({
|
|
|
4830
4939
|
init_server();
|
|
4831
4940
|
init_mailbox();
|
|
4832
4941
|
init_exit_marker();
|
|
4942
|
+
init_down_alert();
|
|
4833
4943
|
init_liveness2();
|
|
4834
4944
|
init_dist();
|
|
4835
4945
|
init_snapshot_gather();
|
|
@@ -6799,6 +6909,7 @@ __export(dist_exports, {
|
|
|
6799
6909
|
OPERATOR_INITIATED_COMMANDS: () => OPERATOR_INITIATED_COMMANDS,
|
|
6800
6910
|
PROBE_QUIET_MS: () => PROBE_QUIET_MS,
|
|
6801
6911
|
PROTOCOL_VERSION: () => PROTOCOL_VERSION,
|
|
6912
|
+
READ_ONLY_CREW_SUBCOMMANDS: () => READ_ONLY_CREW_SUBCOMMANDS,
|
|
6802
6913
|
STALE_THRESHOLD_MS: () => STALE_THRESHOLD_MS,
|
|
6803
6914
|
TERMINAL_RECORD_KEEP_PER_PROJECT: () => TERMINAL_RECORD_KEEP_PER_PROJECT,
|
|
6804
6915
|
TERMINAL_RECORD_TTL_MS: () => TERMINAL_RECORD_TTL_MS,
|
|
@@ -6847,6 +6958,7 @@ __export(dist_exports, {
|
|
|
6847
6958
|
crewTag: () => crewTag,
|
|
6848
6959
|
daemonEntryPath: () => daemonEntryPath,
|
|
6849
6960
|
daemonLockPath: () => daemonLockPath,
|
|
6961
|
+
decideForeignInstall: () => decideForeignInstall,
|
|
6850
6962
|
decodeFrames: () => decodeFrames,
|
|
6851
6963
|
defaultIsPidAlive: () => defaultIsPidAlive,
|
|
6852
6964
|
defaultListenError: () => defaultListenError,
|
|
@@ -6864,6 +6976,7 @@ __export(dist_exports, {
|
|
|
6864
6976
|
encodeFrame: () => encodeFrame,
|
|
6865
6977
|
encodeMsg: () => encodeMsg,
|
|
6866
6978
|
ensureDaemon: () => ensureDaemon,
|
|
6979
|
+
ensureSocksDir: () => ensureSocksDir,
|
|
6867
6980
|
evaluateStall: () => evaluateStall,
|
|
6868
6981
|
exitMarkerPath: () => exitMarkerPath,
|
|
6869
6982
|
fallsBackToPane: () => fallsBackToPane,
|
|
@@ -6887,9 +7000,11 @@ __export(dist_exports, {
|
|
|
6887
7000
|
isDaemonSocketLive: () => isDaemonSocketLive,
|
|
6888
7001
|
isNotifyActive: () => isNotifyActive,
|
|
6889
7002
|
isOperatorInitiatedCommand: () => isOperatorInitiatedCommand,
|
|
7003
|
+
isReadOnlyCrewCommand: () => isReadOnlyCrewCommand,
|
|
6890
7004
|
isSideTitle: () => isSideTitle,
|
|
6891
7005
|
isStickyAttention: () => isStickyAttention,
|
|
6892
7006
|
isTurnAccepted: () => isTurnAccepted,
|
|
7007
|
+
isVersionUpgrade: () => isVersionUpgrade,
|
|
6893
7008
|
kickstartArgv: () => kickstartArgv,
|
|
6894
7009
|
launchOneWorkspace: () => launchOneWorkspace,
|
|
6895
7010
|
loadSessions: () => loadSessions,
|
|
@@ -6906,6 +7021,7 @@ __export(dist_exports, {
|
|
|
6906
7021
|
parseProgramArgs: () => parseProgramArgs,
|
|
6907
7022
|
plistPath: () => plistPath,
|
|
6908
7023
|
printForeignInstallError: () => printForeignInstallError,
|
|
7024
|
+
printVersionUpgradeNotice: () => printVersionUpgradeNotice,
|
|
6909
7025
|
programArgsBlock: () => programArgsBlock,
|
|
6910
7026
|
projectHealth: () => projectHealth,
|
|
6911
7027
|
purgeExpiredWorkItems: () => purgeExpiredWorkItems,
|
|
@@ -9803,9 +9919,12 @@ async function confirmedSendToPane(runtime, pane, message) {
|
|
|
9803
9919
|
let sawDraft = await settleInputBox(runtime, pane);
|
|
9804
9920
|
await runtime.sendKeyToPane(pane, "Enter");
|
|
9805
9921
|
let repasted = false;
|
|
9922
|
+
let screenMoved = false;
|
|
9806
9923
|
for (let attempt = 0; attempt < SUBMIT_RETRY_LIMIT; attempt++) {
|
|
9807
9924
|
await new Promise((r) => setTimeout(r, POST_SEND_CHECK_MS));
|
|
9808
9925
|
const afterScreen = await runtime.readPaneScreen(pane) ?? "";
|
|
9926
|
+
if (afterScreen !== preSendScreen)
|
|
9927
|
+
screenMoved = true;
|
|
9809
9928
|
const draft = parseDraftFromScreen(afterScreen);
|
|
9810
9929
|
if (draft !== "" && draft !== null)
|
|
9811
9930
|
sawDraft = true;
|
|
@@ -9816,7 +9935,7 @@ async function confirmedSendToPane(runtime, pane, message) {
|
|
|
9816
9935
|
const settled = await settleInputBox(runtime, pane);
|
|
9817
9936
|
if (settled)
|
|
9818
9937
|
sawDraft = true;
|
|
9819
|
-
if (!sawDraft && !repasted) {
|
|
9938
|
+
if (!sawDraft && !repasted && !screenMoved) {
|
|
9820
9939
|
repasted = true;
|
|
9821
9940
|
await runtime.pasteToPane(pane, message);
|
|
9822
9941
|
}
|
|
@@ -9930,6 +10049,7 @@ function registerSenderIdentity(socketPath) {
|
|
|
9930
10049
|
}
|
|
9931
10050
|
async function sharedReceiptListener() {
|
|
9932
10051
|
if (shared) return shared;
|
|
10052
|
+
ensureSocksDir();
|
|
9933
10053
|
const socketPath = `${CC_SOCKS_DIR}/squadrantd-${process.pid}.sock`;
|
|
9934
10054
|
const listener = new ClaudeReceiptListener({
|
|
9935
10055
|
socketPath,
|