@specforge/mcp 3.1.2 → 3.2.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/dist/autopilot/api/autopilot-api-client.d.ts.map +1 -1
- package/dist/autopilot/api/autopilot-api-client.js +0 -8
- package/dist/autopilot/api/autopilot-api-client.js.map +1 -1
- package/dist/autopilot/readiness/post-scoring.js +3 -1
- package/dist/autopilot/readiness/post-scoring.js.map +1 -1
- package/dist/cli/commands/docs/tool-examples.js +4 -3
- package/dist/cli/commands/docs/tool-examples.js.map +1 -1
- package/dist/cli/commands/docs/types.js +1 -1
- package/dist/cli/commands/docs/types.js.map +1 -1
- package/dist/lib/prompt-generator.js +1 -1
- package/dist/lib/prompt-generator.js.map +1 -1
- package/dist/tools/core/help.js +1 -1
- package/dist/tools/core/help.js.map +1 -1
- package/dist/tools/core/index.d.ts +0 -1
- package/dist/tools/core/index.d.ts.map +1 -1
- package/dist/tools/core/index.js +0 -1
- package/dist/tools/core/index.js.map +1 -1
- package/dist/tools/core/session.d.ts.map +1 -1
- package/dist/tools/core/session.js +6 -21
- package/dist/tools/core/session.js.map +1 -1
- package/dist/tools/core/ticket.js +1 -1
- package/dist/tools/core/ticket.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +214 -279
- package/dist/tools/index.js.map +1 -1
- package/dist/types/index.d.ts +82 -11
- package/dist/types/index.d.ts.map +1 -1
- package/dist/validation/index.d.ts.map +1 -1
- package/dist/validation/index.js +20 -56
- package/dist/validation/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/templates/skills/specforge-orchestrator.md +17 -15
- package/src/cli/templates/skills/specforge-worker.md +1 -9
package/dist/tools/index.js
CHANGED
|
@@ -82,8 +82,6 @@ const READ_TOOL_NAMES = new Set([
|
|
|
82
82
|
'search_tickets',
|
|
83
83
|
// Working context
|
|
84
84
|
'get_working_context',
|
|
85
|
-
// Job status
|
|
86
|
-
'get_job_status',
|
|
87
85
|
// Agent Teams (read operations)
|
|
88
86
|
'get_epic_dependency_graph',
|
|
89
87
|
'get_implementation_plan',
|
|
@@ -726,7 +724,7 @@ Examples:
|
|
|
726
724
|
// ========================================================================
|
|
727
725
|
{
|
|
728
726
|
name: 'start_work_session',
|
|
729
|
-
description: 'Start working on a ticket.
|
|
727
|
+
description: 'Start working on a ticket. Creates a WorkSession record and transitions ready -> active. Returns the workSessionId along with error with statusReason if ticket is pending (dependencies not met).',
|
|
730
728
|
inputSchema: {
|
|
731
729
|
type: 'object',
|
|
732
730
|
properties: {
|
|
@@ -740,10 +738,9 @@ Examples:
|
|
|
740
738
|
},
|
|
741
739
|
{
|
|
742
740
|
name: 'complete_work_session',
|
|
743
|
-
description: 'Mark a ticket as complete. Transitions active -> done.\n\n' +
|
|
741
|
+
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\n' +
|
|
742
|
+
'All acceptance criteria must be validated and all implementation steps must be completed via action_work_session before calling this. The completion gate enforces this — shortcuts are not available.\n\n' +
|
|
744
743
|
'Automatically recalculates status for dependent tickets and returns cascade info.\n\n' +
|
|
745
|
-
'By default, checks if summary addresses acceptance criteria and returns warnings (not errors) for gaps.\n\n' +
|
|
746
|
-
'Use validated: true as a simple confirmation that the agent has verified all work meets criteria.\n\n' +
|
|
747
744
|
'Optional validation flags can be provided to report test results inline:\n' +
|
|
748
745
|
'- tests: Unit/integration test results\n' +
|
|
749
746
|
'- lint: Linting results\n' +
|
|
@@ -770,21 +767,18 @@ Examples:
|
|
|
770
767
|
items: { type: 'string' },
|
|
771
768
|
description: 'List of files created',
|
|
772
769
|
},
|
|
770
|
+
filesDeleted: {
|
|
771
|
+
type: 'array',
|
|
772
|
+
items: { type: 'string' },
|
|
773
|
+
description: 'List of files deleted',
|
|
774
|
+
},
|
|
773
775
|
actualHours: {
|
|
774
776
|
type: 'number',
|
|
775
777
|
description: 'Actual hours spent on the ticket',
|
|
776
778
|
},
|
|
777
|
-
validated: {
|
|
778
|
-
type: 'boolean',
|
|
779
|
-
description: 'Simple validation confirmation. When true, indicates:\n' +
|
|
780
|
-
'- Agent has verified work meets acceptance criteria\n' +
|
|
781
|
-
'- All necessary tests/validations were run and passed\n' +
|
|
782
|
-
'- No detailed breakdown needed\n' +
|
|
783
|
-
'Trust-based approach for streamlined completion.',
|
|
784
|
-
},
|
|
785
779
|
validation: {
|
|
786
780
|
type: 'object',
|
|
787
|
-
description: 'Detailed validation flags
|
|
781
|
+
description: 'Detailed validation flags for reporting test/lint/build results',
|
|
788
782
|
properties: {
|
|
789
783
|
tests: {
|
|
790
784
|
type: 'string',
|
|
@@ -812,61 +806,175 @@ Examples:
|
|
|
812
806
|
},
|
|
813
807
|
},
|
|
814
808
|
},
|
|
815
|
-
skipCriteriaCheck: {
|
|
816
|
-
type: 'boolean',
|
|
817
|
-
description: 'Skip acceptance criteria validation. Use for trivial changes or when criteria check is not needed. Default: false',
|
|
818
|
-
},
|
|
819
809
|
},
|
|
820
810
|
required: ['ticketId', 'summary'],
|
|
821
811
|
},
|
|
822
812
|
},
|
|
823
813
|
{
|
|
824
|
-
name: '
|
|
825
|
-
description: '
|
|
814
|
+
name: 'pause_work_session',
|
|
815
|
+
description: 'Pause work on a ticket, setting it back to ready status. Use this to temporarily pause work on a ticket without completing it.',
|
|
826
816
|
inputSchema: {
|
|
827
817
|
type: 'object',
|
|
828
818
|
properties: {
|
|
829
819
|
ticketId: {
|
|
830
820
|
type: 'string',
|
|
831
|
-
description: 'The ID of the ticket',
|
|
832
|
-
},
|
|
833
|
-
progress: {
|
|
834
|
-
type: 'number',
|
|
835
|
-
minimum: 0,
|
|
836
|
-
maximum: 100,
|
|
837
|
-
description: 'Progress percentage (0-100)',
|
|
838
|
-
},
|
|
839
|
-
message: {
|
|
840
|
-
type: 'string',
|
|
841
|
-
description: 'Progress message',
|
|
821
|
+
description: 'The ID of the ticket to pause',
|
|
842
822
|
},
|
|
843
823
|
},
|
|
844
|
-
required: ['ticketId'
|
|
824
|
+
required: ['ticketId'],
|
|
845
825
|
},
|
|
846
826
|
},
|
|
847
827
|
{
|
|
848
|
-
name: '
|
|
849
|
-
description: '
|
|
828
|
+
name: 'resume_work_session',
|
|
829
|
+
description: 'Resume work on a paused ticket, setting it to active status. Use this to continue work on a ticket that was previously paused.',
|
|
850
830
|
inputSchema: {
|
|
851
831
|
type: 'object',
|
|
852
832
|
properties: {
|
|
853
833
|
ticketId: {
|
|
854
834
|
type: 'string',
|
|
855
|
-
description: 'The ID of the ticket to
|
|
835
|
+
description: 'The ID of the ticket to resume',
|
|
856
836
|
},
|
|
857
837
|
},
|
|
858
838
|
required: ['ticketId'],
|
|
859
839
|
},
|
|
860
840
|
},
|
|
861
841
|
{
|
|
862
|
-
name: '
|
|
863
|
-
description:
|
|
842
|
+
name: 'action_work_session',
|
|
843
|
+
description: `Update checklist state during an active WorkSession. Combines step completion, AC validation, test result reporting, and file tracking into a single atomic operation. All state changes are recorded on the WorkSession and its related validation/completion records.
|
|
844
|
+
|
|
845
|
+
Use this instead of calling update_ticket for checklist changes. Provides:
|
|
846
|
+
- Step completion (individual or bulk via WorkSessionStepCompletion)
|
|
847
|
+
- Acceptance criteria validation (individual or bulk via WorkSessionACValidation)
|
|
848
|
+
- Test result reporting (merged by test type via WorkSessionTestResult)
|
|
849
|
+
- File tracking (created, modified, deleted on WorkSession)
|
|
850
|
+
- Blocker management (set/clear block reasons)
|
|
851
|
+
- Auto-calculated progress percentage
|
|
852
|
+
- Completion readiness hints
|
|
853
|
+
|
|
854
|
+
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.`,
|
|
864
855
|
inputSchema: {
|
|
865
856
|
type: 'object',
|
|
866
857
|
properties: {
|
|
867
858
|
ticketId: {
|
|
868
859
|
type: 'string',
|
|
869
|
-
description: 'The ID of the ticket
|
|
860
|
+
description: 'The ID of the ticket being worked on (must be in active status)',
|
|
861
|
+
},
|
|
862
|
+
steps: {
|
|
863
|
+
type: 'array',
|
|
864
|
+
description: 'Individual step completion updates',
|
|
865
|
+
items: {
|
|
866
|
+
type: 'object',
|
|
867
|
+
properties: {
|
|
868
|
+
index: {
|
|
869
|
+
type: 'number',
|
|
870
|
+
description: 'Zero-based index of the step in the implementation.steps array',
|
|
871
|
+
},
|
|
872
|
+
completed: {
|
|
873
|
+
type: 'boolean',
|
|
874
|
+
description: 'Whether the step is completed',
|
|
875
|
+
},
|
|
876
|
+
notes: {
|
|
877
|
+
type: 'string',
|
|
878
|
+
description: 'Optional note about this step',
|
|
879
|
+
},
|
|
880
|
+
},
|
|
881
|
+
required: ['index', 'completed'],
|
|
882
|
+
},
|
|
883
|
+
},
|
|
884
|
+
allStepsDone: {
|
|
885
|
+
type: 'boolean',
|
|
886
|
+
description: 'Shortcut: mark all steps as completed',
|
|
887
|
+
},
|
|
888
|
+
acceptanceCriteria: {
|
|
889
|
+
type: 'array',
|
|
890
|
+
description: 'Individual AC validation updates',
|
|
891
|
+
items: {
|
|
892
|
+
type: 'object',
|
|
893
|
+
properties: {
|
|
894
|
+
index: {
|
|
895
|
+
type: 'number',
|
|
896
|
+
description: 'Zero-based index of the AC in the acceptanceCriteria array',
|
|
897
|
+
},
|
|
898
|
+
validated: {
|
|
899
|
+
type: 'boolean',
|
|
900
|
+
description: 'Whether the AC is validated',
|
|
901
|
+
},
|
|
902
|
+
notes: {
|
|
903
|
+
type: 'string',
|
|
904
|
+
description: 'Optional note about this AC',
|
|
905
|
+
},
|
|
906
|
+
},
|
|
907
|
+
required: ['index', 'validated'],
|
|
908
|
+
},
|
|
909
|
+
},
|
|
910
|
+
allACValidated: {
|
|
911
|
+
type: 'boolean',
|
|
912
|
+
description: 'Shortcut: mark all acceptance criteria as validated',
|
|
913
|
+
},
|
|
914
|
+
testResults: {
|
|
915
|
+
type: 'array',
|
|
916
|
+
description: 'Test result reports to append (merged by testType)',
|
|
917
|
+
items: {
|
|
918
|
+
type: 'object',
|
|
919
|
+
properties: {
|
|
920
|
+
testType: {
|
|
921
|
+
type: 'string',
|
|
922
|
+
description: 'Type of test (e.g., "unit", "integration", "e2e", "lint", "typeCheck")',
|
|
923
|
+
},
|
|
924
|
+
passed: {
|
|
925
|
+
type: 'number',
|
|
926
|
+
description: 'Number of tests that passed',
|
|
927
|
+
},
|
|
928
|
+
failed: {
|
|
929
|
+
type: 'number',
|
|
930
|
+
description: 'Number of tests that failed',
|
|
931
|
+
},
|
|
932
|
+
skipped: {
|
|
933
|
+
type: 'number',
|
|
934
|
+
description: 'Number of tests skipped',
|
|
935
|
+
},
|
|
936
|
+
command: {
|
|
937
|
+
type: 'string',
|
|
938
|
+
description: 'Command used to run the tests',
|
|
939
|
+
},
|
|
940
|
+
output: {
|
|
941
|
+
type: 'string',
|
|
942
|
+
description: 'Test output (truncated if needed)',
|
|
943
|
+
},
|
|
944
|
+
duration: {
|
|
945
|
+
type: 'number',
|
|
946
|
+
description: 'Duration in milliseconds',
|
|
947
|
+
},
|
|
948
|
+
},
|
|
949
|
+
required: ['testType', 'passed', 'failed'],
|
|
950
|
+
},
|
|
951
|
+
},
|
|
952
|
+
notes: {
|
|
953
|
+
type: 'string',
|
|
954
|
+
description: 'Additional notes to append to the ticket',
|
|
955
|
+
},
|
|
956
|
+
filesCreated: {
|
|
957
|
+
type: 'array',
|
|
958
|
+
items: { type: 'string' },
|
|
959
|
+
description: 'Files created during this session. Accumulated incrementally.',
|
|
960
|
+
},
|
|
961
|
+
filesModified: {
|
|
962
|
+
type: 'array',
|
|
963
|
+
items: { type: 'string' },
|
|
964
|
+
description: 'Files modified during this session. Accumulated incrementally.',
|
|
965
|
+
},
|
|
966
|
+
filesDeleted: {
|
|
967
|
+
type: 'array',
|
|
968
|
+
items: { type: 'string' },
|
|
969
|
+
description: 'Files deleted during this session. Accumulated incrementally.',
|
|
970
|
+
},
|
|
971
|
+
blockReason: {
|
|
972
|
+
type: 'string',
|
|
973
|
+
description: 'Set a blocker on this ticket. Requires a prior discovery via report_discovery.',
|
|
974
|
+
},
|
|
975
|
+
clearBlockReason: {
|
|
976
|
+
type: 'boolean',
|
|
977
|
+
description: 'Clear existing blocker and resume work.',
|
|
870
978
|
},
|
|
871
979
|
},
|
|
872
980
|
required: ['ticketId'],
|
|
@@ -883,7 +991,7 @@ Report types:
|
|
|
883
991
|
- 'implementation': Progress, velocity, completions (replaces get_implementation_summary)
|
|
884
992
|
- 'time': Estimated vs actual hours (replaces get_time_report)
|
|
885
993
|
- 'blockers': Blocked tickets with reasons (replaces get_blockers_report)
|
|
886
|
-
- 'work': Completed work summary (replaces get_work_summary)
|
|
994
|
+
- 'work': Completed work summary from WorkSession records (replaces get_work_summary)
|
|
887
995
|
|
|
888
996
|
Format options:
|
|
889
997
|
- 'json': Full structured data (default)
|
|
@@ -1475,10 +1583,6 @@ At least one scope filter (projectId, specificationId, or epicId) is required.`,
|
|
|
1475
1583
|
items: { type: 'string' },
|
|
1476
1584
|
description: 'Array of ticket IDs this ticket depends on',
|
|
1477
1585
|
},
|
|
1478
|
-
skipValidation: {
|
|
1479
|
-
type: 'boolean',
|
|
1480
|
-
description: 'Skip validation and completeness scoring. Default: false',
|
|
1481
|
-
},
|
|
1482
1586
|
validationStrictness: {
|
|
1483
1587
|
type: 'string',
|
|
1484
1588
|
enum: ['lenient', 'normal', 'strict'],
|
|
@@ -1587,11 +1691,6 @@ At least one scope filter (projectId, specificationId, or epicId) is required.`,
|
|
|
1587
1691
|
type: 'object',
|
|
1588
1692
|
description: 'Technical details like stack, endpoints (JSON) (optional)',
|
|
1589
1693
|
},
|
|
1590
|
-
skipValidation: {
|
|
1591
|
-
type: 'boolean',
|
|
1592
|
-
description: 'Skip validation and completeness scoring (default: false)',
|
|
1593
|
-
default: false,
|
|
1594
|
-
},
|
|
1595
1694
|
validationStrictness: {
|
|
1596
1695
|
type: 'string',
|
|
1597
1696
|
enum: ['lenient', 'normal', 'strict'],
|
|
@@ -2043,119 +2142,6 @@ At least one scope filter (projectId, specificationId, or epicId) is required.`,
|
|
|
2043
2142
|
// ========================================================================
|
|
2044
2143
|
// Bulk Operations
|
|
2045
2144
|
// ========================================================================
|
|
2046
|
-
{
|
|
2047
|
-
name: 'bulk_create_tickets',
|
|
2048
|
-
description: 'Create multiple tickets in an epic with optional inline dependencies in a single atomic transaction. Reduces 15+ API calls to one.',
|
|
2049
|
-
inputSchema: {
|
|
2050
|
-
type: 'object',
|
|
2051
|
-
properties: {
|
|
2052
|
-
epicId: {
|
|
2053
|
-
type: 'string',
|
|
2054
|
-
description: 'The ID of the epic to create tickets in',
|
|
2055
|
-
},
|
|
2056
|
-
tickets: {
|
|
2057
|
-
type: 'array',
|
|
2058
|
-
description: 'Array of ticket definitions to create',
|
|
2059
|
-
items: {
|
|
2060
|
-
type: 'object',
|
|
2061
|
-
properties: {
|
|
2062
|
-
title: { type: 'string', description: 'Ticket title (required)' },
|
|
2063
|
-
description: { type: 'string', description: 'Ticket description' },
|
|
2064
|
-
estimatedHours: { type: 'number', description: 'Estimated hours' },
|
|
2065
|
-
complexity: {
|
|
2066
|
-
type: 'string',
|
|
2067
|
-
enum: ['small', 'medium', 'large', 'xlarge'],
|
|
2068
|
-
description: 'Complexity level',
|
|
2069
|
-
},
|
|
2070
|
-
priority: {
|
|
2071
|
-
type: 'string',
|
|
2072
|
-
enum: ['high', 'medium', 'low'],
|
|
2073
|
-
description: 'Priority level',
|
|
2074
|
-
},
|
|
2075
|
-
acceptanceCriteria: {
|
|
2076
|
-
type: 'array',
|
|
2077
|
-
items: { type: 'string' },
|
|
2078
|
-
description: 'Acceptance criteria',
|
|
2079
|
-
},
|
|
2080
|
-
implementation: {
|
|
2081
|
-
type: 'object',
|
|
2082
|
-
description: 'Implementation details (filesToCreate, filesToModify, steps, etc.)',
|
|
2083
|
-
},
|
|
2084
|
-
technicalDetails: {
|
|
2085
|
-
type: 'object',
|
|
2086
|
-
description: 'Technical details (files, stack, endpoints, etc.)',
|
|
2087
|
-
},
|
|
2088
|
-
tags: {
|
|
2089
|
-
type: 'array',
|
|
2090
|
-
items: { type: 'string' },
|
|
2091
|
-
description: 'Tags',
|
|
2092
|
-
},
|
|
2093
|
-
},
|
|
2094
|
-
required: ['title'],
|
|
2095
|
-
},
|
|
2096
|
-
},
|
|
2097
|
-
dependencies: {
|
|
2098
|
-
type: 'array',
|
|
2099
|
-
description: 'Optional inline dependencies using array indexes',
|
|
2100
|
-
items: {
|
|
2101
|
-
type: 'object',
|
|
2102
|
-
properties: {
|
|
2103
|
-
ticket: {
|
|
2104
|
-
type: 'number',
|
|
2105
|
-
description: 'Index of the ticket in the tickets array',
|
|
2106
|
-
},
|
|
2107
|
-
dependsOn: {
|
|
2108
|
-
oneOf: [
|
|
2109
|
-
{ type: 'number', description: 'Index of the ticket it depends on' },
|
|
2110
|
-
{
|
|
2111
|
-
type: 'array',
|
|
2112
|
-
items: { type: 'number' },
|
|
2113
|
-
description: 'Indexes of the tickets it depends on',
|
|
2114
|
-
},
|
|
2115
|
-
],
|
|
2116
|
-
description: 'Index(es) of the ticket(s) it depends on',
|
|
2117
|
-
},
|
|
2118
|
-
},
|
|
2119
|
-
required: ['ticket', 'dependsOn'],
|
|
2120
|
-
},
|
|
2121
|
-
},
|
|
2122
|
-
onError: {
|
|
2123
|
-
type: 'string',
|
|
2124
|
-
enum: ['rollback', 'continue'],
|
|
2125
|
-
description: "Error handling mode: 'rollback' stops and undoes all, 'continue' skips failures (default: 'continue')",
|
|
2126
|
-
},
|
|
2127
|
-
},
|
|
2128
|
-
required: ['epicId', 'tickets'],
|
|
2129
|
-
},
|
|
2130
|
-
},
|
|
2131
|
-
{
|
|
2132
|
-
name: 'get_job_status',
|
|
2133
|
-
description: 'Get the status of an asynchronous bulk operation job. For batches >= 20 items, bulk operations return a job ID for async processing.',
|
|
2134
|
-
inputSchema: {
|
|
2135
|
-
type: 'object',
|
|
2136
|
-
properties: {
|
|
2137
|
-
jobId: {
|
|
2138
|
-
type: 'string',
|
|
2139
|
-
description: 'The job ID returned from a bulk operation',
|
|
2140
|
-
},
|
|
2141
|
-
},
|
|
2142
|
-
required: ['jobId'],
|
|
2143
|
-
},
|
|
2144
|
-
},
|
|
2145
|
-
{
|
|
2146
|
-
name: 'cancel_job',
|
|
2147
|
-
description: 'Cancel a running async job. Only queued or processing jobs can be cancelled.',
|
|
2148
|
-
inputSchema: {
|
|
2149
|
-
type: 'object',
|
|
2150
|
-
properties: {
|
|
2151
|
-
jobId: {
|
|
2152
|
-
type: 'string',
|
|
2153
|
-
description: 'The job ID returned from a bulk operation',
|
|
2154
|
-
},
|
|
2155
|
-
},
|
|
2156
|
-
required: ['jobId'],
|
|
2157
|
-
},
|
|
2158
|
-
},
|
|
2159
2145
|
{
|
|
2160
2146
|
name: 'bulk_add_dependencies',
|
|
2161
2147
|
description: 'Add multiple dependencies between tickets in a single atomic transaction.',
|
|
@@ -3223,19 +3209,9 @@ export function createToolHandlers(apiClient) {
|
|
|
3223
3209
|
summary: args.summary,
|
|
3224
3210
|
filesModified: args.filesModified,
|
|
3225
3211
|
filesCreated: args.filesCreated,
|
|
3212
|
+
filesDeleted: args.filesDeleted,
|
|
3226
3213
|
actualHours: args.actualHours,
|
|
3227
|
-
|
|
3228
|
-
validation: args.validation, // MCI-064: validation flags
|
|
3229
|
-
skipCriteriaCheck: args.skipCriteriaCheck, // MCI-065: skip criteria check
|
|
3230
|
-
});
|
|
3231
|
-
},
|
|
3232
|
-
report_progress: async (_client, args) => {
|
|
3233
|
-
validateRequired(args, 'ticketId', 'progress');
|
|
3234
|
-
validateRange(args.progress, 'progress', 0, 100);
|
|
3235
|
-
return await apiClient.call('report_progress', {
|
|
3236
|
-
ticketId: args.ticketId,
|
|
3237
|
-
progress: args.progress,
|
|
3238
|
-
message: args.message,
|
|
3214
|
+
validation: args.validation,
|
|
3239
3215
|
});
|
|
3240
3216
|
},
|
|
3241
3217
|
pause_work_session: async (_client, args) => {
|
|
@@ -3250,6 +3226,23 @@ export function createToolHandlers(apiClient) {
|
|
|
3250
3226
|
ticketId: args.ticketId,
|
|
3251
3227
|
});
|
|
3252
3228
|
},
|
|
3229
|
+
action_work_session: async (_client, args) => {
|
|
3230
|
+
validateRequired(args, 'ticketId');
|
|
3231
|
+
return await apiClient.call('action_work_session', {
|
|
3232
|
+
ticketId: args.ticketId,
|
|
3233
|
+
steps: args.steps,
|
|
3234
|
+
allStepsDone: args.allStepsDone,
|
|
3235
|
+
acceptanceCriteria: args.acceptanceCriteria,
|
|
3236
|
+
allACValidated: args.allACValidated,
|
|
3237
|
+
testResults: args.testResults,
|
|
3238
|
+
notes: args.notes,
|
|
3239
|
+
filesCreated: args.filesCreated,
|
|
3240
|
+
filesModified: args.filesModified,
|
|
3241
|
+
filesDeleted: args.filesDeleted,
|
|
3242
|
+
blockReason: args.blockReason,
|
|
3243
|
+
clearBlockReason: args.clearBlockReason,
|
|
3244
|
+
});
|
|
3245
|
+
},
|
|
3253
3246
|
// ========================================================================
|
|
3254
3247
|
// Status & Analytics Tools
|
|
3255
3248
|
// ========================================================================
|
|
@@ -3400,7 +3393,6 @@ export function createToolHandlers(apiClient) {
|
|
|
3400
3393
|
validateRequired(args, 'epicId', 'title');
|
|
3401
3394
|
const responseMode = getResponseModeFromArgs(args);
|
|
3402
3395
|
// Extract validation options
|
|
3403
|
-
const skipValidation = args.skipValidation === true;
|
|
3404
3396
|
const validationStrictness = args.validationStrictness === 'lenient' || args.validationStrictness === 'strict'
|
|
3405
3397
|
? args.validationStrictness
|
|
3406
3398
|
: 'normal';
|
|
@@ -3421,21 +3413,19 @@ export function createToolHandlers(apiClient) {
|
|
|
3421
3413
|
dependsOn: args.dependsOn,
|
|
3422
3414
|
notes: args.notes, // F8-001: Add missing notes field
|
|
3423
3415
|
});
|
|
3424
|
-
// Run validation
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
result.completenessScore = validation.completenessScore;
|
|
3438
|
-
}
|
|
3416
|
+
// Run validation
|
|
3417
|
+
const validation = validateTicket({
|
|
3418
|
+
complexity: args.complexity,
|
|
3419
|
+
implementation: args.implementation,
|
|
3420
|
+
technicalDetails: args.technicalDetails,
|
|
3421
|
+
notes: args.notes,
|
|
3422
|
+
acceptanceCriteria: args.acceptanceCriteria,
|
|
3423
|
+
});
|
|
3424
|
+
// Filter warnings by strictness level
|
|
3425
|
+
const warnings = filterWarningsByStrictness(validation.warnings, validationStrictness);
|
|
3426
|
+
// Add validation results to response
|
|
3427
|
+
result.warnings = warnings;
|
|
3428
|
+
result.completenessScore = validation.completenessScore;
|
|
3439
3429
|
return formatWriteResponse(result, responseMode, 'Ticket created');
|
|
3440
3430
|
},
|
|
3441
3431
|
import_specification: async (_client, args) => {
|
|
@@ -3454,31 +3444,28 @@ export function createToolHandlers(apiClient) {
|
|
|
3454
3444
|
validateRequired(args, 'ticketId');
|
|
3455
3445
|
const responseMode = getResponseModeFromArgs(args);
|
|
3456
3446
|
// Extract validation options
|
|
3457
|
-
const skipValidation = args.skipValidation === true;
|
|
3458
3447
|
const validationStrictness = args.validationStrictness === 'lenient' || args.validationStrictness === 'strict'
|
|
3459
3448
|
? args.validationStrictness
|
|
3460
3449
|
: 'normal';
|
|
3461
3450
|
// Get current ticket to calculate previous completeness score
|
|
3462
3451
|
let previousCompletenessScore;
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
previousCompletenessScore = undefined;
|
|
3481
|
-
}
|
|
3452
|
+
try {
|
|
3453
|
+
const currentTicket = await apiClient.call('get_ticket', {
|
|
3454
|
+
ticketId: args.ticketId,
|
|
3455
|
+
});
|
|
3456
|
+
// Calculate previous completeness score
|
|
3457
|
+
const prevValidation = validateTicket({
|
|
3458
|
+
complexity: currentTicket.complexity,
|
|
3459
|
+
implementation: currentTicket.implementation,
|
|
3460
|
+
technicalDetails: currentTicket.technicalDetails,
|
|
3461
|
+
notes: currentTicket.notes,
|
|
3462
|
+
acceptanceCriteria: currentTicket.acceptanceCriteria,
|
|
3463
|
+
});
|
|
3464
|
+
previousCompletenessScore = prevValidation.completenessScore;
|
|
3465
|
+
}
|
|
3466
|
+
catch {
|
|
3467
|
+
// If we can't get the current ticket, skip previous score tracking
|
|
3468
|
+
previousCompletenessScore = undefined;
|
|
3482
3469
|
}
|
|
3483
3470
|
// Update the ticket
|
|
3484
3471
|
const result = await apiClient.call('update_ticket', {
|
|
@@ -3497,25 +3484,23 @@ export function createToolHandlers(apiClient) {
|
|
|
3497
3484
|
technicalDetails: args.technicalDetails,
|
|
3498
3485
|
blockReason: args.blockReason,
|
|
3499
3486
|
});
|
|
3500
|
-
// Run validation on updated ticket
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
result.previousCompletenessScore = previousCompletenessScore;
|
|
3518
|
-
}
|
|
3487
|
+
// Run validation on updated ticket
|
|
3488
|
+
// Use the updated values (from args) merged with existing values (from result)
|
|
3489
|
+
// The result should contain the final state after update
|
|
3490
|
+
const validation = validateTicket({
|
|
3491
|
+
complexity: (args.complexity || result.complexity),
|
|
3492
|
+
implementation: (args.implementation || result.implementation),
|
|
3493
|
+
technicalDetails: (args.technicalDetails || result.technicalDetails),
|
|
3494
|
+
notes: (args.notes || result.notes),
|
|
3495
|
+
acceptanceCriteria: (args.acceptanceCriteria || result.acceptanceCriteria),
|
|
3496
|
+
});
|
|
3497
|
+
// Filter warnings by strictness level
|
|
3498
|
+
const warnings = filterWarningsByStrictness(validation.warnings, validationStrictness);
|
|
3499
|
+
// Add validation results to response
|
|
3500
|
+
result.warnings = warnings;
|
|
3501
|
+
result.completenessScore = validation.completenessScore;
|
|
3502
|
+
if (previousCompletenessScore !== undefined) {
|
|
3503
|
+
result.previousCompletenessScore = previousCompletenessScore;
|
|
3519
3504
|
}
|
|
3520
3505
|
return formatWriteResponse(result, responseMode, 'Ticket updated');
|
|
3521
3506
|
},
|
|
@@ -3630,56 +3615,6 @@ export function createToolHandlers(apiClient) {
|
|
|
3630
3615
|
// ========================================================================
|
|
3631
3616
|
// Bulk Operations
|
|
3632
3617
|
// ========================================================================
|
|
3633
|
-
bulk_create_tickets: async (_client, args) => {
|
|
3634
|
-
validateRequired(args, 'epicId', 'tickets');
|
|
3635
|
-
if (!Array.isArray(args.tickets) || args.tickets.length === 0) {
|
|
3636
|
-
throw new Error('tickets array is required and must not be empty');
|
|
3637
|
-
}
|
|
3638
|
-
// Validate each ticket has a title
|
|
3639
|
-
const tickets = args.tickets;
|
|
3640
|
-
for (let i = 0; i < tickets.length; i++) {
|
|
3641
|
-
if (!tickets[i].title || typeof tickets[i].title !== 'string') {
|
|
3642
|
-
throw new Error(`tickets[${i}].title is required and must be a string`);
|
|
3643
|
-
}
|
|
3644
|
-
}
|
|
3645
|
-
// Validate dependencies if provided
|
|
3646
|
-
if (args.dependencies && Array.isArray(args.dependencies)) {
|
|
3647
|
-
const deps = args.dependencies;
|
|
3648
|
-
for (let i = 0; i < deps.length; i++) {
|
|
3649
|
-
const dep = deps[i];
|
|
3650
|
-
if (typeof dep.ticket !== 'number' || dep.ticket < 0 || dep.ticket >= tickets.length) {
|
|
3651
|
-
throw new Error(`dependencies[${i}].ticket must be a valid index in tickets array (0-${tickets.length - 1})`);
|
|
3652
|
-
}
|
|
3653
|
-
const dependsOn = Array.isArray(dep.dependsOn) ? dep.dependsOn : [dep.dependsOn];
|
|
3654
|
-
for (const idx of dependsOn) {
|
|
3655
|
-
if (typeof idx !== 'number' || idx < 0 || idx >= tickets.length) {
|
|
3656
|
-
throw new Error(`dependencies[${i}].dependsOn contains invalid index ${idx} (must be 0-${tickets.length - 1})`);
|
|
3657
|
-
}
|
|
3658
|
-
if (idx === dep.ticket) {
|
|
3659
|
-
throw new Error(`dependencies[${i}]: ticket cannot depend on itself`);
|
|
3660
|
-
}
|
|
3661
|
-
}
|
|
3662
|
-
}
|
|
3663
|
-
}
|
|
3664
|
-
return await apiClient.call('bulk_create_tickets', {
|
|
3665
|
-
epicId: args.epicId,
|
|
3666
|
-
tickets: args.tickets,
|
|
3667
|
-
dependencies: args.dependencies,
|
|
3668
|
-
onError: args.onError,
|
|
3669
|
-
});
|
|
3670
|
-
},
|
|
3671
|
-
get_job_status: async (_client, args) => {
|
|
3672
|
-
validateRequired(args, 'jobId');
|
|
3673
|
-
return await apiClient.call('get_job_status', {
|
|
3674
|
-
jobId: args.jobId,
|
|
3675
|
-
});
|
|
3676
|
-
},
|
|
3677
|
-
cancel_job: async (_client, args) => {
|
|
3678
|
-
validateRequired(args, 'jobId');
|
|
3679
|
-
return await apiClient.call('cancel_job', {
|
|
3680
|
-
jobId: args.jobId,
|
|
3681
|
-
});
|
|
3682
|
-
},
|
|
3683
3618
|
bulk_add_dependencies: async (_client, args) => {
|
|
3684
3619
|
validateRequired(args, 'dependencies');
|
|
3685
3620
|
if (!Array.isArray(args.dependencies) || args.dependencies.length === 0) {
|