mcoda 0.1.18 → 0.1.19
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BacklogCommands.d.ts","sourceRoot":"","sources":["../../../src/commands/backlog/BacklogCommands.ts"],"names":[],"mappings":"AAIA,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,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AA6BD,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,EAAE,KAAG,UAuHjD,CAAC;
|
|
1
|
+
{"version":3,"file":"BacklogCommands.d.ts","sourceRoot":"","sources":["../../../src/commands/backlog/BacklogCommands.ts"],"names":[],"mappings":"AAIA,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,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AA6BD,eAAO,MAAM,gBAAgB,GAAI,MAAM,MAAM,EAAE,KAAG,UAuHjD,CAAC;AAqLF,qBAAa,eAAe;WACb,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CA4DhD"}
|
|
@@ -177,13 +177,17 @@ const resolveStatuses = (parsed) => {
|
|
|
177
177
|
};
|
|
178
178
|
const pad = (value, width) => value.padEnd(width, " ");
|
|
179
179
|
const formatTable = (headers, rows) => {
|
|
180
|
-
const widths = headers.map((header, idx) =>
|
|
181
|
-
|
|
182
|
-
})
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
180
|
+
const widths = headers.map((header, idx) => Math.max(header.length, ...rows.map((row) => (row[idx] ?? "").length)));
|
|
181
|
+
const border = (left, join, right) => `${left}${widths.map((width) => "─".repeat(width + 2)).join(join)}${right}`;
|
|
182
|
+
const headerLine = `│${headers.map((header, idx) => ` ${pad(header, widths[idx])} `).join("│")}│`;
|
|
183
|
+
const rowLines = rows.map((row) => `│${row.map((cell, idx) => ` ${pad(cell ?? "", widths[idx])} `).join("│")}│`);
|
|
184
|
+
return [
|
|
185
|
+
border("╭", "┬", "╮"),
|
|
186
|
+
headerLine,
|
|
187
|
+
border("├", "┼", "┤"),
|
|
188
|
+
...rowLines,
|
|
189
|
+
border("╰", "┴", "╯"),
|
|
190
|
+
].join("\n");
|
|
187
191
|
};
|
|
188
192
|
const truncate = (value, max = 100) => {
|
|
189
193
|
if (!value)
|
|
@@ -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;
|
|
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"}
|
|
@@ -168,13 +168,43 @@ export const parseEstimateArgs = (argv) => {
|
|
|
168
168
|
}
|
|
169
169
|
return parsed;
|
|
170
170
|
};
|
|
171
|
-
const
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
171
|
+
const ANSI_REGEX = /\x1b\[[0-9;]*m/g;
|
|
172
|
+
const stripAnsi = (value) => value.replace(ANSI_REGEX, "");
|
|
173
|
+
const visibleLength = (value) => stripAnsi(value).length;
|
|
174
|
+
const padVisible = (value, width) => {
|
|
175
|
+
const diff = width - visibleLength(value);
|
|
176
|
+
return diff > 0 ? `${value}${" ".repeat(diff)}` : value;
|
|
177
|
+
};
|
|
178
|
+
const colorize = (enabled, code, value) => enabled ? `\x1b[${code}m${value}\x1b[0m` : value;
|
|
179
|
+
const style = {
|
|
180
|
+
bold: (enabled, value) => colorize(enabled, 1, value),
|
|
181
|
+
dim: (enabled, value) => colorize(enabled, 2, value),
|
|
182
|
+
blue: (enabled, value) => colorize(enabled, 34, value),
|
|
183
|
+
cyan: (enabled, value) => colorize(enabled, 36, value),
|
|
184
|
+
green: (enabled, value) => colorize(enabled, 32, value),
|
|
185
|
+
yellow: (enabled, value) => colorize(enabled, 33, value),
|
|
186
|
+
magenta: (enabled, value) => colorize(enabled, 35, value),
|
|
187
|
+
red: (enabled, value) => colorize(enabled, 31, value),
|
|
188
|
+
};
|
|
189
|
+
const formatPanel = (lines) => {
|
|
190
|
+
const width = Math.max(0, ...lines.map((line) => visibleLength(line)));
|
|
191
|
+
const top = `╭${"─".repeat(width + 2)}╮`;
|
|
192
|
+
const body = lines.map((line) => `│ ${padVisible(line, width)} │`);
|
|
193
|
+
const bottom = `╰${"─".repeat(width + 2)}╯`;
|
|
194
|
+
return [top, ...body, bottom].join("\n");
|
|
195
|
+
};
|
|
196
|
+
const formatBoxTable = (headers, rows) => {
|
|
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("│")}│`);
|
|
201
|
+
return [
|
|
202
|
+
border("╭", "┬", "╮"),
|
|
203
|
+
headerLine,
|
|
204
|
+
border("├", "┼", "┤"),
|
|
205
|
+
...rowLines,
|
|
206
|
+
border("╰", "┴", "╯"),
|
|
207
|
+
].join("\n");
|
|
178
208
|
};
|
|
179
209
|
const fmt = (value) => {
|
|
180
210
|
if (value === null || value === undefined)
|
|
@@ -249,7 +279,57 @@ const formatEtaCell = (eta) => {
|
|
|
249
279
|
const relative = formatRelativeDuration(date.getTime(), Date.now());
|
|
250
280
|
return `${eta} (local ${local}, ${relative})`;
|
|
251
281
|
};
|
|
252
|
-
const
|
|
282
|
+
const createBar = (percentValue, theme) => {
|
|
283
|
+
const percent = Math.max(0, Math.min(100, Number.isFinite(percentValue) ? percentValue : 0));
|
|
284
|
+
const rounded = Math.round(percent);
|
|
285
|
+
const width = 10;
|
|
286
|
+
if (rounded <= 0) {
|
|
287
|
+
return theme.empty("░".repeat(width));
|
|
288
|
+
}
|
|
289
|
+
if (rounded >= 100) {
|
|
290
|
+
return theme.full("█".repeat(width));
|
|
291
|
+
}
|
|
292
|
+
const fullCount = Math.min(width - 1, Math.floor((rounded / 100) * width));
|
|
293
|
+
const partialCount = 1;
|
|
294
|
+
const emptyCount = Math.max(0, width - fullCount - partialCount);
|
|
295
|
+
return `${theme.full("█".repeat(fullCount))}${theme.partial("▒".repeat(partialCount))}${theme.empty("░".repeat(emptyCount))}`;
|
|
296
|
+
};
|
|
297
|
+
const renderProgressSection = (result, colorEnabled) => {
|
|
298
|
+
const work = result.completion.workOnTasks;
|
|
299
|
+
const qa = result.completion.readyToQa;
|
|
300
|
+
const done = result.completion.done;
|
|
301
|
+
const labels = [
|
|
302
|
+
"🛠️ Work on tasks",
|
|
303
|
+
"🧪 Ready to qa",
|
|
304
|
+
"✅ Done",
|
|
305
|
+
];
|
|
306
|
+
const maxLabel = Math.max(...labels.map((label) => visibleLength(label)));
|
|
307
|
+
const formatLine = (label, metric, theme) => {
|
|
308
|
+
const bar = createBar(metric.percent, theme);
|
|
309
|
+
const percent = `${Math.round(metric.percent)}%`;
|
|
310
|
+
return `${padVisible(label, maxLabel)} : ${bar} ${percent} (${metric.done}/${metric.total})`;
|
|
311
|
+
};
|
|
312
|
+
return formatPanel([
|
|
313
|
+
style.bold(colorEnabled, "📊 Completion"),
|
|
314
|
+
formatLine("🛠️ Work on tasks", work, {
|
|
315
|
+
full: (value) => style.cyan(colorEnabled, value),
|
|
316
|
+
partial: (value) => style.blue(colorEnabled, value),
|
|
317
|
+
empty: (value) => style.dim(colorEnabled, value),
|
|
318
|
+
}),
|
|
319
|
+
formatLine("🧪 Ready to qa", qa, {
|
|
320
|
+
full: (value) => style.yellow(colorEnabled, value),
|
|
321
|
+
partial: (value) => style.magenta(colorEnabled, value),
|
|
322
|
+
empty: (value) => style.dim(colorEnabled, value),
|
|
323
|
+
}),
|
|
324
|
+
formatLine("✅ Done", done, {
|
|
325
|
+
full: (value) => style.green(colorEnabled, value),
|
|
326
|
+
partial: (value) => style.yellow(colorEnabled, value),
|
|
327
|
+
empty: (value) => style.dim(colorEnabled, value),
|
|
328
|
+
}),
|
|
329
|
+
]);
|
|
330
|
+
};
|
|
331
|
+
const renderResult = (result, options) => {
|
|
332
|
+
const { colorEnabled } = options;
|
|
253
333
|
const velocity = result.effectiveVelocity;
|
|
254
334
|
const source = velocity.source;
|
|
255
335
|
const spHeader = `SP/H (${source})`;
|
|
@@ -290,28 +370,58 @@ const renderResult = (result) => {
|
|
|
290
370
|
],
|
|
291
371
|
];
|
|
292
372
|
// eslint-disable-next-line no-console
|
|
293
|
-
console.log(
|
|
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
|
+
]));
|
|
382
|
+
const counts = result.statusCounts;
|
|
383
|
+
// eslint-disable-next-line no-console
|
|
384
|
+
console.log(formatPanel([
|
|
385
|
+
style.bold(colorEnabled, "📌 Task Status"),
|
|
386
|
+
`${style.bold(colorEnabled, "Total tasks")} : ${counts.total}`,
|
|
387
|
+
`${style.cyan(colorEnabled, "Ready to code review")} : ${counts.readyToCodeReview}`,
|
|
388
|
+
`${style.yellow(colorEnabled, "Ready to qa")} : ${counts.readyToQa}`,
|
|
389
|
+
`${style.blue(colorEnabled, "In progress")} : ${counts.inProgress}`,
|
|
390
|
+
`${style.red(colorEnabled, "Failed")} : ${counts.failed}`,
|
|
391
|
+
`${style.green(colorEnabled, "Completed")} : ${counts.completed}`,
|
|
392
|
+
]));
|
|
393
|
+
// eslint-disable-next-line no-console
|
|
394
|
+
console.log(renderProgressSection(result, colorEnabled));
|
|
294
395
|
const samples = velocity.samples ?? { implementation: 0, review: 0, qa: 0 };
|
|
295
396
|
const windowLabel = velocity.windowTasks ? ` (window ${velocity.windowTasks})` : "";
|
|
296
397
|
const fallbackNote = velocity.requestedMode && velocity.requestedMode !== velocity.source
|
|
297
398
|
? ` (requested ${velocity.requestedMode}; no empirical samples, using config)`
|
|
298
399
|
: "";
|
|
299
400
|
// eslint-disable-next-line no-console
|
|
300
|
-
console.log(
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
401
|
+
console.log(formatPanel([
|
|
402
|
+
style.bold(colorEnabled, "📈 Velocity"),
|
|
403
|
+
`${style.bold(colorEnabled, "Velocity source")} : ${velocity.source}${fallbackNote}`,
|
|
404
|
+
`${style.bold(colorEnabled, "Samples")}${windowLabel} : impl=${samples.implementation ?? 0}, review=${samples.review ?? 0}, qa=${samples.qa ?? 0}`,
|
|
405
|
+
]));
|
|
305
406
|
// eslint-disable-next-line no-console
|
|
306
|
-
console.log(
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
+
]),
|
|
312
420
|
]));
|
|
313
421
|
// eslint-disable-next-line no-console
|
|
314
|
-
console.log(
|
|
422
|
+
console.log(formatPanel([
|
|
423
|
+
`${style.bold(colorEnabled, "ℹ️ Assumptions")} : lane work runs in parallel; total hours uses the longest lane.`,
|
|
424
|
+
]));
|
|
315
425
|
};
|
|
316
426
|
export class EstimateCommands {
|
|
317
427
|
static async run(argv) {
|
|
@@ -346,17 +456,19 @@ export class EstimateCommands {
|
|
|
346
456
|
console.log(JSON.stringify(result, null, 2));
|
|
347
457
|
}
|
|
348
458
|
else if (!parsed.quiet) {
|
|
459
|
+
const colorEnabled = !parsed.noColor;
|
|
349
460
|
const totalTasks = result.backlogTotals.implementation.tasks +
|
|
350
461
|
result.backlogTotals.review.tasks +
|
|
351
462
|
result.backlogTotals.qa.tasks +
|
|
352
463
|
result.backlogTotals.done.tasks;
|
|
464
|
+
const scopeText = `project=${parsed.project ?? "all"}${parsed.epic ? `, epic=${parsed.epic}` : ""}${parsed.story ? `, story=${parsed.story}` : ""}${parsed.assignee ? `, assignee=${parsed.assignee}` : ""}`;
|
|
353
465
|
// eslint-disable-next-line no-console
|
|
354
|
-
console.log(
|
|
466
|
+
console.log(formatPanel([`${style.bold(colorEnabled, "🧭 Scope")} : ${scopeText}`]));
|
|
355
467
|
if (totalTasks === 0) {
|
|
356
468
|
// eslint-disable-next-line no-console
|
|
357
|
-
console.log("No tasks found in the selected scope. Showing zeroed estimate.");
|
|
469
|
+
console.log(formatPanel([style.yellow(colorEnabled, "No tasks found in the selected scope. Showing zeroed estimate.")]));
|
|
358
470
|
}
|
|
359
|
-
renderResult(result);
|
|
471
|
+
renderResult(result, { colorEnabled });
|
|
360
472
|
}
|
|
361
473
|
}
|
|
362
474
|
catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcoda",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"description": "Local-first CLI for planning, documentation, and execution workflows with agent assistance.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -45,12 +45,12 @@
|
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
47
|
"yaml": "^2.4.2",
|
|
48
|
-
"@mcoda/core": "0.1.
|
|
49
|
-
"@mcoda/shared": "0.1.
|
|
48
|
+
"@mcoda/core": "0.1.19",
|
|
49
|
+
"@mcoda/shared": "0.1.19"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@mcoda/
|
|
53
|
-
"@mcoda/
|
|
52
|
+
"@mcoda/db": "0.1.19",
|
|
53
|
+
"@mcoda/integrations": "0.1.19"
|
|
54
54
|
},
|
|
55
55
|
"scripts": {
|
|
56
56
|
"build": "tsc -p tsconfig.json",
|