squadrant 0.13.1 → 0.13.3
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 +105 -21
- package/dist/index.js.map +1 -1
- package/dist/squadrantd.js +49 -4
- package/dist/squadrantd.js.map +1 -1
- package/package.json +1 -1
package/dist/squadrantd.js
CHANGED
|
@@ -543,6 +543,11 @@ function reduce(rec, ev, now) {
|
|
|
543
543
|
return { ...stampAttempt(base, {}, now), state: "blocked", question: ev.question, pendingTool: void 0 };
|
|
544
544
|
case "task.reattached":
|
|
545
545
|
return stampAttempt(base, {}, now);
|
|
546
|
+
case "task.first-turn.confirmed":
|
|
547
|
+
if (rec.firstTurnConfirmedAt) {
|
|
548
|
+
return { ...rec, lastEvent: "task.progress" };
|
|
549
|
+
}
|
|
550
|
+
return { ...rec, firstTurnConfirmedAt: now, lastEvent: ev.type };
|
|
546
551
|
case "task.stalled":
|
|
547
552
|
case "task.idle":
|
|
548
553
|
case "task.quiet":
|
|
@@ -580,6 +585,7 @@ function recoverStall(rec, now) {
|
|
|
580
585
|
// packages/core/dist/daemon/reduce.js
|
|
581
586
|
var DEFAULT_TASK_TIMEOUT_MS = 8 * 60 * 60 * 1e3;
|
|
582
587
|
var TERMINAL_RECORD_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
588
|
+
var TERMINAL_RECORD_KEEP_PER_PROJECT = 20;
|
|
583
589
|
var ATTENTION_STATES = /* @__PURE__ */ new Set(["done", "blocked", "failed", "stalled", "awaiting-input"]);
|
|
584
590
|
var REAPABLE_SURFACE_STATES = /* @__PURE__ */ new Set(["working", "stalled", "awaiting-input", "blocked"]);
|
|
585
591
|
var IDLE_DEBOUNCE_MS = 12e3;
|
|
@@ -689,7 +695,9 @@ var KNOWN_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
|
689
695
|
"task.timeout",
|
|
690
696
|
"task.reconcile-failed",
|
|
691
697
|
"task.cancelled",
|
|
692
|
-
"task.session.ended"
|
|
698
|
+
"task.session.ended",
|
|
699
|
+
"task.first-turn.confirmed"
|
|
700
|
+
// #466: delivery confirmation
|
|
693
701
|
]);
|
|
694
702
|
function createDaemon(deps) {
|
|
695
703
|
const { store, now } = deps;
|
|
@@ -808,6 +816,13 @@ function createDaemon(deps) {
|
|
|
808
816
|
async sweep() {
|
|
809
817
|
const t = now();
|
|
810
818
|
const surfaceAlive = deps.isSurfaceAlive ?? (async () => "unknown");
|
|
819
|
+
const projects = new Set(store.listAll().map((r) => r.project));
|
|
820
|
+
for (const project of projects) {
|
|
821
|
+
const terminal = store.list(project).filter((r) => TERMINAL_STATES.has(r.state)).sort((a, b) => b.lastHeartbeat - a.lastHeartbeat);
|
|
822
|
+
for (const r of terminal.slice(TERMINAL_RECORD_KEEP_PER_PROJECT)) {
|
|
823
|
+
store.delete(r.project, r.id);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
811
826
|
for (const r of store.listAll()) {
|
|
812
827
|
if (TERMINAL_STATES.has(r.state) && t - r.lastHeartbeat > TERMINAL_RECORD_TTL_MS) {
|
|
813
828
|
store.delete(r.project, r.id);
|
|
@@ -822,7 +837,13 @@ function createDaemon(deps) {
|
|
|
822
837
|
const msg = `CREW TIMEOUT ${tag}: wall-clock exceeded ${hrs}h (id: ${r.id}, state: ${prevState})`;
|
|
823
838
|
const synthEvent = { type: "task.timeout", id: r.id, taskTimeoutMs: ceiling };
|
|
824
839
|
store.put({ ...r, state: "cancelled", lastEvent: "sweep.task-timeout" });
|
|
825
|
-
|
|
840
|
+
let shouldNotify = true;
|
|
841
|
+
if (r.mode === "interactive") {
|
|
842
|
+
const liveness = await surfaceAlive(r);
|
|
843
|
+
if (liveness === "gone")
|
|
844
|
+
shouldNotify = false;
|
|
845
|
+
}
|
|
846
|
+
if (deps.notify && shouldNotify) {
|
|
826
847
|
try {
|
|
827
848
|
const p = deps.notify({ project: r.project, message: msg, record: r, event: synthEvent });
|
|
828
849
|
if (p && typeof p.catch === "function") {
|
|
@@ -842,6 +863,25 @@ function createDaemon(deps) {
|
|
|
842
863
|
continue;
|
|
843
864
|
}
|
|
844
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
|
+
}
|
|
845
885
|
const idle = evaluateStall(r, t);
|
|
846
886
|
if (idle) {
|
|
847
887
|
store.put(idle);
|
|
@@ -856,9 +896,14 @@ function createDaemon(deps) {
|
|
|
856
896
|
if (deps.notify && quietNotifiedAt.get(r.id) !== liveness) {
|
|
857
897
|
quietNotifiedAt.set(r.id, liveness);
|
|
858
898
|
const tag = crewTag(r);
|
|
859
|
-
const mins = Math.max(1, Math.round(quiet / 6e4));
|
|
860
|
-
const message = `CREW QUIET ${tag}: working ~${mins}min with no tool activity \u2014 likely deep thinking (no reply expected yet).`;
|
|
861
899
|
const synthEvent = { type: "task.quiet", id: r.id, quietMs: quiet };
|
|
900
|
+
let message;
|
|
901
|
+
if (!r.firstTurnConfirmedAt) {
|
|
902
|
+
message = `\u26A0\uFE0F CREW UNDELIVERED ${tag}: first turn may not have landed (0 activity) \u2014 re-send the task or check the spawn.`;
|
|
903
|
+
} else {
|
|
904
|
+
const mins = Math.max(1, Math.round(quiet / 6e4));
|
|
905
|
+
message = `CREW QUIET ${tag}: working ~${mins}min with no tool activity \u2014 likely deep thinking (no reply expected yet).`;
|
|
906
|
+
}
|
|
862
907
|
try {
|
|
863
908
|
const p = deps.notify({ project: r.project, message, record: r, event: synthEvent });
|
|
864
909
|
if (p && typeof p.catch === "function")
|