mcoda 0.1.16 → 0.1.18
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.
|
@@ -18,6 +18,7 @@ interface ParsedArgs {
|
|
|
18
18
|
debug: boolean;
|
|
19
19
|
}
|
|
20
20
|
export declare const parseEstimateArgs: (argv: string[]) => ParsedArgs;
|
|
21
|
+
export declare const formatTimeLeft: (hours: number | null | undefined) => string;
|
|
21
22
|
export declare class EstimateCommands {
|
|
22
23
|
static run(argv: string[]): Promise<void>;
|
|
23
24
|
}
|
|
@@ -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,
|
|
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;AAkBF,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,GAAG,IAAI,GAAG,SAAS,KAAG,MAwBjE,CAAC;AA4HF,qBAAa,gBAAgB;WACd,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAgEhD"}
|
|
@@ -34,6 +34,8 @@ export const parseEstimateArgs = (argv) => {
|
|
|
34
34
|
quiet: false,
|
|
35
35
|
noColor: false,
|
|
36
36
|
noTelemetry: false,
|
|
37
|
+
velocityMode: "empirical",
|
|
38
|
+
velocityWindow: 50,
|
|
37
39
|
};
|
|
38
40
|
for (let i = 0; i < argv.length; i += 1) {
|
|
39
41
|
const arg = argv[i];
|
|
@@ -87,7 +89,12 @@ export const parseEstimateArgs = (argv) => {
|
|
|
87
89
|
i += 1;
|
|
88
90
|
break;
|
|
89
91
|
case "--velocity-mode":
|
|
90
|
-
|
|
92
|
+
{
|
|
93
|
+
const mode = parseVelocityMode(argv[i + 1]);
|
|
94
|
+
if (mode) {
|
|
95
|
+
parsed.velocityMode = mode;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
91
98
|
i += 1;
|
|
92
99
|
break;
|
|
93
100
|
case "--velocity-window":
|
|
@@ -133,7 +140,10 @@ export const parseEstimateArgs = (argv) => {
|
|
|
133
140
|
parsed.assignee = arg.split("=")[1];
|
|
134
141
|
}
|
|
135
142
|
else if (arg.startsWith("--velocity-mode=")) {
|
|
136
|
-
|
|
143
|
+
const mode = parseVelocityMode(arg.split("=")[1]);
|
|
144
|
+
if (mode) {
|
|
145
|
+
parsed.velocityMode = mode;
|
|
146
|
+
}
|
|
137
147
|
}
|
|
138
148
|
else if (arg.startsWith("--velocity-window=") || arg.startsWith("--window=")) {
|
|
139
149
|
const value = parseNumber(arg.split("=")[1]);
|
|
@@ -173,6 +183,32 @@ const fmt = (value) => {
|
|
|
173
183
|
return `${value}`;
|
|
174
184
|
return value.toFixed(2);
|
|
175
185
|
};
|
|
186
|
+
export const formatTimeLeft = (hours) => {
|
|
187
|
+
if (hours === null || hours === undefined)
|
|
188
|
+
return "N/A";
|
|
189
|
+
if (!Number.isFinite(hours) || hours <= 0)
|
|
190
|
+
return "0h";
|
|
191
|
+
let remainingHours = Math.max(1, Math.round(hours));
|
|
192
|
+
const monthHours = 24 * 30;
|
|
193
|
+
const weekHours = 24 * 7;
|
|
194
|
+
const dayHours = 24;
|
|
195
|
+
const months = Math.floor(remainingHours / monthHours);
|
|
196
|
+
remainingHours -= months * monthHours;
|
|
197
|
+
const weeks = Math.floor(remainingHours / weekHours);
|
|
198
|
+
remainingHours -= weeks * weekHours;
|
|
199
|
+
const days = Math.floor(remainingHours / dayHours);
|
|
200
|
+
remainingHours -= days * dayHours;
|
|
201
|
+
const parts = [];
|
|
202
|
+
if (months > 0)
|
|
203
|
+
parts.push(`${months}mo`);
|
|
204
|
+
if (weeks > 0)
|
|
205
|
+
parts.push(`${weeks}w`);
|
|
206
|
+
if (days > 0)
|
|
207
|
+
parts.push(`${days}d`);
|
|
208
|
+
if (remainingHours > 0 || parts.length === 0)
|
|
209
|
+
parts.push(`${remainingHours}h`);
|
|
210
|
+
return parts.join("");
|
|
211
|
+
};
|
|
176
212
|
const pad2 = (value) => `${value}`.padStart(2, "0");
|
|
177
213
|
const formatLocalDateTime = (date) => `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())} ${pad2(date.getHours())}:${pad2(date.getMinutes())}`;
|
|
178
214
|
const formatRelativeDuration = (targetMs, nowMs) => {
|
|
@@ -226,35 +262,35 @@ const renderResult = (result) => {
|
|
|
226
262
|
"Implementation",
|
|
227
263
|
fmt(result.backlogTotals.implementation.story_points),
|
|
228
264
|
fmt(result.effectiveVelocity.implementationSpPerHour),
|
|
229
|
-
|
|
265
|
+
formatTimeLeft(result.durationsHours.implementationHours),
|
|
230
266
|
],
|
|
231
267
|
[
|
|
232
268
|
"Review",
|
|
233
269
|
fmt(result.backlogTotals.review.story_points),
|
|
234
270
|
fmt(result.effectiveVelocity.reviewSpPerHour),
|
|
235
|
-
|
|
271
|
+
formatTimeLeft(result.durationsHours.reviewHours),
|
|
236
272
|
],
|
|
237
273
|
[
|
|
238
274
|
"QA",
|
|
239
275
|
fmt(result.backlogTotals.qa.story_points),
|
|
240
276
|
fmt(result.effectiveVelocity.qaSpPerHour),
|
|
241
|
-
|
|
277
|
+
formatTimeLeft(result.durationsHours.qaHours),
|
|
242
278
|
],
|
|
243
279
|
[
|
|
244
280
|
"Done",
|
|
245
281
|
fmt(result.backlogTotals.done.story_points),
|
|
246
282
|
fmt(null),
|
|
247
|
-
|
|
283
|
+
formatTimeLeft(0),
|
|
248
284
|
],
|
|
249
285
|
[
|
|
250
286
|
"Total",
|
|
251
287
|
fmt(totalSp),
|
|
252
288
|
fmt(null),
|
|
253
|
-
|
|
289
|
+
formatTimeLeft(result.durationsHours.totalHours),
|
|
254
290
|
],
|
|
255
291
|
];
|
|
256
292
|
// eslint-disable-next-line no-console
|
|
257
|
-
console.log(formatTable(["LANE", "STORY_POINTS", spHeader, "
|
|
293
|
+
console.log(formatTable(["LANE", "STORY_POINTS", spHeader, "TIME_LEFT"], rows));
|
|
258
294
|
const samples = velocity.samples ?? { implementation: 0, review: 0, qa: 0 };
|
|
259
295
|
const windowLabel = velocity.windowTasks ? ` (window ${velocity.windowTasks})` : "";
|
|
260
296
|
const fallbackNote = velocity.requestedMode && velocity.requestedMode !== velocity.source
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcoda",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
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.18",
|
|
49
|
+
"@mcoda/shared": "0.1.18"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@mcoda/integrations": "0.1.
|
|
53
|
-
"@mcoda/db": "0.1.
|
|
52
|
+
"@mcoda/integrations": "0.1.18",
|
|
53
|
+
"@mcoda/db": "0.1.18"
|
|
54
54
|
},
|
|
55
55
|
"scripts": {
|
|
56
56
|
"build": "tsc -p tsconfig.json",
|