@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
package/dist/cron/normalize.js
CHANGED
|
@@ -1,55 +1,298 @@
|
|
|
1
1
|
import { sanitizeAgentId } from "../routing/session-key.js";
|
|
2
|
+
import { isRecord } from "../utils.js";
|
|
2
3
|
import { parseAbsoluteTimeMs } from "./parse.js";
|
|
3
4
|
import { migrateLegacyCronPayload } from "./payload-migration.js";
|
|
5
|
+
import { inferLegacyName } from "./service/normalize.js";
|
|
4
6
|
const DEFAULT_OPTIONS = {
|
|
5
7
|
applyDefaults: false,
|
|
6
8
|
};
|
|
7
|
-
function isRecord(value) {
|
|
8
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9
|
-
}
|
|
10
9
|
function coerceSchedule(schedule) {
|
|
11
10
|
const next = { ...schedule };
|
|
12
|
-
const
|
|
11
|
+
const rawKind = typeof schedule.kind === "string" ? schedule.kind.trim().toLowerCase() : "";
|
|
12
|
+
const kind = rawKind === "at" || rawKind === "every" || rawKind === "cron" ? rawKind : undefined;
|
|
13
13
|
const atMsRaw = schedule.atMs;
|
|
14
14
|
const atRaw = schedule.at;
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
const atString = typeof atRaw === "string" ? atRaw.trim() : "";
|
|
16
|
+
const parsedAtMs = typeof atMsRaw === "number"
|
|
17
|
+
? atMsRaw
|
|
18
|
+
: typeof atMsRaw === "string"
|
|
19
|
+
? parseAbsoluteTimeMs(atMsRaw)
|
|
20
|
+
: atString
|
|
21
|
+
? parseAbsoluteTimeMs(atString)
|
|
22
|
+
: null;
|
|
23
|
+
if (kind) {
|
|
24
|
+
next.kind = kind;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
21
27
|
if (typeof schedule.atMs === "number" ||
|
|
22
28
|
typeof schedule.at === "string" ||
|
|
23
|
-
typeof schedule.atMs === "string")
|
|
29
|
+
typeof schedule.atMs === "string") {
|
|
24
30
|
next.kind = "at";
|
|
25
|
-
|
|
31
|
+
}
|
|
32
|
+
else if (typeof schedule.everyMs === "number") {
|
|
26
33
|
next.kind = "every";
|
|
27
|
-
|
|
34
|
+
}
|
|
35
|
+
else if (typeof schedule.expr === "string") {
|
|
28
36
|
next.kind = "cron";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (atString) {
|
|
40
|
+
next.at = parsedAtMs !== null ? new Date(parsedAtMs).toISOString() : atString;
|
|
29
41
|
}
|
|
30
|
-
if (
|
|
31
|
-
next.
|
|
42
|
+
else if (parsedAtMs !== null) {
|
|
43
|
+
next.at = new Date(parsedAtMs).toISOString();
|
|
44
|
+
}
|
|
45
|
+
if ("atMs" in next) {
|
|
46
|
+
delete next.atMs;
|
|
32
47
|
}
|
|
33
|
-
if ("at" in next)
|
|
34
|
-
delete next.at;
|
|
35
48
|
return next;
|
|
36
49
|
}
|
|
37
50
|
function coercePayload(payload) {
|
|
38
51
|
const next = { ...payload };
|
|
39
52
|
// Back-compat: older configs used `provider` for delivery channel.
|
|
40
53
|
migrateLegacyCronPayload(next);
|
|
54
|
+
const kindRaw = typeof next.kind === "string" ? next.kind.trim().toLowerCase() : "";
|
|
55
|
+
if (kindRaw === "agentturn") {
|
|
56
|
+
next.kind = "agentTurn";
|
|
57
|
+
}
|
|
58
|
+
else if (kindRaw === "systemevent") {
|
|
59
|
+
next.kind = "systemEvent";
|
|
60
|
+
}
|
|
61
|
+
else if (kindRaw) {
|
|
62
|
+
next.kind = kindRaw;
|
|
63
|
+
}
|
|
64
|
+
if (!next.kind) {
|
|
65
|
+
const hasMessage = typeof next.message === "string" && next.message.trim().length > 0;
|
|
66
|
+
const hasText = typeof next.text === "string" && next.text.trim().length > 0;
|
|
67
|
+
if (hasMessage) {
|
|
68
|
+
next.kind = "agentTurn";
|
|
69
|
+
}
|
|
70
|
+
else if (hasText) {
|
|
71
|
+
next.kind = "systemEvent";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (typeof next.message === "string") {
|
|
75
|
+
const trimmed = next.message.trim();
|
|
76
|
+
if (trimmed) {
|
|
77
|
+
next.message = trimmed;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (typeof next.text === "string") {
|
|
81
|
+
const trimmed = next.text.trim();
|
|
82
|
+
if (trimmed) {
|
|
83
|
+
next.text = trimmed;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if ("model" in next) {
|
|
87
|
+
if (typeof next.model === "string") {
|
|
88
|
+
const trimmed = next.model.trim();
|
|
89
|
+
if (trimmed) {
|
|
90
|
+
next.model = trimmed;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
delete next.model;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
delete next.model;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if ("thinking" in next) {
|
|
101
|
+
if (typeof next.thinking === "string") {
|
|
102
|
+
const trimmed = next.thinking.trim();
|
|
103
|
+
if (trimmed) {
|
|
104
|
+
next.thinking = trimmed;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
delete next.thinking;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
delete next.thinking;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if ("timeoutSeconds" in next) {
|
|
115
|
+
if (typeof next.timeoutSeconds === "number" && Number.isFinite(next.timeoutSeconds)) {
|
|
116
|
+
next.timeoutSeconds = Math.max(1, Math.floor(next.timeoutSeconds));
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
delete next.timeoutSeconds;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if ("allowUnsafeExternalContent" in next &&
|
|
123
|
+
typeof next.allowUnsafeExternalContent !== "boolean") {
|
|
124
|
+
delete next.allowUnsafeExternalContent;
|
|
125
|
+
}
|
|
41
126
|
return next;
|
|
42
127
|
}
|
|
128
|
+
function coerceDelivery(delivery) {
|
|
129
|
+
const next = { ...delivery };
|
|
130
|
+
if (typeof delivery.mode === "string") {
|
|
131
|
+
const mode = delivery.mode.trim().toLowerCase();
|
|
132
|
+
if (mode === "deliver") {
|
|
133
|
+
next.mode = "announce";
|
|
134
|
+
}
|
|
135
|
+
else if (mode === "announce" || mode === "none") {
|
|
136
|
+
next.mode = mode;
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
delete next.mode;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else if ("mode" in next) {
|
|
143
|
+
delete next.mode;
|
|
144
|
+
}
|
|
145
|
+
if (typeof delivery.channel === "string") {
|
|
146
|
+
const trimmed = delivery.channel.trim().toLowerCase();
|
|
147
|
+
if (trimmed) {
|
|
148
|
+
next.channel = trimmed;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
delete next.channel;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (typeof delivery.to === "string") {
|
|
155
|
+
const trimmed = delivery.to.trim();
|
|
156
|
+
if (trimmed) {
|
|
157
|
+
next.to = trimmed;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
delete next.to;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return next;
|
|
164
|
+
}
|
|
165
|
+
function hasLegacyDeliveryHints(payload) {
|
|
166
|
+
if (typeof payload.deliver === "boolean") {
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
if (typeof payload.bestEffortDeliver === "boolean") {
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
if (typeof payload.to === "string" && payload.to.trim()) {
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
function buildDeliveryFromLegacyPayload(payload) {
|
|
178
|
+
const deliver = payload.deliver;
|
|
179
|
+
const mode = deliver === false ? "none" : "announce";
|
|
180
|
+
const channelRaw = typeof payload.channel === "string" ? payload.channel.trim().toLowerCase() : "";
|
|
181
|
+
const toRaw = typeof payload.to === "string" ? payload.to.trim() : "";
|
|
182
|
+
const next = { mode };
|
|
183
|
+
if (channelRaw) {
|
|
184
|
+
next.channel = channelRaw;
|
|
185
|
+
}
|
|
186
|
+
if (toRaw) {
|
|
187
|
+
next.to = toRaw;
|
|
188
|
+
}
|
|
189
|
+
if (typeof payload.bestEffortDeliver === "boolean") {
|
|
190
|
+
next.bestEffort = payload.bestEffortDeliver;
|
|
191
|
+
}
|
|
192
|
+
return next;
|
|
193
|
+
}
|
|
194
|
+
function stripLegacyDeliveryFields(payload) {
|
|
195
|
+
if ("deliver" in payload) {
|
|
196
|
+
delete payload.deliver;
|
|
197
|
+
}
|
|
198
|
+
if ("channel" in payload) {
|
|
199
|
+
delete payload.channel;
|
|
200
|
+
}
|
|
201
|
+
if ("to" in payload) {
|
|
202
|
+
delete payload.to;
|
|
203
|
+
}
|
|
204
|
+
if ("bestEffortDeliver" in payload) {
|
|
205
|
+
delete payload.bestEffortDeliver;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
43
208
|
function unwrapJob(raw) {
|
|
44
|
-
if (isRecord(raw.data))
|
|
209
|
+
if (isRecord(raw.data)) {
|
|
45
210
|
return raw.data;
|
|
46
|
-
|
|
211
|
+
}
|
|
212
|
+
if (isRecord(raw.job)) {
|
|
47
213
|
return raw.job;
|
|
214
|
+
}
|
|
48
215
|
return raw;
|
|
49
216
|
}
|
|
217
|
+
function normalizeSessionTarget(raw) {
|
|
218
|
+
if (typeof raw !== "string") {
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
const trimmed = raw.trim().toLowerCase();
|
|
222
|
+
if (trimmed === "main" || trimmed === "isolated") {
|
|
223
|
+
return trimmed;
|
|
224
|
+
}
|
|
225
|
+
return undefined;
|
|
226
|
+
}
|
|
227
|
+
function normalizeWakeMode(raw) {
|
|
228
|
+
if (typeof raw !== "string") {
|
|
229
|
+
return undefined;
|
|
230
|
+
}
|
|
231
|
+
const trimmed = raw.trim().toLowerCase();
|
|
232
|
+
if (trimmed === "now" || trimmed === "next-heartbeat") {
|
|
233
|
+
return trimmed;
|
|
234
|
+
}
|
|
235
|
+
return undefined;
|
|
236
|
+
}
|
|
237
|
+
function copyTopLevelAgentTurnFields(next, payload) {
|
|
238
|
+
const copyString = (field) => {
|
|
239
|
+
if (typeof payload[field] === "string" && payload[field].trim()) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const value = next[field];
|
|
243
|
+
if (typeof value === "string" && value.trim()) {
|
|
244
|
+
payload[field] = value.trim();
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
copyString("model");
|
|
248
|
+
copyString("thinking");
|
|
249
|
+
if (typeof payload.timeoutSeconds !== "number" && typeof next.timeoutSeconds === "number") {
|
|
250
|
+
payload.timeoutSeconds = next.timeoutSeconds;
|
|
251
|
+
}
|
|
252
|
+
if (typeof payload.allowUnsafeExternalContent !== "boolean" &&
|
|
253
|
+
typeof next.allowUnsafeExternalContent === "boolean") {
|
|
254
|
+
payload.allowUnsafeExternalContent = next.allowUnsafeExternalContent;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function copyTopLevelLegacyDeliveryFields(next, payload) {
|
|
258
|
+
if (typeof payload.deliver !== "boolean" && typeof next.deliver === "boolean") {
|
|
259
|
+
payload.deliver = next.deliver;
|
|
260
|
+
}
|
|
261
|
+
if (typeof payload.channel !== "string" &&
|
|
262
|
+
typeof next.channel === "string" &&
|
|
263
|
+
next.channel.trim()) {
|
|
264
|
+
payload.channel = next.channel.trim();
|
|
265
|
+
}
|
|
266
|
+
if (typeof payload.to !== "string" && typeof next.to === "string" && next.to.trim()) {
|
|
267
|
+
payload.to = next.to.trim();
|
|
268
|
+
}
|
|
269
|
+
if (typeof payload.bestEffortDeliver !== "boolean" &&
|
|
270
|
+
typeof next.bestEffortDeliver === "boolean") {
|
|
271
|
+
payload.bestEffortDeliver = next.bestEffortDeliver;
|
|
272
|
+
}
|
|
273
|
+
if (typeof payload.provider !== "string" &&
|
|
274
|
+
typeof next.provider === "string" &&
|
|
275
|
+
next.provider.trim()) {
|
|
276
|
+
payload.provider = next.provider.trim();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function stripLegacyTopLevelFields(next) {
|
|
280
|
+
delete next.model;
|
|
281
|
+
delete next.thinking;
|
|
282
|
+
delete next.timeoutSeconds;
|
|
283
|
+
delete next.allowUnsafeExternalContent;
|
|
284
|
+
delete next.message;
|
|
285
|
+
delete next.text;
|
|
286
|
+
delete next.deliver;
|
|
287
|
+
delete next.channel;
|
|
288
|
+
delete next.to;
|
|
289
|
+
delete next.bestEffortDeliver;
|
|
290
|
+
delete next.provider;
|
|
291
|
+
}
|
|
50
292
|
export function normalizeCronJobInput(raw, options = DEFAULT_OPTIONS) {
|
|
51
|
-
if (!isRecord(raw))
|
|
293
|
+
if (!isRecord(raw)) {
|
|
52
294
|
return null;
|
|
295
|
+
}
|
|
53
296
|
const base = unwrapJob(raw);
|
|
54
297
|
const next = { ...base };
|
|
55
298
|
if ("agentId" in base) {
|
|
@@ -59,10 +302,12 @@ export function normalizeCronJobInput(raw, options = DEFAULT_OPTIONS) {
|
|
|
59
302
|
}
|
|
60
303
|
else if (typeof agentId === "string") {
|
|
61
304
|
const trimmed = agentId.trim();
|
|
62
|
-
if (trimmed)
|
|
305
|
+
if (trimmed) {
|
|
63
306
|
next.agentId = sanitizeAgentId(trimmed);
|
|
64
|
-
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
65
309
|
delete next.agentId;
|
|
310
|
+
}
|
|
66
311
|
}
|
|
67
312
|
}
|
|
68
313
|
if ("enabled" in base) {
|
|
@@ -72,27 +317,110 @@ export function normalizeCronJobInput(raw, options = DEFAULT_OPTIONS) {
|
|
|
72
317
|
}
|
|
73
318
|
else if (typeof enabled === "string") {
|
|
74
319
|
const trimmed = enabled.trim().toLowerCase();
|
|
75
|
-
if (trimmed === "true")
|
|
320
|
+
if (trimmed === "true") {
|
|
76
321
|
next.enabled = true;
|
|
77
|
-
|
|
322
|
+
}
|
|
323
|
+
if (trimmed === "false") {
|
|
78
324
|
next.enabled = false;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if ("sessionTarget" in base) {
|
|
329
|
+
const normalized = normalizeSessionTarget(base.sessionTarget);
|
|
330
|
+
if (normalized) {
|
|
331
|
+
next.sessionTarget = normalized;
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
delete next.sessionTarget;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if ("wakeMode" in base) {
|
|
338
|
+
const normalized = normalizeWakeMode(base.wakeMode);
|
|
339
|
+
if (normalized) {
|
|
340
|
+
next.wakeMode = normalized;
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
delete next.wakeMode;
|
|
79
344
|
}
|
|
80
345
|
}
|
|
81
346
|
if (isRecord(base.schedule)) {
|
|
82
347
|
next.schedule = coerceSchedule(base.schedule);
|
|
83
348
|
}
|
|
349
|
+
if (!("payload" in next) || !isRecord(next.payload)) {
|
|
350
|
+
const message = typeof next.message === "string" ? next.message.trim() : "";
|
|
351
|
+
const text = typeof next.text === "string" ? next.text.trim() : "";
|
|
352
|
+
if (message) {
|
|
353
|
+
next.payload = { kind: "agentTurn", message };
|
|
354
|
+
}
|
|
355
|
+
else if (text) {
|
|
356
|
+
next.payload = { kind: "systemEvent", text };
|
|
357
|
+
}
|
|
358
|
+
}
|
|
84
359
|
if (isRecord(base.payload)) {
|
|
85
360
|
next.payload = coercePayload(base.payload);
|
|
86
361
|
}
|
|
362
|
+
if (isRecord(base.delivery)) {
|
|
363
|
+
next.delivery = coerceDelivery(base.delivery);
|
|
364
|
+
}
|
|
365
|
+
if ("isolation" in next) {
|
|
366
|
+
delete next.isolation;
|
|
367
|
+
}
|
|
368
|
+
const payload = isRecord(next.payload) ? next.payload : null;
|
|
369
|
+
if (payload && payload.kind === "agentTurn") {
|
|
370
|
+
copyTopLevelAgentTurnFields(next, payload);
|
|
371
|
+
copyTopLevelLegacyDeliveryFields(next, payload);
|
|
372
|
+
}
|
|
373
|
+
stripLegacyTopLevelFields(next);
|
|
87
374
|
if (options.applyDefaults) {
|
|
88
|
-
if (!next.wakeMode)
|
|
89
|
-
next.wakeMode = "
|
|
375
|
+
if (!next.wakeMode) {
|
|
376
|
+
next.wakeMode = "now";
|
|
377
|
+
}
|
|
378
|
+
if (typeof next.enabled !== "boolean") {
|
|
379
|
+
next.enabled = true;
|
|
380
|
+
}
|
|
381
|
+
if ((typeof next.name !== "string" || !next.name.trim()) &&
|
|
382
|
+
isRecord(next.schedule) &&
|
|
383
|
+
isRecord(next.payload)) {
|
|
384
|
+
next.name = inferLegacyName({
|
|
385
|
+
schedule: next.schedule,
|
|
386
|
+
payload: next.payload,
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
else if (typeof next.name === "string") {
|
|
390
|
+
const trimmed = next.name.trim();
|
|
391
|
+
if (trimmed) {
|
|
392
|
+
next.name = trimmed;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
90
395
|
if (!next.sessionTarget && isRecord(next.payload)) {
|
|
91
396
|
const kind = typeof next.payload.kind === "string" ? next.payload.kind : "";
|
|
92
|
-
if (kind === "systemEvent")
|
|
397
|
+
if (kind === "systemEvent") {
|
|
93
398
|
next.sessionTarget = "main";
|
|
94
|
-
|
|
399
|
+
}
|
|
400
|
+
if (kind === "agentTurn") {
|
|
95
401
|
next.sessionTarget = "isolated";
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
if ("schedule" in next &&
|
|
405
|
+
isRecord(next.schedule) &&
|
|
406
|
+
next.schedule.kind === "at" &&
|
|
407
|
+
!("deleteAfterRun" in next)) {
|
|
408
|
+
next.deleteAfterRun = true;
|
|
409
|
+
}
|
|
410
|
+
const payload = isRecord(next.payload) ? next.payload : null;
|
|
411
|
+
const payloadKind = payload && typeof payload.kind === "string" ? payload.kind : "";
|
|
412
|
+
const sessionTarget = typeof next.sessionTarget === "string" ? next.sessionTarget : "";
|
|
413
|
+
const isIsolatedAgentTurn = sessionTarget === "isolated" || (sessionTarget === "" && payloadKind === "agentTurn");
|
|
414
|
+
const hasDelivery = "delivery" in next && next.delivery !== undefined;
|
|
415
|
+
const hasLegacyDelivery = payload ? hasLegacyDeliveryHints(payload) : false;
|
|
416
|
+
if (!hasDelivery && isIsolatedAgentTurn && payloadKind === "agentTurn") {
|
|
417
|
+
if (payload && hasLegacyDelivery) {
|
|
418
|
+
next.delivery = buildDeliveryFromLegacyPayload(payload);
|
|
419
|
+
stripLegacyDeliveryFields(payload);
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
next.delivery = { mode: "announce" };
|
|
423
|
+
}
|
|
96
424
|
}
|
|
97
425
|
}
|
|
98
426
|
return next;
|
package/dist/cron/parse.js
CHANGED
|
@@ -2,22 +2,27 @@ const ISO_TZ_RE = /(Z|[+-]\d{2}:?\d{2})$/i;
|
|
|
2
2
|
const ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
3
3
|
const ISO_DATE_TIME_RE = /^\d{4}-\d{2}-\d{2}T/;
|
|
4
4
|
function normalizeUtcIso(raw) {
|
|
5
|
-
if (ISO_TZ_RE.test(raw))
|
|
5
|
+
if (ISO_TZ_RE.test(raw)) {
|
|
6
6
|
return raw;
|
|
7
|
-
|
|
7
|
+
}
|
|
8
|
+
if (ISO_DATE_RE.test(raw)) {
|
|
8
9
|
return `${raw}T00:00:00Z`;
|
|
9
|
-
|
|
10
|
+
}
|
|
11
|
+
if (ISO_DATE_TIME_RE.test(raw)) {
|
|
10
12
|
return `${raw}Z`;
|
|
13
|
+
}
|
|
11
14
|
return raw;
|
|
12
15
|
}
|
|
13
16
|
export function parseAbsoluteTimeMs(input) {
|
|
14
17
|
const raw = input.trim();
|
|
15
|
-
if (!raw)
|
|
18
|
+
if (!raw) {
|
|
16
19
|
return null;
|
|
20
|
+
}
|
|
17
21
|
if (/^\d+$/.test(raw)) {
|
|
18
22
|
const n = Number(raw);
|
|
19
|
-
if (Number.isFinite(n) && n > 0)
|
|
23
|
+
if (Number.isFinite(n) && n > 0) {
|
|
20
24
|
return Math.floor(n);
|
|
25
|
+
}
|
|
21
26
|
}
|
|
22
27
|
const parsed = Date.parse(normalizeUtcIso(raw));
|
|
23
28
|
return Number.isFinite(parsed) ? parsed : null;
|
package/dist/cron/run-log.js
CHANGED
|
@@ -8,8 +8,9 @@ export function resolveCronRunLogPath(params) {
|
|
|
8
8
|
const writesByPath = new Map();
|
|
9
9
|
async function pruneIfNeeded(filePath, opts) {
|
|
10
10
|
const stat = await fs.stat(filePath).catch(() => null);
|
|
11
|
-
if (!stat || stat.size <= opts.maxBytes)
|
|
11
|
+
if (!stat || stat.size <= opts.maxBytes) {
|
|
12
12
|
return;
|
|
13
|
+
}
|
|
13
14
|
const raw = await fs.readFile(filePath, "utf-8").catch(() => "");
|
|
14
15
|
const lines = raw
|
|
15
16
|
.split("\n")
|
|
@@ -40,31 +41,55 @@ export async function readCronRunLogEntries(filePath, opts) {
|
|
|
40
41
|
const limit = Math.max(1, Math.min(5000, Math.floor(opts?.limit ?? 200)));
|
|
41
42
|
const jobId = opts?.jobId?.trim() || undefined;
|
|
42
43
|
const raw = await fs.readFile(path.resolve(filePath), "utf-8").catch(() => "");
|
|
43
|
-
if (!raw.trim())
|
|
44
|
+
if (!raw.trim()) {
|
|
44
45
|
return [];
|
|
46
|
+
}
|
|
45
47
|
const parsed = [];
|
|
46
48
|
const lines = raw.split("\n");
|
|
47
49
|
for (let i = lines.length - 1; i >= 0 && parsed.length < limit; i--) {
|
|
48
50
|
const line = lines[i]?.trim();
|
|
49
|
-
if (!line)
|
|
51
|
+
if (!line) {
|
|
50
52
|
continue;
|
|
53
|
+
}
|
|
51
54
|
try {
|
|
52
55
|
const obj = JSON.parse(line);
|
|
53
|
-
if (!obj || typeof obj !== "object")
|
|
56
|
+
if (!obj || typeof obj !== "object") {
|
|
54
57
|
continue;
|
|
55
|
-
|
|
58
|
+
}
|
|
59
|
+
if (obj.action !== "finished") {
|
|
56
60
|
continue;
|
|
57
|
-
|
|
61
|
+
}
|
|
62
|
+
if (typeof obj.jobId !== "string" || obj.jobId.trim().length === 0) {
|
|
58
63
|
continue;
|
|
59
|
-
|
|
64
|
+
}
|
|
65
|
+
if (typeof obj.ts !== "number" || !Number.isFinite(obj.ts)) {
|
|
60
66
|
continue;
|
|
61
|
-
|
|
67
|
+
}
|
|
68
|
+
if (jobId && obj.jobId !== jobId) {
|
|
62
69
|
continue;
|
|
63
|
-
|
|
70
|
+
}
|
|
71
|
+
const entry = {
|
|
72
|
+
ts: obj.ts,
|
|
73
|
+
jobId: obj.jobId,
|
|
74
|
+
action: "finished",
|
|
75
|
+
status: obj.status,
|
|
76
|
+
error: obj.error,
|
|
77
|
+
summary: obj.summary,
|
|
78
|
+
runAtMs: obj.runAtMs,
|
|
79
|
+
durationMs: obj.durationMs,
|
|
80
|
+
nextRunAtMs: obj.nextRunAtMs,
|
|
81
|
+
};
|
|
82
|
+
if (typeof obj.sessionId === "string" && obj.sessionId.trim().length > 0) {
|
|
83
|
+
entry.sessionId = obj.sessionId;
|
|
84
|
+
}
|
|
85
|
+
if (typeof obj.sessionKey === "string" && obj.sessionKey.trim().length > 0) {
|
|
86
|
+
entry.sessionKey = obj.sessionKey;
|
|
87
|
+
}
|
|
88
|
+
parsed.push(entry);
|
|
64
89
|
}
|
|
65
90
|
catch {
|
|
66
91
|
// ignore invalid lines
|
|
67
92
|
}
|
|
68
93
|
}
|
|
69
|
-
return parsed.
|
|
94
|
+
return parsed.toReversed();
|
|
70
95
|
}
|
package/dist/cron/schedule.js
CHANGED
|
@@ -1,24 +1,59 @@
|
|
|
1
1
|
import { Cron } from "croner";
|
|
2
|
+
import { parseAbsoluteTimeMs } from "./parse.js";
|
|
3
|
+
function resolveCronTimezone(tz) {
|
|
4
|
+
const trimmed = typeof tz === "string" ? tz.trim() : "";
|
|
5
|
+
if (trimmed) {
|
|
6
|
+
return trimmed;
|
|
7
|
+
}
|
|
8
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
9
|
+
}
|
|
2
10
|
export function computeNextRunAtMs(schedule, nowMs) {
|
|
3
11
|
if (schedule.kind === "at") {
|
|
4
|
-
|
|
12
|
+
// Handle both canonical `at` (string) and legacy `atMs` (number) fields.
|
|
13
|
+
// The store migration should convert atMs→at, but be defensive in case
|
|
14
|
+
// the migration hasn't run yet or was bypassed.
|
|
15
|
+
const sched = schedule;
|
|
16
|
+
const atMs = typeof sched.atMs === "number" && Number.isFinite(sched.atMs) && sched.atMs > 0
|
|
17
|
+
? sched.atMs
|
|
18
|
+
: typeof sched.atMs === "string"
|
|
19
|
+
? parseAbsoluteTimeMs(sched.atMs)
|
|
20
|
+
: typeof sched.at === "string"
|
|
21
|
+
? parseAbsoluteTimeMs(sched.at)
|
|
22
|
+
: null;
|
|
23
|
+
if (atMs === null) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
return atMs > nowMs ? atMs : undefined;
|
|
5
27
|
}
|
|
6
28
|
if (schedule.kind === "every") {
|
|
7
29
|
const everyMs = Math.max(1, Math.floor(schedule.everyMs));
|
|
8
30
|
const anchor = Math.max(0, Math.floor(schedule.anchorMs ?? nowMs));
|
|
9
|
-
if (nowMs < anchor)
|
|
31
|
+
if (nowMs < anchor) {
|
|
10
32
|
return anchor;
|
|
33
|
+
}
|
|
11
34
|
const elapsed = nowMs - anchor;
|
|
12
35
|
const steps = Math.max(1, Math.floor((elapsed + everyMs - 1) / everyMs));
|
|
13
36
|
return anchor + steps * everyMs;
|
|
14
37
|
}
|
|
15
38
|
const expr = schedule.expr.trim();
|
|
16
|
-
if (!expr)
|
|
39
|
+
if (!expr) {
|
|
17
40
|
return undefined;
|
|
41
|
+
}
|
|
18
42
|
const cron = new Cron(expr, {
|
|
19
|
-
timezone: schedule.tz
|
|
43
|
+
timezone: resolveCronTimezone(schedule.tz),
|
|
20
44
|
catch: false,
|
|
21
45
|
});
|
|
22
|
-
|
|
23
|
-
|
|
46
|
+
// Cron operates at second granularity, so floor nowMs to the start of the
|
|
47
|
+
// current second. This prevents the lookback from landing inside a matching
|
|
48
|
+
// second — if nowMs is e.g. 12:00:00.500 and the pattern fires at second 0,
|
|
49
|
+
// a 1ms lookback (12:00:00.499) is still *within* that second, causing
|
|
50
|
+
// croner to skip ahead to the next occurrence (e.g. the following day).
|
|
51
|
+
// Flooring first ensures the lookback always falls in the *previous* second.
|
|
52
|
+
const nowSecondMs = Math.floor(nowMs / 1000) * 1000;
|
|
53
|
+
const next = cron.nextRun(new Date(nowSecondMs - 1));
|
|
54
|
+
if (!next) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
const nextMs = next.getTime();
|
|
58
|
+
return Number.isFinite(nextMs) && nextMs >= nowSecondMs ? nextMs : undefined;
|
|
24
59
|
}
|