@specforge/cli 0.1.0
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 +781 -0
- package/bin/specforge +21 -0
- package/dist/channel.d.ts +27 -0
- package/dist/channel.d.ts.map +1 -0
- package/dist/channel.js +22 -0
- package/dist/channel.js.map +1 -0
- package/dist/cli/commands/configure.d.ts +16 -0
- package/dist/cli/commands/configure.d.ts.map +1 -0
- package/dist/cli/commands/configure.js +186 -0
- package/dist/cli/commands/configure.js.map +1 -0
- package/dist/cli/commands/configure.types.d.ts +110 -0
- package/dist/cli/commands/configure.types.d.ts.map +1 -0
- package/dist/cli/commands/configure.types.js +82 -0
- package/dist/cli/commands/configure.types.js.map +1 -0
- package/dist/cli/commands/debug/call.d.ts +14 -0
- package/dist/cli/commands/debug/call.d.ts.map +1 -0
- package/dist/cli/commands/debug/call.js +96 -0
- package/dist/cli/commands/debug/call.js.map +1 -0
- package/dist/cli/commands/debug/index.d.ts +12 -0
- package/dist/cli/commands/debug/index.d.ts.map +1 -0
- package/dist/cli/commands/debug/index.js +14 -0
- package/dist/cli/commands/debug/index.js.map +1 -0
- package/dist/cli/commands/debug/register.d.ts +11 -0
- package/dist/cli/commands/debug/register.d.ts.map +1 -0
- package/dist/cli/commands/debug/register.js +78 -0
- package/dist/cli/commands/debug/register.js.map +1 -0
- package/dist/cli/commands/debug/test.d.ts +13 -0
- package/dist/cli/commands/debug/test.d.ts.map +1 -0
- package/dist/cli/commands/debug/test.js +91 -0
- package/dist/cli/commands/debug/test.js.map +1 -0
- package/dist/cli/commands/debug/tools.d.ts +13 -0
- package/dist/cli/commands/debug/tools.d.ts.map +1 -0
- package/dist/cli/commands/debug/tools.js +86 -0
- package/dist/cli/commands/debug/tools.js.map +1 -0
- package/dist/cli/commands/debug/types.d.ts +119 -0
- package/dist/cli/commands/debug/types.d.ts.map +1 -0
- package/dist/cli/commands/debug/types.js +36 -0
- package/dist/cli/commands/debug/types.js.map +1 -0
- package/dist/cli/commands/debug/whoami.d.ts +13 -0
- package/dist/cli/commands/debug/whoami.d.ts.map +1 -0
- package/dist/cli/commands/debug/whoami.js +131 -0
- package/dist/cli/commands/debug/whoami.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +16 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +413 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/doctor.types.d.ts +180 -0
- package/dist/cli/commands/doctor.types.d.ts.map +1 -0
- package/dist/cli/commands/doctor.types.js +140 -0
- package/dist/cli/commands/doctor.types.js.map +1 -0
- package/dist/cli/commands/feedback.d.ts +27 -0
- package/dist/cli/commands/feedback.d.ts.map +1 -0
- package/dist/cli/commands/feedback.js +262 -0
- package/dist/cli/commands/feedback.js.map +1 -0
- package/dist/cli/commands/feedback.types.d.ts +116 -0
- package/dist/cli/commands/feedback.types.d.ts.map +1 -0
- package/dist/cli/commands/feedback.types.js +65 -0
- package/dist/cli/commands/feedback.types.js.map +1 -0
- package/dist/cli/commands/index.d.ts +15 -0
- package/dist/cli/commands/index.d.ts.map +1 -0
- package/dist/cli/commands/index.js +21 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/init.d.ts +17 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +773 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/init.types.d.ts +193 -0
- package/dist/cli/commands/init.types.d.ts.map +1 -0
- package/dist/cli/commands/init.types.js +29 -0
- package/dist/cli/commands/init.types.js.map +1 -0
- package/dist/cli/commands/invitations.d.ts +31 -0
- package/dist/cli/commands/invitations.d.ts.map +1 -0
- package/dist/cli/commands/invitations.js +250 -0
- package/dist/cli/commands/invitations.js.map +1 -0
- package/dist/cli/commands/login.d.ts +40 -0
- package/dist/cli/commands/login.d.ts.map +1 -0
- package/dist/cli/commands/login.js +139 -0
- package/dist/cli/commands/login.js.map +1 -0
- package/dist/cli/commands/members.d.ts +55 -0
- package/dist/cli/commands/members.d.ts.map +1 -0
- package/dist/cli/commands/members.js +296 -0
- package/dist/cli/commands/members.js.map +1 -0
- package/dist/cli/commands/scaffold/agent-types.d.ts +54 -0
- package/dist/cli/commands/scaffold/agent-types.d.ts.map +1 -0
- package/dist/cli/commands/scaffold/agent-types.js +22 -0
- package/dist/cli/commands/scaffold/agent-types.js.map +1 -0
- package/dist/cli/commands/scaffold/display.d.ts +56 -0
- package/dist/cli/commands/scaffold/display.d.ts.map +1 -0
- package/dist/cli/commands/scaffold/display.js +217 -0
- package/dist/cli/commands/scaffold/display.js.map +1 -0
- package/dist/cli/commands/scaffold/files.d.ts +99 -0
- package/dist/cli/commands/scaffold/files.d.ts.map +1 -0
- package/dist/cli/commands/scaffold/files.js +122 -0
- package/dist/cli/commands/scaffold/files.js.map +1 -0
- package/dist/cli/commands/scaffold/index.d.ts +13 -0
- package/dist/cli/commands/scaffold/index.d.ts.map +1 -0
- package/dist/cli/commands/scaffold/index.js +12 -0
- package/dist/cli/commands/scaffold/index.js.map +1 -0
- package/dist/cli/commands/scaffold/register.d.ts +11 -0
- package/dist/cli/commands/scaffold/register.d.ts.map +1 -0
- package/dist/cli/commands/scaffold/register.js +11 -0
- package/dist/cli/commands/scaffold/register.js.map +1 -0
- package/dist/cli/commands/scaffold/scaffold.d.ts +11 -0
- package/dist/cli/commands/scaffold/scaffold.d.ts.map +1 -0
- package/dist/cli/commands/scaffold/scaffold.js +728 -0
- package/dist/cli/commands/scaffold/scaffold.js.map +1 -0
- package/dist/cli/commands/scaffold/targets.d.ts +60 -0
- package/dist/cli/commands/scaffold/targets.d.ts.map +1 -0
- package/dist/cli/commands/scaffold/targets.js +251 -0
- package/dist/cli/commands/scaffold/targets.js.map +1 -0
- package/dist/cli/commands/scaffold/types.d.ts +170 -0
- package/dist/cli/commands/scaffold/types.d.ts.map +1 -0
- package/dist/cli/commands/scaffold/types.js +12 -0
- package/dist/cli/commands/scaffold/types.js.map +1 -0
- package/dist/cli/commands/scaffold/utils.d.ts +89 -0
- package/dist/cli/commands/scaffold/utils.d.ts.map +1 -0
- package/dist/cli/commands/scaffold/utils.js +401 -0
- package/dist/cli/commands/scaffold/utils.js.map +1 -0
- package/dist/cli/commands/status.d.ts +19 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +124 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/status.types.d.ts +37 -0
- package/dist/cli/commands/status.types.d.ts.map +1 -0
- package/dist/cli/commands/status.types.js +7 -0
- package/dist/cli/commands/status.types.js.map +1 -0
- package/dist/cli/commands/switch.d.ts +18 -0
- package/dist/cli/commands/switch.d.ts.map +1 -0
- package/dist/cli/commands/switch.js +134 -0
- package/dist/cli/commands/switch.js.map +1 -0
- package/dist/cli/commands/switch.types.d.ts +123 -0
- package/dist/cli/commands/switch.types.d.ts.map +1 -0
- package/dist/cli/commands/switch.types.js +46 -0
- package/dist/cli/commands/switch.types.js.map +1 -0
- package/dist/cli/config/agent-teams.types.d.ts +120 -0
- package/dist/cli/config/agent-teams.types.d.ts.map +1 -0
- package/dist/cli/config/agent-teams.types.js +23 -0
- package/dist/cli/config/agent-teams.types.js.map +1 -0
- package/dist/cli/config/index.d.ts +13 -0
- package/dist/cli/config/index.d.ts.map +1 -0
- package/dist/cli/config/index.js +7 -0
- package/dist/cli/config/index.js.map +1 -0
- package/dist/cli/config/loader.d.ts +114 -0
- package/dist/cli/config/loader.d.ts.map +1 -0
- package/dist/cli/config/loader.js +198 -0
- package/dist/cli/config/loader.js.map +1 -0
- package/dist/cli/config/paths.d.ts +107 -0
- package/dist/cli/config/paths.d.ts.map +1 -0
- package/dist/cli/config/paths.js +79 -0
- package/dist/cli/config/paths.js.map +1 -0
- package/dist/cli/config/planning-sessions-registry.d.ts +52 -0
- package/dist/cli/config/planning-sessions-registry.d.ts.map +1 -0
- package/dist/cli/config/planning-sessions-registry.js +46 -0
- package/dist/cli/config/planning-sessions-registry.js.map +1 -0
- package/dist/cli/config/types.d.ts +186 -0
- package/dist/cli/config/types.d.ts.map +1 -0
- package/dist/cli/config/types.js +27 -0
- package/dist/cli/config/types.js.map +1 -0
- package/dist/cli/config/validation.d.ts +62 -0
- package/dist/cli/config/validation.d.ts.map +1 -0
- package/dist/cli/config/validation.js +133 -0
- package/dist/cli/config/validation.js.map +1 -0
- package/dist/cli/config/writer.d.ts +153 -0
- package/dist/cli/config/writer.d.ts.map +1 -0
- package/dist/cli/config/writer.js +168 -0
- package/dist/cli/config/writer.js.map +1 -0
- package/dist/cli/index.d.ts +30 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +142 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/middleware/auth-guard.d.ts +107 -0
- package/dist/cli/middleware/auth-guard.d.ts.map +1 -0
- package/dist/cli/middleware/auth-guard.js +97 -0
- package/dist/cli/middleware/auth-guard.js.map +1 -0
- package/dist/cli/middleware/error-handler.d.ts +133 -0
- package/dist/cli/middleware/error-handler.d.ts.map +1 -0
- package/dist/cli/middleware/error-handler.js +139 -0
- package/dist/cli/middleware/error-handler.js.map +1 -0
- package/dist/cli/middleware/index.d.ts +6 -0
- package/dist/cli/middleware/index.d.ts.map +1 -0
- package/dist/cli/middleware/index.js +3 -0
- package/dist/cli/middleware/index.js.map +1 -0
- package/dist/cli/templates/agents/content/core/sfag-orchestrator.d.ts +9 -0
- package/dist/cli/templates/agents/content/core/sfag-orchestrator.d.ts.map +1 -0
- package/dist/cli/templates/agents/content/core/sfag-orchestrator.js +160 -0
- package/dist/cli/templates/agents/content/core/sfag-orchestrator.js.map +1 -0
- package/dist/cli/templates/agents/content/core/sfag-spec-creator.d.ts +9 -0
- package/dist/cli/templates/agents/content/core/sfag-spec-creator.d.ts.map +1 -0
- package/dist/cli/templates/agents/content/core/sfag-spec-creator.js +343 -0
- package/dist/cli/templates/agents/content/core/sfag-spec-creator.js.map +1 -0
- package/dist/cli/templates/agents/content/core/sfag-ticket-implementer.d.ts +9 -0
- package/dist/cli/templates/agents/content/core/sfag-ticket-implementer.d.ts.map +1 -0
- package/dist/cli/templates/agents/content/core/sfag-ticket-implementer.js +254 -0
- package/dist/cli/templates/agents/content/core/sfag-ticket-implementer.js.map +1 -0
- package/dist/cli/templates/agents/content/research/sfag-package-researcher.d.ts +8 -0
- package/dist/cli/templates/agents/content/research/sfag-package-researcher.d.ts.map +1 -0
- package/dist/cli/templates/agents/content/research/sfag-package-researcher.js +128 -0
- package/dist/cli/templates/agents/content/research/sfag-package-researcher.js.map +1 -0
- package/dist/cli/templates/agents/index.d.ts +23 -0
- package/dist/cli/templates/agents/index.d.ts.map +1 -0
- package/dist/cli/templates/agents/index.js +29 -0
- package/dist/cli/templates/agents/index.js.map +1 -0
- package/dist/cli/templates/commands.d.ts +17 -0
- package/dist/cli/templates/commands.d.ts.map +1 -0
- package/dist/cli/templates/commands.js +78 -0
- package/dist/cli/templates/commands.js.map +1 -0
- package/dist/cli/templates/content/sf-blockers.d.ts +7 -0
- package/dist/cli/templates/content/sf-blockers.d.ts.map +1 -0
- package/dist/cli/templates/content/sf-blockers.js +69 -0
- package/dist/cli/templates/content/sf-blockers.js.map +1 -0
- package/dist/cli/templates/content/sf-commit.d.ts +7 -0
- package/dist/cli/templates/content/sf-commit.d.ts.map +1 -0
- package/dist/cli/templates/content/sf-commit.js +79 -0
- package/dist/cli/templates/content/sf-commit.js.map +1 -0
- package/dist/cli/templates/content/sf-context.d.ts +7 -0
- package/dist/cli/templates/content/sf-context.d.ts.map +1 -0
- package/dist/cli/templates/content/sf-context.js +63 -0
- package/dist/cli/templates/content/sf-context.js.map +1 -0
- package/dist/cli/templates/content/sf-help.d.ts +7 -0
- package/dist/cli/templates/content/sf-help.d.ts.map +1 -0
- package/dist/cli/templates/content/sf-help.js +42 -0
- package/dist/cli/templates/content/sf-help.js.map +1 -0
- package/dist/cli/templates/content/sf-init.d.ts +7 -0
- package/dist/cli/templates/content/sf-init.d.ts.map +1 -0
- package/dist/cli/templates/content/sf-init.js +62 -0
- package/dist/cli/templates/content/sf-init.js.map +1 -0
- package/dist/cli/templates/content/sf-reset.d.ts +7 -0
- package/dist/cli/templates/content/sf-reset.d.ts.map +1 -0
- package/dist/cli/templates/content/sf-reset.js +67 -0
- package/dist/cli/templates/content/sf-reset.js.map +1 -0
- package/dist/cli/templates/content/sf-search.d.ts +7 -0
- package/dist/cli/templates/content/sf-search.d.ts.map +1 -0
- package/dist/cli/templates/content/sf-search.js +63 -0
- package/dist/cli/templates/content/sf-search.js.map +1 -0
- package/dist/cli/templates/content/sf-status.d.ts +7 -0
- package/dist/cli/templates/content/sf-status.d.ts.map +1 -0
- package/dist/cli/templates/content/sf-status.js +62 -0
- package/dist/cli/templates/content/sf-status.js.map +1 -0
- package/dist/cli/templates/index.d.ts +8 -0
- package/dist/cli/templates/index.d.ts.map +1 -0
- package/dist/cli/templates/index.js +17 -0
- package/dist/cli/templates/index.js.map +1 -0
- package/dist/cli/ui/banner.d.ts +38 -0
- package/dist/cli/ui/banner.d.ts.map +1 -0
- package/dist/cli/ui/banner.js +89 -0
- package/dist/cli/ui/banner.js.map +1 -0
- package/dist/cli/ui/colors.d.ts +76 -0
- package/dist/cli/ui/colors.d.ts.map +1 -0
- package/dist/cli/ui/colors.js +67 -0
- package/dist/cli/ui/colors.js.map +1 -0
- package/dist/cli/ui/index.d.ts +7 -0
- package/dist/cli/ui/index.d.ts.map +1 -0
- package/dist/cli/ui/index.js +4 -0
- package/dist/cli/ui/index.js.map +1 -0
- package/dist/cli/ui/output.d.ts +117 -0
- package/dist/cli/ui/output.d.ts.map +1 -0
- package/dist/cli/ui/output.js +83 -0
- package/dist/cli/ui/output.js.map +1 -0
- package/dist/cli/ui/spinner.d.ts +120 -0
- package/dist/cli/ui/spinner.d.ts.map +1 -0
- package/dist/cli/ui/spinner.js +158 -0
- package/dist/cli/ui/spinner.js.map +1 -0
- package/dist/cli/ui/time.d.ts +54 -0
- package/dist/cli/ui/time.d.ts.map +1 -0
- package/dist/cli/ui/time.js +119 -0
- package/dist/cli/ui/time.js.map +1 -0
- package/dist/client/api-client.d.ts +123 -0
- package/dist/client/api-client.d.ts.map +1 -0
- package/dist/client/api-client.js +105 -0
- package/dist/client/api-client.js.map +1 -0
- package/dist/client/cli-client.d.ts +26 -0
- package/dist/client/cli-client.d.ts.map +1 -0
- package/dist/client/cli-client.js +20 -0
- package/dist/client/cli-client.js.map +1 -0
- package/dist/config/index.d.ts +78 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +79 -0
- package/dist/config/index.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/format.d.ts +126 -0
- package/dist/lib/format.d.ts.map +1 -0
- package/dist/lib/format.js +71 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/index.d.ts +11 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +45 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/monorepo-detector.d.ts +31 -0
- package/dist/lib/monorepo-detector.d.ts.map +1 -0
- package/dist/lib/monorepo-detector.js +188 -0
- package/dist/lib/monorepo-detector.js.map +1 -0
- package/dist/lib/prompt-generator.d.ts +65 -0
- package/dist/lib/prompt-generator.d.ts.map +1 -0
- package/dist/lib/prompt-generator.js +162 -0
- package/dist/lib/prompt-generator.js.map +1 -0
- package/dist/lib/strategy-analyzer.d.ts +59 -0
- package/dist/lib/strategy-analyzer.d.ts.map +1 -0
- package/dist/lib/strategy-analyzer.js +91 -0
- package/dist/lib/strategy-analyzer.js.map +1 -0
- package/dist/lib/workflow-definitions.d.ts +41 -0
- package/dist/lib/workflow-definitions.d.ts.map +1 -0
- package/dist/lib/workflow-definitions.js +497 -0
- package/dist/lib/workflow-definitions.js.map +1 -0
- package/dist/patterns/index.d.ts +9 -0
- package/dist/patterns/index.d.ts.map +1 -0
- package/dist/patterns/index.js +21 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/patterns/inheritance.d.ts +193 -0
- package/dist/patterns/inheritance.d.ts.map +1 -0
- package/dist/patterns/inheritance.js +125 -0
- package/dist/patterns/inheritance.js.map +1 -0
- package/dist/server.d.ts +44 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +91 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/core/context-helper.d.ts +50 -0
- package/dist/tools/core/context-helper.d.ts.map +1 -0
- package/dist/tools/core/context-helper.js +49 -0
- package/dist/tools/core/context-helper.js.map +1 -0
- package/dist/tools/core/index.d.ts +2 -0
- package/dist/tools/core/index.d.ts.map +1 -0
- package/dist/tools/core/index.js +2 -0
- package/dist/tools/core/index.js.map +1 -0
- package/dist/tools/index.d.ts +58 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +1499 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/transport/__tests__/resolve-endpoint.test.d.ts +6 -0
- package/dist/transport/__tests__/resolve-endpoint.test.d.ts.map +1 -0
- package/dist/transport/index.d.ts +6 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +5 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/interface.d.ts +25 -0
- package/dist/transport/interface.d.ts.map +1 -0
- package/dist/transport/interface.js +1 -0
- package/dist/transport/interface.js.map +1 -0
- package/dist/transport/remote.d.ts +38 -0
- package/dist/transport/remote.d.ts.map +1 -0
- package/dist/transport/remote.js +107 -0
- package/dist/transport/remote.js.map +1 -0
- package/dist/transport/resolve-endpoint.d.ts +58 -0
- package/dist/transport/resolve-endpoint.d.ts.map +1 -0
- package/dist/transport/resolve-endpoint.js +146 -0
- package/dist/transport/resolve-endpoint.js.map +1 -0
- package/dist/types/index.d.ts +212 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +16 -0
- package/dist/types/index.js.map +1 -0
- package/dist/validation/index.d.ts +86 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +392 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/ticket-validation.d.ts +162 -0
- package/dist/validation/ticket-validation.d.ts.map +1 -0
- package/dist/validation/ticket-validation.js +188 -0
- package/dist/validation/ticket-validation.js.map +1 -0
- package/package.json +69 -0
- package/src/cli/templates/agents/content/core/sfag-orchestrator.ts +165 -0
- package/src/cli/templates/agents/content/core/sfag-spec-creator.ts +348 -0
- package/src/cli/templates/agents/content/core/sfag-ticket-implementer.ts +259 -0
- package/src/cli/templates/agents/content/research/sfag-package-researcher.ts +132 -0
- package/src/cli/templates/agents/index.ts +47 -0
- package/src/cli/templates/commands.ts +90 -0
- package/src/cli/templates/content/sf-blockers.ts +71 -0
- package/src/cli/templates/content/sf-commit.ts +81 -0
- package/src/cli/templates/content/sf-context.ts +65 -0
- package/src/cli/templates/content/sf-help.ts +44 -0
- package/src/cli/templates/content/sf-init.ts +64 -0
- package/src/cli/templates/content/sf-reset.ts +69 -0
- package/src/cli/templates/content/sf-search.ts +65 -0
- package/src/cli/templates/content/sf-status.ts +64 -0
- package/src/cli/templates/index.ts +16 -0
- package/src/cli/templates/skills/specforge-conventions.md +114 -0
- package/src/cli/templates/skills/specforge-orchestrator.md +409 -0
- package/src/cli/templates/skills/specforge-validator.md +128 -0
- package/src/cli/templates/skills/specforge-worker.md +412 -0
|
@@ -0,0 +1,1499 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ValidationError,
|
|
3
|
+
ApiError,
|
|
4
|
+
validateToolArgs,
|
|
5
|
+
formatMCPError,
|
|
6
|
+
transformError
|
|
7
|
+
} from "../validation/index.js";
|
|
8
|
+
import { injectContext, injectContextRequired } from "./core/context-helper.js";
|
|
9
|
+
import { tryLoadProjectConfig, saveProjectConfig } from "../cli/config/index.js";
|
|
10
|
+
import {
|
|
11
|
+
appendPlanningSessionRegistry,
|
|
12
|
+
markPlanningSessionRegistryCompleted
|
|
13
|
+
} from "../cli/config/planning-sessions-registry.js";
|
|
14
|
+
function getTools() {
|
|
15
|
+
const tools = [
|
|
16
|
+
// ========================================================================
|
|
17
|
+
// Queries (6)
|
|
18
|
+
// ========================================================================
|
|
19
|
+
{
|
|
20
|
+
name: "get",
|
|
21
|
+
description: "Get a single entity by type and ID.",
|
|
22
|
+
inputSchema: {
|
|
23
|
+
type: "object",
|
|
24
|
+
properties: {
|
|
25
|
+
type: {
|
|
26
|
+
type: "string",
|
|
27
|
+
enum: ["project", "specification", "epic", "ticket", "implementation_session"],
|
|
28
|
+
description: "Entity type to retrieve"
|
|
29
|
+
},
|
|
30
|
+
id: {
|
|
31
|
+
type: "string",
|
|
32
|
+
description: "Entity ID (for project, specification, epic, ticket)"
|
|
33
|
+
},
|
|
34
|
+
specificationId: {
|
|
35
|
+
type: "string",
|
|
36
|
+
description: "Specification ID (for implementation_session)"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
required: ["type"]
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: "list",
|
|
44
|
+
description: "List entities by type.",
|
|
45
|
+
inputSchema: {
|
|
46
|
+
type: "object",
|
|
47
|
+
properties: {
|
|
48
|
+
type: {
|
|
49
|
+
type: "string",
|
|
50
|
+
enum: ["projects", "specifications", "epics", "tickets"],
|
|
51
|
+
description: "Entity type to list"
|
|
52
|
+
},
|
|
53
|
+
projectId: {
|
|
54
|
+
type: "string",
|
|
55
|
+
description: "Filter by project (for specifications)"
|
|
56
|
+
},
|
|
57
|
+
specificationId: {
|
|
58
|
+
type: "string",
|
|
59
|
+
description: "Filter by specification (for epics, tickets)"
|
|
60
|
+
},
|
|
61
|
+
epicId: {
|
|
62
|
+
type: "string",
|
|
63
|
+
description: "Filter by epic (for tickets)"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
required: ["type"]
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "search",
|
|
71
|
+
description: `Unified ticket search with multiple filter options.
|
|
72
|
+
|
|
73
|
+
Combines:
|
|
74
|
+
- Full-text search (query)
|
|
75
|
+
- File matching (files) - replaces find_tickets_by_file
|
|
76
|
+
- Tag filtering (tags) - replaces find_tickets_by_tag
|
|
77
|
+
- Related tickets (relatedTo) - replaces find_related_tickets
|
|
78
|
+
- Status, complexity, priority filters
|
|
79
|
+
|
|
80
|
+
At least one of: query, files, tags, or relatedTo is required.
|
|
81
|
+
At least one scope filter (projectId, specificationId, or epicId) is required.`,
|
|
82
|
+
inputSchema: {
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: {
|
|
85
|
+
query: {
|
|
86
|
+
type: "string",
|
|
87
|
+
description: "Full-text search query"
|
|
88
|
+
},
|
|
89
|
+
files: {
|
|
90
|
+
type: "array",
|
|
91
|
+
items: { type: "string" },
|
|
92
|
+
description: 'Glob patterns to match ticket files (e.g., "**/channel/*.ts")'
|
|
93
|
+
},
|
|
94
|
+
tags: {
|
|
95
|
+
type: "array",
|
|
96
|
+
items: { type: "string" },
|
|
97
|
+
description: "Tags to filter by"
|
|
98
|
+
},
|
|
99
|
+
matchAllTags: {
|
|
100
|
+
type: "boolean",
|
|
101
|
+
description: "If true, match all tags (AND). If false, match any (OR). Default: false"
|
|
102
|
+
},
|
|
103
|
+
relatedTo: {
|
|
104
|
+
type: "string",
|
|
105
|
+
description: "Find tickets related to this ticket ID (by tags, files, tech stack)"
|
|
106
|
+
},
|
|
107
|
+
status: {
|
|
108
|
+
type: "array",
|
|
109
|
+
items: {
|
|
110
|
+
type: "string",
|
|
111
|
+
enum: ["pending", "ready", "active", "done"]
|
|
112
|
+
},
|
|
113
|
+
description: "Filter by status"
|
|
114
|
+
},
|
|
115
|
+
complexity: {
|
|
116
|
+
type: "array",
|
|
117
|
+
items: {
|
|
118
|
+
type: "string",
|
|
119
|
+
enum: ["small", "medium", "large", "xlarge"]
|
|
120
|
+
},
|
|
121
|
+
description: "Filter by complexity"
|
|
122
|
+
},
|
|
123
|
+
priority: {
|
|
124
|
+
type: "array",
|
|
125
|
+
items: {
|
|
126
|
+
type: "string",
|
|
127
|
+
enum: ["low", "medium", "high", "critical"]
|
|
128
|
+
},
|
|
129
|
+
description: "Filter by priority"
|
|
130
|
+
},
|
|
131
|
+
projectId: {
|
|
132
|
+
type: "string",
|
|
133
|
+
description: "Limit search to project"
|
|
134
|
+
},
|
|
135
|
+
specificationId: {
|
|
136
|
+
type: "string",
|
|
137
|
+
description: "Limit search to specification"
|
|
138
|
+
},
|
|
139
|
+
epicId: {
|
|
140
|
+
type: "string",
|
|
141
|
+
description: "Limit search to epic"
|
|
142
|
+
},
|
|
143
|
+
limit: {
|
|
144
|
+
type: "number",
|
|
145
|
+
description: "Maximum results (default: 20, max: 100)"
|
|
146
|
+
},
|
|
147
|
+
offset: {
|
|
148
|
+
type: "number",
|
|
149
|
+
description: "Pagination offset (default: 0)"
|
|
150
|
+
},
|
|
151
|
+
fields: {
|
|
152
|
+
type: "array",
|
|
153
|
+
items: {
|
|
154
|
+
type: "string",
|
|
155
|
+
enum: [
|
|
156
|
+
"id",
|
|
157
|
+
"epicId",
|
|
158
|
+
"ticketNumber",
|
|
159
|
+
"title",
|
|
160
|
+
"description",
|
|
161
|
+
"status",
|
|
162
|
+
"priority",
|
|
163
|
+
"complexity",
|
|
164
|
+
"estimatedHours",
|
|
165
|
+
"actualHours",
|
|
166
|
+
"acceptanceCriteria",
|
|
167
|
+
"implementation",
|
|
168
|
+
"technicalDetails",
|
|
169
|
+
"notes",
|
|
170
|
+
"tags",
|
|
171
|
+
"blockReason",
|
|
172
|
+
"progress",
|
|
173
|
+
"testsPassed",
|
|
174
|
+
"order",
|
|
175
|
+
"startedAt",
|
|
176
|
+
"completedAt",
|
|
177
|
+
"createdAt",
|
|
178
|
+
"updatedAt"
|
|
179
|
+
]
|
|
180
|
+
},
|
|
181
|
+
description: "Select specific fields to return. Returns all fields if not specified. id is always included."
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
name: "get_next_actionable_tickets",
|
|
188
|
+
description: 'Get tickets with status "ready" (all dependencies satisfied). Use start_work_session() to begin work on these tickets.',
|
|
189
|
+
inputSchema: {
|
|
190
|
+
type: "object",
|
|
191
|
+
properties: {
|
|
192
|
+
specificationId: {
|
|
193
|
+
type: "string",
|
|
194
|
+
description: "The ID of the specification (optional if projectId provided)"
|
|
195
|
+
},
|
|
196
|
+
projectId: {
|
|
197
|
+
type: "string",
|
|
198
|
+
description: "The ID of the project to get actionable tickets across all specifications"
|
|
199
|
+
},
|
|
200
|
+
limit: {
|
|
201
|
+
type: "number",
|
|
202
|
+
description: "Maximum number of tickets to return (default: 5)"
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
name: "get_blocked_tickets",
|
|
209
|
+
description: 'Get tickets with status "pending" and their statusReason explaining why they are blocked (unsatisfied dependencies or external block)',
|
|
210
|
+
inputSchema: {
|
|
211
|
+
type: "object",
|
|
212
|
+
properties: {
|
|
213
|
+
specificationId: {
|
|
214
|
+
type: "string",
|
|
215
|
+
description: "The ID of the specification"
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
required: ["specificationId"]
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
name: "get_report",
|
|
223
|
+
description: `Generate unified reports for implementation, time tracking, blockers, work summary, or active sessions.
|
|
224
|
+
|
|
225
|
+
Report types:
|
|
226
|
+
- 'implementation': Progress, velocity, completions (replaces get_implementation_summary)
|
|
227
|
+
- 'time': Estimated vs actual hours (replaces get_time_report)
|
|
228
|
+
- 'blockers': Blocked tickets with reasons (replaces get_blockers_report)
|
|
229
|
+
- 'work': Completed work summary from WorkSession records (replaces get_work_summary)
|
|
230
|
+
- 'implementation_analysis': Deeper implementation insights
|
|
231
|
+
- 'sessions': Live planning/work/review sessions for a project (requires scope='project')
|
|
232
|
+
|
|
233
|
+
Format options:
|
|
234
|
+
- 'json': Full structured data (default)
|
|
235
|
+
- 'summary': Condensed text summary`,
|
|
236
|
+
inputSchema: {
|
|
237
|
+
type: "object",
|
|
238
|
+
properties: {
|
|
239
|
+
type: {
|
|
240
|
+
type: "string",
|
|
241
|
+
enum: ["implementation", "time", "blockers", "work", "implementation_analysis", "sessions"],
|
|
242
|
+
description: "Type of report to generate"
|
|
243
|
+
},
|
|
244
|
+
scope: {
|
|
245
|
+
type: "string",
|
|
246
|
+
enum: ["project", "specification", "epic"],
|
|
247
|
+
description: "Scope of the report. 'sessions' requires scope='project'."
|
|
248
|
+
},
|
|
249
|
+
scopeId: {
|
|
250
|
+
type: "string",
|
|
251
|
+
description: "ID of the scoped entity (projectId, specificationId, or epicId)"
|
|
252
|
+
},
|
|
253
|
+
startDate: {
|
|
254
|
+
type: "string",
|
|
255
|
+
description: "Start date for work report (ISO 8601)"
|
|
256
|
+
},
|
|
257
|
+
endDate: {
|
|
258
|
+
type: "string",
|
|
259
|
+
description: "End date for work report (ISO 8601)"
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
required: ["type", "scope", "scopeId"]
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
// ========================================================================
|
|
266
|
+
// Lifecycle (10)
|
|
267
|
+
// ========================================================================
|
|
268
|
+
{
|
|
269
|
+
name: "start_planning_session",
|
|
270
|
+
description: "Start or resume a guided planning session for a specification. Project-scoped lock: only one active planning session per project (the project is derived from the spec \u2014 you do not pass it). Calling with the same spec resumes the existing session (idempotent). Calling with a different spec while one is active returns a rejection with the active session details. Planning is independent of implementation and review \u2014 they can run concurrently.",
|
|
271
|
+
inputSchema: {
|
|
272
|
+
type: "object",
|
|
273
|
+
properties: {
|
|
274
|
+
specificationId: {
|
|
275
|
+
type: "string",
|
|
276
|
+
description: "The specification to plan. Optional \u2014 defaults to the active spec in the local config (.specforge/config.json), so you normally omit it. Do NOT pass projectId; it is derived from the spec."
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
// Nothing is required: specificationId falls back to local config, and the
|
|
280
|
+
// returned sessionId is persisted + injected into subsequent calls.
|
|
281
|
+
required: []
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
name: "action_planning_session",
|
|
286
|
+
description: "Execute a planning action within an active session. Wraps all planning operations (create/update epics, tickets, dependencies, blueprints) and read operations (get_ticket for inspecting details, gps for full readiness X-ray worst-first) with automatic status tracking. The spec status advances or regresses automatically based on the action type and gate checks. Returns updated progress, blockers, and next suggested actions after every call. Use responseDetail to control verbosity: 'minimal' (~80 tokens) for rapid iteration, 'standard' (~200 tokens, default) for normal work, 'full' (~500 tokens) for debugging.",
|
|
287
|
+
inputSchema: {
|
|
288
|
+
type: "object",
|
|
289
|
+
properties: {
|
|
290
|
+
operation: {
|
|
291
|
+
type: "object",
|
|
292
|
+
description: 'The operation to perform. Must include a "type" field. Per-op required fields are declared in `oneOf` below \u2014 agents should consult their own tool schema parser for the exact shape per type. Do NOT pass sessionId/projectId/specificationId: the active planning session is injected from local config.',
|
|
293
|
+
properties: {
|
|
294
|
+
type: {
|
|
295
|
+
type: "string",
|
|
296
|
+
enum: [
|
|
297
|
+
"set_metadata",
|
|
298
|
+
"create_epic",
|
|
299
|
+
"update_epic",
|
|
300
|
+
"create_ticket",
|
|
301
|
+
"update_ticket",
|
|
302
|
+
"delete_epic",
|
|
303
|
+
"delete_ticket",
|
|
304
|
+
"add_dependencies",
|
|
305
|
+
"remove_dependency",
|
|
306
|
+
"create_blueprint",
|
|
307
|
+
"link_blueprint",
|
|
308
|
+
"update_blueprint",
|
|
309
|
+
"delete_blueprint",
|
|
310
|
+
"unlink_blueprint",
|
|
311
|
+
"get_ticket",
|
|
312
|
+
"get_status",
|
|
313
|
+
"gps"
|
|
314
|
+
],
|
|
315
|
+
description: "The type of planning operation to perform"
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
required: ["type"],
|
|
319
|
+
oneOf: [
|
|
320
|
+
{
|
|
321
|
+
properties: { type: { const: "set_metadata" } },
|
|
322
|
+
required: ["type"]
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
properties: {
|
|
326
|
+
type: { const: "create_epic" },
|
|
327
|
+
title: { type: "string", minLength: 1, description: "Epic title (non-empty)" },
|
|
328
|
+
description: { type: "string", minLength: 1, description: "What this epic delivers" },
|
|
329
|
+
objective: { type: "string", minLength: 1, description: "Goal achieved for the user" },
|
|
330
|
+
goals: { type: "array", items: { type: "string" } },
|
|
331
|
+
acceptanceCriteria: { type: "array", items: { type: "string" } },
|
|
332
|
+
tickets: { type: "array", description: "Optional bulk-create tickets within the epic" }
|
|
333
|
+
},
|
|
334
|
+
required: ["type", "title", "description", "objective"]
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
properties: {
|
|
338
|
+
type: { const: "update_epic" },
|
|
339
|
+
epicId: { type: "string", description: "Epic id; use list_epics or lookup_epic to find" }
|
|
340
|
+
},
|
|
341
|
+
required: ["type", "epicId"]
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
properties: {
|
|
345
|
+
type: { const: "create_ticket" },
|
|
346
|
+
epicId: { type: "string", description: "Parent epic id" },
|
|
347
|
+
title: { type: "string", minLength: 1, description: "Ticket title (non-empty)" },
|
|
348
|
+
description: { type: "string" },
|
|
349
|
+
ticketType: { type: "string", enum: ["implementation", "verification"], description: "Ticket type \u2014 implementation (default) or verification (tests/QA). Drives which fields the readiness rubric expects." },
|
|
350
|
+
priority: { type: "string", enum: ["high", "medium", "low"] },
|
|
351
|
+
complexity: { type: "string", enum: ["small", "medium", "large", "xlarge"] },
|
|
352
|
+
acceptanceCriteria: { type: "array", items: { type: "string" } },
|
|
353
|
+
implementationSteps: { type: "array", items: { type: "string" }, description: "Implementation steps; persisted as TicketImplementationStep rows" },
|
|
354
|
+
dependsOn: { type: "array", items: { type: "string" }, description: "Other ticket ids this depends on; created post-insert" }
|
|
355
|
+
},
|
|
356
|
+
required: ["type", "epicId", "title"]
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
properties: {
|
|
360
|
+
type: { const: "update_ticket" },
|
|
361
|
+
ticketId: { type: "string", description: "Ticket id; use list_tickets or lookup_ticket to find" }
|
|
362
|
+
},
|
|
363
|
+
required: ["type", "ticketId"]
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
properties: {
|
|
367
|
+
type: { const: "delete_epic" },
|
|
368
|
+
epicId: { type: "string", description: "Epic id; cascades to all tickets in the epic" }
|
|
369
|
+
},
|
|
370
|
+
required: ["type", "epicId"]
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
properties: {
|
|
374
|
+
type: { const: "delete_ticket" },
|
|
375
|
+
ticketId: { type: "string" }
|
|
376
|
+
},
|
|
377
|
+
required: ["type", "ticketId"]
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
properties: {
|
|
381
|
+
type: { const: "add_dependencies" },
|
|
382
|
+
dependencies: {
|
|
383
|
+
type: "array",
|
|
384
|
+
minItems: 1,
|
|
385
|
+
maxItems: 100,
|
|
386
|
+
description: "Up to 100 dependency pairs. Valid pairs commit; malformed pairs come back in failed[] with a per-entry reason.",
|
|
387
|
+
items: {
|
|
388
|
+
type: "object",
|
|
389
|
+
properties: {
|
|
390
|
+
ticketId: { type: "string", description: "The dependent ticket" },
|
|
391
|
+
dependsOnId: { type: "string", description: "The blocker ticket" },
|
|
392
|
+
type: { type: "string", enum: ["requires", "blocks"], description: 'Defaults to "requires"' }
|
|
393
|
+
},
|
|
394
|
+
required: ["ticketId", "dependsOnId"]
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
},
|
|
398
|
+
required: ["type", "dependencies"]
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
properties: {
|
|
402
|
+
type: { const: "remove_dependency" },
|
|
403
|
+
dependencyId: { type: "string" }
|
|
404
|
+
},
|
|
405
|
+
required: ["type", "dependencyId"]
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
properties: {
|
|
409
|
+
type: { const: "remove_dependency" },
|
|
410
|
+
ticketId: { type: "string" },
|
|
411
|
+
dependsOnId: { type: "string" }
|
|
412
|
+
},
|
|
413
|
+
required: ["type", "ticketId", "dependsOnId"]
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
properties: {
|
|
417
|
+
type: { const: "create_blueprint" },
|
|
418
|
+
title: { type: "string", minLength: 1, description: "Blueprint title (non-empty)" },
|
|
419
|
+
content: { type: "string", description: "Body. Mermaid format extracts ```mermaid``` fences automatically." },
|
|
420
|
+
format: { type: "string", description: 'Defaults to "mermaid"' },
|
|
421
|
+
category: { type: "string" },
|
|
422
|
+
description: { type: "string" },
|
|
423
|
+
tags: { type: "array", items: { type: "string" } }
|
|
424
|
+
},
|
|
425
|
+
required: ["type", "title"]
|
|
426
|
+
},
|
|
427
|
+
{
|
|
428
|
+
properties: {
|
|
429
|
+
type: { const: "update_blueprint" },
|
|
430
|
+
blueprintId: { type: "string" }
|
|
431
|
+
},
|
|
432
|
+
required: ["type", "blueprintId"]
|
|
433
|
+
},
|
|
434
|
+
{
|
|
435
|
+
properties: {
|
|
436
|
+
type: { const: "delete_blueprint" },
|
|
437
|
+
blueprintId: { type: "string" }
|
|
438
|
+
},
|
|
439
|
+
required: ["type", "blueprintId"]
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
properties: {
|
|
443
|
+
type: { const: "link_blueprint" },
|
|
444
|
+
ticketId: { type: "string" },
|
|
445
|
+
blueprintId: { type: "string" },
|
|
446
|
+
context: { type: "string", description: "Optional context annotation" },
|
|
447
|
+
section: { type: "string", description: "Optional section reference" }
|
|
448
|
+
},
|
|
449
|
+
required: ["type", "ticketId", "blueprintId"]
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
properties: {
|
|
453
|
+
type: { const: "unlink_blueprint" },
|
|
454
|
+
referenceId: { type: "string" }
|
|
455
|
+
},
|
|
456
|
+
required: ["type", "referenceId"]
|
|
457
|
+
},
|
|
458
|
+
{
|
|
459
|
+
properties: {
|
|
460
|
+
type: { const: "unlink_blueprint" },
|
|
461
|
+
ticketId: { type: "string" },
|
|
462
|
+
blueprintId: { type: "string" }
|
|
463
|
+
},
|
|
464
|
+
required: ["type", "ticketId", "blueprintId"]
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
properties: {
|
|
468
|
+
type: { const: "get_ticket" },
|
|
469
|
+
ticketId: { type: "string" },
|
|
470
|
+
include: { type: "array", items: { type: "string", enum: ["dependencies", "testStatus", "statusReason"] } }
|
|
471
|
+
},
|
|
472
|
+
required: ["type", "ticketId"]
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
properties: { type: { const: "get_status" } },
|
|
476
|
+
required: ["type"]
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
properties: {
|
|
480
|
+
type: { const: "gps" },
|
|
481
|
+
responseDetail: { type: "string", enum: ["minimal", "standard", "full"] }
|
|
482
|
+
},
|
|
483
|
+
required: ["type"]
|
|
484
|
+
}
|
|
485
|
+
]
|
|
486
|
+
},
|
|
487
|
+
responseDetail: {
|
|
488
|
+
type: "string",
|
|
489
|
+
enum: ["minimal", "standard", "full"],
|
|
490
|
+
description: "Response detail level: minimal (~80 tokens), standard (~200, default), full (~500)"
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
required: ["operation"]
|
|
494
|
+
}
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
name: "complete_planning_session",
|
|
498
|
+
description: "Complete the planning session and submit the spec for final review. Spec must be in 'planning' status. Runs the planning gate (consistency checks + readinessThreshold from project/spec settings). Transitions the spec directly to 'ready' on pass. Takes no arguments \u2014 the active planning session is injected from local config.",
|
|
499
|
+
inputSchema: {
|
|
500
|
+
type: "object",
|
|
501
|
+
// No inputs: the active planning session (sessionId) is injected from
|
|
502
|
+
// local config (.specforge/config.json). Do NOT pass sessionId/projectId/specificationId.
|
|
503
|
+
properties: {},
|
|
504
|
+
required: []
|
|
505
|
+
}
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
name: "start_work_session",
|
|
509
|
+
description: "Start working on a ticket. Returns full ticket details (description, implementation steps, AC, technicalDetails, codeReferences, typeReferences, tags, notes, complexity, priority) alongside checklistState and workSessionId. No need to call get_ticket separately. Returns error with statusReason if ticket is pending.",
|
|
510
|
+
inputSchema: {
|
|
511
|
+
type: "object",
|
|
512
|
+
properties: {
|
|
513
|
+
ticketId: {
|
|
514
|
+
type: "string",
|
|
515
|
+
description: "The ID of the ticket to start"
|
|
516
|
+
}
|
|
517
|
+
},
|
|
518
|
+
required: ["ticketId"]
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
name: "action_work_session",
|
|
523
|
+
description: `Update checklist state during an active WorkSession. Combines step completion, AC validation, test result reporting, file tracking, reference review confirmation, and discovery reporting into a single atomic operation. All state changes are recorded on the WorkSession and its related validation/completion records.
|
|
524
|
+
|
|
525
|
+
Use this instead of calling update_ticket for checklist changes. Provides:
|
|
526
|
+
- Step completion (individual or bulk via WorkSessionStepCompletion)
|
|
527
|
+
- Acceptance criteria validation (individual or bulk via WorkSessionACValidation)
|
|
528
|
+
- Test result reporting (merged by test type via WorkSessionTestResult)
|
|
529
|
+
- File tracking (created, modified, deleted on WorkSession)
|
|
530
|
+
- Discovery reporting (create discoveries for blockers, bugs, tech debt)
|
|
531
|
+
- Blocker management (set block reason; requires existing discovery)
|
|
532
|
+
- Reference review tracking (codeSnippetsReviewed, typeReferencesReviewed)
|
|
533
|
+
- Auto-calculated progress percentage
|
|
534
|
+
- Completion readiness hints
|
|
535
|
+
|
|
536
|
+
IMPORTANT: All acceptance criteria must be validated and all implementation steps must be completed via this tool before calling complete_work_session. The completion gate enforces this.
|
|
537
|
+
|
|
538
|
+
If the ticket has codeReferences or typeReferences, set codeSnippetsReviewed/typeReferencesReviewed to true after reviewing them \u2014 completion readiness will block until these are confirmed.
|
|
539
|
+
|
|
540
|
+
Set getTicket: true to fetch full ticket details in the response \u2014 useful for re-reading ticket context mid-implementation. Can be the sole operation or combined with other actions.`,
|
|
541
|
+
inputSchema: {
|
|
542
|
+
type: "object",
|
|
543
|
+
properties: {
|
|
544
|
+
ticketId: {
|
|
545
|
+
type: "string",
|
|
546
|
+
description: "The ID of the ticket being worked on (must be in active status)"
|
|
547
|
+
},
|
|
548
|
+
steps: {
|
|
549
|
+
type: "array",
|
|
550
|
+
description: "Individual step completion updates",
|
|
551
|
+
items: {
|
|
552
|
+
type: "object",
|
|
553
|
+
properties: {
|
|
554
|
+
index: {
|
|
555
|
+
type: "number",
|
|
556
|
+
description: "Zero-based index of the step in the implementation.steps array"
|
|
557
|
+
},
|
|
558
|
+
completed: {
|
|
559
|
+
type: "boolean",
|
|
560
|
+
description: "Whether the step is completed"
|
|
561
|
+
},
|
|
562
|
+
notes: {
|
|
563
|
+
type: "string",
|
|
564
|
+
description: "Optional note about this step"
|
|
565
|
+
}
|
|
566
|
+
},
|
|
567
|
+
required: ["index", "completed"]
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
allStepsDone: {
|
|
571
|
+
type: "boolean",
|
|
572
|
+
description: "Shortcut: mark all steps as completed"
|
|
573
|
+
},
|
|
574
|
+
acceptanceCriteria: {
|
|
575
|
+
type: "array",
|
|
576
|
+
description: "Individual AC validation updates",
|
|
577
|
+
items: {
|
|
578
|
+
type: "object",
|
|
579
|
+
properties: {
|
|
580
|
+
index: {
|
|
581
|
+
type: "number",
|
|
582
|
+
description: "Zero-based index of the AC in the acceptanceCriteria array"
|
|
583
|
+
},
|
|
584
|
+
validated: {
|
|
585
|
+
type: "boolean",
|
|
586
|
+
description: "Whether the AC is validated"
|
|
587
|
+
},
|
|
588
|
+
notes: {
|
|
589
|
+
type: "string",
|
|
590
|
+
description: "Optional note about this AC"
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
required: ["index", "validated"]
|
|
594
|
+
}
|
|
595
|
+
},
|
|
596
|
+
allACValidated: {
|
|
597
|
+
type: "boolean",
|
|
598
|
+
description: "Shortcut: mark all acceptance criteria as validated"
|
|
599
|
+
},
|
|
600
|
+
testResults: {
|
|
601
|
+
type: "array",
|
|
602
|
+
description: "Test result reports to append (merged by testType)",
|
|
603
|
+
items: {
|
|
604
|
+
type: "object",
|
|
605
|
+
properties: {
|
|
606
|
+
testType: {
|
|
607
|
+
type: "string",
|
|
608
|
+
description: 'Type of test (e.g., "unit", "integration", "e2e", "lint", "typeCheck")'
|
|
609
|
+
},
|
|
610
|
+
passed: {
|
|
611
|
+
type: "number",
|
|
612
|
+
description: "Number of tests that passed"
|
|
613
|
+
},
|
|
614
|
+
failed: {
|
|
615
|
+
type: "number",
|
|
616
|
+
description: "Number of tests that failed"
|
|
617
|
+
},
|
|
618
|
+
skipped: {
|
|
619
|
+
type: "number",
|
|
620
|
+
description: "Number of tests skipped"
|
|
621
|
+
},
|
|
622
|
+
command: {
|
|
623
|
+
type: "string",
|
|
624
|
+
description: "Command used to run the tests"
|
|
625
|
+
},
|
|
626
|
+
output: {
|
|
627
|
+
type: "string",
|
|
628
|
+
description: "Test output (truncated if needed)"
|
|
629
|
+
},
|
|
630
|
+
duration: {
|
|
631
|
+
type: "number",
|
|
632
|
+
description: "Duration in milliseconds"
|
|
633
|
+
},
|
|
634
|
+
suites: {
|
|
635
|
+
type: "array",
|
|
636
|
+
description: "Optional suite-level breakdown",
|
|
637
|
+
items: {
|
|
638
|
+
type: "object",
|
|
639
|
+
properties: {
|
|
640
|
+
name: { type: "string", description: "Suite name" },
|
|
641
|
+
passed: { type: "number", description: "Passed tests in suite" },
|
|
642
|
+
failed: { type: "number", description: "Failed tests in suite" },
|
|
643
|
+
skipped: { type: "number", description: "Skipped tests in suite" },
|
|
644
|
+
duration: { type: "number", description: "Suite duration in ms" }
|
|
645
|
+
},
|
|
646
|
+
required: ["name", "passed", "failed"]
|
|
647
|
+
}
|
|
648
|
+
},
|
|
649
|
+
tests: {
|
|
650
|
+
type: "array",
|
|
651
|
+
description: "Optional individual test breakdown",
|
|
652
|
+
items: {
|
|
653
|
+
type: "object",
|
|
654
|
+
properties: {
|
|
655
|
+
name: { type: "string", description: "Test name" },
|
|
656
|
+
suite: { type: "string", description: "Parent suite name" },
|
|
657
|
+
status: { type: "string", enum: ["passed", "failed", "skipped"], description: "Test result" },
|
|
658
|
+
duration: { type: "number", description: "Test duration in ms" }
|
|
659
|
+
},
|
|
660
|
+
required: ["name", "status"]
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
},
|
|
664
|
+
required: ["testType", "passed", "failed"]
|
|
665
|
+
}
|
|
666
|
+
},
|
|
667
|
+
notes: {
|
|
668
|
+
type: "string",
|
|
669
|
+
description: "Additional notes to append to the ticket"
|
|
670
|
+
},
|
|
671
|
+
filesCreated: {
|
|
672
|
+
type: "array",
|
|
673
|
+
items: { type: "string" },
|
|
674
|
+
description: "Files created during this session. Accumulated incrementally."
|
|
675
|
+
},
|
|
676
|
+
filesModified: {
|
|
677
|
+
type: "array",
|
|
678
|
+
items: { type: "string" },
|
|
679
|
+
description: "Files modified during this session. Accumulated incrementally."
|
|
680
|
+
},
|
|
681
|
+
filesDeleted: {
|
|
682
|
+
type: "array",
|
|
683
|
+
items: { type: "string" },
|
|
684
|
+
description: "Files deleted during this session. Accumulated incrementally."
|
|
685
|
+
},
|
|
686
|
+
discovery: {
|
|
687
|
+
type: "object",
|
|
688
|
+
description: "Create a discovery (observation about the implementation). Use this to report blockers, bugs, tech debt, scope changes, etc.",
|
|
689
|
+
properties: {
|
|
690
|
+
description: { type: "string", description: "Description of the discovery" },
|
|
691
|
+
type: { type: "string", description: "Discovery type: bug, tech_debt, blocker, clarification, scope_change, dependency, risk, ticket, epic" },
|
|
692
|
+
severity: { type: "string", description: "Severity: blocker, critical, major, minor" },
|
|
693
|
+
suggestedTitle: { type: "string", description: "Suggested title for the new ticket/epic" },
|
|
694
|
+
suggestedPriority: { type: "string", description: "Suggested priority: high, medium, low" },
|
|
695
|
+
relatedFiles: { type: "array", items: { type: "string" }, description: "Related file paths" },
|
|
696
|
+
notes: { type: "string", description: "Additional notes" }
|
|
697
|
+
},
|
|
698
|
+
required: ["description"]
|
|
699
|
+
},
|
|
700
|
+
blockReason: {
|
|
701
|
+
type: "string",
|
|
702
|
+
description: "Set a blocker on this ticket. Requires an existing discovery (create via discovery parameter first)."
|
|
703
|
+
},
|
|
704
|
+
getTicket: {
|
|
705
|
+
type: "boolean",
|
|
706
|
+
description: "Fetch full ticket details. Can be the sole operation or combined with other actions."
|
|
707
|
+
},
|
|
708
|
+
includeFullContext: {
|
|
709
|
+
type: "boolean",
|
|
710
|
+
description: "Include full implementation context in response"
|
|
711
|
+
},
|
|
712
|
+
codeSnippetsReviewed: {
|
|
713
|
+
type: "boolean",
|
|
714
|
+
description: "Confirm that code snippets (codeReferences) on the ticket have been reviewed. Required before completion when the ticket has non-empty codeReferences."
|
|
715
|
+
},
|
|
716
|
+
typeReferencesReviewed: {
|
|
717
|
+
type: "boolean",
|
|
718
|
+
description: "Confirm that type references (typeReferences) on the ticket have been reviewed. Required before completion when the ticket has non-empty typeReferences."
|
|
719
|
+
}
|
|
720
|
+
},
|
|
721
|
+
required: ["ticketId"]
|
|
722
|
+
}
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
name: "complete_work_session",
|
|
726
|
+
description: "Mark a ticket as complete and finalize the active WorkSession. Transitions active -> done. Session data (files, test results, time) is stored on the WorkSession record.\n\nAll acceptance criteria must be validated and all implementation steps must be completed via action_work_session before calling this. The completion gate enforces this \u2014 shortcuts are not available.\n\nAutomatically recalculates status for dependent tickets and returns cascade info.\n\nOptional validation flags can be provided to report test results inline:\n- tests: Unit/integration test results\n- lint: Linting results\n- typeCheck: TypeScript type checking\n- build: Build/compilation results",
|
|
727
|
+
inputSchema: {
|
|
728
|
+
type: "object",
|
|
729
|
+
properties: {
|
|
730
|
+
ticketId: {
|
|
731
|
+
type: "string",
|
|
732
|
+
description: "The ID of the ticket"
|
|
733
|
+
},
|
|
734
|
+
summary: {
|
|
735
|
+
type: "string",
|
|
736
|
+
description: "Summary of work completed"
|
|
737
|
+
},
|
|
738
|
+
filesModified: {
|
|
739
|
+
type: "array",
|
|
740
|
+
items: { type: "string" },
|
|
741
|
+
description: "List of files modified"
|
|
742
|
+
},
|
|
743
|
+
filesCreated: {
|
|
744
|
+
type: "array",
|
|
745
|
+
items: { type: "string" },
|
|
746
|
+
description: "List of files created"
|
|
747
|
+
},
|
|
748
|
+
filesDeleted: {
|
|
749
|
+
type: "array",
|
|
750
|
+
items: { type: "string" },
|
|
751
|
+
description: "List of files deleted"
|
|
752
|
+
},
|
|
753
|
+
actualHours: {
|
|
754
|
+
type: "number",
|
|
755
|
+
description: "Actual hours spent on the ticket"
|
|
756
|
+
},
|
|
757
|
+
validation: {
|
|
758
|
+
type: "object",
|
|
759
|
+
description: "Detailed validation flags for reporting test/lint/build results",
|
|
760
|
+
properties: {
|
|
761
|
+
tests: {
|
|
762
|
+
type: "string",
|
|
763
|
+
enum: ["passed", "failed", "skipped", "na"],
|
|
764
|
+
description: "Unit/integration test results"
|
|
765
|
+
},
|
|
766
|
+
lint: {
|
|
767
|
+
type: "string",
|
|
768
|
+
enum: ["passed", "failed", "skipped", "na"],
|
|
769
|
+
description: "Linting results"
|
|
770
|
+
},
|
|
771
|
+
typeCheck: {
|
|
772
|
+
type: "string",
|
|
773
|
+
enum: ["passed", "failed", "skipped", "na"],
|
|
774
|
+
description: "TypeScript type checking results"
|
|
775
|
+
},
|
|
776
|
+
build: {
|
|
777
|
+
type: "string",
|
|
778
|
+
enum: ["passed", "failed", "skipped", "na"],
|
|
779
|
+
description: "Build/compilation results"
|
|
780
|
+
},
|
|
781
|
+
notes: {
|
|
782
|
+
type: "string",
|
|
783
|
+
description: "Additional validation notes"
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
},
|
|
788
|
+
required: ["ticketId", "summary"]
|
|
789
|
+
}
|
|
790
|
+
},
|
|
791
|
+
{
|
|
792
|
+
name: "start_review_session",
|
|
793
|
+
description: 'Start the implementation review lifecycle. Runs the implementation gate and either auto-transitions to "reviewed" (on pass) or transitions to "in_review" with an active ReviewSession (on fail). Creates correction tickets via action_review_session, then call complete_review_session.',
|
|
794
|
+
inputSchema: {
|
|
795
|
+
type: "object",
|
|
796
|
+
properties: {
|
|
797
|
+
specificationId: {
|
|
798
|
+
type: "string",
|
|
799
|
+
description: "The ID of the specification to review (must be in ready_for_review status)"
|
|
800
|
+
}
|
|
801
|
+
},
|
|
802
|
+
required: ["specificationId"]
|
|
803
|
+
}
|
|
804
|
+
},
|
|
805
|
+
{
|
|
806
|
+
name: "action_review_session",
|
|
807
|
+
description: 'Address findings in an active review session. Create correction tickets inline or dismiss findings with justification. Only available when specification is in "in_review" status.',
|
|
808
|
+
inputSchema: {
|
|
809
|
+
type: "object",
|
|
810
|
+
properties: {
|
|
811
|
+
specificationId: {
|
|
812
|
+
type: "string",
|
|
813
|
+
description: "The ID of the specification"
|
|
814
|
+
},
|
|
815
|
+
reviewSessionId: {
|
|
816
|
+
type: "string",
|
|
817
|
+
description: "The review session ID (auto-detected if omitted)"
|
|
818
|
+
},
|
|
819
|
+
findingsAddressed: {
|
|
820
|
+
type: "array",
|
|
821
|
+
description: "Findings to address in this action",
|
|
822
|
+
items: {
|
|
823
|
+
type: "object",
|
|
824
|
+
properties: {
|
|
825
|
+
findingId: {
|
|
826
|
+
type: "string",
|
|
827
|
+
description: "The finding ID to address"
|
|
828
|
+
},
|
|
829
|
+
action: {
|
|
830
|
+
type: "string",
|
|
831
|
+
enum: ["correction_ticket", "dismissed"],
|
|
832
|
+
description: "How to address the finding"
|
|
833
|
+
},
|
|
834
|
+
correctionTicket: {
|
|
835
|
+
type: "object",
|
|
836
|
+
description: "Inline ticket creation params (required for correction_ticket action)",
|
|
837
|
+
properties: {
|
|
838
|
+
epicId: { type: "string", description: "Epic to add the correction ticket to" },
|
|
839
|
+
title: { type: "string", description: "Ticket title" },
|
|
840
|
+
description: { type: "string", description: "Ticket description" },
|
|
841
|
+
ticketType: { type: "string", enum: ["implementation", "verification"], description: "Ticket type \u2014 defaults to implementation." },
|
|
842
|
+
priority: { type: "string", enum: ["low", "medium", "high", "critical"] },
|
|
843
|
+
complexity: { type: "string", enum: ["small", "medium", "large", "xlarge"] },
|
|
844
|
+
estimatedHours: { type: "number" },
|
|
845
|
+
acceptanceCriteria: { type: "array", items: { type: "string" } },
|
|
846
|
+
implementationSteps: { type: "array", items: { type: "string" }, description: "Implementation steps; persisted as TicketImplementationStep rows" },
|
|
847
|
+
tags: { type: "array", items: { type: "string" } }
|
|
848
|
+
},
|
|
849
|
+
required: ["epicId", "title"]
|
|
850
|
+
},
|
|
851
|
+
justification: {
|
|
852
|
+
type: "string",
|
|
853
|
+
description: 'Required justification when action is "dismissed"'
|
|
854
|
+
}
|
|
855
|
+
},
|
|
856
|
+
required: ["findingId", "action"]
|
|
857
|
+
}
|
|
858
|
+
},
|
|
859
|
+
notes: {
|
|
860
|
+
type: "string",
|
|
861
|
+
description: "Optional notes for this review action"
|
|
862
|
+
}
|
|
863
|
+
},
|
|
864
|
+
required: ["specificationId"]
|
|
865
|
+
}
|
|
866
|
+
},
|
|
867
|
+
{
|
|
868
|
+
name: "complete_review_session",
|
|
869
|
+
description: 'Complete an active review session. All error-severity findings must be addressed. If correction tickets exist, transitions to "in_progress". If all findings dismissed, triggers user confirmation flow.',
|
|
870
|
+
inputSchema: {
|
|
871
|
+
type: "object",
|
|
872
|
+
properties: {
|
|
873
|
+
specificationId: {
|
|
874
|
+
type: "string",
|
|
875
|
+
description: "The ID of the specification"
|
|
876
|
+
},
|
|
877
|
+
reviewSessionId: {
|
|
878
|
+
type: "string",
|
|
879
|
+
description: "The review session ID (auto-detected if omitted)"
|
|
880
|
+
},
|
|
881
|
+
summary: {
|
|
882
|
+
type: "string",
|
|
883
|
+
description: "Optional completion summary"
|
|
884
|
+
},
|
|
885
|
+
confirmAllDismissed: {
|
|
886
|
+
type: "boolean",
|
|
887
|
+
description: "Set to true when all findings were dismissed to trigger user confirmation flow"
|
|
888
|
+
}
|
|
889
|
+
},
|
|
890
|
+
required: ["specificationId"]
|
|
891
|
+
}
|
|
892
|
+
},
|
|
893
|
+
{
|
|
894
|
+
name: "reopen_specification",
|
|
895
|
+
description: 'Reopen a specification in "ready" status, regressing to "planning". After reopening, call start_planning_session to begin a new planning session.',
|
|
896
|
+
inputSchema: {
|
|
897
|
+
type: "object",
|
|
898
|
+
properties: {
|
|
899
|
+
specificationId: {
|
|
900
|
+
type: "string",
|
|
901
|
+
description: "The ID of the specification to reopen"
|
|
902
|
+
}
|
|
903
|
+
},
|
|
904
|
+
required: ["specificationId"]
|
|
905
|
+
}
|
|
906
|
+
},
|
|
907
|
+
// Spec creation is a HUMAN bootstrap step, NOT an agent MCP tool: specs are
|
|
908
|
+
// created via `specforge init` (cli-rest surface), which also writes the new
|
|
909
|
+
// spec id into the local config so the agent's per-call injection finds it.
|
|
910
|
+
// The agent assumes the spec already exists and starts from
|
|
911
|
+
// `start_planning_session`. (Backend keeps `create_specification` REST-only;
|
|
912
|
+
// it was never dispatchable on /local.)
|
|
913
|
+
// ========================================================================
|
|
914
|
+
// Utilities (3)
|
|
915
|
+
// ========================================================================
|
|
916
|
+
{
|
|
917
|
+
name: "feedback",
|
|
918
|
+
description: `Submit and manage feedback about MCP tools. Operations:
|
|
919
|
+
- submit: Submit new feedback (requires category, summary)
|
|
920
|
+
- list: List recent feedback entries
|
|
921
|
+
- get: Get a specific feedback entry by ID`,
|
|
922
|
+
inputSchema: {
|
|
923
|
+
type: "object",
|
|
924
|
+
properties: {
|
|
925
|
+
operation: {
|
|
926
|
+
type: "string",
|
|
927
|
+
enum: ["submit", "list", "get"],
|
|
928
|
+
description: "The operation to perform"
|
|
929
|
+
},
|
|
930
|
+
// For submit operation
|
|
931
|
+
category: {
|
|
932
|
+
type: "string",
|
|
933
|
+
enum: ["bug", "feature_request", "usability", "documentation", "performance"],
|
|
934
|
+
description: "Feedback category (required for submit)"
|
|
935
|
+
},
|
|
936
|
+
summary: {
|
|
937
|
+
type: "string",
|
|
938
|
+
description: "Brief summary of the feedback (required for submit)"
|
|
939
|
+
},
|
|
940
|
+
severity: {
|
|
941
|
+
type: "string",
|
|
942
|
+
enum: ["critical", "high", "medium", "low"],
|
|
943
|
+
description: "Severity level (default: medium)"
|
|
944
|
+
},
|
|
945
|
+
tool: {
|
|
946
|
+
type: "string",
|
|
947
|
+
description: "Which MCP tool this relates to"
|
|
948
|
+
},
|
|
949
|
+
toolOperation: {
|
|
950
|
+
type: "string",
|
|
951
|
+
description: "Specific operation within the tool"
|
|
952
|
+
},
|
|
953
|
+
details: {
|
|
954
|
+
type: "string",
|
|
955
|
+
description: "Extended description"
|
|
956
|
+
},
|
|
957
|
+
expected: {
|
|
958
|
+
type: "string",
|
|
959
|
+
description: "Expected behavior"
|
|
960
|
+
},
|
|
961
|
+
actual: {
|
|
962
|
+
type: "string",
|
|
963
|
+
description: "Actual behavior"
|
|
964
|
+
},
|
|
965
|
+
errorMessage: {
|
|
966
|
+
type: "string",
|
|
967
|
+
description: "Error message if reporting a bug"
|
|
968
|
+
},
|
|
969
|
+
ticketId: {
|
|
970
|
+
type: "string",
|
|
971
|
+
description: "Related ticket ID"
|
|
972
|
+
},
|
|
973
|
+
// For list operation
|
|
974
|
+
limit: {
|
|
975
|
+
type: "number",
|
|
976
|
+
description: "Maximum entries to return (default: 10)"
|
|
977
|
+
},
|
|
978
|
+
categoryFilter: {
|
|
979
|
+
type: "string",
|
|
980
|
+
enum: ["bug", "feature_request", "usability", "documentation", "performance"],
|
|
981
|
+
description: "Filter by category"
|
|
982
|
+
},
|
|
983
|
+
// For get operation
|
|
984
|
+
feedbackId: {
|
|
985
|
+
type: "string",
|
|
986
|
+
description: "Feedback ID to retrieve (required for get)"
|
|
987
|
+
}
|
|
988
|
+
},
|
|
989
|
+
required: ["operation"]
|
|
990
|
+
}
|
|
991
|
+
},
|
|
992
|
+
{
|
|
993
|
+
name: "reset_work_session",
|
|
994
|
+
description: "Reset tickets to pending/ready status (calculated from dependencies). Returns statusCalculation showing how many became pending vs ready.",
|
|
995
|
+
inputSchema: {
|
|
996
|
+
type: "object",
|
|
997
|
+
properties: {
|
|
998
|
+
specificationId: {
|
|
999
|
+
type: "string",
|
|
1000
|
+
description: "The specification containing the tickets"
|
|
1001
|
+
},
|
|
1002
|
+
ticketIds: {
|
|
1003
|
+
type: "array",
|
|
1004
|
+
items: { type: "string" },
|
|
1005
|
+
description: "Specific ticket IDs to reset"
|
|
1006
|
+
},
|
|
1007
|
+
fromTicketId: {
|
|
1008
|
+
type: "string",
|
|
1009
|
+
description: "Reset this ticket and all its dependents"
|
|
1010
|
+
},
|
|
1011
|
+
epicId: {
|
|
1012
|
+
type: "string",
|
|
1013
|
+
description: "Reset all tickets in this epic"
|
|
1014
|
+
},
|
|
1015
|
+
allTickets: {
|
|
1016
|
+
type: "boolean",
|
|
1017
|
+
description: "Reset all tickets in the specification"
|
|
1018
|
+
},
|
|
1019
|
+
resetDependents: {
|
|
1020
|
+
type: "boolean",
|
|
1021
|
+
description: "Also reset tickets that depend on the specified tickets (default: false)"
|
|
1022
|
+
},
|
|
1023
|
+
includeCompleted: {
|
|
1024
|
+
type: "boolean",
|
|
1025
|
+
description: "Include tickets with done status in the reset (default: false)"
|
|
1026
|
+
},
|
|
1027
|
+
preserveNotes: {
|
|
1028
|
+
type: "boolean",
|
|
1029
|
+
description: "Keep existing notes on tickets (default: true)"
|
|
1030
|
+
},
|
|
1031
|
+
clearTestResults: {
|
|
1032
|
+
type: "boolean",
|
|
1033
|
+
description: "Clear test result history (default: false)"
|
|
1034
|
+
}
|
|
1035
|
+
},
|
|
1036
|
+
required: ["specificationId"]
|
|
1037
|
+
}
|
|
1038
|
+
},
|
|
1039
|
+
{
|
|
1040
|
+
name: "link_pull_request",
|
|
1041
|
+
description: "Associate a pull request with a ticket",
|
|
1042
|
+
inputSchema: {
|
|
1043
|
+
type: "object",
|
|
1044
|
+
properties: {
|
|
1045
|
+
ticketId: {
|
|
1046
|
+
type: "string",
|
|
1047
|
+
description: "The ID of the ticket"
|
|
1048
|
+
},
|
|
1049
|
+
prNumber: {
|
|
1050
|
+
type: "number",
|
|
1051
|
+
description: "PR number (provide this or prUrl)"
|
|
1052
|
+
},
|
|
1053
|
+
prUrl: {
|
|
1054
|
+
type: "string",
|
|
1055
|
+
description: "Full PR URL (GitHub, GitLab, or Bitbucket)"
|
|
1056
|
+
},
|
|
1057
|
+
title: {
|
|
1058
|
+
type: "string",
|
|
1059
|
+
description: "PR title"
|
|
1060
|
+
},
|
|
1061
|
+
author: {
|
|
1062
|
+
type: "string",
|
|
1063
|
+
description: "PR author"
|
|
1064
|
+
},
|
|
1065
|
+
repoUrl: {
|
|
1066
|
+
type: "string",
|
|
1067
|
+
description: "Repository URL (required if using prNumber)"
|
|
1068
|
+
}
|
|
1069
|
+
},
|
|
1070
|
+
required: ["ticketId"]
|
|
1071
|
+
}
|
|
1072
|
+
},
|
|
1073
|
+
// ========================================================================
|
|
1074
|
+
// Orchestration (2)
|
|
1075
|
+
// ========================================================================
|
|
1076
|
+
{
|
|
1077
|
+
name: "get_critical_path",
|
|
1078
|
+
description: "Get the critical execution path for a specification.",
|
|
1079
|
+
inputSchema: {
|
|
1080
|
+
type: "object",
|
|
1081
|
+
properties: {
|
|
1082
|
+
specificationId: {
|
|
1083
|
+
type: "string",
|
|
1084
|
+
description: "Specification ID"
|
|
1085
|
+
}
|
|
1086
|
+
},
|
|
1087
|
+
required: ["specificationId"]
|
|
1088
|
+
}
|
|
1089
|
+
},
|
|
1090
|
+
{
|
|
1091
|
+
name: "get_dependency_tree",
|
|
1092
|
+
description: "Get the full dependency tree for a specification.",
|
|
1093
|
+
inputSchema: {
|
|
1094
|
+
type: "object",
|
|
1095
|
+
properties: {
|
|
1096
|
+
specificationId: {
|
|
1097
|
+
type: "string",
|
|
1098
|
+
description: "Specification ID"
|
|
1099
|
+
}
|
|
1100
|
+
},
|
|
1101
|
+
required: ["specificationId"]
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
];
|
|
1105
|
+
return tools;
|
|
1106
|
+
}
|
|
1107
|
+
const RETRY_CONFIG = {
|
|
1108
|
+
maxRetries: 3,
|
|
1109
|
+
initialDelayMs: 500,
|
|
1110
|
+
maxDelayMs: 5e3,
|
|
1111
|
+
backoffMultiplier: 2
|
|
1112
|
+
};
|
|
1113
|
+
const TRANSIENT_ERROR_PATTERNS = [
|
|
1114
|
+
/ETIMEDOUT/i,
|
|
1115
|
+
/ECONNRESET/i,
|
|
1116
|
+
/ECONNREFUSED/i,
|
|
1117
|
+
/socket hang up/i,
|
|
1118
|
+
/network error/i,
|
|
1119
|
+
/too many requests/i,
|
|
1120
|
+
/rate limit/i,
|
|
1121
|
+
/5\d{2}/
|
|
1122
|
+
// 5xx status codes
|
|
1123
|
+
];
|
|
1124
|
+
function isTransientError(error) {
|
|
1125
|
+
return TRANSIENT_ERROR_PATTERNS.some(
|
|
1126
|
+
(pattern) => pattern.test(error.message)
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
function sleep(ms) {
|
|
1130
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1131
|
+
}
|
|
1132
|
+
async function withRetry(fn, toolName, debug) {
|
|
1133
|
+
let lastError = null;
|
|
1134
|
+
let delay = RETRY_CONFIG.initialDelayMs;
|
|
1135
|
+
for (let attempt = 1; attempt <= RETRY_CONFIG.maxRetries; attempt++) {
|
|
1136
|
+
try {
|
|
1137
|
+
return await fn();
|
|
1138
|
+
} catch (error) {
|
|
1139
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
1140
|
+
if (attempt < RETRY_CONFIG.maxRetries && isTransientError(lastError)) {
|
|
1141
|
+
if (debug) {
|
|
1142
|
+
console.error(
|
|
1143
|
+
`[DEBUG] Tool ${toolName} attempt ${attempt} failed with transient error, retrying in ${delay}ms:`,
|
|
1144
|
+
lastError.message
|
|
1145
|
+
);
|
|
1146
|
+
}
|
|
1147
|
+
await sleep(delay);
|
|
1148
|
+
delay = Math.min(delay * RETRY_CONFIG.backoffMultiplier, RETRY_CONFIG.maxDelayMs);
|
|
1149
|
+
} else {
|
|
1150
|
+
break;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
throw lastError;
|
|
1155
|
+
}
|
|
1156
|
+
function createToolHandlers(apiClient) {
|
|
1157
|
+
const callLocal = async (op, args) => {
|
|
1158
|
+
const body = await apiClient.getTransport().execute(op, args);
|
|
1159
|
+
if (body && typeof body === "object") {
|
|
1160
|
+
if (body.kind === "standard_error") {
|
|
1161
|
+
const guidance = body.guidance;
|
|
1162
|
+
const prose = guidance && typeof guidance.prose === "string" ? guidance.prose : void 0;
|
|
1163
|
+
throw new Error(
|
|
1164
|
+
prose ?? (typeof body.message === "string" ? body.message : `Operation failed: ${op}`)
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
if (body.kind === "lifecycle" && "agentResponse" in body) {
|
|
1168
|
+
return body.agentResponse;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
return body;
|
|
1172
|
+
};
|
|
1173
|
+
return {
|
|
1174
|
+
// ========================================================================
|
|
1175
|
+
// Queries — forward the canonical super-tools straight through (the backend
|
|
1176
|
+
// owns the `type` dispatch; M9 dropped the old granular-op fan-out).
|
|
1177
|
+
// ========================================================================
|
|
1178
|
+
get: async (_client, args) => {
|
|
1179
|
+
if (!args.type) throw new Error("Missing required argument: type");
|
|
1180
|
+
const withCtx = injectContext(args, ["projectId", "specificationId"]);
|
|
1181
|
+
return await callLocal("get", withCtx);
|
|
1182
|
+
},
|
|
1183
|
+
list: async (_client, args) => {
|
|
1184
|
+
if (!args.type) throw new Error("Missing required argument: type");
|
|
1185
|
+
const withCtx = injectContext(args, ["projectId", "specificationId"]);
|
|
1186
|
+
return await callLocal("list", withCtx);
|
|
1187
|
+
},
|
|
1188
|
+
search: async (_client, args) => {
|
|
1189
|
+
if (!args.query && !args.files && !args.tags && !args.relatedTo) {
|
|
1190
|
+
throw new Error("At least one filter is required: query, files, tags, or relatedTo");
|
|
1191
|
+
}
|
|
1192
|
+
const withCtx = injectContext(args, ["projectId", "specificationId"]);
|
|
1193
|
+
if (!withCtx.projectId && !withCtx.specificationId && !withCtx.epicId) {
|
|
1194
|
+
throw new Error('One of projectId, specificationId, or epicId is required. Run "specforge switch" or provide explicitly.');
|
|
1195
|
+
}
|
|
1196
|
+
return await callLocal("search", withCtx);
|
|
1197
|
+
},
|
|
1198
|
+
get_next_actionable_tickets: async (_client, args) => {
|
|
1199
|
+
const argsWithContext = injectContext(args, ["projectId", "specificationId"]);
|
|
1200
|
+
if (!argsWithContext.specificationId && !argsWithContext.projectId) {
|
|
1201
|
+
throw new Error('Either specificationId or projectId is required. Set working context with "specforge switch" or provide explicitly.');
|
|
1202
|
+
}
|
|
1203
|
+
return await callLocal("get_next_actionable_tickets", {
|
|
1204
|
+
specificationId: argsWithContext.specificationId,
|
|
1205
|
+
projectId: argsWithContext.projectId,
|
|
1206
|
+
limit: argsWithContext.limit ?? 5
|
|
1207
|
+
});
|
|
1208
|
+
},
|
|
1209
|
+
get_blocked_tickets: async (_client, args) => {
|
|
1210
|
+
const argsWithContext = injectContext(args, ["specificationId"]);
|
|
1211
|
+
if (!argsWithContext.specificationId) {
|
|
1212
|
+
throw new Error('specificationId is required. Set working context with "specforge switch" or provide explicitly.');
|
|
1213
|
+
}
|
|
1214
|
+
return await callLocal("get_blocked_tickets", {
|
|
1215
|
+
specificationId: argsWithContext.specificationId
|
|
1216
|
+
});
|
|
1217
|
+
},
|
|
1218
|
+
get_report: async (_client, args) => {
|
|
1219
|
+
validateRequired(args, "type", "scope", "scopeId");
|
|
1220
|
+
return await callLocal("get_report", {
|
|
1221
|
+
type: args.type,
|
|
1222
|
+
scope: args.scope,
|
|
1223
|
+
scopeId: args.scopeId,
|
|
1224
|
+
format: args.format ?? "json",
|
|
1225
|
+
startDate: args.startDate,
|
|
1226
|
+
endDate: args.endDate
|
|
1227
|
+
});
|
|
1228
|
+
},
|
|
1229
|
+
// ========================================================================
|
|
1230
|
+
// Lifecycle
|
|
1231
|
+
// ========================================================================
|
|
1232
|
+
// Planning lifecycle (M9.6b) — identity/session injected from the
|
|
1233
|
+
// `.specforge` config; SPS persists the session id, a `closed` status
|
|
1234
|
+
// clears it. Payloads match the post-M8 boundary (SPS {specificationId};
|
|
1235
|
+
// APS {sessionId, operation:{type,...}}; CPS {sessionId}).
|
|
1236
|
+
start_planning_session: async (_client, args) => {
|
|
1237
|
+
const cfg = tryLoadProjectConfig();
|
|
1238
|
+
const specificationId = args.specificationId ?? cfg?.specificationId;
|
|
1239
|
+
if (!specificationId) {
|
|
1240
|
+
throw new Error("No active specification. Run `specforge switch <spec-id>` or pass specificationId.");
|
|
1241
|
+
}
|
|
1242
|
+
const agentResponse = await callLocal(
|
|
1243
|
+
"start_planning_session",
|
|
1244
|
+
{ specificationId }
|
|
1245
|
+
);
|
|
1246
|
+
if (agentResponse?.sessionId) {
|
|
1247
|
+
saveProjectConfig({ planningSessionId: agentResponse.sessionId });
|
|
1248
|
+
appendPlanningSessionRegistry({
|
|
1249
|
+
specificationId,
|
|
1250
|
+
planningSessionId: agentResponse.sessionId,
|
|
1251
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
return agentResponse;
|
|
1255
|
+
},
|
|
1256
|
+
action_planning_session: async (_client, args) => {
|
|
1257
|
+
if (!args.operation || typeof args.operation !== "object") {
|
|
1258
|
+
throw new Error('Missing required argument: operation (e.g. { type: "get_planning_status" })');
|
|
1259
|
+
}
|
|
1260
|
+
const cfg = tryLoadProjectConfig();
|
|
1261
|
+
const sessionId = args.sessionId ?? cfg?.planningSessionId;
|
|
1262
|
+
if (!sessionId) {
|
|
1263
|
+
throw new Error("No active planning session. Call start_planning_session first.");
|
|
1264
|
+
}
|
|
1265
|
+
const agentResponse = await callLocal(
|
|
1266
|
+
"action_planning_session",
|
|
1267
|
+
{ sessionId, operation: args.operation }
|
|
1268
|
+
);
|
|
1269
|
+
if (agentResponse?.planningStatus === "closed" && cfg?.specificationId) {
|
|
1270
|
+
saveProjectConfig({ planningSessionId: void 0 });
|
|
1271
|
+
markPlanningSessionRegistryCompleted({
|
|
1272
|
+
specificationId: cfg.specificationId,
|
|
1273
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1274
|
+
});
|
|
1275
|
+
}
|
|
1276
|
+
return agentResponse;
|
|
1277
|
+
},
|
|
1278
|
+
complete_planning_session: async (_client, args) => {
|
|
1279
|
+
const cfg = tryLoadProjectConfig();
|
|
1280
|
+
const sessionId = args.sessionId ?? cfg?.planningSessionId;
|
|
1281
|
+
if (!sessionId) {
|
|
1282
|
+
throw new Error("No active planning session. Call start_planning_session first.");
|
|
1283
|
+
}
|
|
1284
|
+
return await callLocal("complete_planning_session", { sessionId });
|
|
1285
|
+
},
|
|
1286
|
+
start_work_session: async (_client, args) => {
|
|
1287
|
+
validateRequired(args, "ticketId");
|
|
1288
|
+
return await callLocal("start_work_session", {
|
|
1289
|
+
ticketId: args.ticketId
|
|
1290
|
+
});
|
|
1291
|
+
},
|
|
1292
|
+
action_work_session: async (_client, args) => {
|
|
1293
|
+
validateRequired(args, "ticketId");
|
|
1294
|
+
return await callLocal("action_work_session", {
|
|
1295
|
+
ticketId: args.ticketId,
|
|
1296
|
+
steps: args.steps,
|
|
1297
|
+
allStepsDone: args.allStepsDone,
|
|
1298
|
+
acceptanceCriteria: args.acceptanceCriteria,
|
|
1299
|
+
allACValidated: args.allACValidated,
|
|
1300
|
+
testResults: args.testResults,
|
|
1301
|
+
notes: args.notes,
|
|
1302
|
+
filesCreated: args.filesCreated,
|
|
1303
|
+
filesModified: args.filesModified,
|
|
1304
|
+
filesDeleted: args.filesDeleted,
|
|
1305
|
+
discovery: args.discovery,
|
|
1306
|
+
blockReason: args.blockReason,
|
|
1307
|
+
getTicket: args.getTicket,
|
|
1308
|
+
includeFullContext: args.includeFullContext,
|
|
1309
|
+
codeSnippetsReviewed: args.codeSnippetsReviewed,
|
|
1310
|
+
typeReferencesReviewed: args.typeReferencesReviewed
|
|
1311
|
+
});
|
|
1312
|
+
},
|
|
1313
|
+
complete_work_session: async (_client, args) => {
|
|
1314
|
+
validateRequired(args, "ticketId", "summary");
|
|
1315
|
+
return await callLocal("complete_work_session", {
|
|
1316
|
+
ticketId: args.ticketId,
|
|
1317
|
+
summary: args.summary,
|
|
1318
|
+
filesModified: args.filesModified,
|
|
1319
|
+
filesCreated: args.filesCreated,
|
|
1320
|
+
filesDeleted: args.filesDeleted,
|
|
1321
|
+
actualHours: args.actualHours,
|
|
1322
|
+
validation: args.validation
|
|
1323
|
+
});
|
|
1324
|
+
},
|
|
1325
|
+
start_review_session: async (_client, args) => {
|
|
1326
|
+
const argsWithContext = injectContextRequired(args, ["specificationId"]);
|
|
1327
|
+
return await callLocal("start_review_session", {
|
|
1328
|
+
specificationId: argsWithContext.specificationId
|
|
1329
|
+
});
|
|
1330
|
+
},
|
|
1331
|
+
action_review_session: async (_client, args) => {
|
|
1332
|
+
const argsWithContext = injectContextRequired(args, ["specificationId"]);
|
|
1333
|
+
return await callLocal("action_review_session", {
|
|
1334
|
+
specificationId: argsWithContext.specificationId,
|
|
1335
|
+
reviewSessionId: args.reviewSessionId,
|
|
1336
|
+
findingsAddressed: args.findingsAddressed,
|
|
1337
|
+
notes: args.notes
|
|
1338
|
+
});
|
|
1339
|
+
},
|
|
1340
|
+
complete_review_session: async (_client, args) => {
|
|
1341
|
+
const argsWithContext = injectContextRequired(args, ["specificationId"]);
|
|
1342
|
+
return await callLocal("complete_review_session", {
|
|
1343
|
+
specificationId: argsWithContext.specificationId,
|
|
1344
|
+
reviewSessionId: args.reviewSessionId,
|
|
1345
|
+
summary: args.summary,
|
|
1346
|
+
confirmAllDismissed: args.confirmAllDismissed
|
|
1347
|
+
});
|
|
1348
|
+
},
|
|
1349
|
+
reopen_specification: async (_client, args) => {
|
|
1350
|
+
const argsWithContext = injectContextRequired(args, ["specificationId"]);
|
|
1351
|
+
return await callLocal("reopen_specification", {
|
|
1352
|
+
specificationId: argsWithContext.specificationId
|
|
1353
|
+
});
|
|
1354
|
+
},
|
|
1355
|
+
// ========================================================================
|
|
1356
|
+
// Mutation
|
|
1357
|
+
// ========================================================================
|
|
1358
|
+
// ========================================================================
|
|
1359
|
+
// Utilities
|
|
1360
|
+
// ========================================================================
|
|
1361
|
+
feedback: async (_client, args) => {
|
|
1362
|
+
return await callLocal("feedback", args);
|
|
1363
|
+
},
|
|
1364
|
+
reset_work_session: async (_client, args) => {
|
|
1365
|
+
validateRequired(args, "specificationId");
|
|
1366
|
+
return await callLocal("reset_work_session", {
|
|
1367
|
+
specificationId: args.specificationId,
|
|
1368
|
+
ticketIds: args.ticketIds,
|
|
1369
|
+
fromTicketId: args.fromTicketId,
|
|
1370
|
+
epicId: args.epicId,
|
|
1371
|
+
allTickets: args.allTickets,
|
|
1372
|
+
targetStatus: args.targetStatus,
|
|
1373
|
+
resetDependents: args.resetDependents,
|
|
1374
|
+
includeCompleted: args.includeCompleted,
|
|
1375
|
+
preserveNotes: args.preserveNotes,
|
|
1376
|
+
clearTestResults: args.clearTestResults
|
|
1377
|
+
});
|
|
1378
|
+
},
|
|
1379
|
+
link_pull_request: async (_client, args) => {
|
|
1380
|
+
validateRequired(args, "ticketId");
|
|
1381
|
+
if (!args.prNumber && !args.prUrl) {
|
|
1382
|
+
throw new Error("Either prNumber or prUrl must be provided");
|
|
1383
|
+
}
|
|
1384
|
+
return await callLocal("link_pull_request", {
|
|
1385
|
+
ticketId: args.ticketId,
|
|
1386
|
+
prNumber: args.prNumber,
|
|
1387
|
+
prUrl: args.prUrl,
|
|
1388
|
+
title: args.title,
|
|
1389
|
+
author: args.author,
|
|
1390
|
+
repoUrl: args.repoUrl
|
|
1391
|
+
});
|
|
1392
|
+
},
|
|
1393
|
+
// ========================================================================
|
|
1394
|
+
// Orchestration
|
|
1395
|
+
// ========================================================================
|
|
1396
|
+
get_critical_path: async (_client, args) => {
|
|
1397
|
+
const argsWithContext = injectContext(args, ["specificationId"]);
|
|
1398
|
+
if (!argsWithContext.specificationId) {
|
|
1399
|
+
throw new Error("specificationId is required");
|
|
1400
|
+
}
|
|
1401
|
+
return await callLocal("get_critical_path", {
|
|
1402
|
+
specificationId: argsWithContext.specificationId
|
|
1403
|
+
});
|
|
1404
|
+
},
|
|
1405
|
+
get_dependency_tree: async (_client, args) => {
|
|
1406
|
+
const argsWithContext = injectContext(args, ["specificationId"]);
|
|
1407
|
+
if (!argsWithContext.specificationId) {
|
|
1408
|
+
throw new Error("specificationId is required");
|
|
1409
|
+
}
|
|
1410
|
+
return await callLocal("get_dependency_tree", {
|
|
1411
|
+
specificationId: argsWithContext.specificationId
|
|
1412
|
+
});
|
|
1413
|
+
}
|
|
1414
|
+
};
|
|
1415
|
+
}
|
|
1416
|
+
function validateRequired(args, ...required) {
|
|
1417
|
+
for (const field of required) {
|
|
1418
|
+
if (args[field] === void 0 || args[field] === null || args[field] === "") {
|
|
1419
|
+
throw new Error(`Missing required argument: ${field}`);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
let cachedHandlers = null;
|
|
1424
|
+
function resetToolHandlers() {
|
|
1425
|
+
cachedHandlers = null;
|
|
1426
|
+
}
|
|
1427
|
+
async function handleToolCall(apiClient, toolName, args, debug = false) {
|
|
1428
|
+
const startTime = Date.now();
|
|
1429
|
+
if (!cachedHandlers) {
|
|
1430
|
+
cachedHandlers = createToolHandlers(apiClient);
|
|
1431
|
+
}
|
|
1432
|
+
const handler = cachedHandlers[toolName];
|
|
1433
|
+
if (!handler) {
|
|
1434
|
+
throw new Error(`Unknown tool: ${toolName}`);
|
|
1435
|
+
}
|
|
1436
|
+
if (debug) {
|
|
1437
|
+
console.error(`[DEBUG] Calling tool: ${toolName}`, {
|
|
1438
|
+
args: JSON.stringify(args)
|
|
1439
|
+
});
|
|
1440
|
+
}
|
|
1441
|
+
try {
|
|
1442
|
+
validateToolArgs(toolName, args);
|
|
1443
|
+
const result = await withRetry(
|
|
1444
|
+
() => handler(apiClient, args),
|
|
1445
|
+
toolName,
|
|
1446
|
+
debug
|
|
1447
|
+
);
|
|
1448
|
+
const duration = Date.now() - startTime;
|
|
1449
|
+
if (debug) {
|
|
1450
|
+
console.error(`[DEBUG] Tool ${toolName} completed in ${duration}ms`);
|
|
1451
|
+
}
|
|
1452
|
+
return result;
|
|
1453
|
+
} catch (error) {
|
|
1454
|
+
const duration = Date.now() - startTime;
|
|
1455
|
+
const transformedError = transformError(error);
|
|
1456
|
+
const message = transformedError.message;
|
|
1457
|
+
if (debug) {
|
|
1458
|
+
console.error(`[DEBUG] Tool ${toolName} failed after ${duration}ms:`, message);
|
|
1459
|
+
if (transformedError instanceof ValidationError) {
|
|
1460
|
+
console.error(`[DEBUG] Validation field: ${transformedError.field}, code: ${transformedError.code}`);
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
if (transformedError instanceof ValidationError) {
|
|
1464
|
+
throw transformedError;
|
|
1465
|
+
}
|
|
1466
|
+
if (transformedError instanceof ApiError) {
|
|
1467
|
+
throw transformedError;
|
|
1468
|
+
}
|
|
1469
|
+
throw new Error(`Tool ${toolName} failed: ${message}`);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
async function handleToolCallSafe(apiClient, toolName, args, debug = false) {
|
|
1473
|
+
try {
|
|
1474
|
+
return await handleToolCall(apiClient, toolName, args, debug);
|
|
1475
|
+
} catch (error) {
|
|
1476
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
1477
|
+
return formatMCPError(err);
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
import {
|
|
1481
|
+
ValidationError as ValidationError2,
|
|
1482
|
+
ApiError as ApiError2,
|
|
1483
|
+
validateToolArgs as validateToolArgs2,
|
|
1484
|
+
formatMCPError as formatMCPError2,
|
|
1485
|
+
transformError as transformError2
|
|
1486
|
+
} from "../validation/index.js";
|
|
1487
|
+
export {
|
|
1488
|
+
ApiError2 as ApiError,
|
|
1489
|
+
ValidationError2 as ValidationError,
|
|
1490
|
+
createToolHandlers,
|
|
1491
|
+
formatMCPError2 as formatMCPError,
|
|
1492
|
+
getTools,
|
|
1493
|
+
handleToolCall,
|
|
1494
|
+
handleToolCallSafe,
|
|
1495
|
+
resetToolHandlers,
|
|
1496
|
+
transformError2 as transformError,
|
|
1497
|
+
validateToolArgs2 as validateToolArgs
|
|
1498
|
+
};
|
|
1499
|
+
//# sourceMappingURL=index.js.map
|