macro-agent 0.1.0 → 0.1.1
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/.claude/settings.local.json +3 -1
- package/.sudocode/specs.jsonl +4 -0
- package/CLAUDE.md +16 -14
- package/README.md +11 -29
- package/dist/acp/macro-agent.d.ts +15 -0
- package/dist/acp/macro-agent.d.ts.map +1 -1
- package/dist/acp/macro-agent.js +131 -35
- package/dist/acp/macro-agent.js.map +1 -1
- package/dist/acp/types.d.ts +32 -1
- package/dist/acp/types.d.ts.map +1 -1
- package/dist/acp/types.js.map +1 -1
- package/dist/agent/agent-manager.d.ts +65 -1
- package/dist/agent/agent-manager.d.ts.map +1 -1
- package/dist/agent/agent-manager.js +464 -183
- package/dist/agent/agent-manager.js.map +1 -1
- package/dist/agent/types.d.ts +1 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/api/server.d.ts +3 -0
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +37 -6
- package/dist/api/server.js.map +1 -1
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +2 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/token.d.ts +41 -0
- package/dist/auth/token.d.ts.map +1 -0
- package/dist/auth/token.js +73 -0
- package/dist/auth/token.js.map +1 -0
- package/dist/cli/acp.d.ts +2 -23
- package/dist/cli/acp.d.ts.map +1 -1
- package/dist/cli/acp.js +127 -61
- package/dist/cli/acp.js.map +1 -1
- package/dist/cli/index.js +147 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp.d.ts +6 -0
- package/dist/cli/mcp.d.ts.map +1 -1
- package/dist/cli/mcp.js +268 -181
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/parse-args.d.ts +20 -0
- package/dist/cli/parse-args.d.ts.map +1 -0
- package/dist/cli/parse-args.js +43 -0
- package/dist/cli/parse-args.js.map +1 -0
- package/dist/cli/stable-instance-id.d.ts +8 -0
- package/dist/cli/stable-instance-id.d.ts.map +1 -0
- package/dist/cli/stable-instance-id.js +14 -0
- package/dist/cli/stable-instance-id.js.map +1 -0
- package/dist/config/project-config.d.ts +74 -7
- package/dist/config/project-config.d.ts.map +1 -1
- package/dist/config/project-config.js +123 -20
- package/dist/config/project-config.js.map +1 -1
- package/dist/map/adapter/acp-over-map.d.ts +17 -0
- package/dist/map/adapter/acp-over-map.d.ts.map +1 -1
- package/dist/map/adapter/acp-over-map.js +384 -23
- package/dist/map/adapter/acp-over-map.js.map +1 -1
- package/dist/map/adapter/connection-manager.d.ts.map +1 -1
- package/dist/map/adapter/connection-manager.js +3 -0
- package/dist/map/adapter/connection-manager.js.map +1 -1
- package/dist/map/adapter/event-log.d.ts +87 -0
- package/dist/map/adapter/event-log.d.ts.map +1 -0
- package/dist/map/adapter/event-log.js +122 -0
- package/dist/map/adapter/event-log.js.map +1 -0
- package/dist/map/adapter/event-translator.js +6 -6
- package/dist/map/adapter/event-translator.js.map +1 -1
- package/dist/map/adapter/extensions/agent-lifecycle.d.ts +82 -0
- package/dist/map/adapter/extensions/agent-lifecycle.d.ts.map +1 -0
- package/dist/map/adapter/extensions/agent-lifecycle.js +164 -0
- package/dist/map/adapter/extensions/agent-lifecycle.js.map +1 -0
- package/dist/map/adapter/extensions/index.d.ts +10 -1
- package/dist/map/adapter/extensions/index.d.ts.map +1 -1
- package/dist/map/adapter/extensions/index.js +34 -0
- package/dist/map/adapter/extensions/index.js.map +1 -1
- package/dist/map/adapter/extensions/mcp-bridge.d.ts +57 -0
- package/dist/map/adapter/extensions/mcp-bridge.d.ts.map +1 -0
- package/dist/map/adapter/extensions/mcp-bridge.js +745 -0
- package/dist/map/adapter/extensions/mcp-bridge.js.map +1 -0
- package/dist/map/adapter/extensions/rename.d.ts +29 -0
- package/dist/map/adapter/extensions/rename.d.ts.map +1 -0
- package/dist/map/adapter/extensions/rename.js +49 -0
- package/dist/map/adapter/extensions/rename.js.map +1 -0
- package/dist/map/adapter/extensions/task.d.ts.map +1 -1
- package/dist/map/adapter/extensions/task.js +10 -0
- package/dist/map/adapter/extensions/task.js.map +1 -1
- package/dist/map/adapter/extensions/update-metadata.d.ts +29 -0
- package/dist/map/adapter/extensions/update-metadata.d.ts.map +1 -0
- package/dist/map/adapter/extensions/update-metadata.js +67 -0
- package/dist/map/adapter/extensions/update-metadata.js.map +1 -0
- package/dist/map/adapter/index.d.ts +2 -1
- package/dist/map/adapter/index.d.ts.map +1 -1
- package/dist/map/adapter/index.js +8 -2
- package/dist/map/adapter/index.js.map +1 -1
- package/dist/map/adapter/interface.d.ts +2 -0
- package/dist/map/adapter/interface.d.ts.map +1 -1
- package/dist/map/adapter/map-adapter.d.ts +3 -0
- package/dist/map/adapter/map-adapter.d.ts.map +1 -1
- package/dist/map/adapter/map-adapter.js +258 -35
- package/dist/map/adapter/map-adapter.js.map +1 -1
- package/dist/map/adapter/subscription-manager.d.ts.map +1 -1
- package/dist/map/adapter/subscription-manager.js +5 -1
- package/dist/map/adapter/subscription-manager.js.map +1 -1
- package/dist/map/adapter/types.d.ts +2 -0
- package/dist/map/adapter/types.d.ts.map +1 -1
- package/dist/mcp/map-client.d.ts +39 -0
- package/dist/mcp/map-client.d.ts.map +1 -0
- package/dist/mcp/map-client.js +129 -0
- package/dist/mcp/map-client.js.map +1 -0
- package/dist/mcp/mcp-server.d.ts +14 -0
- package/dist/mcp/mcp-server.d.ts.map +1 -1
- package/dist/mcp/mcp-server.js +113 -85
- package/dist/mcp/mcp-server.js.map +1 -1
- package/dist/mcp/types.d.ts +9 -1
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/mcp/types.js.map +1 -1
- package/dist/metrics/metrics.js +1 -1
- package/dist/metrics/metrics.js.map +1 -1
- package/dist/roles/capabilities.d.ts +3 -1
- package/dist/roles/capabilities.d.ts.map +1 -1
- package/dist/roles/capabilities.js +17 -7
- package/dist/roles/capabilities.js.map +1 -1
- package/dist/roles/config-loader.d.ts +6 -6
- package/dist/roles/config-loader.d.ts.map +1 -1
- package/dist/roles/config-loader.js +6 -6
- package/dist/roles/config-loader.js.map +1 -1
- package/dist/roles/registry.d.ts +2 -2
- package/dist/roles/registry.js +2 -2
- package/dist/server/combined-server.d.ts +20 -0
- package/dist/server/combined-server.d.ts.map +1 -1
- package/dist/server/combined-server.js +107 -8
- package/dist/server/combined-server.js.map +1 -1
- package/dist/store/event-store.d.ts +2 -1
- package/dist/store/event-store.d.ts.map +1 -1
- package/dist/store/event-store.js +69 -20
- package/dist/store/event-store.js.map +1 -1
- package/dist/store/types/agents.d.ts +18 -0
- package/dist/store/types/agents.d.ts.map +1 -1
- package/dist/store/types/events.d.ts +1 -1
- package/dist/store/types/events.d.ts.map +1 -1
- package/dist/task/backend/index.d.ts +47 -29
- package/dist/task/backend/index.d.ts.map +1 -1
- package/dist/task/backend/index.js +109 -71
- package/dist/task/backend/index.js.map +1 -1
- package/dist/task/backend/memory.d.ts +1 -0
- package/dist/task/backend/memory.d.ts.map +1 -1
- package/dist/task/backend/memory.js +3 -0
- package/dist/task/backend/memory.js.map +1 -1
- package/dist/task/backend/opentasks/backend.d.ts +140 -0
- package/dist/task/backend/opentasks/backend.d.ts.map +1 -0
- package/dist/task/backend/opentasks/backend.js +1023 -0
- package/dist/task/backend/opentasks/backend.js.map +1 -0
- package/dist/task/backend/opentasks/client.d.ts +337 -0
- package/dist/task/backend/opentasks/client.d.ts.map +1 -0
- package/dist/task/backend/opentasks/client.js +225 -0
- package/dist/task/backend/opentasks/client.js.map +1 -0
- package/dist/task/backend/opentasks/daemon-manager.d.ts +89 -0
- package/dist/task/backend/opentasks/daemon-manager.d.ts.map +1 -0
- package/dist/task/backend/opentasks/daemon-manager.js +195 -0
- package/dist/task/backend/opentasks/daemon-manager.js.map +1 -0
- package/dist/task/backend/opentasks/index.d.ts +21 -0
- package/dist/task/backend/opentasks/index.d.ts.map +1 -0
- package/dist/task/backend/opentasks/index.js +21 -0
- package/dist/task/backend/opentasks/index.js.map +1 -0
- package/dist/task/backend/opentasks/mapping.d.ts +48 -0
- package/dist/task/backend/opentasks/mapping.d.ts.map +1 -0
- package/dist/task/backend/opentasks/mapping.js +77 -0
- package/dist/task/backend/opentasks/mapping.js.map +1 -0
- package/dist/task/backend/types.d.ts +33 -53
- package/dist/task/backend/types.d.ts.map +1 -1
- package/dist/task/backend/types.js +7 -11
- package/dist/task/backend/types.js.map +1 -1
- package/dist/task/backend/unified-tool-provider.d.ts +57 -0
- package/dist/task/backend/unified-tool-provider.d.ts.map +1 -0
- package/dist/task/backend/unified-tool-provider.js +623 -0
- package/dist/task/backend/unified-tool-provider.js.map +1 -0
- package/dist/teams/team-loader.d.ts +2 -2
- package/dist/teams/team-loader.js +3 -3
- package/dist/teams/team-loader.js.map +1 -1
- package/dist/teams/team-runtime.d.ts.map +1 -1
- package/dist/teams/team-runtime.js +2 -0
- package/dist/teams/team-runtime.js.map +1 -1
- package/docs/architecture.md +7 -6
- package/docs/configuration.md +26 -62
- package/docs/implementation-details.md +5 -5
- package/docs/implementation-summary.md +17 -17
- package/docs/plan-self-driving-support.md +4 -4
- package/docs/spec-self-driving-support.md +10 -10
- package/docs/team-templates.md +2 -2
- package/docs/teams.md +3 -3
- package/docs/troubleshooting.md +10 -11
- package/package.json +6 -4
- package/src/__tests__/e2e/agent-spawn-visibility.e2e.test.ts +761 -0
- package/src/__tests__/e2e/full-agent-conflict-resolution.e2e.test.ts +2 -2
- package/src/__tests__/e2e/mcp-thin-client-bridge.e2e.test.ts +304 -0
- package/src/__tests__/e2e/mcp-tools-available.e2e.test.ts +324 -0
- package/src/__tests__/e2e/multi-agent.e2e.test.ts +5 -5
- package/src/__tests__/e2e/spawn-session-streaming.e2e.test.ts +563 -0
- package/src/acp/__tests__/integration.test.ts +56 -31
- package/src/acp/__tests__/macro-agent.test.ts +16 -7
- package/src/acp/macro-agent.ts +170 -36
- package/src/acp/types.ts +46 -1
- package/src/agent/__tests__/agent-manager.test.ts +228 -2
- package/src/agent/agent-manager.ts +714 -261
- package/src/agent/types.ts +3 -1
- package/src/api/server.ts +41 -7
- package/src/auth/__tests__/token.test.ts +100 -0
- package/src/auth/index.ts +1 -0
- package/src/auth/token.ts +82 -0
- package/src/cli/__tests__/acp.test.ts +1 -1
- package/src/cli/__tests__/stable-instance-id.test.ts +1 -1
- package/src/cli/acp.ts +130 -72
- package/src/cli/index.ts +120 -14
- package/src/cli/mcp.ts +311 -207
- package/src/cli/parse-args.ts +54 -0
- package/src/cli/stable-instance-id.ts +14 -0
- package/src/config/project-config.ts +190 -27
- package/src/lifecycle/__tests__/cascade-termination.test.ts +1 -1
- package/src/map/adapter/__tests__/acp-over-map-cancel.test.ts +22 -4
- package/src/map/adapter/__tests__/acp-over-map-getmodels.test.ts +355 -0
- package/src/map/adapter/__tests__/acp-over-map-history.test.ts +263 -0
- package/src/map/adapter/__tests__/acp-over-map-persistence.e2e.test.ts +1 -1
- package/src/map/adapter/__tests__/event-broadcast.test.ts +420 -0
- package/src/map/adapter/__tests__/event-log.test.ts +527 -0
- package/src/map/adapter/__tests__/event-translator.test.ts +3 -3
- package/src/map/adapter/__tests__/extensions.test.ts +408 -0
- package/src/map/adapter/__tests__/map-adapter.test.ts +99 -0
- package/src/map/adapter/__tests__/mcp-bridge.test.ts +1187 -0
- package/src/map/adapter/__tests__/multi-client-broadcast.test.ts +711 -0
- package/src/map/adapter/__tests__/websocket-integration.test.ts +218 -0
- package/src/map/adapter/acp-over-map.ts +678 -66
- package/src/map/adapter/connection-manager.ts +3 -0
- package/src/map/adapter/event-log.ts +208 -0
- package/src/map/adapter/event-translator.ts +6 -6
- package/src/map/adapter/extensions/agent-lifecycle.ts +267 -0
- package/src/map/adapter/extensions/index.ts +60 -0
- package/src/map/adapter/extensions/mcp-bridge.ts +995 -0
- package/src/map/adapter/extensions/task.ts +11 -0
- package/src/map/adapter/extensions/update-metadata.ts +126 -0
- package/src/map/adapter/index.ts +28 -0
- package/src/map/adapter/interface.ts +2 -0
- package/src/map/adapter/map-adapter.ts +312 -47
- package/src/map/adapter/subscription-manager.ts +5 -1
- package/src/map/adapter/types.ts +2 -0
- package/src/mcp/__tests__/map-client.test.ts +386 -0
- package/src/mcp/__tests__/mcp-server-thin-client.test.ts +368 -0
- package/src/mcp/__tests__/mcp-server.test.ts +100 -1
- package/src/mcp/map-client.ts +177 -0
- package/src/mcp/mcp-server.ts +191 -100
- package/src/mcp/types.ts +6 -1
- package/src/metrics/metrics.ts +1 -1
- package/src/monitor/__tests__/stale-agent-flow.integration.test.ts +1 -1
- package/src/roles/__tests__/config-loader.test.ts +7 -7
- package/src/roles/capabilities.ts +17 -7
- package/src/roles/config-loader.ts +6 -6
- package/src/roles/registry.ts +2 -2
- package/src/server/__tests__/combined-server.test.ts +94 -21
- package/src/server/combined-server.ts +189 -33
- package/src/steering/__tests__/steering-integration.test.ts +1 -1
- package/src/store/__tests__/event-store.test.ts +196 -1
- package/src/store/__tests__/instance.test.ts +3 -3
- package/src/store/event-store.ts +80 -21
- package/src/store/types/agents.ts +15 -0
- package/src/store/types/events.ts +1 -1
- package/src/task/backend/__tests__/create-task-backend.test.ts +225 -0
- package/src/task/backend/__tests__/e2e/unified-tool-provider-opentasks.e2e.test.ts +524 -0
- package/src/task/backend/__tests__/unified-tool-provider.test.ts +579 -0
- package/src/task/backend/index.ts +156 -106
- package/src/task/backend/memory.ts +4 -0
- package/src/task/backend/opentasks/__tests__/backend.test.ts +968 -0
- package/src/task/backend/opentasks/__tests__/daemon-manager.test.ts +406 -0
- package/src/task/backend/opentasks/__tests__/mapping.test.ts +84 -0
- package/src/task/backend/opentasks/__tests__/opentasks-backend.e2e.test.ts +1338 -0
- package/src/task/backend/opentasks/backend.ts +1323 -0
- package/src/task/backend/opentasks/client.ts +652 -0
- package/src/task/backend/opentasks/daemon-manager.ts +253 -0
- package/src/task/backend/opentasks/index.ts +69 -0
- package/src/task/backend/opentasks/mapping.ts +94 -0
- package/src/task/backend/types.ts +42 -66
- package/src/task/backend/unified-tool-provider.ts +779 -0
- package/src/teams/__tests__/cross-subsystem.integration.test.ts +1 -1
- package/src/teams/team-loader.ts +3 -3
- package/src/teams/team-runtime.ts +2 -0
- package/test_fixtures/README.md +2 -3
- package/test_fixtures/fixtures/index.ts +0 -3
- package/test_fixtures/fixtures/projects/project-with-specs.ts +7 -149
- package/test_fixtures/fixtures/repos/index.ts +1 -3
- package/test_fixtures/fixtures/repos/temp-repo-factory.ts +0 -116
- package/test_fixtures/fixtures/repos/types.ts +0 -11
- package/test_fixtures/harness/__tests__/fixtures.test.ts +10 -102
- package/test_fixtures/harness/__tests__/temp-repo-and-simulator.test.ts +0 -33
- package/test_fixtures/harness/simulator/agent-simulator.ts +4 -4
- package/vitest.config.ts +1 -1
- package/vitest.e2e.config.ts +1 -1
- package/vitest.setup.ts +1 -30
- package/.macro-agent/teams/self-driving/prompts/grinder.md +0 -27
- package/.macro-agent/teams/self-driving/prompts/judge.md +0 -27
- package/.macro-agent/teams/self-driving/prompts/planner.md +0 -33
- package/.macro-agent/teams/self-driving/roles/grinder.yaml +0 -17
- package/.macro-agent/teams/self-driving/roles/judge.yaml +0 -24
- package/.macro-agent/teams/self-driving/roles/planner.yaml +0 -18
- package/.macro-agent/teams/self-driving/team.yaml +0 -103
- package/.macro-agent/teams/structured/prompts/developer.md +0 -26
- package/.macro-agent/teams/structured/prompts/lead.md +0 -25
- package/.macro-agent/teams/structured/prompts/reviewer.md +0 -24
- package/.macro-agent/teams/structured/roles/developer.yaml +0 -12
- package/.macro-agent/teams/structured/roles/lead.yaml +0 -11
- package/.macro-agent/teams/structured/roles/reviewer.yaml +0 -19
- package/.macro-agent/teams/structured/team.yaml +0 -89
- package/docs/sudocode-integration.md +0 -383
- package/src/task/backend/__tests__/backend-parity.test.ts +0 -451
- package/src/task/backend/__tests__/tool-provider-edge-cases.test.ts +0 -430
- package/src/task/backend/__tests__/tool-provider.test.ts +0 -983
- package/src/task/backend/sudocode/__tests__/backend-edge-cases.test.ts +0 -575
- package/src/task/backend/sudocode/__tests__/backend.test.ts +0 -1194
- package/src/task/backend/sudocode/__tests__/client-integration.test.ts +0 -418
- package/src/task/backend/sudocode/__tests__/client.test.ts +0 -345
- package/src/task/backend/sudocode/__tests__/e2e/backend.e2e.test.ts +0 -753
- package/src/task/backend/sudocode/__tests__/e2e/server-client.e2e.test.ts +0 -680
- package/src/task/backend/sudocode/__tests__/e2e-workflow.test.ts +0 -666
- package/src/task/backend/sudocode/__tests__/integration/standalone-client.integration.test.ts +0 -396
- package/src/task/backend/sudocode/__tests__/integration/sudocode-cli.integration.test.ts +0 -328
- package/src/task/backend/sudocode/__tests__/integration/test-utils.ts +0 -175
- package/src/task/backend/sudocode/__tests__/mapping-edge-cases.test.ts +0 -265
- package/src/task/backend/sudocode/__tests__/server-client.test.ts +0 -675
- package/src/task/backend/sudocode/__tests__/sync-policy-edge-cases.test.ts +0 -521
- package/src/task/backend/sudocode/__tests__/sync-policy.test.ts +0 -519
- package/src/task/backend/sudocode/__tests__/tools.test.ts +0 -471
- package/src/task/backend/sudocode/backend.ts +0 -1237
- package/src/task/backend/sudocode/client.ts +0 -515
- package/src/task/backend/sudocode/index.ts +0 -120
- package/src/task/backend/sudocode/mapping.ts +0 -93
- package/src/task/backend/sudocode/server-client.ts +0 -522
- package/src/task/backend/sudocode/standalone-client.ts +0 -623
- package/src/task/backend/sudocode/sync-policy.ts +0 -387
- package/src/task/backend/sudocode/tools.ts +0 -896
- package/src/task/backend/tool-provider.ts +0 -506
- package/test_fixtures/fixtures/sudocode/index.ts +0 -29
- package/test_fixtures/fixtures/sudocode/issues.ts +0 -185
- package/test_fixtures/fixtures/sudocode/specs.ts +0 -159
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for UnifiedTaskToolProvider
|
|
3
|
+
*
|
|
4
|
+
* Covers:
|
|
5
|
+
* - Core CRUD tools (create_task, get_task, list_tasks, assign_task) with in-memory backend
|
|
6
|
+
* - OpenTasks graph tools (task, link, annotate) with mock client
|
|
7
|
+
* - Tool exclusion and conditional tool exposure
|
|
8
|
+
*
|
|
9
|
+
* @module task/backend/__tests__/unified-tool-provider.test
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
13
|
+
import { createEventStore, type EventStore } from "../../../store/event-store.js";
|
|
14
|
+
import { InMemoryTaskBackend, createInMemoryTaskBackend } from "../memory.js";
|
|
15
|
+
import {
|
|
16
|
+
UnifiedTaskToolProvider,
|
|
17
|
+
createUnifiedToolProvider,
|
|
18
|
+
} from "../unified-tool-provider.js";
|
|
19
|
+
import type { OpenTasksClient } from "../opentasks/client.js";
|
|
20
|
+
import type { MCPToolDefinition } from "../types.js";
|
|
21
|
+
|
|
22
|
+
// =============================================================================
|
|
23
|
+
// Helpers
|
|
24
|
+
// =============================================================================
|
|
25
|
+
|
|
26
|
+
const TEST_AGENT_ID = "agent_test123";
|
|
27
|
+
const getContext = () => ({ agent_id: TEST_AGENT_ID });
|
|
28
|
+
|
|
29
|
+
function findTool(
|
|
30
|
+
tools: MCPToolDefinition[],
|
|
31
|
+
name: string
|
|
32
|
+
): MCPToolDefinition | undefined {
|
|
33
|
+
return tools.find((t) => t.name === name);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function createMockOpenTasksClient(): OpenTasksClient {
|
|
37
|
+
return {
|
|
38
|
+
createIssue: vi.fn().mockResolvedValue({ id: "i-abc1", title: "test", status: "open" }),
|
|
39
|
+
getIssue: vi.fn().mockResolvedValue({
|
|
40
|
+
id: "i-abc1",
|
|
41
|
+
type: "issue",
|
|
42
|
+
title: "test",
|
|
43
|
+
content: "body",
|
|
44
|
+
status: "open",
|
|
45
|
+
priority: 2,
|
|
46
|
+
tags: [],
|
|
47
|
+
assignee: null,
|
|
48
|
+
parent_id: null,
|
|
49
|
+
claimed_by: null,
|
|
50
|
+
created_at: "2026-01-01T00:00:00Z",
|
|
51
|
+
updated_at: "2026-01-01T00:00:00Z",
|
|
52
|
+
metadata: {},
|
|
53
|
+
}),
|
|
54
|
+
updateIssue: vi.fn().mockResolvedValue({ id: "i-abc1", title: "test", status: "open" }),
|
|
55
|
+
deleteIssue: vi.fn().mockResolvedValue(undefined),
|
|
56
|
+
listIssues: vi.fn().mockResolvedValue([]),
|
|
57
|
+
getReadyIssues: vi.fn().mockResolvedValue([]),
|
|
58
|
+
createEdge: vi.fn().mockResolvedValue({ id: "e-123", from_id: "i-1", to_id: "i-2", type: "blocks" }),
|
|
59
|
+
removeEdge: vi.fn().mockResolvedValue(undefined),
|
|
60
|
+
getBlockers: vi.fn().mockResolvedValue([]),
|
|
61
|
+
getBlocking: vi.fn().mockResolvedValue([]),
|
|
62
|
+
task: vi.fn().mockResolvedValue({ success: true, data: {} }),
|
|
63
|
+
taskTransition: vi.fn().mockResolvedValue({ success: true, data: { id: "i-1", status: "in_progress" } }),
|
|
64
|
+
taskReady: vi.fn().mockResolvedValue({ success: true, data: { type: "ready", items: [], total: 0 } }),
|
|
65
|
+
taskAssign: vi.fn().mockResolvedValue({ success: true, data: { id: "i-1", assignee: TEST_AGENT_ID } }),
|
|
66
|
+
taskValidActions: vi.fn().mockResolvedValue({ success: true, data: { id: "i-1", actions: ["start", "close"] } }),
|
|
67
|
+
listProviders: vi.fn().mockResolvedValue([]),
|
|
68
|
+
isConnected: vi.fn().mockReturnValue(true),
|
|
69
|
+
connect: vi.fn().mockResolvedValue(undefined),
|
|
70
|
+
disconnect: vi.fn().mockResolvedValue(undefined),
|
|
71
|
+
} as unknown as OpenTasksClient;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// =============================================================================
|
|
75
|
+
// Tests
|
|
76
|
+
// =============================================================================
|
|
77
|
+
|
|
78
|
+
describe("UnifiedTaskToolProvider", () => {
|
|
79
|
+
let eventStore: EventStore;
|
|
80
|
+
let backend: InMemoryTaskBackend;
|
|
81
|
+
|
|
82
|
+
beforeEach(async () => {
|
|
83
|
+
eventStore = await createEventStore({ inMemory: true });
|
|
84
|
+
backend = createInMemoryTaskBackend(eventStore);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
afterEach(async () => {
|
|
88
|
+
await eventStore.close();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
92
|
+
// Tool Exposure
|
|
93
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
94
|
+
|
|
95
|
+
describe("tool exposure", () => {
|
|
96
|
+
it("should expose 4 core tools when no OpenTasks client provided", () => {
|
|
97
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext);
|
|
98
|
+
const tools = provider.getTools();
|
|
99
|
+
|
|
100
|
+
expect(tools).toHaveLength(4);
|
|
101
|
+
expect(tools.map((t) => t.name)).toEqual([
|
|
102
|
+
"create_task",
|
|
103
|
+
"get_task",
|
|
104
|
+
"list_tasks",
|
|
105
|
+
"assign_task",
|
|
106
|
+
]);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should expose 8 tools when OpenTasks client is provided", () => {
|
|
110
|
+
const client = createMockOpenTasksClient();
|
|
111
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext, client);
|
|
112
|
+
const tools = provider.getTools();
|
|
113
|
+
|
|
114
|
+
expect(tools).toHaveLength(8);
|
|
115
|
+
expect(tools.map((t) => t.name)).toEqual([
|
|
116
|
+
"create_task",
|
|
117
|
+
"get_task",
|
|
118
|
+
"list_tasks",
|
|
119
|
+
"assign_task",
|
|
120
|
+
"task",
|
|
121
|
+
"link",
|
|
122
|
+
"annotate",
|
|
123
|
+
"list_providers",
|
|
124
|
+
]);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should exclude built-in create_task and get_task", () => {
|
|
128
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext);
|
|
129
|
+
const excluded = provider.getExcludedTools();
|
|
130
|
+
|
|
131
|
+
expect(excluded).toEqual(["create_task", "get_task"]);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
136
|
+
// Factory
|
|
137
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
138
|
+
|
|
139
|
+
describe("createUnifiedToolProvider", () => {
|
|
140
|
+
it("should create provider without client", () => {
|
|
141
|
+
const provider = createUnifiedToolProvider(backend, getContext);
|
|
142
|
+
expect(provider).toBeInstanceOf(UnifiedTaskToolProvider);
|
|
143
|
+
expect(provider.getTools()).toHaveLength(4);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("should create provider with client", () => {
|
|
147
|
+
const client = createMockOpenTasksClient();
|
|
148
|
+
const provider = createUnifiedToolProvider(backend, getContext, client);
|
|
149
|
+
expect(provider).toBeInstanceOf(UnifiedTaskToolProvider);
|
|
150
|
+
expect(provider.getTools()).toHaveLength(8);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
155
|
+
// Core CRUD Tools (backed by in-memory backend)
|
|
156
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
157
|
+
|
|
158
|
+
describe("create_task", () => {
|
|
159
|
+
it("should create a task via backend", async () => {
|
|
160
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext);
|
|
161
|
+
const tool = findTool(provider.getTools(), "create_task")!;
|
|
162
|
+
|
|
163
|
+
const result = (await tool.handler({
|
|
164
|
+
description: "Test task",
|
|
165
|
+
})) as { task_id: string; status: string };
|
|
166
|
+
|
|
167
|
+
expect(result.task_id).toMatch(/^task_/);
|
|
168
|
+
expect(result.status).toBe("pending");
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("should pass parent_task", async () => {
|
|
172
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext);
|
|
173
|
+
const tool = findTool(provider.getTools(), "create_task")!;
|
|
174
|
+
|
|
175
|
+
// Create parent first
|
|
176
|
+
const parent = await backend.create({
|
|
177
|
+
description: "Parent",
|
|
178
|
+
created_by: TEST_AGENT_ID,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const result = (await tool.handler({
|
|
182
|
+
description: "Child task",
|
|
183
|
+
parent_task: parent.id,
|
|
184
|
+
})) as { task_id: string };
|
|
185
|
+
|
|
186
|
+
const task = await backend.get(result.task_id);
|
|
187
|
+
expect(task?.parent_task).toBe(parent.id);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe("get_task", () => {
|
|
192
|
+
it("should return task details", async () => {
|
|
193
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext);
|
|
194
|
+
const tool = findTool(provider.getTools(), "get_task")!;
|
|
195
|
+
|
|
196
|
+
const task = await backend.create({
|
|
197
|
+
description: "Fetch me",
|
|
198
|
+
created_by: TEST_AGENT_ID,
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const result = (await tool.handler({
|
|
202
|
+
task_id: task.id,
|
|
203
|
+
})) as { id: string; description: string; status: string };
|
|
204
|
+
|
|
205
|
+
expect(result.id).toBe(task.id);
|
|
206
|
+
expect(result.description).toBe("Fetch me");
|
|
207
|
+
expect(result.status).toBe("pending");
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it("should throw for non-existent task", async () => {
|
|
211
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext);
|
|
212
|
+
const tool = findTool(provider.getTools(), "get_task")!;
|
|
213
|
+
|
|
214
|
+
await expect(tool.handler({ task_id: "task_nonexistent" })).rejects.toThrow(
|
|
215
|
+
"Task not found"
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
describe("list_tasks", () => {
|
|
221
|
+
it("should list all tasks", async () => {
|
|
222
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext);
|
|
223
|
+
const tool = findTool(provider.getTools(), "list_tasks")!;
|
|
224
|
+
|
|
225
|
+
await backend.create({ description: "Task 1", created_by: TEST_AGENT_ID });
|
|
226
|
+
await backend.create({ description: "Task 2", created_by: TEST_AGENT_ID });
|
|
227
|
+
|
|
228
|
+
const result = (await tool.handler({})) as {
|
|
229
|
+
tasks: unknown[];
|
|
230
|
+
total: number;
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
expect(result.total).toBe(2);
|
|
234
|
+
expect(result.tasks).toHaveLength(2);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it("should filter by status", async () => {
|
|
238
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext);
|
|
239
|
+
const tool = findTool(provider.getTools(), "list_tasks")!;
|
|
240
|
+
|
|
241
|
+
const task = await backend.create({
|
|
242
|
+
description: "Task 1",
|
|
243
|
+
created_by: TEST_AGENT_ID,
|
|
244
|
+
});
|
|
245
|
+
await backend.assign(task.id, TEST_AGENT_ID);
|
|
246
|
+
await backend.start(task.id);
|
|
247
|
+
|
|
248
|
+
await backend.create({ description: "Task 2", created_by: TEST_AGENT_ID });
|
|
249
|
+
|
|
250
|
+
const result = (await tool.handler({ status: "in_progress" })) as {
|
|
251
|
+
tasks: unknown[];
|
|
252
|
+
total: number;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
expect(result.total).toBe(1);
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
describe("assign_task", () => {
|
|
260
|
+
it("should assign task to calling agent by default", async () => {
|
|
261
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext);
|
|
262
|
+
const tool = findTool(provider.getTools(), "assign_task")!;
|
|
263
|
+
|
|
264
|
+
const task = await backend.create({
|
|
265
|
+
description: "Assign me",
|
|
266
|
+
created_by: TEST_AGENT_ID,
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
const result = (await tool.handler({
|
|
270
|
+
task_id: task.id,
|
|
271
|
+
})) as { assigned_agent: string; assigned: boolean };
|
|
272
|
+
|
|
273
|
+
expect(result.assigned_agent).toBe(TEST_AGENT_ID);
|
|
274
|
+
expect(result.assigned).toBe(true);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it("should assign task to specified agent", async () => {
|
|
278
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext);
|
|
279
|
+
const tool = findTool(provider.getTools(), "assign_task")!;
|
|
280
|
+
|
|
281
|
+
const task = await backend.create({
|
|
282
|
+
description: "Assign me",
|
|
283
|
+
created_by: TEST_AGENT_ID,
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
const result = (await tool.handler({
|
|
287
|
+
task_id: task.id,
|
|
288
|
+
agent_id: "agent_other",
|
|
289
|
+
})) as { assigned_agent: string };
|
|
290
|
+
|
|
291
|
+
expect(result.assigned_agent).toBe("agent_other");
|
|
292
|
+
});
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
296
|
+
// OpenTasks Graph Tools (mock client)
|
|
297
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
298
|
+
|
|
299
|
+
describe("task tool", () => {
|
|
300
|
+
it("should handle transition operation", async () => {
|
|
301
|
+
const client = createMockOpenTasksClient();
|
|
302
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext, client);
|
|
303
|
+
const tool = findTool(provider.getTools(), "task")!;
|
|
304
|
+
|
|
305
|
+
const result = await tool.handler({
|
|
306
|
+
transition: { id: "i-abc1", action: "start" },
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
expect(client.taskTransition).toHaveBeenCalledWith("i-abc1", "start");
|
|
310
|
+
expect(result).toEqual({ id: "i-1", status: "in_progress" });
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it("should handle ready operation", async () => {
|
|
314
|
+
const client = createMockOpenTasksClient();
|
|
315
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext, client);
|
|
316
|
+
const tool = findTool(provider.getTools(), "task")!;
|
|
317
|
+
|
|
318
|
+
const result = await tool.handler({
|
|
319
|
+
ready: { limit: 10 },
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
expect(client.taskReady).toHaveBeenCalledWith({ limit: 10 });
|
|
323
|
+
expect(result).toEqual({ type: "ready", items: [], total: 0 });
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it("should handle assign operation with default agent", async () => {
|
|
327
|
+
const client = createMockOpenTasksClient();
|
|
328
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext, client);
|
|
329
|
+
const tool = findTool(provider.getTools(), "task")!;
|
|
330
|
+
|
|
331
|
+
await tool.handler({
|
|
332
|
+
assign: { id: "i-abc1" },
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
expect(client.taskAssign).toHaveBeenCalledWith("i-abc1", TEST_AGENT_ID);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it("should handle validActions operation", async () => {
|
|
339
|
+
const client = createMockOpenTasksClient();
|
|
340
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext, client);
|
|
341
|
+
const tool = findTool(provider.getTools(), "task")!;
|
|
342
|
+
|
|
343
|
+
const result = await tool.handler({
|
|
344
|
+
validActions: { id: "i-abc1" },
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
expect(client.taskValidActions).toHaveBeenCalledWith("i-abc1");
|
|
348
|
+
expect(result).toEqual({ id: "i-1", actions: ["start", "close"] });
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it("should throw when no operation specified", async () => {
|
|
352
|
+
const client = createMockOpenTasksClient();
|
|
353
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext, client);
|
|
354
|
+
const tool = findTool(provider.getTools(), "task")!;
|
|
355
|
+
|
|
356
|
+
await expect(tool.handler({})).rejects.toThrow(
|
|
357
|
+
"Specify exactly one operation"
|
|
358
|
+
);
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
it("should throw when transition fails", async () => {
|
|
362
|
+
const client = createMockOpenTasksClient();
|
|
363
|
+
(client.taskTransition as ReturnType<typeof vi.fn>).mockResolvedValue({
|
|
364
|
+
success: false,
|
|
365
|
+
error: "Invalid transition",
|
|
366
|
+
});
|
|
367
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext, client);
|
|
368
|
+
const tool = findTool(provider.getTools(), "task")!;
|
|
369
|
+
|
|
370
|
+
await expect(
|
|
371
|
+
tool.handler({ transition: { id: "i-1", action: "start" } })
|
|
372
|
+
).rejects.toThrow("Invalid transition");
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
it("should call syncExternalTransition after successful transition", async () => {
|
|
376
|
+
const client = createMockOpenTasksClient();
|
|
377
|
+
const syncFn = vi.fn().mockResolvedValue(undefined);
|
|
378
|
+
const backendWithSync = {
|
|
379
|
+
...backend,
|
|
380
|
+
syncExternalTransition: syncFn,
|
|
381
|
+
};
|
|
382
|
+
const provider = new UnifiedTaskToolProvider(backendWithSync, getContext, client);
|
|
383
|
+
const tool = findTool(provider.getTools(), "task")!;
|
|
384
|
+
|
|
385
|
+
await tool.handler({
|
|
386
|
+
transition: { id: "i-abc1", action: "complete" },
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
expect(syncFn).toHaveBeenCalledWith("i-abc1", "complete", TEST_AGENT_ID);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it("should call syncExternalTransition after successful assign", async () => {
|
|
393
|
+
const client = createMockOpenTasksClient();
|
|
394
|
+
const syncFn = vi.fn().mockResolvedValue(undefined);
|
|
395
|
+
const backendWithSync = {
|
|
396
|
+
...backend,
|
|
397
|
+
syncExternalTransition: syncFn,
|
|
398
|
+
};
|
|
399
|
+
const provider = new UnifiedTaskToolProvider(backendWithSync, getContext, client);
|
|
400
|
+
const tool = findTool(provider.getTools(), "task")!;
|
|
401
|
+
|
|
402
|
+
await tool.handler({
|
|
403
|
+
assign: { id: "i-abc1" },
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
expect(syncFn).toHaveBeenCalledWith("i-abc1", "assign", TEST_AGENT_ID);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it("should not fail tool call if syncExternalTransition throws", async () => {
|
|
410
|
+
const client = createMockOpenTasksClient();
|
|
411
|
+
const syncFn = vi.fn().mockRejectedValue(new Error("sync error"));
|
|
412
|
+
const backendWithSync = {
|
|
413
|
+
...backend,
|
|
414
|
+
syncExternalTransition: syncFn,
|
|
415
|
+
};
|
|
416
|
+
const provider = new UnifiedTaskToolProvider(backendWithSync, getContext, client);
|
|
417
|
+
const tool = findTool(provider.getTools(), "task")!;
|
|
418
|
+
|
|
419
|
+
// Should not throw even though sync fails
|
|
420
|
+
const result = await tool.handler({
|
|
421
|
+
transition: { id: "i-abc1", action: "start" },
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
expect(result).toBeDefined();
|
|
425
|
+
expect(syncFn).toHaveBeenCalled();
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
describe("link tool", () => {
|
|
430
|
+
it("should create an edge", async () => {
|
|
431
|
+
const client = createMockOpenTasksClient();
|
|
432
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext, client);
|
|
433
|
+
const tool = findTool(provider.getTools(), "link")!;
|
|
434
|
+
|
|
435
|
+
const result = (await tool.handler({
|
|
436
|
+
from_id: "i-1",
|
|
437
|
+
to_id: "i-2",
|
|
438
|
+
type: "blocks",
|
|
439
|
+
})) as { edge_id: string; created: boolean };
|
|
440
|
+
|
|
441
|
+
expect(client.createEdge).toHaveBeenCalledWith("i-1", "i-2", "blocks");
|
|
442
|
+
expect(result.edge_id).toBe("e-123");
|
|
443
|
+
expect(result.created).toBe(true);
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
it("should remove an edge", async () => {
|
|
447
|
+
const client = createMockOpenTasksClient();
|
|
448
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext, client);
|
|
449
|
+
const tool = findTool(provider.getTools(), "link")!;
|
|
450
|
+
|
|
451
|
+
const result = (await tool.handler({
|
|
452
|
+
from_id: "i-1",
|
|
453
|
+
to_id: "i-2",
|
|
454
|
+
type: "blocks",
|
|
455
|
+
remove: true,
|
|
456
|
+
})) as { removed: boolean };
|
|
457
|
+
|
|
458
|
+
expect(client.removeEdge).toHaveBeenCalledWith("i-1", "i-2", "blocks");
|
|
459
|
+
expect(result.removed).toBe(true);
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
describe("annotate tool", () => {
|
|
464
|
+
it("should create feedback", async () => {
|
|
465
|
+
const client = createMockOpenTasksClient();
|
|
466
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext, client);
|
|
467
|
+
const tool = findTool(provider.getTools(), "annotate")!;
|
|
468
|
+
|
|
469
|
+
const result = (await tool.handler({
|
|
470
|
+
target_id: "i-abc1",
|
|
471
|
+
content: "This looks good",
|
|
472
|
+
feedback_type: "comment",
|
|
473
|
+
})) as { feedback_id: string; created: boolean };
|
|
474
|
+
|
|
475
|
+
expect(client.createIssue).toHaveBeenCalledWith(
|
|
476
|
+
expect.objectContaining({
|
|
477
|
+
title: "This looks good",
|
|
478
|
+
content: "This looks good",
|
|
479
|
+
metadata: expect.objectContaining({
|
|
480
|
+
_node_type: "feedback",
|
|
481
|
+
target_id: "i-abc1",
|
|
482
|
+
feedback_type: "comment",
|
|
483
|
+
_created_by_agent: TEST_AGENT_ID,
|
|
484
|
+
}),
|
|
485
|
+
})
|
|
486
|
+
);
|
|
487
|
+
expect(result.feedback_id).toBe("i-abc1");
|
|
488
|
+
expect(result.created).toBe(true);
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
it("should create discovered-from link when from_id provided", async () => {
|
|
492
|
+
const client = createMockOpenTasksClient();
|
|
493
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext, client);
|
|
494
|
+
const tool = findTool(provider.getTools(), "annotate")!;
|
|
495
|
+
|
|
496
|
+
await tool.handler({
|
|
497
|
+
target_id: "i-target",
|
|
498
|
+
content: "Found an issue",
|
|
499
|
+
from_id: "i-source",
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
expect(client.createEdge).toHaveBeenCalledWith(
|
|
503
|
+
"i-source",
|
|
504
|
+
"i-target",
|
|
505
|
+
"discovered-from"
|
|
506
|
+
);
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
it("should resolve feedback", async () => {
|
|
510
|
+
const client = createMockOpenTasksClient();
|
|
511
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext, client);
|
|
512
|
+
const tool = findTool(provider.getTools(), "annotate")!;
|
|
513
|
+
|
|
514
|
+
const result = (await tool.handler({
|
|
515
|
+
target_id: "i-abc1",
|
|
516
|
+
resolve: "f-123",
|
|
517
|
+
})) as { feedback_id: string; resolved: boolean };
|
|
518
|
+
|
|
519
|
+
expect(client.updateIssue).toHaveBeenCalledWith(
|
|
520
|
+
"f-123",
|
|
521
|
+
expect.objectContaining({
|
|
522
|
+
metadata: expect.objectContaining({ resolved: true }),
|
|
523
|
+
})
|
|
524
|
+
);
|
|
525
|
+
expect(result.resolved).toBe(true);
|
|
526
|
+
});
|
|
527
|
+
|
|
528
|
+
it("should dismiss feedback", async () => {
|
|
529
|
+
const client = createMockOpenTasksClient();
|
|
530
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext, client);
|
|
531
|
+
const tool = findTool(provider.getTools(), "annotate")!;
|
|
532
|
+
|
|
533
|
+
const result = (await tool.handler({
|
|
534
|
+
target_id: "i-abc1",
|
|
535
|
+
dismiss: "f-123",
|
|
536
|
+
})) as { feedback_id: string; dismissed: boolean };
|
|
537
|
+
|
|
538
|
+
expect(client.updateIssue).toHaveBeenCalledWith(
|
|
539
|
+
"f-123",
|
|
540
|
+
expect.objectContaining({
|
|
541
|
+
metadata: expect.objectContaining({ dismissed: true }),
|
|
542
|
+
})
|
|
543
|
+
);
|
|
544
|
+
expect(result.dismissed).toBe(true);
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
it("should reopen feedback", async () => {
|
|
548
|
+
const client = createMockOpenTasksClient();
|
|
549
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext, client);
|
|
550
|
+
const tool = findTool(provider.getTools(), "annotate")!;
|
|
551
|
+
|
|
552
|
+
const result = (await tool.handler({
|
|
553
|
+
target_id: "i-abc1",
|
|
554
|
+
reopen: "f-123",
|
|
555
|
+
})) as { feedback_id: string; reopened: boolean };
|
|
556
|
+
|
|
557
|
+
expect(client.updateIssue).toHaveBeenCalledWith(
|
|
558
|
+
"f-123",
|
|
559
|
+
expect.objectContaining({
|
|
560
|
+
metadata: expect.objectContaining({
|
|
561
|
+
resolved: false,
|
|
562
|
+
dismissed: false,
|
|
563
|
+
}),
|
|
564
|
+
})
|
|
565
|
+
);
|
|
566
|
+
expect(result.reopened).toBe(true);
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
it("should throw when no action specified", async () => {
|
|
570
|
+
const client = createMockOpenTasksClient();
|
|
571
|
+
const provider = new UnifiedTaskToolProvider(backend, getContext, client);
|
|
572
|
+
const tool = findTool(provider.getTools(), "annotate")!;
|
|
573
|
+
|
|
574
|
+
await expect(
|
|
575
|
+
tool.handler({ target_id: "i-abc1" })
|
|
576
|
+
).rejects.toThrow("Must provide content");
|
|
577
|
+
});
|
|
578
|
+
});
|
|
579
|
+
});
|