@hyperdrive.bot/bmad-workflow 1.0.17 → 1.0.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.
- package/dist/commands/config/show.js +8 -2
- package/dist/commands/decompose.js +26 -5
- package/dist/commands/epics/create.d.ts +1 -0
- package/dist/commands/mcp/add.d.ts +16 -0
- package/dist/commands/mcp/add.js +77 -0
- package/dist/commands/mcp/credential/get.d.ts +14 -0
- package/dist/commands/mcp/credential/get.js +35 -0
- package/dist/commands/mcp/credential/list.d.ts +17 -0
- package/dist/commands/mcp/credential/list.js +67 -0
- package/dist/commands/mcp/credential/remove.d.ts +18 -0
- package/dist/commands/mcp/credential/remove.js +84 -0
- package/dist/commands/mcp/credential/set.d.ts +16 -0
- package/dist/commands/mcp/credential/set.js +41 -0
- package/dist/commands/mcp/credential/validate.d.ts +12 -0
- package/dist/commands/mcp/credential/validate.js +150 -0
- package/dist/commands/mcp/list.d.ts +17 -0
- package/dist/commands/mcp/list.js +80 -0
- package/dist/commands/mcp/logs.d.ts +15 -0
- package/dist/commands/mcp/logs.js +64 -0
- package/dist/commands/mcp/preset.d.ts +15 -0
- package/dist/commands/mcp/preset.js +84 -0
- package/dist/commands/mcp/remove.d.ts +14 -0
- package/dist/commands/mcp/remove.js +36 -0
- package/dist/commands/mcp/start.d.ts +12 -0
- package/dist/commands/mcp/start.js +80 -0
- package/dist/commands/mcp/status.d.ts +30 -0
- package/dist/commands/mcp/status.js +180 -0
- package/dist/commands/mcp/stop.d.ts +12 -0
- package/dist/commands/mcp/stop.js +47 -0
- package/dist/commands/stories/create.d.ts +1 -0
- package/dist/commands/stories/develop.d.ts +1 -0
- package/dist/commands/stories/qa.js +34 -75
- package/dist/commands/stories/review.d.ts +124 -0
- package/dist/commands/stories/review.js +516 -0
- package/dist/commands/workflow.d.ts +89 -0
- package/dist/commands/workflow.js +487 -14
- package/dist/mcp/types.d.ts +99 -0
- package/dist/mcp/types.js +7 -0
- package/dist/mcp/utils/docker-utils.d.ts +56 -0
- package/dist/mcp/utils/docker-utils.js +108 -0
- package/dist/mcp/utils/template-loader.d.ts +21 -0
- package/dist/mcp/utils/template-loader.js +60 -0
- package/dist/models/agent-options.d.ts +10 -1
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +1 -0
- package/dist/models/workflow-callbacks.d.ts +251 -0
- package/dist/models/workflow-callbacks.js +10 -0
- package/dist/models/workflow-config.d.ts +77 -0
- package/dist/models/workflow-result.d.ts +7 -0
- package/dist/services/WorkflowReporter.d.ts +165 -0
- package/dist/services/WorkflowReporter.js +691 -0
- package/dist/services/agents/claude-agent-runner.js +25 -4
- package/dist/services/file-system/path-resolver.d.ts +10 -0
- package/dist/services/file-system/path-resolver.js +12 -0
- package/dist/services/mcp/mcp-config-manager.d.ts +54 -0
- package/dist/services/mcp/mcp-config-manager.js +146 -0
- package/dist/services/mcp/mcp-context-injector.d.ts +92 -0
- package/dist/services/mcp/mcp-context-injector.js +168 -0
- package/dist/services/mcp/mcp-credential-manager.d.ts +48 -0
- package/dist/services/mcp/mcp-credential-manager.js +124 -0
- package/dist/services/mcp/mcp-health-checker.d.ts +56 -0
- package/dist/services/mcp/mcp-health-checker.js +162 -0
- package/dist/services/mcp/types/health-types.d.ts +31 -0
- package/dist/services/mcp/types/health-types.js +7 -0
- package/dist/services/orchestration/dependency-graph-executor.js +1 -1
- package/dist/services/orchestration/task-decomposition-service.d.ts +2 -1
- package/dist/services/orchestration/task-decomposition-service.js +90 -36
- package/dist/services/orchestration/workflow-orchestrator.d.ts +87 -3
- package/dist/services/orchestration/workflow-orchestrator.js +1169 -289
- package/dist/services/review/ai-review-scanner.d.ts +66 -0
- package/dist/services/review/ai-review-scanner.js +142 -0
- package/dist/services/review/coderabbit-scanner.d.ts +25 -0
- package/dist/services/review/coderabbit-scanner.js +31 -0
- package/dist/services/review/index.d.ts +20 -0
- package/dist/services/review/index.js +15 -0
- package/dist/services/review/lint-scanner.d.ts +46 -0
- package/dist/services/review/lint-scanner.js +172 -0
- package/dist/services/review/review-config.d.ts +62 -0
- package/dist/services/review/review-config.js +91 -0
- package/dist/services/review/review-phase-executor.d.ts +69 -0
- package/dist/services/review/review-phase-executor.js +152 -0
- package/dist/services/review/review-queue.d.ts +98 -0
- package/dist/services/review/review-queue.js +174 -0
- package/dist/services/review/review-reporter.d.ts +94 -0
- package/dist/services/review/review-reporter.js +386 -0
- package/dist/services/review/scanner-factory.d.ts +42 -0
- package/dist/services/review/scanner-factory.js +60 -0
- package/dist/services/review/self-heal-loop.d.ts +58 -0
- package/dist/services/review/self-heal-loop.js +132 -0
- package/dist/services/review/severity-classifier.d.ts +17 -0
- package/dist/services/review/severity-classifier.js +314 -0
- package/dist/services/review/tech-debt-tracker.d.ts +52 -0
- package/dist/services/review/tech-debt-tracker.js +245 -0
- package/dist/services/review/types.d.ts +93 -0
- package/dist/services/review/types.js +23 -0
- package/dist/services/scaffolding/workflow-session-scaffolder.d.ts +182 -0
- package/dist/services/scaffolding/workflow-session-scaffolder.js +236 -0
- package/dist/services/validation/config-validator.d.ts +84 -0
- package/dist/services/validation/config-validator.js +78 -0
- package/dist/utils/colors.d.ts +10 -10
- package/dist/utils/colors.js +15 -15
- package/dist/utils/credential-utils.d.ts +14 -0
- package/dist/utils/credential-utils.js +19 -0
- package/dist/utils/duration.d.ts +41 -0
- package/dist/utils/duration.js +89 -0
- package/dist/utils/listr2-helpers.d.ts +216 -0
- package/dist/utils/listr2-helpers.js +334 -0
- package/dist/utils/shared-flags.d.ts +1 -0
- package/dist/utils/shared-flags.js +11 -2
- package/package.json +6 -3
|
@@ -7,6 +7,77 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { z } from 'zod';
|
|
9
9
|
import { ValidationError } from '../../utils/errors.js';
|
|
10
|
+
/**
|
|
11
|
+
* Valid scanner identifiers for automated code review
|
|
12
|
+
*/
|
|
13
|
+
const VALID_SCANNERS = ['ai', 'lint', 'coderabbit'];
|
|
14
|
+
/**
|
|
15
|
+
* Valid severity levels
|
|
16
|
+
*/
|
|
17
|
+
const VALID_SEVERITIES = ['CRITICAL', 'HIGH', 'MEDIUM', 'LOW'];
|
|
18
|
+
/**
|
|
19
|
+
* Zod schema for review.severity configuration
|
|
20
|
+
*/
|
|
21
|
+
const severityArraySchema = z.array(z.enum(VALID_SEVERITIES, {
|
|
22
|
+
message: `Invalid severity level. Valid values: ${VALID_SEVERITIES.join(', ')}`,
|
|
23
|
+
}));
|
|
24
|
+
/**
|
|
25
|
+
* Zod schema for review.pathRules entries
|
|
26
|
+
*/
|
|
27
|
+
const pathRuleSchema = z.object({
|
|
28
|
+
focus: z.string().min(1, { message: 'Path rule focus description is required' }),
|
|
29
|
+
pattern: z.string().min(1, { message: 'Path rule pattern is required' }),
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* Zod schema for review configuration section
|
|
33
|
+
*
|
|
34
|
+
* Defines scanners, severity thresholds, self-heal limits, and path rules
|
|
35
|
+
* for automated code review in the BMAD workflow pipeline.
|
|
36
|
+
*/
|
|
37
|
+
export const reviewConfigSchema = z
|
|
38
|
+
.object({
|
|
39
|
+
enabled: z.boolean().default(false),
|
|
40
|
+
pathRules: z.array(pathRuleSchema).optional(),
|
|
41
|
+
scanners: z
|
|
42
|
+
.array(z.enum(VALID_SCANNERS, {
|
|
43
|
+
message: `Unknown scanner name. Valid values: ${VALID_SCANNERS.join(', ')}`,
|
|
44
|
+
}))
|
|
45
|
+
.default(['ai', 'lint']),
|
|
46
|
+
selfHeal: z
|
|
47
|
+
.object({
|
|
48
|
+
fixAgent: z.string().default('dev'),
|
|
49
|
+
fixTimeout: z.number().int().positive({ message: 'selfHeal.fixTimeout must be a positive integer' }).default(300_000),
|
|
50
|
+
maxIterations: z
|
|
51
|
+
.number()
|
|
52
|
+
.int()
|
|
53
|
+
.positive({ message: 'selfHeal.maxIterations must be a positive integer' })
|
|
54
|
+
.default(3),
|
|
55
|
+
})
|
|
56
|
+
.default(() => ({ fixAgent: 'dev', fixTimeout: 300_000, maxIterations: 3 })),
|
|
57
|
+
severity: z
|
|
58
|
+
.object({
|
|
59
|
+
blockOn: severityArraySchema.default(['CRITICAL', 'HIGH']),
|
|
60
|
+
documentOn: severityArraySchema.default(['MEDIUM']),
|
|
61
|
+
ignoreOn: severityArraySchema.default(['LOW']),
|
|
62
|
+
})
|
|
63
|
+
.default(() => ({
|
|
64
|
+
blockOn: ['CRITICAL', 'HIGH'],
|
|
65
|
+
documentOn: ['MEDIUM'],
|
|
66
|
+
ignoreOn: ['LOW'],
|
|
67
|
+
})),
|
|
68
|
+
})
|
|
69
|
+
.superRefine((data, ctx) => {
|
|
70
|
+
// Validate that blockOn and ignoreOn do not overlap
|
|
71
|
+
const blockSet = new Set(data.severity.blockOn);
|
|
72
|
+
const overlapping = data.severity.ignoreOn.filter((s) => blockSet.has(s));
|
|
73
|
+
if (overlapping.length > 0) {
|
|
74
|
+
ctx.addIssue({
|
|
75
|
+
code: z.ZodIssueCode.custom,
|
|
76
|
+
message: `severity.blockOn and severity.ignoreOn must not overlap. Overlapping: ${overlapping.join(', ')}`,
|
|
77
|
+
path: ['severity'],
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
});
|
|
10
81
|
/**
|
|
11
82
|
* Zod schema for core configuration
|
|
12
83
|
*
|
|
@@ -25,6 +96,7 @@ const configSchema = z.object({
|
|
|
25
96
|
qaLocation: z.string().optional(),
|
|
26
97
|
})
|
|
27
98
|
.optional(),
|
|
99
|
+
review: reviewConfigSchema.optional(),
|
|
28
100
|
});
|
|
29
101
|
/**
|
|
30
102
|
* ConfigValidator service validates configuration files against schemas
|
|
@@ -105,11 +177,17 @@ export class ConfigValidator {
|
|
|
105
177
|
devStoryLocation: 'docs/stories',
|
|
106
178
|
'prd.prdFile': 'docs/prd.md',
|
|
107
179
|
'qa.qaLocation': 'docs/qa',
|
|
180
|
+
'review.scanners': '[ai, lint]',
|
|
181
|
+
'review.severity.blockOn': '[CRITICAL, HIGH]',
|
|
182
|
+
'review.selfHeal.maxIterations': '3',
|
|
108
183
|
};
|
|
109
184
|
const fieldDisplayNames = {
|
|
110
185
|
devStoryLocation: 'Story directory path (devStoryLocation)',
|
|
111
186
|
'prd.prdFile': 'PRD file path (prd.prdFile)',
|
|
112
187
|
'qa.qaLocation': 'QA location path (qa.qaLocation)',
|
|
188
|
+
'review.scanners': 'Review scanners (review.scanners)',
|
|
189
|
+
'review.severity.blockOn': 'Review severity blockOn (review.severity.blockOn)',
|
|
190
|
+
'review.selfHeal.maxIterations': 'Self-heal max iterations (review.selfHeal.maxIterations)',
|
|
113
191
|
};
|
|
114
192
|
const example = examples[fieldName] || 'path/to/directory';
|
|
115
193
|
const displayName = fieldDisplayNames[fieldName] || fieldName;
|
package/dist/utils/colors.d.ts
CHANGED
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Format a success message with
|
|
2
|
+
* Format a success message with checkmark icon
|
|
3
3
|
*
|
|
4
4
|
* @param text - Message text to format
|
|
5
|
-
* @returns Formatted string with
|
|
5
|
+
* @returns Formatted string with ✓ icon
|
|
6
6
|
*/
|
|
7
7
|
export declare const success: (text: string) => string;
|
|
8
8
|
/**
|
|
9
|
-
* Format an error message with
|
|
9
|
+
* Format an error message with X icon
|
|
10
10
|
*
|
|
11
11
|
* @param text - Message text to format
|
|
12
|
-
* @returns Formatted string with
|
|
12
|
+
* @returns Formatted string with ✗ icon
|
|
13
13
|
*/
|
|
14
14
|
export declare const error: (text: string) => string;
|
|
15
15
|
/**
|
|
16
|
-
* Format a warning message with
|
|
16
|
+
* Format a warning message with warning icon
|
|
17
17
|
*
|
|
18
18
|
* @param text - Message text to format
|
|
19
|
-
* @returns Formatted string with
|
|
19
|
+
* @returns Formatted string with ⚠ icon
|
|
20
20
|
*/
|
|
21
21
|
export declare const warning: (text: string) => string;
|
|
22
22
|
/**
|
|
23
|
-
* Format an info message with
|
|
23
|
+
* Format an info message with info icon
|
|
24
24
|
*
|
|
25
25
|
* @param text - Message text to format
|
|
26
|
-
* @returns Formatted string with
|
|
26
|
+
* @returns Formatted string with ℹ icon
|
|
27
27
|
*/
|
|
28
28
|
export declare const info: (text: string) => string;
|
|
29
29
|
/**
|
|
30
|
-
* Highlight text
|
|
30
|
+
* Highlight text for emphasis
|
|
31
31
|
*
|
|
32
32
|
* @param text - Text to highlight
|
|
33
|
-
* @returns Formatted string with ANSI
|
|
33
|
+
* @returns Formatted string with ANSI bold codes
|
|
34
34
|
*/
|
|
35
35
|
export declare const highlight: (text: string) => string;
|
|
36
36
|
/**
|
package/dist/utils/colors.js
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
/**
|
|
3
|
-
* Format a success message with
|
|
3
|
+
* Format a success message with checkmark icon
|
|
4
4
|
*
|
|
5
5
|
* @param text - Message text to format
|
|
6
|
-
* @returns Formatted string with
|
|
6
|
+
* @returns Formatted string with ✓ icon
|
|
7
7
|
*/
|
|
8
|
-
export const success = (text) => chalk.
|
|
8
|
+
export const success = (text) => chalk.bold(`✓ ${text}`);
|
|
9
9
|
/**
|
|
10
|
-
* Format an error message with
|
|
10
|
+
* Format an error message with X icon
|
|
11
11
|
*
|
|
12
12
|
* @param text - Message text to format
|
|
13
|
-
* @returns Formatted string with
|
|
13
|
+
* @returns Formatted string with ✗ icon
|
|
14
14
|
*/
|
|
15
|
-
export const error = (text) => chalk.
|
|
15
|
+
export const error = (text) => chalk.bold(`✗ ${text}`);
|
|
16
16
|
/**
|
|
17
|
-
* Format a warning message with
|
|
17
|
+
* Format a warning message with warning icon
|
|
18
18
|
*
|
|
19
19
|
* @param text - Message text to format
|
|
20
|
-
* @returns Formatted string with
|
|
20
|
+
* @returns Formatted string with ⚠ icon
|
|
21
21
|
*/
|
|
22
|
-
export const warning = (text) => chalk.
|
|
22
|
+
export const warning = (text) => chalk.bold(`⚠ ${text}`);
|
|
23
23
|
/**
|
|
24
|
-
* Format an info message with
|
|
24
|
+
* Format an info message with info icon
|
|
25
25
|
*
|
|
26
26
|
* @param text - Message text to format
|
|
27
|
-
* @returns Formatted string with
|
|
27
|
+
* @returns Formatted string with ℹ icon
|
|
28
28
|
*/
|
|
29
|
-
export const info = (text) =>
|
|
29
|
+
export const info = (text) => `ℹ ${text}`;
|
|
30
30
|
/**
|
|
31
|
-
* Highlight text
|
|
31
|
+
* Highlight text for emphasis
|
|
32
32
|
*
|
|
33
33
|
* @param text - Text to highlight
|
|
34
|
-
* @returns Formatted string with ANSI
|
|
34
|
+
* @returns Formatted string with ANSI bold codes
|
|
35
35
|
*/
|
|
36
|
-
export const highlight = (text) => chalk.
|
|
36
|
+
export const highlight = (text) => chalk.bold(text);
|
|
37
37
|
/**
|
|
38
38
|
* Format text in bold style
|
|
39
39
|
*
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential utility functions
|
|
3
|
+
*
|
|
4
|
+
* Shared helpers for credential display masking.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Mask a credential value for display.
|
|
8
|
+
* Shows first 3 chars + '***...***' + last 3 chars.
|
|
9
|
+
* For values shorter than 8 chars, mask entirely as '***'.
|
|
10
|
+
*
|
|
11
|
+
* @param value - The raw credential value
|
|
12
|
+
* @returns Masked string safe for display
|
|
13
|
+
*/
|
|
14
|
+
export declare function maskValue(value: string): string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential utility functions
|
|
3
|
+
*
|
|
4
|
+
* Shared helpers for credential display masking.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Mask a credential value for display.
|
|
8
|
+
* Shows first 3 chars + '***...***' + last 3 chars.
|
|
9
|
+
* For values shorter than 8 chars, mask entirely as '***'.
|
|
10
|
+
*
|
|
11
|
+
* @param value - The raw credential value
|
|
12
|
+
* @returns Masked string safe for display
|
|
13
|
+
*/
|
|
14
|
+
export function maskValue(value) {
|
|
15
|
+
if (value.length < 8) {
|
|
16
|
+
return '***';
|
|
17
|
+
}
|
|
18
|
+
return `${value.slice(0, 3)}***...***${value.slice(-3)}`;
|
|
19
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Duration Parsing Utility
|
|
3
|
+
*
|
|
4
|
+
* Parses human-readable duration strings (e.g., "30s", "5m", "1h", "90m")
|
|
5
|
+
* into milliseconds. Also accepts raw millisecond numbers for backward
|
|
6
|
+
* compatibility with existing --timeout flag usage.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* parseDuration('30s') // 30_000
|
|
11
|
+
* parseDuration('5m') // 300_000
|
|
12
|
+
* parseDuration('45m') // 2_700_000
|
|
13
|
+
* parseDuration('1h') // 3_600_000
|
|
14
|
+
* parseDuration('1.5h') // 5_400_000
|
|
15
|
+
* parseDuration('2700000') // 2_700_000 (raw ms, backward compat)
|
|
16
|
+
* parseDuration(2700000) // 2_700_000 (numeric passthrough)
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Parse a duration string or number into milliseconds.
|
|
21
|
+
*
|
|
22
|
+
* Accepted formats:
|
|
23
|
+
* - `"30s"` — seconds
|
|
24
|
+
* - `"5m"` — minutes
|
|
25
|
+
* - `"1h"` — hours
|
|
26
|
+
* - `"1.5h"` — fractional units
|
|
27
|
+
* - `"2700000"` — raw milliseconds (string)
|
|
28
|
+
* - `2700000` — raw milliseconds (number)
|
|
29
|
+
*
|
|
30
|
+
* @param input - Duration string or number
|
|
31
|
+
* @returns Duration in milliseconds
|
|
32
|
+
* @throws Error if the input format is invalid or value is non-positive
|
|
33
|
+
*/
|
|
34
|
+
export declare function parseDuration(input: number | string): number;
|
|
35
|
+
/**
|
|
36
|
+
* Format a millisecond duration into a human-readable string.
|
|
37
|
+
*
|
|
38
|
+
* @param ms - Duration in milliseconds
|
|
39
|
+
* @returns Formatted string (e.g., "45m", "1.5h", "30s")
|
|
40
|
+
*/
|
|
41
|
+
export declare function formatDuration(ms: number): string;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Duration Parsing Utility
|
|
3
|
+
*
|
|
4
|
+
* Parses human-readable duration strings (e.g., "30s", "5m", "1h", "90m")
|
|
5
|
+
* into milliseconds. Also accepts raw millisecond numbers for backward
|
|
6
|
+
* compatibility with existing --timeout flag usage.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* parseDuration('30s') // 30_000
|
|
11
|
+
* parseDuration('5m') // 300_000
|
|
12
|
+
* parseDuration('45m') // 2_700_000
|
|
13
|
+
* parseDuration('1h') // 3_600_000
|
|
14
|
+
* parseDuration('1.5h') // 5_400_000
|
|
15
|
+
* parseDuration('2700000') // 2_700_000 (raw ms, backward compat)
|
|
16
|
+
* parseDuration(2700000) // 2_700_000 (numeric passthrough)
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
/** Duration unit multipliers in milliseconds */
|
|
20
|
+
const UNIT_MS = {
|
|
21
|
+
h: 3_600_000,
|
|
22
|
+
m: 60_000,
|
|
23
|
+
s: 1_000,
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Parse a duration string or number into milliseconds.
|
|
27
|
+
*
|
|
28
|
+
* Accepted formats:
|
|
29
|
+
* - `"30s"` — seconds
|
|
30
|
+
* - `"5m"` — minutes
|
|
31
|
+
* - `"1h"` — hours
|
|
32
|
+
* - `"1.5h"` — fractional units
|
|
33
|
+
* - `"2700000"` — raw milliseconds (string)
|
|
34
|
+
* - `2700000` — raw milliseconds (number)
|
|
35
|
+
*
|
|
36
|
+
* @param input - Duration string or number
|
|
37
|
+
* @returns Duration in milliseconds
|
|
38
|
+
* @throws Error if the input format is invalid or value is non-positive
|
|
39
|
+
*/
|
|
40
|
+
export function parseDuration(input) {
|
|
41
|
+
// Numeric passthrough
|
|
42
|
+
if (typeof input === 'number') {
|
|
43
|
+
if (input <= 0 || !Number.isFinite(input)) {
|
|
44
|
+
throw new Error(`Invalid timeout value: ${input}. Must be a positive number.`);
|
|
45
|
+
}
|
|
46
|
+
return Math.round(input);
|
|
47
|
+
}
|
|
48
|
+
const trimmed = input.trim();
|
|
49
|
+
if (trimmed.length === 0) {
|
|
50
|
+
throw new Error('Timeout value cannot be empty.');
|
|
51
|
+
}
|
|
52
|
+
// Try matching duration pattern: number + unit suffix
|
|
53
|
+
const match = trimmed.match(/^(\d+(?:\.\d+)?)\s*(s|m|h)$/i);
|
|
54
|
+
if (match) {
|
|
55
|
+
const value = Number.parseFloat(match[1]);
|
|
56
|
+
const unit = match[2].toLowerCase();
|
|
57
|
+
const multiplier = UNIT_MS[unit];
|
|
58
|
+
const ms = Math.round(value * multiplier);
|
|
59
|
+
if (ms <= 0) {
|
|
60
|
+
throw new Error(`Invalid timeout value: ${trimmed}. Must result in a positive duration.`);
|
|
61
|
+
}
|
|
62
|
+
return ms;
|
|
63
|
+
}
|
|
64
|
+
// Try raw numeric string (milliseconds)
|
|
65
|
+
const numeric = Number(trimmed);
|
|
66
|
+
if (!Number.isNaN(numeric) && Number.isFinite(numeric) && numeric > 0) {
|
|
67
|
+
return Math.round(numeric);
|
|
68
|
+
}
|
|
69
|
+
throw new Error(`Invalid timeout format: "${trimmed}". ` +
|
|
70
|
+
`Expected a duration like "30s", "5m", "1h", "90m", or raw milliseconds like "2700000".`);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Format a millisecond duration into a human-readable string.
|
|
74
|
+
*
|
|
75
|
+
* @param ms - Duration in milliseconds
|
|
76
|
+
* @returns Formatted string (e.g., "45m", "1.5h", "30s")
|
|
77
|
+
*/
|
|
78
|
+
export function formatDuration(ms) {
|
|
79
|
+
if (ms >= 3_600_000) {
|
|
80
|
+
const hours = ms / 3_600_000;
|
|
81
|
+
return Number.isInteger(hours) ? `${hours}h` : `${hours.toFixed(1)}h`;
|
|
82
|
+
}
|
|
83
|
+
if (ms >= 60_000) {
|
|
84
|
+
const minutes = ms / 60_000;
|
|
85
|
+
return Number.isInteger(minutes) ? `${minutes}m` : `${minutes.toFixed(1)}m`;
|
|
86
|
+
}
|
|
87
|
+
const seconds = ms / 1_000;
|
|
88
|
+
return Number.isInteger(seconds) ? `${seconds}s` : `${seconds.toFixed(1)}s`;
|
|
89
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* listr2 Helper Functions
|
|
3
|
+
*
|
|
4
|
+
* Utility functions for creating and managing listr2 task structures
|
|
5
|
+
* used by the WorkflowReporter for visualizing workflow progress.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Default terminal width constraint for output formatting
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_TERMINAL_WIDTH = 80;
|
|
11
|
+
/**
|
|
12
|
+
* Regex pattern for detecting ANSI escape codes
|
|
13
|
+
*/
|
|
14
|
+
export declare const ANSI_ESCAPE_PATTERN: RegExp;
|
|
15
|
+
/**
|
|
16
|
+
* Strip ANSI escape codes from text
|
|
17
|
+
*
|
|
18
|
+
* @param text - Text potentially containing ANSI codes
|
|
19
|
+
* @returns Clean text without ANSI escape sequences
|
|
20
|
+
*/
|
|
21
|
+
export declare const stripAnsi: (text: string) => string;
|
|
22
|
+
/**
|
|
23
|
+
* Check if the current environment is a TTY
|
|
24
|
+
*
|
|
25
|
+
* @returns true if stdout is a TTY, false otherwise
|
|
26
|
+
*/
|
|
27
|
+
export declare const isTTY: () => boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Plain-text status indicators (no ANSI codes)
|
|
30
|
+
*/
|
|
31
|
+
export declare const PLAIN_STATUS_INDICATORS: {
|
|
32
|
+
readonly completed: "[+]";
|
|
33
|
+
readonly failed: "[X]";
|
|
34
|
+
readonly queued: "[.]";
|
|
35
|
+
readonly running: "[*]";
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Format a plain-text phase header for non-TTY output
|
|
39
|
+
*
|
|
40
|
+
* @param phaseName - Phase name (epic, story, dev, qa)
|
|
41
|
+
* @returns Plain-text header string (e.g., "=== Phase: Epic Generation ===")
|
|
42
|
+
*/
|
|
43
|
+
export declare const formatPlainPhaseHeader: (phaseName: string) => string;
|
|
44
|
+
/**
|
|
45
|
+
* Format a plain-text spawn marker for non-TTY output
|
|
46
|
+
*
|
|
47
|
+
* @param itemId - Item identifier
|
|
48
|
+
* @param status - Spawn status (STARTED, COMPLETED, FAILED)
|
|
49
|
+
* @param durationMs - Optional duration in milliseconds
|
|
50
|
+
* @param error - Optional error message for failed spawns
|
|
51
|
+
* @returns Plain-text marker string (e.g., "[SPAWN] story-1.001 STARTED")
|
|
52
|
+
*/
|
|
53
|
+
export declare const formatPlainSpawnMarker: (itemId: string, status: "COMPLETED" | "FAILED" | "STARTED", durationMs?: number, error?: string) => string;
|
|
54
|
+
/**
|
|
55
|
+
* Format a plain-text summary for non-TTY output
|
|
56
|
+
*
|
|
57
|
+
* @param totalSpawns - Total number of spawns
|
|
58
|
+
* @param passedCount - Number of passed spawns
|
|
59
|
+
* @param failedCount - Number of failed spawns
|
|
60
|
+
* @param durationMs - Total duration in milliseconds
|
|
61
|
+
* @returns Plain-text summary string
|
|
62
|
+
*/
|
|
63
|
+
export declare const formatPlainSummary: (totalSpawns: number, passedCount: number, failedCount: number, durationMs: number) => string;
|
|
64
|
+
/**
|
|
65
|
+
* Format spawn output with visual delimiters for verbose mode
|
|
66
|
+
*
|
|
67
|
+
* @param spawnId - Spawn identifier
|
|
68
|
+
* @param output - Output content from the spawn
|
|
69
|
+
* @param maxWidth - Maximum line width (default: 80)
|
|
70
|
+
* @returns Formatted output with header/footer delimiters
|
|
71
|
+
*/
|
|
72
|
+
export declare const formatVerboseSpawnOutput: (spawnId: string, output: string, maxWidth?: number) => string;
|
|
73
|
+
/**
|
|
74
|
+
* Wrap text lines to fit within a maximum width
|
|
75
|
+
*
|
|
76
|
+
* @param text - Text to wrap
|
|
77
|
+
* @param maxWidth - Maximum line width
|
|
78
|
+
* @returns Wrapped text
|
|
79
|
+
*/
|
|
80
|
+
export declare const wrapLines: (text: string, maxWidth: number) => string;
|
|
81
|
+
/**
|
|
82
|
+
* Phase emoji mapping for visual consistency
|
|
83
|
+
*/
|
|
84
|
+
export declare const PHASE_EMOJI: Record<string, string>;
|
|
85
|
+
/**
|
|
86
|
+
* Phase display names for titles
|
|
87
|
+
*/
|
|
88
|
+
export declare const PHASE_TITLES: Record<string, string>;
|
|
89
|
+
/**
|
|
90
|
+
* Action verbs for spawn labels — maps phase to what the spawn is DOING (lowercase)
|
|
91
|
+
*/
|
|
92
|
+
export declare const PHASE_ACTION_VERBS: Record<string, string>;
|
|
93
|
+
/**
|
|
94
|
+
* Get the action verb for a phase (e.g., "Creating" for story phase)
|
|
95
|
+
*/
|
|
96
|
+
export declare const getPhaseActionVerb: (phaseName: string) => string;
|
|
97
|
+
/**
|
|
98
|
+
* Status indicators for spawn states
|
|
99
|
+
*/
|
|
100
|
+
export declare const STATUS_INDICATORS: {
|
|
101
|
+
readonly completed: string;
|
|
102
|
+
readonly failed: string;
|
|
103
|
+
readonly queued: string;
|
|
104
|
+
readonly running: string;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Get emoji for a phase name
|
|
108
|
+
*
|
|
109
|
+
* @param phaseName - Phase name (epic, story, dev, qa)
|
|
110
|
+
* @returns Emoji string for the phase
|
|
111
|
+
*/
|
|
112
|
+
export declare const getPhaseEmoji: (phaseName: string) => string;
|
|
113
|
+
/**
|
|
114
|
+
* Create a formatted phase title with emoji
|
|
115
|
+
*
|
|
116
|
+
* @param phaseName - Phase name (epic, story, dev, qa)
|
|
117
|
+
* @returns Formatted title string with emoji (e.g., "📋 Epic Phase")
|
|
118
|
+
*/
|
|
119
|
+
export declare const createPhaseTitle: (phaseName: string) => string;
|
|
120
|
+
/**
|
|
121
|
+
* Create a phase task group configuration for listr2
|
|
122
|
+
*
|
|
123
|
+
* @param phaseName - Phase name (epic, story, dev, qa)
|
|
124
|
+
* @returns Object with title and phase metadata
|
|
125
|
+
*/
|
|
126
|
+
export declare const createPhaseTaskGroup: (phaseName: string) => {
|
|
127
|
+
emoji: string;
|
|
128
|
+
phaseName: string;
|
|
129
|
+
title: string;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Create a layer task group configuration for listr2
|
|
133
|
+
*
|
|
134
|
+
* @param layerIndex - Zero-based layer index
|
|
135
|
+
* @param spawnCount - Number of spawns in the layer
|
|
136
|
+
* @param totalLayers - Total number of layers in the phase
|
|
137
|
+
* @returns Object with title and layer metadata
|
|
138
|
+
*/
|
|
139
|
+
export declare const createLayerTaskGroup: (layerIndex: number, spawnCount: number, totalLayers: number) => {
|
|
140
|
+
layerIndex: number;
|
|
141
|
+
spawnCount: number;
|
|
142
|
+
title: string;
|
|
143
|
+
totalLayers: number;
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Spawn status type
|
|
147
|
+
*/
|
|
148
|
+
export type SpawnStatus = 'completed' | 'failed' | 'queued' | 'running';
|
|
149
|
+
/**
|
|
150
|
+
* Format spawn status for display
|
|
151
|
+
*
|
|
152
|
+
* @param status - Current spawn status
|
|
153
|
+
* @param durationMs - Duration in milliseconds (optional)
|
|
154
|
+
* @param itemCount - Number of items processed (optional, for completed status)
|
|
155
|
+
* @param errorMessage - Error message (optional, for failed status)
|
|
156
|
+
* @returns Formatted status string
|
|
157
|
+
*/
|
|
158
|
+
export declare const formatSpawnStatus: (status: SpawnStatus, durationMs?: number, itemCount?: number, errorMessage?: string) => string;
|
|
159
|
+
/**
|
|
160
|
+
* Layer result summary
|
|
161
|
+
*/
|
|
162
|
+
export interface LayerResult {
|
|
163
|
+
durationMs: number;
|
|
164
|
+
failureCount: number;
|
|
165
|
+
layerIndex: number;
|
|
166
|
+
spawnCount: number;
|
|
167
|
+
successCount: number;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Format a layer summary line for collapsed display
|
|
171
|
+
*
|
|
172
|
+
* @param result - Layer execution results
|
|
173
|
+
* @returns Formatted summary string
|
|
174
|
+
*/
|
|
175
|
+
export declare const formatLayerSummary: (result: LayerResult) => string;
|
|
176
|
+
/**
|
|
177
|
+
* Phase result summary
|
|
178
|
+
*/
|
|
179
|
+
export interface PhaseResult {
|
|
180
|
+
durationMs: number;
|
|
181
|
+
failureCount: number;
|
|
182
|
+
itemCount: number;
|
|
183
|
+
phaseName: string;
|
|
184
|
+
successCount: number;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Format a phase summary for completion display
|
|
188
|
+
*
|
|
189
|
+
* @param result - Phase execution results
|
|
190
|
+
* @returns Formatted summary string
|
|
191
|
+
*/
|
|
192
|
+
export declare const formatPhaseSummary: (result: PhaseResult) => string;
|
|
193
|
+
/**
|
|
194
|
+
* Create a spawn task title
|
|
195
|
+
*
|
|
196
|
+
* @param itemId - Item identifier (epic number, story number, etc.)
|
|
197
|
+
* @param itemTitle - Optional item title/description
|
|
198
|
+
* @param agentType - Type of agent being spawned
|
|
199
|
+
* @returns Formatted spawn task title
|
|
200
|
+
*/
|
|
201
|
+
export declare const createSpawnTitle: (itemId: string, itemTitle?: string, agentType?: string) => string;
|
|
202
|
+
/**
|
|
203
|
+
* Truncate a string to a maximum length with ellipsis
|
|
204
|
+
*
|
|
205
|
+
* @param text - Text to truncate
|
|
206
|
+
* @param maxLength - Maximum length (default: 60)
|
|
207
|
+
* @returns Truncated string with ellipsis if needed
|
|
208
|
+
*/
|
|
209
|
+
export declare const truncateText: (text: string, maxLength?: number) => string;
|
|
210
|
+
/**
|
|
211
|
+
* Format elapsed time for running tasks (updates every second)
|
|
212
|
+
*
|
|
213
|
+
* @param startTime - Start timestamp in milliseconds
|
|
214
|
+
* @returns Formatted elapsed time string
|
|
215
|
+
*/
|
|
216
|
+
export declare const formatElapsedTime: (startTime: number) => string;
|