@mcoda/core 0.1.8 → 0.1.11

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 (216) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/README.md +2 -2
  3. package/dist/api/AgentsApi.d.ts +9 -1
  4. package/dist/api/AgentsApi.d.ts.map +1 -1
  5. package/dist/api/AgentsApi.js +201 -6
  6. package/dist/api/QaTasksApi.d.ts.map +1 -1
  7. package/dist/api/QaTasksApi.js +6 -0
  8. package/dist/api/TasksApi.d.ts.map +1 -1
  9. package/dist/api/TasksApi.js +1 -0
  10. package/dist/index.d.ts +4 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +4 -0
  13. package/dist/prompts/PdrPrompts.d.ts.map +1 -1
  14. package/dist/prompts/PdrPrompts.js +9 -1
  15. package/dist/prompts/SdsPrompts.d.ts.map +1 -1
  16. package/dist/prompts/SdsPrompts.js +9 -0
  17. package/dist/services/agents/AgentRatingFormula.d.ts +27 -0
  18. package/dist/services/agents/AgentRatingFormula.d.ts.map +1 -0
  19. package/dist/services/agents/AgentRatingFormula.js +45 -0
  20. package/dist/services/agents/AgentRatingService.d.ts +60 -0
  21. package/dist/services/agents/AgentRatingService.d.ts.map +1 -0
  22. package/dist/services/agents/AgentRatingService.js +363 -0
  23. package/dist/services/agents/GatewayAgentService.d.ts +11 -0
  24. package/dist/services/agents/GatewayAgentService.d.ts.map +1 -1
  25. package/dist/services/agents/GatewayAgentService.js +525 -84
  26. package/dist/services/agents/GatewayHandoff.d.ts +11 -0
  27. package/dist/services/agents/GatewayHandoff.d.ts.map +1 -0
  28. package/dist/services/agents/GatewayHandoff.js +141 -0
  29. package/dist/services/agents/RoutingService.d.ts +1 -0
  30. package/dist/services/agents/RoutingService.d.ts.map +1 -1
  31. package/dist/services/agents/RoutingService.js +4 -4
  32. package/dist/services/backlog/BacklogService.d.ts +23 -0
  33. package/dist/services/backlog/BacklogService.d.ts.map +1 -1
  34. package/dist/services/backlog/BacklogService.js +62 -7
  35. package/dist/services/backlog/TaskOrderingHeuristics.d.ts +12 -0
  36. package/dist/services/backlog/TaskOrderingHeuristics.d.ts.map +1 -0
  37. package/dist/services/backlog/TaskOrderingHeuristics.js +56 -0
  38. package/dist/services/backlog/TaskOrderingService.d.ts +17 -4
  39. package/dist/services/backlog/TaskOrderingService.d.ts.map +1 -1
  40. package/dist/services/backlog/TaskOrderingService.js +538 -79
  41. package/dist/services/docs/DocInventory.d.ts +11 -0
  42. package/dist/services/docs/DocInventory.d.ts.map +1 -0
  43. package/dist/services/docs/DocInventory.js +230 -0
  44. package/dist/services/docs/DocgenRunContext.d.ts +59 -0
  45. package/dist/services/docs/DocgenRunContext.d.ts.map +1 -0
  46. package/dist/services/docs/DocgenRunContext.js +4 -0
  47. package/dist/services/docs/DocsService.d.ts +70 -3
  48. package/dist/services/docs/DocsService.d.ts.map +1 -1
  49. package/dist/services/docs/DocsService.js +1930 -89
  50. package/dist/services/docs/alignment/DocAlignmentGraph.d.ts +23 -0
  51. package/dist/services/docs/alignment/DocAlignmentGraph.d.ts.map +1 -0
  52. package/dist/services/docs/alignment/DocAlignmentGraph.js +78 -0
  53. package/dist/services/docs/alignment/DocAlignmentPatcher.d.ts +19 -0
  54. package/dist/services/docs/alignment/DocAlignmentPatcher.d.ts.map +1 -0
  55. package/dist/services/docs/alignment/DocAlignmentPatcher.js +222 -0
  56. package/dist/services/docs/patch/DocPatchEngine.d.ts +57 -0
  57. package/dist/services/docs/patch/DocPatchEngine.d.ts.map +1 -0
  58. package/dist/services/docs/patch/DocPatchEngine.js +331 -0
  59. package/dist/services/docs/review/Glossary.d.ts +16 -0
  60. package/dist/services/docs/review/Glossary.d.ts.map +1 -0
  61. package/dist/services/docs/review/Glossary.js +47 -0
  62. package/dist/services/docs/review/ReviewReportRenderer.d.ts +3 -0
  63. package/dist/services/docs/review/ReviewReportRenderer.d.ts.map +1 -0
  64. package/dist/services/docs/review/ReviewReportRenderer.js +133 -0
  65. package/dist/services/docs/review/ReviewReportSchema.d.ts +39 -0
  66. package/dist/services/docs/review/ReviewReportSchema.d.ts.map +1 -0
  67. package/dist/services/docs/review/ReviewReportSchema.js +47 -0
  68. package/dist/services/docs/review/ReviewTypes.d.ts +76 -0
  69. package/dist/services/docs/review/ReviewTypes.d.ts.map +1 -0
  70. package/dist/services/docs/review/ReviewTypes.js +94 -0
  71. package/dist/services/docs/review/gates/AdminOpenApiSpecGate.d.ts +7 -0
  72. package/dist/services/docs/review/gates/AdminOpenApiSpecGate.d.ts.map +1 -0
  73. package/dist/services/docs/review/gates/AdminOpenApiSpecGate.js +93 -0
  74. package/dist/services/docs/review/gates/ApiPathConsistencyGate.d.ts +7 -0
  75. package/dist/services/docs/review/gates/ApiPathConsistencyGate.d.ts.map +1 -0
  76. package/dist/services/docs/review/gates/ApiPathConsistencyGate.js +308 -0
  77. package/dist/services/docs/review/gates/BuildReadyCompletenessGate.d.ts +8 -0
  78. package/dist/services/docs/review/gates/BuildReadyCompletenessGate.d.ts.map +1 -0
  79. package/dist/services/docs/review/gates/BuildReadyCompletenessGate.js +278 -0
  80. package/dist/services/docs/review/gates/DeploymentBlueprintGate.d.ts +8 -0
  81. package/dist/services/docs/review/gates/DeploymentBlueprintGate.d.ts.map +1 -0
  82. package/dist/services/docs/review/gates/DeploymentBlueprintGate.js +487 -0
  83. package/dist/services/docs/review/gates/NoMaybesGate.d.ts +8 -0
  84. package/dist/services/docs/review/gates/NoMaybesGate.d.ts.map +1 -0
  85. package/dist/services/docs/review/gates/NoMaybesGate.js +145 -0
  86. package/dist/services/docs/review/gates/OpenApiCoverageGate.d.ts +7 -0
  87. package/dist/services/docs/review/gates/OpenApiCoverageGate.d.ts.map +1 -0
  88. package/dist/services/docs/review/gates/OpenApiCoverageGate.js +266 -0
  89. package/dist/services/docs/review/gates/OpenApiSchemaSanityGate.d.ts +7 -0
  90. package/dist/services/docs/review/gates/OpenApiSchemaSanityGate.d.ts.map +1 -0
  91. package/dist/services/docs/review/gates/OpenApiSchemaSanityGate.js +59 -0
  92. package/dist/services/docs/review/gates/OpenQuestionsGate.d.ts +7 -0
  93. package/dist/services/docs/review/gates/OpenQuestionsGate.d.ts.map +1 -0
  94. package/dist/services/docs/review/gates/OpenQuestionsGate.js +200 -0
  95. package/dist/services/docs/review/gates/PdrInterfacesGate.d.ts +7 -0
  96. package/dist/services/docs/review/gates/PdrInterfacesGate.d.ts.map +1 -0
  97. package/dist/services/docs/review/gates/PdrInterfacesGate.js +159 -0
  98. package/dist/services/docs/review/gates/PdrOpenQuestionsGate.d.ts +8 -0
  99. package/dist/services/docs/review/gates/PdrOpenQuestionsGate.d.ts.map +1 -0
  100. package/dist/services/docs/review/gates/PdrOpenQuestionsGate.js +129 -0
  101. package/dist/services/docs/review/gates/PdrOwnershipGate.d.ts +7 -0
  102. package/dist/services/docs/review/gates/PdrOwnershipGate.d.ts.map +1 -0
  103. package/dist/services/docs/review/gates/PdrOwnershipGate.js +169 -0
  104. package/dist/services/docs/review/gates/PlaceholderArtifactGate.d.ts +10 -0
  105. package/dist/services/docs/review/gates/PlaceholderArtifactGate.d.ts.map +1 -0
  106. package/dist/services/docs/review/gates/PlaceholderArtifactGate.js +261 -0
  107. package/dist/services/docs/review/gates/RfpConsentGate.d.ts +6 -0
  108. package/dist/services/docs/review/gates/RfpConsentGate.d.ts.map +1 -0
  109. package/dist/services/docs/review/gates/RfpConsentGate.js +127 -0
  110. package/dist/services/docs/review/gates/RfpDefinitionGate.d.ts +7 -0
  111. package/dist/services/docs/review/gates/RfpDefinitionGate.d.ts.map +1 -0
  112. package/dist/services/docs/review/gates/RfpDefinitionGate.js +173 -0
  113. package/dist/services/docs/review/gates/SdsAdaptersGate.d.ts +7 -0
  114. package/dist/services/docs/review/gates/SdsAdaptersGate.d.ts.map +1 -0
  115. package/dist/services/docs/review/gates/SdsAdaptersGate.js +196 -0
  116. package/dist/services/docs/review/gates/SdsDecisionsGate.d.ts +7 -0
  117. package/dist/services/docs/review/gates/SdsDecisionsGate.d.ts.map +1 -0
  118. package/dist/services/docs/review/gates/SdsDecisionsGate.js +89 -0
  119. package/dist/services/docs/review/gates/SdsOpsGate.d.ts +7 -0
  120. package/dist/services/docs/review/gates/SdsOpsGate.d.ts.map +1 -0
  121. package/dist/services/docs/review/gates/SdsOpsGate.js +162 -0
  122. package/dist/services/docs/review/gates/SdsPolicyTelemetryGate.d.ts +7 -0
  123. package/dist/services/docs/review/gates/SdsPolicyTelemetryGate.d.ts.map +1 -0
  124. package/dist/services/docs/review/gates/SdsPolicyTelemetryGate.js +166 -0
  125. package/dist/services/docs/review/gates/SqlRequiredTablesGate.d.ts +7 -0
  126. package/dist/services/docs/review/gates/SqlRequiredTablesGate.d.ts.map +1 -0
  127. package/dist/services/docs/review/gates/SqlRequiredTablesGate.js +273 -0
  128. package/dist/services/docs/review/gates/SqlSyntaxGate.d.ts +7 -0
  129. package/dist/services/docs/review/gates/SqlSyntaxGate.d.ts.map +1 -0
  130. package/dist/services/docs/review/gates/SqlSyntaxGate.js +203 -0
  131. package/dist/services/docs/review/gates/TerminologyNormalizationGate.d.ts +9 -0
  132. package/dist/services/docs/review/gates/TerminologyNormalizationGate.d.ts.map +1 -0
  133. package/dist/services/docs/review/gates/TerminologyNormalizationGate.js +217 -0
  134. package/dist/services/docs/review/glossary.json +47 -0
  135. package/dist/services/estimate/EstimateService.d.ts +2 -0
  136. package/dist/services/estimate/EstimateService.d.ts.map +1 -1
  137. package/dist/services/estimate/EstimateService.js +66 -18
  138. package/dist/services/estimate/VelocityService.d.ts +4 -0
  139. package/dist/services/estimate/VelocityService.d.ts.map +1 -1
  140. package/dist/services/estimate/VelocityService.js +179 -36
  141. package/dist/services/estimate/types.d.ts +1 -0
  142. package/dist/services/estimate/types.d.ts.map +1 -1
  143. package/dist/services/execution/GatewayTrioService.d.ts +200 -0
  144. package/dist/services/execution/GatewayTrioService.d.ts.map +1 -0
  145. package/dist/services/execution/GatewayTrioService.js +2492 -0
  146. package/dist/services/execution/QaApiRunner.d.ts +30 -0
  147. package/dist/services/execution/QaApiRunner.d.ts.map +1 -0
  148. package/dist/services/execution/QaApiRunner.js +881 -0
  149. package/dist/services/execution/QaFollowupService.d.ts +2 -0
  150. package/dist/services/execution/QaFollowupService.d.ts.map +1 -1
  151. package/dist/services/execution/QaFollowupService.js +9 -2
  152. package/dist/services/execution/QaPlanValidator.d.ts +10 -0
  153. package/dist/services/execution/QaPlanValidator.d.ts.map +1 -0
  154. package/dist/services/execution/QaPlanValidator.js +128 -0
  155. package/dist/services/execution/QaProfileService.d.ts +27 -1
  156. package/dist/services/execution/QaProfileService.d.ts.map +1 -1
  157. package/dist/services/execution/QaProfileService.js +354 -7
  158. package/dist/services/execution/QaTasksService.d.ts +59 -1
  159. package/dist/services/execution/QaTasksService.d.ts.map +1 -1
  160. package/dist/services/execution/QaTasksService.js +3347 -318
  161. package/dist/services/execution/QaTestCommandBuilder.d.ts +51 -0
  162. package/dist/services/execution/QaTestCommandBuilder.d.ts.map +1 -0
  163. package/dist/services/execution/QaTestCommandBuilder.js +495 -0
  164. package/dist/services/execution/TaskSelectionService.d.ts +4 -2
  165. package/dist/services/execution/TaskSelectionService.d.ts.map +1 -1
  166. package/dist/services/execution/TaskSelectionService.js +144 -28
  167. package/dist/services/execution/TaskStateService.d.ts +19 -6
  168. package/dist/services/execution/TaskStateService.d.ts.map +1 -1
  169. package/dist/services/execution/TaskStateService.js +128 -13
  170. package/dist/services/execution/WorkOnTasksService.d.ts +32 -1
  171. package/dist/services/execution/WorkOnTasksService.d.ts.map +1 -1
  172. package/dist/services/execution/WorkOnTasksService.js +4667 -722
  173. package/dist/services/jobs/JobInsightsService.d.ts +4 -0
  174. package/dist/services/jobs/JobInsightsService.d.ts.map +1 -1
  175. package/dist/services/jobs/JobInsightsService.js +51 -5
  176. package/dist/services/jobs/JobResumeService.d.ts.map +1 -1
  177. package/dist/services/jobs/JobResumeService.js +23 -10
  178. package/dist/services/jobs/JobService.d.ts +56 -4
  179. package/dist/services/jobs/JobService.d.ts.map +1 -1
  180. package/dist/services/jobs/JobService.js +232 -1
  181. package/dist/services/openapi/OpenApiService.d.ts +51 -0
  182. package/dist/services/openapi/OpenApiService.d.ts.map +1 -1
  183. package/dist/services/openapi/OpenApiService.js +953 -106
  184. package/dist/services/planning/CreateTasksService.d.ts +21 -0
  185. package/dist/services/planning/CreateTasksService.d.ts.map +1 -1
  186. package/dist/services/planning/CreateTasksService.js +569 -31
  187. package/dist/services/planning/RefineTasksService.d.ts +9 -0
  188. package/dist/services/planning/RefineTasksService.d.ts.map +1 -1
  189. package/dist/services/planning/RefineTasksService.js +409 -59
  190. package/dist/services/review/CodeReviewService.d.ts +18 -0
  191. package/dist/services/review/CodeReviewService.d.ts.map +1 -1
  192. package/dist/services/review/CodeReviewService.js +1309 -167
  193. package/dist/services/review/ReviewNormalizer.d.ts +9 -0
  194. package/dist/services/review/ReviewNormalizer.d.ts.map +1 -0
  195. package/dist/services/review/ReviewNormalizer.js +147 -0
  196. package/dist/services/shared/AuthErrors.d.ts +3 -0
  197. package/dist/services/shared/AuthErrors.d.ts.map +1 -0
  198. package/dist/services/shared/AuthErrors.js +17 -0
  199. package/dist/services/shared/DocdexGuidance.d.ts +7 -0
  200. package/dist/services/shared/DocdexGuidance.d.ts.map +1 -0
  201. package/dist/services/shared/DocdexGuidance.js +12 -0
  202. package/dist/services/shared/ProjectGuidance.d.ts +17 -0
  203. package/dist/services/shared/ProjectGuidance.d.ts.map +1 -0
  204. package/dist/services/shared/ProjectGuidance.js +78 -0
  205. package/dist/services/system/ToolDenylist.d.ts +13 -0
  206. package/dist/services/system/ToolDenylist.d.ts.map +1 -0
  207. package/dist/services/system/ToolDenylist.js +85 -0
  208. package/dist/services/tasks/TaskCommentFormatter.d.ts +20 -0
  209. package/dist/services/tasks/TaskCommentFormatter.d.ts.map +1 -0
  210. package/dist/services/tasks/TaskCommentFormatter.js +54 -0
  211. package/dist/services/telemetry/TelemetryService.d.ts.map +1 -1
  212. package/dist/services/telemetry/TelemetryService.js +39 -7
  213. package/dist/workspace/WorkspaceManager.d.ts +26 -0
  214. package/dist/workspace/WorkspaceManager.d.ts.map +1 -1
  215. package/dist/workspace/WorkspaceManager.js +206 -32
  216. package/package.json +6 -5
