claude-autopm 1.17.0 → 1.20.0
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/core/mcp-manager.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/mcp/MCP-REGISTRY.md +1 -1
- 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/bin/autopm.js +25 -0
- package/bin/commands/team.js +86 -0
- package/package.json +1 -1
- 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/traefik/manager.js
DELETED
|
@@ -1,484 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Traefik Configuration Manager
|
|
3
|
-
* Centralized Traefik setup and configuration functionality
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const fs = require('fs').promises;
|
|
7
|
-
const path = require('path');
|
|
8
|
-
const { exec } = require('child_process');
|
|
9
|
-
const { promisify } = require('util');
|
|
10
|
-
const execAsync = promisify(exec);
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Configuration constants
|
|
14
|
-
*/
|
|
15
|
-
const CONFIG = {
|
|
16
|
-
directories: {
|
|
17
|
-
traefik: '.claude/traefik'
|
|
18
|
-
},
|
|
19
|
-
defaults: {
|
|
20
|
-
traefikImage: 'traefik:v2.9',
|
|
21
|
-
network: 'web',
|
|
22
|
-
dashboardPort: 8080,
|
|
23
|
-
httpPort: 80,
|
|
24
|
-
httpsPort: 443
|
|
25
|
-
},
|
|
26
|
-
files: {
|
|
27
|
-
config: 'traefik.yml',
|
|
28
|
-
dockerCompose: 'docker-compose.yml',
|
|
29
|
-
routes: 'routes.json'
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Default configurations
|
|
35
|
-
*/
|
|
36
|
-
const DEFAULT_CONFIGS = {
|
|
37
|
-
traefik: {
|
|
38
|
-
api: {
|
|
39
|
-
dashboard: true,
|
|
40
|
-
debug: false
|
|
41
|
-
},
|
|
42
|
-
entryPoints: {
|
|
43
|
-
web: {
|
|
44
|
-
address: ':80'
|
|
45
|
-
},
|
|
46
|
-
websecure: {
|
|
47
|
-
address: ':443'
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
providers: {
|
|
51
|
-
docker: {
|
|
52
|
-
endpoint: 'unix:///var/run/docker.sock',
|
|
53
|
-
exposedByDefault: false
|
|
54
|
-
},
|
|
55
|
-
file: {
|
|
56
|
-
directory: '/etc/traefik/dynamic',
|
|
57
|
-
watch: true
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
log: {
|
|
61
|
-
level: 'INFO'
|
|
62
|
-
},
|
|
63
|
-
accessLog: {}
|
|
64
|
-
},
|
|
65
|
-
routes: {
|
|
66
|
-
routes: [
|
|
67
|
-
{
|
|
68
|
-
name: 'api',
|
|
69
|
-
rule: 'PathPrefix(`/api`)',
|
|
70
|
-
service: 'api-service',
|
|
71
|
-
servers: [{ url: 'http://api:3000' }]
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
name: 'web',
|
|
75
|
-
rule: 'Host(`localhost`)',
|
|
76
|
-
service: 'web-service',
|
|
77
|
-
servers: [{ url: 'http://web:80' }]
|
|
78
|
-
}
|
|
79
|
-
]
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
class TraefikManager {
|
|
84
|
-
constructor(projectRoot = process.cwd()) {
|
|
85
|
-
this.projectRoot = projectRoot;
|
|
86
|
-
this.traefikDir = path.join(projectRoot, CONFIG.directories.traefik);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Generates Traefik configuration
|
|
91
|
-
*/
|
|
92
|
-
async generateConfig(options = {}) {
|
|
93
|
-
await fs.mkdir(this.traefikDir, { recursive: true });
|
|
94
|
-
|
|
95
|
-
const config = {
|
|
96
|
-
...DEFAULT_CONFIGS.traefik,
|
|
97
|
-
api: {
|
|
98
|
-
...DEFAULT_CONFIGS.traefik.api,
|
|
99
|
-
debug: options.debug || false
|
|
100
|
-
},
|
|
101
|
-
log: {
|
|
102
|
-
level: options.logLevel || 'INFO'
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
const configPath = path.join(this.traefikDir, CONFIG.files.config);
|
|
107
|
-
const yaml = this.generateYAML(config);
|
|
108
|
-
await fs.writeFile(configPath, yaml);
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
path: configPath,
|
|
112
|
-
config: config
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Generates Docker Compose configuration
|
|
118
|
-
*/
|
|
119
|
-
async generateDockerCompose(options = {}) {
|
|
120
|
-
await fs.mkdir(this.traefikDir, { recursive: true });
|
|
121
|
-
|
|
122
|
-
const dockerCompose = {
|
|
123
|
-
version: '3.8',
|
|
124
|
-
services: {
|
|
125
|
-
traefik: {
|
|
126
|
-
image: options.image || CONFIG.defaults.traefikImage,
|
|
127
|
-
container_name: 'traefik',
|
|
128
|
-
restart: 'unless-stopped',
|
|
129
|
-
ports: [
|
|
130
|
-
`${CONFIG.defaults.httpPort}:80`,
|
|
131
|
-
`${CONFIG.defaults.httpsPort}:443`,
|
|
132
|
-
`${CONFIG.defaults.dashboardPort}:8080`
|
|
133
|
-
],
|
|
134
|
-
volumes: [
|
|
135
|
-
'/var/run/docker.sock:/var/run/docker.sock:ro',
|
|
136
|
-
'./traefik.yml:/traefik.yml:ro',
|
|
137
|
-
'./dynamic:/etc/traefik/dynamic:ro',
|
|
138
|
-
'./letsencrypt:/letsencrypt'
|
|
139
|
-
],
|
|
140
|
-
networks: [CONFIG.defaults.network],
|
|
141
|
-
labels: {
|
|
142
|
-
'traefik.enable': 'true',
|
|
143
|
-
'traefik.http.routers.dashboard.rule': 'Host(`traefik.localhost`)',
|
|
144
|
-
'traefik.http.routers.dashboard.service': 'api@internal',
|
|
145
|
-
'traefik.http.routers.dashboard.middlewares': 'auth'
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
},
|
|
149
|
-
networks: {
|
|
150
|
-
[CONFIG.defaults.network]: {
|
|
151
|
-
external: true
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
const dockerPath = path.join(this.traefikDir, CONFIG.files.dockerCompose);
|
|
157
|
-
const yaml = this.generateYAML(dockerCompose);
|
|
158
|
-
await fs.writeFile(dockerPath, yaml);
|
|
159
|
-
|
|
160
|
-
return {
|
|
161
|
-
path: dockerPath,
|
|
162
|
-
config: dockerCompose
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Configures routes
|
|
168
|
-
*/
|
|
169
|
-
async configureRoutes(customRoutes = null) {
|
|
170
|
-
await fs.mkdir(this.traefikDir, { recursive: true });
|
|
171
|
-
const routesPath = path.join(this.traefikDir, CONFIG.files.routes);
|
|
172
|
-
|
|
173
|
-
let routesConfig;
|
|
174
|
-
if (customRoutes) {
|
|
175
|
-
routesConfig = customRoutes;
|
|
176
|
-
} else {
|
|
177
|
-
try {
|
|
178
|
-
const content = await fs.readFile(routesPath, 'utf8');
|
|
179
|
-
routesConfig = JSON.parse(content);
|
|
180
|
-
} catch (error) {
|
|
181
|
-
routesConfig = DEFAULT_CONFIGS.routes;
|
|
182
|
-
await fs.writeFile(routesPath, JSON.stringify(routesConfig, null, 2));
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// Generate dynamic configuration for each route
|
|
187
|
-
for (const route of routesConfig.routes) {
|
|
188
|
-
const dynamicConfig = {
|
|
189
|
-
http: {
|
|
190
|
-
routers: {
|
|
191
|
-
[route.name]: {
|
|
192
|
-
rule: route.rule,
|
|
193
|
-
service: route.service,
|
|
194
|
-
middlewares: route.middlewares || []
|
|
195
|
-
}
|
|
196
|
-
},
|
|
197
|
-
services: {
|
|
198
|
-
[route.service]: {
|
|
199
|
-
loadBalancer: {
|
|
200
|
-
servers: route.servers || [{ url: 'http://localhost:3000' }]
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
const dynamicPath = path.join(this.traefikDir, `dynamic-${route.name}.yml`);
|
|
208
|
-
await fs.writeFile(dynamicPath, this.generateYAML(dynamicConfig));
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return {
|
|
212
|
-
routes: routesConfig.routes,
|
|
213
|
-
path: routesPath
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Configures SSL/TLS
|
|
219
|
-
*/
|
|
220
|
-
async configureSSL(domain) {
|
|
221
|
-
await fs.mkdir(this.traefikDir, { recursive: true });
|
|
222
|
-
|
|
223
|
-
const sslConfig = {
|
|
224
|
-
tls: {
|
|
225
|
-
certificates: [
|
|
226
|
-
{
|
|
227
|
-
certFile: `/letsencrypt/certs/${domain}.crt`,
|
|
228
|
-
keyFile: `/letsencrypt/certs/${domain}.key`
|
|
229
|
-
}
|
|
230
|
-
],
|
|
231
|
-
stores: {
|
|
232
|
-
default: {
|
|
233
|
-
defaultCertificate: {
|
|
234
|
-
certFile: `/letsencrypt/certs/${domain}.crt`,
|
|
235
|
-
keyFile: `/letsencrypt/certs/${domain}.key`
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
const sslPath = path.join(this.traefikDir, 'ssl-config.yml');
|
|
243
|
-
await fs.writeFile(sslPath, this.generateYAML(sslConfig));
|
|
244
|
-
|
|
245
|
-
return {
|
|
246
|
-
path: sslPath,
|
|
247
|
-
domain: domain,
|
|
248
|
-
config: sslConfig
|
|
249
|
-
};
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* Configures Let's Encrypt
|
|
254
|
-
*/
|
|
255
|
-
async configureLetsEncrypt(email, staging = false) {
|
|
256
|
-
await fs.mkdir(this.traefikDir, { recursive: true });
|
|
257
|
-
|
|
258
|
-
const acmeConfig = {
|
|
259
|
-
certificatesResolvers: {
|
|
260
|
-
letsencrypt: {
|
|
261
|
-
acme: {
|
|
262
|
-
email: email,
|
|
263
|
-
storage: '/letsencrypt/acme.json',
|
|
264
|
-
httpChallenge: {
|
|
265
|
-
entryPoint: 'web'
|
|
266
|
-
},
|
|
267
|
-
caServer: staging
|
|
268
|
-
? 'https://acme-staging-v02.api.letsencrypt.org/directory'
|
|
269
|
-
: 'https://acme-v02.api.letsencrypt.org/directory'
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
const acmePath = path.join(this.traefikDir, 'letsencrypt-config.yml');
|
|
276
|
-
await fs.writeFile(acmePath, this.generateYAML(acmeConfig));
|
|
277
|
-
|
|
278
|
-
return {
|
|
279
|
-
path: acmePath,
|
|
280
|
-
email: email,
|
|
281
|
-
staging: staging,
|
|
282
|
-
config: acmeConfig
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Configures middleware
|
|
288
|
-
*/
|
|
289
|
-
async configureMiddleware(type, options = {}) {
|
|
290
|
-
await fs.mkdir(this.traefikDir, { recursive: true });
|
|
291
|
-
|
|
292
|
-
const middlewares = {
|
|
293
|
-
http: {
|
|
294
|
-
middlewares: {}
|
|
295
|
-
}
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
switch (type) {
|
|
299
|
-
case 'auth':
|
|
300
|
-
middlewares.http.middlewares.auth = {
|
|
301
|
-
basicAuth: {
|
|
302
|
-
users: options.users || ['admin:$2y$10$...']
|
|
303
|
-
}
|
|
304
|
-
};
|
|
305
|
-
break;
|
|
306
|
-
|
|
307
|
-
case 'compress':
|
|
308
|
-
middlewares.http.middlewares.compress = {
|
|
309
|
-
compress: {}
|
|
310
|
-
};
|
|
311
|
-
break;
|
|
312
|
-
|
|
313
|
-
case 'redirect':
|
|
314
|
-
middlewares.http.middlewares['redirect-to-https'] = {
|
|
315
|
-
redirectScheme: {
|
|
316
|
-
scheme: 'https',
|
|
317
|
-
permanent: true
|
|
318
|
-
}
|
|
319
|
-
};
|
|
320
|
-
break;
|
|
321
|
-
|
|
322
|
-
case 'ratelimit':
|
|
323
|
-
middlewares.http.middlewares['rate-limit'] = {
|
|
324
|
-
rateLimit: {
|
|
325
|
-
average: options.average || 100,
|
|
326
|
-
burst: options.burst || 200,
|
|
327
|
-
period: '1m'
|
|
328
|
-
}
|
|
329
|
-
};
|
|
330
|
-
break;
|
|
331
|
-
|
|
332
|
-
default:
|
|
333
|
-
throw new Error(`Unknown middleware type: ${type}`);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const middlewarePath = path.join(this.traefikDir, `middleware-${type}.yml`);
|
|
337
|
-
await fs.writeFile(middlewarePath, this.generateYAML(middlewares));
|
|
338
|
-
|
|
339
|
-
return {
|
|
340
|
-
path: middlewarePath,
|
|
341
|
-
type: type,
|
|
342
|
-
config: middlewares
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* Configures service discovery
|
|
348
|
-
*/
|
|
349
|
-
async configureDiscovery(provider, options = {}) {
|
|
350
|
-
await fs.mkdir(this.traefikDir, { recursive: true });
|
|
351
|
-
|
|
352
|
-
let discoveryConfig = {};
|
|
353
|
-
|
|
354
|
-
switch (provider) {
|
|
355
|
-
case 'docker':
|
|
356
|
-
discoveryConfig = {
|
|
357
|
-
providers: {
|
|
358
|
-
docker: {
|
|
359
|
-
endpoint: 'unix:///var/run/docker.sock',
|
|
360
|
-
exposedByDefault: false,
|
|
361
|
-
network: options.network || CONFIG.defaults.network,
|
|
362
|
-
watch: true
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
};
|
|
366
|
-
break;
|
|
367
|
-
|
|
368
|
-
case 'kubernetes':
|
|
369
|
-
case 'k8s':
|
|
370
|
-
discoveryConfig = {
|
|
371
|
-
providers: {
|
|
372
|
-
kubernetes: {
|
|
373
|
-
namespace: options.namespace || 'default',
|
|
374
|
-
labelSelector: options.selector || '',
|
|
375
|
-
ingressClass: 'traefik'
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
};
|
|
379
|
-
break;
|
|
380
|
-
|
|
381
|
-
case 'consul':
|
|
382
|
-
discoveryConfig = {
|
|
383
|
-
providers: {
|
|
384
|
-
consul: {
|
|
385
|
-
endpoint: options.endpoint || 'http://localhost:8500',
|
|
386
|
-
prefix: 'traefik',
|
|
387
|
-
watch: true
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
};
|
|
391
|
-
break;
|
|
392
|
-
|
|
393
|
-
default:
|
|
394
|
-
throw new Error(`Unknown provider: ${provider}`);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
const discoveryPath = path.join(this.traefikDir, `discovery-${provider}.yml`);
|
|
398
|
-
await fs.writeFile(discoveryPath, this.generateYAML(discoveryConfig));
|
|
399
|
-
|
|
400
|
-
return {
|
|
401
|
-
path: discoveryPath,
|
|
402
|
-
provider: provider,
|
|
403
|
-
config: discoveryConfig
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* Checks Traefik status
|
|
409
|
-
*/
|
|
410
|
-
async checkStatus() {
|
|
411
|
-
const status = {
|
|
412
|
-
configuration: {
|
|
413
|
-
exists: false,
|
|
414
|
-
files: []
|
|
415
|
-
},
|
|
416
|
-
container: {
|
|
417
|
-
running: false,
|
|
418
|
-
status: 'unknown'
|
|
419
|
-
},
|
|
420
|
-
dashboard: {
|
|
421
|
-
url: `http://localhost:${CONFIG.defaults.dashboardPort}/dashboard`
|
|
422
|
-
}
|
|
423
|
-
};
|
|
424
|
-
|
|
425
|
-
// Check configuration files
|
|
426
|
-
try {
|
|
427
|
-
const files = await fs.readdir(this.traefikDir);
|
|
428
|
-
status.configuration.exists = true;
|
|
429
|
-
for (const file of files) {
|
|
430
|
-
const stats = await fs.stat(path.join(this.traefikDir, file));
|
|
431
|
-
status.configuration.files.push({
|
|
432
|
-
name: file,
|
|
433
|
-
size: stats.size
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
} catch (error) {
|
|
437
|
-
// No configuration directory
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// Check Docker container status
|
|
441
|
-
try {
|
|
442
|
-
const { stdout } = await execAsync('docker ps --filter name=traefik --format "{{.Status}}"');
|
|
443
|
-
if (stdout.includes('Up')) {
|
|
444
|
-
status.container.running = true;
|
|
445
|
-
status.container.status = stdout.trim();
|
|
446
|
-
}
|
|
447
|
-
} catch (error) {
|
|
448
|
-
// Docker not available or container not running
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
return status;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* Simple YAML generator
|
|
456
|
-
*/
|
|
457
|
-
generateYAML(obj, indent = 0) {
|
|
458
|
-
let yaml = '';
|
|
459
|
-
const spaces = ' '.repeat(indent);
|
|
460
|
-
|
|
461
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
462
|
-
if (value === null || value === undefined) {
|
|
463
|
-
yaml += `${spaces}${key}:\n`;
|
|
464
|
-
} else if (typeof value === 'object' && !Array.isArray(value)) {
|
|
465
|
-
yaml += `${spaces}${key}:\n${this.generateYAML(value, indent + 1)}`;
|
|
466
|
-
} else if (Array.isArray(value)) {
|
|
467
|
-
yaml += `${spaces}${key}:\n`;
|
|
468
|
-
for (const item of value) {
|
|
469
|
-
if (typeof item === 'object') {
|
|
470
|
-
yaml += `${spaces} -\n${this.generateYAML(item, indent + 2)}`;
|
|
471
|
-
} else {
|
|
472
|
-
yaml += `${spaces} - ${item}\n`;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
} else {
|
|
476
|
-
yaml += `${spaces}${key}: ${value}\n`;
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
return yaml;
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
module.exports = TraefikManager;
|
package/lib/utils/colors.js
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cross-platform color utility
|
|
3
|
-
* Works with or without chalk library
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// Color codes for fallback
|
|
7
|
-
const colors = {
|
|
8
|
-
reset: '\x1b[0m',
|
|
9
|
-
bold: '\x1b[1m',
|
|
10
|
-
underline: '\x1b[4m',
|
|
11
|
-
|
|
12
|
-
// Foreground colors
|
|
13
|
-
black: '\x1b[30m',
|
|
14
|
-
red: '\x1b[31m',
|
|
15
|
-
green: '\x1b[32m',
|
|
16
|
-
yellow: '\x1b[33m',
|
|
17
|
-
blue: '\x1b[34m',
|
|
18
|
-
magenta: '\x1b[35m',
|
|
19
|
-
cyan: '\x1b[36m',
|
|
20
|
-
white: '\x1b[37m',
|
|
21
|
-
gray: '\x1b[90m',
|
|
22
|
-
grey: '\x1b[90m',
|
|
23
|
-
|
|
24
|
-
// Background colors
|
|
25
|
-
bgBlack: '\x1b[40m',
|
|
26
|
-
bgRed: '\x1b[41m',
|
|
27
|
-
bgGreen: '\x1b[42m',
|
|
28
|
-
bgYellow: '\x1b[43m',
|
|
29
|
-
bgBlue: '\x1b[44m',
|
|
30
|
-
bgMagenta: '\x1b[45m',
|
|
31
|
-
bgCyan: '\x1b[46m',
|
|
32
|
-
bgWhite: '\x1b[47m'
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
class ColorHelper {
|
|
36
|
-
constructor() {
|
|
37
|
-
this.supportsColor = process.stdout.isTTY &&
|
|
38
|
-
process.env.TERM !== 'dumb' &&
|
|
39
|
-
!process.env.NO_COLOR;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
colorize(text, color) {
|
|
43
|
-
if (!this.supportsColor) {
|
|
44
|
-
return text;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const code = colors[color] || '';
|
|
48
|
-
return code + text + colors.reset;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Basic colors
|
|
52
|
-
red(text) {
|
|
53
|
-
return this.colorize(text, 'red');
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
green(text) {
|
|
57
|
-
return this.colorize(text, 'green');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
yellow(text) {
|
|
61
|
-
return this.colorize(text, 'yellow');
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
blue(text) {
|
|
65
|
-
return this.colorize(text, 'blue');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
magenta(text) {
|
|
69
|
-
return this.colorize(text, 'magenta');
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
cyan(text) {
|
|
73
|
-
return this.colorize(text, 'cyan');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
white(text) {
|
|
77
|
-
return this.colorize(text, 'white');
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
gray(text) {
|
|
81
|
-
return this.colorize(text, 'gray');
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
grey(text) {
|
|
85
|
-
return this.colorize(text, 'grey');
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Styles
|
|
89
|
-
bold(text) {
|
|
90
|
-
return this.colorize(text, 'bold');
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
underline(text) {
|
|
94
|
-
return this.colorize(text, 'underline');
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Combined styles
|
|
98
|
-
boldRed(text) {
|
|
99
|
-
return this.bold(this.red(text));
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
boldGreen(text) {
|
|
103
|
-
return this.bold(this.green(text));
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
boldYellow(text) {
|
|
107
|
-
return this.bold(this.yellow(text));
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
boldBlue(text) {
|
|
111
|
-
return this.bold(this.blue(text));
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
boldCyan(text) {
|
|
115
|
-
return this.bold(this.cyan(text));
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
boldUnderline(text) {
|
|
119
|
-
return this.bold(this.underline(text));
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Note: Removed chaining support due to infinite recursion issues
|
|
123
|
-
// Use direct method calls instead (e.g., boldRed(), boldGreen(), etc.)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
module.exports = new ColorHelper();
|