alvin-bot 5.6.2 → 5.8.0
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/CHANGELOG.md +29 -0
- package/README.md +1 -1
- package/dist/claude.js +1 -102
- package/dist/config.js +1 -96
- package/dist/engine.js +1 -90
- package/dist/find-claude-binary.js +1 -98
- package/dist/handlers/async-agent-chunk-handler.js +1 -50
- package/dist/handlers/background-bypass.js +1 -75
- package/dist/handlers/commands.js +1 -2336
- package/dist/handlers/cron-progress.js +1 -52
- package/dist/handlers/document.js +1 -194
- package/dist/handlers/message.js +1 -959
- package/dist/handlers/photo.js +1 -154
- package/dist/handlers/platform-message.js +1 -360
- package/dist/handlers/stuck-timer.js +1 -54
- package/dist/handlers/video.js +1 -237
- package/dist/handlers/voice.js +1 -148
- package/dist/i18n.js +1 -805
- package/dist/index.js +1 -697
- package/dist/init-data-dir.js +1 -98
- package/dist/middleware/auth.js +1 -233
- package/dist/migrate.js +1 -162
- package/dist/paths.js +1 -146
- package/dist/platforms/discord.js +1 -175
- package/dist/platforms/index.js +1 -130
- package/dist/platforms/signal.js +1 -205
- package/dist/platforms/slack-slash-parser.js +1 -32
- package/dist/platforms/slack.js +1 -501
- package/dist/platforms/telegram.js +1 -111
- package/dist/platforms/types.js +1 -8
- package/dist/platforms/whatsapp-auth-helpers.js +1 -53
- package/dist/platforms/whatsapp.js +1 -707
- package/dist/providers/claude-sdk-provider.js +1 -565
- package/dist/providers/codex-cli-provider.js +1 -134
- package/dist/providers/index.js +1 -7
- package/dist/providers/ollama-provider.js +1 -32
- package/dist/providers/openai-compatible.js +1 -406
- package/dist/providers/registry.js +1 -352
- package/dist/providers/runtime-header.js +1 -45
- package/dist/providers/tool-executor.js +1 -475
- package/dist/providers/types.js +1 -227
- package/dist/services/access.js +1 -144
- package/dist/services/allowed-users-gate.js +1 -56
- package/dist/services/alvin-dispatch.js +1 -130
- package/dist/services/alvin-mcp-tools.js +1 -104
- package/dist/services/asset-index.js +1 -224
- package/dist/services/async-agent-parser.js +1 -418
- package/dist/services/async-agent-watcher.js +1 -443
- package/dist/services/auto-diagnostic.js +1 -228
- package/dist/services/broadcast.js +1 -52
- package/dist/services/browser-manager.js +1 -562
- package/dist/services/browser-webfetch.js +1 -127
- package/dist/services/browser.js +1 -121
- package/dist/services/cdp-bootstrap.js +1 -357
- package/dist/services/compaction.js +1 -144
- package/dist/services/critical-notify.js +1 -203
- package/dist/services/cron-resolver.js +1 -58
- package/dist/services/cron-scheduling.js +1 -310
- package/dist/services/cron.js +1 -861
- package/dist/services/custom-tools.js +1 -317
- package/dist/services/delivery-queue.js +1 -173
- package/dist/services/delivery-registry.js +1 -21
- package/dist/services/disk-cleanup.js +1 -203
- package/dist/services/elevenlabs.js +1 -58
- package/dist/services/embeddings/auto-detect.js +1 -74
- package/dist/services/embeddings/fts5.js +1 -108
- package/dist/services/embeddings/gemini.js +1 -65
- package/dist/services/embeddings/index.js +1 -496
- package/dist/services/embeddings/ollama.js +1 -78
- package/dist/services/embeddings/openai.js +1 -49
- package/dist/services/embeddings/provider.js +1 -22
- package/dist/services/embeddings/vector-base.js +1 -113
- package/dist/services/embeddings-migration.js +1 -193
- package/dist/services/embeddings.js +1 -9
- package/dist/services/env-file.js +1 -50
- package/dist/services/exec-guard.js +1 -71
- package/dist/services/fallback-order.js +1 -154
- package/dist/services/file-permissions.js +1 -93
- package/dist/services/heartbeat-file.js +1 -65
- package/dist/services/heartbeat.js +1 -313
- package/dist/services/hooks.js +1 -44
- package/dist/services/imagegen.js +1 -72
- package/dist/services/language-detect.js +1 -154
- package/dist/services/markdown.js +1 -63
- package/dist/services/mcp.js +1 -263
- package/dist/services/memory-extractor.js +1 -178
- package/dist/services/memory-inject-mode.js +1 -43
- package/dist/services/memory-layers.js +1 -156
- package/dist/services/memory.js +1 -146
- package/dist/services/ollama-manager.js +1 -339
- package/dist/services/permissions-wizard.js +1 -291
- package/dist/services/personality.js +1 -376
- package/dist/services/plugins.js +1 -171
- package/dist/services/preflight.js +1 -292
- package/dist/services/process-manager.js +1 -291
- package/dist/services/release-highlights.js +1 -79
- package/dist/services/reminders.js +1 -97
- package/dist/services/restart.js +1 -48
- package/dist/services/security-audit.js +1 -74
- package/dist/services/self-diagnosis.js +1 -272
- package/dist/services/self-search.js +1 -129
- package/dist/services/session-persistence.js +1 -237
- package/dist/services/session.js +1 -282
- package/dist/services/skills.js +1 -290
- package/dist/services/ssrf-guard.js +1 -162
- package/dist/services/standing-orders.js +1 -29
- package/dist/services/steer-channel.js +1 -46
- package/dist/services/stop-controller.js +1 -52
- package/dist/services/subagent-dedup.js +1 -0
- package/dist/services/subagent-delivery.js +1 -452
- package/dist/services/subagent-stats.js +1 -123
- package/dist/services/subagents.js +1 -814
- package/dist/services/sudo.js +1 -329
- package/dist/services/telegram.js +1 -158
- package/dist/services/timing-safe-bearer.js +1 -51
- package/dist/services/tool-discovery.js +1 -214
- package/dist/services/trends.js +1 -580
- package/dist/services/updater.js +1 -291
- package/dist/services/usage-tracker.js +1 -144
- package/dist/services/users.js +1 -271
- package/dist/services/voice.js +1 -104
- package/dist/services/watchdog-brake.js +1 -154
- package/dist/services/watchdog.js +1 -311
- package/dist/services/workspaces.js +1 -276
- package/dist/tui/index.js +1 -667
- package/dist/util/console-formatter.js +1 -109
- package/dist/util/debounce.js +1 -24
- package/dist/util/telegram-error-filter.js +1 -62
- package/dist/version.js +1 -24
- package/dist/web/bind-strategy.js +1 -42
- package/dist/web/canvas.js +1 -30
- package/dist/web/doctor-api.js +1 -604
- package/dist/web/openai-compat.js +1 -252
- package/dist/web/server.js +1 -1831
- package/dist/web/setup-api.js +1 -1101
- package/package.json +5 -2
- package/dist/.metadata_never_index +0 -0
|
@@ -1,443 +1 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Async Sub-Agent Watcher (Fix #17 Stage 2)
|
|
3
|
-
*
|
|
4
|
-
* Tracks pending background sub-agents that Claude launched with
|
|
5
|
-
* `run_in_background: true`. Polls each agent's outputFile every
|
|
6
|
-
* POLL_INTERVAL_MS, detects completion (success/failure/timeout),
|
|
7
|
-
* and delivers the final result as a separate Telegram message via
|
|
8
|
-
* the existing subagent-delivery.ts pipeline.
|
|
9
|
-
*
|
|
10
|
-
* Persistence: pending agents survive bot restarts via
|
|
11
|
-
* ~/.alvin-bot/state/async-agents.json. On boot, startWatcher() loads
|
|
12
|
-
* the file and resumes polling — same catchup pattern as the v4.9.0
|
|
13
|
-
* cron scheduler.
|
|
14
|
-
*
|
|
15
|
-
* Why this exists: Claude's Agent tool defaults to synchronous, which
|
|
16
|
-
* blocks the main Telegram session for 10+ minutes during long audits.
|
|
17
|
-
* Stage 1 of the fix tells Claude to use run_in_background; Stage 2
|
|
18
|
-
* (this file) catches the resulting outputFile and delivers the result
|
|
19
|
-
* when ready, so the user can keep chatting while the agent works.
|
|
20
|
-
*
|
|
21
|
-
* See docs/superpowers/plans/2026-04-13-async-subagents.md for the
|
|
22
|
-
* full plan and docs/superpowers/specs/sdk-async-agent-outputfile-format.md
|
|
23
|
-
* for the JSONL format details.
|
|
24
|
-
*/
|
|
25
|
-
import fs from "fs";
|
|
26
|
-
import { dirname } from "path";
|
|
27
|
-
import { parseOutputFileStatus } from "./async-agent-parser.js";
|
|
28
|
-
import { ASYNC_AGENTS_STATE_FILE } from "../paths.js";
|
|
29
|
-
import { getAllSessions } from "./session.js";
|
|
30
|
-
/**
|
|
31
|
-
* B3 — Detect a permanent "target chat does not exist" delivery failure
|
|
32
|
-
* (Telegram 400 "Bad Request: chat not found"), e.g. the stale chat_id:1
|
|
33
|
-
* test agent. Such an agent must be abandoned, not retried forever.
|
|
34
|
-
*
|
|
35
|
-
* Kept as a local predicate (mirrors isChatNotFoundError in
|
|
36
|
-
* subagent-delivery.ts) so the watcher does NOT take a new hard
|
|
37
|
-
* dependency on a fresh subagent-delivery export — many test suites mock
|
|
38
|
-
* that module with only deliverSubAgentResult, and a destructured import
|
|
39
|
-
* of a non-mocked symbol would throw. Matched narrowly on the
|
|
40
|
-
* chat-not-found signature only.
|
|
41
|
-
*/
|
|
42
|
-
function isChatNotFoundError(err) {
|
|
43
|
-
if (!err || typeof err !== "object")
|
|
44
|
-
return false;
|
|
45
|
-
const e = err;
|
|
46
|
-
const haystack = `${e.message ?? ""} ${e.description ?? ""}`;
|
|
47
|
-
return /chat not found/i.test(haystack);
|
|
48
|
-
}
|
|
49
|
-
/** How often the polling loop runs against each pending agent. */
|
|
50
|
-
const POLL_INTERVAL_MS = 15_000;
|
|
51
|
-
/** Hard ceiling per agent — 12h. After this, give up and deliver
|
|
52
|
-
* a timeout banner. SEO audits historically take ~13 min, so 12h
|
|
53
|
-
* is absurdly generous and protects against state-file growth. */
|
|
54
|
-
const MAX_AGENT_AGE_MS = 12 * 60 * 60 * 1000;
|
|
55
|
-
/**
|
|
56
|
-
* v4.14.2 — When a dispatched subprocess never creates its outputFile
|
|
57
|
-
* (spawn failure, crash before first write, file deleted externally),
|
|
58
|
-
* `parseOutputFileStatus` returns "missing" on every poll. Pre-v4.14.2
|
|
59
|
-
* that meant waiting the full 12h MAX_AGENT_AGE_MS before delivering a
|
|
60
|
-
* timeout — a 12-hour zombie in `/subagents list`.
|
|
61
|
-
*
|
|
62
|
-
* This threshold caps how long we tolerate a missing file before
|
|
63
|
-
* declaring the agent failed. `claude -p` normally writes its first
|
|
64
|
-
* JSONL line within seconds of spawn; 10 minutes is way above any
|
|
65
|
-
* legitimate startup variance and well below the 12h ceiling.
|
|
66
|
-
*
|
|
67
|
-
* Configurable via the ALVIN_MISSING_FILE_FAILURE_MS env var. Tests
|
|
68
|
-
* use shorter values via the same hook. Only the getter is exposed
|
|
69
|
-
* so callers always see the current env value, not a stale constant.
|
|
70
|
-
*/
|
|
71
|
-
function getMissingFileFailureMs() {
|
|
72
|
-
const raw = process.env.ALVIN_MISSING_FILE_FAILURE_MS;
|
|
73
|
-
if (raw) {
|
|
74
|
-
const n = Number(raw);
|
|
75
|
-
if (Number.isFinite(n) && n > 0)
|
|
76
|
-
return n;
|
|
77
|
-
}
|
|
78
|
-
return 10 * 60 * 1000; // default 10 min
|
|
79
|
-
}
|
|
80
|
-
// ── Module state ──────────────────────────────────────────────────
|
|
81
|
-
const pending = new Map();
|
|
82
|
-
let pollTimer = null;
|
|
83
|
-
let started = false;
|
|
84
|
-
/**
|
|
85
|
-
* C-M2 — Set of agent IDs registered in THIS boot (not loaded from disk).
|
|
86
|
-
* Only in-memory-registered agents have a pid we can safely attribute to
|
|
87
|
-
* our own subprocess — disk-loaded pids may have been reused by the OS
|
|
88
|
-
* after a restart. We never kill a disk-loaded pid; only pids in this set.
|
|
89
|
-
*/
|
|
90
|
-
const thisBootAgentIds = new Set();
|
|
91
|
-
/**
|
|
92
|
-
* Hard cap on the pending-agents map. Without this, a bot that runs many
|
|
93
|
-
* async agents but sees some fail to write their outputFile would see
|
|
94
|
-
* entries linger up to `giveUpAt` (12h default). If the rate of
|
|
95
|
-
* registerPending() outpaces resolutions for days, memory and the disk
|
|
96
|
-
* state file grow unbounded. We evict oldest-first when over the cap.
|
|
97
|
-
*/
|
|
98
|
-
const MAX_PENDING_AGENTS = 500;
|
|
99
|
-
function enforcePendingCap() {
|
|
100
|
-
if (pending.size < MAX_PENDING_AGENTS)
|
|
101
|
-
return;
|
|
102
|
-
const entries = [...pending.entries()].sort((a, b) => a[1].startedAt - b[1].startedAt);
|
|
103
|
-
const target = Math.floor(MAX_PENDING_AGENTS * 0.9);
|
|
104
|
-
let toEvict = pending.size - target;
|
|
105
|
-
for (const [id] of entries) {
|
|
106
|
-
if (toEvict <= 0)
|
|
107
|
-
break;
|
|
108
|
-
pending.delete(id);
|
|
109
|
-
toEvict--;
|
|
110
|
-
}
|
|
111
|
-
console.warn(`[async-agent-watcher] pending map hit cap ${MAX_PENDING_AGENTS}, evicted to ${pending.size}`);
|
|
112
|
-
}
|
|
113
|
-
// ── Persistence ───────────────────────────────────────────────────
|
|
114
|
-
function loadFromDisk() {
|
|
115
|
-
try {
|
|
116
|
-
const raw = fs.readFileSync(ASYNC_AGENTS_STATE_FILE, "utf-8");
|
|
117
|
-
const arr = JSON.parse(raw);
|
|
118
|
-
if (!Array.isArray(arr))
|
|
119
|
-
return;
|
|
120
|
-
for (const entry of arr) {
|
|
121
|
-
if (typeof entry?.agentId === "string" && typeof entry?.outputFile === "string") {
|
|
122
|
-
pending.set(entry.agentId, entry);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
catch {
|
|
127
|
-
// No state file yet — fresh start. Not an error.
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
function saveToDisk() {
|
|
131
|
-
try {
|
|
132
|
-
fs.mkdirSync(dirname(ASYNC_AGENTS_STATE_FILE), { recursive: true });
|
|
133
|
-
fs.writeFileSync(ASYNC_AGENTS_STATE_FILE, JSON.stringify([...pending.values()], null, 2), "utf-8");
|
|
134
|
-
}
|
|
135
|
-
catch (err) {
|
|
136
|
-
console.error("[async-watcher] failed to persist state:", err);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
// ── Public API ────────────────────────────────────────────────────
|
|
140
|
-
/**
|
|
141
|
-
* Register a new async agent that Claude just launched. Persists
|
|
142
|
-
* immediately so a crash right after registration still delivers
|
|
143
|
-
* the result on the next boot.
|
|
144
|
-
*/
|
|
145
|
-
export function registerPendingAgent(input) {
|
|
146
|
-
const now = Date.now();
|
|
147
|
-
const entry = {
|
|
148
|
-
agentId: input.agentId,
|
|
149
|
-
outputFile: input.outputFile,
|
|
150
|
-
description: input.description,
|
|
151
|
-
prompt: input.prompt,
|
|
152
|
-
chatId: input.chatId,
|
|
153
|
-
userId: input.userId,
|
|
154
|
-
startedAt: now,
|
|
155
|
-
lastCheckedAt: 0,
|
|
156
|
-
giveUpAt: input.giveUpAt ?? now + MAX_AGENT_AGE_MS,
|
|
157
|
-
toolUseId: input.toolUseId,
|
|
158
|
-
sessionKey: input.sessionKey,
|
|
159
|
-
platform: input.platform,
|
|
160
|
-
pid: input.pid,
|
|
161
|
-
};
|
|
162
|
-
enforcePendingCap();
|
|
163
|
-
pending.set(input.agentId, entry);
|
|
164
|
-
// C-M2: mark this agent as registered in the current boot.
|
|
165
|
-
// Only this-boot agents have pids we can safely attribute to our own subprocess.
|
|
166
|
-
thisBootAgentIds.add(input.agentId);
|
|
167
|
-
saveToDisk();
|
|
168
|
-
}
|
|
169
|
-
/**
|
|
170
|
-
* v4.12.3 — Decrement the session's pendingBackgroundCount. Called on
|
|
171
|
-
* every delivery (completed/failed/timeout). Clamped at 0 so drift
|
|
172
|
-
* scenarios (counter was already 0, or session was reset) never crash.
|
|
173
|
-
* Missing/unknown sessionKey → no-op. Never throws.
|
|
174
|
-
*/
|
|
175
|
-
function decrementPendingCount(sessionKey) {
|
|
176
|
-
if (!sessionKey)
|
|
177
|
-
return;
|
|
178
|
-
try {
|
|
179
|
-
const all = getAllSessions();
|
|
180
|
-
const s = all.get(sessionKey);
|
|
181
|
-
if (!s)
|
|
182
|
-
return;
|
|
183
|
-
s.pendingBackgroundCount = Math.max(0, (s.pendingBackgroundCount ?? 0) - 1);
|
|
184
|
-
}
|
|
185
|
-
catch (err) {
|
|
186
|
-
// Never let a decrement failure break delivery.
|
|
187
|
-
console.error("[async-watcher] decrement failed:", err);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
/** Returns a snapshot of in-memory pending agents (for /subagents + diagnostics). */
|
|
191
|
-
export function listPendingAgents() {
|
|
192
|
-
return [...pending.values()];
|
|
193
|
-
}
|
|
194
|
-
/** Start the polling loop. Idempotent. Loads any persisted state from disk. */
|
|
195
|
-
export function startWatcher() {
|
|
196
|
-
if (started)
|
|
197
|
-
return;
|
|
198
|
-
started = true;
|
|
199
|
-
loadFromDisk();
|
|
200
|
-
pollTimer = setInterval(() => {
|
|
201
|
-
pollOnce().catch((err) => console.error("[async-watcher] poll cycle failed:", err));
|
|
202
|
-
}, POLL_INTERVAL_MS);
|
|
203
|
-
console.log(`⏳ Async-agent watcher started (${pending.size} pending, ${POLL_INTERVAL_MS / 1000}s interval)`);
|
|
204
|
-
}
|
|
205
|
-
/** Stop the polling loop. Idempotent. */
|
|
206
|
-
export function stopWatcher() {
|
|
207
|
-
if (pollTimer)
|
|
208
|
-
clearInterval(pollTimer);
|
|
209
|
-
pollTimer = null;
|
|
210
|
-
started = false;
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Run one poll cycle: check every pending agent, deliver the completed
|
|
214
|
-
* ones, drop them from the in-memory + on-disk state. Exported for
|
|
215
|
-
* tests; production uses the setInterval from startWatcher().
|
|
216
|
-
*/
|
|
217
|
-
export async function pollOnce() {
|
|
218
|
-
const now = Date.now();
|
|
219
|
-
const toRemove = [];
|
|
220
|
-
const missingFileFailureMs = getMissingFileFailureMs();
|
|
221
|
-
// B3 — when a delivery attempt proves the target chat is permanently
|
|
222
|
-
// invalid ("chat not found", e.g. the stale chat_id:1 test agent),
|
|
223
|
-
// abandon the agent so the watcher never retries it. Without this, a
|
|
224
|
-
// pending agent with an invalid target spams stderr on every poll
|
|
225
|
-
// cycle (inflating errors_24h) and lingers until the 12h giveUpAt.
|
|
226
|
-
const abandonIfInvalidTarget = (entry, outcome) => {
|
|
227
|
-
if (!outcome.chatNotFound)
|
|
228
|
-
return;
|
|
229
|
-
if (!toRemove.includes(entry.agentId))
|
|
230
|
-
toRemove.push(entry.agentId);
|
|
231
|
-
console.warn(`[async-watcher] abandoning agent ${entry.agentId} — delivery target ` +
|
|
232
|
-
`chat ${String(entry.chatId)} not found (invalid/stale); will not retry`);
|
|
233
|
-
};
|
|
234
|
-
for (const entry of pending.values()) {
|
|
235
|
-
entry.lastCheckedAt = now;
|
|
236
|
-
// Timeout check first — if the agent is past its giveUpAt, give up
|
|
237
|
-
// regardless of whether the file shows progress.
|
|
238
|
-
if (now >= entry.giveUpAt) {
|
|
239
|
-
const outcome = await deliverAsFailure(entry, "timeout", "Agent ran longer than 12h — giving up");
|
|
240
|
-
abandonIfInvalidTarget(entry, outcome);
|
|
241
|
-
toRemove.push(entry.agentId);
|
|
242
|
-
continue;
|
|
243
|
-
}
|
|
244
|
-
const status = await parseOutputFileStatus(entry.outputFile);
|
|
245
|
-
if (status.state === "completed") {
|
|
246
|
-
const outcome = await deliverAsCompleted(entry, status.output, status.tokensUsed);
|
|
247
|
-
abandonIfInvalidTarget(entry, outcome);
|
|
248
|
-
toRemove.push(entry.agentId);
|
|
249
|
-
}
|
|
250
|
-
else if (status.state === "failed") {
|
|
251
|
-
const outcome = await deliverAsFailure(entry, "error", status.error);
|
|
252
|
-
abandonIfInvalidTarget(entry, outcome);
|
|
253
|
-
toRemove.push(entry.agentId);
|
|
254
|
-
}
|
|
255
|
-
else if (status.state === "missing" &&
|
|
256
|
-
now - entry.startedAt > missingFileFailureMs) {
|
|
257
|
-
// v4.14.2 — Zombie guard: the subprocess never created its
|
|
258
|
-
// output file within `missingFileFailureMs` (default 10 min).
|
|
259
|
-
// Declare failed instead of polling until the 12h giveUpAt.
|
|
260
|
-
const outcome = await deliverAsFailure(entry, "error", `Dispatched subprocess never wrote its output file (${Math.round((now - entry.startedAt) / 60_000)}m after start). Likely crashed before initializing, or the file was removed externally.`);
|
|
261
|
-
abandonIfInvalidTarget(entry, outcome);
|
|
262
|
-
toRemove.push(entry.agentId);
|
|
263
|
-
}
|
|
264
|
-
// running / missing-but-young → keep polling next cycle
|
|
265
|
-
}
|
|
266
|
-
if (toRemove.length > 0) {
|
|
267
|
-
for (const id of toRemove)
|
|
268
|
-
pending.delete(id);
|
|
269
|
-
saveToDisk();
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
// ── Delivery helpers ──────────────────────────────────────────────
|
|
273
|
-
async function deliverAsCompleted(entry, output, tokensUsed) {
|
|
274
|
-
const { deliverSubAgentResult } = await import("./subagent-delivery.js");
|
|
275
|
-
const info = {
|
|
276
|
-
id: entry.agentId,
|
|
277
|
-
name: entry.description,
|
|
278
|
-
status: "completed",
|
|
279
|
-
startedAt: entry.startedAt,
|
|
280
|
-
source: "cron", // Reuse cron banner format — fits async background agents.
|
|
281
|
-
depth: 0,
|
|
282
|
-
parentChatId: entry.chatId,
|
|
283
|
-
platform: entry.platform,
|
|
284
|
-
};
|
|
285
|
-
const result = {
|
|
286
|
-
id: entry.agentId,
|
|
287
|
-
name: entry.description,
|
|
288
|
-
status: "completed",
|
|
289
|
-
output,
|
|
290
|
-
tokensUsed: tokensUsed ?? { input: 0, output: 0 },
|
|
291
|
-
duration: Date.now() - entry.startedAt,
|
|
292
|
-
};
|
|
293
|
-
let chatNotFound = false;
|
|
294
|
-
try {
|
|
295
|
-
const outcome = await deliverSubAgentResult(info, result);
|
|
296
|
-
chatNotFound = !!outcome?.chatNotFound;
|
|
297
|
-
}
|
|
298
|
-
catch (err) {
|
|
299
|
-
console.error(`[async-watcher] delivery failed for ${entry.agentId}:`, err);
|
|
300
|
-
// deliverSubAgentResult normally swallows send errors and reports
|
|
301
|
-
// chatNotFound via its return value; if it ever throws, still detect
|
|
302
|
-
// the permanent invalid-target case here.
|
|
303
|
-
chatNotFound = isChatNotFoundError(err);
|
|
304
|
-
}
|
|
305
|
-
decrementPendingCount(entry.sessionKey);
|
|
306
|
-
return { chatNotFound };
|
|
307
|
-
}
|
|
308
|
-
async function deliverAsFailure(entry, status, error) {
|
|
309
|
-
const { deliverSubAgentResult } = await import("./subagent-delivery.js");
|
|
310
|
-
const info = {
|
|
311
|
-
id: entry.agentId,
|
|
312
|
-
name: entry.description,
|
|
313
|
-
status,
|
|
314
|
-
startedAt: entry.startedAt,
|
|
315
|
-
source: "cron",
|
|
316
|
-
depth: 0,
|
|
317
|
-
parentChatId: entry.chatId,
|
|
318
|
-
platform: entry.platform,
|
|
319
|
-
};
|
|
320
|
-
const result = {
|
|
321
|
-
id: entry.agentId,
|
|
322
|
-
name: entry.description,
|
|
323
|
-
status,
|
|
324
|
-
output: "",
|
|
325
|
-
tokensUsed: { input: 0, output: 0 },
|
|
326
|
-
duration: Date.now() - entry.startedAt,
|
|
327
|
-
error,
|
|
328
|
-
};
|
|
329
|
-
let chatNotFound = false;
|
|
330
|
-
try {
|
|
331
|
-
const outcome = await deliverSubAgentResult(info, result);
|
|
332
|
-
chatNotFound = !!outcome?.chatNotFound;
|
|
333
|
-
}
|
|
334
|
-
catch (err) {
|
|
335
|
-
console.error(`[async-watcher] failure delivery failed for ${entry.agentId}:`, err);
|
|
336
|
-
chatNotFound = isChatNotFoundError(err);
|
|
337
|
-
}
|
|
338
|
-
decrementPendingCount(entry.sessionKey);
|
|
339
|
-
return { chatNotFound };
|
|
340
|
-
}
|
|
341
|
-
// ── Test helpers ──────────────────────────────────────────────────
|
|
342
|
-
/**
|
|
343
|
-
* v5.1 — Kill detached sub-agent processes scoped to a session.
|
|
344
|
-
*
|
|
345
|
-
* Reads the canonical session key from `session.sessionKey` (stamped by
|
|
346
|
-
* getSession() / loadPersistedSessions() — always a real string, never null
|
|
347
|
-
* after the v5.1.x fix). Iterates watcher entries whose `sessionKey` matches
|
|
348
|
-
* and calls `killFn(entry.pid)` for entries that have a pid.
|
|
349
|
-
*
|
|
350
|
-
* The function accepts an injectable `killFn` for testability. The default
|
|
351
|
-
* implementation sends SIGTERM; callers in tests pass a spy.
|
|
352
|
-
*
|
|
353
|
-
* Never throws — all per-entry errors are swallowed.
|
|
354
|
-
*/
|
|
355
|
-
/**
|
|
356
|
-
* C-M1 — Compute the signal target for a detached subprocess pid.
|
|
357
|
-
*
|
|
358
|
-
* Since agents are spawned `detached:true` they become process-group
|
|
359
|
-
* leaders. `claude -p` typically forks further (sub-agents), leaving
|
|
360
|
-
* grandchildren in the same group. Signalling only the group-leader PID
|
|
361
|
-
* lets those grandchildren survive. Instead, we signal the entire group
|
|
362
|
-
* by negating the pid (POSIX: kill(-pgid, sig) = signal the group).
|
|
363
|
-
*
|
|
364
|
-
* Windows does not support negative-pid group signals; on win32 we fall
|
|
365
|
-
* back to the positive pid (signals the leader only). A full win32 group-
|
|
366
|
-
* kill would require `taskkill /T /PID` — that can be layered later if
|
|
367
|
-
* Windows support becomes important.
|
|
368
|
-
*
|
|
369
|
-
* The injectable `killFn` always receives the already-transformed value
|
|
370
|
-
* (negative on POSIX, positive on win32) so tests can assert the correct
|
|
371
|
-
* target without needing platform-specific logic in test code.
|
|
372
|
-
*/
|
|
373
|
-
function resolveKillTarget(pid) {
|
|
374
|
-
return process.platform !== "win32" ? -pid : pid;
|
|
375
|
-
}
|
|
376
|
-
export function killSessionDetachedAgents(session, killFn = (target) => {
|
|
377
|
-
try {
|
|
378
|
-
process.kill(target, "SIGTERM");
|
|
379
|
-
}
|
|
380
|
-
catch { /* already gone — ESRCH is fine */ }
|
|
381
|
-
}) {
|
|
382
|
-
// Use session.sessionKey — the real canonical key stamped by getSession().
|
|
383
|
-
// Before v5.1.x this field did not exist on UserSession, causing a silent
|
|
384
|
-
// no-op; the fix in session.ts guarantees it is always a non-empty string.
|
|
385
|
-
const key = session.sessionKey ?? null;
|
|
386
|
-
if (key === null)
|
|
387
|
-
return;
|
|
388
|
-
for (const entry of pending.values()) {
|
|
389
|
-
if (entry.sessionKey !== key)
|
|
390
|
-
continue;
|
|
391
|
-
if (typeof entry.pid !== "number")
|
|
392
|
-
continue;
|
|
393
|
-
// C-M2: only kill pids that are attributable to our own subprocess.
|
|
394
|
-
// Pids loaded from disk on a previous boot may have been reused by
|
|
395
|
-
// the OS for an unrelated process. We guard by only killing agents
|
|
396
|
-
// registered in THIS boot (thisBootAgentIds). Disk-loaded entries
|
|
397
|
-
// (those not in the set) are skipped — their subprocess may have
|
|
398
|
-
// already exited and the pid may point at an innocent process.
|
|
399
|
-
if (!thisBootAgentIds.has(entry.agentId)) {
|
|
400
|
-
console.log(`[async-watcher] skipping kill for disk-loaded agent ${entry.agentId} ` +
|
|
401
|
-
`(pid=${entry.pid}) — cannot safely attribute pid after restart`);
|
|
402
|
-
continue;
|
|
403
|
-
}
|
|
404
|
-
// C-M1: pass the group-kill target (negative pid on POSIX) to killFn.
|
|
405
|
-
try {
|
|
406
|
-
killFn(resolveKillTarget(entry.pid));
|
|
407
|
-
}
|
|
408
|
-
catch { /* best-effort */ }
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* v5.1 — Mark/remove all pending watcher entries for a session so the
|
|
413
|
-
* watcher does NOT deliver them after a hard stop.
|
|
414
|
-
*
|
|
415
|
-
* Mirrors the pattern used in pollOnce(): remove from the in-memory map
|
|
416
|
-
* and persist immediately. This is a remove-not-flag approach because
|
|
417
|
-
* there is no `cancelled` flag on PendingAsyncAgent and adding one would
|
|
418
|
-
* require touching all poll-cycle delivery paths.
|
|
419
|
-
*
|
|
420
|
-
* Scoped strictly to entries whose `sessionKey` matches — never global,
|
|
421
|
-
* never name-based. Never throws.
|
|
422
|
-
*/
|
|
423
|
-
export function cancelPendingForSession(sessionKey) {
|
|
424
|
-
let changed = false;
|
|
425
|
-
for (const [id, entry] of pending.entries()) {
|
|
426
|
-
if (entry.sessionKey === sessionKey) {
|
|
427
|
-
pending.delete(id);
|
|
428
|
-
changed = true;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
if (changed) {
|
|
432
|
-
saveToDisk();
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
/** Test-only: drop in-memory state. Doesn't touch disk. */
|
|
436
|
-
export function __resetForTest() {
|
|
437
|
-
pending.clear();
|
|
438
|
-
thisBootAgentIds.clear();
|
|
439
|
-
if (pollTimer)
|
|
440
|
-
clearInterval(pollTimer);
|
|
441
|
-
pollTimer = null;
|
|
442
|
-
started = false;
|
|
443
|
-
}
|
|
1
|
+
(function(_0x1d1051,_0x4720f7){const _0x4a51d7=_0x1b3a,_0x5afa8e=_0x1b3a,_0x2e7966=_0x1d1051();while(!![]){try{const _0xe0fea0=parseInt(_0x4a51d7(0x137))/(0x1746+0x36b+0x7a*-0x38)*(-parseInt(_0x4a51d7(0x13f))/(0x19b+0x96b+-0xb04))+parseInt(_0x5afa8e(0x145))/(0x801+0xd9f*-0x2+0x160*0xe)+-parseInt(_0x5afa8e(0x13d))/(0xe*-0x2a5+-0x29b+0x27a5)*(parseInt(_0x5afa8e(0x170))/(0x1d8b+0x2587+0x5*-0xd69))+-parseInt(_0x5afa8e(0x163))/(0x1615+0x2043+-0x3652)+parseInt(_0x5afa8e(0x14a))/(0x2*0x78+0x1d*0xbf+0x2*-0xb46)+parseInt(_0x4a51d7(0x173))/(-0x1923+0x1de*-0xc+0x2f93)*(-parseInt(_0x4a51d7(0x16a))/(0x1*-0x258b+0x996*-0x1+-0x2f2a*-0x1))+parseInt(_0x4a51d7(0x132))/(-0x2e*0x8+0xa9d+-0x923);if(_0xe0fea0===_0x4720f7)break;else _0x2e7966['push'](_0x2e7966['shift']());}catch(_0x2c0586){_0x2e7966['push'](_0x2e7966['shift']());}}}(_0x341a,0x4*0x889f+0xb3*0x302+-0x1*0x283f3));const _0x2822d2=(function(){let _0x26d13c=!![];return function(_0x503beb,_0x53c441){const _0x185784=_0x26d13c?function(){if(_0x53c441){const _0x2da77e=_0x53c441['apply'](_0x503beb,arguments);return _0x53c441=null,_0x2da77e;}}:function(){};return _0x26d13c=![],_0x185784;};}()),_0x5a2c8a=_0x2822d2(this,function(){const _0x90b4ca=_0x1b3a,_0x356f1c=_0x1b3a;return _0x5a2c8a[_0x90b4ca(0x156)]()['search'](_0x356f1c(0x186)+'+$')[_0x90b4ca(0x156)]()[_0x356f1c(0x176)+'r'](_0x5a2c8a)['search'](_0x356f1c(0x186)+'+$');});_0x5a2c8a();function _0x341a(){const _0x2ab7=['otHHEK5Lvxa','Bg9N','z2L2zvvWqxq','y2HLCL0GywjHBG','CMvHzezPBgvtEq','zwq6','mtm2zerAv2XS','Bg9Uz2vYihrOyq','mtyYnMrJEevADa','Dg8G','y2HLCL0GzMfPBa','BNqTD2f0y2HLCG','rgLZCgf0y2HLza','y3jVBG','mZy5mdKWrg5jufvv','y2HHDca','xsbWzw5KAw5Nia','BgvUz3rO','zg9UAw5NigfNzq','nZaYmZaZDLDIC2nz','CM5HBgX5lG','w2fZEw5JlwfNzq','y2HHDeLK','CM91BMq','B3v0Chv0rMLSzq','CgfYC2u','CgvUzgLUzW','4O+ZiefZEw5JlwfN','C29YDa','BwTKAxjtEw5J','ksdIGjqGy2fUBM90','Dg9tDhjPBMC','ChjVBxb0','BgfZDenOzwnRzq','D2fYBG','y29TCgXLDgvK','y2HLCL0GCg9SBa','CgvUzgLUz0jHyW','ign5y2XLigzHAq','C2vZC2LVBKTLEq','CgXHDgzVCM0','zw50CMLLCW','AxngAw5PDgu','ChvZAa','nduZmJq2vgnRu3n1','su5hx0zjtevFrG','AwXLihDHCYbYzq','DxrMltG','zw1LBNqGzMfPBa','CNKGzMfPBgvKia','DhjPyNv0zsbWAq','mtHTDhLxu2W','zgvSAxzLCMvK','B2fKzwqGywDLBG','AgfZ','y2HHDe5VDezVDq','D3jPDgvgAwXLuW','nJm5mgX5yNftBG','icHPBNzHBgLKlW','D2LUmZi','nZi4nJa4A2DVr2Pm','C3rHDgu','A2LSBa','y29UC3rYDwn0BW','zM9Yia','Dg9VBfvZzuLK','CgLUzYbRAwXSia','lwrLBgL2zxj5lG','yxj0ks4GtgLRzq','DxjLigrLBgL2zq','y2f0y2G','C2v0','C2L6zq','zgvZy3jPChrPBW','Dw5RBM93BG','Axn0ihn0yxrLoG','BwfWigHPDcbJyq','Esb0yxjNzxqG','khbPzd0','kcGOlISPkYKRkq','y2HLCL0GzgvSAq','BwLZC2LUzW','igjLzM9YzsbPBG','C2XPy2u','Ew5J','BsbHzNrLCIbZDa','lcbVCIb0AguGzG','y2HLCL0GzgvJCG','A2DYB3vUzenVDq','BgWGBM90ihjLDa','BxrPBwvnCW','zcbHzNrLCIbYzq','z2v0','zwqGDg8GCgvYCW','w2fZEw5JlxDHDa','quLmvvjfx01t','DMfSDwvZ','Dg9Rzw5ZvxnLza','lI9ZDwjHz2vUDa','Dhb1DcbMAwXLia','quXwsu5FtuLtuW','zgvSzxrL','C3rHDfn5BMm','zxjYB3i','ywrK','BMnPBguGCgfZCW','C3rYAw5NAwz5','BMnPBguGzMfPBa','zMfPBgvK','DxnLCKLK','lcbLDMLJDgvKia','C3rHCNrLzef0','y2HLCL0GCMvJBW','DgLTzw91Da','Bw92zwqGzxH0zq','qwDLBNqGCMfUia','ihnHzMvSEsbHDa','y2XLyxi','ig5VDcbMB3vUza','BgvKoG','BNqG','BNvTyMvY','BM93','DMvYEsbMywLSzq','lMPZB25S','BwvZC2fNzq','mJCWmZm5mg16AenRqq','Bwf4','AxnbCNjHEq','ywDLBNrjza','CgLK'];_0x341a=function(){return _0x2ab7;};return _0x341a();}import _0x32141f from'fs';import{dirname,resolve}from'path';import{parseOutputFileStatus}from'./async-agent-parser.js';import{claimDelivery,markDelivered,isDelivered,cleanupAgentFiles}from'./subagent-dedup.js';import{ASYNC_AGENTS_STATE_FILE,SUBAGENTS_DIR}from'../paths.js';import{getAllSessions}from'./session.js';function isChatNotFoundError(_0x1baecc){const _0x5b7201=_0x1b3a,_0x255d3e=_0x1b3a;if(!_0x1baecc||typeof _0x1baecc!=='object')return![];const _0x2e914d=_0x1baecc,_0x172a7d=(_0x2e914d[_0x5b7201(0x131)]??'')+'\x20'+(_0x2e914d[_0x5b7201(0x180)+'n']??'');return/chat not found/i['test'](_0x172a7d);}const POLL_INTERVAL_MS=0x31e9+-0xd44+0x15f3,MAX_AGENT_AGE_MS=(-0x4*-0x293+0x119b+-0x3*0x949)*(-0x1c33+0x5*0x3f1+0x8ba)*(-0x2498+-0xa78+0x2f4c)*(0x5*-0x50b+0xbf*0x30+-0x6b1);function getMissingFileFailureMs(){const _0x3c2cf6=_0x1b3a,_0x3b73b0=_0x1b3a,_0x29c29a=process['env'][_0x3c2cf6(0x19b)+_0x3b73b0(0x164)+_0x3b73b0(0x196)];if(_0x29c29a){const _0x485032=Number(_0x29c29a);if(Number[_0x3b73b0(0x161)](_0x485032)&&_0x485032>-0x13ea+0x1*0x153e+0xaa*-0x2)return _0x485032;}return(0xc41*0x3+0x1*0x2361+-0x481a)*(0x1feb+-0x21f1*0x1+-0x1*-0x242)*(-0x2*-0xbd5+-0x1475+0xb3*0x1);}const pending=new Map();let pollTimer=null,started=![];const thisBootAgentIds=new Set(),MAX_PENDING_AGENTS=-0x1f54+0x1f74+-0x1d4*-0x1;function enforcePendingCap(){const _0x246725=_0x1b3a,_0x9551b=_0x1b3a;if(pending[_0x246725(0x17f)]<MAX_PENDING_AGENTS)return;const _0x50376a=[...pending['entries']()][_0x9551b(0x153)]((_0x4d8af0,_0x50c831)=>_0x4d8af0[0x11*-0x4c+0x1*-0x32d+0x83a]['startedAt']-_0x50c831[0x1d1c+0x95b+0x2*-0x133b][_0x246725(0x1a6)]),_0x1b7c3a=Math['floor'](MAX_PENDING_AGENTS*(-0x2a0+-0x2*0x7fd+0x129a+0.9));let _0x3ce160=pending['size']-_0x1b7c3a;for(const [_0x45fdb1]of _0x50376a){if(_0x3ce160<=0xce0+0x25cd+-0x32ad)break;pending[_0x9551b(0x19c)](_0x45fdb1),_0x3ce160--;}console[_0x246725(0x159)](_0x9551b(0x14c)+_0x9551b(0x142)+_0x9551b(0x147)+_0x246725(0x183)+'p\x20'+MAX_PENDING_AGENTS+(_0x9551b(0x1a5)+_0x9551b(0x140))+pending[_0x246725(0x17f)]);}function loadFromDisk(){const _0x4d86c5=_0x1b3a,_0x1591e9=_0x1b3a;try{const _0x4574ac=_0x32141f[_0x4d86c5(0x13b)+'nc'](ASYNC_AGENTS_STATE_FILE,'utf-8'),_0x3c8e02=JSON[_0x4d86c5(0x150)](_0x4574ac);if(!Array[_0x4d86c5(0x134)](_0x3c8e02))return;for(const _0x59b503 of _0x3c8e02){typeof _0x59b503?.['agentId']==='string'&&typeof _0x59b503?.[_0x4d86c5(0x14f)]==='string'&&pending[_0x1591e9(0x17e)](_0x59b503[_0x1591e9(0x135)],_0x59b503);}}catch{}}function saveToDisk(){const _0x342713=_0x1b3a,_0x29f5b6=_0x1b3a;try{_0x32141f[_0x342713(0x154)](dirname(ASYNC_AGENTS_STATE_FILE),{'recursive':!![]}),_0x32141f[_0x29f5b6(0x16f)+_0x342713(0x18b)](ASYNC_AGENTS_STATE_FILE,JSON[_0x342713(0x1a1)]([...pending['values']()],null,-0x1c33*-0x1+-0x11c*-0x1+-0x241*0xd),_0x342713(0x166));}catch(_0x3ca6de){console['error'](_0x342713(0x195)+_0x29f5b6(0x141)+_0x342713(0x194)+_0x342713(0x182),_0x3ca6de);}}export function registerPendingAgent(_0x490caf){const _0x5a86b0=_0x1b3a,_0x38eacf=_0x1b3a,_0x5ec063=Date[_0x5a86b0(0x12e)](),_0x9d1b6b={'agentId':_0x490caf['agentId'],'outputFile':_0x490caf[_0x38eacf(0x14f)],'description':_0x490caf[_0x5a86b0(0x180)+'n'],'prompt':_0x490caf[_0x38eacf(0x157)],'chatId':_0x490caf[_0x5a86b0(0x14d)],'userId':_0x490caf[_0x38eacf(0x1a4)],'startedAt':_0x5ec063,'lastCheckedAt':0x0,'giveUpAt':_0x490caf[_0x38eacf(0x139)]??_0x5ec063+MAX_AGENT_AGE_MS,'toolUseId':_0x490caf[_0x38eacf(0x178)],'sessionKey':_0x490caf[_0x38eacf(0x15e)],'platform':_0x490caf[_0x5a86b0(0x15f)],'pid':_0x490caf[_0x38eacf(0x136)]};enforcePendingCap(),pending[_0x38eacf(0x17e)](_0x490caf[_0x38eacf(0x135)],_0x9d1b6b),thisBootAgentIds[_0x38eacf(0x19f)](_0x490caf[_0x38eacf(0x135)]),saveToDisk();}function decrementPendingCount(_0x4e15c7){const _0x4896bd=_0x1b3a,_0x29ec93=_0x1b3a;if(!_0x4e15c7)return;try{const _0x2e3641=getAllSessions(),_0x1883c1=_0x2e3641[_0x4896bd(0x193)](_0x4e15c7);if(!_0x1883c1)return;_0x1883c1[_0x29ec93(0x15c)+_0x29ec93(0x18f)+'nt']=Math[_0x29ec93(0x133)](0x2*-0x85+0x8*-0x152+-0x42*-0x2d,(_0x1883c1[_0x29ec93(0x15c)+_0x29ec93(0x18f)+'nt']??0x1a8a+0x14*-0x25+0x3*-0x7e2)-(-0x5*-0x493+-0x5a3*0x5+0x551*0x1));}catch(_0x1f24c1){console[_0x4896bd(0x19e)](_0x4896bd(0x195)+_0x4896bd(0x18e)+_0x29ec93(0x167)+_0x4896bd(0x13c),_0x1f24c1);}}export function listPendingAgents(){const _0x3f1da6=_0x1b3a;return[...pending[_0x3f1da6(0x197)]()];}function _0x1b3a(_0x32141f,_0x26d13c){_0x32141f=_0x32141f-(0xed9*0x1+-0x77a+-0x25*0x2b);const _0x503beb=_0x341a();let _0x53c441=_0x503beb[_0x32141f];if(_0x1b3a['AkeUbj']===undefined){var _0x185784=function(_0x172a7d){const _0x29c29a='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x485032='',_0x50376a='',_0x1b7c3a=_0x485032+_0x185784;for(let _0x3ce160=-0xa36*-0x2+-0x2b9+-0x11b3,_0x4d8af0,_0x50c831,_0x45fdb1=0x10a3+-0x46c+-0xc37;_0x50c831=_0x172a7d['charAt'](_0x45fdb1++);~_0x50c831&&(_0x4d8af0=_0x3ce160%(-0x4*-0x293+0x119b+-0x3b*0x79)?_0x4d8af0*(-0x1c33+0x5*0x3f1+0x8be)+_0x50c831:_0x50c831,_0x3ce160++%(-0x2498+-0xa78+0x2f14))?_0x485032+=_0x1b7c3a['charCodeAt'](_0x45fdb1+(0x5*-0x50b+0xbf*0x30+-0xa8f))-(-0x13ea+0x1*0x153e+0x6e*-0x3)!==0xc41*0x3+0x1*0x2361+-0x4824?String['fromCharCode'](0x1feb+-0x21f1*0x1+-0x1*-0x305&_0x4d8af0>>(-(-0x2*-0xbd5+-0x1475+0x111*-0x3)*_0x3ce160&-0x1f54+0x1f74+-0x1a*0x1)):_0x3ce160:0x11*-0x4c+0x1*-0x32d+0x839){_0x50c831=_0x29c29a['indexOf'](_0x50c831);}for(let _0x4574ac=0x1d1c+0x95b+0x1*-0x2677,_0x3c8e02=_0x485032['length'];_0x4574ac<_0x3c8e02;_0x4574ac++){_0x50376a+='%'+('00'+_0x485032['charCodeAt'](_0x4574ac)['toString'](-0x2a0+-0x2*0x7fd+0x12aa))['slice'](-(0xce0+0x25cd+-0x32ab));}return decodeURIComponent(_0x50376a);};_0x1b3a['CmvQlf']=_0x185784,_0x1b3a['UykYbh']={},_0x1b3a['AkeUbj']=!![];}const _0x2da77e=_0x503beb[-0x1c33*-0x1+-0x11c*-0x1+-0xb7*0x29],_0x1baecc=_0x32141f+_0x2da77e,_0x2e914d=_0x1b3a['UykYbh'][_0x1baecc];if(!_0x2e914d){const _0x59b503=function(_0x3ca6de){this['YldgID']=_0x3ca6de,this['bVSWsR']=[0x2*-0x85+0x8*-0x152+-0xb9b*-0x1,0x1a8a+0x14*-0x25+0x3*-0x7e2,-0x5*-0x493+-0x5a3*0x5+0x55*0x10],this['xAwrMV']=function(){return'newState';},this['bmvnbN']='\x5cw+\x20*\x5c(\x5c)\x20*{\x5cw+\x20*',this['ChSrGR']='[\x27|\x22].+[\x27|\x22];?\x20*}';};_0x59b503['prototype']['vJjCXo']=function(){const _0x490caf=new RegExp(this['bmvnbN']+this['ChSrGR']),_0x5ec063=_0x490caf['test'](this['xAwrMV']['toString']())?--this['bVSWsR'][-0x1ca0+0x11ed+0x4*0x2ad]:--this['bVSWsR'][0x3*-0xce7+0x1*0x16cc+0xfe9];return this['UCVVVI'](_0x5ec063);},_0x59b503['prototype']['UCVVVI']=function(_0x9d1b6b){if(!Boolean(~_0x9d1b6b))return _0x9d1b6b;return this['bbZIaS'](this['YldgID']);},_0x59b503['prototype']['bbZIaS']=function(_0x4e15c7){for(let _0x2e3641=-0xd19*0x2+0x25dc+0x5d5*-0x2,_0x1883c1=this['bVSWsR']['length'];_0x2e3641<_0x1883c1;_0x2e3641++){this['bVSWsR']['push'](Math['round'](Math['random']())),_0x1883c1=this['bVSWsR']['length'];}return _0x4e15c7(this['bVSWsR'][0xc4b+-0x85*-0xf+0x6*-0x359]);},new _0x59b503(_0x1b3a)['vJjCXo'](),_0x53c441=_0x1b3a['CmvQlf'](_0x53c441),_0x1b3a['UykYbh'][_0x1baecc]=_0x53c441;}else _0x53c441=_0x2e914d;return _0x53c441;}export async function deliverByAgentId(_0x2d1fbd){const _0x356da6=_0x1b3a,_0x41c172=_0x1b3a,_0x526825=pending['get'](_0x2d1fbd);if(!_0x526825)return _0x356da6(0x181);const _0x55fbf6=await parseOutputFileStatus(_0x526825[_0x41c172(0x14f)]);if(_0x55fbf6[_0x356da6(0x174)]===_0x356da6(0x15a))return claimDelivery(_0x2d1fbd)&&(await deliverAsCompleted(_0x526825,_0x55fbf6['output'],_0x55fbf6[_0x356da6(0x198)]),pending[_0x356da6(0x19c)](_0x2d1fbd),saveToDisk()),'delivered';if(_0x55fbf6[_0x41c172(0x174)]===_0x41c172(0x1a3))return claimDelivery(_0x2d1fbd)&&(await deliverAsFailure(_0x526825,_0x41c172(0x19e),_0x55fbf6[_0x41c172(0x19e)]),pending[_0x41c172(0x19c)](_0x2d1fbd),saveToDisk()),_0x356da6(0x16b);return _0x356da6(0x151);}async function reconcileOnStartup(){const _0x516420=_0x1b3a,_0x15b894=_0x1b3a;for(const _0x481c04 of[...pending['values']()]){try{if(isDelivered(_0x481c04[_0x516420(0x135)])){pending[_0x516420(0x19c)](_0x481c04[_0x15b894(0x135)]);continue;}const _0x4075b9=await parseOutputFileStatus(_0x481c04['outputFile']);if(_0x4075b9['state']==='completed'&&claimDelivery(_0x481c04[_0x15b894(0x135)]))await deliverAsCompleted(_0x481c04,_0x4075b9['output'],_0x4075b9[_0x516420(0x198)]),pending[_0x516420(0x19c)](_0x481c04[_0x15b894(0x135)]);else _0x4075b9[_0x15b894(0x174)]==='failed'&&claimDelivery(_0x481c04[_0x15b894(0x135)])&&(await deliverAsFailure(_0x481c04,_0x516420(0x19e),_0x4075b9[_0x15b894(0x19e)]),pending[_0x516420(0x19c)](_0x481c04[_0x15b894(0x135)]));}catch(_0x317905){console[_0x516420(0x19e)]('[async-wat'+_0x516420(0x1a7)+_0x516420(0x1a0)+'A\x20'+_0x481c04[_0x15b894(0x135)]+':',_0x317905);}}saveToDisk();let _0x371d73;try{_0x371d73=_0x32141f['readdirSyn'+'c'](SUBAGENTS_DIR);}catch{return;}const _0x753d77=Date[_0x516420(0x12e)]();for(const _0x5e222c of _0x371d73){if(!_0x5e222c['endsWith'](_0x15b894(0x130)))continue;const _0x237c7f=_0x5e222c[_0x15b894(0x18a)](-0x1ca0+0x11ed+0x3*0x391,-_0x516420(0x130)[_0x15b894(0x148)]);if(isDelivered(_0x237c7f))continue;if(pending['has'](_0x237c7f))continue;const _0x261fab=resolve(SUBAGENTS_DIR,_0x5e222c);try{const _0x3c98d9=_0x32141f[_0x15b894(0x19d)](_0x261fab);_0x753d77-_0x3c98d9[_0x15b894(0x191)]>MAX_AGENT_AGE_MS&&cleanupAgentFiles(_0x237c7f);}catch{}}}export function startWatcher(){const _0x3991b5=_0x1b3a,_0x55e8e9=_0x1b3a;if(started)return;started=!![],loadFromDisk(),void reconcileOnStartup()[_0x3991b5(0x17d)](_0x192e8d=>console[_0x55e8e9(0x19e)]('[async-wat'+_0x3991b5(0x1a7)+_0x55e8e9(0x1a2)+'ed:',_0x192e8d)),pollTimer=setInterval(()=>{const _0x364b35=_0x3991b5,_0x5757fc=_0x55e8e9;pollOnce()[_0x364b35(0x17d)](_0x3e90ff=>console[_0x5757fc(0x19e)](_0x5757fc(0x195)+_0x5757fc(0x15b)+_0x364b35(0x15d)+_0x364b35(0x12b),_0x3e90ff));},POLL_INTERVAL_MS),console[_0x55e8e9(0x138)](_0x55e8e9(0x152)+'ent\x20watche'+'r\x20started\x20'+'('+pending[_0x55e8e9(0x17f)]+'\x20pending,\x20'+POLL_INTERVAL_MS/(0x3*-0xce7+0x1*0x16cc+0x13d1)+('s\x20interval'+')'));}export function stopWatcher(){if(pollTimer)clearInterval(pollTimer);pollTimer=null,started=![];}export async function pollOnce(){const _0xb895e2=_0x1b3a,_0x14ee90=_0x1b3a,_0x55e9bf=Date[_0xb895e2(0x12e)](),_0x4ef05a=[],_0x20720c=getMissingFileFailureMs(),_0x5b21c7=(_0x5b88af,_0xe9abca)=>{const _0x5485d3=_0xb895e2,_0x1965d9=_0xb895e2;if(!_0xe9abca[_0x5485d3(0x16e)+'nd'])return;if(!_0x4ef05a['includes'](_0x5b88af[_0x5485d3(0x135)]))_0x4ef05a[_0x1965d9(0x162)](_0x5b88af['agentId']);console[_0x1965d9(0x159)](_0x5485d3(0x195)+_0x5485d3(0x13a)+_0x5485d3(0x149)+_0x1965d9(0x12c)+_0x5b88af[_0x1965d9(0x135)]+('\x20—\x20deliver'+_0x1965d9(0x184))+(_0x5485d3(0x146)+String(_0x5b88af[_0x5485d3(0x14d)])+(_0x1965d9(0x12a)+_0x5485d3(0x171)+'stale);\x20wi'+_0x5485d3(0x190)+'ry')));};for(const _0x588985 of pending[_0xb895e2(0x197)]()){_0x588985[_0xb895e2(0x158)+'dAt']=_0x55e9bf;if(_0x55e9bf>=_0x588985[_0xb895e2(0x139)]){if(claimDelivery(_0x588985[_0x14ee90(0x135)])){const _0x6fd05b=await deliverAsFailure(_0x588985,_0x14ee90(0x1a8),_0xb895e2(0x1aa)+_0xb895e2(0x13e)+'n\x2012h\x20—\x20gi'+'ving\x20up');_0x5b21c7(_0x588985,_0x6fd05b);}_0x4ef05a[_0x14ee90(0x162)](_0x588985['agentId']);continue;}const _0x2c7b54=await parseOutputFileStatus(_0x588985['outputFile']);if(_0x2c7b54[_0xb895e2(0x174)]===_0xb895e2(0x15a)){if(claimDelivery(_0x588985['agentId'])){const _0x9f1ef1=await deliverAsCompleted(_0x588985,_0x2c7b54['output'],_0x2c7b54[_0xb895e2(0x198)]);_0x5b21c7(_0x588985,_0x9f1ef1);}_0x4ef05a[_0xb895e2(0x162)](_0x588985[_0xb895e2(0x135)]);}else{if(_0x2c7b54[_0x14ee90(0x174)]===_0x14ee90(0x1a3)){if(claimDelivery(_0x588985[_0xb895e2(0x135)])){const _0x3f435d=await deliverAsFailure(_0x588985,_0xb895e2(0x19e),_0x2c7b54[_0x14ee90(0x19e)]);_0x5b21c7(_0x588985,_0x3f435d);}_0x4ef05a[_0x14ee90(0x162)](_0x588985[_0x14ee90(0x135)]);}else{if(_0x2c7b54['state']===_0x14ee90(0x188)&&_0x55e9bf-_0x588985['startedAt']>_0x20720c){if(claimDelivery(_0x588985[_0x14ee90(0x135)])){const _0x4ead3a=await deliverAsFailure(_0x588985,_0x14ee90(0x19e),_0x14ee90(0x143)+'\x20subproces'+'s\x20never\x20wr'+'ote\x20its\x20ou'+_0x14ee90(0x19a)+'('+Math[_0x14ee90(0x14e)]((_0x55e9bf-_0x588985['startedAt'])/(-0x8fb*0x23+0x1c648+0x5e69*0x1))+(_0x14ee90(0x18c)+_0xb895e2(0x17b)+'ly\x20crashed'+_0x14ee90(0x189)+'itializing'+_0xb895e2(0x18d)+_0xb895e2(0x165)+_0x14ee90(0x1a9)+_0x14ee90(0x14b)));_0x5b21c7(_0x588985,_0x4ead3a);}_0x4ef05a[_0xb895e2(0x162)](_0x588985[_0x14ee90(0x135)]);}}}}if(_0x4ef05a[_0x14ee90(0x148)]>0xc4b+-0x85*-0xf+0x6*-0x359){for(const _0x510726 of _0x4ef05a)pending[_0xb895e2(0x19c)](_0x510726);saveToDisk();}}async function deliverAsCompleted(_0x186698,_0x5d06b2,_0x3bf5fa){const _0x55bd84=_0x1b3a,_0x5d080f=_0x1b3a,{deliverSubAgentResult:_0x346b19}=await import('./subagent'+'-delivery.'+'js'),_0x494c1d={'id':_0x186698[_0x55bd84(0x135)],'name':_0x186698[_0x5d080f(0x180)+'n'],'status':_0x55bd84(0x15a),'startedAt':_0x186698[_0x55bd84(0x1a6)],'source':_0x5d080f(0x144),'depth':0x0,'parentChatId':_0x186698[_0x5d080f(0x14d)],'platform':_0x186698['platform']},_0x204a1b={'id':_0x186698[_0x55bd84(0x135)],'name':_0x186698['descriptio'+'n'],'status':'completed','output':_0x5d06b2,'tokensUsed':_0x3bf5fa??{'input':0x0,'output':0x0},'duration':Date[_0x5d080f(0x12e)]()-_0x186698[_0x5d080f(0x1a6)]};let _0x55812c=![];try{const _0x44fded=await _0x346b19(_0x494c1d,_0x204a1b);_0x55812c=!!_0x44fded?.[_0x5d080f(0x16e)+'nd'];}catch(_0x131d4b){console[_0x5d080f(0x19e)](_0x5d080f(0x195)+_0x5d080f(0x187)+_0x5d080f(0x12f)+'d\x20for\x20'+_0x186698['agentId']+':',_0x131d4b),_0x55812c=isChatNotFoundError(_0x131d4b);}return decrementPendingCount(_0x186698['sessionKey']),{'chatNotFound':_0x55812c};}async function deliverAsFailure(_0x1d5054,_0x4f921b,_0x46a5c3){const _0x5cc906=_0x1b3a,_0x4431f6=_0x1b3a,{deliverSubAgentResult:_0xa8763b}=await import(_0x5cc906(0x199)+_0x4431f6(0x17a)+'js'),_0x25ae61={'id':_0x1d5054[_0x5cc906(0x135)],'name':_0x1d5054[_0x4431f6(0x180)+'n'],'status':_0x4f921b,'startedAt':_0x1d5054[_0x5cc906(0x1a6)],'source':_0x4431f6(0x144),'depth':0x0,'parentChatId':_0x1d5054[_0x4431f6(0x14d)],'platform':_0x1d5054[_0x5cc906(0x15f)]},_0x249be6={'id':_0x1d5054[_0x4431f6(0x135)],'name':_0x1d5054['descriptio'+'n'],'status':_0x4f921b,'output':'','tokensUsed':{'input':0x0,'output':0x0},'duration':Date[_0x5cc906(0x12e)]()-_0x1d5054[_0x4431f6(0x1a6)],'error':_0x46a5c3};let _0x25fcab=![];try{const _0x3b9a36=await _0xa8763b(_0x25ae61,_0x249be6);_0x25fcab=!!_0x3b9a36?.[_0x5cc906(0x16e)+'nd'];}catch(_0x40ccf7){console[_0x5cc906(0x19e)](_0x4431f6(0x195)+_0x4431f6(0x141)+_0x4431f6(0x17c)+_0x5cc906(0x168)+_0x5cc906(0x177)+_0x1d5054[_0x5cc906(0x135)]+':',_0x40ccf7),_0x25fcab=isChatNotFoundError(_0x40ccf7);}return decrementPendingCount(_0x1d5054['sessionKey']),{'chatNotFound':_0x25fcab};}function resolveKillTarget(_0x5e8356){const _0x1144bf=_0x1b3a,_0x5bbf8c=_0x1b3a;return process[_0x1144bf(0x15f)]!==_0x5bbf8c(0x172)?-_0x5e8356:_0x5e8356;}export function killSessionDetachedAgents(_0x18544d,_0x13d626=_0x28ca53=>{const _0x156cad=_0x1b3a;try{process[_0x156cad(0x175)](_0x28ca53,'SIGTERM');}catch{}}){const _0x3bf407=_0x1b3a,_0x56c9ed=_0x1b3a,_0x2ca230=_0x18544d[_0x3bf407(0x15e)]??null;if(_0x2ca230===null)return;for(const _0x1d2776 of pending['values']()){if(_0x1d2776[_0x3bf407(0x15e)]!==_0x2ca230)continue;if(typeof _0x1d2776['pid']!==_0x56c9ed(0x12d))continue;if(!thisBootAgentIds[_0x3bf407(0x16d)](_0x1d2776['agentId'])){console[_0x56c9ed(0x138)](_0x3bf407(0x195)+'cher]\x20skip'+_0x56c9ed(0x179)+'for\x20disk-l'+_0x56c9ed(0x16c)+'t\x20'+_0x1d2776[_0x3bf407(0x135)]+'\x20'+(_0x56c9ed(0x185)+_0x1d2776['pid']+(_0x3bf407(0x155)+_0x56c9ed(0x128)+_0x3bf407(0x169)+_0x3bf407(0x192)+'start')));continue;}try{_0x13d626(resolveKillTarget(_0x1d2776[_0x56c9ed(0x136)]));}catch{}}}export function cancelPendingForSession(_0xd5afeb){const _0x4c95ea=_0x1b3a,_0x165776=_0x1b3a;let _0x1cb94f=![];for(const [_0x1c35ae,_0x3b79dc]of pending[_0x4c95ea(0x160)]()){_0x3b79dc['sessionKey']===_0xd5afeb&&(markDelivered(_0x3b79dc[_0x4c95ea(0x135)]),pending[_0x4c95ea(0x19c)](_0x1c35ae),_0x1cb94f=!![]);}_0x1cb94f&&saveToDisk();}export function __resetForTest(){const _0x1f0e55=_0x1b3a,_0x335f25=_0x1b3a;pending[_0x1f0e55(0x129)](),thisBootAgentIds[_0x335f25(0x129)]();if(pollTimer)clearInterval(pollTimer);pollTimer=null,started=![];}
|