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,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Tool, ToolContext, ToolExecutionResult } from '../types.js';
|
|
3
|
-
import type { ToolDefinition } from '../../providers/types.js';
|
|
1
|
+
import type { ToolContext, ToolExecutionResult } from '../types.js';
|
|
4
2
|
import { getTask, listTasks, createTask } from '../../tasks/task-store.js';
|
|
5
|
-
import {
|
|
3
|
+
import { createWorkItemWithPermissions, findActiveWorkItemsByTitle, updateWorkItem, identifyEntityById, buildWorkItemMismatchError } from '../../work-items/work-item-store.js';
|
|
4
|
+
import { sanitizeToolList } from '../../tasks/tool-sanitizer.js';
|
|
6
5
|
import { getLogger } from '../../util/logger.js';
|
|
7
6
|
|
|
8
7
|
const log = getLogger('task-list-add');
|
|
@@ -13,237 +12,114 @@ const PRIORITY_LABELS: Record<number, string> = {
|
|
|
13
12
|
2: 'low',
|
|
14
13
|
};
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
type: 'string',
|
|
34
|
-
description:
|
|
35
|
-
'Title for the work item. When provided WITHOUT task_id or task_name, creates an ad-hoc work item directly (a lightweight task template is auto-created behind the scenes). When provided WITH task_id or task_name, overrides the task definition title.',
|
|
36
|
-
},
|
|
37
|
-
notes: {
|
|
38
|
-
type: 'string',
|
|
39
|
-
description: 'Notes to attach to the work item.',
|
|
40
|
-
},
|
|
41
|
-
priority_tier: {
|
|
42
|
-
type: 'number',
|
|
43
|
-
description: '0 = high, 1 = medium (default), 2 = low.',
|
|
44
|
-
},
|
|
45
|
-
sort_index: {
|
|
46
|
-
type: 'number',
|
|
47
|
-
description: 'Manual sort order within the priority tier.',
|
|
48
|
-
},
|
|
49
|
-
if_exists: {
|
|
50
|
-
type: 'string',
|
|
51
|
-
enum: ['create_duplicate', 'reuse_existing', 'update_existing'],
|
|
52
|
-
description:
|
|
53
|
-
'What to do if an active work item with the same title already exists. Defaults to "reuse_existing".',
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
class TaskListAddTool implements Tool {
|
|
60
|
-
name = 'task_list_add';
|
|
61
|
-
description = definition.description;
|
|
62
|
-
category = 'tasks';
|
|
63
|
-
defaultRiskLevel = RiskLevel.Low;
|
|
64
|
-
|
|
65
|
-
getDefinition(): ToolDefinition {
|
|
66
|
-
return definition;
|
|
15
|
+
function handleDuplicate(
|
|
16
|
+
title: string,
|
|
17
|
+
ifExists: string,
|
|
18
|
+
input: Record<string, unknown>,
|
|
19
|
+
): ToolExecutionResult | null {
|
|
20
|
+
const existing = findActiveWorkItemsByTitle(title);
|
|
21
|
+
if (existing.length === 0) return null;
|
|
22
|
+
|
|
23
|
+
const match = existing[0];
|
|
24
|
+
log.info({ title, existingId: match.id, ifExists }, 'task_list_add: duplicate detected');
|
|
25
|
+
|
|
26
|
+
if (ifExists === 'reuse_existing') {
|
|
27
|
+
log.info({ title, existingId: match.id }, 'task_list_add: reused existing item');
|
|
28
|
+
return {
|
|
29
|
+
content: `Task "${match.title}" already exists in the queue (ID: ${match.id}, status: ${match.status}). Use task_list_update to modify it.`,
|
|
30
|
+
isError: false,
|
|
31
|
+
};
|
|
67
32
|
}
|
|
68
33
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
ifExists: string,
|
|
77
|
-
input: Record<string, unknown>,
|
|
78
|
-
): ToolExecutionResult | null {
|
|
79
|
-
const existing = findActiveWorkItemsByTitle(title);
|
|
80
|
-
if (existing.length === 0) return null;
|
|
81
|
-
|
|
82
|
-
const match = existing[0];
|
|
83
|
-
log.info({ title, existingId: match.id, ifExists }, 'task_list_add: duplicate detected');
|
|
84
|
-
|
|
85
|
-
if (ifExists === 'reuse_existing') {
|
|
86
|
-
log.info({ title, existingId: match.id }, 'task_list_add: reused existing item');
|
|
87
|
-
return {
|
|
88
|
-
content: `Task "${match.title}" already exists in the queue (ID: ${match.id}, status: ${match.status}). Use task_list_update to modify it.`,
|
|
89
|
-
isError: false,
|
|
90
|
-
};
|
|
34
|
+
if (ifExists === 'update_existing') {
|
|
35
|
+
const updates: Partial<{ title: string; notes: string; priorityTier: number; sortIndex: number }> = {};
|
|
36
|
+
if (input.priority_tier !== undefined) updates.priorityTier = input.priority_tier as number;
|
|
37
|
+
if (input.notes !== undefined) updates.notes = input.notes as string;
|
|
38
|
+
if (input.sort_index !== undefined) updates.sortIndex = input.sort_index as number;
|
|
39
|
+
if (Object.keys(updates).length > 0) {
|
|
40
|
+
updateWorkItem(match.id, updates);
|
|
91
41
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
updateWorkItem(match.id, updates);
|
|
100
|
-
}
|
|
101
|
-
log.info({ title, existingId: match.id, updates }, 'task_list_add: updated existing item');
|
|
102
|
-
return {
|
|
103
|
-
content: `Reused existing task "${match.title}" (ID: ${match.id}) instead of creating a duplicate.${
|
|
104
|
-
Object.keys(updates).length > 0 ? ` Updated: ${Object.keys(updates).join(', ')}.` : ''
|
|
105
|
-
}`,
|
|
106
|
-
isError: false,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return null;
|
|
42
|
+
log.info({ title, existingId: match.id, updates }, 'task_list_add: updated existing item');
|
|
43
|
+
return {
|
|
44
|
+
content: `Reused existing task "${match.title}" (ID: ${match.id}) instead of creating a duplicate.${
|
|
45
|
+
Object.keys(updates).length > 0 ? ` Updated: ${Object.keys(updates).join(', ')}.` : ''
|
|
46
|
+
}`,
|
|
47
|
+
isError: false,
|
|
48
|
+
};
|
|
111
49
|
}
|
|
112
50
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const taskId = input.task_id as string | undefined;
|
|
116
|
-
const taskName = input.task_name as string | undefined;
|
|
117
|
-
const titleOverride = input.title as string | undefined;
|
|
118
|
-
const notes = input.notes as string | undefined;
|
|
119
|
-
const priorityTier = input.priority_tier as number | undefined;
|
|
120
|
-
const sortIndex = input.sort_index as number | undefined;
|
|
121
|
-
|
|
122
|
-
const ifExists = (input.if_exists as string) || 'reuse_existing';
|
|
123
|
-
|
|
124
|
-
// Ad-hoc mode: title provided without task_id or task_name
|
|
125
|
-
if (!taskId && !taskName) {
|
|
126
|
-
if (!titleOverride) {
|
|
127
|
-
return {
|
|
128
|
-
content: 'Error: You must provide either task_id, task_name, or title to create a work item.',
|
|
129
|
-
isError: true,
|
|
130
|
-
};
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Duplicate-prevention guard
|
|
134
|
-
if (ifExists !== 'create_duplicate') {
|
|
135
|
-
const duplicateResult = this.handleDuplicate(titleOverride, ifExists, input);
|
|
136
|
-
if (duplicateResult) return duplicateResult;
|
|
137
|
-
} else {
|
|
138
|
-
log.info({ title: titleOverride }, 'task_list_add: creating duplicate (if_exists=create_duplicate)');
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
log.debug({ title: titleOverride }, 'task_list_add: creating new item');
|
|
142
|
-
|
|
143
|
-
// Auto-create a lightweight task template for the ad-hoc item
|
|
144
|
-
const adHocTask = createTask({
|
|
145
|
-
title: titleOverride,
|
|
146
|
-
template: titleOverride,
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
const workItem = createWorkItem({
|
|
150
|
-
taskId: adHocTask.id,
|
|
151
|
-
title: titleOverride,
|
|
152
|
-
notes,
|
|
153
|
-
priorityTier: priorityTier ?? 1,
|
|
154
|
-
sortIndex,
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
log.info({ selectorType: 'title', workItemId: workItem.id, title: workItem.title }, 'ad-hoc work item created');
|
|
158
|
-
|
|
159
|
-
const priority = PRIORITY_LABELS[workItem.priorityTier] ?? `tier ${workItem.priorityTier}`;
|
|
160
|
-
const lines = [
|
|
161
|
-
`Enqueued work item:`,
|
|
162
|
-
` Title: ${workItem.title}`,
|
|
163
|
-
` ID: ${workItem.id}`,
|
|
164
|
-
` Priority: ${priority}`,
|
|
165
|
-
` Status: ${workItem.status}`,
|
|
166
|
-
];
|
|
167
|
-
if (workItem.notes) {
|
|
168
|
-
lines.push(` Notes: ${workItem.notes}`);
|
|
169
|
-
}
|
|
170
|
-
if (workItem.sortIndex !== null) {
|
|
171
|
-
lines.push(` Sort index: ${workItem.sortIndex}`);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
return { content: lines.join('\n'), isError: false };
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
let resolvedTask;
|
|
178
|
-
|
|
179
|
-
if (taskId) {
|
|
180
|
-
resolvedTask = getTask(taskId);
|
|
181
|
-
if (!resolvedTask) {
|
|
182
|
-
const entity = identifyEntityById(taskId);
|
|
183
|
-
if (entity.type === 'work_item') {
|
|
184
|
-
return {
|
|
185
|
-
content: `Error: ${buildWorkItemMismatchError(taskId, entity.title!, 'task_list_update to modify the existing work item, or task_list_add with just a title for a new ad-hoc item')}`,
|
|
186
|
-
isError: true,
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
return { content: `Error: No task definition found with ID "${taskId}". Use task_list to see available task templates, or provide just a title to create an ad-hoc work item.`, isError: true };
|
|
190
|
-
}
|
|
191
|
-
} else {
|
|
192
|
-
// Search by name (case-insensitive substring match)
|
|
193
|
-
const needle = taskName!.toLowerCase();
|
|
194
|
-
const allTasks = listTasks();
|
|
195
|
-
const matches = allTasks.filter((t) => t.title.toLowerCase().includes(needle));
|
|
196
|
-
|
|
197
|
-
if (matches.length === 0) {
|
|
198
|
-
return {
|
|
199
|
-
content: `Error: No task definition found matching "${taskName}". Use task_list to see available tasks.`,
|
|
200
|
-
isError: true,
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (matches.length > 1) {
|
|
205
|
-
const lines = [
|
|
206
|
-
`Multiple task definitions match "${taskName}". Please specify by ID:`,
|
|
207
|
-
'',
|
|
208
|
-
];
|
|
209
|
-
for (const m of matches) {
|
|
210
|
-
lines.push(`- ${m.title} (ID: ${m.id})`);
|
|
211
|
-
}
|
|
212
|
-
return { content: lines.join('\n'), isError: true };
|
|
213
|
-
}
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
214
53
|
|
|
215
|
-
|
|
54
|
+
export async function executeTaskListAdd(
|
|
55
|
+
input: Record<string, unknown>,
|
|
56
|
+
_context: ToolContext,
|
|
57
|
+
): Promise<ToolExecutionResult> {
|
|
58
|
+
try {
|
|
59
|
+
const taskId = input.task_id as string | undefined;
|
|
60
|
+
const taskName = input.task_name as string | undefined;
|
|
61
|
+
const titleOverride = input.title as string | undefined;
|
|
62
|
+
const executionPrompt = input.execution_prompt as string | undefined;
|
|
63
|
+
const notes = input.notes as string | undefined;
|
|
64
|
+
const priorityTier = input.priority_tier as number | undefined;
|
|
65
|
+
const sortIndex = input.sort_index as number | undefined;
|
|
66
|
+
const rawRequiredTools = input.required_tools as string[] | undefined;
|
|
67
|
+
|
|
68
|
+
const ifExists = (input.if_exists as string) || 'reuse_existing';
|
|
69
|
+
|
|
70
|
+
// Sanitize explicit required_tools if provided (including empty array)
|
|
71
|
+
const hasExplicitTools = rawRequiredTools !== undefined;
|
|
72
|
+
const sanitizedTools = hasExplicitTools ? sanitizeToolList(rawRequiredTools) : undefined;
|
|
73
|
+
|
|
74
|
+
// Ad-hoc mode: title provided without task_id or task_name
|
|
75
|
+
if (!taskId && !taskName) {
|
|
76
|
+
if (!titleOverride) {
|
|
77
|
+
return {
|
|
78
|
+
content: 'Error: You must provide either task_id, task_name, or title to create a work item.',
|
|
79
|
+
isError: true,
|
|
80
|
+
};
|
|
216
81
|
}
|
|
217
82
|
|
|
218
|
-
const finalTitle = titleOverride ?? resolvedTask.title;
|
|
219
|
-
|
|
220
83
|
// Duplicate-prevention guard
|
|
221
84
|
if (ifExists !== 'create_duplicate') {
|
|
222
|
-
const duplicateResult =
|
|
85
|
+
const duplicateResult = handleDuplicate(titleOverride, ifExists, input);
|
|
223
86
|
if (duplicateResult) return duplicateResult;
|
|
224
87
|
} else {
|
|
225
|
-
log.info({ title:
|
|
88
|
+
log.info({ title: titleOverride }, 'task_list_add: creating duplicate (if_exists=create_duplicate)');
|
|
226
89
|
}
|
|
227
90
|
|
|
228
|
-
log.debug({ title:
|
|
91
|
+
log.debug({ title: titleOverride }, 'task_list_add: creating new item');
|
|
92
|
+
|
|
93
|
+
// Auto-create a lightweight task template for the ad-hoc item.
|
|
94
|
+
// Use execution_prompt as the template (the actual instruction sent to the
|
|
95
|
+
// model at run time), falling back to notes then title. This preserves
|
|
96
|
+
// detailed instructions (e.g. full file paths) that may be shortened in
|
|
97
|
+
// the display title.
|
|
98
|
+
const adHocTemplate = executionPrompt ?? notes ?? titleOverride;
|
|
99
|
+
const adHocTask = createTask({
|
|
100
|
+
title: titleOverride,
|
|
101
|
+
template: adHocTemplate,
|
|
102
|
+
});
|
|
229
103
|
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
104
|
+
// For ad-hoc items: explicit tools → persist; omitted → null
|
|
105
|
+
const adHocRequiredTools = hasExplicitTools ? JSON.stringify(sanitizedTools) : undefined;
|
|
106
|
+
|
|
107
|
+
const workItem = createWorkItemWithPermissions({
|
|
108
|
+
taskId: adHocTask.id,
|
|
109
|
+
title: titleOverride,
|
|
234
110
|
notes,
|
|
235
111
|
priorityTier: priorityTier ?? 1,
|
|
236
112
|
sortIndex,
|
|
113
|
+
requiredTools: adHocRequiredTools,
|
|
237
114
|
});
|
|
238
115
|
|
|
239
|
-
log.info({ selectorType
|
|
116
|
+
log.info({ selectorType: 'title', workItemId: workItem.id, title: workItem.title }, 'ad-hoc work item created');
|
|
240
117
|
|
|
241
118
|
const priority = PRIORITY_LABELS[workItem.priorityTier] ?? `tier ${workItem.priorityTier}`;
|
|
242
119
|
const lines = [
|
|
243
120
|
`Enqueued work item:`,
|
|
244
121
|
` Title: ${workItem.title}`,
|
|
245
122
|
` ID: ${workItem.id}`,
|
|
246
|
-
` Task definition: ${resolvedTask.title} (${resolvedTask.id})`,
|
|
247
123
|
` Priority: ${priority}`,
|
|
248
124
|
` Status: ${workItem.status}`,
|
|
249
125
|
];
|
|
@@ -255,12 +131,104 @@ class TaskListAddTool implements Tool {
|
|
|
255
131
|
}
|
|
256
132
|
|
|
257
133
|
return { content: lines.join('\n'), isError: false };
|
|
258
|
-
} catch (err) {
|
|
259
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
260
|
-
log.error({ error: msg }, 'enqueue failed');
|
|
261
|
-
return { content: `Error: ${msg}`, isError: true };
|
|
262
134
|
}
|
|
135
|
+
|
|
136
|
+
let resolvedTask;
|
|
137
|
+
|
|
138
|
+
if (taskId) {
|
|
139
|
+
resolvedTask = getTask(taskId);
|
|
140
|
+
if (!resolvedTask) {
|
|
141
|
+
const entity = identifyEntityById(taskId);
|
|
142
|
+
if (entity.type === 'work_item') {
|
|
143
|
+
return {
|
|
144
|
+
content: `Error: ${buildWorkItemMismatchError(taskId, entity.title!, 'task_list_update to modify the existing work item, or task_list_add with just a title for a new ad-hoc item')}`,
|
|
145
|
+
isError: true,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
return { content: `Error: No task definition found with ID "${taskId}". Use task_list to see available task templates, or provide just a title to create an ad-hoc work item.`, isError: true };
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
// Search by name (case-insensitive substring match)
|
|
152
|
+
const needle = taskName!.toLowerCase();
|
|
153
|
+
const allTasks = listTasks();
|
|
154
|
+
const matches = allTasks.filter((t) => t.title.toLowerCase().includes(needle));
|
|
155
|
+
|
|
156
|
+
if (matches.length === 0) {
|
|
157
|
+
return {
|
|
158
|
+
content: `Error: No task definition found matching "${taskName}". Use task_list to see available tasks.`,
|
|
159
|
+
isError: true,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (matches.length > 1) {
|
|
164
|
+
const lines = [
|
|
165
|
+
`Multiple task definitions match "${taskName}". Please specify by ID:`,
|
|
166
|
+
'',
|
|
167
|
+
];
|
|
168
|
+
for (const m of matches) {
|
|
169
|
+
lines.push(`- ${m.title} (ID: ${m.id})`);
|
|
170
|
+
}
|
|
171
|
+
return { content: lines.join('\n'), isError: true };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
resolvedTask = matches[0];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const finalTitle = titleOverride ?? resolvedTask.title;
|
|
178
|
+
|
|
179
|
+
// Duplicate-prevention guard
|
|
180
|
+
if (ifExists !== 'create_duplicate') {
|
|
181
|
+
const duplicateResult = handleDuplicate(finalTitle, ifExists, input);
|
|
182
|
+
if (duplicateResult) return duplicateResult;
|
|
183
|
+
} else {
|
|
184
|
+
log.info({ title: finalTitle }, 'task_list_add: creating duplicate (if_exists=create_duplicate)');
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
log.debug({ title: finalTitle }, 'task_list_add: creating new item');
|
|
188
|
+
|
|
189
|
+
const selectorType = taskId ? 'task_id' : 'task_name';
|
|
190
|
+
|
|
191
|
+
// Snapshot precedence: explicit required_tools > template tools > null
|
|
192
|
+
let resolvedRequiredTools: string | undefined;
|
|
193
|
+
if (hasExplicitTools) {
|
|
194
|
+
resolvedRequiredTools = JSON.stringify(sanitizedTools);
|
|
195
|
+
} else if (resolvedTask.requiredTools) {
|
|
196
|
+
// Snapshot template tools at add time
|
|
197
|
+
const templateTools = sanitizeToolList(JSON.parse(resolvedTask.requiredTools));
|
|
198
|
+
resolvedRequiredTools = JSON.stringify(templateTools);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const workItem = createWorkItemWithPermissions({
|
|
202
|
+
taskId: resolvedTask.id,
|
|
203
|
+
title: finalTitle,
|
|
204
|
+
notes,
|
|
205
|
+
priorityTier: priorityTier ?? 1,
|
|
206
|
+
sortIndex,
|
|
207
|
+
requiredTools: resolvedRequiredTools,
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
log.info({ selectorType, taskId: resolvedTask.id, workItemId: workItem.id, title: workItem.title }, 'work item created from task definition');
|
|
211
|
+
|
|
212
|
+
const priority = PRIORITY_LABELS[workItem.priorityTier] ?? `tier ${workItem.priorityTier}`;
|
|
213
|
+
const lines = [
|
|
214
|
+
`Enqueued work item:`,
|
|
215
|
+
` Title: ${workItem.title}`,
|
|
216
|
+
` ID: ${workItem.id}`,
|
|
217
|
+
` Task definition: ${resolvedTask.title} (${resolvedTask.id})`,
|
|
218
|
+
` Priority: ${priority}`,
|
|
219
|
+
` Status: ${workItem.status}`,
|
|
220
|
+
];
|
|
221
|
+
if (workItem.notes) {
|
|
222
|
+
lines.push(` Notes: ${workItem.notes}`);
|
|
223
|
+
}
|
|
224
|
+
if (workItem.sortIndex !== null) {
|
|
225
|
+
lines.push(` Sort index: ${workItem.sortIndex}`);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return { content: lines.join('\n'), isError: false };
|
|
229
|
+
} catch (err) {
|
|
230
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
231
|
+
log.error({ error: msg }, 'enqueue failed');
|
|
232
|
+
return { content: `Error: ${msg}`, isError: true };
|
|
263
233
|
}
|
|
264
234
|
}
|
|
265
|
-
|
|
266
|
-
export const taskListAddTool = new TaskListAddTool();
|
|
@@ -1,71 +1,41 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Tool, ToolContext, ToolExecutionResult } from '../types.js';
|
|
3
|
-
import type { ToolDefinition } from '../../providers/types.js';
|
|
1
|
+
import type { ToolContext, ToolExecutionResult } from '../types.js';
|
|
4
2
|
import { listWorkItems, type WorkItemStatus } from '../../work-items/work-item-store.js';
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
name = 'task_list_show';
|
|
26
|
-
description = definition.description;
|
|
27
|
-
category = 'tasks';
|
|
28
|
-
defaultRiskLevel = RiskLevel.Low;
|
|
29
|
-
|
|
30
|
-
getDefinition(): ToolDefinition {
|
|
31
|
-
return definition;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async execute(input: Record<string, unknown>, _context: ToolContext): Promise<ToolExecutionResult> {
|
|
35
|
-
try {
|
|
36
|
-
const statusFilter = input.status as string | string[] | undefined;
|
|
37
|
-
|
|
38
|
-
let items;
|
|
39
|
-
if (typeof statusFilter === 'string') {
|
|
40
|
-
items = listWorkItems({ status: statusFilter as WorkItemStatus });
|
|
41
|
-
} else if (Array.isArray(statusFilter)) {
|
|
42
|
-
// listWorkItems only supports a single status filter, so we fetch all
|
|
43
|
-
// and filter client-side when an array is provided
|
|
44
|
-
const allItems = listWorkItems();
|
|
45
|
-
const allowed = new Set(statusFilter);
|
|
46
|
-
items = allItems.filter((item) => allowed.has(item.status));
|
|
47
|
-
} else {
|
|
48
|
-
items = listWorkItems();
|
|
49
|
-
}
|
|
4
|
+
export async function executeTaskListShow(
|
|
5
|
+
input: Record<string, unknown>,
|
|
6
|
+
_context: ToolContext,
|
|
7
|
+
): Promise<ToolExecutionResult> {
|
|
8
|
+
try {
|
|
9
|
+
const statusFilter = input.status as string | string[] | undefined;
|
|
10
|
+
|
|
11
|
+
let items;
|
|
12
|
+
if (typeof statusFilter === 'string') {
|
|
13
|
+
items = listWorkItems({ status: statusFilter as WorkItemStatus });
|
|
14
|
+
} else if (Array.isArray(statusFilter)) {
|
|
15
|
+
// listWorkItems only supports a single status filter, so we fetch all
|
|
16
|
+
// and filter client-side when an array is provided
|
|
17
|
+
const allItems = listWorkItems();
|
|
18
|
+
const allowed = new Set(statusFilter);
|
|
19
|
+
items = allItems.filter((item) => allowed.has(item.status));
|
|
20
|
+
} else {
|
|
21
|
+
items = listWorkItems();
|
|
22
|
+
}
|
|
50
23
|
|
|
51
|
-
|
|
52
|
-
|
|
24
|
+
const count = items.length;
|
|
25
|
+
const filtered = statusFilter !== undefined;
|
|
53
26
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
27
|
+
if (count === 0) {
|
|
28
|
+
const suffix = filtered ? 'no items matching filter.' : 'no tasks queued.';
|
|
29
|
+
return { content: `Opened Tasks window \u2014 ${suffix}`, isError: false };
|
|
30
|
+
}
|
|
58
31
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
32
|
+
const label = filtered
|
|
33
|
+
? `${count} ${Array.isArray(statusFilter) ? 'matching' : statusFilter} item${count === 1 ? '' : 's'}`
|
|
34
|
+
: `${count} item${count === 1 ? '' : 's'}`;
|
|
62
35
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
36
|
+
return { content: `Opened Tasks window (${label}).`, isError: false };
|
|
37
|
+
} catch (err) {
|
|
38
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
39
|
+
return { content: `Error: ${msg}`, isError: true };
|
|
68
40
|
}
|
|
69
41
|
}
|
|
70
|
-
|
|
71
|
-
export const taskListShowTool = new TaskListShowTool();
|