@mcoda/core 0.1.14 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,6 +24,8 @@ export interface WorkOnTasksRequest extends TaskSelectionFilters {
24
24
  abortSignal?: AbortSignal;
25
25
  maxAgentSeconds?: number;
26
26
  allowFileOverwrite?: boolean;
27
+ missingTestsPolicy?: MissingTestsPolicy;
28
+ allowMissingTests?: boolean;
27
29
  }
28
30
  export interface TaskExecutionResult {
29
31
  taskKey: string;
@@ -38,6 +40,7 @@ export interface WorkOnTasksResult {
38
40
  results: TaskExecutionResult[];
39
41
  warnings: string[];
40
42
  }
43
+ export type MissingTestsPolicy = "block_job" | "skip_task" | "fail_task";
41
44
  export declare class WorkOnTasksService {
42
45
  private workspace;
43
46
  private deps;
@@ -105,6 +108,7 @@ export declare class WorkOnTasksService {
105
108
  private usesCliBrowserTools;
106
109
  private ensureCypressChromium;
107
110
  private applyChromiumForTests;
111
+ private findMissingTestHarnessTasks;
108
112
  private runTests;
109
113
  workOnTasks(request: WorkOnTasksRequest): Promise<WorkOnTasksResult>;
110
114
  }
@@ -1 +1 @@
1
- {"version":3,"file":"WorkOnTasksService.d.ts","sourceRoot":"","sources":["../../../src/services/execution/WorkOnTasksService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"WorkOnTasksService.d.ts","sourceRoot":"","sources":["../../../src/services/execution/WorkOnTasksService.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAgD,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE9D,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAuB,MAAM,WAAW,CAAC;AAEvF,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAiB,MAAM,uBAAuB,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC1G,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AAiFrE,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D,SAAS,EAAE,mBAAmB,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,iBAAiB,CAAC;IAC7B,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AA6wBD,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;AAqjCzE,qBAAa,kBAAkB;IA0B3B,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,IAAI;IA1Bd,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,YAAY,CAAmB;IACvC,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,GAAG,CAAY;IACvB,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,aAAa,CAAC,CAAqB;YAC7B,eAAe;gBAmBnB,SAAS,EAAE,mBAAmB,EAC9B,IAAI,EAAE;QACZ,YAAY,EAAE,YAAY,CAAC;QAC3B,MAAM,EAAE,YAAY,CAAC;QACrB,UAAU,EAAE,UAAU,CAAC;QACvB,aAAa,EAAE,mBAAmB,CAAC;QACnC,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;QACxC,YAAY,CAAC,EAAE,gBAAgB,CAAC;QAChC,IAAI,EAAE,gBAAgB,CAAC;QACvB,SAAS,CAAC,EAAE,SAAS,CAAC;QACtB,cAAc,EAAE,cAAc,CAAC;QAC/B,aAAa,CAAC,EAAE,kBAAkB,CAAC;KACpC;YASW,WAAW;YAsDX,WAAW;YAIX,mBAAmB;YAOnB,oBAAoB;YAUpB,UAAU;WAUX,MAAM,CAAC,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA6B1E,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB5B,qBAAqB,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI;YAQlD,YAAY;IAU1B,OAAO,CAAC,eAAe;IAQvB,OAAO,CAAC,mBAAmB;IAY3B,OAAO,CAAC,qBAAqB;IAW7B,OAAO,CAAC,UAAU;YAMJ,OAAO;YAWP,gBAAgB;YAsChB,eAAe;YAcf,gBAAgB;IA6G9B,OAAO,CAAC,gBAAgB;IA2BxB,OAAO,CAAC,mBAAmB;IAmC3B,OAAO,CAAC,YAAY;YAgBN,kBAAkB;YASlB,WAAW;YAOX,2BAA2B;YAY3B,uBAAuB;IAwGrC,OAAO,CAAC,WAAW;YAsCL,kBAAkB;IAoBhC,OAAO,CAAC,cAAc;YAYR,oBAAoB;YAkDpB,cAAc;IAmM5B,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,oBAAoB;IAI5B,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,oBAAoB;YAGd,gBAAgB;IA6D9B,OAAO,CAAC,aAAa;YAiBP,yBAAyB;YA4CzB,sBAAsB;YA4DtB,YAAY;YAsOZ,eAAe;IAuE7B,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,qBAAqB;YASf,qBAAqB;YA0BrB,2BAA2B;YAkE3B,QAAQ;IA4ChB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAs9F3E"}
@@ -833,6 +833,16 @@ const splitFileBlocksByExistence = (fileBlocks, cwd) => {
833
833
  }
834
834
  return { existing, remaining };
835
835
  };
836
+ const DEFAULT_MISSING_TESTS_POLICY = "block_job";
837
+ const normalizeMissingTestsPolicy = (value) => {
838
+ if (typeof value !== "string")
839
+ return undefined;
840
+ const normalized = value.trim().toLowerCase().replace(/-/g, "_");
841
+ if (normalized === "block_job" || normalized === "skip_task" || normalized === "fail_task") {
842
+ return normalized;
843
+ }
844
+ return undefined;
845
+ };
836
846
  const normalizeStringArray = (value) => {
837
847
  if (!Array.isArray(value))
838
848
  return [];
@@ -1192,6 +1202,7 @@ const buildRunAllTestsScript = (seedCategory, seedCommands) => {
1192
1202
  " const status = typeof result.status === \"number\" ? result.status : 1;",
1193
1203
  " if (status !== 0) failed = true;",
1194
1204
  "}",
1205
+ 'console.log(`MCODA_RUN_ALL_TESTS_COMPLETE status=${failed ? "failed" : "passed"}`);',
1195
1206
  'console.log("MCODA_RUN_ALL_TESTS_END");',
1196
1207
  "process.exit(failed ? 1 : 0);",
1197
1208
  "",
@@ -3142,6 +3153,56 @@ export class WorkOnTasksService {
3142
3153
  const updated = commands.map((command) => this.ensureCypressChromium(command));
3143
3154
  return { ok: true, commands: updated, env };
3144
3155
  }
3156
+ async findMissingTestHarnessTasks(orderedTasks) {
3157
+ const issues = [];
3158
+ const commandBuilder = new QaTestCommandBuilder(this.workspace.workspaceRoot);
3159
+ const runAllTestsCommandHint = detectRunAllTestsCommand(this.workspace.workspaceRoot);
3160
+ for (const selected of orderedTasks) {
3161
+ const metadata = selected.task.metadata ?? {};
3162
+ const testRequirements = normalizeTestRequirements(metadata.test_requirements ?? metadata.testRequirements);
3163
+ if (!hasTestRequirements(testRequirements))
3164
+ continue;
3165
+ let testCommands = normalizeTestCommands(metadata.tests ?? metadata.testCommands);
3166
+ const attemptedCommands = [];
3167
+ const sanitizedMetadata = sanitizeTestCommands(testCommands, this.workspace.workspaceRoot);
3168
+ testCommands = sanitizedMetadata.commands;
3169
+ attemptedCommands.push(...testCommands);
3170
+ if (!testCommands.length) {
3171
+ try {
3172
+ const commandPlan = await commandBuilder.build({ task: selected.task });
3173
+ const built = sanitizeTestCommands(commandPlan.commands, this.workspace.workspaceRoot);
3174
+ testCommands = built.commands;
3175
+ attemptedCommands.push(...built.commands);
3176
+ }
3177
+ catch {
3178
+ // Ignore command builder errors for preflight and rely on fallback checks.
3179
+ }
3180
+ }
3181
+ if (!testCommands.length) {
3182
+ let allowedFiles = Array.isArray(metadata.files) ? normalizePaths(this.workspace.workspaceRoot, metadata.files) : [];
3183
+ const allowedDirs = normalizeDirList(metadata.allowed_dirs ?? metadata.allowedDirs);
3184
+ if (allowedDirs.length) {
3185
+ const normalizedDirs = normalizePaths(this.workspace.workspaceRoot, allowedDirs);
3186
+ allowedFiles = Array.from(new Set([...allowedFiles, ...normalizedDirs]));
3187
+ }
3188
+ const fallbackCommand = detectScopedTestCommand(this.workspace.workspaceRoot, allowedFiles);
3189
+ if (fallbackCommand) {
3190
+ const fallback = sanitizeTestCommands([fallbackCommand], this.workspace.workspaceRoot);
3191
+ testCommands = fallback.commands;
3192
+ attemptedCommands.push(...fallback.commands);
3193
+ }
3194
+ }
3195
+ const hasRunnableTests = testCommands.length > 0 || Boolean(runAllTestsCommandHint);
3196
+ if (hasRunnableTests)
3197
+ continue;
3198
+ issues.push({
3199
+ taskKey: selected.task.key,
3200
+ testRequirements,
3201
+ attemptedCommands: dedupeCommands(attemptedCommands),
3202
+ });
3203
+ }
3204
+ return issues;
3205
+ }
3145
3206
  async runTests(commands, cwd, abortSignal) {
3146
3207
  const results = [];
3147
3208
  const chromiumPrep = await this.applyChromiumForTests(commands);
@@ -3201,6 +3262,8 @@ export class WorkOnTasksService {
3201
3262
  const directEditsEnabled = !patchModeEnabled;
3202
3263
  const enforceCommentBacklog = isCommentBacklogEnforced();
3203
3264
  const commentBacklogMaxFails = resolveCommentBacklogMaxFails();
3265
+ const requestedMissingTestsPolicy = normalizeMissingTestsPolicy(request.missingTestsPolicy);
3266
+ const missingTestsPolicy = requestedMissingTestsPolicy ?? (request.allowMissingTests ? "skip_task" : DEFAULT_MISSING_TESTS_POLICY);
3204
3267
  const baseCodaliEnvOverrides = codaliRequired ? buildCodaliEnvOverrides() : {};
3205
3268
  const configuredBaseBranch = this.workspace.config?.branch;
3206
3269
  const requestedBaseBranch = request.baseBranch;
@@ -3214,6 +3277,9 @@ export class WorkOnTasksService {
3214
3277
  const baseBranchWarnings = [];
3215
3278
  const statusWarnings = [];
3216
3279
  const runnerWarnings = [];
3280
+ if (request.missingTestsPolicy && !requestedMissingTestsPolicy) {
3281
+ runnerWarnings.push(`Unknown missing-tests policy "${String(request.missingTestsPolicy)}"; using "${missingTestsPolicy}".`);
3282
+ }
3217
3283
  const ignoreStatusFilter = Boolean(request.taskKeys?.length) || request.ignoreStatusFilter === true;
3218
3284
  const { filtered: statusFilter, rejected } = ignoreStatusFilter
3219
3285
  ? { filtered: request.statusFilter ?? [], rejected: [] }
@@ -3259,6 +3325,8 @@ export class WorkOnTasksService {
3259
3325
  dryRun: request.dryRun ?? false,
3260
3326
  agent: request.agentName,
3261
3327
  agentStream,
3328
+ missingTestsPolicy,
3329
+ allowMissingTests: request.allowMissingTests ?? false,
3262
3330
  },
3263
3331
  });
3264
3332
  const workspaceRoot = request.workspace.workspaceRoot;
@@ -3352,6 +3420,23 @@ export class WorkOnTasksService {
3352
3420
  const results = [];
3353
3421
  const taskSummaries = new Map();
3354
3422
  const warnings = [...baseBranchWarnings, ...statusWarnings, ...runnerWarnings, ...selection.warnings];
3423
+ if (missingTestsPolicy === "block_job") {
3424
+ const missingHarnessTasks = await this.findMissingTestHarnessTasks(selection.ordered);
3425
+ if (missingHarnessTasks.length > 0) {
3426
+ const taskKeys = missingHarnessTasks.map((issue) => issue.taskKey);
3427
+ await this.checkpoint(job.id, "tests_preflight_blocked", {
3428
+ reason: "missing_test_harness",
3429
+ policy: missingTestsPolicy,
3430
+ taskKeys,
3431
+ issues: missingHarnessTasks.map((issue) => ({
3432
+ taskKey: issue.taskKey,
3433
+ testRequirements: issue.testRequirements,
3434
+ attemptedCommands: issue.attemptedCommands,
3435
+ })),
3436
+ });
3437
+ throw new Error(`missing_test_harness: selected tasks require tests but no runnable test harness was found (${taskKeys.join(", ")}). Configure metadata.tests/testCommands or add tests/all.js.`);
3438
+ }
3439
+ }
3355
3440
  const gatewayHandoffPath = codaliRequired ? process.env[GATEWAY_HANDOFF_ENV_PATH] : undefined;
3356
3441
  let gatewayHandoff = null;
3357
3442
  if (gatewayHandoffPath) {
@@ -3850,7 +3935,29 @@ export class WorkOnTasksService {
3850
3935
  : "";
3851
3936
  const hasRunnableTests = testCommands.length > 0 || Boolean(runAllTestsCommandHint);
3852
3937
  if (testsRequired && !hasRunnableTests) {
3853
- await this.logTask(taskRun.id, "Tests required but no runnable test commands were found; failing task.", "tests", { testRequirements });
3938
+ if (missingTestsPolicy === "skip_task") {
3939
+ await this.logTask(taskRun.id, "Tests required but no runnable test commands were found; skipping task due to missing-tests policy.", "tests", { testRequirements, missingTestsPolicy });
3940
+ await this.deps.workspaceRepo.updateTaskRun(taskRun.id, {
3941
+ status: "cancelled",
3942
+ finishedAt: new Date().toISOString(),
3943
+ });
3944
+ results.push({ taskKey: task.task.key, status: "skipped", notes: "missing_test_harness" });
3945
+ taskStatus = "skipped";
3946
+ await this.deps.jobService.updateJobStatus(job.id, "running", { processedItems: index + 1 });
3947
+ await emitTaskEndOnce();
3948
+ continue taskLoop;
3949
+ }
3950
+ if (missingTestsPolicy === "block_job") {
3951
+ await this.logTask(taskRun.id, "Tests required but no runnable test commands were found; stopping job due to missing-tests policy.", "tests", { testRequirements, missingTestsPolicy });
3952
+ await this.deps.workspaceRepo.updateTaskRun(taskRun.id, {
3953
+ status: "cancelled",
3954
+ finishedAt: new Date().toISOString(),
3955
+ });
3956
+ taskStatus = "skipped";
3957
+ await emitTaskEndOnce();
3958
+ throw new Error(`missing_test_harness: ${task.task.key} requires tests but no runnable test commands were found`);
3959
+ }
3960
+ await this.logTask(taskRun.id, "Tests required but no runnable test commands were found; failing task.", "tests", { testRequirements, missingTestsPolicy });
3854
3961
  await this.stateService.markFailed(task.task, "tests_not_configured", statusContext);
3855
3962
  await this.deps.workspaceRepo.updateTaskRun(taskRun.id, {
3856
3963
  status: "failed",
@@ -138,6 +138,7 @@ export declare class JobService {
138
138
  private logsDir;
139
139
  private ensureMcoda;
140
140
  private cancelJobOnSignal;
141
+ private cancelRunningTaskRuns;
141
142
  private readJsonArray;
142
143
  private writeJsonArray;
143
144
  private appendJsonArray;
@@ -1 +1 @@
1
- {"version":3,"file":"JobService.d.ts","sourceRoot":"","sources":["../../../src/services/jobs/JobService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"JobService.d.ts","sourceRoot":"","sources":["../../../src/services/jobs/JobService.ts"],"names":[],"mappings":"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"}
@@ -118,6 +118,12 @@ export class JobService {
118
118
  // ignore lock cleanup failures during shutdown
119
119
  }
120
120
  }
121
+ try {
122
+ await this.cancelRunningTaskRuns(jobId);
123
+ }
124
+ catch {
125
+ // ignore task run cleanup failures during shutdown
126
+ }
121
127
  try {
122
128
  await this.updateJobStatus(jobId, "cancelled", { errorSummary: reason });
123
129
  }
@@ -133,6 +139,17 @@ export class JobService {
133
139
  }
134
140
  }
135
141
  }
142
+ async cancelRunningTaskRuns(jobId) {
143
+ if (!this.workspaceRepo || !("getDb" in this.workspaceRepo))
144
+ return;
145
+ const db = this.workspaceRepo.getDb();
146
+ const finishedAt = nowIso();
147
+ await db.run(`UPDATE task_runs
148
+ SET status = 'cancelled',
149
+ finished_at = CASE WHEN finished_at IS NULL THEN ? ELSE finished_at END
150
+ WHERE job_id = ?
151
+ AND status = 'running'`, finishedAt, jobId);
152
+ }
136
153
  async readJsonArray(filePath) {
137
154
  try {
138
155
  const raw = await fs.readFile(filePath, "utf8");
@@ -432,6 +449,12 @@ export class JobService {
432
449
  });
433
450
  }
434
451
  if (state === "cancelled" && this.workspaceRepo && "releaseTaskLocksByJob" in this.workspaceRepo) {
452
+ try {
453
+ await this.cancelRunningTaskRuns(jobId);
454
+ }
455
+ catch {
456
+ // ignore task run cleanup failures during cancellation
457
+ }
435
458
  try {
436
459
  await this.workspaceRepo.releaseTaskLocksByJob(jobId);
437
460
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CreateTasksService.d.ts","sourceRoot":"","sources":["../../../src/services/planning/CreateTasksService.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CreateTasksService.d.ts","sourceRoot":"","sources":["../../../src/services/planning/CreateTasksService.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@ import { RoutingService } from "../agents/RoutingService.js";
9
9
  import { AgentRatingService } from "../agents/AgentRatingService.js";
10
10
  import { classifyTask } from "../backlog/TaskOrderingHeuristics.js";
11
11
  import { TaskOrderingService } from "../backlog/TaskOrderingService.js";
12
+ import { QaTestCommandBuilder } from "../execution/QaTestCommandBuilder.js";
12
13
  import { createEpicKeyGenerator, createStoryKeyGenerator, createTaskKeyGenerator, } from "./KeyHelpers.js";
13
14
  const formatBullets = (items, fallback) => {
14
15
  if (!items || items.length === 0)
@@ -1139,6 +1140,7 @@ export class CreateTasksService {
1139
1140
  }
1140
1141
  const localToKey = new Map(taskDetails.map((t) => [t.localId, t.key]));
1141
1142
  const taskInserts = [];
1143
+ const testCommandBuilder = new QaTestCommandBuilder(this.workspace.workspaceRoot);
1142
1144
  for (const task of taskDetails) {
1143
1145
  const storyId = storyIdByKey.get(task.storyKey);
1144
1146
  const epicId = epicIdByKey.get(task.epicKey);
@@ -1155,9 +1157,60 @@ export class CreateTasksService {
1155
1157
  preflight: options?.qaPreflight,
1156
1158
  overrides: options?.qaOverrides,
1157
1159
  });
1160
+ const testRequirements = {
1161
+ unit: task.plan.unitTests ?? [],
1162
+ component: task.plan.componentTests ?? [],
1163
+ integration: task.plan.integrationTests ?? [],
1164
+ api: task.plan.apiTests ?? [],
1165
+ };
1166
+ const testsRequired = testRequirements.unit.length > 0 ||
1167
+ testRequirements.component.length > 0 ||
1168
+ testRequirements.integration.length > 0 ||
1169
+ testRequirements.api.length > 0;
1170
+ let discoveredTestCommands = [];
1171
+ if (testsRequired) {
1172
+ try {
1173
+ const commandPlan = await testCommandBuilder.build({
1174
+ task: {
1175
+ id: task.key,
1176
+ key: task.key,
1177
+ title: task.plan.title ?? `Task ${task.key}`,
1178
+ description: task.plan.description ?? "",
1179
+ type: task.plan.type ?? "feature",
1180
+ status: "not_started",
1181
+ metadata: { test_requirements: testRequirements },
1182
+ },
1183
+ });
1184
+ discoveredTestCommands = Array.from(new Set(commandPlan.commands.map((command) => command.trim()).filter(Boolean)));
1185
+ }
1186
+ catch {
1187
+ discoveredTestCommands = [];
1188
+ }
1189
+ }
1190
+ const qaBlockers = uniqueStrings([
1191
+ ...(qaReadiness.blockers ?? []),
1192
+ ...(testsRequired && discoveredTestCommands.length === 0
1193
+ ? ["No runnable test harness discovered for required tests during planning."]
1194
+ : []),
1195
+ ]);
1196
+ const qaReadinessWithHarness = {
1197
+ ...qaReadiness,
1198
+ blockers: qaBlockers.length ? qaBlockers : undefined,
1199
+ };
1158
1200
  const depSlugs = (task.plan.dependsOnKeys ?? [])
1159
1201
  .map((dep) => localToKey.get(dep))
1160
1202
  .filter((value) => Boolean(value));
1203
+ const metadata = {
1204
+ doc_links: task.plan.relatedDocs ?? [],
1205
+ test_requirements: testRequirements,
1206
+ stage: classification.stage,
1207
+ foundation: classification.foundation,
1208
+ qa: qaReadinessWithHarness,
1209
+ };
1210
+ if (discoveredTestCommands.length > 0) {
1211
+ metadata.tests = discoveredTestCommands;
1212
+ metadata.testCommands = discoveredTestCommands;
1213
+ }
1161
1214
  taskInserts.push({
1162
1215
  projectId,
1163
1216
  epicId,
@@ -1169,23 +1222,12 @@ export class CreateTasksService {
1169
1222
  componentTests: task.plan.componentTests,
1170
1223
  integrationTests: task.plan.integrationTests,
1171
1224
  apiTests: task.plan.apiTests,
1172
- }, qaReadiness),
1225
+ }, qaReadinessWithHarness),
1173
1226
  type: task.plan.type ?? "feature",
1174
1227
  status: "not_started",
1175
1228
  storyPoints: task.plan.estimatedStoryPoints ?? null,
1176
1229
  priority: task.plan.priorityHint ?? (taskInserts.length + 1),
1177
- metadata: {
1178
- doc_links: task.plan.relatedDocs ?? [],
1179
- test_requirements: {
1180
- unit: task.plan.unitTests ?? [],
1181
- component: task.plan.componentTests ?? [],
1182
- integration: task.plan.integrationTests ?? [],
1183
- api: task.plan.apiTests ?? [],
1184
- },
1185
- stage: classification.stage,
1186
- foundation: classification.foundation,
1187
- qa: qaReadiness,
1188
- },
1230
+ metadata,
1189
1231
  });
1190
1232
  }
1191
1233
  taskRows = await this.workspaceRepo.insertTasks(taskInserts, false);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcoda/core",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "description": "Core services and APIs for the mcoda CLI.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -32,11 +32,11 @@
32
32
  "dependencies": {
33
33
  "@apidevtools/swagger-parser": "^10.1.0",
34
34
  "yaml": "^2.4.2",
35
- "@mcoda/db": "0.1.14",
36
- "@mcoda/shared": "0.1.14",
37
- "@mcoda/agents": "0.1.14",
38
- "@mcoda/integrations": "0.1.14",
39
- "@mcoda/generators": "0.1.14"
35
+ "@mcoda/agents": "0.1.15",
36
+ "@mcoda/shared": "0.1.15",
37
+ "@mcoda/db": "0.1.15",
38
+ "@mcoda/generators": "0.1.15",
39
+ "@mcoda/integrations": "0.1.15"
40
40
  },
41
41
  "scripts": {
42
42
  "build": "tsc -p tsconfig.json",