@poolzin/pool-bot 2026.4.18 → 2026.4.19

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2026.4.18",
2
+ "version": "2026.4.19",
3
3
  "commit": "4e1f8d4b27c26618d3a69049dbe44698929a6ba8",
4
- "builtAt": "2026-03-27T01:18:30.781Z"
4
+ "builtAt": "2026-03-27T02:14:00.021Z"
5
5
  }
@@ -15,5 +15,11 @@ export type CronConfig = {
15
15
  * Default: "24h".
16
16
  */
17
17
  sessionRetention?: string | false;
18
+ /**
19
+ * Default timeout for cron jobs in seconds.
20
+ * Per-job `timeoutSeconds` overrides this. Set to 0 to disable timeout (not recommended).
21
+ * Default: 7200 (2 hours).
22
+ */
23
+ defaultJobTimeoutSeconds?: number;
18
24
  };
19
25
  //# sourceMappingURL=types.cron.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.cron.d.ts","sourceRoot":"","sources":["../../src/config/types.cron.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CACnC,CAAC"}
1
+ {"version":3,"file":"types.cron.d.ts","sourceRoot":"","sources":["../../src/config/types.cron.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAClC;;;;OAIG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../../src/cron/delivery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,gBAAgB,CAAC;IACvB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,UAAU,GAAG,SAAS,CAAC;IAC/B,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAqBF,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,CA+CtE"}
1
+ {"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../../src/cron/delivery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,gBAAgB,CAAC;IACvB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,UAAU,GAAG,SAAS,CAAC;IAC/B,SAAS,EAAE,OAAO,CAAC;CACpB,CAAC;AAqBF,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,gBAAgB,CAiDtE"}
@@ -25,9 +25,11 @@ export function resolveCronDeliveryPlan(job) {
25
25
  ? "announce"
26
26
  : normalizedMode === "none"
27
27
  ? "none"
28
- : normalizedMode === "deliver"
29
- ? "announce"
30
- : undefined;
28
+ : normalizedMode === "webhook"
29
+ ? "webhook"
30
+ : normalizedMode === "deliver"
31
+ ? "announce"
32
+ : undefined;
31
33
  const payloadChannel = normalizeChannel(payload?.channel);
32
34
  const payloadTo = normalizeTo(payload?.to);
33
35
  const deliveryChannel = normalizeChannel(delivery?.channel);
@@ -41,7 +43,7 @@ export function resolveCronDeliveryPlan(job) {
41
43
  channel,
42
44
  to,
43
45
  source: "delivery",
44
- requested: resolvedMode === "announce",
46
+ requested: resolvedMode === "announce" || resolvedMode === "webhook",
45
47
  };
46
48
  }
47
49
  const legacyMode = payload?.deliver === true ? "explicit" : payload?.deliver === false ? "off" : "auto";
@@ -1,15 +1,18 @@
1
1
  import type { PoolBotConfig } from "../../config/config.js";
2
2
  import { type SessionEntry } from "../../config/sessions.js";
3
- export declare function resolveCronSession(params: {
4
- cfg: PoolBotConfig;
5
- sessionKey: string;
6
- nowMs: number;
7
- agentId: string;
8
- }): {
3
+ export type CronSessionResult = {
9
4
  storePath: string;
10
5
  store: Record<string, SessionEntry>;
11
6
  sessionEntry: SessionEntry;
12
7
  systemSent: boolean;
13
8
  isNewSession: boolean;
9
+ reusedSessionId?: string;
14
10
  };
11
+ export declare function resolveCronSession(params: {
12
+ cfg: PoolBotConfig;
13
+ sessionKey: string;
14
+ nowMs: number;
15
+ agentId: string;
16
+ forceNew?: boolean;
17
+ }): CronSessionResult;
15
18
  //# sourceMappingURL=session.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/cron/isolated-agent/session.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAsC,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAEjG,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,GAAG,EAAE,aAAa,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;;;;;;EA0BA"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/cron/isolated-agent/session.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAsC,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAIjG,MAAM,MAAM,iBAAiB,GAAG;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACpC,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,GAAG,EAAE,aAAa,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,iBAAiB,CAgDpB"}
@@ -1,5 +1,6 @@
1
1
  import crypto from "node:crypto";
2
2
  import { loadSessionStore, resolveStorePath } from "../../config/sessions.js";
3
+ const SESSION_FRESHNESS_MS = 10 * 60_000; // 10 minutes
3
4
  export function resolveCronSession(params) {
4
5
  const sessionCfg = params.cfg.session;
5
6
  const storePath = resolveStorePath(sessionCfg?.store, {
@@ -7,6 +8,25 @@ export function resolveCronSession(params) {
7
8
  });
8
9
  const store = loadSessionStore(storePath);
9
10
  const entry = store[params.sessionKey];
11
+ // Check if we can reuse the existing session (fresh and forceNew is not set)
12
+ const forceNew = params.forceNew !== false;
13
+ const isFresh = entry?.updatedAt && params.nowMs - entry.updatedAt < SESSION_FRESHNESS_MS;
14
+ if (!forceNew && isFresh && entry) {
15
+ // Reuse existing session — preserve context continuity
16
+ const sessionEntry = {
17
+ ...entry,
18
+ updatedAt: params.nowMs,
19
+ };
20
+ return {
21
+ storePath,
22
+ store,
23
+ sessionEntry,
24
+ systemSent: entry.systemSent ?? false,
25
+ isNewSession: false,
26
+ reusedSessionId: entry.sessionId,
27
+ };
28
+ }
29
+ // Create fresh session
10
30
  const sessionId = crypto.randomUUID();
11
31
  const systemSent = false;
12
32
  const sessionEntry = {
@@ -4,6 +4,11 @@ export declare function readDescendantSubagentFallbackReply(params: {
4
4
  sessionKey: string;
5
5
  runStartedAt: number;
6
6
  }): Promise<string | undefined>;
7
+ /**
8
+ * Wait for descendant subagents with exponential backoff.
9
+ * Starts at 500ms, doubles up to 10s between polls.
10
+ * This dramatically reduces CPU usage for long-running overnight tasks.
11
+ */
7
12
  export declare function waitForDescendantSubagentSummary(params: {
8
13
  sessionKey: string;
9
14
  initialReply?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"subagent-followup.d.ts","sourceRoot":"","sources":["../../../src/cron/isolated-agent/subagent-followup.ts"],"names":[],"mappings":"AAWA,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CA6BjE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAa9D;AAED,wBAAsB,mCAAmC,CAAC,MAAM,EAAE;IAChE,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA2C9B;AAED,wBAAsB,gCAAgC,CAAC,MAAM,EAAE;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAyC9B"}
1
+ {"version":3,"file":"subagent-followup.d.ts","sourceRoot":"","sources":["../../../src/cron/isolated-agent/subagent-followup.ts"],"names":[],"mappings":"AAYA,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CA6BjE;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAa9D;AAED,wBAAsB,mCAAmC,CAAC,MAAM,EAAE;IAChE,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA2C9B;AAED;;;;GAIG;AACH,wBAAsB,gCAAgC,CAAC,MAAM,EAAE;IAC7D,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAiD9B"}
@@ -1,7 +1,8 @@
1
1
  import { countActiveDescendantRuns, listDescendantRunsForRequester, } from "../../agents/subagent-registry.js";
2
2
  import { readLatestAssistantReply } from "../../agents/tools/agent-step.js";
3
3
  import { SILENT_REPLY_TOKEN } from "../../auto-reply/tokens.js";
4
- const CRON_SUBAGENT_WAIT_POLL_MS = 500;
4
+ const CRON_SUBAGENT_WAIT_INITIAL_POLL_MS = 500;
5
+ const CRON_SUBAGENT_WAIT_MAX_POLL_MS = 10_000;
5
6
  const CRON_SUBAGENT_WAIT_MIN_MS = 30_000;
6
7
  const CRON_SUBAGENT_FINAL_REPLY_GRACE_MS = 5_000;
7
8
  export function isLikelyInterimCronMessage(value) {
@@ -87,19 +88,29 @@ export async function readDescendantSubagentFallbackReply(params) {
87
88
  }
88
89
  return replies.join("\n\n");
89
90
  }
91
+ /**
92
+ * Wait for descendant subagents with exponential backoff.
93
+ * Starts at 500ms, doubles up to 10s between polls.
94
+ * This dramatically reduces CPU usage for long-running overnight tasks.
95
+ */
90
96
  export async function waitForDescendantSubagentSummary(params) {
91
97
  const initialReply = params.initialReply?.trim();
92
98
  const deadline = Date.now() + Math.max(CRON_SUBAGENT_WAIT_MIN_MS, Math.floor(params.timeoutMs));
93
99
  let sawActiveDescendants = params.observedActiveDescendants === true;
94
100
  let drainedAtMs;
101
+ let pollInterval = CRON_SUBAGENT_WAIT_INITIAL_POLL_MS;
95
102
  while (Date.now() < deadline) {
96
103
  const activeDescendants = countActiveDescendantRuns(params.sessionKey);
97
104
  if (activeDescendants > 0) {
98
105
  sawActiveDescendants = true;
99
106
  drainedAtMs = undefined;
100
- await new Promise((resolve) => setTimeout(resolve, CRON_SUBAGENT_WAIT_POLL_MS));
107
+ // Exponential backoff: 500ms → 1s → 2s → 4s → 8s → 10s (cap)
108
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
109
+ pollInterval = Math.min(pollInterval * 2, CRON_SUBAGENT_WAIT_MAX_POLL_MS);
101
110
  continue;
102
111
  }
112
+ // Reset poll interval when descendants drain
113
+ pollInterval = CRON_SUBAGENT_WAIT_INITIAL_POLL_MS;
103
114
  if (!sawActiveDescendants) {
104
115
  return initialReply;
105
116
  }
@@ -115,7 +126,7 @@ export async function waitForDescendantSubagentSummary(params) {
115
126
  if (Date.now() - drainedAtMs >= CRON_SUBAGENT_FINAL_REPLY_GRACE_MS) {
116
127
  return undefined;
117
128
  }
118
- await new Promise((resolve) => setTimeout(resolve, CRON_SUBAGENT_WAIT_POLL_MS));
129
+ await new Promise((resolve) => setTimeout(resolve, CRON_SUBAGENT_WAIT_INITIAL_POLL_MS));
119
130
  }
120
131
  const latest = (await readLatestAssistantReply({ sessionKey: params.sessionKey }))?.trim();
121
132
  if (latest &&
@@ -1 +1 @@
1
- {"version":3,"file":"timer.d.ts","sourceRoot":"","sources":["../../../src/cron/service/timer.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAmD,MAAM,aAAa,CAAC;AAQ5F,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA+I9D,wBAAgB,QAAQ,CAAC,KAAK,EAAE,gBAAgB,QAuC/C;AAED,wBAAsB,OAAO,CAAC,KAAK,EAAE,gBAAgB,iBA2MpD;AAyDD,wBAAsB,aAAa,CACjC,KAAK,EAAE,gBAAgB,EACvB,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CAAE,iBA6F5C;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,gBAAgB,iBASvD;AAuHD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,gBAAgB,EACvB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,iBAoC3B;AAmDD,wBAAgB,IAAI,CAClB,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE;IAAE,IAAI,EAAE,KAAK,GAAG,gBAAgB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;;;;EAWvD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,gBAAgB,QAKhD;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,SAAS,QAM3D"}
1
+ {"version":3,"file":"timer.d.ts","sourceRoot":"","sources":["../../../src/cron/service/timer.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAmD,MAAM,aAAa,CAAC;AAQ5F,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA+I9D,wBAAgB,QAAQ,CAAC,KAAK,EAAE,gBAAgB,QAuC/C;AAED,wBAAsB,OAAO,CAAC,KAAK,EAAE,gBAAgB,iBAkNpD;AAyDD,wBAAsB,aAAa,CACjC,KAAK,EAAE,gBAAgB,EACvB,IAAI,CAAC,EAAE;IAAE,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CAAE,iBA6F5C;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,gBAAgB,iBASvD;AAuHD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,gBAAgB,EACvB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,iBAoC3B;AAmDD,wBAAgB,IAAI,CAClB,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE;IAAE,IAAI,EAAE,KAAK,GAAG,gBAAgB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE;;;;EAWvD;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,gBAAgB,QAKhD;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,SAAS,QAM3D"}
@@ -18,7 +18,7 @@ const MIN_REFIRE_GAP_MS = 2_000;
18
18
  * on top of the per-provider / per-agent timeouts to prevent one stuck job
19
19
  * from wedging the entire cron lane.
20
20
  */
21
- const DEFAULT_JOB_TIMEOUT_MS = 10 * 60_000; // 10 minutes
21
+ const DEFAULT_JOB_TIMEOUT_MS = 2 * 60 * 60_000; // 2 hours (allows overnight/long-running tasks)
22
22
  function resolveRunConcurrency(state) {
23
23
  const raw = state.deps.cronConfig?.maxConcurrentRuns;
24
24
  if (typeof raw !== "number" || !Number.isFinite(raw)) {
@@ -203,11 +203,17 @@ export async function onTimer(state) {
203
203
  const configuredTimeoutMs = job.payload.kind === "agentTurn" && typeof job.payload.timeoutSeconds === "number"
204
204
  ? Math.floor(job.payload.timeoutSeconds * 1_000)
205
205
  : undefined;
206
+ const cronDefaultTimeoutMs = typeof state.deps.cronConfig?.defaultJobTimeoutSeconds === "number"
207
+ ? state.deps.cronConfig.defaultJobTimeoutSeconds <= 0
208
+ ? undefined
209
+ : Math.floor(state.deps.cronConfig.defaultJobTimeoutSeconds * 1_000)
210
+ : undefined;
211
+ const effectiveDefaultMs = cronDefaultTimeoutMs ?? DEFAULT_JOB_TIMEOUT_MS;
206
212
  const jobTimeoutMs = configuredTimeoutMs !== undefined
207
213
  ? configuredTimeoutMs <= 0
208
214
  ? undefined
209
215
  : configuredTimeoutMs
210
- : DEFAULT_JOB_TIMEOUT_MS;
216
+ : effectiveDefaultMs;
211
217
  try {
212
218
  const result = typeof jobTimeoutMs === "number"
213
219
  ? await (async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poolzin/pool-bot",
3
- "version": "2026.4.18",
3
+ "version": "2026.4.19",
4
4
  "description": "🎱 Pool Bot - AI assistant with PLCODE integrations",
5
5
  "keywords": [],
6
6
  "license": "MIT",