@specforge/canary-cli 0.1.3 → 0.1.5

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.
@@ -24,19 +24,15 @@ function getTools() {
24
24
  properties: {
25
25
  type: {
26
26
  type: "string",
27
- enum: ["project", "specification", "epic", "ticket", "implementation_session"],
27
+ enum: ["project", "specification", "epic", "ticket", "blueprint"],
28
28
  description: "Entity type to retrieve"
29
29
  },
30
30
  id: {
31
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)"
32
+ description: "Entity ID"
37
33
  }
38
34
  },
39
- required: ["type"]
35
+ required: ["type", "id"]
40
36
  }
41
37
  },
42
38
  {
@@ -47,7 +43,7 @@ function getTools() {
47
43
  properties: {
48
44
  type: {
49
45
  type: "string",
50
- enum: ["projects", "specifications", "epics", "tickets"],
46
+ enum: ["projects", "specifications", "epics", "tickets", "blueprints"],
51
47
  description: "Entity type to list"
52
48
  },
53
49
  projectId: {
@@ -120,14 +116,6 @@ At least one scope filter (projectId, specificationId, or epicId) is required.`,
120
116
  },
121
117
  description: "Filter by complexity"
122
118
  },
123
- priority: {
124
- type: "array",
125
- items: {
126
- type: "string",
127
- enum: ["low", "medium", "high", "critical"]
128
- },
129
- description: "Filter by priority"
130
- },
131
119
  projectId: {
132
120
  type: "string",
133
121
  description: "Limit search to project"
@@ -147,38 +135,6 @@ At least one scope filter (projectId, specificationId, or epicId) is required.`,
147
135
  offset: {
148
136
  type: "number",
149
137
  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
138
  }
183
139
  }
184
140
  }
@@ -206,7 +162,7 @@ At least one scope filter (projectId, specificationId, or epicId) is required.`,
206
162
  },
207
163
  {
208
164
  name: "get_blocked_tickets",
209
- description: 'Get tickets with status "pending" and their statusReason explaining why they are blocked (unsatisfied dependencies or external block)',
165
+ description: 'Get tickets with status "pending", each with the `blockedBy` list of unsatisfied dependency tickets computed from the dependency tree.',
210
166
  inputSchema: {
211
167
  type: "object",
212
168
  properties: {
@@ -227,7 +183,6 @@ Report types:
227
183
  - 'time': Estimated vs actual hours (replaces get_time_report)
228
184
  - 'blockers': Blocked tickets with reasons (replaces get_blockers_report)
229
185
  - 'work': Completed work summary from WorkSession records (replaces get_work_summary)
230
- - 'implementation_analysis': Deeper implementation insights
231
186
  - 'sessions': Live planning/work/review sessions for a project (requires scope='project')
232
187
 
233
188
  Format options:
@@ -238,7 +193,7 @@ Format options:
238
193
  properties: {
239
194
  type: {
240
195
  type: "string",
241
- enum: ["implementation", "time", "blockers", "work", "implementation_analysis", "sessions"],
196
+ enum: ["implementation", "time", "blockers", "work", "sessions"],
242
197
  description: "Type of report to generate"
243
198
  },
244
199
  scope: {
@@ -257,6 +212,11 @@ Format options:
257
212
  endDate: {
258
213
  type: "string",
259
214
  description: "End date for work report (ISO 8601)"
215
+ },
216
+ format: {
217
+ type: "string",
218
+ enum: ["json", "summary"],
219
+ description: "Response format: 'json' (default) or 'summary'."
260
220
  }
261
221
  },
262
222
  required: ["type", "scope", "scopeId"]
@@ -287,7 +247,7 @@ Format options:
287
247
  },
288
248
  {
289
249
  name: "action_planning_session",
290
- description: "Execute a planning action within an active session. Wraps all planning operations (create/update/delete epics, tickets, dependencies, blueprints) plus get_planning_status (readiness X-ray, worst-first) with automatic status tracking. The operation.type IS the backend PlanningOperationName. 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. To read a single ticket, use the `get` tool (type:'ticket'). Use responseDetail to control verbosity: 'minimal' (~80 tokens) for rapid iteration, 'standard' (~200 tokens, default) for normal work, 'full' (~500 tokens) for debugging.",
250
+ description: "Execute a planning action within an active session. Wraps all planning operations (create/update/delete epics, tickets, dependencies, blueprints) plus get_planning_status (readiness X-ray, worst-first) with automatic status tracking. The operation.type IS the backend PlanningOperationName. 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. To read a single ticket, use the `get` tool (type:'ticket').",
291
251
  inputSchema: {
292
252
  type: "object",
293
253
  properties: {
@@ -301,17 +261,17 @@ Format options:
301
261
  "update_spec",
302
262
  "create_epic",
303
263
  "update_epic",
264
+ "delete_epic",
304
265
  "create_ticket",
305
266
  "update_ticket",
306
- "delete_epic",
307
267
  "delete_ticket",
308
- "create_dependencies",
309
- "delete_dependencies",
310
268
  "create_blueprint",
311
269
  "update_blueprint",
312
270
  "delete_blueprint",
313
271
  "link_blueprint_to_tickets",
314
272
  "unlink_blueprint_to_tickets",
273
+ "create_dependencies",
274
+ "delete_dependencies",
315
275
  "get_planning_status"
316
276
  ],
317
277
  description: "The planning operation to perform (lifecycle vocabulary). The type IS the backend PlanningOperationName; remaining fields are the operation payload."
@@ -326,15 +286,15 @@ Format options:
326
286
  },
327
287
  required: ["type", "fields"]
328
288
  },
289
+ // create_epic — SHELL only (epic_decomposition). Body fields are authored
290
+ // by update_epic in epic_expansion; only title/description/objective are
291
+ // persisted on create, so only those are advertised.
329
292
  {
330
293
  properties: {
331
294
  type: { const: "create_epic" },
332
295
  title: { type: "string", minLength: 1, description: "Epic title (non-empty)" },
333
296
  description: { type: "string", description: "What this epic delivers" },
334
- objective: { type: "string", description: "Goal achieved for the user" },
335
- goals: { type: "array", items: { type: "string" } },
336
- acceptanceCriteria: { type: "array", items: { type: "string" } },
337
- tickets: { type: "array", description: "Optional bulk-create tickets within the epic" }
297
+ objective: { type: "string", description: "Goal achieved for the user" }
338
298
  },
339
299
  required: ["type", "title"]
340
300
  },
@@ -349,26 +309,33 @@ Format options:
349
309
  title: { type: "string" },
350
310
  description: { type: "string" },
351
311
  objective: { type: "string", description: "Goal achieved for the user." },
352
- priority: { type: "string", enum: ["high", "medium", "low"] },
353
- goals: { type: "array", items: { type: "string" } },
354
- acceptanceCriteria: { type: "array", items: { type: "string" } }
312
+ architecture: { type: "string", description: "Structural approach specific to this epic." },
313
+ scope: { type: "object", description: "Epic scope.", properties: { inScope: { type: "array", items: { type: "string" } }, outOfScope: { type: "array", items: { type: "string" } }, assumptions: { type: "array", items: { type: "string" } }, externalDependencies: { type: "array", items: { type: "string" } } } },
314
+ goals: { type: "array", description: "Epic goals as objects (Epic.goals is a json object[], not string[]).", items: { type: "object", properties: { title: { type: "string" }, description: { type: "string" }, type: { type: "string", enum: ["business", "technical", "user", "operational"] }, successCriteria: { type: "array", items: { type: "string" } } }, required: ["title", "description"] } },
315
+ acceptanceCriteria: { type: "array", description: "BDD criteria objects (Epic.acceptanceCriteria is a json object[], not string[]).", items: { type: "object", properties: { given: { type: "string" }, when: { type: "string" }, then: { type: "string" } }, required: ["given", "when", "then"] } },
316
+ validationCommands: { type: "array", items: { type: "string" }, description: "Commands that verify this epic end-to-end." },
317
+ apiContracts: { type: "array", description: "API contracts this epic exposes.", items: { type: "object", properties: { id: { type: "string" }, name: { type: "string" }, type: { type: "string" }, description: { type: "string" } } } },
318
+ sharedPatterns: { type: "array", description: "Reusable patterns the epic's tickets should follow.", items: { type: "object" } },
319
+ fileStructures: { type: "array", description: "Concrete files this epic creates/modifies.", items: { type: "object", properties: { id: { type: "string" }, scope: { type: "string" }, description: { type: "string" }, content: { type: "string" } } } },
320
+ requirementsCovered: { type: "array", items: { type: "string" }, description: "Spec requirement ids this epic covers." },
321
+ nfrsCovered: { type: "array", items: { type: "string" }, description: "Spec NFR ids this epic covers." },
322
+ goalsCovered: { type: "array", items: { type: "string" }, description: "Spec goal ids this epic advances." }
355
323
  }
356
324
  }
357
325
  },
358
326
  required: ["type", "id", "fields"]
359
327
  },
328
+ // create_ticket — SHELL only (ticket_decomposition). Body fields
329
+ // (ticketType, complexity, acceptanceCriteria, implementationSteps, …)
330
+ // are authored by update_ticket in ticket_expansion; dependencies via
331
+ // create_dependencies in cross_validation. Only epicId/title/description
332
+ // are persisted on create, so only those are advertised.
360
333
  {
361
334
  properties: {
362
335
  type: { const: "create_ticket" },
363
336
  epicId: { type: "string", description: "Parent epic id" },
364
337
  title: { type: "string", minLength: 1, description: "Ticket title (non-empty)" },
365
- description: { type: "string" },
366
- ticketType: { type: "string", enum: ["implementation", "verification"], description: "Ticket type \u2014 implementation (default) or verification (tests/QA). Drives which fields the readiness rubric expects." },
367
- priority: { type: "string", enum: ["high", "medium", "low"] },
368
- complexity: { type: "string", enum: ["small", "medium", "large", "xlarge"] },
369
- acceptanceCriteria: { type: "array", items: { type: "string" } },
370
- implementationSteps: { type: "array", items: { type: "string" }, description: "Implementation steps; persisted as TicketImplementationStep rows" },
371
- dependsOn: { type: "array", items: { type: "string" }, description: "Other ticket ids this depends on; created post-insert" }
338
+ description: { type: "string" }
372
339
  },
373
340
  required: ["type", "epicId", "title"]
374
341
  },
@@ -392,7 +359,9 @@ Format options:
392
359
  filesToBeDeleted: { type: "array", items: { type: "string" } },
393
360
  filesToBeReferenced: { type: "array", items: { type: "string" } },
394
361
  guardrails: { type: "array", items: { type: "string" } },
395
- testSpecification: { type: "object", properties: { testTypes: { type: "array", items: { type: "string", enum: ["unit", "integration", "e2e", "typecheck", "lint", "build", "contract", "structural", "layout", "a11y", "performance"] } }, qualityGates: { type: "array", items: { type: "string" } }, testCommands: { type: "array", items: { type: "string" } }, coverageTarget: { type: "number", minimum: 0, maximum: 100 } } },
362
+ testSpecification: { type: "object", properties: { testTypes: { type: "array", items: { type: "string", enum: ["unit", "integration", "e2e", "typecheck", "lint", "build", "contract", "structural", "layout", "a11y", "performance"] } }, qualityGates: { type: "array", items: { type: "string" } }, testCommands: { type: "array", items: { type: "string" } }, coverageTarget: { type: "integer", minimum: 0, maximum: 100 } } },
363
+ codeReferences: { type: "array", description: "Existing code to reuse/anchor on.", items: { type: "object", properties: { filePath: { type: "string" }, symbol: { type: "string" }, description: { type: "string" } }, required: ["filePath"] } },
364
+ typeReferences: { type: "array", description: "Existing types to use.", items: { type: "object", properties: { filePath: { type: "string" }, typeName: { type: "string" }, description: { type: "string" } }, required: ["filePath", "typeName"] } },
396
365
  codeSnippets: { type: "array", items: { type: "object", properties: { language: { type: "string" }, content: { type: "string" }, description: { type: "string" } }, required: ["language", "content"] } },
397
366
  typeSnippets: { type: "array", items: { type: "object", properties: { language: { type: "string" }, content: { type: "string" }, description: { type: "string" } }, required: ["language", "content"] } },
398
367
  blueprintReferences: { type: "array", items: { type: "object", properties: { blueprintId: { type: "string" }, context: { type: "string" }, section: { type: "string" } }, required: ["blueprintId"] } },
@@ -405,14 +374,16 @@ Format options:
405
374
  {
406
375
  properties: {
407
376
  type: { const: "delete_epic" },
408
- id: { type: "string", description: "Epic id; cascades to all tickets in the epic." }
377
+ id: { type: "string", description: "Epic id; cascades to all tickets in the epic." },
378
+ cascadeRemoveDependencies: { type: "boolean", description: "Confirm removing dependency edges pointing at this epic's tickets from outside the epic. Required (true) when such referrers exist, else the delete is denied." }
409
379
  },
410
380
  required: ["type", "id"]
411
381
  },
412
382
  {
413
383
  properties: {
414
384
  type: { const: "delete_ticket" },
415
- id: { type: "string", description: "Ticket id (use list_tickets / lookup_ticket to find)." }
385
+ id: { type: "string", description: "Ticket id (use list_tickets / lookup_ticket to find)." },
386
+ cascadeRemoveDependencies: { type: "boolean", description: "Confirm removing dependency edges from other tickets that point at this ticket. Required (true) when such referrers exist, else the delete is denied." }
416
387
  },
417
388
  required: ["type", "id"]
418
389
  },
@@ -422,14 +393,13 @@ Format options:
422
393
  dependencies: {
423
394
  type: "array",
424
395
  minItems: 1,
425
- maxItems: 100,
426
- description: "Up to 100 dependency pairs. Valid pairs commit; malformed pairs come back in failed[] with a per-entry reason.",
396
+ maxItems: 5e3,
397
+ description: 'Up to 5000 dependency pairs, each a "requires" edge (fromTicketId depends on toTicketId). The batch is validated atomically: a cycle or an all-duplicate batch is rejected with guidance; already-existing edges are skipped.',
427
398
  items: {
428
399
  type: "object",
429
400
  properties: {
430
401
  fromTicketId: { type: "string", description: "The dependent ticket (this one depends on the other)." },
431
- toTicketId: { type: "string", description: "The blocker ticket it depends on." },
432
- type: { type: "string", enum: ["requires", "blocks"], description: 'Defaults to "requires"' }
402
+ toTicketId: { type: "string", description: "The blocker ticket it depends on." }
433
403
  },
434
404
  required: ["fromTicketId", "toTicketId"]
435
405
  }
@@ -448,9 +418,9 @@ Format options:
448
418
  properties: {
449
419
  type: { const: "create_blueprint" },
450
420
  title: { type: "string", minLength: 1, description: "Blueprint title (non-empty)" },
451
- content: { type: "string", description: "Body. Mermaid format extracts ```mermaid``` fences automatically." },
452
- format: { type: "string", description: 'Defaults to "mermaid"' },
453
- category: { type: "string", description: "Blueprint category (model enum, e.g. flowchart | architecture | sequence | data_model)." },
421
+ content: { type: "string", description: "Body \u2014 diagram source or markdown, persisted as-is on create." },
422
+ format: { type: "string", enum: ["markdown", "mermaid", "ascii", "mixed", "html", "svg", "image"], description: 'Defaults to "mermaid"' },
423
+ category: { type: "string", enum: ["flowchart", "architecture", "state", "sequence", "erd", "mockup", "adr", "component", "deployment", "api", "algorithm", "protocol", "glossary", "design_system"], description: "Blueprint category (SpecificationBlueprint.category model enum)." },
454
424
  description: { type: "string" },
455
425
  tags: { type: "array", items: { type: "string" } }
456
426
  },
@@ -485,9 +455,7 @@ Format options:
485
455
  properties: {
486
456
  type: { const: "link_blueprint_to_tickets" },
487
457
  blueprintId: { type: "string", description: "Blueprint to link." },
488
- ticketIds: { type: "array", minItems: 1, items: { type: "string" }, description: "Tickets to link the blueprint to." },
489
- context: { type: "string", description: "Optional context annotation" },
490
- section: { type: "string", description: "Optional section reference" }
458
+ ticketIds: { type: "array", minItems: 1, items: { type: "string" }, description: "Tickets to link the blueprint to." }
491
459
  },
492
460
  required: ["type", "blueprintId", "ticketIds"]
493
461
  },
@@ -502,17 +470,11 @@ Format options:
502
470
  {
503
471
  // Read-only poll/resume. To read a single ticket, use the `get` tool (type:'ticket').
504
472
  properties: {
505
- type: { const: "get_planning_status" },
506
- responseDetail: { type: "string", enum: ["minimal", "standard", "full"] }
473
+ type: { const: "get_planning_status" }
507
474
  },
508
475
  required: ["type"]
509
476
  }
510
477
  ]
511
- },
512
- responseDetail: {
513
- type: "string",
514
- enum: ["minimal", "standard", "full"],
515
- description: "Response detail level: minimal (~80 tokens), standard (~200, default), full (~500)"
516
478
  }
517
479
  },
518
480
  required: ["operation"]
@@ -578,7 +540,7 @@ Set getTicket: true to fetch full ticket details in the response \u2014 useful f
578
540
  properties: {
579
541
  index: {
580
542
  type: "number",
581
- description: "Zero-based index of the step in the implementation.steps array"
543
+ description: "Zero-based index of the step among the ticket's implementation steps (TicketImplementationStep rows, ordered by `order`)"
582
544
  },
583
545
  completed: {
584
546
  type: "boolean",
@@ -785,22 +747,22 @@ Set getTicket: true to fetch full ticket details in the response \u2014 useful f
785
747
  properties: {
786
748
  tests: {
787
749
  type: "string",
788
- enum: ["passed", "failed", "skipped", "na"],
750
+ enum: ["passed", "failed", "partial", "pending"],
789
751
  description: "Unit/integration test results"
790
752
  },
791
753
  lint: {
792
754
  type: "string",
793
- enum: ["passed", "failed", "skipped", "na"],
755
+ enum: ["passed", "failed", "partial", "pending"],
794
756
  description: "Linting results"
795
757
  },
796
758
  typeCheck: {
797
759
  type: "string",
798
- enum: ["passed", "failed", "skipped", "na"],
760
+ enum: ["passed", "failed", "partial", "pending"],
799
761
  description: "TypeScript type checking results"
800
762
  },
801
763
  build: {
802
764
  type: "string",
803
- enum: ["passed", "failed", "skipped", "na"],
765
+ enum: ["passed", "failed", "partial", "pending"],
804
766
  description: "Build/compilation results"
805
767
  },
806
768
  notes: {
@@ -864,9 +826,8 @@ Set getTicket: true to fetch full ticket details in the response \u2014 useful f
864
826
  title: { type: "string", description: "Ticket title" },
865
827
  description: { type: "string", description: "Ticket description" },
866
828
  ticketType: { type: "string", enum: ["implementation", "verification"], description: "Ticket type \u2014 defaults to implementation." },
867
- priority: { type: "string", enum: ["low", "medium", "high", "critical"] },
868
829
  complexity: { type: "string", enum: ["small", "medium", "large", "xlarge"] },
869
- estimatedHours: { type: "number" },
830
+ estimatedMinutes: { type: "integer", minimum: 0 },
870
831
  acceptanceCriteria: { type: "array", items: { type: "string" } },
871
832
  implementationSteps: { type: "array", items: { type: "string" }, description: "Implementation steps; persisted as TicketImplementationStep rows" },
872
833
  tags: { type: "array", items: { type: "string" } }
@@ -1127,6 +1088,23 @@ Set getTicket: true to fetch full ticket details in the response \u2014 useful f
1127
1088
  }
1128
1089
  }
1129
1090
  ];
1091
+ const IN_DEVELOPMENT_PLANNED_FOR = {
1092
+ start_work_session: "0.2.0",
1093
+ action_work_session: "0.2.0",
1094
+ complete_work_session: "0.2.0",
1095
+ reset_work_session: "0.2.0",
1096
+ start_review_session: "0.3.0",
1097
+ action_review_session: "0.3.0",
1098
+ complete_review_session: "0.3.0"
1099
+ };
1100
+ for (const t of tools) {
1101
+ const plannedFor = IN_DEVELOPMENT_PLANNED_FOR[t.name];
1102
+ if (plannedFor) {
1103
+ t.description = `**In development \u2014 ships with ${plannedFor}.** Calling returns a typed stub response the client should render as a "coming soon" affordance.
1104
+
1105
+ ${t.description}`;
1106
+ }
1107
+ }
1130
1108
  return tools;
1131
1109
  }
1132
1110
  const RETRY_CONFIG = {
@@ -1398,7 +1376,6 @@ function createToolHandlers(apiClient) {
1398
1376
  fromTicketId: args.fromTicketId,
1399
1377
  epicId: args.epicId,
1400
1378
  allTickets: args.allTickets,
1401
- targetStatus: args.targetStatus,
1402
1379
  resetDependents: args.resetDependents,
1403
1380
  includeCompleted: args.includeCompleted,
1404
1381
  preserveNotes: args.preserveNotes,