@mcoda/core 0.1.4

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 (142) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +9 -0
  4. package/dist/api/AgentsApi.d.ts +36 -0
  5. package/dist/api/AgentsApi.d.ts.map +1 -0
  6. package/dist/api/AgentsApi.js +176 -0
  7. package/dist/api/QaTasksApi.d.ts +8 -0
  8. package/dist/api/QaTasksApi.d.ts.map +1 -0
  9. package/dist/api/QaTasksApi.js +36 -0
  10. package/dist/api/TasksApi.d.ts +7 -0
  11. package/dist/api/TasksApi.d.ts.map +1 -0
  12. package/dist/api/TasksApi.js +34 -0
  13. package/dist/config/ConfigService.d.ts +3 -0
  14. package/dist/config/ConfigService.d.ts.map +1 -0
  15. package/dist/config/ConfigService.js +2 -0
  16. package/dist/domain/dependencies/Dependency.d.ts +3 -0
  17. package/dist/domain/dependencies/Dependency.d.ts.map +1 -0
  18. package/dist/domain/dependencies/Dependency.js +2 -0
  19. package/dist/domain/epics/Epic.d.ts +3 -0
  20. package/dist/domain/epics/Epic.d.ts.map +1 -0
  21. package/dist/domain/epics/Epic.js +2 -0
  22. package/dist/domain/projects/Project.d.ts +3 -0
  23. package/dist/domain/projects/Project.d.ts.map +1 -0
  24. package/dist/domain/projects/Project.js +2 -0
  25. package/dist/domain/tasks/Task.d.ts +3 -0
  26. package/dist/domain/tasks/Task.d.ts.map +1 -0
  27. package/dist/domain/tasks/Task.js +2 -0
  28. package/dist/domain/userStories/UserStory.d.ts +3 -0
  29. package/dist/domain/userStories/UserStory.d.ts.map +1 -0
  30. package/dist/domain/userStories/UserStory.js +2 -0
  31. package/dist/index.d.ts +28 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +27 -0
  34. package/dist/prompts/PdrPrompts.d.ts +4 -0
  35. package/dist/prompts/PdrPrompts.d.ts.map +1 -0
  36. package/dist/prompts/PdrPrompts.js +21 -0
  37. package/dist/prompts/PromptLoader.d.ts +3 -0
  38. package/dist/prompts/PromptLoader.d.ts.map +1 -0
  39. package/dist/prompts/PromptLoader.js +2 -0
  40. package/dist/prompts/SdsPrompts.d.ts +5 -0
  41. package/dist/prompts/SdsPrompts.d.ts.map +1 -0
  42. package/dist/prompts/SdsPrompts.js +44 -0
  43. package/dist/services/agents/AgentManagementService.d.ts +3 -0
  44. package/dist/services/agents/AgentManagementService.d.ts.map +1 -0
  45. package/dist/services/agents/AgentManagementService.js +2 -0
  46. package/dist/services/agents/GatewayAgentService.d.ts +92 -0
  47. package/dist/services/agents/GatewayAgentService.d.ts.map +1 -0
  48. package/dist/services/agents/GatewayAgentService.js +870 -0
  49. package/dist/services/agents/RoutingApiClient.d.ts +23 -0
  50. package/dist/services/agents/RoutingApiClient.d.ts.map +1 -0
  51. package/dist/services/agents/RoutingApiClient.js +62 -0
  52. package/dist/services/agents/RoutingService.d.ts +50 -0
  53. package/dist/services/agents/RoutingService.d.ts.map +1 -0
  54. package/dist/services/agents/RoutingService.js +386 -0
  55. package/dist/services/agents/generated/RoutingApiClient.d.ts +21 -0
  56. package/dist/services/agents/generated/RoutingApiClient.d.ts.map +1 -0
  57. package/dist/services/agents/generated/RoutingApiClient.js +68 -0
  58. package/dist/services/backlog/BacklogService.d.ts +98 -0
  59. package/dist/services/backlog/BacklogService.d.ts.map +1 -0
  60. package/dist/services/backlog/BacklogService.js +453 -0
  61. package/dist/services/backlog/TaskOrderingService.d.ts +88 -0
  62. package/dist/services/backlog/TaskOrderingService.d.ts.map +1 -0
  63. package/dist/services/backlog/TaskOrderingService.js +675 -0
  64. package/dist/services/docs/DocsService.d.ts +82 -0
  65. package/dist/services/docs/DocsService.d.ts.map +1 -0
  66. package/dist/services/docs/DocsService.js +1631 -0
  67. package/dist/services/estimate/EstimateService.d.ts +12 -0
  68. package/dist/services/estimate/EstimateService.d.ts.map +1 -0
  69. package/dist/services/estimate/EstimateService.js +103 -0
  70. package/dist/services/estimate/VelocityService.d.ts +19 -0
  71. package/dist/services/estimate/VelocityService.d.ts.map +1 -0
  72. package/dist/services/estimate/VelocityService.js +237 -0
  73. package/dist/services/estimate/types.d.ts +30 -0
  74. package/dist/services/estimate/types.d.ts.map +1 -0
  75. package/dist/services/estimate/types.js +1 -0
  76. package/dist/services/execution/ExecutionService.d.ts +3 -0
  77. package/dist/services/execution/ExecutionService.d.ts.map +1 -0
  78. package/dist/services/execution/ExecutionService.js +2 -0
  79. package/dist/services/execution/QaFollowupService.d.ts +38 -0
  80. package/dist/services/execution/QaFollowupService.d.ts.map +1 -0
  81. package/dist/services/execution/QaFollowupService.js +236 -0
  82. package/dist/services/execution/QaProfileService.d.ts +22 -0
  83. package/dist/services/execution/QaProfileService.d.ts.map +1 -0
  84. package/dist/services/execution/QaProfileService.js +142 -0
  85. package/dist/services/execution/QaTasksService.d.ts +101 -0
  86. package/dist/services/execution/QaTasksService.d.ts.map +1 -0
  87. package/dist/services/execution/QaTasksService.js +1117 -0
  88. package/dist/services/execution/TaskSelectionService.d.ts +50 -0
  89. package/dist/services/execution/TaskSelectionService.d.ts.map +1 -0
  90. package/dist/services/execution/TaskSelectionService.js +281 -0
  91. package/dist/services/execution/TaskStateService.d.ts +19 -0
  92. package/dist/services/execution/TaskStateService.d.ts.map +1 -0
  93. package/dist/services/execution/TaskStateService.js +59 -0
  94. package/dist/services/execution/WorkOnTasksService.d.ts +80 -0
  95. package/dist/services/execution/WorkOnTasksService.d.ts.map +1 -0
  96. package/dist/services/execution/WorkOnTasksService.js +1833 -0
  97. package/dist/services/jobs/JobInsightsService.d.ts +97 -0
  98. package/dist/services/jobs/JobInsightsService.d.ts.map +1 -0
  99. package/dist/services/jobs/JobInsightsService.js +263 -0
  100. package/dist/services/jobs/JobResumeService.d.ts +16 -0
  101. package/dist/services/jobs/JobResumeService.d.ts.map +1 -0
  102. package/dist/services/jobs/JobResumeService.js +113 -0
  103. package/dist/services/jobs/JobService.d.ts +149 -0
  104. package/dist/services/jobs/JobService.d.ts.map +1 -0
  105. package/dist/services/jobs/JobService.js +490 -0
  106. package/dist/services/jobs/JobsApiClient.d.ts +73 -0
  107. package/dist/services/jobs/JobsApiClient.d.ts.map +1 -0
  108. package/dist/services/jobs/JobsApiClient.js +67 -0
  109. package/dist/services/openapi/OpenApiService.d.ts +54 -0
  110. package/dist/services/openapi/OpenApiService.d.ts.map +1 -0
  111. package/dist/services/openapi/OpenApiService.js +503 -0
  112. package/dist/services/planning/CreateTasksService.d.ts +68 -0
  113. package/dist/services/planning/CreateTasksService.d.ts.map +1 -0
  114. package/dist/services/planning/CreateTasksService.js +989 -0
  115. package/dist/services/planning/KeyHelpers.d.ts +5 -0
  116. package/dist/services/planning/KeyHelpers.d.ts.map +1 -0
  117. package/dist/services/planning/KeyHelpers.js +62 -0
  118. package/dist/services/planning/PlanningService.d.ts +3 -0
  119. package/dist/services/planning/PlanningService.d.ts.map +1 -0
  120. package/dist/services/planning/PlanningService.js +2 -0
  121. package/dist/services/planning/RefineTasksService.d.ts +56 -0
  122. package/dist/services/planning/RefineTasksService.d.ts.map +1 -0
  123. package/dist/services/planning/RefineTasksService.js +1328 -0
  124. package/dist/services/review/CodeReviewService.d.ts +103 -0
  125. package/dist/services/review/CodeReviewService.d.ts.map +1 -0
  126. package/dist/services/review/CodeReviewService.js +1187 -0
  127. package/dist/services/system/SystemUpdateService.d.ts +55 -0
  128. package/dist/services/system/SystemUpdateService.d.ts.map +1 -0
  129. package/dist/services/system/SystemUpdateService.js +136 -0
  130. package/dist/services/tasks/TaskApiResolver.d.ts +7 -0
  131. package/dist/services/tasks/TaskApiResolver.d.ts.map +1 -0
  132. package/dist/services/tasks/TaskApiResolver.js +41 -0
  133. package/dist/services/tasks/TaskDetailService.d.ts +106 -0
  134. package/dist/services/tasks/TaskDetailService.d.ts.map +1 -0
  135. package/dist/services/tasks/TaskDetailService.js +332 -0
  136. package/dist/services/telemetry/TelemetryService.d.ts +53 -0
  137. package/dist/services/telemetry/TelemetryService.d.ts.map +1 -0
  138. package/dist/services/telemetry/TelemetryService.js +434 -0
  139. package/dist/workspace/WorkspaceManager.d.ts +35 -0
  140. package/dist/workspace/WorkspaceManager.d.ts.map +1 -0
  141. package/dist/workspace/WorkspaceManager.js +201 -0
  142. package/package.json +45 -0
