@poolzin/pool-bot 2026.2.0 → 2026.2.2
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 +118 -0
- package/README-header.png +0 -0
- package/dist/agents/bash-tools.exec.js +76 -25
- package/dist/agents/cli-runner/helpers.js +9 -11
- package/dist/agents/context.js +1 -1
- package/dist/agents/identity.js +47 -7
- package/dist/agents/memory-search.js +25 -8
- package/dist/agents/model-catalog.js +1 -1
- package/dist/agents/model-selection.js +21 -0
- package/dist/agents/pi-embedded-block-chunker.js +117 -42
- package/dist/agents/pi-embedded-helpers/errors.js +183 -78
- package/dist/agents/pi-embedded-helpers.js +1 -1
- package/dist/agents/pi-embedded-runner/compact.js +8 -10
- package/dist/agents/pi-embedded-runner/model.js +62 -3
- package/dist/agents/pi-embedded-runner/run/attempt.js +21 -11
- package/dist/agents/pi-embedded-runner/run.js +199 -46
- package/dist/agents/pi-embedded-runner/system-prompt.js +10 -2
- package/dist/agents/pi-embedded-subscribe.js +118 -29
- package/dist/agents/pi-tools.js +10 -5
- package/dist/agents/poolbot-tools.js +15 -10
- package/dist/agents/sandbox-paths.js +31 -0
- package/dist/agents/session-tool-result-guard.js +94 -15
- package/dist/agents/shell-utils.js +51 -0
- package/dist/agents/skills/bundled-context.js +23 -0
- package/dist/agents/skills/bundled-dir.js +41 -7
- package/dist/agents/skills-install.js +60 -23
- package/dist/agents/subagent-announce.js +79 -34
- package/dist/agents/tool-policy.conformance.js +14 -0
- package/dist/agents/tool-policy.js +24 -0
- package/dist/agents/tools/cron-tool.js +166 -19
- package/dist/agents/tools/discord-actions-presence.js +78 -0
- package/dist/agents/tools/image-tool.js +1 -1
- package/dist/agents/tools/message-tool.js +56 -2
- package/dist/agents/tools/sessions-history-tool.js +69 -1
- package/dist/agents/tools/web-search.js +211 -42
- package/dist/agents/usage.js +23 -1
- package/dist/agents/workspace-run.js +67 -0
- package/dist/agents/workspace-templates.js +44 -0
- package/dist/auto-reply/command-auth.js +121 -6
- package/dist/auto-reply/envelope.js +74 -82
- package/dist/auto-reply/reply/commands-compact.js +1 -0
- package/dist/auto-reply/reply/commands-context-report.js +1 -0
- package/dist/auto-reply/reply/commands-context.js +1 -0
- package/dist/auto-reply/reply/commands-models.js +107 -60
- package/dist/auto-reply/reply/commands-ptt.js +171 -0
- package/dist/auto-reply/reply/get-reply-run.js +2 -1
- package/dist/auto-reply/reply/inbound-context.js +5 -1
- package/dist/auto-reply/reply/mentions.js +1 -1
- package/dist/auto-reply/reply/model-selection.js +3 -3
- package/dist/auto-reply/thinking.js +88 -43
- package/dist/browser/bridge-server.js +13 -0
- package/dist/browser/cdp.helpers.js +38 -24
- package/dist/browser/client-fetch.js +50 -7
- package/dist/browser/config.js +1 -10
- package/dist/browser/extension-relay.js +101 -40
- package/dist/browser/pw-ai.js +1 -1
- package/dist/browser/pw-session.js +143 -8
- package/dist/browser/pw-tools-core.interactions.js +125 -27
- package/dist/browser/pw-tools-core.responses.js +1 -1
- package/dist/browser/pw-tools-core.state.js +1 -1
- package/dist/browser/routes/agent.act.js +86 -41
- package/dist/browser/routes/dispatcher.js +4 -4
- package/dist/browser/screenshot.js +1 -1
- package/dist/browser/server.js +13 -0
- package/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/index.html +28 -28
- package/dist/channels/reply-prefix.js +8 -1
- package/dist/cli/cron-cli/register.cron-add.js +61 -40
- package/dist/cli/cron-cli/register.cron-edit.js +60 -34
- package/dist/cli/cron-cli/shared.js +56 -41
- package/dist/cli/dns-cli.js +26 -14
- package/dist/cli/gateway-cli/register.js +37 -19
- package/dist/cli/memory-cli.js +5 -5
- package/dist/cli/parse-bytes.js +37 -0
- package/dist/cli/update-cli.js +173 -52
- package/dist/commands/agent.js +1 -0
- package/dist/commands/auth-choice.apply.oauth.js +1 -1
- package/dist/commands/doctor-config-flow.js +61 -5
- package/dist/commands/doctor-state-migrations.js +1 -1
- package/dist/commands/health.js +1 -1
- package/dist/commands/model-allowlist.js +29 -0
- package/dist/commands/model-picker.js +2 -1
- package/dist/commands/models/list.registry.js +1 -1
- package/dist/commands/models/list.status-command.js +43 -23
- package/dist/commands/models/shared.js +15 -0
- package/dist/commands/onboard-custom.js +384 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice-inference.js +35 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +6 -3
- package/dist/commands/onboard-skills.js +63 -38
- package/dist/commands/openai-model-default.js +41 -0
- package/dist/compat/legacy-names.js +2 -0
- package/dist/config/defaults.js +3 -2
- package/dist/config/paths.js +136 -35
- package/dist/config/plugin-auto-enable.js +21 -5
- package/dist/config/redact-snapshot.js +153 -0
- package/dist/config/schema.field-metadata.js +590 -0
- package/dist/config/schema.js +2 -2
- package/dist/config/sessions/store.js +291 -23
- package/dist/config/zod-schema.agent-defaults.js +3 -0
- package/dist/config/zod-schema.agent-runtime.js +13 -2
- package/dist/config/zod-schema.providers-core.js +142 -0
- package/dist/config/zod-schema.session.js +3 -0
- package/dist/control-ui/assets/{index-CIRDm-Lu.css → index-CSfXd2LO.css} +1 -1
- package/dist/control-ui/assets/{index-CmNMuoem.js → index-HRr1grwl.js} +446 -413
- package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -0
- package/dist/control-ui/index.html +4 -4
- package/dist/cron/delivery.js +57 -0
- package/dist/cron/isolated-agent/delivery-target.js +18 -3
- package/dist/cron/isolated-agent/helpers.js +22 -5
- package/dist/cron/isolated-agent/run.js +172 -63
- package/dist/cron/isolated-agent/session.js +2 -0
- package/dist/cron/normalize.js +356 -28
- package/dist/cron/parse.js +10 -5
- package/dist/cron/run-log.js +35 -10
- package/dist/cron/schedule.js +41 -6
- package/dist/cron/service/jobs.js +208 -35
- package/dist/cron/service/ops.js +72 -16
- package/dist/cron/service/state.js +2 -0
- package/dist/cron/service/store.js +386 -14
- package/dist/cron/service/timer.js +390 -147
- package/dist/cron/session-reaper.js +86 -0
- package/dist/cron/store.js +23 -8
- package/dist/cron/validate-timestamp.js +43 -0
- package/dist/discord/monitor/agent-components.js +438 -0
- package/dist/discord/monitor/allow-list.js +28 -5
- package/dist/discord/monitor/gateway-registry.js +29 -0
- package/dist/discord/monitor/native-command.js +44 -23
- package/dist/discord/monitor/sender-identity.js +45 -0
- package/dist/discord/pluralkit.js +27 -0
- package/dist/discord/send.outbound.js +92 -5
- package/dist/discord/send.shared.js +60 -23
- package/dist/discord/targets.js +84 -1
- package/dist/entry.js +15 -9
- package/dist/extensionAPI.js +8 -0
- package/dist/gateway/control-ui.js +8 -1
- package/dist/gateway/hooks-mapping.js +3 -0
- package/dist/gateway/hooks.js +65 -0
- package/dist/gateway/net.js +96 -31
- package/dist/gateway/node-command-policy.js +50 -15
- package/dist/gateway/origin-check.js +56 -0
- package/dist/gateway/protocol/client-info.js +9 -0
- package/dist/gateway/protocol/index.js +9 -2
- package/dist/gateway/protocol/schema/agents-models-skills.js +71 -1
- package/dist/gateway/protocol/schema/cron.js +22 -10
- package/dist/gateway/protocol/schema/protocol-schemas.js +16 -2
- package/dist/gateway/protocol/schema/sessions.js +12 -0
- package/dist/gateway/server/hooks.js +1 -1
- package/dist/gateway/server-broadcast.js +26 -9
- package/dist/gateway/server-chat.js +112 -23
- package/dist/gateway/server-discovery-runtime.js +10 -2
- package/dist/gateway/server-http.js +109 -11
- package/dist/gateway/server-methods/agent-timestamp.js +60 -0
- package/dist/gateway/server-methods/agents.js +321 -2
- package/dist/gateway/server-methods/usage.js +559 -16
- package/dist/gateway/server-runtime-state.js +22 -8
- package/dist/gateway/server-startup-memory.js +16 -0
- package/dist/gateway/server.impl.js +5 -1
- package/dist/gateway/session-utils.fs.js +23 -25
- package/dist/gateway/session-utils.js +20 -10
- package/dist/gateway/sessions-patch.js +7 -22
- package/dist/gateway/test-helpers.mocks.js +11 -7
- package/dist/gateway/test-helpers.server.js +35 -2
- package/dist/imessage/constants.js +2 -0
- package/dist/imessage/monitor/deliver.js +4 -1
- package/dist/imessage/monitor/monitor-provider.js +51 -1
- package/dist/infra/bonjour-discovery.js +131 -70
- package/dist/infra/control-ui-assets.js +134 -12
- package/dist/infra/errors.js +12 -0
- package/dist/infra/exec-approvals.js +266 -57
- package/dist/infra/format-time/format-datetime.js +79 -0
- package/dist/infra/format-time/format-duration.js +81 -0
- package/dist/infra/format-time/format-relative.js +80 -0
- package/dist/infra/heartbeat-runner.js +140 -49
- package/dist/infra/home-dir.js +54 -0
- package/dist/infra/net/fetch-guard.js +122 -0
- package/dist/infra/net/ssrf.js +65 -29
- package/dist/infra/outbound/abort.js +14 -0
- package/dist/infra/outbound/message-action-runner.js +77 -13
- package/dist/infra/outbound/outbound-session.js +143 -37
- package/dist/infra/poolbot-root.js +43 -1
- package/dist/infra/session-cost-usage.js +631 -41
- package/dist/infra/state-migrations.js +317 -47
- package/dist/infra/update-global.js +35 -0
- package/dist/infra/update-runner.js +149 -43
- package/dist/infra/warning-filter.js +65 -0
- package/dist/infra/widearea-dns.js +30 -9
- package/dist/logging/redact-identifier.js +12 -0
- package/dist/media/fetch.js +81 -58
- package/dist/media/store.js +2 -0
- package/dist/media-understanding/apply.js +403 -3
- package/dist/media-understanding/attachments.js +38 -27
- package/dist/media-understanding/defaults.js +16 -0
- package/dist/media-understanding/providers/deepgram/audio.js +22 -14
- package/dist/media-understanding/providers/google/audio.js +24 -17
- package/dist/media-understanding/providers/google/video.js +24 -17
- package/dist/media-understanding/providers/image.js +3 -3
- package/dist/media-understanding/providers/index.js +4 -1
- package/dist/media-understanding/providers/openai/audio.js +22 -14
- package/dist/media-understanding/providers/shared.js +16 -11
- package/dist/media-understanding/providers/zai/index.js +6 -0
- package/dist/media-understanding/runner.js +158 -90
- package/dist/memory/batch-voyage.js +277 -0
- package/dist/memory/embeddings-voyage.js +75 -0
- package/dist/memory/embeddings.js +28 -16
- package/dist/memory/internal.js +101 -18
- package/dist/memory/manager.js +154 -48
- package/dist/memory/search-manager.js +173 -0
- package/dist/memory/session-files.js +9 -3
- package/dist/node-host/runner.js +34 -24
- package/dist/node-host/with-timeout.js +27 -0
- package/dist/plugins/commands.js +5 -1
- package/dist/plugins/config-state.js +86 -7
- package/dist/plugins/source-display.js +51 -0
- package/dist/process/exec.js +20 -2
- package/dist/routing/resolve-route.js +12 -0
- package/dist/routing/session-key.js +15 -0
- package/dist/runtime.js +2 -0
- package/dist/security/audit-extra.async.js +601 -0
- package/dist/security/audit-extra.js +2 -830
- package/dist/security/audit-extra.sync.js +505 -0
- package/dist/security/channel-metadata.js +34 -0
- package/dist/security/external-content.js +88 -6
- package/dist/security/skill-scanner.js +330 -0
- package/dist/sessions/session-key-utils.js +7 -0
- package/dist/signal/monitor/event-handler.js +80 -1
- package/dist/slack/monitor/media.js +85 -15
- package/dist/tailscale/detect.js +1 -2
- package/dist/telegram/bot/helpers.js +109 -28
- package/dist/telegram/bot-handlers.js +144 -3
- package/dist/telegram/bot-message-context.js +37 -10
- package/dist/telegram/bot-message-dispatch.js +54 -17
- package/dist/telegram/bot-native-commands.js +86 -29
- package/dist/telegram/bot.js +30 -29
- package/dist/telegram/model-buttons.js +163 -0
- package/dist/telegram/monitor.js +110 -85
- package/dist/telegram/send.js +129 -47
- package/dist/terminal/restore.js +45 -0
- package/dist/test-helpers/state-dir-env.js +16 -0
- package/dist/tts/tts.js +12 -6
- package/dist/tui/tui-session-actions.js +166 -54
- package/dist/utils/fetch-timeout.js +20 -0
- package/dist/utils/normalize-secret-input.js +19 -0
- package/dist/utils/transcript-tools.js +58 -0
- package/dist/utils.js +45 -14
- package/dist/version.js +42 -5
- package/dist/wizard/clack-prompter.js +9 -6
- package/extensions/googlechat/node_modules/.bin/poolbot +21 -0
- package/extensions/googlechat/package.json +2 -2
- package/extensions/line/node_modules/.bin/poolbot +21 -0
- package/extensions/line/package.json +1 -1
- package/extensions/matrix/node_modules/.bin/poolbot +21 -0
- package/extensions/matrix/package.json +1 -1
- package/extensions/memory-core/node_modules/.bin/poolbot +21 -0
- package/extensions/memory-core/package.json +4 -1
- package/extensions/twitch/node_modules/.bin/poolbot +21 -0
- package/extensions/twitch/package.json +1 -1
- package/package.json +183 -24
- package/dist/control-ui/assets/index-CmNMuoem.js.map +0 -1
|
@@ -1,19 +1,245 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { parseAbsoluteTimeMs } from "../parse.js";
|
|
1
3
|
import { migrateLegacyCronPayload } from "../payload-migration.js";
|
|
2
4
|
import { loadCronStore, saveCronStore } from "../store.js";
|
|
5
|
+
import { recomputeNextRuns } from "./jobs.js";
|
|
3
6
|
import { inferLegacyName, normalizeOptionalText } from "./normalize.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
function hasLegacyDeliveryHints(payload) {
|
|
8
|
+
if (typeof payload.deliver === "boolean") {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
if (typeof payload.bestEffortDeliver === "boolean") {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
if (typeof payload.to === "string" && payload.to.trim()) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
function buildDeliveryFromLegacyPayload(payload) {
|
|
20
|
+
const deliver = payload.deliver;
|
|
21
|
+
const mode = deliver === false ? "none" : "announce";
|
|
22
|
+
const channelRaw = typeof payload.channel === "string" ? payload.channel.trim().toLowerCase() : "";
|
|
23
|
+
const toRaw = typeof payload.to === "string" ? payload.to.trim() : "";
|
|
24
|
+
const next = { mode };
|
|
25
|
+
if (channelRaw) {
|
|
26
|
+
next.channel = channelRaw;
|
|
27
|
+
}
|
|
28
|
+
if (toRaw) {
|
|
29
|
+
next.to = toRaw;
|
|
30
|
+
}
|
|
31
|
+
if (typeof payload.bestEffortDeliver === "boolean") {
|
|
32
|
+
next.bestEffort = payload.bestEffortDeliver;
|
|
33
|
+
}
|
|
34
|
+
return next;
|
|
35
|
+
}
|
|
36
|
+
function buildDeliveryPatchFromLegacyPayload(payload) {
|
|
37
|
+
const deliver = payload.deliver;
|
|
38
|
+
const channelRaw = typeof payload.channel === "string" ? payload.channel.trim().toLowerCase() : "";
|
|
39
|
+
const toRaw = typeof payload.to === "string" ? payload.to.trim() : "";
|
|
40
|
+
const next = {};
|
|
41
|
+
let hasPatch = false;
|
|
42
|
+
if (deliver === false) {
|
|
43
|
+
next.mode = "none";
|
|
44
|
+
hasPatch = true;
|
|
45
|
+
}
|
|
46
|
+
else if (deliver === true || toRaw) {
|
|
47
|
+
next.mode = "announce";
|
|
48
|
+
hasPatch = true;
|
|
49
|
+
}
|
|
50
|
+
if (channelRaw) {
|
|
51
|
+
next.channel = channelRaw;
|
|
52
|
+
hasPatch = true;
|
|
53
|
+
}
|
|
54
|
+
if (toRaw) {
|
|
55
|
+
next.to = toRaw;
|
|
56
|
+
hasPatch = true;
|
|
57
|
+
}
|
|
58
|
+
if (typeof payload.bestEffortDeliver === "boolean") {
|
|
59
|
+
next.bestEffort = payload.bestEffortDeliver;
|
|
60
|
+
hasPatch = true;
|
|
61
|
+
}
|
|
62
|
+
return hasPatch ? next : null;
|
|
63
|
+
}
|
|
64
|
+
function mergeLegacyDeliveryInto(delivery, payload) {
|
|
65
|
+
const patch = buildDeliveryPatchFromLegacyPayload(payload);
|
|
66
|
+
if (!patch) {
|
|
67
|
+
return { delivery, mutated: false };
|
|
68
|
+
}
|
|
69
|
+
const next = { ...delivery };
|
|
70
|
+
let mutated = false;
|
|
71
|
+
if ("mode" in patch && patch.mode !== next.mode) {
|
|
72
|
+
next.mode = patch.mode;
|
|
73
|
+
mutated = true;
|
|
74
|
+
}
|
|
75
|
+
if ("channel" in patch && patch.channel !== next.channel) {
|
|
76
|
+
next.channel = patch.channel;
|
|
77
|
+
mutated = true;
|
|
78
|
+
}
|
|
79
|
+
if ("to" in patch && patch.to !== next.to) {
|
|
80
|
+
next.to = patch.to;
|
|
81
|
+
mutated = true;
|
|
82
|
+
}
|
|
83
|
+
if ("bestEffort" in patch && patch.bestEffort !== next.bestEffort) {
|
|
84
|
+
next.bestEffort = patch.bestEffort;
|
|
85
|
+
mutated = true;
|
|
86
|
+
}
|
|
87
|
+
return { delivery: next, mutated };
|
|
88
|
+
}
|
|
89
|
+
function stripLegacyDeliveryFields(payload) {
|
|
90
|
+
if ("deliver" in payload) {
|
|
91
|
+
delete payload.deliver;
|
|
92
|
+
}
|
|
93
|
+
if ("channel" in payload) {
|
|
94
|
+
delete payload.channel;
|
|
95
|
+
}
|
|
96
|
+
if ("to" in payload) {
|
|
97
|
+
delete payload.to;
|
|
98
|
+
}
|
|
99
|
+
if ("bestEffortDeliver" in payload) {
|
|
100
|
+
delete payload.bestEffortDeliver;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function normalizePayloadKind(payload) {
|
|
104
|
+
const raw = typeof payload.kind === "string" ? payload.kind.trim().toLowerCase() : "";
|
|
105
|
+
if (raw === "agentturn") {
|
|
106
|
+
payload.kind = "agentTurn";
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
if (raw === "systemevent") {
|
|
110
|
+
payload.kind = "systemEvent";
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
function inferPayloadIfMissing(raw) {
|
|
116
|
+
const message = typeof raw.message === "string" ? raw.message.trim() : "";
|
|
117
|
+
const text = typeof raw.text === "string" ? raw.text.trim() : "";
|
|
118
|
+
if (message) {
|
|
119
|
+
raw.payload = { kind: "agentTurn", message };
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
if (text) {
|
|
123
|
+
raw.payload = { kind: "systemEvent", text };
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
function copyTopLevelAgentTurnFields(raw, payload) {
|
|
129
|
+
let mutated = false;
|
|
130
|
+
const copyTrimmedString = (field) => {
|
|
131
|
+
const existing = payload[field];
|
|
132
|
+
if (typeof existing === "string" && existing.trim()) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const value = raw[field];
|
|
136
|
+
if (typeof value === "string" && value.trim()) {
|
|
137
|
+
payload[field] = value.trim();
|
|
138
|
+
mutated = true;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
copyTrimmedString("model");
|
|
142
|
+
copyTrimmedString("thinking");
|
|
143
|
+
if (typeof payload.timeoutSeconds !== "number" &&
|
|
144
|
+
typeof raw.timeoutSeconds === "number" &&
|
|
145
|
+
Number.isFinite(raw.timeoutSeconds)) {
|
|
146
|
+
payload.timeoutSeconds = Math.max(1, Math.floor(raw.timeoutSeconds));
|
|
147
|
+
mutated = true;
|
|
148
|
+
}
|
|
149
|
+
if (typeof payload.allowUnsafeExternalContent !== "boolean" &&
|
|
150
|
+
typeof raw.allowUnsafeExternalContent === "boolean") {
|
|
151
|
+
payload.allowUnsafeExternalContent = raw.allowUnsafeExternalContent;
|
|
152
|
+
mutated = true;
|
|
153
|
+
}
|
|
154
|
+
if (typeof payload.deliver !== "boolean" && typeof raw.deliver === "boolean") {
|
|
155
|
+
payload.deliver = raw.deliver;
|
|
156
|
+
mutated = true;
|
|
157
|
+
}
|
|
158
|
+
if (typeof payload.channel !== "string" &&
|
|
159
|
+
typeof raw.channel === "string" &&
|
|
160
|
+
raw.channel.trim()) {
|
|
161
|
+
payload.channel = raw.channel.trim();
|
|
162
|
+
mutated = true;
|
|
163
|
+
}
|
|
164
|
+
if (typeof payload.to !== "string" && typeof raw.to === "string" && raw.to.trim()) {
|
|
165
|
+
payload.to = raw.to.trim();
|
|
166
|
+
mutated = true;
|
|
167
|
+
}
|
|
168
|
+
if (typeof payload.bestEffortDeliver !== "boolean" &&
|
|
169
|
+
typeof raw.bestEffortDeliver === "boolean") {
|
|
170
|
+
payload.bestEffortDeliver = raw.bestEffortDeliver;
|
|
171
|
+
mutated = true;
|
|
172
|
+
}
|
|
173
|
+
if (typeof payload.provider !== "string" &&
|
|
174
|
+
typeof raw.provider === "string" &&
|
|
175
|
+
raw.provider.trim()) {
|
|
176
|
+
payload.provider = raw.provider.trim();
|
|
177
|
+
mutated = true;
|
|
178
|
+
}
|
|
179
|
+
return mutated;
|
|
180
|
+
}
|
|
181
|
+
function stripLegacyTopLevelFields(raw) {
|
|
182
|
+
if ("model" in raw) {
|
|
183
|
+
delete raw.model;
|
|
184
|
+
}
|
|
185
|
+
if ("thinking" in raw) {
|
|
186
|
+
delete raw.thinking;
|
|
187
|
+
}
|
|
188
|
+
if ("timeoutSeconds" in raw) {
|
|
189
|
+
delete raw.timeoutSeconds;
|
|
190
|
+
}
|
|
191
|
+
if ("allowUnsafeExternalContent" in raw) {
|
|
192
|
+
delete raw.allowUnsafeExternalContent;
|
|
193
|
+
}
|
|
194
|
+
if ("message" in raw) {
|
|
195
|
+
delete raw.message;
|
|
196
|
+
}
|
|
197
|
+
if ("text" in raw) {
|
|
198
|
+
delete raw.text;
|
|
199
|
+
}
|
|
200
|
+
if ("deliver" in raw) {
|
|
201
|
+
delete raw.deliver;
|
|
202
|
+
}
|
|
203
|
+
if ("channel" in raw) {
|
|
204
|
+
delete raw.channel;
|
|
205
|
+
}
|
|
206
|
+
if ("to" in raw) {
|
|
207
|
+
delete raw.to;
|
|
208
|
+
}
|
|
209
|
+
if ("bestEffortDeliver" in raw) {
|
|
210
|
+
delete raw.bestEffortDeliver;
|
|
211
|
+
}
|
|
212
|
+
if ("provider" in raw) {
|
|
213
|
+
delete raw.provider;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async function getFileMtimeMs(path) {
|
|
217
|
+
try {
|
|
218
|
+
const stats = await fs.promises.stat(path);
|
|
219
|
+
return stats.mtimeMs;
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
export async function ensureLoaded(state, opts) {
|
|
226
|
+
// Fast path: store is already in memory. Other callers (add, list, run, …)
|
|
227
|
+
// trust the in-memory copy to avoid a stat syscall on every operation.
|
|
228
|
+
if (state.store && !opts?.forceReload) {
|
|
11
229
|
return;
|
|
12
230
|
}
|
|
231
|
+
// Force reload always re-reads the file to avoid missing cross-service
|
|
232
|
+
// edits on filesystems with coarse mtime resolution.
|
|
233
|
+
const fileMtimeMs = await getFileMtimeMs(state.deps.storePath);
|
|
13
234
|
const loaded = await loadCronStore(state.deps.storePath);
|
|
14
235
|
const jobs = (loaded.jobs ?? []);
|
|
15
236
|
let mutated = false;
|
|
16
237
|
for (const raw of jobs) {
|
|
238
|
+
const state = raw.state;
|
|
239
|
+
if (!state || typeof state !== "object" || Array.isArray(state)) {
|
|
240
|
+
raw.state = {};
|
|
241
|
+
mutated = true;
|
|
242
|
+
}
|
|
17
243
|
const nameRaw = raw.name;
|
|
18
244
|
if (typeof nameRaw !== "string" || nameRaw.trim().length === 0) {
|
|
19
245
|
raw.name = inferLegacyName({
|
|
@@ -30,28 +256,174 @@ export async function ensureLoaded(state) {
|
|
|
30
256
|
raw.description = desc;
|
|
31
257
|
mutated = true;
|
|
32
258
|
}
|
|
259
|
+
if (typeof raw.enabled !== "boolean") {
|
|
260
|
+
raw.enabled = true;
|
|
261
|
+
mutated = true;
|
|
262
|
+
}
|
|
33
263
|
const payload = raw.payload;
|
|
34
|
-
if (payload
|
|
35
|
-
|
|
264
|
+
if ((!payload || typeof payload !== "object" || Array.isArray(payload)) &&
|
|
265
|
+
inferPayloadIfMissing(raw)) {
|
|
266
|
+
mutated = true;
|
|
267
|
+
}
|
|
268
|
+
const payloadRecord = raw.payload && typeof raw.payload === "object" && !Array.isArray(raw.payload)
|
|
269
|
+
? raw.payload
|
|
270
|
+
: null;
|
|
271
|
+
if (payloadRecord) {
|
|
272
|
+
if (normalizePayloadKind(payloadRecord)) {
|
|
273
|
+
mutated = true;
|
|
274
|
+
}
|
|
275
|
+
if (!payloadRecord.kind) {
|
|
276
|
+
if (typeof payloadRecord.message === "string" && payloadRecord.message.trim()) {
|
|
277
|
+
payloadRecord.kind = "agentTurn";
|
|
278
|
+
mutated = true;
|
|
279
|
+
}
|
|
280
|
+
else if (typeof payloadRecord.text === "string" && payloadRecord.text.trim()) {
|
|
281
|
+
payloadRecord.kind = "systemEvent";
|
|
282
|
+
mutated = true;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (payloadRecord.kind === "agentTurn") {
|
|
286
|
+
if (copyTopLevelAgentTurnFields(raw, payloadRecord)) {
|
|
287
|
+
mutated = true;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
const hadLegacyTopLevelFields = "model" in raw ||
|
|
292
|
+
"thinking" in raw ||
|
|
293
|
+
"timeoutSeconds" in raw ||
|
|
294
|
+
"allowUnsafeExternalContent" in raw ||
|
|
295
|
+
"message" in raw ||
|
|
296
|
+
"text" in raw ||
|
|
297
|
+
"deliver" in raw ||
|
|
298
|
+
"channel" in raw ||
|
|
299
|
+
"to" in raw ||
|
|
300
|
+
"bestEffortDeliver" in raw ||
|
|
301
|
+
"provider" in raw;
|
|
302
|
+
if (hadLegacyTopLevelFields) {
|
|
303
|
+
stripLegacyTopLevelFields(raw);
|
|
304
|
+
mutated = true;
|
|
305
|
+
}
|
|
306
|
+
if (payloadRecord) {
|
|
307
|
+
if (migrateLegacyCronPayload(payloadRecord)) {
|
|
308
|
+
mutated = true;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
const schedule = raw.schedule;
|
|
312
|
+
if (schedule && typeof schedule === "object" && !Array.isArray(schedule)) {
|
|
313
|
+
const sched = schedule;
|
|
314
|
+
const kind = typeof sched.kind === "string" ? sched.kind.trim().toLowerCase() : "";
|
|
315
|
+
if (!kind && ("at" in sched || "atMs" in sched)) {
|
|
316
|
+
sched.kind = "at";
|
|
317
|
+
mutated = true;
|
|
318
|
+
}
|
|
319
|
+
const atRaw = typeof sched.at === "string" ? sched.at.trim() : "";
|
|
320
|
+
const atMsRaw = sched.atMs;
|
|
321
|
+
const parsedAtMs = typeof atMsRaw === "number"
|
|
322
|
+
? atMsRaw
|
|
323
|
+
: typeof atMsRaw === "string"
|
|
324
|
+
? parseAbsoluteTimeMs(atMsRaw)
|
|
325
|
+
: atRaw
|
|
326
|
+
? parseAbsoluteTimeMs(atRaw)
|
|
327
|
+
: null;
|
|
328
|
+
if (parsedAtMs !== null) {
|
|
329
|
+
sched.at = new Date(parsedAtMs).toISOString();
|
|
330
|
+
if ("atMs" in sched) {
|
|
331
|
+
delete sched.atMs;
|
|
332
|
+
}
|
|
333
|
+
mutated = true;
|
|
334
|
+
}
|
|
335
|
+
const everyMsRaw = sched.everyMs;
|
|
336
|
+
const everyMs = typeof everyMsRaw === "number" && Number.isFinite(everyMsRaw)
|
|
337
|
+
? Math.floor(everyMsRaw)
|
|
338
|
+
: null;
|
|
339
|
+
if ((kind === "every" || sched.kind === "every") && everyMs !== null) {
|
|
340
|
+
const anchorRaw = sched.anchorMs;
|
|
341
|
+
const normalizedAnchor = typeof anchorRaw === "number" && Number.isFinite(anchorRaw)
|
|
342
|
+
? Math.max(0, Math.floor(anchorRaw))
|
|
343
|
+
: typeof raw.createdAtMs === "number" && Number.isFinite(raw.createdAtMs)
|
|
344
|
+
? Math.max(0, Math.floor(raw.createdAtMs))
|
|
345
|
+
: typeof raw.updatedAtMs === "number" && Number.isFinite(raw.updatedAtMs)
|
|
346
|
+
? Math.max(0, Math.floor(raw.updatedAtMs))
|
|
347
|
+
: null;
|
|
348
|
+
if (normalizedAnchor !== null && anchorRaw !== normalizedAnchor) {
|
|
349
|
+
sched.anchorMs = normalizedAnchor;
|
|
350
|
+
mutated = true;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
const delivery = raw.delivery;
|
|
355
|
+
if (delivery && typeof delivery === "object" && !Array.isArray(delivery)) {
|
|
356
|
+
const modeRaw = delivery.mode;
|
|
357
|
+
if (typeof modeRaw === "string") {
|
|
358
|
+
const lowered = modeRaw.trim().toLowerCase();
|
|
359
|
+
if (lowered === "deliver") {
|
|
360
|
+
delivery.mode = "announce";
|
|
361
|
+
mutated = true;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
else if (modeRaw === undefined || modeRaw === null) {
|
|
365
|
+
// Explicitly persist the default so existing jobs don't silently
|
|
366
|
+
// change behaviour when the runtime default shifts.
|
|
367
|
+
delivery.mode = "announce";
|
|
368
|
+
mutated = true;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
const isolation = raw.isolation;
|
|
372
|
+
if (isolation && typeof isolation === "object" && !Array.isArray(isolation)) {
|
|
373
|
+
delete raw.isolation;
|
|
374
|
+
mutated = true;
|
|
375
|
+
}
|
|
376
|
+
const payloadKind = payloadRecord && typeof payloadRecord.kind === "string" ? payloadRecord.kind : "";
|
|
377
|
+
const sessionTarget = typeof raw.sessionTarget === "string" ? raw.sessionTarget.trim().toLowerCase() : "";
|
|
378
|
+
const isIsolatedAgentTurn = sessionTarget === "isolated" || (sessionTarget === "" && payloadKind === "agentTurn");
|
|
379
|
+
const hasDelivery = delivery && typeof delivery === "object" && !Array.isArray(delivery);
|
|
380
|
+
const hasLegacyDelivery = payloadRecord ? hasLegacyDeliveryHints(payloadRecord) : false;
|
|
381
|
+
if (isIsolatedAgentTurn && payloadKind === "agentTurn") {
|
|
382
|
+
if (!hasDelivery) {
|
|
383
|
+
raw.delivery =
|
|
384
|
+
payloadRecord && hasLegacyDelivery
|
|
385
|
+
? buildDeliveryFromLegacyPayload(payloadRecord)
|
|
386
|
+
: { mode: "announce" };
|
|
387
|
+
mutated = true;
|
|
388
|
+
}
|
|
389
|
+
if (payloadRecord && hasLegacyDelivery) {
|
|
390
|
+
if (hasDelivery) {
|
|
391
|
+
const merged = mergeLegacyDeliveryInto(delivery, payloadRecord);
|
|
392
|
+
if (merged.mutated) {
|
|
393
|
+
raw.delivery = merged.delivery;
|
|
394
|
+
mutated = true;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
stripLegacyDeliveryFields(payloadRecord);
|
|
36
398
|
mutated = true;
|
|
37
399
|
}
|
|
38
400
|
}
|
|
39
401
|
}
|
|
40
402
|
state.store = { version: 1, jobs: jobs };
|
|
41
|
-
|
|
42
|
-
|
|
403
|
+
state.storeLoadedAtMs = state.deps.nowMs();
|
|
404
|
+
state.storeFileMtimeMs = fileMtimeMs;
|
|
405
|
+
if (!opts?.skipRecompute) {
|
|
406
|
+
recomputeNextRuns(state);
|
|
407
|
+
}
|
|
408
|
+
if (mutated) {
|
|
43
409
|
await persist(state);
|
|
410
|
+
}
|
|
44
411
|
}
|
|
45
412
|
export function warnIfDisabled(state, action) {
|
|
46
|
-
if (state.deps.cronEnabled)
|
|
413
|
+
if (state.deps.cronEnabled) {
|
|
47
414
|
return;
|
|
48
|
-
|
|
415
|
+
}
|
|
416
|
+
if (state.warnedDisabled) {
|
|
49
417
|
return;
|
|
418
|
+
}
|
|
50
419
|
state.warnedDisabled = true;
|
|
51
420
|
state.deps.log.warn({ enabled: false, action, storePath: state.deps.storePath }, "cron: scheduler disabled; jobs will not run automatically");
|
|
52
421
|
}
|
|
53
422
|
export async function persist(state) {
|
|
54
|
-
if (!state.store)
|
|
423
|
+
if (!state.store) {
|
|
55
424
|
return;
|
|
425
|
+
}
|
|
56
426
|
await saveCronStore(state.deps.storePath, state.store);
|
|
427
|
+
// Update file mtime after save to prevent immediate reload
|
|
428
|
+
state.storeFileMtimeMs = await getFileMtimeMs(state.deps.storePath);
|
|
57
429
|
}
|