mcoda 0.1.19 → 0.1.20

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 (27) hide show
  1. package/dist/commands/backlog/OrderTasksCommand.d.ts +2 -0
  2. package/dist/commands/backlog/OrderTasksCommand.d.ts.map +1 -1
  3. package/dist/commands/backlog/OrderTasksCommand.js +38 -2
  4. package/dist/commands/docs/DocsCommands.d.ts.map +1 -1
  5. package/dist/commands/docs/DocsCommands.js +11 -11
  6. package/dist/commands/estimate/EstimateCommands.d.ts.map +1 -1
  7. package/dist/commands/estimate/EstimateCommands.js +28 -27
  8. package/dist/commands/openapi/OpenapiCommands.d.ts +1 -0
  9. package/dist/commands/openapi/OpenapiCommands.d.ts.map +1 -1
  10. package/dist/commands/openapi/OpenapiCommands.js +11 -1
  11. package/dist/commands/planning/CreateTasksCommand.d.ts.map +1 -1
  12. package/dist/commands/planning/CreateTasksCommand.js +18 -12
  13. package/dist/commands/planning/QaTasksCommand.d.ts +14 -0
  14. package/dist/commands/planning/QaTasksCommand.d.ts.map +1 -1
  15. package/dist/commands/planning/QaTasksCommand.js +89 -7
  16. package/dist/commands/review/CodeReviewCommand.d.ts +14 -0
  17. package/dist/commands/review/CodeReviewCommand.d.ts.map +1 -1
  18. package/dist/commands/review/CodeReviewCommand.js +133 -4
  19. package/dist/commands/work/WorkOnTasksCommand.d.ts +14 -0
  20. package/dist/commands/work/WorkOnTasksCommand.d.ts.map +1 -1
  21. package/dist/commands/work/WorkOnTasksCommand.js +129 -6
  22. package/dist/commands/workspace/ProjectGuidanceCommand.d.ts +1 -0
  23. package/dist/commands/workspace/ProjectGuidanceCommand.d.ts.map +1 -1
  24. package/dist/commands/workspace/ProjectGuidanceCommand.js +81 -1
  25. package/dist/commands/workspace/SetWorkspaceCommand.d.ts.map +1 -1
  26. package/dist/commands/workspace/SetWorkspaceCommand.js +37 -1
  27. package/package.json +5 -5
@@ -2,12 +2,14 @@ interface ParsedArgs {
2
2
  workspaceRoot?: string;
3
3
  project?: string;
4
4
  epic?: string;
5
+ story?: string;
5
6
  status?: string[];
6
7
  agentName?: string;
7
8
  agentStream?: boolean;
8
9
  rateAgents: boolean;
9
10
  inferDeps: boolean;
10
11
  apply: boolean;
12
+ planningContextPolicy: "best_effort" | "require_any" | "require_sds_or_openapi";
11
13
  stageOrder?: string[];
12
14
  json: boolean;
13
15
  }
@@ -1 +1 @@
1
- {"version":3,"file":"OrderTasksCommand.d.ts","sourceRoot":"","sources":["../../../src/commands/backlog/OrderTasksCommand.ts"],"names":[],"mappings":"AAGA,UAAU,UAAU;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,OAAO,CAAC;CACf;AA0CD,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,EAAE,KAAG,UAwHpD,CAAC;AAkDF,qBAAa,iBAAiB;WACf,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA4DhD"}
1
+ {"version":3,"file":"OrderTasksCommand.d.ts","sourceRoot":"","sources":["../../../src/commands/backlog/OrderTasksCommand.ts"],"names":[],"mappings":"AAGA,UAAU,UAAU;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,qBAAqB,EAAE,aAAa,GAAG,aAAa,GAAG,wBAAwB,CAAC;IAChF,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,OAAO,CAAC;CACf;AAuDD,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,EAAE,KAAG,UA4IpD,CAAC;AAkDF,qBAAa,iBAAiB;WACf,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA+DhD"}
@@ -4,11 +4,13 @@ const usage = `mcoda order-tasks \\
4
4
  [--workspace-root <PATH>] \\
5
5
  --project <PROJECT_KEY> \\
6
6
  [--epic <EPIC_KEY>] \\
7
+ [--story <STORY_KEY>] \\
7
8
  [--status <STATUS_FILTER>] \\
8
9
  [--agent <NAME>] \\
9
10
  [--agent-stream <true|false>] \\
10
11
  [--infer-deps] \\
11
- [--apply] \\
12
+ [--apply <true|false>] \\
13
+ [--planning-context-policy <best_effort|require_any|require_sds_or_openapi>] \\
12
14
  [--stage-order <foundation,backend,frontend,other>] \\
13
15
  [--rate-agents] \\
14
16
  [--json]`;
@@ -41,12 +43,22 @@ const parseStageOrder = (value) => {
41
43
  .filter(Boolean);
42
44
  return parts.length ? parts : undefined;
43
45
  };
