@cohortapp/agent-sdk 2.18.11 → 2.18.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cohortapp/agent-sdk",
3
- "version": "2.18.11",
3
+ "version": "2.18.12",
4
4
  "description": "Cohort Agent SDK — autonomous AI colleague runtime. Deploy senior AI colleagues on dedicated Mac minis, wired to the Cohort operating surface.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -160,7 +160,7 @@ import { processOne } from "../../lib/execution/pipeline.mjs";
160
160
  // gate is pure (lib/session/frontdoor.mjs); the assurance sweep reopens a
161
161
  // session claim that was neither replied nor done within 20 min.
162
162
  import { shouldReviveFrontDoor, reviveCommand, sessionJobLabelOnDisk } from "../../lib/session/revive.mjs";
163
- import { makeFrontDoorGate, sessionLiveFromHeartbeat } from "../../lib/session/frontdoor.mjs";
163
+ import { makeFrontDoorGate, sessionLiveFromHeartbeat, readFrontDoorState } from "../../lib/session/frontdoor.mjs";
164
164
  import { CADENCE_REGISTRY } from "./cadence-handlers.mjs";
165
165
  import { sweepSessionInboxForDaemon } from "../../lib/session/inbox-claims.mjs";
166
166
  import { defaultEffects, scheduleToQueue } from "../../lib/execution/effects.mjs";
@@ -291,6 +291,8 @@ const _frontDoorGate = makeFrontDoorGate({ agentRoot: AGENT_REPO_DIR });
291
291
  // State is per-process and deliberately not persisted: a daemon restart is
292
292
  // itself a change of circumstances, and a fresh budget after one is the answer
293
293
  // we want rather than a stale count carried across it.
294
+ /** How often the daemon asks whether the front door has gone quiet. */
295
+ const REVIVE_CHECK_INTERVAL_MS = 60 * 1000;
294
296
  const _revive = { attempts: 0, lastAt: null };
295
297
  async function reviveFrontDoorIfShut(state, deps = {}) {
296
298
  const now = deps.now ? deps.now() : Date.now();
@@ -325,9 +327,6 @@ async function pollService(svc) {
325
327
  // Front door: a live main session owns this service's inbox — leave it.
326
328
  const fd = _frontDoorGate.check(svc.name);
327
329
  if (fd.changed) console.log(`[daemon] front door for ${svc.name}: ${fd.dispatch ? "daemon dispatches" : "main session owns intake"} (${fd.reason})`);
328
- // A door that is shut is not a door that owns anything. Ask on every poll,
329
- // cheap and bounded: the common answer is "answering" off a fresh beat.
330
- if (svc.name === "cohort") await reviveFrontDoorIfShut(fd.state).catch(() => {});
331
330
  if (!fd.dispatch) return 0;
332
331
  const result = await svc.fn();
333
332
  // Dedup by raw_ref first: the same Slack message arrives via multiple paths
@@ -3150,6 +3149,22 @@ async function main() {
3150
3149
  pollCohortFast().catch((err) => console.error("[daemon] cohort fast-poll error:", err.message));
3151
3150
  }, COHORT_FAST_INTERVAL);
3152
3151
 
3152
+ // ── THE SHUT-DOOR CHECK GETS ITS OWN TICK ─────────────────────────────────
3153
+ //
3154
+ // It lived inside pollService for one release, which was the wrong place for
3155
+ // exactly the reason it exists: `pollCohortFast` guards itself with
3156
+ // `_cohortFastRunning`, so a poll that hangs starves every later call — and a
3157
+ // seat whose front door is wedged is precisely a seat where things hang. The
3158
+ // remedy must not share a lane with the thing it is rescuing.
3159
+ //
3160
+ // Its own interval, reading the front-door state directly, so nothing between
3161
+ // here and the kickstart can be blocked by the wedge.
3162
+ setInterval(() => {
3163
+ let state = null;
3164
+ try { state = readFrontDoorState(AGENT_REPO_DIR, { now: Date.now() }); } catch { state = null; }
3165
+ if (state) reviveFrontDoorIfShut(state).catch(() => {});
3166
+ }, REVIVE_CHECK_INTERVAL_MS);
3167
+
3153
3168
  // Backlog sweep
3154
3169
  setInterval(async () => {
3155
3170
  try {