@@ -4,7 +4,41 @@ import { promises as fs } from "node:fs";
4
4
  import { PathHelper } from "@mcoda/shared";
5
5
  import { WorkspaceRepository, } from "@mcoda/db";
6
6
  const nowIso = () => new Date().toISOString();
7
+ const TERMINAL_JOB_STATES = new Set(["completed", "failed", "cancelled", "partial"]);
7
8
  export class JobService {
9
+ static ensureSignalHandlers() {
10
+ if (JobService.signalHandlersRegistered)
11
+ return;
12
+ if (process.env.MCODA_DISABLE_JOB_SIGNAL_HANDLERS === "1")
13
+ return;
14
+ JobService.signalHandlersRegistered = true;
15
+ const handler = (signal) => {
16
+ void JobService.handleProcessSignal(signal);
17
+ };
18
+ process.once("SIGINT", handler);
19
+ process.once("SIGTERM", handler);
20
+ process.once("SIGTSTP", handler);
21
+ }
22
+ static registerActiveJob(jobId, service, commandRunId) {
23
+ JobService.activeJobs.set(jobId, { service, commandRunId });
24
+ JobService.ensureSignalHandlers();
25
+ }
26
+ static unregisterActiveJob(jobId) {
27
+ JobService.activeJobs.delete(jobId);
28
+ }
29
+ static async cancelActiveJobs(signal) {
30
+ const active = Array.from(JobService.activeJobs.entries());
31
+ await Promise.all(active.map(async ([jobId, entry]) => entry.service.cancelJobOnSignal(jobId, entry.commandRunId, signal)));
32
+ }
33
+ static async handleProcessSignal(signal) {
34
+ if (JobService.handlingSignal)
35
+ return;
36
+ JobService.handlingSignal = true;
37
+ await JobService.cancelActiveJobs(signal);
38
+ const exitCode = signal === "SIGTERM" ? 143 : 130;
39
+ process.exitCode = exitCode;
40
+ process.exit(exitCode);
41
+ }
8
42
  constructor(workspace, workspaceRepo, options = {}) {
9
43
  this.workspaceRepo = workspaceRepo;
10
44
  this.checkpointCounters = new Map();
@@ -14,12 +48,13 @@ export class JobService {
14
48
  const resolvedRoot = typeof workspace === "string" ? workspace : workspace.workspaceRoot;
15
49
  this.workspaceRoot = resolvedRoot;
16
50
  this.workspaceId = typeof workspace === "string" ? resolvedRoot : workspace.workspaceId ?? resolvedRoot;
51
+ this.mcodaDirOverride = typeof workspace === "string" ? undefined : workspace.mcodaDir;
17
52
  this.perRunTelemetryDisabled = options.noTelemetry ?? false;
18
53
  this.envTelemetryDisabled = (process.env.MCODA_TELEMETRY ?? "").toLowerCase() === "off";
19
54
  this.requireRepo = options.requireRepo ?? false;
20
55
  }
21
56
  get mcodaDir() {
22
- return path.join(this.workspaceRoot, ".mcoda");
57
+ return this.mcodaDirOverride ?? PathHelper.getWorkspaceDir(this.workspaceRoot);
23
58
  }
24
59
  get commandRunsPath() {
25
60
  return path.join(this.mcodaDir, "command_runs.json");
@@ -67,6 +102,37 @@ export class JobService {
67
102
  this.workspaceRepo = undefined;
68
103
  }
69
104
  }
105
+ async cancelJobOnSignal(jobId, commandRunId, signal) {
106
+ const reason = `Cancelled by ${signal}`;
107
+ try {
108
+ await this.ensureMcoda();
109
+ }
110
+ catch {
111
+ // ignore workspace bootstrap failures during shutdown
112
+ }
113
+ if (this.workspaceRepo && "releaseTaskLocksByJob" in this.workspaceRepo) {
114
+ try {
115
+ await this.workspaceRepo.releaseTaskLocksByJob(jobId);
116
+ }
117
+ catch {
118
+ // ignore lock cleanup failures during shutdown
119
+ }
120
+ }
121
+ try {
122
+ await this.updateJobStatus(jobId, "cancelled", { errorSummary: reason });
123
+ }
124
+ catch {
125
+ // ignore job status failures during shutdown
126
+ }
127
+ if (commandRunId) {
128
+ try {
129
+ await this.finishCommandRun(commandRunId, "cancelled", reason);
130
+ }
131
+ catch {
132
+ // ignore command run failures during shutdown
133
+ }
134
+ }
135
+ }
70
136
  async readJsonArray(filePath) {
71
137
  try {
72
138
  const raw = await fs.readFile(filePath, "utf8");
@@ -104,6 +170,16 @@ export class JobService {
104
170
  const jobs = await this.readJsonArray(this.jobsStorePath);
105
171
  return jobs.find((j) => j.id === jobId);
106
172
  }
173
+ async readManifest(jobId) {
174
+ const manifestPath = this.manifestPath(jobId);
175
+ try {
176
+ const raw = await fs.readFile(manifestPath, "utf8");
177
+ return JSON.parse(raw);
178
+ }
179
+ catch {
180
+ return undefined;
181
+ }
182
+ }
107
183
  async readCheckpoints(jobId) {
108
184
  const dir = this.checkpointDir(jobId);
109
185
  try {
@@ -207,6 +283,7 @@ export class JobService {
207
283
  workspaceId: this.workspaceId,
208
284
  projectKey,
209
285
  jobId: options?.jobId,
286
+ agentId: options?.agentId,
210
287
  taskIds: options?.taskIds,
211
288
  gitBranch: options?.gitBranch,
212
289
  gitBaseBranch: options?.gitBaseBranch,
@@ -219,6 +296,7 @@ export class JobService {
219
296
  workspaceId: this.workspaceId,
220
297
  commandName,
221
298
  jobId: record.jobId,
299
+ agentId: record.agentId ?? null,
222
300
  taskIds: record.taskIds,
223
301
  gitBranch: record.gitBranch,
224
302
  gitBaseBranch: record.gitBaseBranch,
@@ -261,6 +339,8 @@ export class JobService {
261
339
  workspaceId: this.workspaceId,
262
340
  projectKey,
263
341
  payload: options.payload,
342
+ agentId: options.agentId,
343
+ agentIds: options.agentIds ?? (options.agentId ? [options.agentId] : undefined),
264
344
  totalItems: options.totalItems,
265
345
  processedItems: options.processedItems,
266
346
  totalUnits: options.totalItems,
@@ -275,6 +355,8 @@ export class JobService {
275
355
  state: "running",
276
356
  commandName: record.commandName,
277
357
  payload: options.payload,
358
+ agentId: record.agentId ?? null,
359
+ agentIds: record.agentIds ?? null,
278
360
  totalItems: record.totalItems,
279
361
  processedItems: record.processedItems,
280
362
  });
@@ -287,6 +369,7 @@ export class JobService {
287
369
  if (commandRunId) {
288
370
  await this.attachCommandRunToJob(commandRunId, record.id);
289
371
  }
372
+ JobService.registerActiveJob(record.id, this, commandRunId);
290
373
  return record;
291
374
  }
292
375
  async attachCommandRunToJob(commandRunId, jobId) {
@@ -348,6 +431,110 @@ export class JobService {
348
431
  payload: updated.payload,
349
432
  });
350
433
  }
434
+ if (state === "cancelled" && this.workspaceRepo && "releaseTaskLocksByJob" in this.workspaceRepo) {
435
+ try {
436
+ await this.workspaceRepo.releaseTaskLocksByJob(jobId);
437
+ }
438
+ catch {
439
+ // ignore lock cleanup failures during cancellation
440
+ }
441
+ }
442
+ if (TERMINAL_JOB_STATES.has(state)) {
443
+ JobService.unregisterActiveJob(jobId);
444
+ }
445
+ else if (state === "running") {
446
+ JobService.registerActiveJob(jobId, this, updated.commandRunId);
447
+ }
448
+ }
449
+ async computeElapsed(jobId) {
450
+ const job = await this.getJob(jobId);
451
+ if (!job?.createdAt)
452
+ return {};
453
+ const startedAt = Date.parse(job.createdAt);
454
+ if (Number.isNaN(startedAt))
455
+ return {};
456
+ const elapsedMs = Math.max(0, Date.now() - startedAt);
457
+ return { elapsedMs, elapsedSeconds: Math.round(elapsedMs / 1000) };
458
+ }
459
+ async recordJobProgress(jobId, input) {
460
+ const elapsed = await this.computeElapsed(jobId);
461
+ const payload = {
462
+ docgen_stage: input.stage,
463
+ docgen_status_message: input.message,
464
+ };
465
+ if (elapsed.elapsedMs !== undefined) {
466
+ payload.docgen_elapsed_ms = elapsed.elapsedMs;
467
+ payload.docgen_elapsed_seconds = elapsed.elapsedSeconds;
468
+ }
469
+ if (input.iteration) {
470
+ payload.docgen_iteration_current = input.iteration.current;
471
+ payload.docgen_iteration_max = input.iteration.max;
472
+ if (input.iteration.phase) {
473
+ payload.docgen_iteration_phase = input.iteration.phase;
474
+ }
475
+ }
476
+ if (input.payload && Object.keys(input.payload).length > 0) {
477
+ Object.assign(payload, input.payload);
478
+ }
479
+ await this.updateJobStatus(jobId, "running", {
480
+ totalItems: input.totalItems,
481
+ processedItems: input.processedItems,
482
+ lastCheckpoint: input.stage,
483
+ jobStateDetail: input.message,
484
+ payload,
485
+ });
486
+ const checkpointDetails = { message: input.message };
487
+ if (elapsed.elapsedMs !== undefined) {
488
+ checkpointDetails.elapsedMs = elapsed.elapsedMs;
489
+ checkpointDetails.elapsedSeconds = elapsed.elapsedSeconds;
490
+ }
491
+ if (input.iteration) {
492
+ checkpointDetails.iteration = input.iteration;
493
+ }
494
+ if (input.details && Object.keys(input.details).length > 0) {
495
+ Object.assign(checkpointDetails, input.details);
496
+ }
497
+ await this.writeCheckpoint(jobId, {
498
+ stage: input.stage,
499
+ timestamp: nowIso(),
500
+ details: checkpointDetails,
501
+ });
502
+ if (input.heartbeat) {
503
+ const parts = [`[docgen heartbeat] ${input.message}`];
504
+ if (input.iteration) {
505
+ const phase = input.iteration.phase ? `:${input.iteration.phase}` : "";
506
+ parts.push(`iter=${input.iteration.current}/${input.iteration.max}${phase}`);
507
+ }
508
+ if (elapsed.elapsedSeconds !== undefined) {
509
+ parts.push(`elapsed=${elapsed.elapsedSeconds}s`);
510
+ }
511
+ await this.appendLog(jobId, `${parts.join(" ")}\n`);
512
+ }
513
+ }
514
+ async recordIterationProgress(jobId, input) {
515
+ const stage = `iteration_${input.current}_${input.phase}`;
516
+ const phaseLabel = input.phase === "recheck"
517
+ ? "Re-check"
518
+ : input.phase === "review"
519
+ ? "Review"
520
+ : input.phase === "patch"
521
+ ? "Patch"
522
+ : input.phase;
523
+ const payload = {
524
+ iteration: { current: input.current, max: input.max, phase: input.phase },
525
+ };
526
+ if (input.details && Object.keys(input.details).length > 0) {
527
+ payload.iterationDetails = input.details;
528
+ }
529
+ await this.recordJobProgress(jobId, {
530
+ stage,
531
+ message: `${phaseLabel} iteration ${input.current}/${input.max}`,
532
+ iteration: { current: input.current, max: input.max, phase: input.phase },
533
+ details: input.details,
534
+ totalItems: input.max,
535
+ processedItems: input.current,
536
+ payload,
537
+ });
351
538
  }
352
539
  async writeCheckpoint(jobId, checkpoint) {
353
540
  const dir = this.checkpointDir(jobId);
@@ -446,26 +633,67 @@ export class JobService {
446
633
  projectId: entry.projectId ?? null,
447
634
  epicId: entry.epicId ?? null,
448
635
  userStoryId: entry.userStoryId ?? null,
636
+ commandName: entry.commandName ?? null,
637
+ action: entry.action ?? null,
638
+ invocationKind: entry.invocationKind ?? null,
639
+ provider: entry.provider ?? null,
640
+ currency: entry.currency ?? null,
449
641
  tokensPrompt: entry.tokensPrompt ?? entry.promptTokens ?? null,
450
642
  tokensCompletion: entry.tokensCompletion ?? entry.completionTokens ?? null,
451
643
  tokensTotal: entry.tokensTotal ?? null,
644
+ tokensCached: entry.tokensCached ?? null,
645
+ tokensCacheRead: entry.tokensCacheRead ?? null,
646
+ tokensCacheWrite: entry.tokensCacheWrite ?? null,
452
647
  costEstimate: entry.costEstimate ?? entry.costUsd ?? null,
453
648
  durationSeconds: entry.durationSeconds ?? null,
649
+ durationMs: entry.durationMs ?? null,
650
+ startedAt: entry.startedAt ?? null,
651
+ finishedAt: entry.finishedAt ?? null,
454
652
  timestamp: entry.timestamp,
455
653
  metadata: {
456
654
  ...(entry.metadata ?? {}),
457
655
  ...(entry.commandName ? { commandName: entry.commandName } : {}),
458
656
  ...(entry.action ? { action: entry.action } : {}),
657
+ ...(entry.invocationKind ? { invocationKind: entry.invocationKind } : {}),
658
+ ...(entry.provider ? { provider: entry.provider } : {}),
659
+ ...(entry.currency ? { currency: entry.currency } : {}),
459
660
  },
460
661
  };
461
662
  const fileRecord = {
462
663
  ...normalized,
463
664
  ...(entry.commandName ? { commandName: entry.commandName } : {}),
464
665
  ...(entry.action ? { action: entry.action } : {}),
666
+ ...(entry.invocationKind ? { invocationKind: entry.invocationKind } : {}),
667
+ ...(entry.provider ? { provider: entry.provider } : {}),
668
+ ...(entry.currency ? { currency: entry.currency } : {}),
669
+ ...(entry.tokensCached !== undefined && entry.tokensCached !== null ? { tokensCached: entry.tokensCached } : {}),
670
+ ...(entry.tokensCacheRead !== undefined && entry.tokensCacheRead !== null ? { tokensCacheRead: entry.tokensCacheRead } : {}),
671
+ ...(entry.tokensCacheWrite !== undefined && entry.tokensCacheWrite !== null ? { tokensCacheWrite: entry.tokensCacheWrite } : {}),
672
+ ...(entry.durationMs !== undefined && entry.durationMs !== null ? { durationMs: entry.durationMs } : {}),
673
+ ...(entry.startedAt ? { startedAt: entry.startedAt } : {}),
674
+ ...(entry.finishedAt ? { finishedAt: entry.finishedAt } : {}),
465
675
  };
466
676
  await this.appendJsonArray(this.tokenUsagePath, fileRecord);
467
677
  if (this.workspaceRepo) {
468
678
  await this.workspaceRepo.recordTokenUsage(normalized);
679
+ if (entry.agentId) {
680
+ if (entry.commandRunId) {
681
+ try {
682
+ await this.workspaceRepo.setCommandRunAgentId(entry.commandRunId, entry.agentId);
683
+ }
684
+ catch {
685
+ // ignore attribution failures
686
+ }
687
+ }
688
+ if (entry.jobId) {
689
+ try {
690
+ await this.workspaceRepo.setJobAgentIds(entry.jobId, entry.agentId);
691
+ }
692
+ catch {
693
+ // ignore attribution failures
694
+ }
695
+ }
696
+ }
469
697
  }
470
698
  }
471
699
  async writeManifest(job, extras = {}) {
@@ -488,3 +716,6 @@ export class JobService {
488
716
  }
489
717
  }
490
718
  }
719
+ JobService.activeJobs = new Map();
720
+ JobService.signalHandlersRegistered = false;
721
+ JobService.handlingSignal = false;
@@ -1,38 +1,79 @@
1
1
  import { AgentService } from "@mcoda/agents";
2
2
  import { DocdexClient } from "@mcoda/integrations";
3
+ import { GlobalRepository, WorkspaceRepository } from "@mcoda/db";
3
4
  import { WorkspaceResolution } from "../../workspace/WorkspaceManager.js";
4
5
  import { JobService } from "../jobs/JobService.js";
5
6
  import { RoutingService } from "../agents/RoutingService.js";
7
+ import { AgentRatingService } from "../agents/AgentRatingService.js";
6
8
  export interface GenerateOpenapiOptions {
7
9
  workspace: WorkspaceResolution;
8
10
  agentName?: string;
9
11
  agentStream?: boolean;
12
+ rateAgents?: boolean;
10
13
  force?: boolean;
11
14
  dryRun?: boolean;
12
15
  validateOnly?: boolean;
13
16
  cliVersion: string;
14
17
  onToken?: (token: string) => void;
15
18
  projectKey?: string;
19
+ resumeJobId?: string;
20
+ timeoutMs?: number;
21
+ iteration?: {
22
+ current: number;
23
+ max?: number;
24
+ };
16
25
  }
17
26
  export interface GenerateOpenapiResult {
18
27
  jobId: string;
19
28
  commandRunId: string;
20
29
  outputPath?: string;
21
30
  spec: string;
31
+ adminOutputPath?: string;
32
+ adminSpec?: string;
22
33
  docdexId?: string;
34
+ adminDocdexId?: string;
23
35
  warnings: string[];
24
36
  }
37
+ export declare class OpenApiJobError extends Error {
38
+ code: string;
39
+ jobId?: string;
40
+ constructor(code: string, message: string, jobId?: string);
41
+ }
42
+ export declare const normalizeOpenApiPath: (value: string) => string;
43
+ export declare const extractOpenApiPaths: (raw: string) => {
44
+ paths: string[];
45
+ errors: string[];
46
+ };
47
+ export declare const findOpenApiPathLine: (raw: string, target: string) => number | undefined;
48
+ export interface AdminSurfaceMention {
49
+ line: number;
50
+ excerpt: string;
51
+ heading?: string;
52
+ }
53
+ export declare const findAdminSurfaceMentions: (raw: string) => AdminSurfaceMention[];
54
+ export interface OpenApiSchemaValidationResult {
55
+ doc?: any;
56
+ errors: string[];
57
+ }
58
+ export declare const validateOpenApiSchema: (doc: any) => string[];
59
+ export declare const validateOpenApiSchemaContent: (raw: string) => OpenApiSchemaValidationResult;
25
60
  export declare class OpenApiService {
26
61
  private docdex;
27
62
  private jobService;
28
63
  private agentService;
29
64
  private routingService;
30
65
  private workspace;
66
+ private repo?;
67
+ private ratingService?;
68
+ private workspaceRepo?;
31
69
  constructor(workspace: WorkspaceResolution, deps: {
32
70
  docdex?: DocdexClient;
33
71
  jobService?: JobService;
34
72
  agentService: AgentService;
35
73
  routingService: RoutingService;
74
+ repo?: GlobalRepository;
75
+ workspaceRepo?: WorkspaceRepository;
76
+ ratingService?: AgentRatingService;
36
77
  noTelemetry?: boolean;
37
78
  });
38
79
  static create(workspace: WorkspaceResolution, options?: {
@@ -40,6 +81,7 @@ export declare class OpenApiService {
40
81
  }): Promise<OpenApiService>;
41
82
  close(): Promise<void>;
42
83
  private resolveAgent;
84
+ private ensureRatingService;
43
85
  private invokeAgent;
44
86
  private sanitizeOutput;
45
87
  private validateSpec;
@@ -49,6 +91,15 @@ export declare class OpenApiService {
49
91
  private backupIfNeeded;
50
92
  private registerOpenapi;
51
93
  private validateExistingSpec;
94
+ private collectAdminMentions;
95
+ private openapiDraftPath;
96
+ private readOpenapiDraft;
97
+ private writeOpenapiDraft;
98
+ private isJobCancelled;
99
+ private updateOpenapiJobStatus;
100
+ private writeOpenapiCheckpoint;
101
+ private startOpenapiHeartbeat;
102
+ private tryResumeOpenapi;
52
103
  generateFromDocs(options: GenerateOpenapiOptions): Promise<GenerateOpenapiResult>;
53
104
  }
54
105
  //# sourceMappingURL=OpenApiService.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"OpenApiService.d.ts","sourceRoot":"","sources":["../../../src/services/openapi/OpenApiService.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAkB,MAAM,qBAAqB,CAAC;AAGnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,mBAAmB,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AA0MD,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,YAAY,CAAe;IACnC,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,SAAS,CAAsB;gBAGrC,SAAS,EAAE,mBAAmB,EAC9B,IAAI,EAAE;QAAE,MAAM,CAAC,EAAE,YAAY,CAAC;QAAC,UAAU,CAAC,EAAE,UAAU,CAAC;QAAC,YAAY,EAAE,YAAY,CAAC;QAAC,cAAc,EAAE,cAAc,CAAC;QAAC,WAAW,CAAC,EAAE,OAAO,CAAA;KAAE;WAShI,MAAM,CAAC,SAAS,EAAE,mBAAmB,EAAE,OAAO,GAAE;QAAE,WAAW,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,cAAc,CAAC;IAY/G,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAKd,YAAY;YASZ,WAAW;IA8BzB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,YAAY;YAaN,mBAAmB;IAajC,OAAO,CAAC,WAAW;YAwBL,gBAAgB;YAMhB,cAAc;YAOd,eAAe;YAef,oBAAoB;IAS5B,gBAAgB,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CA0JxF"}
1
+ {"version":3,"file":"OpenApiService.d.ts","sourceRoot":"","sources":["../../../src/services/openapi/OpenApiService.ts"],"names":[],"mappings":"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"}