46
+ const normalizePlanningContextPolicy = (value) => {
47
+ if (!value)
48
+ return undefined;
49
+ const normalized = value.trim().toLowerCase();
50
+ if (normalized === "best_effort" || normalized === "require_any" || normalized === "require_sds_or_openapi") {
51
+ return normalized;
52
+ }
53
+ return undefined;
54
+ };
44
55
  export const parseOrderTasksArgs = (argv) => {
45
56
  const parsed = {
46
57
  agentStream: false,
47
58
  rateAgents: false,
48
59
  inferDeps: false,
49
- apply: false,
60
+ apply: true,
61
+ planningContextPolicy: "require_sds_or_openapi",
50
62
  json: false,
51
63
  };
52
64
  for (let i = 0; i < argv.length; i += 1) {
@@ -75,6 +87,12 @@ export const parseOrderTasksArgs = (argv) => {
75
87
  parsed.stageOrder = parseStageOrder(arg.split("=")[1]);
76
88
  continue;
77
89
  }
90
+ if (arg.startsWith("--planning-context-policy=")) {
91
+ const policy = normalizePlanningContextPolicy(arg.split("=")[1]);
92
+ if (policy)
93
+ parsed.planningContextPolicy = policy;
94
+ continue;
95
+ }
78
96
  switch (arg) {
79
97
  case "--workspace-root":
80
98
  parsed.workspaceRoot = argv[i + 1] ? path.resolve(argv[i + 1]) : undefined;
@@ -88,6 +106,10 @@ export const parseOrderTasksArgs = (argv) => {
88
106
  parsed.epic = argv[i + 1];
89
107
  i += 1;
90
108
  break;
109
+ case "--story":
110
+ parsed.story = argv[i + 1];
111
+ i += 1;
112
+ break;
91
113
  case "--status":
92
114
  parsed.status = parseStatuses(argv[i + 1]);
93
115
  i += 1;
@@ -133,6 +155,14 @@ export const parseOrderTasksArgs = (argv) => {
133
155
  parsed.stageOrder = parseStageOrder(argv[i + 1]);
134
156
  i += 1;
135
157
  break;
158
+ case "--planning-context-policy": {
159
+ const policy = normalizePlanningContextPolicy(argv[i + 1]);
160
+ if (policy) {
161
+ parsed.planningContextPolicy = policy;
162
+ }
163
+ i += 1;
164
+ break;
165
+ }
136
166
  case "--rate-agents": {
137
167
  const next = argv[i + 1];
138
168
  if (next && !next.startsWith("-")) {
@@ -160,6 +190,9 @@ export const parseOrderTasksArgs = (argv) => {
160
190
  else if (arg.startsWith("--epic=")) {
161
191
  parsed.epic = arg.split("=")[1];
162
192
  }
193
+ else if (arg.startsWith("--story=")) {
194
+ parsed.story = arg.split("=")[1];
195
+ }
163
196
  else if (arg === "--json=true") {
164
197
  parsed.json = true;
165
198
  }
@@ -232,11 +265,14 @@ export class OrderTasksCommand {
232
265
  const result = await service.orderTasks({
233
266
  projectKey: parsed.project,
234
267
  epicKey: parsed.epic,
268
+ storyKey: parsed.story,
235
269
  statusFilter: parsed.status,
236
270
  agentName: parsed.agentName,
237
271
  agentStream: parsed.agentStream,
238
272
  rateAgents: parsed.rateAgents,
239
273
  inferDependencies: parsed.inferDeps,
274
+ apply: parsed.apply,
275
+ planningContextPolicy: parsed.planningContextPolicy,
240
276
  stageOrder: resolvedStageOrder,
241
277
  });
242
278
  if (parsed.json) {
@@ -1 +1 @@
1
- {"version":3,"file":"DocsCommands.d.ts","sourceRoot":"","sources":["../../../src/commands/docs/DocsCommands.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAUD,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,KAAG,aAiO7C,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,KAAG,aAiO7C,CAAC;AAoBF,qBAAa,YAAY;WACV,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA+KhD"}
1
+ {"version":3,"file":"DocsCommands.d.ts","sourceRoot":"","sources":["../../../src/commands/docs/DocsCommands.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAUD,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,KAAG,aA8N7C,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,KAAG,aAoO7C,CAAC;AAoBF,qBAAa,YAAY;WACV,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA+KhD"}
@@ -23,10 +23,10 @@ export const parsePdrArgs = (argv) => {
23
23
  let rateAgents = false;
24
24
  let fast = false;
25
25
  let iterate = false;
26
- let quality;
27
- let resolveOpenQuestions = false;
28
- let noPlaceholders = false;
29
- let noMaybes = false;
26
+ let quality = "build-ready";
27
+ let resolveOpenQuestions = true;
28
+ let noPlaceholders = true;
29
+ let noMaybes = true;
30
30
  let crossAlign = true;
31
31
  let dryRun = false;
32
32
  let json = false;
@@ -205,9 +205,6 @@ export const parsePdrArgs = (argv) => {
205
205
  case "--no-telemetry":
206
206
  noTelemetry = true;
207
207
  break;
208
- case "--no-telemetry":
209
- noTelemetry = true;
210
- break;
211
208
  case "--help":
212
209
  case "-h":
213
210
  // eslint-disable-next-line no-console
@@ -255,10 +252,10 @@ export const parseSdsArgs = (argv) => {
255
252
  let force = false;
256
253
  let fast = false;
257
254
  let iterate = false;
258
- let quality;
259
- let resolveOpenQuestions = false;
260
- let noPlaceholders = false;
261
- let noMaybes = false;
255
+ let quality = "build-ready";
256
+ let resolveOpenQuestions = true;
257
+ let noPlaceholders = true;
258
+ let noMaybes = true;
262
259
  let crossAlign = true;
263
260
  let resumeJobId;
264
261
  let dryRun = false;
@@ -439,6 +436,9 @@ export const parseSdsArgs = (argv) => {
439
436
  case "--no-color":
440
437
  noColor = true;
441
438
  break;
439
+ case "--no-telemetry":
440
+ noTelemetry = true;
441
+ break;
442
442
  case "--help":
443
443
  case "-h":
444
444
  // eslint-disable-next-line no-console
@@ -1 +1 @@
1
- {"version":3,"file":"EstimateCommands.d.ts","sourceRoot":"","sources":["../../../src/commands/estimate/EstimateCommands.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,cAAc,EAGf,MAAM,aAAa,CAAC;AAErB,UAAU,UAAU;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,cAAc,CAAC;IAC9B,cAAc,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB;AA6BD,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,EAAE,KAAG,UA4HlD,CAAC;AA0DF,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,GAAG,IAAI,GAAG,SAAS,KAAG,MAwBjE,CAAC;AA4NF,qBAAa,gBAAgB;WACd,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAkEhD"}
1
+ {"version":3,"file":"EstimateCommands.d.ts","sourceRoot":"","sources":["../../../src/commands/estimate/EstimateCommands.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,cAAc,EAGf,MAAM,aAAa,CAAC;AAErB,UAAU,UAAU;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,cAAc,CAAC;IAC9B,cAAc,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IAC9B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;CAChB;AA6BD,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,EAAE,KAAG,UA4HlD,CAAC;AAgEF,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,GAAG,IAAI,GAAG,SAAS,KAAG,MAwBjE,CAAC;AA6NF,qBAAa,gBAAgB;WACd,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAkEhD"}
@@ -193,11 +193,13 @@ const formatPanel = (lines) => {
193
193
  const bottom = `╰${"─".repeat(width + 2)}╯`;
194
194
  return [top, ...body, bottom].join("\n");
195
195
  };
196
- const formatBoxTable = (headers, rows) => {
196
+ const formatBoxTable = (headers, rows, options) => {
197
197
  const widths = headers.map((header, idx) => Math.max(visibleLength(header), ...rows.map((row) => visibleLength(row[idx] ?? ""))));
198
- const border = (left, join, right) => `${left}${widths.map((width) => "─".repeat(width + 2)).join(join)}${right}`;
199
- const headerLine = `│${headers.map((header, idx) => ` ${padVisible(header, widths[idx])} `).join("│")}│`;
200
- const rowLines = rows.map((row) => `│${row.map((cell, idx) => ` ${padVisible(cell ?? "", widths[idx])} `).join("│")}│`);
198
+ const lineStyle = options?.lineStyle ?? ((value) => value);
199
+ const border = (left, join, right) => lineStyle(`${left}${widths.map((width) => "─".repeat(width + 2)).join(join)}${right}`);
200
+ const verticalLine = lineStyle("│");
201
+ const headerLine = `${verticalLine}${headers.map((header, idx) => ` ${padVisible(header, widths[idx])} `).join(verticalLine)}${verticalLine}`;
202
+ const rowLines = rows.map((row) => `${verticalLine}${row.map((cell, idx) => ` ${padVisible(cell ?? "", widths[idx])} `).join(verticalLine)}${verticalLine}`);
201
203
  return [
202
204
  border("╭", "┬", "╮"),
203
205
  headerLine,
@@ -330,6 +332,7 @@ const renderProgressSection = (result, colorEnabled) => {
330
332
  };
331
333
  const renderResult = (result, options) => {
332
334
  const { colorEnabled } = options;
335
+ const purpleTableLines = (value) => style.magenta(colorEnabled, value);
333
336
  const velocity = result.effectiveVelocity;
334
337
  const source = velocity.source;
335
338
  const spHeader = `SP/H (${source})`;
@@ -370,15 +373,14 @@ const renderResult = (result, options) => {
370
373
  ],
371
374
  ];
372
375
  // eslint-disable-next-line no-console
373
- console.log(formatPanel([
374
- style.bold(colorEnabled, "🧮 Effort by Lane"),
375
- formatBoxTable([
376
- style.bold(colorEnabled, "LANE"),
377
- style.bold(colorEnabled, "STORY POINTS"),
378
- style.bold(colorEnabled, spHeader.toUpperCase()),
379
- style.bold(colorEnabled, "TIME LEFT"),
380
- ], rows),
381
- ]));
376
+ console.log(style.bold(colorEnabled, style.magenta(colorEnabled, "🧮 Effort by Lane")));
377
+ // eslint-disable-next-line no-console
378
+ console.log(formatBoxTable([
379
+ style.bold(colorEnabled, "LANE"),
380
+ style.bold(colorEnabled, "STORY POINTS"),
381
+ style.bold(colorEnabled, spHeader.toUpperCase()),
382
+ style.bold(colorEnabled, "TIME LEFT"),
383
+ ], rows, { lineStyle: purpleTableLines }));
382
384
  const counts = result.statusCounts;
383
385
  // eslint-disable-next-line no-console
384
386
  console.log(formatPanel([
@@ -404,20 +406,19 @@ const renderResult = (result, options) => {
404
406
  `${style.bold(colorEnabled, "Samples")}${windowLabel} : impl=${samples.implementation ?? 0}, review=${samples.review ?? 0}, qa=${samples.qa ?? 0}`,
405
407
  ]));
406
408
  // eslint-disable-next-line no-console
407
- console.log(formatPanel([
408
- style.bold(colorEnabled, "⏱️ ETAs"),
409
- formatBoxTable([
410
- style.bold(colorEnabled, "READY TO REVIEW"),
411
- style.bold(colorEnabled, "READY TO QA"),
412
- style.bold(colorEnabled, "COMPLETE"),
413
- ], [
414
- [
415
- formatEtaCell(result.etas.readyToReviewEta),
416
- formatEtaCell(result.etas.readyToQaEta),
417
- formatEtaCell(result.etas.completeEta),
418
- ],
419
- ]),
420
- ]));
409
+ console.log(style.bold(colorEnabled, style.magenta(colorEnabled, "⏱️ ETAs")));
410
+ // eslint-disable-next-line no-console
411
+ console.log(formatBoxTable([
412
+ style.bold(colorEnabled, "READY TO REVIEW"),
413
+ style.bold(colorEnabled, "READY TO QA"),
414
+ style.bold(colorEnabled, "COMPLETE"),
415
+ ], [
416
+ [
417
+ formatEtaCell(result.etas.readyToReviewEta),
418
+ formatEtaCell(result.etas.readyToQaEta),
419
+ formatEtaCell(result.etas.completeEta),
420
+ ],
421
+ ], { lineStyle: purpleTableLines }));
421
422
  // eslint-disable-next-line no-console
422
423
  console.log(formatPanel([
423
424
  `${style.bold(colorEnabled, "ℹ️ Assumptions")} : lane work runs in parallel; total hours uses the longest lane.`,
@@ -1,5 +1,6 @@
1
1
  export interface ParsedOpenapiArgs {
2
2
  workspaceRoot?: string;
3
+ project?: string;
3
4
  agentName?: string;
4
5
  agentStream: boolean;
5
6
  rateAgents: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"OpenapiCommands.d.ts","sourceRoot":"","sources":["../../../src/commands/openapi/OpenapiCommands.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;CACtB;AAUD,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,EAAE,KAAG,iBAoFjD,CAAC;AAcF,eAAO,MAAM,wBAAwB,GAAI,OAAO,OAAO,KAAG,MAAM,EAiB/D,CAAC;AAEF,qBAAa,eAAe;WACb,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA4EhD"}
1
+ {"version":3,"file":"OpenapiCommands.d.ts","sourceRoot":"","sources":["../../../src/commands/openapi/OpenapiCommands.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;CACtB;AAUD,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,EAAE,KAAG,iBA6FjD,CAAC;AAcF,eAAO,MAAM,wBAAwB,GAAI,OAAO,OAAO,KAAG,MAAM,EAiB/D,CAAC;AAEF,qBAAa,eAAe;WACb,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA6EhD"}
@@ -1,7 +1,7 @@
1
1
  import path from "node:path";
2
2
  import { createRequire } from "node:module";
3
3
  import { OpenApiJobError, OpenApiService, WorkspaceResolver } from "@mcoda/core";
4
- const usage = "mcoda openapi-from-docs [--workspace-root <PATH>] [--agent <NAME>] [--agent-stream <true|false>] [--rate-agents] [--force] [--dry-run] [--validate-only] [--no-telemetry]";
4
+ const usage = "mcoda openapi-from-docs [--workspace-root <PATH>] [--project <PROJECT_KEY>] [--agent <NAME>] [--agent-stream <true|false>] [--rate-agents] [--force] [--dry-run] [--validate-only] [--no-telemetry]";
5
5
  const parseBooleanFlag = (value, defaultValue) => {
6
6
  if (value === undefined)
7
7
  return defaultValue;
@@ -14,6 +14,7 @@ const parseBooleanFlag = (value, defaultValue) => {
14
14
  };
15
15
  export const parseOpenapiArgs = (argv) => {
16
16
  let workspaceRoot;
17
+ let project;
17
18
  let agentName;
18
19
  let agentStream;
19
20
  let rateAgents = false;
@@ -38,6 +39,10 @@ export const parseOpenapiArgs = (argv) => {
38
39
  workspaceRoot = argv[i + 1] ? path.resolve(argv[i + 1]) : undefined;
39
40
  i += 1;
40
41
  break;
42
+ case "--project":
43
+ project = argv[i + 1];
44
+ i += 1;
45
+ break;
41
46
  case "--agent":
42
47
  agentName = argv[i + 1];
43
48
  i += 1;
@@ -83,11 +88,15 @@ export const parseOpenapiArgs = (argv) => {
83
88
  process.exit(0);
84
89
  break;
85
90
  default:
91
+ if (arg.startsWith("--project=")) {
92
+ project = arg.split("=")[1];
93
+ }
86
94
  break;
87
95
  }
88
96
  }
89
97
  return {
90
98
  workspaceRoot,
99
+ project,
91
100
  agentName,
92
101
  agentStream: agentStream ?? false,
93
102
  rateAgents,
@@ -141,6 +150,7 @@ export class OpenapiCommands {
141
150
  const onToken = shouldStream ? (token) => process.stdout.write(token) : undefined;
142
151
  const result = await service.generateFromDocs({
143
152
  workspace,
153
+ projectKey: parsed.project,
144
154
  agentName: parsed.agentName,
145
155
  agentStream: parsed.agentStream,
146
156
  rateAgents: parsed.rateAgents,
@@ -1 +1 @@
1
- {"version":3,"file":"CreateTasksCommand.d.ts","sourceRoot":"","sources":["../../../src/commands/planning/CreateTasksCommand.ts"],"names":[],"mappings":"AAKA,UAAU,UAAU;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,KAAK,mBAAmB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AA2D5D,eAAO,MAAM,yBAAyB,GAAI,SAAS;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;CACjC,KAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CA0C3C,CAAC;AAUF,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,EAAE,KAAG,UAsIrD,CAAC;AAEF,qBAAa,kBAAkB;WAChB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAmEhD"}
1
+ {"version":3,"file":"CreateTasksCommand.d.ts","sourceRoot":"","sources":["../../../src/commands/planning/CreateTasksCommand.ts"],"names":[],"mappings":"AAKA,UAAU,UAAU;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,KAAK,mBAAmB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AA2D5D,eAAO,MAAM,yBAAyB,GAAI,SAAS;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;CACjC,KAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAmD3C,CAAC;AAUF,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,EAAE,KAAG,UAsIrD,CAAC;AAEF,qBAAa,kBAAkB;WAChB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAmEhD"}
@@ -61,26 +61,32 @@ const listTaskProjects = async (mcodaDir) => {
61
61
  };
62
62
  export const pickCreateTasksProjectKey = (options) => {
63
63
  const warnings = [];
64
+ const requestedKey = options.requestedKey?.trim() || undefined;
65
+ const configuredKey = options.configuredKey?.trim() || undefined;
64
66
  const derivedKey = options.derivedKey || "proj";
65
67
  const existing = options.existing ?? [];
66
68
  const latestExisting = existing[0]?.key;
67
- if (options.configuredKey) {
68
- if (options.requestedKey && options.requestedKey !== options.configuredKey) {
69
- warnings.push(`Using configured project key "${options.configuredKey}" from workspace config; ignoring requested "${options.requestedKey}".`);
69
+ const existingMatchesRequested = requestedKey ? existing.some((item) => item.key === requestedKey) : false;
70
+ if (requestedKey) {
71
+ if (configuredKey && configuredKey !== requestedKey) {
72
+ warnings.push(`Using explicitly requested project key "${requestedKey}"; overriding configured project key "${configuredKey}".`);
73
+ }
74
+ if (latestExisting && !existingMatchesRequested) {
75
+ warnings.push(`Using explicitly requested project key "${requestedKey}"; existing task plans were found for "${latestExisting}".`);
70
76
  }
71
77
  if (existing.length > 1) {
72
- warnings.push(`Multiple task plan folders detected (${existing.map((item) => item.key).join(", ")}); using configured project key "${options.configuredKey}".`);
78
+ warnings.push(`Multiple task plan folders detected (${existing.map((item) => item.key).join(", ")}); using explicitly requested project key "${requestedKey}".`);
73
79
  }
74
- return { projectKey: options.configuredKey, warnings };
80
+ return { projectKey: requestedKey, warnings };
75
81
  }
76
- if (latestExisting) {
77
- const requestedMatches = options.requestedKey
78
- ? existing.some((item) => item.key === options.requestedKey)
79
- : false;
80
- const selected = requestedMatches ? (options.requestedKey ?? latestExisting) : latestExisting;
81
- if (options.requestedKey && !requestedMatches) {
82
- warnings.push(`Found existing project key "${latestExisting}" under workspace task plans; ignoring requested "${options.requestedKey}".`);
82
+ if (configuredKey) {
83
+ if (existing.length > 1) {
84
+ warnings.push(`Multiple task plan folders detected (${existing.map((item) => item.key).join(", ")}); using configured project key "${configuredKey}".`);
83
85
  }
86
+ return { projectKey: configuredKey, warnings };
87
+ }
88
+ if (latestExisting) {
89
+ const selected = latestExisting;
84
90
  if (!options.requestedKey && selected !== derivedKey) {
85
91
  warnings.push(`Reusing existing project key "${selected}" from workspace task plans.`);
86
92
  }
@@ -14,6 +14,8 @@ interface ParsedArgs {
14
14
  agentStream: boolean;
15
15
  rateAgents: boolean;
16
16
  createFollowupTasks: "auto" | "none" | "prompt";
17
+ dependencyPolicy: "enforce" | "ignore";
18
+ noChangesPolicy: "require_qa" | "skip" | "manual";
17
19
  dryRun: boolean;
18
20
  json: boolean;
19
21
  debug: boolean;
@@ -26,7 +28,19 @@ interface ParsedArgs {
26
28
  cleanIgnorePaths: string[];
27
29
  quiet?: boolean;
28
30
  }
31
+ type ProjectKeyCandidate = {
32
+ key: string;
33
+ createdAt?: string | null;
34
+ };
29
35
  export declare const parseQaTasksArgs: (argv: string[]) => ParsedArgs;
36
+ export declare const pickQaTasksProjectKey: (options: {
37
+ requestedKey?: string;
38
+ configuredKey?: string;
39
+ existing: ProjectKeyCandidate[];
40
+ }) => {
41
+ projectKey?: string;
42
+ warnings: string[];
43
+ };
30
44
  export declare class QaTasksCommand {
31
45
  static run(argv: string[]): Promise<void>;
32
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"QaTasksCommand.d.ts","sourceRoot":"","sources":["../../../src/commands/planning/QaTasksCommand.ts"],"names":[],"mappings":"AAIA,UAAU,UAAU;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,mBAAmB,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAChD,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAYD,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,EAAE,KAAG,UA4MjD,CAAC;AAEF,qBAAa,cAAc;WACZ,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAmIhD"}
1
+ {"version":3,"file":"QaTasksCommand.d.ts","sourceRoot":"","sources":["../../../src/commands/planning/QaTasksCommand.ts"],"names":[],"mappings":"AAKA,UAAU,UAAU;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,QAAQ,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,mBAAmB,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAChD,gBAAgB,EAAE,SAAS,GAAG,QAAQ,CAAC;IACvC,eAAe,EAAE,YAAY,GAAG,MAAM,GAAG,QAAQ,CAAC;IAClD,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,KAAK,mBAAmB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAYtE,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,EAAE,KAAG,UAiOjD,CAAC;AAkBF,eAAO,MAAM,qBAAqB,GAAI,SAAS;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;CACjC,KAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAgC5C,CAAC;AAEF,qBAAa,cAAc;WACZ,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAsJhD"}
@@ -1,7 +1,8 @@
1
1
  import path from "node:path";
2
+ import { WorkspaceRepository } from "@mcoda/db";
2
3
  import { QaTasksApi, WorkspaceResolver } from "@mcoda/core";
3
4
  import { PathHelper, QA_ALLOWED_STATUSES, filterTaskStatuses } from "@mcoda/shared";
4
- const usage = `mcoda qa-tasks [--workspace-root <path>] --project <PROJECT_KEY> [--task <TASK_KEY> ... | --epic <EPIC_KEY> | --story <STORY_KEY>] [--status <STATUS_FILTER>] [--limit N] [--mode auto|manual] [--profile <PROFILE_NAME>] [--level unit|integration|acceptance] [--test-command "<CMD>"] [--agent <NAME>] [--agent-stream true|false] [--rate-agents] [--create-followup-tasks auto|none|prompt] [--result pass|fail] [--notes "<text>"] [--evidence-url "<url>"] [--resume <JOB_ID>] [--allow-dirty true|false] [--clean-ignore "<path[,path]...>"] [--dry-run] [--json]`;
5
+ const usage = `mcoda qa-tasks [--workspace-root <path>] [--project <PROJECT_KEY>] [--task <TASK_KEY> ... | --epic <EPIC_KEY> | --story <STORY_KEY>] [--status <STATUS_FILTER>] [--limit N] [--mode auto|manual] [--profile <PROFILE_NAME>] [--level unit|integration|acceptance] [--test-command "<CMD>"] [--agent <NAME>] [--agent-stream true|false] [--rate-agents] [--create-followup-tasks auto|none|prompt] [--dependency-policy enforce|ignore] [--no-changes-policy require_qa|skip|manual] [--result pass|fail] [--notes "<text>"] [--evidence-url "<url>"] [--resume <JOB_ID>] [--allow-dirty true|false] [--clean-ignore "<path[,path]...>"] [--dry-run] [--json]`;
5
6
  const parseBooleanFlag = (value, defaultValue) => {
6
7
  if (value === undefined)
7
8
  return defaultValue;
@@ -28,6 +29,8 @@ export const parseQaTasksArgs = (argv) => {
28
29
  let agentStream;
29
30
  let rateAgents = false;
30
31
  let followups = "auto";
32
+ let dependencyPolicy;
33
+ let noChangesPolicy;
31
34
  let dryRun = false;
32
35
  let json = false;
33
36
  let debug = false;
@@ -126,6 +129,23 @@ export const parseQaTasksArgs = (argv) => {
126
129
  followups = argv[i + 1] ?? "auto";
127
130
  i += 1;
128
131
  break;
132
+ case "--dependency-policy": {
133
+ const next = argv[i + 1];
134
+ if (next && !next.startsWith("--")) {
135
+ dependencyPolicy = next === "ignore" ? "ignore" : "enforce";
136
+ i += 1;
137
+ }
138
+ break;
139
+ }
140
+ case "--no-changes-policy": {
141
+ const next = argv[i + 1];
142
+ if (next && !next.startsWith("--")) {
143
+ noChangesPolicy =
144
+ next === "skip" || next === "manual" || next === "require_qa" ? next : "require_qa";
145
+ i += 1;
146
+ }
147
+ break;
148
+ }
129
149
  case "--dry-run":
130
150
  dryRun = true;
131
151
  break;
@@ -199,6 +219,8 @@ export const parseQaTasksArgs = (argv) => {
199
219
  agentStream: agentStream ?? true,
200
220
  rateAgents,
201
221
  createFollowupTasks: followups,
222
+ dependencyPolicy: dependencyPolicy ?? "enforce",
223
+ noChangesPolicy: noChangesPolicy ?? "require_qa",
202
224
  dryRun,
203
225
  json,
204
226
  debug,
@@ -212,6 +234,50 @@ export const parseQaTasksArgs = (argv) => {
212
234
  quiet,
213
235
  };
214
236
  };
237
+ const listWorkspaceProjects = async (workspaceRoot) => {
238
+ const repo = await WorkspaceRepository.create(workspaceRoot);
239
+ try {
240
+ const rows = await repo
241
+ .getDb()
242
+ .all(`SELECT key, created_at FROM projects ORDER BY created_at ASC, key ASC`);
243
+ return rows
244
+ .map((row) => ({ key: String(row.key), createdAt: row.created_at ?? null }))
245
+ .filter((row) => row.key.trim().length > 0);
246
+ }
247
+ catch {
248
+ return [];
249
+ }
250
+ finally {
251
+ await repo.close();
252
+ }
253
+ };
254
+ export const pickQaTasksProjectKey = (options) => {
255
+ const warnings = [];
256
+ const requestedKey = options.requestedKey?.trim() || undefined;
257
+ const configuredKey = options.configuredKey?.trim() || undefined;
258
+ const existing = options.existing ?? [];
259
+ const firstExisting = existing[0]?.key;
260
+ if (requestedKey) {
261
+ if (configuredKey && configuredKey !== requestedKey) {
262
+ warnings.push(`Using explicitly requested project key "${requestedKey}"; overriding configured project key "${configuredKey}".`);
263
+ }
264
+ if (firstExisting && requestedKey !== firstExisting) {
265
+ warnings.push(`Using explicitly requested project key "${requestedKey}"; first workspace project is "${firstExisting}".`);
266
+ }
267
+ return { projectKey: requestedKey, warnings };
268
+ }
269
+ if (configuredKey) {
270
+ if (firstExisting && configuredKey !== firstExisting) {
271
+ warnings.push(`Using configured project key "${configuredKey}" instead of first workspace project "${firstExisting}".`);
272
+ }
273
+ return { projectKey: configuredKey, warnings };
274
+ }
275
+ if (firstExisting) {
276
+ warnings.push(`No --project provided; defaulting to first workspace project "${firstExisting}".`);
277
+ return { projectKey: firstExisting, warnings };
278
+ }
279
+ return { projectKey: undefined, warnings };
280
+ };
215
281
  export class QaTasksCommand {
216
282
  static async run(argv) {
217
283
  const parsed = parseQaTasksArgs(argv);
@@ -243,18 +309,29 @@ export class QaTasksCommand {
243
309
  explicitWorkspace: parsed.workspaceRoot,
244
310
  noRepoWrites: true,
245
311
  });
246
- const derivedKey = path.basename(workspace.workspaceRoot).replace(/[^a-z0-9]+/gi, "").toLowerCase();
247
- const projectKey = parsed.projectKey ?? (derivedKey || undefined);
248
- if (!projectKey) {
312
+ const existingProjects = parsed.projectKey ? [] : await listWorkspaceProjects(workspace.workspaceRoot);
313
+ const configuredKey = typeof workspace.config?.projectKey === "string" && workspace.config.projectKey.trim().length > 0
314
+ ? workspace.config.projectKey
315
+ : undefined;
316
+ const projectResolution = pickQaTasksProjectKey({
317
+ requestedKey: parsed.projectKey,
318
+ configuredKey,
319
+ existing: existingProjects,
320
+ });
321
+ if (!projectResolution.projectKey) {
249
322
  // eslint-disable-next-line no-console
250
- console.error("--project is required for qa-tasks.");
323
+ console.error("qa-tasks could not resolve a project key. Provide --project <PROJECT_KEY> or create tasks for this workspace first.");
251
324
  process.exitCode = 1;
252
325
  return;
253
326
  }
327
+ if (projectResolution.warnings.length && !parsed.json && !parsed.quiet) {
328
+ // eslint-disable-next-line no-console
329
+ console.warn(projectResolution.warnings.map((warning) => `! ${warning}`).join("\n"));
330
+ }
254
331
  try {
255
332
  const result = await QaTasksApi.runQa({
256
333
  workspaceRoot: workspace.workspaceRoot,
257
- projectKey,
334
+ projectKey: projectResolution.projectKey,
258
335
  taskKeys: parsed.taskKeys,
259
336
  epicKey: parsed.epicKey,
260
337
  storyKey: parsed.storyKey,
@@ -270,6 +347,9 @@ export class QaTasksCommand {
270
347
  agentStream: parsed.agentStream,
271
348
  rateAgents: parsed.rateAgents,
272
349
  createFollowupTasks: followupMode,
350
+ dependencyPolicy: parsed.dependencyPolicy,
351
+ noChangesPolicy: parsed.noChangesPolicy,
352
+ debug: parsed.debug,
273
353
  dryRun: parsed.dryRun,
274
354
  result: parsed.result,
275
355
  notes: parsed.notes,
@@ -281,7 +361,7 @@ export class QaTasksCommand {
281
361
  if (parsed.debug && !parsed.json && !parsed.quiet) {
282
362
  // eslint-disable-next-line no-console
283
363
  console.log("[debug] options", {
284
- projectKey,
364
+ projectKey: projectResolution.projectKey,
285
365
  tasks: parsed.taskKeys,
286
366
  epicKey: parsed.epicKey,
287
367
  storyKey: parsed.storyKey,
@@ -291,6 +371,8 @@ export class QaTasksCommand {
291
371
  limit: parsed.limit,
292
372
  testCommand: parsed.testCommand,
293
373
  followups: followupMode,
374
+ dependencyPolicy: parsed.dependencyPolicy,
375
+ noChangesPolicy: parsed.noChangesPolicy,
294
376
  dryRun: parsed.dryRun,
295
377
  noTelemetry: parsed.noTelemetry,
296
378
  });
@@ -13,9 +13,23 @@ interface ParsedArgs {
13
13
  agentStream?: boolean;
14
14
  rateAgents: boolean;
15
15
  createFollowupTasks: boolean;
16
+ executionContextPolicy?: "best_effort" | "require_any" | "require_sds_or_openapi";
17
+ emptyDiffApprovalPolicy?: "ready_to_qa" | "complete";
16
18
  json: boolean;
17
19
  }
20
+ type ProjectKeyCandidate = {
21
+ key: string;
22
+ createdAt?: string | null;
23
+ };
18
24
  export declare const parseCodeReviewArgs: (argv: string[]) => ParsedArgs;
25
+ export declare const pickCodeReviewProjectKey: (options: {
26
+ requestedKey?: string;
27
+ configuredKey?: string;
28
+ existing: ProjectKeyCandidate[];
29
+ }) => {
30
+ projectKey?: string;
31
+ warnings: string[];
32
+ };
19
33
  export declare class CodeReviewCommand {
20
34
  static run(argv: string[]): Promise<void>;
21
35
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CodeReviewCommand.d.ts","sourceRoot":"","sources":["../../../src/commands/review/CodeReviewCommand.ts"],"names":[],"mappings":"AAIA,UAAU,UAAU;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,IAAI,EAAE,OAAO,CAAC;CACf;AAmCD,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,EAAE,KAAG,UAiKpD,CAAC;AAEF,qBAAa,iBAAiB;WACf,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAyFhD"}
1
+ {"version":3,"file":"CodeReviewCommand.d.ts","sourceRoot":"","sources":["../../../src/commands/review/CodeReviewCommand.ts"],"names":[],"mappings":"AAKA,UAAU,UAAU;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,sBAAsB,CAAC,EAAE,aAAa,GAAG,aAAa,GAAG,wBAAwB,CAAC;IAClF,uBAAuB,CAAC,EAAE,aAAa,GAAG,UAAU,CAAC;IACrD,IAAI,EAAE,OAAO,CAAC;CACf;AAED,KAAK,mBAAmB,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AA2DtE,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,EAAE,KAAG,UAuMpD,CAAC;AAoBF,eAAO,MAAM,wBAAwB,GAAI,SAAS;IAChD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;CACjC,KAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAkC5C,CAAC;AAEF,qBAAa,iBAAiB;WACf,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAoHhD"}