claude-autopm 1.18.0 → 1.20.1
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/README.md +159 -0
- package/autopm/.claude/agents/README.md +1 -1
- package/autopm/.claude/agents/core/mcp-manager.md +1 -1
- package/autopm/.claude/agents/decision-matrices/python-backend-selection.md +25 -25
- package/autopm/.claude/agents/decision-matrices/ui-framework-selection.md +43 -43
- package/autopm/.claude/agents/devops/github-operations-specialist.md +1 -1
- package/autopm/.claude/agents/frameworks/README.md +5 -5
- package/autopm/.claude/agents/frameworks/e2e-test-engineer.md +1 -1
- package/autopm/.claude/agents/frameworks/nats-messaging-expert.md +1 -1
- package/autopm/.claude/agents/frameworks/react-frontend-engineer.md +1 -1
- package/autopm/.claude/agents/frameworks/react-ui-expert.md +3 -3
- package/autopm/.claude/agents/frameworks/tailwindcss-expert.md +3 -3
- package/autopm/.claude/agents/frameworks/ux-design-expert.md +3 -3
- package/autopm/.claude/commands/infrastructure/traefik-setup.md +1 -1
- package/autopm/.claude/commands/playwright/test-scaffold.md +1 -1
- package/autopm/.claude/commands/pm/context.md +11 -0
- package/autopm/.claude/commands/pm/epic-decompose.md +25 -2
- package/autopm/.claude/commands/pm/epic-oneshot.md +13 -0
- package/autopm/.claude/commands/pm/epic-start.md +19 -0
- package/autopm/.claude/commands/pm/epic-sync-modular.md +10 -10
- package/autopm/.claude/commands/pm/epic-sync.md +14 -14
- package/autopm/.claude/commands/pm/issue-start.md +50 -5
- package/autopm/.claude/commands/pm/issue-sync.md +15 -15
- package/autopm/.claude/commands/pm/what-next.md +11 -0
- package/autopm/.claude/commands/ui/bootstrap-scaffold.md +6 -5
- package/autopm/.claude/commands/ui/tailwind-system.md +1 -1
- package/autopm/.claude/examples/mcp/playwright-mcp.md +2 -2
- package/autopm/.claude/examples/mcp-servers.example.json +2 -2
- package/autopm/.claude/hooks/docker-first-enforcement.sh +1 -1
- package/autopm/.claude/mcp/MCP-REGISTRY.md +1 -1
- package/autopm/.claude/mcp/playwright-mcp.md +2 -2
- package/autopm/.claude/rules/agent-coordination.md +26 -24
- package/autopm/.claude/rules/docker-first-development.md +1 -1
- package/autopm/.claude/rules/infrastructure-pipeline.md +1 -1
- package/autopm/.claude/rules/ui-development-standards.md +1 -1
- package/autopm/.claude/rules/visual-testing.md +3 -3
- package/autopm/.claude/scripts/azure/active-work.js +2 -2
- package/autopm/.claude/scripts/azure/blocked.js +13 -13
- package/autopm/.claude/scripts/azure/daily.js +1 -1
- package/autopm/.claude/scripts/azure/dashboard.js +1 -1
- package/autopm/.claude/scripts/azure/feature-list.js +2 -2
- package/autopm/.claude/scripts/azure/feature-status.js +1 -1
- package/autopm/.claude/scripts/azure/next-task.js +1 -1
- package/autopm/.claude/scripts/azure/search.js +1 -1
- package/autopm/.claude/scripts/azure/setup.js +15 -15
- package/autopm/.claude/scripts/azure/sprint-report.js +2 -2
- package/autopm/.claude/scripts/azure/sync.js +1 -1
- package/autopm/.claude/scripts/azure/us-list.js +1 -1
- package/autopm/.claude/scripts/azure/us-status.js +1 -1
- package/autopm/.claude/scripts/azure/validate.js +13 -13
- package/autopm/.claude/scripts/lib/frontmatter-utils.sh +42 -7
- package/autopm/.claude/scripts/lib/logging-utils.sh +20 -16
- package/autopm/.claude/scripts/lib/validation-utils.sh +1 -1
- package/autopm/.claude/scripts/pm/context.js +338 -0
- package/autopm/.claude/scripts/pm/issue-sync/format-comment.sh +3 -3
- package/autopm/.claude/scripts/pm/lib/README.md +85 -0
- package/autopm/.claude/scripts/pm/lib/logger.js +78 -0
- package/autopm/.claude/scripts/pm/next.js +25 -1
- package/autopm/.claude/scripts/pm/what-next.js +660 -0
- package/autopm/.claude/teams.json +3 -5
- package/autopm/.claude/templates/claude-templates/addons/devops-agents.md +2 -2
- package/autopm/.claude/templates/claude-templates/addons/docker-agents.md +4 -4
- package/autopm/.claude/templates/claude-templates/addons/minimal-agents.md +1 -1
- package/autopm/.claude/templates/issue-decomposition/api.yaml +2 -2
- package/autopm/.claude/templates/issue-decomposition/auth.yaml +4 -4
- package/autopm/.claude/templates/issue-decomposition/crud.yaml +3 -3
- package/autopm/.claude/templates/issue-decomposition/default.yaml +1 -1
- package/autopm/.claude/templates/issue-decomposition/ui-feature.yaml +2 -2
- package/bin/autopm.js +25 -0
- package/package.json +1 -2
- package/lib/agentExecutor.js.deprecated +0 -101
- package/lib/azure/cache.js +0 -80
- package/lib/azure/client.js +0 -77
- package/lib/azure/formatter.js +0 -177
- package/lib/commandHelpers.js +0 -177
- package/lib/context/manager.js +0 -290
- package/lib/documentation/manager.js +0 -528
- package/lib/github/workflow-manager.js +0 -546
- package/lib/helpers/azure-batch-api.js +0 -133
- package/lib/helpers/azure-cache-manager.js +0 -287
- package/lib/helpers/azure-parallel-processor.js +0 -158
- package/lib/helpers/azure-work-item-create.js +0 -278
- package/lib/helpers/gh-issue-create.js +0 -250
- package/lib/helpers/interactive-prompt.js +0 -336
- package/lib/helpers/output-manager.js +0 -335
- package/lib/helpers/progress-indicator.js +0 -258
- package/lib/performance/benchmarker.js +0 -429
- package/lib/pm/epic-decomposer.js +0 -273
- package/lib/pm/epic-syncer.js +0 -221
- package/lib/prdMetadata.js +0 -270
- package/lib/providers/azure/index.js +0 -234
- package/lib/providers/factory.js +0 -87
- package/lib/providers/github/index.js +0 -204
- package/lib/providers/interface.js +0 -73
- package/lib/python/scaffold-manager.js +0 -576
- package/lib/react/scaffold-manager.js +0 -745
- package/lib/regression/analyzer.js +0 -578
- package/lib/release/manager.js +0 -324
- package/lib/tailwind/manager.js +0 -486
- package/lib/traefik/manager.js +0 -484
- package/lib/utils/colors.js +0 -126
- package/lib/utils/config.js +0 -317
- package/lib/utils/filesystem.js +0 -316
- package/lib/utils/logger.js +0 -135
- package/lib/utils/prompts.js +0 -294
- package/lib/utils/shell.js +0 -237
- package/lib/validators/email-validator.js +0 -337
- package/lib/workflow/manager.js +0 -449
package/lib/utils/logger.js
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Logger utility for consistent output formatting
|
|
3
|
-
* Provides cross-platform colored console output
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const chalk = require('./colors');
|
|
7
|
-
|
|
8
|
-
class Logger {
|
|
9
|
-
constructor(options = {}) {
|
|
10
|
-
this.verbose = options.verbose || false;
|
|
11
|
-
this.silent = options.silent || false;
|
|
12
|
-
|
|
13
|
-
// Ensure logger is always safe to use
|
|
14
|
-
if (!this.silent && typeof this.silent !== 'boolean') {
|
|
15
|
-
this.silent = false;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Success messages
|
|
20
|
-
success(message) {
|
|
21
|
-
if (!this.silent) {
|
|
22
|
-
console.log(chalk.green('✅'), message);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Error messages
|
|
27
|
-
error(message, error = null) {
|
|
28
|
-
if (!this.silent) {
|
|
29
|
-
console.error(chalk.red('❌'), chalk.red(message));
|
|
30
|
-
if (error && this.verbose) {
|
|
31
|
-
console.error(chalk.gray(error.stack || error));
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Warning messages
|
|
37
|
-
warn(message) {
|
|
38
|
-
if (!this.silent) {
|
|
39
|
-
console.log(chalk.yellow('⚠️ '), chalk.yellow(message));
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Info messages
|
|
44
|
-
info(message) {
|
|
45
|
-
if (!this.silent) {
|
|
46
|
-
console.log(chalk.blue('ℹ️ '), message);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Debug messages (only shown in verbose mode)
|
|
51
|
-
debug(message) {
|
|
52
|
-
if (this.verbose && !this.silent) {
|
|
53
|
-
console.log(chalk.gray('🔍'), chalk.gray(message));
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Section headers
|
|
58
|
-
header(title) {
|
|
59
|
-
if (!this.silent) {
|
|
60
|
-
console.log('\n' + chalk.boldUnderline(title));
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Step indicators
|
|
65
|
-
step(number, total, message) {
|
|
66
|
-
if (!this.silent) {
|
|
67
|
-
console.log(chalk.cyan(`[${number}/${total}]`), message);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Progress indicators
|
|
72
|
-
progress(message) {
|
|
73
|
-
if (!this.silent) {
|
|
74
|
-
console.log(chalk.gray('⏳'), message);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Completion message
|
|
79
|
-
complete(message) {
|
|
80
|
-
if (!this.silent) {
|
|
81
|
-
console.log(chalk.boldGreen('🎉'), chalk.green(message));
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Box drawing for important messages
|
|
86
|
-
box(message, color = 'cyan') {
|
|
87
|
-
if (!this.silent) {
|
|
88
|
-
const lines = message.split('\n');
|
|
89
|
-
const maxLength = Math.max(...lines.map(l => l.length));
|
|
90
|
-
const horizontal = '─'.repeat(maxLength + 2);
|
|
91
|
-
|
|
92
|
-
console.log(chalk[color](`┌${horizontal}┐`));
|
|
93
|
-
lines.forEach(line => {
|
|
94
|
-
const padding = ' '.repeat(maxLength - line.length);
|
|
95
|
-
console.log(chalk[color]('│'), line + padding, chalk[color]('│'));
|
|
96
|
-
});
|
|
97
|
-
console.log(chalk[color](`└${horizontal}┘`));
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Simple list formatting
|
|
102
|
-
list(items, ordered = false) {
|
|
103
|
-
if (!this.silent) {
|
|
104
|
-
items.forEach((item, index) => {
|
|
105
|
-
const bullet = ordered ? `${index + 1}.` : '•';
|
|
106
|
-
console.log(` ${chalk.gray(bullet)} ${item}`);
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Table formatting (simple)
|
|
112
|
-
table(headers, rows) {
|
|
113
|
-
if (!this.silent) {
|
|
114
|
-
try {
|
|
115
|
-
const { table } = require('table');
|
|
116
|
-
const data = [headers, ...rows];
|
|
117
|
-
console.log(table(data));
|
|
118
|
-
} catch (error) {
|
|
119
|
-
// Fallback to simple table
|
|
120
|
-
console.log(headers.join(' | '));
|
|
121
|
-
console.log('-'.repeat(headers.join(' | ').length));
|
|
122
|
-
rows.forEach(row => console.log(row.join(' | ')));
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Divider
|
|
128
|
-
divider() {
|
|
129
|
-
if (!this.silent) {
|
|
130
|
-
console.log(chalk.gray('━'.repeat(50)));
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
module.exports = Logger;
|
package/lib/utils/prompts.js
DELETED
|
@@ -1,294 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Prompts utility for consistent user interaction
|
|
3
|
-
* Wraps inquirer with common prompt patterns
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const inquirer = require('inquirer');
|
|
7
|
-
const chalk = require('./colors');
|
|
8
|
-
|
|
9
|
-
class Prompts {
|
|
10
|
-
constructor(logger) {
|
|
11
|
-
this.logger = logger;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Simple yes/no confirmation
|
|
16
|
-
*/
|
|
17
|
-
async confirm(message, defaultValue = false) {
|
|
18
|
-
const { confirmed } = await inquirer.prompt([
|
|
19
|
-
{
|
|
20
|
-
type: 'confirm',
|
|
21
|
-
name: 'confirmed',
|
|
22
|
-
message,
|
|
23
|
-
default: defaultValue
|
|
24
|
-
}
|
|
25
|
-
]);
|
|
26
|
-
return confirmed;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Text input
|
|
31
|
-
*/
|
|
32
|
-
async input(message, defaultValue = '', options = {}) {
|
|
33
|
-
const { value } = await inquirer.prompt([
|
|
34
|
-
{
|
|
35
|
-
type: 'input',
|
|
36
|
-
name: 'value',
|
|
37
|
-
message,
|
|
38
|
-
default: defaultValue,
|
|
39
|
-
...options
|
|
40
|
-
}
|
|
41
|
-
]);
|
|
42
|
-
return value;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Password input
|
|
47
|
-
*/
|
|
48
|
-
async password(message, options = {}) {
|
|
49
|
-
const { value } = await inquirer.prompt([
|
|
50
|
-
{
|
|
51
|
-
type: 'password',
|
|
52
|
-
name: 'value',
|
|
53
|
-
message,
|
|
54
|
-
mask: '*',
|
|
55
|
-
...options
|
|
56
|
-
}
|
|
57
|
-
]);
|
|
58
|
-
return value;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Single selection from list
|
|
63
|
-
*/
|
|
64
|
-
async select(message, choices, defaultValue = null) {
|
|
65
|
-
const { selected } = await inquirer.prompt([
|
|
66
|
-
{
|
|
67
|
-
type: 'list',
|
|
68
|
-
name: 'selected',
|
|
69
|
-
message,
|
|
70
|
-
choices,
|
|
71
|
-
default: defaultValue
|
|
72
|
-
}
|
|
73
|
-
]);
|
|
74
|
-
return selected;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Multiple selection from list
|
|
79
|
-
*/
|
|
80
|
-
async multiSelect(message, choices, defaultValues = []) {
|
|
81
|
-
const { selected } = await inquirer.prompt([
|
|
82
|
-
{
|
|
83
|
-
type: 'checkbox',
|
|
84
|
-
name: 'selected',
|
|
85
|
-
message,
|
|
86
|
-
choices,
|
|
87
|
-
default: defaultValues
|
|
88
|
-
}
|
|
89
|
-
]);
|
|
90
|
-
return selected;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Number input
|
|
95
|
-
*/
|
|
96
|
-
async number(message, defaultValue = 0, options = {}) {
|
|
97
|
-
const { value } = await inquirer.prompt([
|
|
98
|
-
{
|
|
99
|
-
type: 'number',
|
|
100
|
-
name: 'value',
|
|
101
|
-
message,
|
|
102
|
-
default: defaultValue,
|
|
103
|
-
...options
|
|
104
|
-
}
|
|
105
|
-
]);
|
|
106
|
-
return value;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Platform selection helper
|
|
111
|
-
*/
|
|
112
|
-
async selectPlatform() {
|
|
113
|
-
return this.select(
|
|
114
|
-
'Choose your project management platform:',
|
|
115
|
-
[
|
|
116
|
-
{ name: '📙 GitHub (Issues, Projects, Pull Requests)', value: 'github' },
|
|
117
|
-
{ name: '🔷 Azure DevOps (Work Items, Boards, Repos)', value: 'azure' }
|
|
118
|
-
],
|
|
119
|
-
'github'
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Configuration type selection
|
|
125
|
-
*/
|
|
126
|
-
async selectConfiguration() {
|
|
127
|
-
return this.select(
|
|
128
|
-
'Choose your configuration:',
|
|
129
|
-
[
|
|
130
|
-
{
|
|
131
|
-
name: '1) Minimal - Traditional development (no Docker/K8s)',
|
|
132
|
-
value: 'minimal'
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
name: '2) Docker-only - Container-first development',
|
|
136
|
-
value: 'docker'
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
name: '3) Full DevOps - Enterprise with Docker + K8s (RECOMMENDED)',
|
|
140
|
-
value: 'devops'
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
name: '4) Performance - Hybrid parallel execution for power users',
|
|
144
|
-
value: 'performance'
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
name: '5) Custom - Manual configuration',
|
|
148
|
-
value: 'custom'
|
|
149
|
-
}
|
|
150
|
-
],
|
|
151
|
-
'devops'
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Ask for API key/token with validation
|
|
157
|
-
*/
|
|
158
|
-
async askForToken(service, required = false) {
|
|
159
|
-
const message = required
|
|
160
|
-
? `Enter your ${service} token (required):`
|
|
161
|
-
: `Enter your ${service} token (optional, press Enter to skip):`;
|
|
162
|
-
|
|
163
|
-
const token = await this.password(message, {
|
|
164
|
-
validate: (input) => {
|
|
165
|
-
if (required && !input.trim()) {
|
|
166
|
-
return `${service} token is required`;
|
|
167
|
-
}
|
|
168
|
-
return true;
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
return token.trim();
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Pause execution and wait for user
|
|
177
|
-
*/
|
|
178
|
-
async pause(message = 'Press Enter to continue...') {
|
|
179
|
-
await inquirer.prompt([
|
|
180
|
-
{
|
|
181
|
-
type: 'input',
|
|
182
|
-
name: 'pause',
|
|
183
|
-
message: chalk.gray(message)
|
|
184
|
-
}
|
|
185
|
-
]);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Display menu and get selection
|
|
190
|
-
*/
|
|
191
|
-
async menu(title, items) {
|
|
192
|
-
this.logger.header(title);
|
|
193
|
-
|
|
194
|
-
const choices = items.map((item, index) => ({
|
|
195
|
-
name: `${index + 1}) ${item.label}`,
|
|
196
|
-
value: item.value,
|
|
197
|
-
short: item.short || item.label
|
|
198
|
-
}));
|
|
199
|
-
|
|
200
|
-
choices.push(new inquirer.Separator());
|
|
201
|
-
choices.push({ name: 'Exit', value: 'exit' });
|
|
202
|
-
|
|
203
|
-
return this.select('Select an option:', choices);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Ask series of questions
|
|
208
|
-
*/
|
|
209
|
-
async askQuestions(questions) {
|
|
210
|
-
return inquirer.prompt(questions);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Path input with validation
|
|
215
|
-
*/
|
|
216
|
-
async askForPath(message, defaultPath = '.', mustExist = false) {
|
|
217
|
-
return this.input(message, defaultPath, {
|
|
218
|
-
validate: async (input) => {
|
|
219
|
-
if (!input.trim()) {
|
|
220
|
-
return 'Path cannot be empty';
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
if (mustExist) {
|
|
224
|
-
const fs = require('fs-extra');
|
|
225
|
-
const exists = await fs.pathExists(input);
|
|
226
|
-
if (!exists) {
|
|
227
|
-
return `Path does not exist: ${input}`;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
return true;
|
|
232
|
-
}
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* URL input with validation
|
|
238
|
-
*/
|
|
239
|
-
async askForUrl(message, defaultUrl = '') {
|
|
240
|
-
return this.input(message, defaultUrl, {
|
|
241
|
-
validate: (input) => {
|
|
242
|
-
if (!input.trim()) {
|
|
243
|
-
return true; // Allow empty for optional URLs
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
try {
|
|
247
|
-
new URL(input);
|
|
248
|
-
return true;
|
|
249
|
-
} catch {
|
|
250
|
-
return 'Please enter a valid URL';
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Email input with validation
|
|
258
|
-
*/
|
|
259
|
-
async askForEmail(message, defaultEmail = '') {
|
|
260
|
-
return this.input(message, defaultEmail, {
|
|
261
|
-
validate: (input) => {
|
|
262
|
-
if (!input.trim()) {
|
|
263
|
-
return true; // Allow empty for optional emails
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
267
|
-
if (!emailRegex.test(input)) {
|
|
268
|
-
return 'Please enter a valid email address';
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
return true;
|
|
272
|
-
}
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Show spinner during async operation
|
|
278
|
-
*/
|
|
279
|
-
async withSpinner(message, asyncFn) {
|
|
280
|
-
const ora = require('ora');
|
|
281
|
-
const spinner = ora(message).start();
|
|
282
|
-
|
|
283
|
-
try {
|
|
284
|
-
const result = await asyncFn();
|
|
285
|
-
spinner.succeed();
|
|
286
|
-
return result;
|
|
287
|
-
} catch (error) {
|
|
288
|
-
spinner.fail();
|
|
289
|
-
throw error;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
module.exports = Prompts;
|
package/lib/utils/shell.js
DELETED
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shell command execution utility
|
|
3
|
-
* Wraps execa for safe cross-platform command execution
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const { execa } = require('execa');
|
|
7
|
-
const which = require('which');
|
|
8
|
-
|
|
9
|
-
class Shell {
|
|
10
|
-
constructor(logger) {
|
|
11
|
-
this.logger = logger;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Execute a command
|
|
16
|
-
*/
|
|
17
|
-
async exec(command, args = [], options = {}) {
|
|
18
|
-
try {
|
|
19
|
-
this.logger.debug(`Executing: ${command} ${args.join(' ')}`);
|
|
20
|
-
|
|
21
|
-
const result = await execa(command, args, {
|
|
22
|
-
...options,
|
|
23
|
-
preferLocal: true,
|
|
24
|
-
reject: false
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
if (result.exitCode !== 0) {
|
|
28
|
-
throw new Error(`Command failed with exit code ${result.exitCode}: ${result.stderr}`);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return result;
|
|
32
|
-
} catch (error) {
|
|
33
|
-
this.logger.error(`Failed to execute: ${command}`, error);
|
|
34
|
-
throw error;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Execute command and return stdout
|
|
40
|
-
*/
|
|
41
|
-
async execOutput(command, args = [], options = {}) {
|
|
42
|
-
const result = await this.exec(command, args, options);
|
|
43
|
-
return result.stdout;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Check if command exists
|
|
48
|
-
*/
|
|
49
|
-
async commandExists(command) {
|
|
50
|
-
try {
|
|
51
|
-
await which(command);
|
|
52
|
-
return true;
|
|
53
|
-
} catch {
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Execute git command
|
|
60
|
-
*/
|
|
61
|
-
async git(args, options = {}) {
|
|
62
|
-
return this.exec('git', args, options);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Execute npm command
|
|
67
|
-
*/
|
|
68
|
-
async npm(args, options = {}) {
|
|
69
|
-
return this.exec('npm', args, options);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Execute node command
|
|
74
|
-
*/
|
|
75
|
-
async node(args, options = {}) {
|
|
76
|
-
return this.exec('node', args, options);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Get current git branch
|
|
81
|
-
*/
|
|
82
|
-
async getCurrentBranch() {
|
|
83
|
-
try {
|
|
84
|
-
const branch = await this.execOutput('git', ['branch', '--show-current']);
|
|
85
|
-
return branch.trim();
|
|
86
|
-
} catch {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Check if in git repository
|
|
93
|
-
*/
|
|
94
|
-
async isGitRepo() {
|
|
95
|
-
try {
|
|
96
|
-
await this.exec('git', ['rev-parse', '--git-dir']);
|
|
97
|
-
return true;
|
|
98
|
-
} catch {
|
|
99
|
-
return false;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Get git remote URL
|
|
105
|
-
*/
|
|
106
|
-
async getGitRemote(remote = 'origin') {
|
|
107
|
-
try {
|
|
108
|
-
const url = await this.execOutput('git', ['remote', 'get-url', remote]);
|
|
109
|
-
return url.trim();
|
|
110
|
-
} catch {
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Run command with live output
|
|
117
|
-
*/
|
|
118
|
-
async execInteractive(command, args = [], options = {}) {
|
|
119
|
-
this.logger.debug(`Executing interactive: ${command} ${args.join(' ')}`);
|
|
120
|
-
|
|
121
|
-
return execa(command, args, {
|
|
122
|
-
...options,
|
|
123
|
-
preferLocal: true,
|
|
124
|
-
stdio: 'inherit'
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Execute shell script content
|
|
130
|
-
*/
|
|
131
|
-
async execScript(script, options = {}) {
|
|
132
|
-
const shell = process.platform === 'win32' ? 'powershell' : 'bash';
|
|
133
|
-
return this.exec(shell, ['-c', script], options);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Get environment variable
|
|
138
|
-
*/
|
|
139
|
-
getEnv(key, defaultValue = '') {
|
|
140
|
-
return process.env[key] || defaultValue;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Set environment variable
|
|
145
|
-
*/
|
|
146
|
-
setEnv(key, value) {
|
|
147
|
-
process.env[key] = value;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Check if running in CI
|
|
152
|
-
*/
|
|
153
|
-
isCI() {
|
|
154
|
-
return process.env.CI === 'true' || process.env.CONTINUOUS_INTEGRATION === 'true';
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Get platform
|
|
159
|
-
*/
|
|
160
|
-
getPlatform() {
|
|
161
|
-
return process.platform;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Check if Windows
|
|
166
|
-
*/
|
|
167
|
-
isWindows() {
|
|
168
|
-
return process.platform === 'win32';
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Check if macOS
|
|
173
|
-
*/
|
|
174
|
-
isMacOS() {
|
|
175
|
-
return process.platform === 'darwin';
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Check if Linux
|
|
180
|
-
*/
|
|
181
|
-
isLinux() {
|
|
182
|
-
return process.platform === 'linux';
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Execute with timeout
|
|
187
|
-
*/
|
|
188
|
-
async execWithTimeout(command, args = [], timeout = 30000, options = {}) {
|
|
189
|
-
return this.exec(command, args, {
|
|
190
|
-
...options,
|
|
191
|
-
timeout
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Execute and parse JSON output
|
|
197
|
-
*/
|
|
198
|
-
async execJson(command, args = [], options = {}) {
|
|
199
|
-
const output = await this.execOutput(command, args, options);
|
|
200
|
-
try {
|
|
201
|
-
return JSON.parse(output);
|
|
202
|
-
} catch (error) {
|
|
203
|
-
this.logger.error(`Failed to parse JSON output from: ${command}`, error);
|
|
204
|
-
throw error;
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Check GitHub CLI availability
|
|
210
|
-
*/
|
|
211
|
-
async hasGitHubCLI() {
|
|
212
|
-
return this.commandExists('gh');
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Check Azure CLI availability
|
|
217
|
-
*/
|
|
218
|
-
async hasAzureCLI() {
|
|
219
|
-
return this.commandExists('az');
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/**
|
|
223
|
-
* Check Docker availability
|
|
224
|
-
*/
|
|
225
|
-
async hasDocker() {
|
|
226
|
-
return this.commandExists('docker');
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Check kubectl availability
|
|
231
|
-
*/
|
|
232
|
-
async hasKubectl() {
|
|
233
|
-
return this.commandExists('kubectl');
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
module.exports = Shell;
|