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,779 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Task Tool Provider
|
|
3
|
+
*
|
|
4
|
+
* Single tool provider for all task backends. Provides:
|
|
5
|
+
* - Core CRUD tools (always available): create_task, get_task, list_tasks, assign_task
|
|
6
|
+
* - OpenTasks graph tools (when client available): task, link, annotate
|
|
7
|
+
*
|
|
8
|
+
* Replaces the separate InMemoryTaskToolProvider and OpenTasksTaskToolProvider.
|
|
9
|
+
*
|
|
10
|
+
* @module task/backend/unified-tool-provider
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { AgentId } from "../../store/types/index.js";
|
|
14
|
+
import type {
|
|
15
|
+
TaskBackend,
|
|
16
|
+
TaskToolProvider,
|
|
17
|
+
MCPToolDefinition,
|
|
18
|
+
TaskFilter,
|
|
19
|
+
TaskStatus,
|
|
20
|
+
} from "./types.js";
|
|
21
|
+
import type { OpenTasksClient } from "./opentasks/client.js";
|
|
22
|
+
|
|
23
|
+
// =============================================================================
|
|
24
|
+
// Types
|
|
25
|
+
// =============================================================================
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Context needed for tool execution
|
|
29
|
+
*/
|
|
30
|
+
export interface ToolContext {
|
|
31
|
+
/** The agent making the tool call */
|
|
32
|
+
agent_id: AgentId;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Factory function type for getting context
|
|
37
|
+
*/
|
|
38
|
+
export type GetToolContext = () => ToolContext;
|
|
39
|
+
|
|
40
|
+
// =============================================================================
|
|
41
|
+
// UnifiedTaskToolProvider
|
|
42
|
+
// =============================================================================
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* UnifiedTaskToolProvider
|
|
46
|
+
*
|
|
47
|
+
* Provides MCP tools for task operations, backed by:
|
|
48
|
+
* - TaskBackend for core CRUD (create_task, get_task, list_tasks, assign_task)
|
|
49
|
+
* - OpenTasksClient (optional) for graph operations (task, link, annotate)
|
|
50
|
+
*/
|
|
51
|
+
export class UnifiedTaskToolProvider implements TaskToolProvider {
|
|
52
|
+
constructor(
|
|
53
|
+
private readonly backend: TaskBackend,
|
|
54
|
+
private readonly getContext: GetToolContext,
|
|
55
|
+
private readonly openTasksClient?: OpenTasksClient
|
|
56
|
+
) {}
|
|
57
|
+
|
|
58
|
+
getTools(): MCPToolDefinition[] {
|
|
59
|
+
const tools: MCPToolDefinition[] = [
|
|
60
|
+
this.createTaskTool(),
|
|
61
|
+
this.getTaskTool(),
|
|
62
|
+
this.listTasksTool(),
|
|
63
|
+
this.assignTaskTool(),
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
if (this.openTasksClient) {
|
|
67
|
+
tools.push(
|
|
68
|
+
this.taskTool(),
|
|
69
|
+
this.linkTool(),
|
|
70
|
+
this.annotateTool(),
|
|
71
|
+
this.listProvidersTool()
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return tools;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Exclude the built-in create_task and get_task from mcp-server.ts
|
|
80
|
+
* since this provider replaces them.
|
|
81
|
+
*/
|
|
82
|
+
getExcludedTools(): string[] {
|
|
83
|
+
return ["create_task", "get_task"];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
87
|
+
// Core CRUD Tools (backed by TaskBackend)
|
|
88
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
private createTaskTool(): MCPToolDefinition {
|
|
91
|
+
return {
|
|
92
|
+
name: "create_task",
|
|
93
|
+
description: "Create a new task",
|
|
94
|
+
schema: {
|
|
95
|
+
type: "object",
|
|
96
|
+
properties: {
|
|
97
|
+
description: {
|
|
98
|
+
type: "string",
|
|
99
|
+
description: "Task description",
|
|
100
|
+
},
|
|
101
|
+
parent_task: {
|
|
102
|
+
type: "string",
|
|
103
|
+
description: "Parent task ID for subtasks",
|
|
104
|
+
},
|
|
105
|
+
tags: {
|
|
106
|
+
type: "array",
|
|
107
|
+
items: { type: "string" },
|
|
108
|
+
description: "Tags for categorization",
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
required: ["description"],
|
|
112
|
+
},
|
|
113
|
+
handler: async (params: unknown) => {
|
|
114
|
+
const args = params as {
|
|
115
|
+
description: string;
|
|
116
|
+
parent_task?: string;
|
|
117
|
+
tags?: string[];
|
|
118
|
+
};
|
|
119
|
+
const context = this.getContext();
|
|
120
|
+
|
|
121
|
+
const task = await this.backend.create({
|
|
122
|
+
description: args.description,
|
|
123
|
+
created_by: context.agent_id,
|
|
124
|
+
parent_task: args.parent_task,
|
|
125
|
+
tags: args.tags,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
task_id: task.id,
|
|
130
|
+
status: task.status,
|
|
131
|
+
external_id: task.external_id,
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private getTaskTool(): MCPToolDefinition {
|
|
138
|
+
return {
|
|
139
|
+
name: "get_task",
|
|
140
|
+
description: "Get details of a specific task",
|
|
141
|
+
schema: {
|
|
142
|
+
type: "object",
|
|
143
|
+
properties: {
|
|
144
|
+
task_id: {
|
|
145
|
+
type: "string",
|
|
146
|
+
description: "Task ID to look up",
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
required: ["task_id"],
|
|
150
|
+
},
|
|
151
|
+
handler: async (params: unknown) => {
|
|
152
|
+
const args = params as { task_id: string };
|
|
153
|
+
|
|
154
|
+
const task = await this.backend.get(args.task_id);
|
|
155
|
+
if (!task) {
|
|
156
|
+
throw new Error(`Task not found: ${args.task_id}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
id: task.id,
|
|
161
|
+
description: task.description,
|
|
162
|
+
status: task.status,
|
|
163
|
+
isBlocked: task.isBlocked,
|
|
164
|
+
external_id: task.external_id,
|
|
165
|
+
source_location: task.source_location,
|
|
166
|
+
assigned_agent: task.assigned_agent,
|
|
167
|
+
parent_task: task.parent_task,
|
|
168
|
+
blockers: task.blockers ?? [],
|
|
169
|
+
created_at: task.created_at,
|
|
170
|
+
started_at: task.started_at,
|
|
171
|
+
completed_at: task.completed_at,
|
|
172
|
+
outputs: task.outputs,
|
|
173
|
+
artifacts: task.artifacts,
|
|
174
|
+
};
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
private listTasksTool(): MCPToolDefinition {
|
|
180
|
+
const client = this.openTasksClient;
|
|
181
|
+
return {
|
|
182
|
+
name: "list_tasks",
|
|
183
|
+
description:
|
|
184
|
+
"List tasks with optional filtering. Use federated=true to include " +
|
|
185
|
+
"tasks from connected project locations (requires opentasks backend).",
|
|
186
|
+
schema: {
|
|
187
|
+
type: "object",
|
|
188
|
+
properties: {
|
|
189
|
+
status: {
|
|
190
|
+
type: "string",
|
|
191
|
+
enum: ["pending", "assigned", "in_progress", "completed", "failed"],
|
|
192
|
+
description: "Filter by task status",
|
|
193
|
+
},
|
|
194
|
+
assigned_agent: {
|
|
195
|
+
type: "string",
|
|
196
|
+
description: "Filter by assigned agent",
|
|
197
|
+
},
|
|
198
|
+
parent_task: {
|
|
199
|
+
type: "string",
|
|
200
|
+
description: "Filter by parent task",
|
|
201
|
+
},
|
|
202
|
+
root_only: {
|
|
203
|
+
type: "boolean",
|
|
204
|
+
description: "Only return root tasks (no parent)",
|
|
205
|
+
},
|
|
206
|
+
include_blocked: {
|
|
207
|
+
type: "boolean",
|
|
208
|
+
description: "Include blocked tasks (default: true)",
|
|
209
|
+
},
|
|
210
|
+
federated: {
|
|
211
|
+
type: "boolean",
|
|
212
|
+
description:
|
|
213
|
+
"Include tasks from connected project locations (default: false). " +
|
|
214
|
+
"Queries the opentasks daemon for ready tasks across all connected projects.",
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
handler: async (params: unknown) => {
|
|
219
|
+
const args = params as {
|
|
220
|
+
status?: TaskStatus;
|
|
221
|
+
assigned_agent?: string;
|
|
222
|
+
parent_task?: string;
|
|
223
|
+
root_only?: boolean;
|
|
224
|
+
include_blocked?: boolean;
|
|
225
|
+
federated?: boolean;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const filter: TaskFilter = {};
|
|
229
|
+
if (args.status) filter.status = args.status;
|
|
230
|
+
if (args.assigned_agent) filter.assigned_agent = args.assigned_agent;
|
|
231
|
+
if (args.parent_task) filter.parent_task = args.parent_task;
|
|
232
|
+
if (args.root_only) filter.rootTasksOnly = true;
|
|
233
|
+
if (args.include_blocked !== undefined)
|
|
234
|
+
filter.includeBlocked = args.include_blocked;
|
|
235
|
+
|
|
236
|
+
// Local tasks from EventStore
|
|
237
|
+
const localTasks = await this.backend.list(filter);
|
|
238
|
+
const localTaskItems = localTasks.map((t) => ({
|
|
239
|
+
id: t.id,
|
|
240
|
+
description: t.description,
|
|
241
|
+
status: t.status,
|
|
242
|
+
isBlocked: t.isBlocked,
|
|
243
|
+
external_id: t.external_id,
|
|
244
|
+
assigned_agent: t.assigned_agent,
|
|
245
|
+
parent_task: t.parent_task,
|
|
246
|
+
source_location: t.source_location,
|
|
247
|
+
}));
|
|
248
|
+
|
|
249
|
+
// If federated requested and client available, also query daemon
|
|
250
|
+
if (args.federated && client) {
|
|
251
|
+
try {
|
|
252
|
+
const result = await client.taskReady({
|
|
253
|
+
tags: filter.tags,
|
|
254
|
+
assignee: args.assigned_agent,
|
|
255
|
+
});
|
|
256
|
+
if (result.success && result.data) {
|
|
257
|
+
const readyData = result.data as { type: string; items: Array<{ id: string; type: string; title: string; status?: string; priority?: number; archived: boolean }>; total: number };
|
|
258
|
+
// Collect external IDs we already know about
|
|
259
|
+
const knownExternalIds = new Set(
|
|
260
|
+
localTaskItems
|
|
261
|
+
.map((t) => t.external_id)
|
|
262
|
+
.filter(Boolean)
|
|
263
|
+
);
|
|
264
|
+
// Add federated items not already in local list
|
|
265
|
+
for (const item of readyData.items ?? []) {
|
|
266
|
+
if (!knownExternalIds.has(item.id)) {
|
|
267
|
+
localTaskItems.push({
|
|
268
|
+
id: item.id,
|
|
269
|
+
description: item.title,
|
|
270
|
+
status: (item.status ?? "pending") as TaskStatus,
|
|
271
|
+
isBlocked: false,
|
|
272
|
+
external_id: item.id,
|
|
273
|
+
assigned_agent: undefined,
|
|
274
|
+
parent_task: undefined,
|
|
275
|
+
source_location: "federated",
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
} catch {
|
|
281
|
+
// Non-fatal — federated query failed, return local results only
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
tasks: localTaskItems,
|
|
287
|
+
total: localTaskItems.length,
|
|
288
|
+
};
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
private assignTaskTool(): MCPToolDefinition {
|
|
294
|
+
return {
|
|
295
|
+
name: "assign_task",
|
|
296
|
+
description: "Assign a task to an agent",
|
|
297
|
+
schema: {
|
|
298
|
+
type: "object",
|
|
299
|
+
properties: {
|
|
300
|
+
task_id: {
|
|
301
|
+
type: "string",
|
|
302
|
+
description: "Task ID to assign",
|
|
303
|
+
},
|
|
304
|
+
agent_id: {
|
|
305
|
+
type: "string",
|
|
306
|
+
description:
|
|
307
|
+
"Agent ID to assign to (defaults to calling agent if not specified)",
|
|
308
|
+
},
|
|
309
|
+
role: {
|
|
310
|
+
type: "string",
|
|
311
|
+
description: "Optional role for the assignment",
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
required: ["task_id"],
|
|
315
|
+
},
|
|
316
|
+
handler: async (params: unknown) => {
|
|
317
|
+
const args = params as {
|
|
318
|
+
task_id: string;
|
|
319
|
+
agent_id?: string;
|
|
320
|
+
role?: string;
|
|
321
|
+
};
|
|
322
|
+
const context = this.getContext();
|
|
323
|
+
|
|
324
|
+
const agentId = args.agent_id ?? context.agent_id;
|
|
325
|
+
await this.backend.assign(args.task_id, agentId, { role: args.role });
|
|
326
|
+
|
|
327
|
+
return {
|
|
328
|
+
task_id: args.task_id,
|
|
329
|
+
assigned_agent: agentId,
|
|
330
|
+
assigned: true,
|
|
331
|
+
};
|
|
332
|
+
},
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
337
|
+
// OpenTasks Graph Tools (require OpenTasksClient)
|
|
338
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
339
|
+
|
|
340
|
+
private taskTool(): MCPToolDefinition {
|
|
341
|
+
const client = this.openTasksClient!;
|
|
342
|
+
const getContext = this.getContext;
|
|
343
|
+
return {
|
|
344
|
+
name: "task",
|
|
345
|
+
description:
|
|
346
|
+
"Provider-agnostic task lifecycle operations. Routes to the correct " +
|
|
347
|
+
"provider based on task ID or URI. " +
|
|
348
|
+
"Supports: transition (start/complete/block/reopen/close), " +
|
|
349
|
+
"ready (federated across providers), assign, validActions. " +
|
|
350
|
+
"Specify exactly one operation.",
|
|
351
|
+
schema: {
|
|
352
|
+
type: "object",
|
|
353
|
+
properties: {
|
|
354
|
+
transition: {
|
|
355
|
+
type: "object",
|
|
356
|
+
description: "Transition a task's status using a semantic action",
|
|
357
|
+
properties: {
|
|
358
|
+
id: {
|
|
359
|
+
type: "string",
|
|
360
|
+
description: "Task ID or provider URI",
|
|
361
|
+
},
|
|
362
|
+
action: {
|
|
363
|
+
type: "string",
|
|
364
|
+
enum: ["start", "complete", "block", "reopen", "close"],
|
|
365
|
+
description: "Semantic action to apply",
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
required: ["id", "action"],
|
|
369
|
+
},
|
|
370
|
+
ready: {
|
|
371
|
+
type: "object",
|
|
372
|
+
description:
|
|
373
|
+
"Get tasks ready to work on (no active blockers), federated across providers",
|
|
374
|
+
properties: {
|
|
375
|
+
providers: {
|
|
376
|
+
type: "array",
|
|
377
|
+
items: { type: "string" },
|
|
378
|
+
description: "Only query these providers. Omit for all.",
|
|
379
|
+
},
|
|
380
|
+
limit: { type: "number", description: "Max results" },
|
|
381
|
+
tags: {
|
|
382
|
+
type: "array",
|
|
383
|
+
items: { type: "string" },
|
|
384
|
+
description: "Filter by tags",
|
|
385
|
+
},
|
|
386
|
+
priority: {
|
|
387
|
+
type: "number",
|
|
388
|
+
description: "Filter by minimum priority",
|
|
389
|
+
},
|
|
390
|
+
assignee: {
|
|
391
|
+
type: "string",
|
|
392
|
+
description: "Filter by assignee",
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
assign: {
|
|
397
|
+
type: "object",
|
|
398
|
+
description: "Assign a task to an owner",
|
|
399
|
+
properties: {
|
|
400
|
+
id: {
|
|
401
|
+
type: "string",
|
|
402
|
+
description: "Task ID or provider URI",
|
|
403
|
+
},
|
|
404
|
+
assignee: {
|
|
405
|
+
type: "string",
|
|
406
|
+
description: "Assignee identifier (defaults to calling agent)",
|
|
407
|
+
},
|
|
408
|
+
},
|
|
409
|
+
required: ["id"],
|
|
410
|
+
},
|
|
411
|
+
validActions: {
|
|
412
|
+
type: "object",
|
|
413
|
+
description: "Get valid next actions for a task's current state",
|
|
414
|
+
properties: {
|
|
415
|
+
id: {
|
|
416
|
+
type: "string",
|
|
417
|
+
description: "Task ID or provider URI",
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
required: ["id"],
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
handler: async (params: unknown) => {
|
|
425
|
+
const args = params as {
|
|
426
|
+
transition?: { id: string; action: string };
|
|
427
|
+
ready?: {
|
|
428
|
+
providers?: string[];
|
|
429
|
+
limit?: number;
|
|
430
|
+
tags?: string[];
|
|
431
|
+
priority?: number;
|
|
432
|
+
assignee?: string;
|
|
433
|
+
};
|
|
434
|
+
assign?: { id: string; assignee?: string };
|
|
435
|
+
validActions?: { id: string };
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
if (args.transition) {
|
|
439
|
+
const result = await client.taskTransition(
|
|
440
|
+
args.transition.id,
|
|
441
|
+
args.transition.action as
|
|
442
|
+
| "start"
|
|
443
|
+
| "complete"
|
|
444
|
+
| "block"
|
|
445
|
+
| "reopen"
|
|
446
|
+
| "close"
|
|
447
|
+
);
|
|
448
|
+
if (!result.success) {
|
|
449
|
+
throw new Error(result.error ?? "Transition failed");
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Sync the transition back to the EventStore so MAP events are emitted
|
|
453
|
+
// and the TUI task board stays in sync. The opentasks daemon already
|
|
454
|
+
// processed the transition, so syncExternalTransition only updates the
|
|
455
|
+
// EventStore without re-syncing to opentasks.
|
|
456
|
+
if (this.backend.syncExternalTransition) {
|
|
457
|
+
try {
|
|
458
|
+
await this.backend.syncExternalTransition(
|
|
459
|
+
args.transition.id,
|
|
460
|
+
args.transition.action,
|
|
461
|
+
getContext().agent_id,
|
|
462
|
+
);
|
|
463
|
+
} catch (err) {
|
|
464
|
+
console.warn(
|
|
465
|
+
`[UnifiedTaskToolProvider] syncExternalTransition failed for ${args.transition.id}: ${err}`
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
return result.data;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
if (args.ready !== undefined) {
|
|
474
|
+
const result = await client.taskReady(args.ready);
|
|
475
|
+
if (!result.success) {
|
|
476
|
+
throw new Error(result.error ?? "Ready query failed");
|
|
477
|
+
}
|
|
478
|
+
return result.data;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (args.assign) {
|
|
482
|
+
const assignee = args.assign.assignee ?? getContext().agent_id;
|
|
483
|
+
const result = await client.taskAssign(args.assign.id, assignee);
|
|
484
|
+
if (!result.success) {
|
|
485
|
+
throw new Error(result.error ?? "Assignment failed");
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Sync assignment back to EventStore
|
|
489
|
+
if (this.backend.syncExternalTransition) {
|
|
490
|
+
try {
|
|
491
|
+
await this.backend.syncExternalTransition(
|
|
492
|
+
args.assign.id,
|
|
493
|
+
"assign",
|
|
494
|
+
assignee,
|
|
495
|
+
);
|
|
496
|
+
} catch (err) {
|
|
497
|
+
console.warn(
|
|
498
|
+
`[UnifiedTaskToolProvider] syncExternalTransition (assign) failed for ${args.assign.id}: ${err}`
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
return result.data;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (args.validActions) {
|
|
507
|
+
const result = await client.taskValidActions(args.validActions.id);
|
|
508
|
+
if (!result.success) {
|
|
509
|
+
throw new Error(result.error ?? "Valid actions query failed");
|
|
510
|
+
}
|
|
511
|
+
return result.data;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
throw new Error(
|
|
515
|
+
"Specify exactly one operation: transition, ready, assign, or validActions"
|
|
516
|
+
);
|
|
517
|
+
},
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
private linkTool(): MCPToolDefinition {
|
|
522
|
+
const client = this.openTasksClient!;
|
|
523
|
+
return {
|
|
524
|
+
name: "link",
|
|
525
|
+
description:
|
|
526
|
+
"Create or remove a relationship between nodes. " +
|
|
527
|
+
"Supports cross-project references via opentasks:// URIs " +
|
|
528
|
+
"(e.g., opentasks://<location-hash>/i-xxxx). " +
|
|
529
|
+
"Types: blocks, implements, references, related, child-of, " +
|
|
530
|
+
"parent-of, depends-on, discovered-from, duplicates, supersedes.",
|
|
531
|
+
schema: {
|
|
532
|
+
type: "object",
|
|
533
|
+
properties: {
|
|
534
|
+
from_id: {
|
|
535
|
+
type: "string",
|
|
536
|
+
description: "Source node ID or provider URI",
|
|
537
|
+
},
|
|
538
|
+
to_id: {
|
|
539
|
+
type: "string",
|
|
540
|
+
description: "Target node ID or provider URI",
|
|
541
|
+
},
|
|
542
|
+
type: {
|
|
543
|
+
type: "string",
|
|
544
|
+
enum: [
|
|
545
|
+
"blocks",
|
|
546
|
+
"implements",
|
|
547
|
+
"references",
|
|
548
|
+
"related",
|
|
549
|
+
"child-of",
|
|
550
|
+
"parent-of",
|
|
551
|
+
"depends-on",
|
|
552
|
+
"discovered-from",
|
|
553
|
+
"duplicates",
|
|
554
|
+
"supersedes",
|
|
555
|
+
],
|
|
556
|
+
description: "Relationship type",
|
|
557
|
+
},
|
|
558
|
+
remove: {
|
|
559
|
+
type: "boolean",
|
|
560
|
+
description: "Remove the edge instead of creating (default: false)",
|
|
561
|
+
},
|
|
562
|
+
},
|
|
563
|
+
required: ["from_id", "to_id", "type"],
|
|
564
|
+
},
|
|
565
|
+
handler: async (params: unknown) => {
|
|
566
|
+
const args = params as {
|
|
567
|
+
from_id: string;
|
|
568
|
+
to_id: string;
|
|
569
|
+
type: string;
|
|
570
|
+
remove?: boolean;
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
if (args.remove) {
|
|
574
|
+
await client.removeEdge(args.from_id, args.to_id, args.type);
|
|
575
|
+
return {
|
|
576
|
+
from_id: args.from_id,
|
|
577
|
+
to_id: args.to_id,
|
|
578
|
+
type: args.type,
|
|
579
|
+
removed: true,
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
const edge = await client.createEdge(
|
|
584
|
+
args.from_id,
|
|
585
|
+
args.to_id,
|
|
586
|
+
args.type
|
|
587
|
+
);
|
|
588
|
+
return {
|
|
589
|
+
edge_id: edge.id,
|
|
590
|
+
from_id: args.from_id,
|
|
591
|
+
to_id: args.to_id,
|
|
592
|
+
type: args.type,
|
|
593
|
+
created: true,
|
|
594
|
+
};
|
|
595
|
+
},
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
private annotateTool(): MCPToolDefinition {
|
|
600
|
+
const client = this.openTasksClient!;
|
|
601
|
+
const getContext = this.getContext;
|
|
602
|
+
return {
|
|
603
|
+
name: "annotate",
|
|
604
|
+
description:
|
|
605
|
+
"Add feedback to a node, or resolve/dismiss/reopen existing feedback. " +
|
|
606
|
+
"Feedback types: comment, suggestion, request. " +
|
|
607
|
+
"Can anchor to specific line numbers or text.",
|
|
608
|
+
schema: {
|
|
609
|
+
type: "object",
|
|
610
|
+
properties: {
|
|
611
|
+
target_id: {
|
|
612
|
+
type: "string",
|
|
613
|
+
description: "Target node receiving feedback",
|
|
614
|
+
},
|
|
615
|
+
content: {
|
|
616
|
+
type: "string",
|
|
617
|
+
description:
|
|
618
|
+
"Feedback content (markdown). Required for new feedback.",
|
|
619
|
+
},
|
|
620
|
+
feedback_type: {
|
|
621
|
+
type: "string",
|
|
622
|
+
enum: ["comment", "suggestion", "request"],
|
|
623
|
+
description: "Type of feedback (default: comment)",
|
|
624
|
+
},
|
|
625
|
+
line: {
|
|
626
|
+
type: "number",
|
|
627
|
+
description: "Line number to anchor feedback to",
|
|
628
|
+
},
|
|
629
|
+
text: {
|
|
630
|
+
type: "string",
|
|
631
|
+
description: "Text snippet to anchor feedback to",
|
|
632
|
+
},
|
|
633
|
+
from_id: {
|
|
634
|
+
type: "string",
|
|
635
|
+
description:
|
|
636
|
+
"Issue providing the feedback (creates discovered-from link)",
|
|
637
|
+
},
|
|
638
|
+
resolve: {
|
|
639
|
+
type: "string",
|
|
640
|
+
description: "Feedback ID to resolve",
|
|
641
|
+
},
|
|
642
|
+
dismiss: {
|
|
643
|
+
type: "string",
|
|
644
|
+
description: "Feedback ID to dismiss",
|
|
645
|
+
},
|
|
646
|
+
reopen: {
|
|
647
|
+
type: "string",
|
|
648
|
+
description: "Feedback ID to reopen",
|
|
649
|
+
},
|
|
650
|
+
},
|
|
651
|
+
required: ["target_id"],
|
|
652
|
+
},
|
|
653
|
+
handler: async (params: unknown) => {
|
|
654
|
+
const args = params as {
|
|
655
|
+
target_id: string;
|
|
656
|
+
content?: string;
|
|
657
|
+
feedback_type?: "comment" | "suggestion" | "request";
|
|
658
|
+
line?: number;
|
|
659
|
+
text?: string;
|
|
660
|
+
from_id?: string;
|
|
661
|
+
resolve?: string;
|
|
662
|
+
dismiss?: string;
|
|
663
|
+
reopen?: string;
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
if (args.content) {
|
|
667
|
+
// Create new feedback node
|
|
668
|
+
const feedbackNode = await client.createIssue({
|
|
669
|
+
title: args.content.slice(0, 100),
|
|
670
|
+
content: args.content,
|
|
671
|
+
metadata: {
|
|
672
|
+
_node_type: "feedback",
|
|
673
|
+
target_id: args.target_id,
|
|
674
|
+
feedback_type: args.feedback_type ?? "comment",
|
|
675
|
+
from_id: args.from_id,
|
|
676
|
+
anchor_line: args.line,
|
|
677
|
+
anchor_text: args.text,
|
|
678
|
+
_created_by_agent: getContext().agent_id,
|
|
679
|
+
},
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
// Link feedback to target
|
|
683
|
+
if (args.from_id) {
|
|
684
|
+
await client.createEdge(
|
|
685
|
+
args.from_id,
|
|
686
|
+
args.target_id,
|
|
687
|
+
"discovered-from"
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
return {
|
|
692
|
+
feedback_id: feedbackNode.id,
|
|
693
|
+
target_id: args.target_id,
|
|
694
|
+
type: args.feedback_type ?? "comment",
|
|
695
|
+
created: true,
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
if (args.resolve) {
|
|
700
|
+
await client.updateIssue(args.resolve, {
|
|
701
|
+
metadata: { resolved: true, resolved_at: new Date().toISOString() },
|
|
702
|
+
});
|
|
703
|
+
return { feedback_id: args.resolve, resolved: true };
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
if (args.dismiss) {
|
|
707
|
+
await client.updateIssue(args.dismiss, {
|
|
708
|
+
metadata: {
|
|
709
|
+
dismissed: true,
|
|
710
|
+
dismissed_at: new Date().toISOString(),
|
|
711
|
+
},
|
|
712
|
+
});
|
|
713
|
+
return { feedback_id: args.dismiss, dismissed: true };
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
if (args.reopen) {
|
|
717
|
+
await client.updateIssue(args.reopen, {
|
|
718
|
+
metadata: { resolved: false, dismissed: false },
|
|
719
|
+
});
|
|
720
|
+
return { feedback_id: args.reopen, reopened: true };
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
throw new Error(
|
|
724
|
+
"Must provide content (new feedback), resolve, dismiss, or reopen"
|
|
725
|
+
);
|
|
726
|
+
},
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
private listProvidersTool(): MCPToolDefinition {
|
|
731
|
+
const client = this.openTasksClient!;
|
|
732
|
+
return {
|
|
733
|
+
name: "list_providers",
|
|
734
|
+
description:
|
|
735
|
+
"List all registered providers and their capabilities. " +
|
|
736
|
+
"Shows what task systems are connected (native opentasks, external integrations) " +
|
|
737
|
+
"and what operations each supports.",
|
|
738
|
+
schema: {
|
|
739
|
+
type: "object",
|
|
740
|
+
properties: {},
|
|
741
|
+
},
|
|
742
|
+
handler: async () => {
|
|
743
|
+
const providers = await client.listProviders();
|
|
744
|
+
return {
|
|
745
|
+
providers: providers.map((p) => ({
|
|
746
|
+
name: p.name,
|
|
747
|
+
schemes: p.schemes,
|
|
748
|
+
is_default: p.isDefault,
|
|
749
|
+
capabilities: p.capabilities,
|
|
750
|
+
task_capabilities: p.taskCapabilities
|
|
751
|
+
? {
|
|
752
|
+
actions: p.taskCapabilities.actions,
|
|
753
|
+
supports_assignment: p.taskCapabilities.supportsAssignment,
|
|
754
|
+
supports_ready_query: p.taskCapabilities.supportsReadyQuery,
|
|
755
|
+
status_model: p.taskCapabilities.statusModel,
|
|
756
|
+
}
|
|
757
|
+
: undefined,
|
|
758
|
+
})),
|
|
759
|
+
total: providers.length,
|
|
760
|
+
};
|
|
761
|
+
},
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// =============================================================================
|
|
767
|
+
// Factory
|
|
768
|
+
// =============================================================================
|
|
769
|
+
|
|
770
|
+
/**
|
|
771
|
+
* Create a UnifiedTaskToolProvider
|
|
772
|
+
*/
|
|
773
|
+
export function createUnifiedToolProvider(
|
|
774
|
+
backend: TaskBackend,
|
|
775
|
+
getContext: GetToolContext,
|
|
776
|
+
openTasksClient?: OpenTasksClient
|
|
777
|
+
): UnifiedTaskToolProvider {
|
|
778
|
+
return new UnifiedTaskToolProvider(backend, getContext, openTasksClient);
|
|
779
|
+
}
|