@sprintdock/backend 0.4.2

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.
Files changed (107) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +252 -0
  3. package/SERVER.md +25 -0
  4. package/dist/index.d.ts +1536 -0
  5. package/dist/index.js +4103 -0
  6. package/drizzle/0000_fresh_roxanne_simpson.sql +51 -0
  7. package/drizzle/0001_sprint_markdown_content.sql +1 -0
  8. package/drizzle/0002_task_touched_files.sql +8 -0
  9. package/drizzle/meta/0000_snapshot.json +372 -0
  10. package/drizzle/meta/0001_snapshot.json +379 -0
  11. package/drizzle/meta/_journal.json +27 -0
  12. package/drizzle.config.ts +14 -0
  13. package/package.json +40 -0
  14. package/src/application/container.ts +44 -0
  15. package/src/application/dto/plan-sprint-analytics.dto.ts +30 -0
  16. package/src/application/plan.service.ts +123 -0
  17. package/src/application/sprint.service.ts +118 -0
  18. package/src/application/task.service.ts +389 -0
  19. package/src/db/connection.ts +25 -0
  20. package/src/db/migrator.ts +46 -0
  21. package/src/db/schema/index.ts +14 -0
  22. package/src/db/schema/plans.ts +18 -0
  23. package/src/db/schema/relations.ts +36 -0
  24. package/src/db/schema/sprints.ts +33 -0
  25. package/src/db/schema/tasks.ts +62 -0
  26. package/src/domain/entities/index.ts +30 -0
  27. package/src/domain/entities/plan.entity.ts +33 -0
  28. package/src/domain/entities/sprint.entity.ts +44 -0
  29. package/src/domain/entities/task.entity.ts +80 -0
  30. package/src/domain/repositories/index.ts +9 -0
  31. package/src/domain/repositories/plan.repository.ts +21 -0
  32. package/src/domain/repositories/sprint.repository.ts +19 -0
  33. package/src/domain/repositories/task.repository.ts +35 -0
  34. package/src/domain/services/index.ts +9 -0
  35. package/src/domain/services/plan-domain.service.ts +44 -0
  36. package/src/domain/services/sprint-domain.service.ts +44 -0
  37. package/src/domain/services/task-domain.service.ts +136 -0
  38. package/src/errors/backend-errors.ts +75 -0
  39. package/src/http/app-factory.ts +55 -0
  40. package/src/http/controllers/health.controller.ts +33 -0
  41. package/src/http/controllers/plan.controller.ts +153 -0
  42. package/src/http/controllers/sprint.controller.ts +111 -0
  43. package/src/http/controllers/task.controller.ts +158 -0
  44. package/src/http/express-augmentation.d.ts +20 -0
  45. package/src/http/middleware/cors.ts +41 -0
  46. package/src/http/middleware/error-handler.ts +50 -0
  47. package/src/http/middleware/request-id.ts +28 -0
  48. package/src/http/middleware/validate.ts +54 -0
  49. package/src/http/routes/v1/index.ts +39 -0
  50. package/src/http/routes/v1/plan.routes.ts +51 -0
  51. package/src/http/routes/v1/schemas.ts +175 -0
  52. package/src/http/routes/v1/sprint.routes.ts +49 -0
  53. package/src/http/routes/v1/task.routes.ts +64 -0
  54. package/src/index.ts +34 -0
  55. package/src/infrastructure/observability/audit-log.ts +34 -0
  56. package/src/infrastructure/observability/request-correlation.ts +20 -0
  57. package/src/infrastructure/repositories/drizzle/drizzle-plan.repository.ts +138 -0
  58. package/src/infrastructure/repositories/drizzle/drizzle-sprint.repository.ts +137 -0
  59. package/src/infrastructure/repositories/drizzle/drizzle-task.repository.ts +403 -0
  60. package/src/infrastructure/repositories/drizzle/index.ts +16 -0
  61. package/src/infrastructure/repositories/drizzle/row-mappers.ts +106 -0
  62. package/src/infrastructure/repositories/drizzle/sqlite-db.ts +13 -0
  63. package/src/infrastructure/repositories/repository-factory.ts +54 -0
  64. package/src/infrastructure/security/auth-context.ts +35 -0
  65. package/src/infrastructure/security/input-guard.ts +21 -0
  66. package/src/infrastructure/security/rate-limiter.ts +65 -0
  67. package/src/mcp/bootstrap-sprintdock-sqlite.ts +45 -0
  68. package/src/mcp/mcp-query-helpers.ts +89 -0
  69. package/src/mcp/mcp-text-formatters.ts +204 -0
  70. package/src/mcp/mcp-tool-error.ts +24 -0
  71. package/src/mcp/plugins/context-tools.plugin.ts +107 -0
  72. package/src/mcp/plugins/default-plugins.ts +23 -0
  73. package/src/mcp/plugins/index.ts +21 -0
  74. package/src/mcp/plugins/mcp-tool-kit.ts +90 -0
  75. package/src/mcp/plugins/plan-tools.plugin.ts +426 -0
  76. package/src/mcp/plugins/sprint-tools.plugin.ts +396 -0
  77. package/src/mcp/plugins/task-tools.plugin.ts +528 -0
  78. package/src/mcp/plugins/task-workflow.plugin.ts +275 -0
  79. package/src/mcp/plugins/types.ts +45 -0
  80. package/src/mcp/register-sprintdock-mcp-tools.ts +50 -0
  81. package/src/mcp/sprintdock-mcp-capabilities.ts +14 -0
  82. package/src/mcp/sprintdock-mcp-runtime.ts +119 -0
  83. package/src/mcp/tool-guard.ts +58 -0
  84. package/src/mcp/transports/http-app-factory.ts +31 -0
  85. package/src/mcp/transports/http-entry.ts +27 -0
  86. package/src/mcp/transports/stdio-entry.ts +17 -0
  87. package/tests/application/container.test.ts +36 -0
  88. package/tests/application/plan.service.test.ts +114 -0
  89. package/tests/application/sprint.service.test.ts +138 -0
  90. package/tests/application/task.service.test.ts +325 -0
  91. package/tests/db/test-db.test.ts +112 -0
  92. package/tests/domain/plan-domain.service.test.ts +44 -0
  93. package/tests/domain/sprint-domain.service.test.ts +38 -0
  94. package/tests/domain/task-domain.service.test.ts +105 -0
  95. package/tests/errors/backend-errors.test.ts +44 -0
  96. package/tests/helpers/test-db.ts +43 -0
  97. package/tests/http/error-handler.test.ts +37 -0
  98. package/tests/http/plan.routes.test.ts +128 -0
  99. package/tests/http/sprint.routes.test.ts +72 -0
  100. package/tests/http/task.routes.test.ts +130 -0
  101. package/tests/http/test-app.ts +17 -0
  102. package/tests/infrastructure/drizzle-plan.repository.test.ts +62 -0
  103. package/tests/infrastructure/drizzle-sprint.repository.test.ts +49 -0
  104. package/tests/infrastructure/drizzle-task.repository.test.ts +132 -0
  105. package/tests/mcp/mcp-text-formatters.test.ts +246 -0
  106. package/tests/mcp/register-sprintdock-mcp-tools.test.ts +207 -0
  107. package/tsconfig.json +9 -0
