vellum 0.2.1 → 0.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/README.md +15 -2
- package/bun.lock +5 -2
- package/package.json +4 -2
- package/scripts/capture-x-graphql.ts +562 -0
- package/scripts/ipc/check-swift-decoder-drift.ts +2 -1
- package/scripts/test.sh +5 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +133 -34
- package/src/__tests__/account-registry.test.ts +2 -1
- package/src/__tests__/agent-heartbeat-service.test.ts +250 -0
- package/src/__tests__/asset-materialize-tool.test.ts +16 -15
- package/src/__tests__/asset-search-tool.test.ts +23 -22
- package/src/__tests__/attachments-store.test.ts +56 -127
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +5 -4
- package/src/__tests__/browser-skill-endstate.test.ts +4 -3
- package/src/__tests__/call-bridge.test.ts +385 -0
- package/src/__tests__/call-constants.test.ts +40 -0
- package/src/__tests__/call-orchestrator.test.ts +130 -4
- package/src/__tests__/call-recovery.test.ts +518 -0
- package/src/__tests__/call-routes-http.test.ts +459 -0
- package/src/__tests__/call-state-machine.test.ts +143 -0
- package/src/__tests__/call-store.test.ts +216 -1
- package/src/__tests__/cli-discover.test.ts +1 -1
- package/src/__tests__/commit-message-enrichment-service.test.ts +148 -7
- package/src/__tests__/compaction.benchmark.test.ts +176 -0
- package/src/__tests__/computer-use-tools.test.ts +250 -0
- package/src/__tests__/config-schema.test.ts +299 -3
- package/src/__tests__/conflict-store.test.ts +2 -1
- package/src/__tests__/contacts-tools.test.ts +331 -0
- package/src/__tests__/conversation-store.test.ts +30 -32
- package/src/__tests__/credential-security-invariants.test.ts +4 -0
- package/src/__tests__/date-context.test.ts +373 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +129 -0
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +3 -3
- package/src/__tests__/followup-tools.test.ts +303 -0
- package/src/__tests__/handlers-twitter-config.test.ts +718 -0
- package/src/__tests__/intent-routing.test.ts +64 -57
- package/src/__tests__/ipc-roundtrip.benchmark.test.ts +237 -0
- package/src/__tests__/ipc-snapshot.test.ts +62 -28
- package/src/__tests__/llm-usage-store.test.ts +3 -8
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/media-reuse-story.e2e.test.ts +7 -7
- package/src/__tests__/memory-retrieval.benchmark.test.ts +430 -0
- package/src/__tests__/parallel-tool.benchmark.test.ts +294 -0
- package/src/__tests__/playbook-tools.test.ts +342 -0
- package/src/__tests__/profile-compiler.test.ts +2 -1
- package/src/__tests__/provider-streaming.benchmark.test.ts +773 -0
- package/src/__tests__/recurrence-engine-rruleset.test.ts +78 -0
- package/src/__tests__/recurrence-engine.test.ts +69 -0
- package/src/__tests__/recurrence-types.test.ts +71 -0
- package/src/__tests__/registry.test.ts +5 -3
- package/src/__tests__/relay-server.test.ts +633 -0
- package/src/__tests__/reminder-store.test.ts +6 -3
- package/src/__tests__/reminder.test.ts +43 -77
- package/src/__tests__/run-orchestrator-assistant-events.test.ts +8 -4
- package/src/__tests__/run-orchestrator.test.ts +4 -4
- package/src/__tests__/runtime-attachment-metadata.test.ts +7 -6
- package/src/__tests__/runtime-runs-http.test.ts +4 -4
- package/src/__tests__/runtime-runs.test.ts +4 -4
- package/src/__tests__/schedule-store.test.ts +482 -0
- package/src/__tests__/schedule-tools.test.ts +700 -0
- package/src/__tests__/scheduler-recurrence.test.ts +329 -0
- package/src/__tests__/server-history-render.test.ts +14 -13
- package/src/__tests__/session-error.test.ts +28 -0
- package/src/__tests__/session-init.benchmark.test.ts +462 -0
- package/src/__tests__/session-queue.test.ts +71 -48
- package/src/__tests__/session-runtime-assembly.test.ts +161 -0
- package/src/__tests__/session-surfaces-task-progress.test.ts +104 -0
- package/src/__tests__/signup-e2e.test.ts +2 -1
- package/src/__tests__/skill-projection.benchmark.test.ts +328 -0
- package/src/__tests__/skill-script-runner.test.ts +159 -0
- package/src/__tests__/speaker-identification.test.ts +52 -0
- package/src/__tests__/subagent-manager-notify.test.ts +42 -10
- package/src/__tests__/subagent-tools.test.ts +141 -41
- package/src/__tests__/task-compiler.test.ts +2 -1
- package/src/__tests__/task-runner.test.ts +2 -1
- package/src/__tests__/task-scheduler.test.ts +2 -1
- package/src/__tests__/task-tools.test.ts +49 -56
- package/src/__tests__/tool-audit-listener.test.ts +1 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +2 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +500 -0
- package/src/__tests__/tool-executor.test.ts +13 -17
- package/src/__tests__/turn-commit.test.ts +218 -3
- package/src/__tests__/twilio-provider.test.ts +143 -0
- package/src/__tests__/twilio-routes.test.ts +789 -0
- package/src/__tests__/twitter-auth-handler.test.ts +581 -0
- package/src/__tests__/view-image-tool.test.ts +217 -0
- package/src/__tests__/workspace-git-service.test.ts +186 -0
- package/src/__tests__/workspace-heartbeat-service.test.ts +13 -3
- package/src/agent-heartbeat/agent-heartbeat-service.ts +155 -0
- package/src/bundler/app-bundler.ts +12 -8
- package/src/calls/call-bridge.ts +95 -0
- package/src/calls/call-constants.ts +43 -5
- package/src/calls/call-domain.ts +276 -0
- package/src/calls/call-orchestrator.ts +43 -17
- package/src/calls/call-recovery.ts +207 -0
- package/src/calls/call-state-machine.ts +68 -0
- package/src/calls/call-store.ts +192 -5
- package/src/calls/relay-server.ts +41 -4
- package/src/calls/speaker-identification.ts +213 -0
- package/src/calls/twilio-provider.ts +10 -6
- package/src/calls/twilio-routes.ts +90 -76
- package/src/calls/types.ts +1 -1
- package/src/cli/config-commands.ts +334 -0
- package/src/cli/core-commands.ts +776 -0
- package/src/cli/doordash.ts +251 -1
- package/src/cli/ipc-client.ts +82 -0
- package/src/cli/map.ts +246 -0
- package/src/cli/twitter.ts +575 -0
- package/src/cli.ts +7 -5
- package/src/commands/__tests__/cc-command-registry.test.ts +319 -0
- package/src/commands/cc-command-registry.ts +209 -0
- package/src/config/bundled-skills/contacts/SKILL.md +39 -0
- package/src/config/bundled-skills/contacts/TOOLS.json +122 -0
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +9 -0
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +9 -0
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +9 -0
- package/src/config/bundled-skills/document/SKILL.md +18 -0
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-create.ts +9 -0
- package/src/config/bundled-skills/document/tools/document-update.ts +9 -0
- package/src/config/bundled-skills/doordash/SKILL.md +82 -23
- package/src/config/bundled-skills/followups/SKILL.md +32 -0
- package/src/config/bundled-skills/followups/TOOLS.json +100 -0
- package/src/config/bundled-skills/followups/tools/followup-create.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-list.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-resolve.ts +9 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +1 -23
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -1
- package/src/config/bundled-skills/playbooks/SKILL.md +31 -0
- package/src/config/bundled-skills/playbooks/TOOLS.json +126 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +9 -0
- package/src/config/bundled-skills/reminder/SKILL.md +20 -0
- package/src/config/bundled-skills/reminder/TOOLS.json +67 -0
- package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-create.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-list.ts +9 -0
- package/src/config/bundled-skills/schedule/SKILL.md +74 -0
- package/src/config/bundled-skills/schedule/TOOLS.json +135 -0
- package/src/config/bundled-skills/schedule/tools/schedule-create.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-list.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-update.ts +9 -0
- package/src/config/bundled-skills/subagent/SKILL.md +25 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +107 -0
- package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-message.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-read.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-status.ts +9 -0
- package/src/config/bundled-skills/tasks/SKILL.md +28 -0
- package/src/config/bundled-skills/tasks/TOOLS.json +256 -0
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-run.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-save.ts +9 -0
- package/src/config/bundled-skills/twitter/SKILL.md +134 -0
- package/src/config/bundled-skills/watcher/SKILL.md +27 -0
- package/src/config/bundled-skills/watcher/TOOLS.json +147 -0
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +9 -0
- package/src/config/defaults.ts +33 -0
- package/src/config/loader.ts +4 -1
- package/src/config/schema.ts +161 -1
- package/src/config/system-prompt.ts +61 -16
- package/src/config/templates/IDENTITY.md +7 -0
- package/src/config/types.ts +4 -0
- package/src/contacts/contact-store.ts +4 -4
- package/src/daemon/assistant-attachments.ts +10 -0
- package/src/daemon/classifier.ts +3 -1
- package/src/daemon/computer-use-session.ts +3 -1
- package/src/daemon/date-context.ts +136 -0
- package/src/daemon/handlers/apps.ts +16 -1
- package/src/daemon/handlers/browser.ts +54 -0
- package/src/daemon/handlers/computer-use.ts +7 -1
- package/src/daemon/handlers/config.ts +163 -5
- package/src/daemon/handlers/diagnostics.ts +5 -1
- package/src/daemon/handlers/documents.ts +18 -29
- package/src/daemon/handlers/home-base.ts +5 -1
- package/src/daemon/handlers/index.ts +40 -277
- package/src/daemon/handlers/misc.ts +9 -1
- package/src/daemon/handlers/publish.ts +6 -1
- package/src/daemon/handlers/sessions.ts +65 -12
- package/src/daemon/handlers/shared.ts +36 -1
- package/src/daemon/handlers/signing.ts +37 -0
- package/src/daemon/handlers/skills.ts +20 -6
- package/src/daemon/handlers/subagents.ts +8 -3
- package/src/daemon/handlers/twitter-auth.ts +169 -0
- package/src/daemon/handlers/work-items.ts +384 -68
- package/src/daemon/ipc-contract-inventory.json +28 -4
- package/src/daemon/ipc-contract.ts +133 -37
- package/src/daemon/ipc-protocol.ts +7 -2
- package/src/daemon/lifecycle.ts +21 -0
- package/src/daemon/main.ts +10 -4
- package/src/daemon/ride-shotgun-handler.ts +74 -10
- package/src/daemon/server.ts +143 -26
- package/src/daemon/session-agent-loop.ts +887 -0
- package/src/daemon/session-attachments.ts +28 -5
- package/src/daemon/session-error.ts +24 -3
- package/src/daemon/session-lifecycle.ts +147 -0
- package/src/daemon/session-media-retry.ts +147 -0
- package/src/daemon/session-messaging.ts +145 -0
- package/src/daemon/session-notifiers.ts +164 -0
- package/src/daemon/session-process.ts +2 -2
- package/src/daemon/session-queue-manager.ts +1 -0
- package/src/daemon/session-runtime-assembly.ts +52 -0
- package/src/daemon/session-skill-tools.ts +124 -5
- package/src/daemon/session-slash.ts +3 -0
- package/src/daemon/session-surfaces.ts +77 -2
- package/src/daemon/session-tool-setup.ts +216 -2
- package/src/daemon/session-usage.ts +0 -2
- package/src/daemon/session.ts +114 -1404
- package/src/daemon/video-thumbnail.ts +60 -0
- package/src/doordash/client.ts +121 -27
- package/src/doordash/queries.ts +1 -2
- package/src/export/formatter.ts +3 -1
- package/src/followups/followup-store.ts +4 -2
- package/src/followups/types.ts +6 -0
- package/src/hooks/templates.ts +1 -1
- package/src/index.ts +32 -1153
- package/src/memory/attachments-store.ts +28 -83
- package/src/memory/channel-delivery-store.ts +7 -21
- package/src/memory/clarification-resolver.ts +6 -5
- package/src/memory/contradiction-checker.ts +3 -2
- package/src/memory/conversation-key-store.ts +10 -29
- package/src/memory/conversation-store.ts +2 -1
- package/src/memory/db.ts +96 -2
- package/src/memory/entity-extractor.ts +6 -3
- package/src/memory/items-extractor.ts +5 -4
- package/src/memory/jobs-store.ts +3 -2
- package/src/memory/llm-usage-store.ts +1 -2
- package/src/memory/runs-store.ts +1 -2
- package/src/memory/schema.ts +23 -2
- package/src/messaging/style-analyzer.ts +3 -2
- package/src/messaging/thread-summarizer.ts +8 -12
- package/src/messaging/triage-engine.ts +4 -2
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/registry.ts +8 -0
- package/src/runtime/http-server.ts +108 -20
- package/src/runtime/routes/attachment-routes.ts +2 -3
- package/src/runtime/routes/call-routes.ts +140 -0
- package/src/runtime/routes/channel-routes.ts +5 -10
- package/src/runtime/routes/conversation-routes.ts +5 -5
- package/src/runtime/routes/run-routes.ts +2 -2
- package/src/runtime/run-orchestrator.ts +9 -3
- package/src/schedule/recurrence-engine.ts +138 -0
- package/src/schedule/recurrence-types.ts +67 -0
- package/src/schedule/schedule-store.ts +102 -57
- package/src/schedule/scheduler.ts +9 -6
- package/src/security/oauth2.ts +29 -4
- package/src/security/secret-allowlist.ts +46 -0
- package/src/skills/clawhub.ts +1 -1
- package/src/subagent/manager.ts +40 -8
- package/src/swarm/backend-claude-code.ts +64 -9
- package/src/swarm/worker-prompts.ts +2 -1
- package/src/tasks/SPEC.md +34 -28
- package/src/tasks/ephemeral-permissions.ts +16 -7
- package/src/tasks/task-compiler.ts +5 -4
- package/src/tasks/task-runner.ts +10 -5
- package/src/tasks/task-scheduler.ts +1 -1
- package/src/tasks/tool-sanitizer.ts +36 -0
- package/src/tools/assets/search.ts +4 -4
- package/src/tools/browser/api-map.ts +220 -0
- package/src/tools/browser/auto-navigate.ts +270 -0
- package/src/tools/browser/browser-execution.ts +2 -1
- package/src/tools/browser/browser-manager.ts +2 -2
- package/src/tools/browser/network-recorder.ts +5 -4
- package/src/tools/browser/x-auto-navigate.ts +207 -0
- package/src/tools/calls/call-end.ts +17 -67
- package/src/tools/calls/call-start.ts +24 -85
- package/src/tools/calls/call-status.ts +35 -51
- package/src/tools/claude-code/claude-code.ts +77 -11
- package/src/tools/contacts/contact-merge.ts +46 -78
- package/src/tools/contacts/contact-search.ts +35 -79
- package/src/tools/contacts/contact-upsert.ts +35 -108
- package/src/tools/credentials/vault.ts +20 -4
- package/src/tools/document/document-tool.ts +71 -144
- package/src/tools/executor.ts +129 -10
- package/src/tools/followups/followup_create.ts +46 -88
- package/src/tools/followups/followup_list.ts +34 -74
- package/src/tools/followups/followup_resolve.ts +31 -66
- package/src/tools/host-terminal/cli-discover.ts +2 -1
- package/src/tools/host-terminal/host-shell.ts +10 -0
- package/src/tools/memory/handlers.ts +5 -4
- package/src/tools/network/__tests__/web-search.test.ts +427 -0
- package/src/tools/network/script-proxy/__tests__/logging.test.ts +248 -0
- package/src/tools/network/script-proxy/__tests__/policy.test.ts +234 -0
- package/src/tools/network/script-proxy/__tests__/router.test.ts +76 -0
- package/src/tools/network/web-fetch.ts +18 -6
- package/src/tools/playbooks/index.ts +4 -5
- package/src/tools/playbooks/playbook-create.ts +3 -47
- package/src/tools/playbooks/playbook-delete.ts +1 -25
- package/src/tools/playbooks/playbook-list.ts +1 -28
- package/src/tools/playbooks/playbook-update.ts +3 -51
- package/src/tools/reminder/reminder.ts +5 -78
- package/src/tools/schedule/create.ts +69 -74
- package/src/tools/schedule/delete.ts +21 -47
- package/src/tools/schedule/list.ts +55 -74
- package/src/tools/schedule/update.ts +77 -84
- package/src/tools/subagent/abort.ts +29 -58
- package/src/tools/subagent/message.ts +30 -63
- package/src/tools/subagent/read.ts +53 -84
- package/src/tools/subagent/spawn.ts +43 -82
- package/src/tools/subagent/status.ts +42 -71
- package/src/tools/swarm/delegate.ts +2 -1
- package/src/tools/tasks/index.ts +8 -8
- package/src/tools/tasks/task-delete.ts +60 -88
- package/src/tools/tasks/task-list.ts +31 -52
- package/src/tools/tasks/task-run.ts +72 -108
- package/src/tools/tasks/task-save.ts +33 -65
- package/src/tools/tasks/work-item-enqueue.ts +183 -215
- package/src/tools/tasks/work-item-list.ts +33 -63
- package/src/tools/tasks/work-item-remove.ts +45 -97
- package/src/tools/tasks/work-item-update.ts +91 -163
- package/src/tools/terminal/backends/native.ts +3 -1
- package/src/tools/tool-manifest.ts +0 -62
- package/src/tools/types.ts +6 -0
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/tools/watch/screen-watch.ts +3 -1
- package/src/tools/watcher/create.ts +52 -98
- package/src/tools/watcher/delete.ts +20 -46
- package/src/tools/watcher/digest.ts +36 -70
- package/src/tools/watcher/list.ts +49 -79
- package/src/tools/watcher/update.ts +45 -91
- package/src/twitter/client.ts +690 -0
- package/src/twitter/session.ts +91 -0
- package/src/usage/types.ts +0 -1
- package/src/util/truncate.ts +6 -0
- package/src/watcher/providers/slack.ts +2 -1
- package/src/watcher/watcher-store.ts +3 -2
- package/src/work-items/work-item-store.ts +27 -2
- package/src/workspace/commit-message-enrichment-service.ts +31 -7
- package/src/workspace/git-service.ts +87 -22
- package/src/workspace/provider-commit-message-generator.ts +242 -0
- package/src/workspace/turn-commit.ts +62 -3
- package/src/tools/contacts/index.ts +0 -4
- package/src/tools/document/index.ts +0 -5
- package/src/tools/followups/index.ts +0 -3
- package/src/tools/subagent/index.ts +0 -5
- /package/src/__tests__/{memory-context-benchmark.test.ts → memory-context-benchmark.benchmark.test.ts} +0 -0
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Tool, ToolContext, ToolExecutionResult } from '../types.js';
|
|
3
|
-
import type { ToolDefinition } from '../../providers/types.js';
|
|
1
|
+
import type { ToolExecutionResult } from '../types.js';
|
|
4
2
|
import { formatLocalDate } from '../../schedule/schedule-store.js';
|
|
5
3
|
import {
|
|
6
4
|
insertReminder,
|
|
@@ -8,28 +6,9 @@ import {
|
|
|
8
6
|
cancelReminder,
|
|
9
7
|
} from './reminder-store.js';
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
const action = input.action as string | undefined;
|
|
13
|
-
if (!action) {
|
|
14
|
-
return { content: 'Error: action is required', isError: true };
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
switch (action) {
|
|
18
|
-
case 'create':
|
|
19
|
-
return createAction(input);
|
|
20
|
-
case 'list':
|
|
21
|
-
return listAction();
|
|
22
|
-
case 'cancel':
|
|
23
|
-
return cancelAction(input);
|
|
24
|
-
default:
|
|
25
|
-
return {
|
|
26
|
-
content: `Error: Unknown action "${action}". Valid actions: create, list, cancel`,
|
|
27
|
-
isError: true,
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
}
|
|
9
|
+
// ── Exported execute functions ──────────────────────────────────────
|
|
31
10
|
|
|
32
|
-
function
|
|
11
|
+
export function executeReminderCreate(input: Record<string, unknown>): ToolExecutionResult {
|
|
33
12
|
const fireAtStr = input.fire_at as string | undefined;
|
|
34
13
|
const label = input.label as string | undefined;
|
|
35
14
|
const message = input.message as string | undefined;
|
|
@@ -68,7 +47,7 @@ function createAction(input: Record<string, unknown>): ToolExecutionResult {
|
|
|
68
47
|
};
|
|
69
48
|
}
|
|
70
49
|
|
|
71
|
-
function
|
|
50
|
+
export function executeReminderList(): ToolExecutionResult {
|
|
72
51
|
const all = listReminders();
|
|
73
52
|
if (all.length === 0) {
|
|
74
53
|
return { content: 'No reminders found.', isError: false };
|
|
@@ -86,7 +65,7 @@ function listAction(): ToolExecutionResult {
|
|
|
86
65
|
return { content: `Reminders:\n${lines.join('\n')}`, isError: false };
|
|
87
66
|
}
|
|
88
67
|
|
|
89
|
-
function
|
|
68
|
+
export function executeReminderCancel(input: Record<string, unknown>): ToolExecutionResult {
|
|
90
69
|
const reminderId = input.reminder_id as string | undefined;
|
|
91
70
|
if (!reminderId) {
|
|
92
71
|
return { content: 'Error: reminder_id is required for cancel', isError: true };
|
|
@@ -99,55 +78,3 @@ function cancelAction(input: Record<string, unknown>): ToolExecutionResult {
|
|
|
99
78
|
|
|
100
79
|
return { content: `Reminder "${reminderId}" cancelled.`, isError: false };
|
|
101
80
|
}
|
|
102
|
-
|
|
103
|
-
class ReminderTool implements Tool {
|
|
104
|
-
name = 'reminder';
|
|
105
|
-
description = 'Create, list, or cancel one-time time-based reminders. Reminders fire at a specific future time and either notify the user or execute a message through the assistant. Use this ONLY when the user wants a time-triggered notification (e.g. "remind me at 3pm", "remind me in 2 hours"). Do NOT use this for "add to my tasks" or "add to my queue" — use task_list_add for those requests.';
|
|
106
|
-
category = 'reminder';
|
|
107
|
-
defaultRiskLevel = RiskLevel.Low;
|
|
108
|
-
|
|
109
|
-
getDefinition(): ToolDefinition {
|
|
110
|
-
return {
|
|
111
|
-
name: this.name,
|
|
112
|
-
description: this.description,
|
|
113
|
-
input_schema: {
|
|
114
|
-
type: 'object',
|
|
115
|
-
properties: {
|
|
116
|
-
action: {
|
|
117
|
-
type: 'string',
|
|
118
|
-
enum: ['create', 'list', 'cancel'],
|
|
119
|
-
description: 'Reminder action',
|
|
120
|
-
},
|
|
121
|
-
fire_at: {
|
|
122
|
-
type: 'string',
|
|
123
|
-
description: 'ISO 8601 timestamp for when the reminder should fire (required for create)',
|
|
124
|
-
},
|
|
125
|
-
label: {
|
|
126
|
-
type: 'string',
|
|
127
|
-
description: 'Human-readable label (required for create)',
|
|
128
|
-
},
|
|
129
|
-
message: {
|
|
130
|
-
type: 'string',
|
|
131
|
-
description: 'Content shown in notification (notify) or sent to agent (execute). Required for create.',
|
|
132
|
-
},
|
|
133
|
-
mode: {
|
|
134
|
-
type: 'string',
|
|
135
|
-
enum: ['notify', 'execute'],
|
|
136
|
-
description: 'How the reminder fires. Defaults to notify.',
|
|
137
|
-
},
|
|
138
|
-
reminder_id: {
|
|
139
|
-
type: 'string',
|
|
140
|
-
description: 'Reminder ID (required for cancel)',
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
required: ['action'],
|
|
144
|
-
},
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async execute(input: Record<string, unknown>, _context: ToolContext): Promise<ToolExecutionResult> {
|
|
149
|
-
return executeReminder(input);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
export const reminderTool = new ReminderTool();
|
|
@@ -1,86 +1,81 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Tool, ToolContext, ToolExecutionResult } from '../types.js';
|
|
3
|
-
import type { ToolDefinition } from '../../providers/types.js';
|
|
4
|
-
import { registerTool } from '../registry.js';
|
|
1
|
+
import type { ToolContext, ToolExecutionResult } from '../types.js';
|
|
5
2
|
import { createSchedule, isValidCronExpression, formatLocalDate, describeCronExpression } from '../../schedule/schedule-store.js';
|
|
3
|
+
import { normalizeScheduleSyntax } from '../../schedule/recurrence-types.js';
|
|
4
|
+
import { validateRruleSetLines } from '../../schedule/recurrence-engine.js';
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
export async function executeScheduleCreate(
|
|
7
|
+
input: Record<string, unknown>,
|
|
8
|
+
_context: ToolContext,
|
|
9
|
+
): Promise<ToolExecutionResult> {
|
|
10
|
+
const name = input.name as string;
|
|
11
|
+
const timezone = (input.timezone as string) ?? null;
|
|
12
|
+
const message = input.message as string;
|
|
13
|
+
const enabled = (input.enabled as boolean) ?? true;
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
type: 'object',
|
|
19
|
-
properties: {
|
|
20
|
-
name: {
|
|
21
|
-
type: 'string',
|
|
22
|
-
description: 'A human-readable name for the scheduled task',
|
|
23
|
-
},
|
|
24
|
-
cron_expression: {
|
|
25
|
-
type: 'string',
|
|
26
|
-
description: 'A cron expression (e.g. "0 9 * * 1-5" for weekdays at 9am). Supports standard 5-field cron syntax.',
|
|
27
|
-
},
|
|
28
|
-
timezone: {
|
|
29
|
-
type: 'string',
|
|
30
|
-
description: 'IANA timezone (e.g. "America/Los_Angeles"). Defaults to system timezone if omitted.',
|
|
31
|
-
},
|
|
32
|
-
message: {
|
|
33
|
-
type: 'string',
|
|
34
|
-
description: 'The message to send to the assistant when the schedule triggers',
|
|
35
|
-
},
|
|
36
|
-
enabled: {
|
|
37
|
-
type: 'boolean',
|
|
38
|
-
description: 'Whether the job is enabled immediately. Defaults to true.',
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
required: ['name', 'cron_expression', 'message'],
|
|
42
|
-
},
|
|
43
|
-
};
|
|
15
|
+
if (!name || typeof name !== 'string') {
|
|
16
|
+
return { content: 'Error: name is required and must be a string', isError: true };
|
|
17
|
+
}
|
|
18
|
+
if (!message || typeof message !== 'string') {
|
|
19
|
+
return { content: 'Error: message is required and must be a string', isError: true };
|
|
44
20
|
}
|
|
45
21
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
22
|
+
// Resolve syntax and expression from new or legacy fields
|
|
23
|
+
const resolved = normalizeScheduleSyntax({
|
|
24
|
+
syntax: input.syntax as 'cron' | 'rrule' | undefined,
|
|
25
|
+
expression: input.expression as string | undefined,
|
|
26
|
+
legacyCronExpression: input.cron_expression as string | undefined,
|
|
27
|
+
});
|
|
52
28
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (!cronExpression || typeof cronExpression !== 'string') {
|
|
57
|
-
return { content: 'Error: cron_expression is required and must be a string', isError: true };
|
|
58
|
-
}
|
|
59
|
-
if (!message || typeof message !== 'string') {
|
|
60
|
-
return { content: 'Error: message is required and must be a string', isError: true };
|
|
61
|
-
}
|
|
62
|
-
if (!isValidCronExpression(cronExpression)) {
|
|
63
|
-
return { content: `Error: Invalid cron expression: "${cronExpression}"`, isError: true };
|
|
64
|
-
}
|
|
29
|
+
if (!resolved) {
|
|
30
|
+
return { content: 'Error: expression (or cron_expression) is required', isError: true };
|
|
31
|
+
}
|
|
65
32
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
33
|
+
// Syntax-specific pre-validation for actionable error messages
|
|
34
|
+
if (resolved.syntax === 'cron' && !isValidCronExpression(resolved.expression)) {
|
|
35
|
+
return { content: `Error: Invalid cron expression: "${resolved.expression}"`, isError: true };
|
|
36
|
+
}
|
|
37
|
+
if (resolved.syntax === 'rrule') {
|
|
38
|
+
if (typeof resolved.expression !== 'string') {
|
|
39
|
+
return { content: 'Error: expression must be a string', isError: true };
|
|
40
|
+
}
|
|
41
|
+
const setError = validateRruleSetLines(resolved.expression);
|
|
42
|
+
if (setError) {
|
|
69
43
|
return {
|
|
70
|
-
content:
|
|
71
|
-
|
|
72
|
-
` Name: ${job.name}`,
|
|
73
|
-
` Schedule: ${describeCronExpression(job.cronExpression)}${job.timezone ? ` (${job.timezone})` : ''}`,
|
|
74
|
-
` Enabled: ${job.enabled}`,
|
|
75
|
-
` Next run: ${nextRunDate}`,
|
|
76
|
-
].join('\n'),
|
|
77
|
-
isError: false,
|
|
44
|
+
content: `Error: ${setError}. Supported line types: DTSTART, RRULE, RDATE, EXDATE, EXRULE.`,
|
|
45
|
+
isError: true,
|
|
78
46
|
};
|
|
79
|
-
} catch (err) {
|
|
80
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
81
|
-
return { content: `Error creating schedule: ${msg}`, isError: true };
|
|
82
47
|
}
|
|
83
48
|
}
|
|
84
|
-
}
|
|
85
49
|
|
|
86
|
-
|
|
50
|
+
try {
|
|
51
|
+
const job = createSchedule({
|
|
52
|
+
name,
|
|
53
|
+
cronExpression: resolved.expression,
|
|
54
|
+
timezone,
|
|
55
|
+
message,
|
|
56
|
+
enabled,
|
|
57
|
+
syntax: resolved.syntax,
|
|
58
|
+
expression: resolved.expression,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const scheduleDescription = job.syntax === 'rrule'
|
|
62
|
+
? job.expression
|
|
63
|
+
: describeCronExpression(job.cronExpression);
|
|
64
|
+
|
|
65
|
+
const nextRunDate = formatLocalDate(job.nextRunAt);
|
|
66
|
+
return {
|
|
67
|
+
content: [
|
|
68
|
+
`Schedule created successfully.`,
|
|
69
|
+
` Name: ${job.name}`,
|
|
70
|
+
` Syntax: ${job.syntax}`,
|
|
71
|
+
` Schedule: ${scheduleDescription}${job.timezone ? ` (${job.timezone})` : ''}`,
|
|
72
|
+
` Enabled: ${job.enabled}`,
|
|
73
|
+
` Next run: ${nextRunDate}`,
|
|
74
|
+
].join('\n'),
|
|
75
|
+
isError: false,
|
|
76
|
+
};
|
|
77
|
+
} catch (err) {
|
|
78
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
79
|
+
return { content: `Error creating schedule: ${msg}`, isError: true };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -1,54 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Tool, ToolContext, ToolExecutionResult } from '../types.js';
|
|
3
|
-
import type { ToolDefinition } from '../../providers/types.js';
|
|
4
|
-
import { registerTool } from '../registry.js';
|
|
1
|
+
import type { ToolContext, ToolExecutionResult } from '../types.js';
|
|
5
2
|
import { deleteSchedule, getSchedule } from '../../schedule/schedule-store.js';
|
|
6
3
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
name: this.name,
|
|
16
|
-
description: this.description,
|
|
17
|
-
input_schema: {
|
|
18
|
-
type: 'object',
|
|
19
|
-
properties: {
|
|
20
|
-
job_id: {
|
|
21
|
-
type: 'string',
|
|
22
|
-
description: 'The ID of the schedule to delete',
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
required: ['job_id'],
|
|
26
|
-
},
|
|
27
|
-
};
|
|
4
|
+
export async function executeScheduleDelete(
|
|
5
|
+
input: Record<string, unknown>,
|
|
6
|
+
_context: ToolContext,
|
|
7
|
+
): Promise<ToolExecutionResult> {
|
|
8
|
+
const jobId = input.job_id as string;
|
|
9
|
+
if (!jobId || typeof jobId !== 'string') {
|
|
10
|
+
return { content: 'Error: job_id is required', isError: true };
|
|
28
11
|
}
|
|
29
12
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// Fetch the job first for the confirmation message
|
|
37
|
-
const job = getSchedule(jobId);
|
|
38
|
-
if (!job) {
|
|
39
|
-
return { content: `Error: Schedule not found: ${jobId}`, isError: true };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const deleted = deleteSchedule(jobId);
|
|
43
|
-
if (!deleted) {
|
|
44
|
-
return { content: `Error: Failed to delete schedule: ${jobId}`, isError: true };
|
|
45
|
-
}
|
|
13
|
+
// Fetch the job first for the confirmation message
|
|
14
|
+
const job = getSchedule(jobId);
|
|
15
|
+
if (!job) {
|
|
16
|
+
return { content: `Error: Schedule not found: ${jobId}`, isError: true };
|
|
17
|
+
}
|
|
46
18
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
};
|
|
19
|
+
const deleted = deleteSchedule(jobId);
|
|
20
|
+
if (!deleted) {
|
|
21
|
+
return { content: `Error: Failed to delete schedule: ${jobId}`, isError: true };
|
|
51
22
|
}
|
|
52
|
-
}
|
|
53
23
|
|
|
54
|
-
|
|
24
|
+
return {
|
|
25
|
+
content: `Schedule deleted: "${job.name}"`,
|
|
26
|
+
isError: false,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -1,88 +1,69 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Tool, ToolContext, ToolExecutionResult } from '../types.js';
|
|
3
|
-
import type { ToolDefinition } from '../../providers/types.js';
|
|
4
|
-
import { registerTool } from '../registry.js';
|
|
1
|
+
import type { ToolContext, ToolExecutionResult } from '../types.js';
|
|
5
2
|
import { listSchedules, getSchedule, getScheduleRuns, formatLocalDate, describeCronExpression } from '../../schedule/schedule-store.js';
|
|
3
|
+
import { hasSetConstructs } from '../../schedule/recurrence-engine.js';
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
defaultRiskLevel = RiskLevel.Low;
|
|
12
|
-
|
|
13
|
-
getDefinition(): ToolDefinition {
|
|
14
|
-
return {
|
|
15
|
-
name: this.name,
|
|
16
|
-
description: this.description,
|
|
17
|
-
input_schema: {
|
|
18
|
-
type: 'object',
|
|
19
|
-
properties: {
|
|
20
|
-
enabled_only: {
|
|
21
|
-
type: 'boolean',
|
|
22
|
-
description: 'When true, only show enabled jobs. Defaults to false.',
|
|
23
|
-
},
|
|
24
|
-
job_id: {
|
|
25
|
-
type: 'string',
|
|
26
|
-
description: 'If provided, show detailed info and recent runs for this specific job.',
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
required: [],
|
|
30
|
-
},
|
|
31
|
-
};
|
|
5
|
+
function describeSchedule(job: { syntax: string; expression: string; cronExpression: string }): string {
|
|
6
|
+
if (job.syntax === 'rrule') {
|
|
7
|
+
const label = hasSetConstructs(job.expression) ? '[RRULE set] ' : '';
|
|
8
|
+
return `${label}${job.expression}`;
|
|
32
9
|
}
|
|
10
|
+
return describeCronExpression(job.cronExpression);
|
|
11
|
+
}
|
|
33
12
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
13
|
+
export async function executeScheduleList(
|
|
14
|
+
input: Record<string, unknown>,
|
|
15
|
+
_context: ToolContext,
|
|
16
|
+
): Promise<ToolExecutionResult> {
|
|
17
|
+
const jobId = input.job_id as string | undefined;
|
|
18
|
+
const enabledOnly = (input.enabled_only as boolean) ?? false;
|
|
37
19
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
20
|
+
// Detail mode for a specific job
|
|
21
|
+
if (jobId) {
|
|
22
|
+
const job = getSchedule(jobId);
|
|
23
|
+
if (!job) {
|
|
24
|
+
return { content: `Error: Schedule not found: ${jobId}`, isError: true };
|
|
25
|
+
}
|
|
44
26
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
27
|
+
const runs = getScheduleRuns(jobId, 5);
|
|
28
|
+
const lines = [
|
|
29
|
+
`Schedule: ${job.name}`,
|
|
30
|
+
` Syntax: ${job.syntax}`,
|
|
31
|
+
` Expression: ${job.expression}`,
|
|
32
|
+
` Schedule: ${describeSchedule(job)}${job.timezone ? ` (${job.timezone})` : ''}`,
|
|
33
|
+
` Enabled: ${job.enabled}`,
|
|
34
|
+
` Message: ${job.message}`,
|
|
35
|
+
` Next run: ${formatLocalDate(job.nextRunAt)}`,
|
|
36
|
+
` Last run: ${job.lastRunAt ? formatLocalDate(job.lastRunAt) : 'never'}`,
|
|
37
|
+
` Last status: ${job.lastStatus ?? 'n/a'}`,
|
|
38
|
+
` Retry count: ${job.retryCount}`,
|
|
39
|
+
` Created: ${formatLocalDate(job.createdAt)}`,
|
|
40
|
+
];
|
|
57
41
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
} else {
|
|
65
|
-
lines.push('', 'No runs yet.');
|
|
42
|
+
if (runs.length > 0) {
|
|
43
|
+
lines.push('', `Recent runs (${runs.length}):`);
|
|
44
|
+
for (const run of runs) {
|
|
45
|
+
const dur = run.durationMs != null ? `${run.durationMs}ms` : 'n/a';
|
|
46
|
+
lines.push(` - ${run.status} at ${formatLocalDate(run.startedAt)} (${dur})${run.error ? ` error: ${run.error}` : ''}`);
|
|
66
47
|
}
|
|
67
|
-
|
|
68
|
-
|
|
48
|
+
} else {
|
|
49
|
+
lines.push('', 'No runs yet.');
|
|
69
50
|
}
|
|
70
51
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (jobs.length === 0) {
|
|
74
|
-
return { content: 'No schedules found.', isError: false };
|
|
75
|
-
}
|
|
52
|
+
return { content: lines.join('\n'), isError: false };
|
|
53
|
+
}
|
|
76
54
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
55
|
+
// List mode
|
|
56
|
+
const jobs = listSchedules({ enabledOnly });
|
|
57
|
+
if (jobs.length === 0) {
|
|
58
|
+
return { content: 'No schedules found.', isError: false };
|
|
59
|
+
}
|
|
83
60
|
|
|
84
|
-
|
|
61
|
+
const lines = [`Schedules (${jobs.length}):`];
|
|
62
|
+
for (const job of jobs) {
|
|
63
|
+
const status = job.enabled ? 'enabled' : 'disabled';
|
|
64
|
+
const next = job.enabled ? formatLocalDate(job.nextRunAt) : 'n/a';
|
|
65
|
+
lines.push(` - [${status}] ${job.name} ([${job.syntax}] ${describeSchedule(job)}) — next: ${next}`);
|
|
85
66
|
}
|
|
86
|
-
}
|
|
87
67
|
|
|
88
|
-
|
|
68
|
+
return { content: lines.join('\n'), isError: false };
|
|
69
|
+
}
|
|
@@ -1,97 +1,90 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Tool, ToolContext, ToolExecutionResult } from '../types.js';
|
|
3
|
-
import type { ToolDefinition } from '../../providers/types.js';
|
|
4
|
-
import { registerTool } from '../registry.js';
|
|
1
|
+
import type { ToolContext, ToolExecutionResult } from '../types.js';
|
|
5
2
|
import { updateSchedule, formatLocalDate, describeCronExpression } from '../../schedule/schedule-store.js';
|
|
3
|
+
import { normalizeScheduleSyntax, type ScheduleSyntax } from '../../schedule/recurrence-types.js';
|
|
4
|
+
import { validateRruleSetLines } from '../../schedule/recurrence-engine.js';
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
name: this.name,
|
|
16
|
-
description: this.description,
|
|
17
|
-
input_schema: {
|
|
18
|
-
type: 'object',
|
|
19
|
-
properties: {
|
|
20
|
-
job_id: {
|
|
21
|
-
type: 'string',
|
|
22
|
-
description: 'The ID of the schedule to update',
|
|
23
|
-
},
|
|
24
|
-
name: {
|
|
25
|
-
type: 'string',
|
|
26
|
-
description: 'New name for the job',
|
|
27
|
-
},
|
|
28
|
-
cron_expression: {
|
|
29
|
-
type: 'string',
|
|
30
|
-
description: 'New cron expression',
|
|
31
|
-
},
|
|
32
|
-
timezone: {
|
|
33
|
-
type: 'string',
|
|
34
|
-
description: 'New IANA timezone',
|
|
35
|
-
},
|
|
36
|
-
message: {
|
|
37
|
-
type: 'string',
|
|
38
|
-
description: 'New message to send when triggered',
|
|
39
|
-
},
|
|
40
|
-
enabled: {
|
|
41
|
-
type: 'boolean',
|
|
42
|
-
description: 'Enable or disable the job',
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
required: ['job_id'],
|
|
46
|
-
},
|
|
47
|
-
};
|
|
6
|
+
export async function executeScheduleUpdate(
|
|
7
|
+
input: Record<string, unknown>,
|
|
8
|
+
_context: ToolContext,
|
|
9
|
+
): Promise<ToolExecutionResult> {
|
|
10
|
+
const jobId = input.job_id as string;
|
|
11
|
+
if (!jobId || typeof jobId !== 'string') {
|
|
12
|
+
return { content: 'Error: job_id is required', isError: true };
|
|
48
13
|
}
|
|
49
14
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const updates: Record<string, unknown> = {};
|
|
57
|
-
if (input.name !== undefined) updates.name = input.name;
|
|
58
|
-
if (input.cron_expression !== undefined) updates.cronExpression = input.cron_expression;
|
|
59
|
-
if (input.timezone !== undefined) updates.timezone = input.timezone;
|
|
60
|
-
if (input.message !== undefined) updates.message = input.message;
|
|
61
|
-
if (input.enabled !== undefined) updates.enabled = input.enabled;
|
|
15
|
+
const updates: Record<string, unknown> = {};
|
|
16
|
+
if (input.name !== undefined) updates.name = input.name;
|
|
17
|
+
if (input.timezone !== undefined) updates.timezone = input.timezone;
|
|
18
|
+
if (input.message !== undefined) updates.message = input.message;
|
|
19
|
+
if (input.enabled !== undefined) updates.enabled = input.enabled;
|
|
62
20
|
|
|
63
|
-
|
|
64
|
-
|
|
21
|
+
// Auto-detect syntax when expression changes without explicit syntax
|
|
22
|
+
const hasExpression = input.expression !== undefined || input.cron_expression !== undefined;
|
|
23
|
+
if (hasExpression || input.syntax !== undefined) {
|
|
24
|
+
const resolved = normalizeScheduleSyntax({
|
|
25
|
+
syntax: input.syntax as 'cron' | 'rrule' | undefined,
|
|
26
|
+
expression: input.expression as string | undefined,
|
|
27
|
+
legacyCronExpression: input.cron_expression as string | undefined,
|
|
28
|
+
});
|
|
29
|
+
if (resolved) {
|
|
30
|
+
updates.syntax = resolved.syntax;
|
|
31
|
+
updates.expression = resolved.expression;
|
|
32
|
+
} else if (input.expression !== undefined) {
|
|
33
|
+
updates.expression = input.expression;
|
|
34
|
+
} else if (input.cron_expression !== undefined) {
|
|
35
|
+
updates.cronExpression = input.cron_expression;
|
|
65
36
|
}
|
|
37
|
+
}
|
|
66
38
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
cronExpression?: string;
|
|
71
|
-
timezone?: string | null;
|
|
72
|
-
message?: string;
|
|
73
|
-
enabled?: boolean;
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
if (!job) {
|
|
77
|
-
return { content: `Error: Schedule not found: ${jobId}`, isError: true };
|
|
78
|
-
}
|
|
39
|
+
if (Object.keys(updates).length === 0) {
|
|
40
|
+
return { content: 'Error: No updates provided. Specify at least one field to update.', isError: true };
|
|
41
|
+
}
|
|
79
42
|
|
|
43
|
+
// Set-aware pre-validation for RRULE expressions
|
|
44
|
+
const effectiveSyntax = updates.syntax as string | undefined;
|
|
45
|
+
const effectiveExpr = (updates.expression as string | undefined) ?? (updates.cronExpression as string | undefined);
|
|
46
|
+
if (effectiveExpr && typeof effectiveExpr === 'string' && (effectiveSyntax === 'rrule' || /^(DTSTART|RRULE:)/m.test(effectiveExpr))) {
|
|
47
|
+
const setError = validateRruleSetLines(effectiveExpr);
|
|
48
|
+
if (setError) {
|
|
80
49
|
return {
|
|
81
|
-
content:
|
|
82
|
-
|
|
83
|
-
` Name: ${job.name}`,
|
|
84
|
-
` Schedule: ${describeCronExpression(job.cronExpression)}${job.timezone ? ` (${job.timezone})` : ''}`,
|
|
85
|
-
` Enabled: ${job.enabled}`,
|
|
86
|
-
` Next run: ${job.enabled ? formatLocalDate(job.nextRunAt) : 'n/a (disabled)'}`,
|
|
87
|
-
].join('\n'),
|
|
88
|
-
isError: false,
|
|
50
|
+
content: `Error: ${setError}. Supported line types: DTSTART, RRULE, RDATE, EXDATE, EXRULE.`,
|
|
51
|
+
isError: true,
|
|
89
52
|
};
|
|
90
|
-
} catch (err) {
|
|
91
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
92
|
-
return { content: `Error updating schedule: ${msg}`, isError: true };
|
|
93
53
|
}
|
|
94
54
|
}
|
|
95
|
-
}
|
|
96
55
|
|
|
97
|
-
|
|
56
|
+
try {
|
|
57
|
+
const job = updateSchedule(jobId, updates as {
|
|
58
|
+
name?: string;
|
|
59
|
+
cronExpression?: string;
|
|
60
|
+
timezone?: string | null;
|
|
61
|
+
message?: string;
|
|
62
|
+
enabled?: boolean;
|
|
63
|
+
syntax?: ScheduleSyntax;
|
|
64
|
+
expression?: string;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
if (!job) {
|
|
68
|
+
return { content: `Error: Schedule not found: ${jobId}`, isError: true };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const scheduleDescription = job.syntax === 'rrule'
|
|
72
|
+
? job.expression
|
|
73
|
+
: describeCronExpression(job.cronExpression);
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
`Schedule updated successfully.`,
|
|
78
|
+
` Name: ${job.name}`,
|
|
79
|
+
` Syntax: ${job.syntax}`,
|
|
80
|
+
` Schedule: ${scheduleDescription}${job.timezone ? ` (${job.timezone})` : ''}`,
|
|
81
|
+
` Enabled: ${job.enabled}`,
|
|
82
|
+
` Next run: ${job.enabled ? formatLocalDate(job.nextRunAt) : 'n/a (disabled)'}`,
|
|
83
|
+
].join('\n'),
|
|
84
|
+
isError: false,
|
|
85
|
+
};
|
|
86
|
+
} catch (err) {
|
|
87
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
88
|
+
return { content: `Error updating schedule: ${msg}`, isError: true };
|
|
89
|
+
}
|
|
90
|
+
}
|