@@ -0,0 +1,12 @@
1
+ import type { EstimateOptions, EstimateResult } from "./types.js";
2
+ import type { WorkspaceResolution } from "../../workspace/WorkspaceManager.js";
3
+ export declare class EstimateService {
4
+ private workspace;
5
+ private constructor();
6
+ static create(workspace: WorkspaceResolution): Promise<EstimateService>;
7
+ private computeDurations;
8
+ private computeEtas;
9
+ estimate(options: Omit<EstimateOptions, "workspace">): Promise<EstimateResult>;
10
+ close(): Promise<void>;
11
+ }
12
+ //# sourceMappingURL=EstimateService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EstimateService.d.ts","sourceRoot":"","sources":["../../../src/services/estimate/EstimateService.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAmC,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEnG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAI/E,qBAAa,eAAe;IACN,OAAO,CAAC,SAAS;IAArC,OAAO;WAEM,MAAM,CAAC,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,eAAe,CAAC;IAI7E,OAAO,CAAC,gBAAgB;IAqBxB,OAAO,CAAC,WAAW;IAmBb,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC;IAmD9E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
@@ -0,0 +1,103 @@
1
+ import { BacklogService } from "../backlog/BacklogService.js";
2
+ import { VelocityService } from "./VelocityService.js";
3
+ const HOURS_IN_MS = 3600 * 1000;
4
+ export class EstimateService {
5
+ constructor(workspace) {
6
+ this.workspace = workspace;
7
+ }
8
+ static async create(workspace) {
9
+ return new EstimateService(workspace);
10
+ }
11
+ computeDurations(totals, velocity) {
12
+ const safeDivide = (sp, spPerHour) => {
13
+ if (!sp || sp <= 0)
14
+ return 0;
15
+ if (!spPerHour || spPerHour <= 0)
16
+ return null;
17
+ return sp / spPerHour;
18
+ };
19
+ const implementationHours = safeDivide(totals.implementation.story_points, velocity.implementationSpPerHour);
20
+ const reviewHours = safeDivide(totals.review.story_points, velocity.reviewSpPerHour);
21
+ const qaHours = safeDivide(totals.qa.story_points, velocity.qaSpPerHour);
22
+ const durationsList = [implementationHours, reviewHours, qaHours];
23
+ const hasNull = durationsList.some((value) => value === null);
24
+ const numeric = durationsList.filter((value) => value !== null);
25
+ const totalHours = hasNull || numeric.length === 0 ? null : Math.max(...numeric);
26
+ return {
27
+ implementationHours,
28
+ reviewHours,
29
+ qaHours,
30
+ totalHours,
31
+ };
32
+ }
33
+ computeEtas(durations) {
34
+ const now = Date.now();
35
+ const addHours = (hours) => {
36
+ if (hours === null || hours === undefined || hours < 0)
37
+ return undefined;
38
+ return new Date(now + hours * HOURS_IN_MS).toISOString();
39
+ };
40
+ const readyToReviewEta = durations.implementationHours !== null ? addHours(durations.implementationHours ?? undefined) : undefined;
41
+ const readyToQaEta = durations.implementationHours !== null && durations.reviewHours !== null
42
+ ? addHours(Math.max(durations.implementationHours ?? 0, durations.reviewHours ?? 0))
43
+ : undefined;
44
+ const completeEta = durations.totalHours !== null ? addHours(durations.totalHours ?? undefined) : undefined;
45
+ return {
46
+ readyToReviewEta,
47
+ readyToQaEta,
48
+ completeEta,
49
+ };
50
+ }
51
+ async estimate(options) {
52
+ const backlogService = await BacklogService.create(this.workspace);
53
+ let backlogTotals;
54
+ try {
55
+ const { summary } = await backlogService.getBacklog({
56
+ projectKey: options.projectKey,
57
+ epicKey: options.epicKey,
58
+ storyKey: options.storyKey,
59
+ assignee: options.assignee,
60
+ });
61
+ backlogTotals = summary.totals;
62
+ }
63
+ finally {
64
+ await backlogService.close();
65
+ }
66
+ const velocityService = await VelocityService.create(this.workspace);
67
+ let effectiveVelocity;
68
+ try {
69
+ effectiveVelocity = await velocityService.getEffectiveVelocity({
70
+ projectKey: options.projectKey,
71
+ epicKey: options.epicKey,
72
+ storyKey: options.storyKey,
73
+ assignee: options.assignee,
74
+ mode: options.mode,
75
+ windowTasks: options.windowTasks,
76
+ spPerHourAll: options.spPerHourAll,
77
+ spPerHourReview: options.spPerHourReview,
78
+ spPerHourQa: options.spPerHourQa,
79
+ });
80
+ }
81
+ finally {
82
+ await velocityService.close();
83
+ }
84
+ const durationsHours = this.computeDurations(backlogTotals, effectiveVelocity);
85
+ const etas = this.computeEtas(durationsHours);
86
+ return {
87
+ scope: {
88
+ workspaceId: this.workspace.workspaceId,
89
+ project: options.projectKey,
90
+ epic: options.epicKey,
91
+ story: options.storyKey,
92
+ assignee: options.assignee,
93
+ },
94
+ backlogTotals,
95
+ effectiveVelocity,
96
+ durationsHours,
97
+ etas,
98
+ };
99
+ }
100
+ async close() {
101
+ // No long-lived resources to release yet, placeholder for symmetry with other services.
102
+ }
103
+ }
@@ -0,0 +1,19 @@
1
+ import { WorkspaceResolution } from "../../workspace/WorkspaceManager.js";
2
+ import type { EffectiveVelocity, VelocityOptions } from "./types.js";
3
+ export declare class VelocityService {
4
+ private workspace;
5
+ private db;
6
+ private connection;
7
+ private globalVelocity?;
8
+ private constructor();
9
+ static create(workspace: WorkspaceResolution): Promise<VelocityService>;
10
+ close(): Promise<void>;
11
+ private static readGlobalVelocityConfig;
12
+ private resolveConfig;
13
+ private resolveScopeIds;
14
+ private buildTaskFilters;
15
+ private computeLaneVelocity;
16
+ private deriveDurationSeconds;
17
+ getEffectiveVelocity(options?: VelocityOptions): Promise<EffectiveVelocity>;
18
+ }
19
+ //# sourceMappingURL=VelocityService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VelocityService.d.ts","sourceRoot":"","sources":["../../../src/services/estimate/VelocityService.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,KAAK,EAAE,iBAAiB,EAAkB,eAAe,EAAoB,MAAM,YAAY,CAAC;AAKvG,qBAAa,eAAe;IAExB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,UAAU;IAClB,OAAO,CAAC,cAAc,CAAC;IAJzB,OAAO;WAOM,MAAM,CAAC,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,eAAe,CAAC;IAOvE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;mBAIP,wBAAwB;IAiB7C,OAAO,CAAC,aAAa;YAoCP,eAAe;IAgC7B,OAAO,CAAC,gBAAgB;YAuBV,mBAAmB;IAmEjC,OAAO,CAAC,qBAAqB;IAQvB,oBAAoB,CAAC,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CA2DtF"}
@@ -0,0 +1,237 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { Connection } from "@mcoda/db";
4
+ import { PathHelper } from "@mcoda/shared";
5
+ const DEFAULT_SP_PER_HOUR = 15;
6
+ const DEFAULT_ALPHA = 0.5;
7
+ export class VelocityService {
8
+ constructor(workspace, db, connection, globalVelocity) {
9
+ this.workspace = workspace;
10
+ this.db = db;
11
+ this.connection = connection;
12
+ this.globalVelocity = globalVelocity;
13
+ }
14
+ static async create(workspace) {
15
+ const dbPath = PathHelper.getWorkspaceDbPath(workspace.workspaceRoot);
16
+ const connection = await Connection.open(dbPath);
17
+ const globalVelocity = await VelocityService.readGlobalVelocityConfig();
18
+ return new VelocityService(workspace, connection.db, connection, globalVelocity);
19
+ }
20
+ async close() {
21
+ await this.connection.close();
22
+ }
23
+ static async readGlobalVelocityConfig() {
24
+ const configPath = path.join(PathHelper.getGlobalMcodaDir(), "config.json");
25
+ try {
26
+ const raw = await fs.readFile(configPath, "utf8");
27
+ const parsed = JSON.parse(raw);
28
+ if (!parsed.velocity)
29
+ return undefined;
30
+ return {
31
+ implementationSpPerHour: parsed.velocity.implementationSpPerHour ?? DEFAULT_SP_PER_HOUR,
32
+ reviewSpPerHour: parsed.velocity.reviewSpPerHour ?? DEFAULT_SP_PER_HOUR,
33
+ qaSpPerHour: parsed.velocity.qaSpPerHour ?? DEFAULT_SP_PER_HOUR,
34
+ alpha: parsed.velocity.alpha ?? DEFAULT_ALPHA,
35
+ };
36
+ }
37
+ catch {
38
+ return undefined;
39
+ }
40
+ }
41
+ resolveConfig(options) {
42
+ const base = {
43
+ implementationSpPerHour: DEFAULT_SP_PER_HOUR,
44
+ reviewSpPerHour: DEFAULT_SP_PER_HOUR,
45
+ qaSpPerHour: DEFAULT_SP_PER_HOUR,
46
+ alpha: DEFAULT_ALPHA,
47
+ };
48
+ // Global config first
49
+ if (this.globalVelocity) {
50
+ base.implementationSpPerHour = this.globalVelocity.implementationSpPerHour ?? base.implementationSpPerHour;
51
+ base.reviewSpPerHour = this.globalVelocity.reviewSpPerHour ?? base.reviewSpPerHour;
52
+ base.qaSpPerHour = this.globalVelocity.qaSpPerHour ?? base.qaSpPerHour;
53
+ base.alpha = this.globalVelocity.alpha ?? base.alpha;
54
+ }
55
+ // Workspace config overrides global
56
+ if (this.workspace.config?.velocity) {
57
+ base.implementationSpPerHour =
58
+ this.workspace.config.velocity.implementationSpPerHour ?? base.implementationSpPerHour;
59
+ base.reviewSpPerHour = this.workspace.config.velocity.reviewSpPerHour ?? base.reviewSpPerHour;
60
+ base.qaSpPerHour = this.workspace.config.velocity.qaSpPerHour ?? base.qaSpPerHour;
61
+ base.alpha = this.workspace.config.velocity.alpha ?? base.alpha;
62
+ }
63
+ if (options.spPerHourAll !== undefined) {
64
+ base.implementationSpPerHour = options.spPerHourAll;
65
+ base.reviewSpPerHour = options.spPerHourAll;
66
+ base.qaSpPerHour = options.spPerHourAll;
67
+ }
68
+ if (options.spPerHourReview !== undefined) {
69
+ base.reviewSpPerHour = options.spPerHourReview;
70
+ }
71
+ if (options.spPerHourQa !== undefined) {
72
+ base.qaSpPerHour = options.spPerHourQa;
73
+ }
74
+ return base;
75
+ }
76
+ async resolveScopeIds(options) {
77
+ const scope = {};
78
+ if (options.projectKey) {
79
+ const row = await this.db.get(`SELECT id FROM projects WHERE key = ?`, options.projectKey);
80
+ if (!row) {
81
+ throw new Error(`Unknown project key: ${options.projectKey}`);
82
+ }
83
+ scope.projectId = row.id;
84
+ }
85
+ if (options.epicKey) {
86
+ const row = await this.db.get(`SELECT id FROM epics WHERE key = ? ${scope.projectId ? "AND project_id = ?" : ""}`, scope.projectId ? [options.epicKey, scope.projectId] : [options.epicKey]);
87
+ if (!row) {
88
+ throw new Error(`Unknown epic key: ${options.epicKey}`);
89
+ }
90
+ scope.epicId = row.id;
91
+ }
92
+ if (options.storyKey) {
93
+ const row = await this.db.get(`SELECT id FROM user_stories WHERE key = ? ${scope.epicId ? "AND epic_id = ?" : ""}`, scope.epicId ? [options.storyKey, scope.epicId] : [options.storyKey]);
94
+ if (!row) {
95
+ throw new Error(`Unknown user story key: ${options.storyKey}`);
96
+ }
97
+ scope.storyId = row.id;
98
+ }
99
+ return scope;
100
+ }
101
+ buildTaskFilters(scope, assignee) {
102
+ const clauses = [];
103
+ const params = [];
104
+ if (scope.projectId) {
105
+ clauses.push("t.project_id = ?");
106
+ params.push(scope.projectId);
107
+ }
108
+ if (scope.epicId) {
109
+ clauses.push("t.epic_id = ?");
110
+ params.push(scope.epicId);
111
+ }
112
+ if (scope.storyId) {
113
+ clauses.push("t.user_story_id = ?");
114
+ params.push(scope.storyId);
115
+ }
116
+ if (assignee) {
117
+ clauses.push("LOWER(t.assignee_human) = LOWER(?)");
118
+ params.push(assignee);
119
+ }
120
+ if (clauses.length === 0)
121
+ return { clause: "", params: [] };
122
+ return { clause: `AND ${clauses.join(" AND ")}`, params };
123
+ }
124
+ async computeLaneVelocity(commandName, scope, assignee, windowTasks) {
125
+ const runs = await this.db.all(`
126
+ SELECT id, started_at, completed_at, duration_seconds
127
+ FROM command_runs
128
+ WHERE command_name = ?
129
+ AND status IN ('success','succeeded')
130
+ ORDER BY COALESCE(completed_at, started_at) DESC
131
+ `, commandName);
132
+ let totalSp = 0;
133
+ let totalDurationSeconds = 0;
134
+ let samples = 0;
135
+ const filters = this.buildTaskFilters(scope, assignee);
136
+ for (const run of runs) {
137
+ const aggregation = await this.db.get(`
138
+ SELECT
139
+ SUM(COALESCE(t.story_points, 0)) as sp,
140
+ COUNT(*) as tasks
141
+ FROM task_runs tr
142
+ INNER JOIN tasks t ON t.id = tr.task_id
143
+ WHERE tr.command_run_id = ?
144
+ ${filters.clause}
145
+ `, run.id, ...filters.params);
146
+ const taskCount = aggregation?.tasks ?? 0;
147
+ const sp = aggregation?.sp ?? 0;
148
+ if (taskCount === 0) {
149
+ continue;
150
+ }
151
+ const durationSeconds = typeof run.duration_seconds === "number" && Number.isFinite(run.duration_seconds)
152
+ ? run.duration_seconds
153
+ : this.deriveDurationSeconds(run.started_at, run.completed_at);
154
+ if (!durationSeconds || durationSeconds <= 0) {
155
+ continue;
156
+ }
157
+ totalSp += sp;
158
+ totalDurationSeconds += durationSeconds;
159
+ samples += taskCount;
160
+ if (samples >= windowTasks)
161
+ break;
162
+ }
163
+ if (samples === 0 || totalDurationSeconds <= 0 || totalSp <= 0) {
164
+ return { samples: 0 };
165
+ }
166
+ return {
167
+ spPerHour: totalSp / (totalDurationSeconds / 3600),
168
+ samples,
169
+ };
170
+ }
171
+ deriveDurationSeconds(started, completed) {
172
+ if (!started || !completed)
173
+ return undefined;
174
+ const startMs = Date.parse(started);
175
+ const endMs = Date.parse(completed);
176
+ if (Number.isNaN(startMs) || Number.isNaN(endMs) || endMs <= startMs)
177
+ return undefined;
178
+ return (endMs - startMs) / 1000;
179
+ }
180
+ async getEffectiveVelocity(options = {}) {
181
+ const mode = options.mode ?? "config";
182
+ const windowTasks = options.windowTasks ?? 10;
183
+ const config = this.resolveConfig(options);
184
+ if (mode === "config") {
185
+ return {
186
+ implementationSpPerHour: config.implementationSpPerHour,
187
+ reviewSpPerHour: config.reviewSpPerHour,
188
+ qaSpPerHour: config.qaSpPerHour,
189
+ source: "config",
190
+ };
191
+ }
192
+ const scope = await this.resolveScopeIds(options);
193
+ const implementation = await this.computeLaneVelocity("work-on-tasks", scope, options.assignee, windowTasks);
194
+ const review = await this.computeLaneVelocity("code-review", scope, options.assignee, windowTasks);
195
+ const qa = await this.computeLaneVelocity("qa-tasks", scope, options.assignee, windowTasks);
196
+ const alpha = config.alpha ?? DEFAULT_ALPHA;
197
+ const resolveLane = (empirical) => {
198
+ if (empirical === undefined || empirical <= 0)
199
+ return config.implementationSpPerHour;
200
+ if (mode === "empirical")
201
+ return empirical;
202
+ return alpha * empirical + (1 - alpha) * config.implementationSpPerHour;
203
+ };
204
+ const resolveReviewLane = (empirical) => {
205
+ if (empirical === undefined || empirical <= 0)
206
+ return config.reviewSpPerHour;
207
+ if (mode === "empirical")
208
+ return empirical;
209
+ return alpha * empirical + (1 - alpha) * config.reviewSpPerHour;
210
+ };
211
+ const resolveQaLane = (empirical) => {
212
+ if (empirical === undefined || empirical <= 0)
213
+ return config.qaSpPerHour;
214
+ if (mode === "empirical")
215
+ return empirical;
216
+ return alpha * empirical + (1 - alpha) * config.qaSpPerHour;
217
+ };
218
+ const implementationSpPerHour = resolveLane(implementation.spPerHour);
219
+ const reviewSpPerHour = resolveReviewLane(review.spPerHour);
220
+ const qaSpPerHour = resolveQaLane(qa.spPerHour);
221
+ const usedEmpirical = (implementation.spPerHour && implementation.spPerHour > 0) ||
222
+ (review.spPerHour && review.spPerHour > 0) ||
223
+ (qa.spPerHour && qa.spPerHour > 0);
224
+ return {
225
+ implementationSpPerHour,
226
+ reviewSpPerHour,
227
+ qaSpPerHour,
228
+ source: usedEmpirical ? mode : "config",
229
+ windowTasks,
230
+ samples: {
231
+ implementation: implementation.samples,
232
+ review: review.samples,
233
+ qa: qa.samples,
234
+ },
235
+ };
236
+ }
237
+ }
@@ -0,0 +1,30 @@
1
+ import type { EffectiveVelocity, EstimateResult, EstimateDurations, EstimateEtas, VelocitySource } from "@mcoda/shared";
2
+ import type { WorkspaceResolution } from "../../workspace/WorkspaceManager.js";
3
+ export interface VelocityConfig {
4
+ implementationSpPerHour: number;
5
+ reviewSpPerHour: number;
6
+ qaSpPerHour: number;
7
+ alpha?: number;
8
+ }
9
+ export interface VelocityOptions {
10
+ projectKey?: string;
11
+ epicKey?: string;
12
+ storyKey?: string;
13
+ assignee?: string;
14
+ mode?: VelocitySource;
15
+ windowTasks?: 10 | 20 | 50;
16
+ spPerHourAll?: number;
17
+ spPerHourReview?: number;
18
+ spPerHourQa?: number;
19
+ }
20
+ export interface VelocityScopeIds {
21
+ projectId?: string;
22
+ epicId?: string;
23
+ storyId?: string;
24
+ }
25
+ export interface EstimateOptions extends VelocityOptions {
26
+ workspace: WorkspaceResolution;
27
+ }
28
+ export type { EstimateDurations, EstimateEtas };
29
+ export type { EffectiveVelocity, EstimateResult, VelocitySource };
30
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/services/estimate/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,cAAc,EACf,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAE/E,MAAM,WAAW,cAAc;IAC7B,uBAAuB,EAAE,MAAM,CAAC;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,WAAW,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACtD,SAAS,EAAE,mBAAmB,CAAC;CAChC;AAED,YAAY,EAAE,iBAAiB,EAAE,YAAY,EAAE,CAAC;AAChD,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ export declare class ExecutionService {
2
+ }
3
+ //# sourceMappingURL=ExecutionService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExecutionService.d.ts","sourceRoot":"","sources":["../../../src/services/execution/ExecutionService.ts"],"names":[],"mappings":"AAAA,qBAAa,gBAAgB;CAAG"}
@@ -0,0 +1,2 @@
1
+ export class ExecutionService {
2
+ }
@@ -0,0 +1,38 @@
1
+ import { TaskCommentInsert, TaskDependencyInsert, TaskInsert, TaskRow, WorkspaceRepository } from '@mcoda/db';
2
+ export interface FollowupSuggestion {
3
+ title: string;
4
+ description?: string;
5
+ type?: string;
6
+ priority?: number;
7
+ storyPoints?: number;
8
+ tags?: string[];
9
+ epicKeyHint?: string;
10
+ storyKeyHint?: string;
11
+ relatedTaskKey?: string;
12
+ components?: string[];
13
+ docLinks?: string[];
14
+ testName?: string;
15
+ evidenceUrl?: string;
16
+ artifacts?: string[];
17
+ }
18
+ export declare class QaFollowupService {
19
+ private workspaceRepo;
20
+ private workspaceRoot;
21
+ constructor(workspaceRepo: WorkspaceRepository, workspaceRoot: string);
22
+ private get cachePath();
23
+ private readCache;
24
+ private writeCache;
25
+ private ensureBugContainer;
26
+ createFollowupTask(sourceTask: TaskRow & {
27
+ storyKey?: string;
28
+ epicKey?: string;
29
+ }, suggestion: FollowupSuggestion): Promise<{
30
+ task: TaskInsert & {
31
+ id: string;
32
+ };
33
+ dependency?: TaskDependencyInsert;
34
+ comment?: TaskCommentInsert;
35
+ }>;
36
+ private resolveTargetContainer;
37
+ }
38
+ //# sourceMappingURL=QaFollowupService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QaFollowupService.d.ts","sourceRoot":"","sources":["../../../src/services/execution/QaFollowupService.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,iBAAiB,EACjB,oBAAoB,EACpB,UAAU,EACV,OAAO,EACP,mBAAmB,EACpB,MAAM,WAAW,CAAC;AAMnB,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAgCD,qBAAa,iBAAiB;IAChB,OAAO,CAAC,aAAa;IAAuB,OAAO,CAAC,aAAa;gBAAzD,aAAa,EAAE,mBAAmB,EAAU,aAAa,EAAE,MAAM;IAErF,OAAO,KAAK,SAAS,GAEpB;YAEa,SAAS;YAST,UAAU;YAKV,kBAAkB;IA+C1B,kBAAkB,CACtB,UAAU,EAAE,OAAO,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,EAC7D,UAAU,EAAE,kBAAkB,GAC7B,OAAO,CAAC;QAAE,IAAI,EAAE,UAAU,GAAG;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,UAAU,CAAC,EAAE,oBAAoB,CAAC;QAAC,OAAO,CAAC,EAAE,iBAAiB,CAAA;KAAE,CAAC;YA6EnG,sBAAsB;CA+ErC"}