@@ -0,0 +1,1536 @@
1
+ import { BetterSQLite3Database } from 'drizzle-orm/better-sqlite3';
2
+ import { SQLJsDatabase } from 'drizzle-orm/sql-js';
3
+ import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
4
+ import * as drizzle_orm from 'drizzle-orm';
5
+ import { Express } from 'express';
6
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
7
+ import { z } from 'zod';
8
+
9
+ /**
10
+ * package: @sprintdock/backend
11
+ * author: vikash sharma
12
+ * description: Plan aggregate root types for the domain layer.
13
+ */
14
+ type PlanStatus = "draft" | "active" | "completed" | "archived";
15
+ interface Plan {
16
+ id: string;
17
+ slug: string;
18
+ title: string;
19
+ description: string | null;
20
+ markdownContent: string | null;
21
+ status: PlanStatus;
22
+ isActive: boolean;
23
+ createdAt: string;
24
+ updatedAt: string;
25
+ }
26
+ interface CreatePlanInput {
27
+ slug: string;
28
+ title: string;
29
+ description?: string | null;
30
+ markdownContent?: string | null;
31
+ }
32
+ interface UpdatePlanInput {
33
+ title?: string;
34
+ description?: string | null;
35
+ markdownContent?: string | null;
36
+ status?: PlanStatus;
37
+ }
38
+
39
+ /**
40
+ * package: @sprintdock/backend
41
+ * author: vikash sharma
42
+ * description: Plan persistence port implemented by infrastructure adapters.
43
+ */
44
+
45
+ interface PlanRepository {
46
+ create(input: CreatePlanInput): Promise<Plan>;
47
+ findById(id: string): Promise<Plan | null>;
48
+ findBySlug(slug: string): Promise<Plan | null>;
49
+ findActive(): Promise<Plan | null>;
50
+ list(): Promise<Plan[]>;
51
+ update(id: string, input: UpdatePlanInput): Promise<Plan | null>;
52
+ setActive(id: string): Promise<void>;
53
+ delete(id: string): Promise<boolean>;
54
+ }
55
+
56
+ /**
57
+ * package: @sprintdock/backend
58
+ * author: vikash sharma
59
+ * description: Sprint entity types scoped to a plan.
60
+ */
61
+ type SprintStatus = "planned" | "active" | "completed" | "archived";
62
+ interface Sprint {
63
+ id: string;
64
+ slug: string;
65
+ planId: string;
66
+ name: string;
67
+ goal: string;
68
+ /** Optional sprint notes / retro / scope — GitHub-flavored markdown. */
69
+ markdownContent: string | null;
70
+ status: SprintStatus;
71
+ order: number;
72
+ startDate: string | null;
73
+ endDate: string | null;
74
+ createdAt: string;
75
+ updatedAt: string;
76
+ }
77
+ interface CreateSprintInput {
78
+ slug: string;
79
+ planId: string;
80
+ name: string;
81
+ goal: string;
82
+ markdownContent?: string | null;
83
+ order?: number;
84
+ startDate?: string | null;
85
+ endDate?: string | null;
86
+ }
87
+ interface UpdateSprintInput {
88
+ name?: string;
89
+ goal?: string;
90
+ markdownContent?: string | null;
91
+ status?: SprintStatus;
92
+ order?: number;
93
+ startDate?: string | null;
94
+ endDate?: string | null;
95
+ }
96
+
97
+ /**
98
+ * package: @sprintdock/backend
99
+ * author: vikash sharma
100
+ * description: Sprint persistence port implemented by infrastructure adapters.
101
+ */
102
+
103
+ interface SprintRepository {
104
+ create(input: CreateSprintInput): Promise<Sprint>;
105
+ findById(id: string): Promise<Sprint | null>;
106
+ findBySlug(planId: string, slug: string): Promise<Sprint | null>;
107
+ listByPlanId(planId: string): Promise<Sprint[]>;
108
+ update(id: string, input: UpdateSprintInput): Promise<Sprint | null>;
109
+ delete(id: string): Promise<boolean>;
110
+ }
111
+
112
+ /**
113
+ * package: @sprintdock/backend
114
+ * author: vikash sharma
115
+ * description: Task and dependency types for the domain layer.
116
+ */
117
+ type TaskStatus = "todo" | "in_progress" | "blocked" | "done";
118
+ type TaskPriority = "low" | "medium" | "high" | "critical";
119
+ /** Persisted in `task_touched_files.file_type`. */
120
+ type TaskTouchedFileType = "test" | "implementation" | "doc" | "config" | "other";
121
+ interface TaskTouchedFile {
122
+ id: string;
123
+ taskId: string;
124
+ path: string;
125
+ fileType: TaskTouchedFileType;
126
+ }
127
+ interface Task {
128
+ id: string;
129
+ sprintId: string;
130
+ title: string;
131
+ description: string | null;
132
+ status: TaskStatus;
133
+ priority: TaskPriority;
134
+ order: number;
135
+ assignee: string | null;
136
+ tags: string[] | null;
137
+ /** Files touched for this task (tests, implementation, docs, …). */
138
+ touchedFiles: TaskTouchedFile[];
139
+ createdAt: string;
140
+ updatedAt: string;
141
+ }
142
+ interface TaskDependency {
143
+ taskId: string;
144
+ dependsOnTaskId: string;
145
+ }
146
+ /** Payload row for create/update (no id / taskId). */
147
+ interface TaskTouchedFileInput {
148
+ path: string;
149
+ fileType: TaskTouchedFileType;
150
+ }
151
+ interface CreateTaskInput {
152
+ sprintId: string;
153
+ title: string;
154
+ description?: string | null;
155
+ priority: TaskPriority;
156
+ order?: number;
157
+ assignee?: string | null;
158
+ tags?: string[] | null;
159
+ dependsOnTaskIds?: string[];
160
+ touchedFiles?: TaskTouchedFileInput[];
161
+ }
162
+ interface UpdateTaskInput {
163
+ title?: string;
164
+ description?: string | null;
165
+ status?: TaskStatus;
166
+ priority?: TaskPriority;
167
+ order?: number;
168
+ assignee?: string | null;
169
+ tags?: string[] | null;
170
+ /** When set, replaces all touched-file rows for this task. */
171
+ touchedFiles?: TaskTouchedFileInput[];
172
+ }
173
+
174
+ /**
175
+ * package: @sprintdock/backend
176
+ * author: vikash sharma
177
+ * description: Task persistence port implemented by infrastructure adapters.
178
+ */
179
+
180
+ interface TaskFilter {
181
+ status?: TaskStatus;
182
+ priority?: TaskPriority;
183
+ assignee?: string;
184
+ }
185
+ interface TaskRepository {
186
+ create(input: CreateTaskInput): Promise<Task>;
187
+ findById(id: string): Promise<Task | null>;
188
+ listBySprintId(sprintId: string, filter?: TaskFilter): Promise<Task[]>;
189
+ listByPlanId(planId: string, filter?: TaskFilter): Promise<Task[]>;
190
+ update(id: string, input: UpdateTaskInput): Promise<Task | null>;
191
+ move(taskId: string, targetSprintId: string): Promise<Task | null>;
192
+ delete(id: string): Promise<boolean>;
193
+ getDependencies(taskId: string): Promise<TaskDependency[]>;
194
+ /** Task IDs that list {@link dependsOnTaskId} as a prerequisite. */
195
+ listDependentTaskIds(dependsOnTaskId: string): Promise<string[]>;
196
+ setDependencies(taskId: string, dependsOnTaskIds: string[]): Promise<void>;
197
+ /** Count tasks in the database grouped by status (all plans). */
198
+ countByStatusGlobally(): Promise<Record<TaskStatus, number>>;
199
+ }
200
+
201
+ declare const plans: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
202
+ name: "plans";
203
+ schema: undefined;
204
+ columns: {
205
+ id: drizzle_orm_sqlite_core.SQLiteColumn<{
206
+ name: "id";
207
+ tableName: "plans";
208
+ dataType: "string";
209
+ columnType: "SQLiteText";
210
+ data: string;
211
+ driverParam: string;
212
+ notNull: true;
213
+ hasDefault: false;
214
+ isPrimaryKey: true;
215
+ isAutoincrement: false;
216
+ hasRuntimeDefault: false;
217
+ enumValues: [string, ...string[]];
218
+ baseColumn: never;
219
+ identity: undefined;
220
+ generated: undefined;
221
+ }, {}, {
222
+ length: number | undefined;
223
+ }>;
224
+ slug: drizzle_orm_sqlite_core.SQLiteColumn<{
225
+ name: "slug";
226
+ tableName: "plans";
227
+ dataType: "string";
228
+ columnType: "SQLiteText";
229
+ data: string;
230
+ driverParam: string;
231
+ notNull: true;
232
+ hasDefault: false;
233
+ isPrimaryKey: false;
234
+ isAutoincrement: false;
235
+ hasRuntimeDefault: false;
236
+ enumValues: [string, ...string[]];
237
+ baseColumn: never;
238
+ identity: undefined;
239
+ generated: undefined;
240
+ }, {}, {
241
+ length: number | undefined;
242
+ }>;
243
+ title: drizzle_orm_sqlite_core.SQLiteColumn<{
244
+ name: "title";
245
+ tableName: "plans";
246
+ dataType: "string";
247
+ columnType: "SQLiteText";
248
+ data: string;
249
+ driverParam: string;
250
+ notNull: true;
251
+ hasDefault: false;
252
+ isPrimaryKey: false;
253
+ isAutoincrement: false;
254
+ hasRuntimeDefault: false;
255
+ enumValues: [string, ...string[]];
256
+ baseColumn: never;
257
+ identity: undefined;
258
+ generated: undefined;
259
+ }, {}, {
260
+ length: number | undefined;
261
+ }>;
262
+ description: drizzle_orm_sqlite_core.SQLiteColumn<{
263
+ name: "description";
264
+ tableName: "plans";
265
+ dataType: "string";
266
+ columnType: "SQLiteText";
267
+ data: string;
268
+ driverParam: string;
269
+ notNull: false;
270
+ hasDefault: false;
271
+ isPrimaryKey: false;
272
+ isAutoincrement: false;
273
+ hasRuntimeDefault: false;
274
+ enumValues: [string, ...string[]];
275
+ baseColumn: never;
276
+ identity: undefined;
277
+ generated: undefined;
278
+ }, {}, {
279
+ length: number | undefined;
280
+ }>;
281
+ markdownContent: drizzle_orm_sqlite_core.SQLiteColumn<{
282
+ name: "markdown_content";
283
+ tableName: "plans";
284
+ dataType: "string";
285
+ columnType: "SQLiteText";
286
+ data: string;
287
+ driverParam: string;
288
+ notNull: false;
289
+ hasDefault: false;
290
+ isPrimaryKey: false;
291
+ isAutoincrement: false;
292
+ hasRuntimeDefault: false;
293
+ enumValues: [string, ...string[]];
294
+ baseColumn: never;
295
+ identity: undefined;
296
+ generated: undefined;
297
+ }, {}, {
298
+ length: number | undefined;
299
+ }>;
300
+ status: drizzle_orm_sqlite_core.SQLiteColumn<{
301
+ name: "status";
302
+ tableName: "plans";
303
+ dataType: "string";
304
+ columnType: "SQLiteText";
305
+ data: string;
306
+ driverParam: string;
307
+ notNull: true;
308
+ hasDefault: false;
309
+ isPrimaryKey: false;
310
+ isAutoincrement: false;
311
+ hasRuntimeDefault: false;
312
+ enumValues: [string, ...string[]];
313
+ baseColumn: never;
314
+ identity: undefined;
315
+ generated: undefined;
316
+ }, {}, {
317
+ length: number | undefined;
318
+ }>;
319
+ isActive: drizzle_orm_sqlite_core.SQLiteColumn<{
320
+ name: "is_active";
321
+ tableName: "plans";
322
+ dataType: "boolean";
323
+ columnType: "SQLiteBoolean";
324
+ data: boolean;
325
+ driverParam: number;
326
+ notNull: true;
327
+ hasDefault: true;
328
+ isPrimaryKey: false;
329
+ isAutoincrement: false;
330
+ hasRuntimeDefault: false;
331
+ enumValues: undefined;
332
+ baseColumn: never;
333
+ identity: undefined;
334
+ generated: undefined;
335
+ }, {}, {}>;
336
+ createdAt: drizzle_orm_sqlite_core.SQLiteColumn<{
337
+ name: "created_at";
338
+ tableName: "plans";
339
+ dataType: "string";
340
+ columnType: "SQLiteText";
341
+ data: string;
342
+ driverParam: string;
343
+ notNull: true;
344
+ hasDefault: false;
345
+ isPrimaryKey: false;
346
+ isAutoincrement: false;
347
+ hasRuntimeDefault: false;
348
+ enumValues: [string, ...string[]];
349
+ baseColumn: never;
350
+ identity: undefined;
351
+ generated: undefined;
352
+ }, {}, {
353
+ length: number | undefined;
354
+ }>;
355
+ updatedAt: drizzle_orm_sqlite_core.SQLiteColumn<{
356
+ name: "updated_at";
357
+ tableName: "plans";
358
+ dataType: "string";
359
+ columnType: "SQLiteText";
360
+ data: string;
361
+ driverParam: string;
362
+ notNull: true;
363
+ hasDefault: false;
364
+ isPrimaryKey: false;
365
+ isAutoincrement: false;
366
+ hasRuntimeDefault: false;
367
+ enumValues: [string, ...string[]];
368
+ baseColumn: never;
369
+ identity: undefined;
370
+ generated: undefined;
371
+ }, {}, {
372
+ length: number | undefined;
373
+ }>;
374
+ };
375
+ dialect: "sqlite";
376
+ }>;
377
+
378
+ declare const sprints: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
379
+ name: "sprints";
380
+ schema: undefined;
381
+ columns: {
382
+ id: drizzle_orm_sqlite_core.SQLiteColumn<{
383
+ name: "id";
384
+ tableName: "sprints";
385
+ dataType: "string";
386
+ columnType: "SQLiteText";
387
+ data: string;
388
+ driverParam: string;
389
+ notNull: true;
390
+ hasDefault: false;
391
+ isPrimaryKey: true;
392
+ isAutoincrement: false;
393
+ hasRuntimeDefault: false;
394
+ enumValues: [string, ...string[]];
395
+ baseColumn: never;
396
+ identity: undefined;
397
+ generated: undefined;
398
+ }, {}, {
399
+ length: number | undefined;
400
+ }>;
401
+ slug: drizzle_orm_sqlite_core.SQLiteColumn<{
402
+ name: "slug";
403
+ tableName: "sprints";
404
+ dataType: "string";
405
+ columnType: "SQLiteText";
406
+ data: string;
407
+ driverParam: string;
408
+ notNull: true;
409
+ hasDefault: false;
410
+ isPrimaryKey: false;
411
+ isAutoincrement: false;
412
+ hasRuntimeDefault: false;
413
+ enumValues: [string, ...string[]];
414
+ baseColumn: never;
415
+ identity: undefined;
416
+ generated: undefined;
417
+ }, {}, {
418
+ length: number | undefined;
419
+ }>;
420
+ planId: drizzle_orm_sqlite_core.SQLiteColumn<{
421
+ name: "plan_id";
422
+ tableName: "sprints";
423
+ dataType: "string";
424
+ columnType: "SQLiteText";
425
+ data: string;
426
+ driverParam: string;
427
+ notNull: true;
428
+ hasDefault: false;
429
+ isPrimaryKey: false;
430
+ isAutoincrement: false;
431
+ hasRuntimeDefault: false;
432
+ enumValues: [string, ...string[]];
433
+ baseColumn: never;
434
+ identity: undefined;
435
+ generated: undefined;
436
+ }, {}, {
437
+ length: number | undefined;
438
+ }>;
439
+ name: drizzle_orm_sqlite_core.SQLiteColumn<{
440
+ name: "name";
441
+ tableName: "sprints";
442
+ dataType: "string";
443
+ columnType: "SQLiteText";
444
+ data: string;
445
+ driverParam: string;
446
+ notNull: true;
447
+ hasDefault: false;
448
+ isPrimaryKey: false;
449
+ isAutoincrement: false;
450
+ hasRuntimeDefault: false;
451
+ enumValues: [string, ...string[]];
452
+ baseColumn: never;
453
+ identity: undefined;
454
+ generated: undefined;
455
+ }, {}, {
456
+ length: number | undefined;
457
+ }>;
458
+ goal: drizzle_orm_sqlite_core.SQLiteColumn<{
459
+ name: "goal";
460
+ tableName: "sprints";
461
+ dataType: "string";
462
+ columnType: "SQLiteText";
463
+ data: string;
464
+ driverParam: string;
465
+ notNull: true;
466
+ hasDefault: false;
467
+ isPrimaryKey: false;
468
+ isAutoincrement: false;
469
+ hasRuntimeDefault: false;
470
+ enumValues: [string, ...string[]];
471
+ baseColumn: never;
472
+ identity: undefined;
473
+ generated: undefined;
474
+ }, {}, {
475
+ length: number | undefined;
476
+ }>;
477
+ markdownContent: drizzle_orm_sqlite_core.SQLiteColumn<{
478
+ name: "markdown_content";
479
+ tableName: "sprints";
480
+ dataType: "string";
481
+ columnType: "SQLiteText";
482
+ data: string;
483
+ driverParam: string;
484
+ notNull: false;
485
+ hasDefault: false;
486
+ isPrimaryKey: false;
487
+ isAutoincrement: false;
488
+ hasRuntimeDefault: false;
489
+ enumValues: [string, ...string[]];
490
+ baseColumn: never;
491
+ identity: undefined;
492
+ generated: undefined;
493
+ }, {}, {
494
+ length: number | undefined;
495
+ }>;
496
+ status: drizzle_orm_sqlite_core.SQLiteColumn<{
497
+ name: "status";
498
+ tableName: "sprints";
499
+ dataType: "string";
500
+ columnType: "SQLiteText";
501
+ data: string;
502
+ driverParam: string;
503
+ notNull: true;
504
+ hasDefault: false;
505
+ isPrimaryKey: false;
506
+ isAutoincrement: false;
507
+ hasRuntimeDefault: false;
508
+ enumValues: [string, ...string[]];
509
+ baseColumn: never;
510
+ identity: undefined;
511
+ generated: undefined;
512
+ }, {}, {
513
+ length: number | undefined;
514
+ }>;
515
+ sprintOrder: drizzle_orm_sqlite_core.SQLiteColumn<{
516
+ name: "order";
517
+ tableName: "sprints";
518
+ dataType: "number";
519
+ columnType: "SQLiteInteger";
520
+ data: number;
521
+ driverParam: number;
522
+ notNull: true;
523
+ hasDefault: true;
524
+ isPrimaryKey: false;
525
+ isAutoincrement: false;
526
+ hasRuntimeDefault: false;
527
+ enumValues: undefined;
528
+ baseColumn: never;
529
+ identity: undefined;
530
+ generated: undefined;
531
+ }, {}, {}>;
532
+ startDate: drizzle_orm_sqlite_core.SQLiteColumn<{
533
+ name: "start_date";
534
+ tableName: "sprints";
535
+ dataType: "string";
536
+ columnType: "SQLiteText";
537
+ data: string;
538
+ driverParam: string;
539
+ notNull: false;
540
+ hasDefault: false;
541
+ isPrimaryKey: false;
542
+ isAutoincrement: false;
543
+ hasRuntimeDefault: false;
544
+ enumValues: [string, ...string[]];
545
+ baseColumn: never;
546
+ identity: undefined;
547
+ generated: undefined;
548
+ }, {}, {
549
+ length: number | undefined;
550
+ }>;
551
+ endDate: drizzle_orm_sqlite_core.SQLiteColumn<{
552
+ name: "end_date";
553
+ tableName: "sprints";
554
+ dataType: "string";
555
+ columnType: "SQLiteText";
556
+ data: string;
557
+ driverParam: string;
558
+ notNull: false;
559
+ hasDefault: false;
560
+ isPrimaryKey: false;
561
+ isAutoincrement: false;
562
+ hasRuntimeDefault: false;
563
+ enumValues: [string, ...string[]];
564
+ baseColumn: never;
565
+ identity: undefined;
566
+ generated: undefined;
567
+ }, {}, {
568
+ length: number | undefined;
569
+ }>;
570
+ createdAt: drizzle_orm_sqlite_core.SQLiteColumn<{
571
+ name: "created_at";
572
+ tableName: "sprints";
573
+ dataType: "string";
574
+ columnType: "SQLiteText";
575
+ data: string;
576
+ driverParam: string;
577
+ notNull: true;
578
+ hasDefault: false;
579
+ isPrimaryKey: false;
580
+ isAutoincrement: false;
581
+ hasRuntimeDefault: false;
582
+ enumValues: [string, ...string[]];
583
+ baseColumn: never;
584
+ identity: undefined;
585
+ generated: undefined;
586
+ }, {}, {
587
+ length: number | undefined;
588
+ }>;
589
+ updatedAt: drizzle_orm_sqlite_core.SQLiteColumn<{
590
+ name: "updated_at";
591
+ tableName: "sprints";
592
+ dataType: "string";
593
+ columnType: "SQLiteText";
594
+ data: string;
595
+ driverParam: string;
596
+ notNull: true;
597
+ hasDefault: false;
598
+ isPrimaryKey: false;
599
+ isAutoincrement: false;
600
+ hasRuntimeDefault: false;
601
+ enumValues: [string, ...string[]];
602
+ baseColumn: never;
603
+ identity: undefined;
604
+ generated: undefined;
605
+ }, {}, {
606
+ length: number | undefined;
607
+ }>;
608
+ };
609
+ dialect: "sqlite";
610
+ }>;
611
+
612
+ declare const tasks: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
613
+ name: "tasks";
614
+ schema: undefined;
615
+ columns: {
616
+ id: drizzle_orm_sqlite_core.SQLiteColumn<{
617
+ name: "id";
618
+ tableName: "tasks";
619
+ dataType: "string";
620
+ columnType: "SQLiteText";
621
+ data: string;
622
+ driverParam: string;
623
+ notNull: true;
624
+ hasDefault: false;
625
+ isPrimaryKey: true;
626
+ isAutoincrement: false;
627
+ hasRuntimeDefault: false;
628
+ enumValues: [string, ...string[]];
629
+ baseColumn: never;
630
+ identity: undefined;
631
+ generated: undefined;
632
+ }, {}, {
633
+ length: number | undefined;
634
+ }>;
635
+ sprintId: drizzle_orm_sqlite_core.SQLiteColumn<{
636
+ name: "sprint_id";
637
+ tableName: "tasks";
638
+ dataType: "string";
639
+ columnType: "SQLiteText";
640
+ data: string;
641
+ driverParam: string;
642
+ notNull: true;
643
+ hasDefault: false;
644
+ isPrimaryKey: false;
645
+ isAutoincrement: false;
646
+ hasRuntimeDefault: false;
647
+ enumValues: [string, ...string[]];
648
+ baseColumn: never;
649
+ identity: undefined;
650
+ generated: undefined;
651
+ }, {}, {
652
+ length: number | undefined;
653
+ }>;
654
+ title: drizzle_orm_sqlite_core.SQLiteColumn<{
655
+ name: "title";
656
+ tableName: "tasks";
657
+ dataType: "string";
658
+ columnType: "SQLiteText";
659
+ data: string;
660
+ driverParam: string;
661
+ notNull: true;
662
+ hasDefault: false;
663
+ isPrimaryKey: false;
664
+ isAutoincrement: false;
665
+ hasRuntimeDefault: false;
666
+ enumValues: [string, ...string[]];
667
+ baseColumn: never;
668
+ identity: undefined;
669
+ generated: undefined;
670
+ }, {}, {
671
+ length: number | undefined;
672
+ }>;
673
+ description: drizzle_orm_sqlite_core.SQLiteColumn<{
674
+ name: "description";
675
+ tableName: "tasks";
676
+ dataType: "string";
677
+ columnType: "SQLiteText";
678
+ data: string;
679
+ driverParam: string;
680
+ notNull: false;
681
+ hasDefault: false;
682
+ isPrimaryKey: false;
683
+ isAutoincrement: false;
684
+ hasRuntimeDefault: false;
685
+ enumValues: [string, ...string[]];
686
+ baseColumn: never;
687
+ identity: undefined;
688
+ generated: undefined;
689
+ }, {}, {
690
+ length: number | undefined;
691
+ }>;
692
+ status: drizzle_orm_sqlite_core.SQLiteColumn<{
693
+ name: "status";
694
+ tableName: "tasks";
695
+ dataType: "string";
696
+ columnType: "SQLiteText";
697
+ data: string;
698
+ driverParam: string;
699
+ notNull: true;
700
+ hasDefault: false;
701
+ isPrimaryKey: false;
702
+ isAutoincrement: false;
703
+ hasRuntimeDefault: false;
704
+ enumValues: [string, ...string[]];
705
+ baseColumn: never;
706
+ identity: undefined;
707
+ generated: undefined;
708
+ }, {}, {
709
+ length: number | undefined;
710
+ }>;
711
+ priority: drizzle_orm_sqlite_core.SQLiteColumn<{
712
+ name: "priority";
713
+ tableName: "tasks";
714
+ dataType: "string";
715
+ columnType: "SQLiteText";
716
+ data: string;
717
+ driverParam: string;
718
+ notNull: true;
719
+ hasDefault: false;
720
+ isPrimaryKey: false;
721
+ isAutoincrement: false;
722
+ hasRuntimeDefault: false;
723
+ enumValues: [string, ...string[]];
724
+ baseColumn: never;
725
+ identity: undefined;
726
+ generated: undefined;
727
+ }, {}, {
728
+ length: number | undefined;
729
+ }>;
730
+ taskOrder: drizzle_orm_sqlite_core.SQLiteColumn<{
731
+ name: "order";
732
+ tableName: "tasks";
733
+ dataType: "number";
734
+ columnType: "SQLiteInteger";
735
+ data: number;
736
+ driverParam: number;
737
+ notNull: true;
738
+ hasDefault: true;
739
+ isPrimaryKey: false;
740
+ isAutoincrement: false;
741
+ hasRuntimeDefault: false;
742
+ enumValues: undefined;
743
+ baseColumn: never;
744
+ identity: undefined;
745
+ generated: undefined;
746
+ }, {}, {}>;
747
+ assignee: drizzle_orm_sqlite_core.SQLiteColumn<{
748
+ name: "assignee";
749
+ tableName: "tasks";
750
+ dataType: "string";
751
+ columnType: "SQLiteText";
752
+ data: string;
753
+ driverParam: string;
754
+ notNull: false;
755
+ hasDefault: false;
756
+ isPrimaryKey: false;
757
+ isAutoincrement: false;
758
+ hasRuntimeDefault: false;
759
+ enumValues: [string, ...string[]];
760
+ baseColumn: never;
761
+ identity: undefined;
762
+ generated: undefined;
763
+ }, {}, {
764
+ length: number | undefined;
765
+ }>;
766
+ tags: drizzle_orm_sqlite_core.SQLiteColumn<{
767
+ name: "tags";
768
+ tableName: "tasks";
769
+ dataType: "json";
770
+ columnType: "SQLiteTextJson";
771
+ data: string[];
772
+ driverParam: string;
773
+ notNull: false;
774
+ hasDefault: false;
775
+ isPrimaryKey: false;
776
+ isAutoincrement: false;
777
+ hasRuntimeDefault: false;
778
+ enumValues: undefined;
779
+ baseColumn: never;
780
+ identity: undefined;
781
+ generated: undefined;
782
+ }, {}, {
783
+ $type: string[];
784
+ }>;
785
+ createdAt: drizzle_orm_sqlite_core.SQLiteColumn<{
786
+ name: "created_at";
787
+ tableName: "tasks";
788
+ dataType: "string";
789
+ columnType: "SQLiteText";
790
+ data: string;
791
+ driverParam: string;
792
+ notNull: true;
793
+ hasDefault: false;
794
+ isPrimaryKey: false;
795
+ isAutoincrement: false;
796
+ hasRuntimeDefault: false;
797
+ enumValues: [string, ...string[]];
798
+ baseColumn: never;
799
+ identity: undefined;
800
+ generated: undefined;
801
+ }, {}, {
802
+ length: number | undefined;
803
+ }>;
804
+ updatedAt: drizzle_orm_sqlite_core.SQLiteColumn<{
805
+ name: "updated_at";
806
+ tableName: "tasks";
807
+ dataType: "string";
808
+ columnType: "SQLiteText";
809
+ data: string;
810
+ driverParam: string;
811
+ notNull: true;
812
+ hasDefault: false;
813
+ isPrimaryKey: false;
814
+ isAutoincrement: false;
815
+ hasRuntimeDefault: false;
816
+ enumValues: [string, ...string[]];
817
+ baseColumn: never;
818
+ identity: undefined;
819
+ generated: undefined;
820
+ }, {}, {
821
+ length: number | undefined;
822
+ }>;
823
+ };
824
+ dialect: "sqlite";
825
+ }>;
826
+ declare const taskDependencies: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
827
+ name: "task_dependencies";
828
+ schema: undefined;
829
+ columns: {
830
+ taskId: drizzle_orm_sqlite_core.SQLiteColumn<{
831
+ name: "task_id";
832
+ tableName: "task_dependencies";
833
+ dataType: "string";
834
+ columnType: "SQLiteText";
835
+ data: string;
836
+ driverParam: string;
837
+ notNull: true;
838
+ hasDefault: false;
839
+ isPrimaryKey: false;
840
+ isAutoincrement: false;
841
+ hasRuntimeDefault: false;
842
+ enumValues: [string, ...string[]];
843
+ baseColumn: never;
844
+ identity: undefined;
845
+ generated: undefined;
846
+ }, {}, {
847
+ length: number | undefined;
848
+ }>;
849
+ dependsOnTaskId: drizzle_orm_sqlite_core.SQLiteColumn<{
850
+ name: "depends_on_task_id";
851
+ tableName: "task_dependencies";
852
+ dataType: "string";
853
+ columnType: "SQLiteText";
854
+ data: string;
855
+ driverParam: string;
856
+ notNull: true;
857
+ hasDefault: false;
858
+ isPrimaryKey: false;
859
+ isAutoincrement: false;
860
+ hasRuntimeDefault: false;
861
+ enumValues: [string, ...string[]];
862
+ baseColumn: never;
863
+ identity: undefined;
864
+ generated: undefined;
865
+ }, {}, {
866
+ length: number | undefined;
867
+ }>;
868
+ };
869
+ dialect: "sqlite";
870
+ }>;
871
+ declare const taskTouchedFiles: drizzle_orm_sqlite_core.SQLiteTableWithColumns<{
872
+ name: "task_touched_files";
873
+ schema: undefined;
874
+ columns: {
875
+ id: drizzle_orm_sqlite_core.SQLiteColumn<{
876
+ name: "id";
877
+ tableName: "task_touched_files";
878
+ dataType: "string";
879
+ columnType: "SQLiteText";
880
+ data: string;
881
+ driverParam: string;
882
+ notNull: true;
883
+ hasDefault: false;
884
+ isPrimaryKey: true;
885
+ isAutoincrement: false;
886
+ hasRuntimeDefault: false;
887
+ enumValues: [string, ...string[]];
888
+ baseColumn: never;
889
+ identity: undefined;
890
+ generated: undefined;
891
+ }, {}, {
892
+ length: number | undefined;
893
+ }>;
894
+ taskId: drizzle_orm_sqlite_core.SQLiteColumn<{
895
+ name: "task_id";
896
+ tableName: "task_touched_files";
897
+ dataType: "string";
898
+ columnType: "SQLiteText";
899
+ data: string;
900
+ driverParam: string;
901
+ notNull: true;
902
+ hasDefault: false;
903
+ isPrimaryKey: false;
904
+ isAutoincrement: false;
905
+ hasRuntimeDefault: false;
906
+ enumValues: [string, ...string[]];
907
+ baseColumn: never;
908
+ identity: undefined;
909
+ generated: undefined;
910
+ }, {}, {
911
+ length: number | undefined;
912
+ }>;
913
+ path: drizzle_orm_sqlite_core.SQLiteColumn<{
914
+ name: "path";
915
+ tableName: "task_touched_files";
916
+ dataType: "string";
917
+ columnType: "SQLiteText";
918
+ data: string;
919
+ driverParam: string;
920
+ notNull: true;
921
+ hasDefault: false;
922
+ isPrimaryKey: false;
923
+ isAutoincrement: false;
924
+ hasRuntimeDefault: false;
925
+ enumValues: [string, ...string[]];
926
+ baseColumn: never;
927
+ identity: undefined;
928
+ generated: undefined;
929
+ }, {}, {
930
+ length: number | undefined;
931
+ }>;
932
+ fileType: drizzle_orm_sqlite_core.SQLiteColumn<{
933
+ name: "file_type";
934
+ tableName: "task_touched_files";
935
+ dataType: "string";
936
+ columnType: "SQLiteText";
937
+ data: string;
938
+ driverParam: string;
939
+ notNull: true;
940
+ hasDefault: false;
941
+ isPrimaryKey: false;
942
+ isAutoincrement: false;
943
+ hasRuntimeDefault: false;
944
+ enumValues: [string, ...string[]];
945
+ baseColumn: never;
946
+ identity: undefined;
947
+ generated: undefined;
948
+ }, {}, {
949
+ length: number | undefined;
950
+ }>;
951
+ };
952
+ dialect: "sqlite";
953
+ }>;
954
+
955
+ declare const plansRelations: drizzle_orm.Relations<"plans", {
956
+ sprints: drizzle_orm.Many<"sprints">;
957
+ }>;
958
+ declare const sprintsRelations: drizzle_orm.Relations<"sprints", {
959
+ plan: drizzle_orm.One<"plans", true>;
960
+ tasks: drizzle_orm.Many<"tasks">;
961
+ }>;
962
+ declare const tasksRelations: drizzle_orm.Relations<"tasks", {
963
+ sprint: drizzle_orm.One<"sprints", true>;
964
+ touchedFiles: drizzle_orm.Many<"task_touched_files">;
965
+ }>;
966
+ declare const taskTouchedFilesRelations: drizzle_orm.Relations<"task_touched_files", {
967
+ task: drizzle_orm.One<"tasks", true>;
968
+ }>;
969
+
970
+ /**
971
+ * package: @sprintdock/backend
972
+ * author: vikash sharma
973
+ * description: Re-exports all Drizzle tables and relations for the migrator and ORM.
974
+ */
975
+
976
+ declare const schema_plans: typeof plans;
977
+ declare const schema_plansRelations: typeof plansRelations;
978
+ declare const schema_sprints: typeof sprints;
979
+ declare const schema_sprintsRelations: typeof sprintsRelations;
980
+ declare const schema_taskDependencies: typeof taskDependencies;
981
+ declare const schema_taskTouchedFiles: typeof taskTouchedFiles;
982
+ declare const schema_taskTouchedFilesRelations: typeof taskTouchedFilesRelations;
983
+ declare const schema_tasks: typeof tasks;
984
+ declare const schema_tasksRelations: typeof tasksRelations;
985
+ declare namespace schema {
986
+ export { schema_plans as plans, schema_plansRelations as plansRelations, schema_sprints as sprints, schema_sprintsRelations as sprintsRelations, schema_taskDependencies as taskDependencies, schema_taskTouchedFiles as taskTouchedFiles, schema_taskTouchedFilesRelations as taskTouchedFilesRelations, schema_tasks as tasks, schema_tasksRelations as tasksRelations };
987
+ }
988
+
989
+ /**
990
+ * package: @sprintdock/backend
991
+ * author: vikash sharma
992
+ * description: Shared Drizzle SQLite client type for better-sqlite3 and sql.js runtimes.
993
+ */
994
+
995
+ /** Drizzle SQLite database used by repository adapters (file DB or in-memory tests). */
996
+ type DrizzleSqliteDb = BetterSQLite3Database<typeof schema> | SQLJsDatabase<typeof schema>;
997
+
998
+ /**
999
+ * package: @sprintdock/backend
1000
+ * author: vikash sharma
1001
+ * description: Factory wiring repository ports to concrete storage adapters.
1002
+ */
1003
+
1004
+ /** Supported storage backends for repository construction. */
1005
+ type StorageAdapterType = "sqlite";
1006
+ /** Per-adapter connection options. */
1007
+ interface StorageConfig {
1008
+ sqlite?: {
1009
+ db: DrizzleSqliteDb;
1010
+ };
1011
+ }
1012
+ /** Wired repository set for application services. */
1013
+ interface RepositorySet {
1014
+ plans: PlanRepository;
1015
+ sprints: SprintRepository;
1016
+ tasks: TaskRepository;
1017
+ }
1018
+ /**
1019
+ * Instantiates repository implementations for the selected adapter.
1020
+ *
1021
+ * @param adapter Storage kind (currently only sqlite).
1022
+ * @param config Connection options for the adapter.
1023
+ * @returns Repository ports backed by the configured database.
1024
+ */
1025
+ declare function createRepositories(adapter: StorageAdapterType, config: StorageConfig): RepositorySet;
1026
+
1027
+ /**
1028
+ * Validates allowed plan status transitions (draft through archived).
1029
+ */
1030
+ declare class PlanDomainService {
1031
+ private readonly transitions;
1032
+ /**
1033
+ * @param from Current plan status.
1034
+ * @param to Requested plan status.
1035
+ * @returns True when the transition is allowed (including no-op same status).
1036
+ */
1037
+ canTransitionStatus(from: PlanStatus, to: PlanStatus): boolean;
1038
+ /**
1039
+ * @param from Current plan status.
1040
+ * @param to Requested plan status.
1041
+ * @throws ValidationError when the transition is not allowed.
1042
+ */
1043
+ validateTransition(from: PlanStatus, to: PlanStatus): void;
1044
+ }
1045
+
1046
+ /**
1047
+ * Coordinates plan persistence with domain transition rules.
1048
+ */
1049
+ declare class PlanService {
1050
+ private readonly planRepo;
1051
+ private readonly planDomain;
1052
+ constructor(planRepo: PlanRepository, planDomain: PlanDomainService);
1053
+ /** @returns All plans in creation order. */
1054
+ listPlans(): Promise<Plan[]>;
1055
+ /**
1056
+ * Creates a plan and activates it when it is the only plan in storage.
1057
+ */
1058
+ createPlan(input: CreatePlanInput): Promise<Plan>;
1059
+ /**
1060
+ * Loads a plan by id, then by slug.
1061
+ *
1062
+ * @throws NotFoundError when neither matches.
1063
+ */
1064
+ getPlan(idOrSlug: string): Promise<Plan>;
1065
+ /**
1066
+ * @throws NotFoundError when no plan is marked active.
1067
+ */
1068
+ getActivePlan(): Promise<Plan>;
1069
+ /**
1070
+ * Marks the resolved plan as the sole active plan.
1071
+ */
1072
+ setActivePlan(idOrSlug: string): Promise<void>;
1073
+ /**
1074
+ * Updates fields; validates plan status transitions through the domain service.
1075
+ */
1076
+ updatePlan(idOrSlug: string, input: UpdatePlanInput): Promise<Plan>;
1077
+ /**
1078
+ * Deletes a plan by id.
1079
+ *
1080
+ * @throws NotFoundError when the plan does not exist.
1081
+ */
1082
+ deletePlan(id: string): Promise<void>;
1083
+ /**
1084
+ * Resolves the current plan from an optional id or slug, otherwise the active plan.
1085
+ *
1086
+ * @throws NotFoundError when lookup fails or no active plan exists.
1087
+ */
1088
+ resolvePlan(idOrSlug?: string): Promise<Plan>;
1089
+ }
1090
+
1091
+ /**
1092
+ * Validates allowed sprint status transitions (planned through archived).
1093
+ */
1094
+ declare class SprintDomainService {
1095
+ private readonly transitions;
1096
+ /**
1097
+ * @param from Current sprint status.
1098
+ * @param to Requested sprint status.
1099
+ * @returns True when the transition is allowed (including no-op same status).
1100
+ */
1101
+ canTransitionStatus(from: SprintStatus, to: SprintStatus): boolean;
1102
+ /**
1103
+ * @param from Current sprint status.
1104
+ * @param to Requested sprint status.
1105
+ * @throws ValidationError when the transition is not allowed.
1106
+ */
1107
+ validateTransition(from: SprintStatus, to: SprintStatus): void;
1108
+ }
1109
+
1110
+ /**
1111
+ * Coordinates sprint persistence, plan resolution, and sprint lifecycle rules.
1112
+ */
1113
+ declare class SprintService {
1114
+ private readonly sprintRepo;
1115
+ private readonly planRepo;
1116
+ private readonly planService;
1117
+ private readonly sprintDomain;
1118
+ constructor(sprintRepo: SprintRepository, planRepo: PlanRepository, planService: PlanService, sprintDomain: SprintDomainService);
1119
+ /** @param planIdOrSlug When omitted, the active plan is used. */
1120
+ listSprints(planIdOrSlug?: string): Promise<Sprint[]>;
1121
+ /**
1122
+ * Creates a sprint under the resolved plan; {@link CreateSprintInput.planId} is overwritten.
1123
+ */
1124
+ createSprint(planIdOrSlug: string, input: CreateSprintInput): Promise<Sprint>;
1125
+ /**
1126
+ * @throws NotFoundError when the sprint does not exist.
1127
+ */
1128
+ getSprint(id: string): Promise<Sprint>;
1129
+ /**
1130
+ * Finds a sprint by plan scope and slug.
1131
+ *
1132
+ * @throws NotFoundError when the sprint is missing.
1133
+ */
1134
+ getSprintBySlug(planIdOrSlug: string, sprintSlug: string): Promise<Sprint>;
1135
+ /**
1136
+ * Updates sprint fields (name, goal, dates, order) without changing status.
1137
+ * Use {@link updateSprintStatus} for lifecycle transitions.
1138
+ */
1139
+ updateSprint(id: string, input: Pick<UpdateSprintInput, "name" | "goal" | "markdownContent" | "startDate" | "endDate" | "order">): Promise<Sprint>;
1140
+ /**
1141
+ * Updates sprint status after validating the transition.
1142
+ */
1143
+ updateSprintStatus(id: string, status: SprintStatus): Promise<Sprint>;
1144
+ /**
1145
+ * @throws NotFoundError when the sprint does not exist.
1146
+ */
1147
+ deleteSprint(id: string): Promise<void>;
1148
+ }
1149
+
1150
+ /**
1151
+ * Enforces task status moves, unique ordering, and acyclic dependencies.
1152
+ */
1153
+ declare class TaskDomainService {
1154
+ private readonly transitions;
1155
+ /**
1156
+ * @param from Current task status.
1157
+ * @param to Requested task status.
1158
+ * @returns True when the transition is allowed (including no-op same status).
1159
+ */
1160
+ canTransitionStatus(from: TaskStatus, to: TaskStatus): boolean;
1161
+ /**
1162
+ * @param from Current task status.
1163
+ * @param to Requested task status.
1164
+ * @throws ValidationError when the transition is not allowed.
1165
+ */
1166
+ validateTransition(from: TaskStatus, to: TaskStatus): void;
1167
+ /**
1168
+ * @param tasks Tasks whose {@link Task.order} values must be unique within this set.
1169
+ * @throws ValidationError when two tasks share the same order value.
1170
+ */
1171
+ validateOrderUniqueness(tasks: Task[]): void;
1172
+ /**
1173
+ * Ensures dependencies only reference known tasks and form a directed acyclic graph.
1174
+ *
1175
+ * @param tasks Tasks participating in the graph.
1176
+ * @param dependencies Directed edges: taskId depends on dependsOnTaskId.
1177
+ * @throws ValidationError when an endpoint is missing or a cycle exists.
1178
+ */
1179
+ validateDependencyGraph(tasks: Task[], dependencies: TaskDependency[]): void;
1180
+ /**
1181
+ * @param dependsOnIds Task ids that must exist as prerequisites.
1182
+ * @param existingTaskIds Task ids that are allowed as dependency targets.
1183
+ * @throws ValidationError when any prerequisite id is not in the allowed set.
1184
+ */
1185
+ validateDependencyReferences(dependsOnIds: string[], existingTaskIds: string[]): void;
1186
+ }
1187
+
1188
+ /**
1189
+ * package: @sprintdock/backend
1190
+ * author: vikash sharma
1191
+ * description: API payload for per-sprint task status analytics within a plan.
1192
+ */
1193
+
1194
+ /** Counts keyed by task status for JSON responses. */
1195
+ interface TaskStatusCountsDto {
1196
+ todo: number;
1197
+ in_progress: number;
1198
+ blocked: number;
1199
+ done: number;
1200
+ }
1201
+ interface SprintTaskAnalyticsDto {
1202
+ sprint: Sprint;
1203
+ tasksByStatus: TaskStatusCountsDto;
1204
+ totalTasks: number;
1205
+ }
1206
+ interface PlanSprintTaskAnalyticsDto {
1207
+ planId: string;
1208
+ sprints: SprintTaskAnalyticsDto[];
1209
+ rollup: {
1210
+ tasksByStatus: TaskStatusCountsDto;
1211
+ totalTasks: number;
1212
+ sprintCount: number;
1213
+ };
1214
+ }
1215
+
1216
+ /**
1217
+ * Field updates for {@link TaskService.updateTask}
1218
+ * (status changes use {@link updateTaskStatus}).
1219
+ */
1220
+ type TaskFieldUpdateInput = Omit<UpdateTaskInput, "status">;
1221
+ /**
1222
+ * Coordinates task persistence, plan resolution, ordering, and dependency validation.
1223
+ */
1224
+ declare class TaskService {
1225
+ private readonly taskRepo;
1226
+ private readonly sprintRepo;
1227
+ private readonly planService;
1228
+ private readonly taskDomain;
1229
+ constructor(taskRepo: TaskRepository, sprintRepo: SprintRepository, planService: PlanService, taskDomain: TaskDomainService);
1230
+ /**
1231
+ * Lists tasks for a sprint, or all tasks in a resolved plan when {@link sprintId} is omitted.
1232
+ */
1233
+ listTasks(sprintId?: string, planIdOrSlug?: string, filter?: TaskFilter): Promise<Task[]>;
1234
+ /**
1235
+ * Creates a task after validating sprint ownership, order uniqueness, and dependencies.
1236
+ */
1237
+ createTask(input: CreateTaskInput, planIdOrSlug?: string): Promise<Task>;
1238
+ /**
1239
+ * @throws NotFoundError when the task does not exist.
1240
+ */
1241
+ getTask(id: string): Promise<Task>;
1242
+ /**
1243
+ * Updates title, description, priority, tags, or order (not status).
1244
+ */
1245
+ updateTask(id: string, input: TaskFieldUpdateInput): Promise<Task>;
1246
+ /**
1247
+ * Replaces prerequisite edges for a task after validating the dependency DAG.
1248
+ */
1249
+ setTaskDependencies(taskId: string, dependsOnTaskIds: string[], planIdOrSlug?: string): Promise<void>;
1250
+ /**
1251
+ * Loads prerequisite tasks and tasks that depend on this task.
1252
+ */
1253
+ getTaskDependencyInfo(taskId: string, planIdOrSlug?: string): Promise<{
1254
+ dependsOn: Task[];
1255
+ dependedOnBy: Task[];
1256
+ }>;
1257
+ /**
1258
+ * Updates task status after validating the transition.
1259
+ */
1260
+ updateTaskStatus(id: string, status: TaskStatus): Promise<Task>;
1261
+ /**
1262
+ * Sets or clears the task assignee.
1263
+ */
1264
+ assignTask(id: string, assignee: string | null): Promise<Task>;
1265
+ /**
1266
+ * Moves a task to another sprint in the same plan.
1267
+ */
1268
+ moveTask(taskId: string, targetSprintId: string): Promise<Task>;
1269
+ /**
1270
+ * @throws NotFoundError when the task does not exist.
1271
+ */
1272
+ deleteTask(id: string): Promise<void>;
1273
+ /**
1274
+ * Loads all sprints for the plan (ordered) and task counts by status per sprint, plus plan rollup.
1275
+ */
1276
+ getPlanSprintTaskAnalytics(planIdOrSlug: string): Promise<PlanSprintTaskAnalyticsDto>;
1277
+ /**
1278
+ * Fleet Command throughput: counts across all tasks (all plans). Blocked tasks are omitted from the trio.
1279
+ */
1280
+ getGlobalTaskThroughput(): Promise<{
1281
+ todo: number;
1282
+ inProgress: number;
1283
+ done: number;
1284
+ }>;
1285
+ }
1286
+
1287
+ /**
1288
+ * package: @sprintdock/backend
1289
+ * author: vikash sharma
1290
+ * description: Factory wiring application services and domain services for a repository set.
1291
+ */
1292
+
1293
+ /** Application-layer services exposed to protocol adapters. */
1294
+ interface ServiceSet {
1295
+ planService: PlanService;
1296
+ sprintService: SprintService;
1297
+ taskService: TaskService;
1298
+ }
1299
+ /**
1300
+ * Builds domain services and wires application services for the given repositories.
1301
+ */
1302
+ declare function createApplicationServices(repos: RepositorySet): ServiceSet;
1303
+
1304
+ /**
1305
+ * package: @sprintdock/backend
1306
+ * author: vikash sharma
1307
+ * description: Express application factory wiring middleware and versioned API routes.
1308
+ */
1309
+
1310
+ interface HttpAppOptions {
1311
+ /** When true (default), applies permissive CORS. */
1312
+ cors?: boolean;
1313
+ /** Forwarded to Express `trust proxy`. */
1314
+ trustProxy?: boolean;
1315
+ }
1316
+ /**
1317
+ * Assembles JSON parsing, optional CORS, request id propagation, `GET /` discovery payload, `/api/v1` routes, and the error handler.
1318
+ */
1319
+ declare function createHttpApp(services: ServiceSet, options?: HttpAppOptions): Express;
1320
+
1321
+ type SprintdockMcpTransportMode = "stdio" | "http";
1322
+ interface SprintdockMcpRuntimeOptions {
1323
+ transport?: SprintdockMcpTransportMode;
1324
+ httpHost?: string;
1325
+ httpPort?: number;
1326
+ }
1327
+ /**
1328
+ * Runs Sprintdock MCP against the workspace SQLite database.
1329
+ */
1330
+ declare class SprintdockMcpRuntime {
1331
+ private readonly options;
1332
+ private readonly workspaceRoot;
1333
+ private toolDeps;
1334
+ constructor(options?: SprintdockMcpRuntimeOptions);
1335
+ /**
1336
+ * Boots SQLite, registers tools, and starts the selected transport.
1337
+ *
1338
+ * @returns Process-style exit code (0 on success).
1339
+ */
1340
+ run(): Promise<number>;
1341
+ private createMcpServer;
1342
+ }
1343
+ /**
1344
+ * Convenience entrypoint for `apps/server` and scripts.
1345
+ */
1346
+ declare function runSprintdockMcpServer(options?: SprintdockMcpRuntimeOptions): Promise<number>;
1347
+
1348
+ interface SprintdockSqliteBootstrapResult {
1349
+ db: BetterSQLite3Database<typeof schema>;
1350
+ services: ServiceSet;
1351
+ dbPath: string;
1352
+ }
1353
+ /**
1354
+ * Resolves DB path (`SPRINTDOCK_DB_PATH` or `.sprintdock/sprintdock.db`), migrates, and returns services.
1355
+ */
1356
+ declare function bootstrapSprintdockSqlite(): Promise<SprintdockSqliteBootstrapResult>;
1357
+
1358
+ /**
1359
+ * package: @sprintdock/backend
1360
+ * author: vikash sharma
1361
+ * description: Structured audit logger contract for mutating MCP tool operations.
1362
+ */
1363
+ /**
1364
+ * Structured audit event model.
1365
+ */
1366
+ interface AuditEvent {
1367
+ action: string;
1368
+ principalId: string;
1369
+ transport: "stdio" | "http";
1370
+ resourceId?: string;
1371
+ correlationId: string;
1372
+ metadata?: Record<string, unknown>;
1373
+ }
1374
+ /**
1375
+ * Contract for audit event emission.
1376
+ */
1377
+ interface AuditLog {
1378
+ write(event: AuditEvent): void;
1379
+ }
1380
+
1381
+ /**
1382
+ * Correlation id provider used across tool and resource handlers.
1383
+ */
1384
+ declare class RequestCorrelation {
1385
+ /**
1386
+ * Creates a new unique correlation identifier.
1387
+ *
1388
+ * @returns Correlation id string.
1389
+ */
1390
+ create(): string;
1391
+ }
1392
+
1393
+ /**
1394
+ * package: @sprintdock/backend
1395
+ * author: vikash sharma
1396
+ * description: Authentication context contracts for MCP request authorization.
1397
+ */
1398
+ /**
1399
+ * Principal context resolved for each request.
1400
+ */
1401
+ interface AuthContext {
1402
+ principalId: string;
1403
+ scopes: readonly string[];
1404
+ transport: "stdio" | "http";
1405
+ }
1406
+ /**
1407
+ * Resolver interface for obtaining request principal details.
1408
+ */
1409
+ interface AuthContextResolver {
1410
+ resolve(transport: "stdio" | "http"): Promise<AuthContext>;
1411
+ }
1412
+
1413
+ /**
1414
+ * package: @sprintdock/backend
1415
+ * author: vikash sharma
1416
+ * description: Lightweight per-key rate limiter for MCP tool invocations.
1417
+ */
1418
+ /**
1419
+ * Rate limiter result for caller decisions.
1420
+ */
1421
+ interface RateLimitResult {
1422
+ allowed: boolean;
1423
+ retryAfterSeconds: number;
1424
+ }
1425
+ /**
1426
+ * Contract for backend tool-call throttling.
1427
+ */
1428
+ interface BackendRateLimiter {
1429
+ check(key: string): RateLimitResult;
1430
+ }
1431
+
1432
+ /**
1433
+ * package: @sprintdock/backend
1434
+ * author: vikash sharma
1435
+ * description: Shared Zod schemas and helpers for Sprintdock MCP tool plugins.
1436
+ */
1437
+
1438
+ declare const optionalPlanSlug: z.ZodOptional<z.ZodString>;
1439
+ declare const paginationSchema: {
1440
+ limit: z.ZodOptional<z.ZodNumber>;
1441
+ offset: z.ZodOptional<z.ZodNumber>;
1442
+ };
1443
+ declare const TASK_STATUS_SCHEMA: z.ZodEnum<{
1444
+ todo: "todo";
1445
+ in_progress: "in_progress";
1446
+ blocked: "blocked";
1447
+ done: "done";
1448
+ }>;
1449
+ declare const TASK_PRIORITY_SCHEMA: z.ZodEnum<{
1450
+ low: "low";
1451
+ medium: "medium";
1452
+ high: "high";
1453
+ critical: "critical";
1454
+ }>;
1455
+ declare function applyPagination<T>(items: T[], limit?: number, offset?: number): {
1456
+ page: T[];
1457
+ total: number;
1458
+ };
1459
+ declare function paginationNote(total: number, limit?: number, offset?: number): string;
1460
+ declare function jsonStructured(data: unknown): Record<string, unknown>;
1461
+ /** Toolkit passed to every plugin so custom plugins reuse the same schemas and helpers. */
1462
+ interface SprintdockMcpToolKit {
1463
+ readonly jsonStructured: typeof jsonStructured;
1464
+ readonly applyPagination: typeof applyPagination;
1465
+ readonly paginationNote: typeof paginationNote;
1466
+ readonly optionalPlanSlug: typeof optionalPlanSlug;
1467
+ readonly paginationSchema: typeof paginationSchema;
1468
+ readonly TASK_STATUS_SCHEMA: typeof TASK_STATUS_SCHEMA;
1469
+ readonly TASK_PRIORITY_SCHEMA: typeof TASK_PRIORITY_SCHEMA;
1470
+ }
1471
+ /**
1472
+ * Returns the shared toolkit (immutable singleton) for MCP tool plugins.
1473
+ */
1474
+ declare function createSprintdockMcpToolKit(): SprintdockMcpToolKit;
1475
+
1476
+ /**
1477
+ * package: @sprintdock/backend
1478
+ * author: vikash sharma
1479
+ * description: Plugin contracts for composing Sprintdock MCP tool registration.
1480
+ */
1481
+
1482
+ /** Injected services and security hooks for MCP tool handlers. */
1483
+ interface SprintdockMcpToolDependencies {
1484
+ services: ServiceSet;
1485
+ auditLog: AuditLog;
1486
+ rateLimiter: BackendRateLimiter;
1487
+ requestCorrelation: RequestCorrelation;
1488
+ authContextResolver: AuthContextResolver;
1489
+ }
1490
+ /** Context passed to each plugin's `register` method. */
1491
+ interface SprintdockMcpPluginContext {
1492
+ deps: SprintdockMcpToolDependencies;
1493
+ kit: SprintdockMcpToolKit;
1494
+ }
1495
+ /**
1496
+ * A plugin registers one or more MCP tools. Implement `id` for logging;
1497
+ * use `register` to call `server.registerTool` like the built-in plugins.
1498
+ */
1499
+ interface SprintdockMcpToolPlugin {
1500
+ readonly id: string;
1501
+ register(server: McpServer, ctx: SprintdockMcpPluginContext): void;
1502
+ }
1503
+ /** Optional configuration when registering tools on the MCP server. */
1504
+ interface RegisterSprintdockMcpToolsOptions {
1505
+ /**
1506
+ * Plugins to load, in order. Defaults to the full built-in Sprintdock set.
1507
+ * Append custom plugins to add tools; pass a subset to expose only part of the API.
1508
+ */
1509
+ plugins?: SprintdockMcpToolPlugin[];
1510
+ }
1511
+
1512
+ /**
1513
+ * Built-in plugins in registration order. Duplicate tool names across plugins will
1514
+ * overwrite earlier registrations — keep each tool name unique per plugin set.
1515
+ */
1516
+ declare const defaultSprintdockMcpPlugins: readonly SprintdockMcpToolPlugin[];
1517
+
1518
+ /**
1519
+ * package: @sprintdock/backend
1520
+ * author: vikash sharma
1521
+ * description: Composes Sprintdock MCP tools from plugins (default set + optional extensions).
1522
+ */
1523
+
1524
+ /**
1525
+ * Registers MCP tools by running each plugin in order against the server.
1526
+ *
1527
+ * @example Add a custom tool plugin after the defaults:
1528
+ * ```ts
1529
+ * registerSprintdockMcpTools(server, deps, {
1530
+ * plugins: [...defaultSprintdockMcpPlugins, myCustomPlugin]
1531
+ * });
1532
+ * ```
1533
+ */
1534
+ declare function registerSprintdockMcpTools(server: McpServer, d: SprintdockMcpToolDependencies, options?: RegisterSprintdockMcpToolsOptions): void;
1535
+
1536
+ export { type HttpAppOptions, type RegisterSprintdockMcpToolsOptions, type RepositorySet, type ServiceSet, type SprintdockMcpPluginContext, SprintdockMcpRuntime, type SprintdockMcpRuntimeOptions, type SprintdockMcpToolDependencies, type SprintdockMcpToolKit, type SprintdockMcpToolPlugin, type SprintdockMcpTransportMode, type SprintdockSqliteBootstrapResult, type StorageAdapterType, type StorageConfig, bootstrapSprintdockSqlite, createApplicationServices, createHttpApp, createRepositories, createSprintdockMcpToolKit, defaultSprintdockMcpPlugins, registerSprintdockMcpTools, runSprintdockMcpServer };