squadrant 0.13.2 → 0.13.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 +77 -14
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +70 -7
- package/dist/squadrantd.js.map +1 -1
- package/package.json +1 -1
package/dist/squadrantd.js
CHANGED
|
@@ -544,6 +544,9 @@ function reduce(rec, ev, now) {
|
|
|
544
544
|
case "task.reattached":
|
|
545
545
|
return stampAttempt(base, {}, now);
|
|
546
546
|
case "task.first-turn.confirmed":
|
|
547
|
+
if (rec.firstTurnConfirmedAt) {
|
|
548
|
+
return { ...rec, lastEvent: "task.progress" };
|
|
549
|
+
}
|
|
547
550
|
return { ...rec, firstTurnConfirmedAt: now, lastEvent: ev.type };
|
|
548
551
|
case "task.stalled":
|
|
549
552
|
case "task.idle":
|
|
@@ -860,6 +863,25 @@ function createDaemon(deps) {
|
|
|
860
863
|
continue;
|
|
861
864
|
}
|
|
862
865
|
}
|
|
866
|
+
if (r.mode === "interactive" && r.state === "submitted" && !r.firstTurnConfirmedAt) {
|
|
867
|
+
const elapsed = t - r.lastHeartbeat;
|
|
868
|
+
if (elapsed > r.heartbeatBudgetMs) {
|
|
869
|
+
if (deps.notify && quietNotifiedAt.get(r.id) !== r.lastHeartbeat) {
|
|
870
|
+
quietNotifiedAt.set(r.id, r.lastHeartbeat);
|
|
871
|
+
const tag = crewTag(r);
|
|
872
|
+
const synthEvent = { type: "task.quiet", id: r.id, quietMs: elapsed };
|
|
873
|
+
const message = `\u26A0\uFE0F CREW UNDELIVERED ${tag}: first turn may not have landed (crew never started) \u2014 re-send the task or check the spawn.`;
|
|
874
|
+
try {
|
|
875
|
+
const p = deps.notify({ project: r.project, message, record: r, event: synthEvent });
|
|
876
|
+
if (p && typeof p.catch === "function")
|
|
877
|
+
p.catch(() => {
|
|
878
|
+
});
|
|
879
|
+
} catch {
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
continue;
|
|
883
|
+
}
|
|
884
|
+
}
|
|
863
885
|
const idle = evaluateStall(r, t);
|
|
864
886
|
if (idle) {
|
|
865
887
|
store.put(idle);
|
|
@@ -1952,6 +1974,7 @@ var CaptainDelivery = class {
|
|
|
1952
1974
|
// packages/core/dist/daemon/delivery-loop.js
|
|
1953
1975
|
var CURSOR_SUBSCRIBER = "captain";
|
|
1954
1976
|
var CAPTAIN_GONE_STREAK_K = 3;
|
|
1977
|
+
var TERMINAL_KINDS = /* @__PURE__ */ new Set(["task.done", "task.failed", "task.cancelled", "task.blocked"]);
|
|
1955
1978
|
function discoverCaptainSurface(surfaces, captainTitle) {
|
|
1956
1979
|
return surfaces.find((s) => s.title === captainTitle) ?? null;
|
|
1957
1980
|
}
|
|
@@ -2044,13 +2067,19 @@ function createDelivery(ctx, daemonCmux) {
|
|
|
2044
2067
|
}
|
|
2045
2068
|
for await (const entry of readFromCursor({ stateRoot, project, fromSeq: lastAcked + 1 })) {
|
|
2046
2069
|
if (new Date(entry.ts).getTime() < sessionStartMs - STALE_THRESHOLD_MS) {
|
|
2047
|
-
|
|
2048
|
-
|
|
2070
|
+
if (!TERMINAL_KINDS.has(entry.kind)) {
|
|
2071
|
+
log(`delivery seq=${entry.seq} kind=${entry.kind} outcome=stale-skipped`);
|
|
2072
|
+
await writeCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER, lastAckedSeq: entry.seq });
|
|
2073
|
+
continue;
|
|
2074
|
+
}
|
|
2075
|
+
log(`delivery seq=${entry.seq} kind=${entry.kind} outcome=stale-terminal-deliver`);
|
|
2049
2076
|
}
|
|
2050
2077
|
const result = await d.deliver(entry, (text, sendOpts) => cmux2.send(surface, text, sendOpts));
|
|
2051
2078
|
if ("delivered" in result) {
|
|
2079
|
+
log(`delivery seq=${entry.seq} kind=${entry.kind} outcome=delivered`);
|
|
2052
2080
|
await writeCursor({ stateRoot, project, subscriber: CURSOR_SUBSCRIBER, lastAckedSeq: entry.seq });
|
|
2053
2081
|
} else {
|
|
2082
|
+
log(`delivery seq=${entry.seq} kind=${entry.kind} outcome=deferred`);
|
|
2054
2083
|
break;
|
|
2055
2084
|
}
|
|
2056
2085
|
}
|
|
@@ -4366,7 +4395,7 @@ function parseDraftFromScreen(screen) {
|
|
|
4366
4395
|
}
|
|
4367
4396
|
return "";
|
|
4368
4397
|
}
|
|
4369
|
-
function readInputBoxRaw(screen) {
|
|
4398
|
+
function readInputBoxRaw(screen, opts) {
|
|
4370
4399
|
if (!screen)
|
|
4371
4400
|
return null;
|
|
4372
4401
|
const lines = screen.split(/\r?\n/);
|
|
@@ -4392,7 +4421,8 @@ function readInputBoxRaw(screen) {
|
|
|
4392
4421
|
s = s.replace(/\s*[▌█▔▎▏]+\s*$/, "");
|
|
4393
4422
|
parts.push(s);
|
|
4394
4423
|
}
|
|
4395
|
-
|
|
4424
|
+
const joined = parts.join("");
|
|
4425
|
+
return opts?.trim === false ? joined : joined.replace(/\s+$/, "");
|
|
4396
4426
|
}
|
|
4397
4427
|
function sendDebugEnabled() {
|
|
4398
4428
|
return !!process.env.SQUADRANT_DEBUG_SEND;
|
|
@@ -4406,6 +4436,19 @@ function classifySendOutcome(payload, postBox) {
|
|
|
4406
4436
|
return "stuck";
|
|
4407
4437
|
return "unknown";
|
|
4408
4438
|
}
|
|
4439
|
+
function classifyDraftLiveness(before, after) {
|
|
4440
|
+
if (before === null || after === null)
|
|
4441
|
+
return "inconclusive";
|
|
4442
|
+
if (after === "")
|
|
4443
|
+
return "no-draft";
|
|
4444
|
+
if (before.length > 0) {
|
|
4445
|
+
const segs = [...new Intl.Segmenter().segment(before)];
|
|
4446
|
+
const expected = segs.slice(0, -1).map((s) => s.segment).join("").replace(/\s+$/, "");
|
|
4447
|
+
if (after === expected)
|
|
4448
|
+
return "real-draft";
|
|
4449
|
+
}
|
|
4450
|
+
return "inconclusive";
|
|
4451
|
+
}
|
|
4409
4452
|
function createCmuxDriver() {
|
|
4410
4453
|
return {
|
|
4411
4454
|
name: "cmux",
|
|
@@ -4603,18 +4646,38 @@ function createCmuxDriver() {
|
|
|
4603
4646
|
if (!opts?.probe)
|
|
4604
4647
|
throw new DeferDelivery(draft);
|
|
4605
4648
|
const before = readInputBoxRaw(screen);
|
|
4649
|
+
const rawBefore = readInputBoxRaw(screen, { trim: false });
|
|
4606
4650
|
await cmux(["send-key", "--workspace", ws, "--surface", sf, "backspace"]);
|
|
4651
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
4607
4652
|
let afterScreen = "";
|
|
4608
4653
|
try {
|
|
4609
4654
|
afterScreen = await cmux(["read-screen", "--workspace", ws, "--surface", sf]);
|
|
4610
4655
|
} catch {
|
|
4611
4656
|
}
|
|
4612
4657
|
const after = readInputBoxRaw(afterScreen);
|
|
4613
|
-
|
|
4614
|
-
|
|
4658
|
+
const rawAfter = readInputBoxRaw(afterScreen, { trim: false });
|
|
4659
|
+
const liveness = classifyDraftLiveness(before, after);
|
|
4660
|
+
if (liveness === "real-draft") {
|
|
4661
|
+
const segs = before ? [...new Intl.Segmenter().segment(before)] : [];
|
|
4662
|
+
const lastGrapheme = segs.length > 0 ? segs[segs.length - 1].segment : before.slice(-1);
|
|
4663
|
+
await cmux(["send", "--workspace", ws, "--surface", sf, lastGrapheme]);
|
|
4615
4664
|
throw new DeferDelivery(draft);
|
|
4616
4665
|
}
|
|
4617
|
-
|
|
4666
|
+
if (liveness === "no-draft") {
|
|
4667
|
+
await deliver();
|
|
4668
|
+
return;
|
|
4669
|
+
}
|
|
4670
|
+
if (rawBefore !== null && rawAfter !== null) {
|
|
4671
|
+
if (rawBefore !== rawAfter) {
|
|
4672
|
+
const segs = [...new Intl.Segmenter().segment(rawBefore)];
|
|
4673
|
+
const lastGrapheme = segs.length > 0 ? segs[segs.length - 1].segment : rawBefore.slice(-1);
|
|
4674
|
+
await cmux(["send", "--workspace", ws, "--surface", sf, lastGrapheme]);
|
|
4675
|
+
throw new DeferDelivery(draft);
|
|
4676
|
+
}
|
|
4677
|
+
await deliver();
|
|
4678
|
+
return;
|
|
4679
|
+
}
|
|
4680
|
+
throw new DeferDelivery(draft);
|
|
4618
4681
|
},
|
|
4619
4682
|
async listSurfaces(workspaceId) {
|
|
4620
4683
|
let output;
|