@build-astron-co/nimbus 0.2.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/LICENSE +21 -0
- package/README.md +628 -0
- package/bin/nimbus +38 -0
- package/package.json +80 -0
- package/src/__tests__/app.test.ts +76 -0
- package/src/__tests__/audit.test.ts +877 -0
- package/src/__tests__/circuit-breaker.test.ts +116 -0
- package/src/__tests__/cli-run.test.ts +115 -0
- package/src/__tests__/context-manager.test.ts +502 -0
- package/src/__tests__/context.test.ts +242 -0
- package/src/__tests__/enterprise.test.ts +401 -0
- package/src/__tests__/generator.test.ts +433 -0
- package/src/__tests__/hooks.test.ts +582 -0
- package/src/__tests__/init.test.ts +436 -0
- package/src/__tests__/intent-parser.test.ts +229 -0
- package/src/__tests__/llm-router.test.ts +209 -0
- package/src/__tests__/lsp.test.ts +293 -0
- package/src/__tests__/modes.test.ts +336 -0
- package/src/__tests__/permissions.test.ts +338 -0
- package/src/__tests__/serve.test.ts +275 -0
- package/src/__tests__/sessions.test.ts +227 -0
- package/src/__tests__/sharing.test.ts +288 -0
- package/src/__tests__/snapshots.test.ts +581 -0
- package/src/__tests__/state-db.test.ts +334 -0
- package/src/__tests__/stream-with-tools.test.ts +732 -0
- package/src/__tests__/subagents.test.ts +176 -0
- package/src/__tests__/system-prompt.test.ts +169 -0
- package/src/__tests__/tool-converter.test.ts +256 -0
- package/src/__tests__/tool-schemas.test.ts +397 -0
- package/src/__tests__/tools.test.ts +143 -0
- package/src/__tests__/version.test.ts +49 -0
- package/src/agent/compaction-agent.ts +227 -0
- package/src/agent/context-manager.ts +435 -0
- package/src/agent/context.ts +427 -0
- package/src/agent/deploy-preview.ts +426 -0
- package/src/agent/index.ts +68 -0
- package/src/agent/loop.ts +717 -0
- package/src/agent/modes.ts +429 -0
- package/src/agent/permissions.ts +466 -0
- package/src/agent/subagents/base.ts +116 -0
- package/src/agent/subagents/cost.ts +51 -0
- package/src/agent/subagents/explore.ts +42 -0
- package/src/agent/subagents/general.ts +54 -0
- package/src/agent/subagents/index.ts +102 -0
- package/src/agent/subagents/infra.ts +59 -0
- package/src/agent/subagents/security.ts +69 -0
- package/src/agent/system-prompt.ts +436 -0
- package/src/app.ts +122 -0
- package/src/audit/activity-log.ts +290 -0
- package/src/audit/compliance-checker.ts +540 -0
- package/src/audit/cost-tracker.ts +318 -0
- package/src/audit/index.ts +23 -0
- package/src/audit/security-scanner.ts +596 -0
- package/src/auth/guard.ts +75 -0
- package/src/auth/index.ts +56 -0
- package/src/auth/oauth.ts +455 -0
- package/src/auth/providers.ts +470 -0
- package/src/auth/sso.ts +113 -0
- package/src/auth/store.ts +505 -0
- package/src/auth/types.ts +187 -0
- package/src/build.ts +141 -0
- package/src/cli/index.ts +16 -0
- package/src/cli/init.ts +854 -0
- package/src/cli/openapi-spec.ts +356 -0
- package/src/cli/run.ts +237 -0
- package/src/cli/serve-auth.ts +80 -0
- package/src/cli/serve.ts +462 -0
- package/src/cli/web.ts +67 -0
- package/src/cli.ts +1417 -0
- package/src/clients/core-engine-client.ts +227 -0
- package/src/clients/enterprise-client.ts +334 -0
- package/src/clients/generator-client.ts +351 -0
- package/src/clients/git-client.ts +627 -0
- package/src/clients/github-client.ts +410 -0
- package/src/clients/helm-client.ts +504 -0
- package/src/clients/index.ts +80 -0
- package/src/clients/k8s-client.ts +497 -0
- package/src/clients/llm-client.ts +161 -0
- package/src/clients/rest-client.ts +130 -0
- package/src/clients/service-discovery.ts +33 -0
- package/src/clients/terraform-client.ts +482 -0
- package/src/clients/tools-client.ts +1843 -0
- package/src/clients/ws-client.ts +115 -0
- package/src/commands/analyze/index.ts +352 -0
- package/src/commands/apply/helm.ts +473 -0
- package/src/commands/apply/index.ts +213 -0
- package/src/commands/apply/k8s.ts +454 -0
- package/src/commands/apply/terraform.ts +582 -0
- package/src/commands/ask.ts +167 -0
- package/src/commands/audit/index.ts +238 -0
- package/src/commands/auth-cloud.ts +294 -0
- package/src/commands/auth-list.ts +134 -0
- package/src/commands/auth-profile.ts +121 -0
- package/src/commands/auth-status.ts +141 -0
- package/src/commands/aws/ec2.ts +501 -0
- package/src/commands/aws/iam.ts +397 -0
- package/src/commands/aws/index.ts +133 -0
- package/src/commands/aws/lambda.ts +396 -0
- package/src/commands/aws/rds.ts +439 -0
- package/src/commands/aws/s3.ts +439 -0
- package/src/commands/aws/vpc.ts +393 -0
- package/src/commands/aws-discover.ts +649 -0
- package/src/commands/aws-terraform.ts +805 -0
- package/src/commands/azure/aks.ts +376 -0
- package/src/commands/azure/functions.ts +253 -0
- package/src/commands/azure/index.ts +116 -0
- package/src/commands/azure/storage.ts +478 -0
- package/src/commands/azure/vm.ts +355 -0
- package/src/commands/billing/index.ts +256 -0
- package/src/commands/chat.ts +314 -0
- package/src/commands/config.ts +346 -0
- package/src/commands/cost/cloud-cost-estimator.ts +266 -0
- package/src/commands/cost/estimator.ts +79 -0
- package/src/commands/cost/index.ts +594 -0
- package/src/commands/cost/parsers/terraform.ts +273 -0
- package/src/commands/cost/parsers/types.ts +25 -0
- package/src/commands/cost/pricing/aws.ts +544 -0
- package/src/commands/cost/pricing/azure.ts +499 -0
- package/src/commands/cost/pricing/gcp.ts +396 -0
- package/src/commands/cost/pricing/index.ts +40 -0
- package/src/commands/demo.ts +250 -0
- package/src/commands/doctor.ts +794 -0
- package/src/commands/drift/index.ts +439 -0
- package/src/commands/explain.ts +277 -0
- package/src/commands/feedback.ts +389 -0
- package/src/commands/fix.ts +324 -0
- package/src/commands/fs/index.ts +402 -0
- package/src/commands/gcp/compute.ts +325 -0
- package/src/commands/gcp/functions.ts +271 -0
- package/src/commands/gcp/gke.ts +438 -0
- package/src/commands/gcp/iam.ts +344 -0
- package/src/commands/gcp/index.ts +129 -0
- package/src/commands/gcp/storage.ts +284 -0
- package/src/commands/generate-helm.ts +1249 -0
- package/src/commands/generate-k8s.ts +1560 -0
- package/src/commands/generate-terraform.ts +1460 -0
- package/src/commands/gh/index.ts +863 -0
- package/src/commands/git/index.ts +1343 -0
- package/src/commands/helm/index.ts +1126 -0
- package/src/commands/help.ts +539 -0
- package/src/commands/history.ts +142 -0
- package/src/commands/import.ts +868 -0
- package/src/commands/index.ts +367 -0
- package/src/commands/init.ts +1046 -0
- package/src/commands/k8s/index.ts +1137 -0
- package/src/commands/login.ts +631 -0
- package/src/commands/logout.ts +83 -0
- package/src/commands/onboarding.ts +228 -0
- package/src/commands/plan/display.ts +279 -0
- package/src/commands/plan/index.ts +599 -0
- package/src/commands/preview.ts +452 -0
- package/src/commands/questionnaire.ts +1270 -0
- package/src/commands/resume.ts +55 -0
- package/src/commands/team/index.ts +346 -0
- package/src/commands/template.ts +232 -0
- package/src/commands/tf/index.ts +1034 -0
- package/src/commands/upgrade.ts +550 -0
- package/src/commands/usage/index.ts +134 -0
- package/src/commands/version.ts +170 -0
- package/src/compat/index.ts +2 -0
- package/src/compat/runtime.ts +12 -0
- package/src/compat/sqlite.ts +107 -0
- package/src/config/index.ts +17 -0
- package/src/config/manager.ts +530 -0
- package/src/config/safety-policy.ts +358 -0
- package/src/config/schema.ts +125 -0
- package/src/config/types.ts +527 -0
- package/src/context/context-db.ts +199 -0
- package/src/demo/index.ts +349 -0
- package/src/demo/scenarios/full-journey.ts +229 -0
- package/src/demo/scenarios/getting-started.ts +127 -0
- package/src/demo/scenarios/helm-release.ts +341 -0
- package/src/demo/scenarios/k8s-deployment.ts +194 -0
- package/src/demo/scenarios/terraform-vpc.ts +170 -0
- package/src/demo/types.ts +92 -0
- package/src/engine/cost-estimator.ts +438 -0
- package/src/engine/diagram-generator.ts +256 -0
- package/src/engine/drift-detector.ts +902 -0
- package/src/engine/executor.ts +1035 -0
- package/src/engine/index.ts +76 -0
- package/src/engine/orchestrator.ts +636 -0
- package/src/engine/planner.ts +720 -0
- package/src/engine/safety.ts +743 -0
- package/src/engine/verifier.ts +770 -0
- package/src/enterprise/audit.ts +348 -0
- package/src/enterprise/auth.ts +270 -0
- package/src/enterprise/billing.ts +822 -0
- package/src/enterprise/index.ts +17 -0
- package/src/enterprise/teams.ts +443 -0
- package/src/generator/best-practices.ts +1608 -0
- package/src/generator/helm.ts +630 -0
- package/src/generator/index.ts +37 -0
- package/src/generator/intent-parser.ts +514 -0
- package/src/generator/kubernetes.ts +976 -0
- package/src/generator/terraform.ts +1867 -0
- package/src/history/index.ts +8 -0
- package/src/history/manager.ts +322 -0
- package/src/history/types.ts +34 -0
- package/src/hooks/config.ts +432 -0
- package/src/hooks/engine.ts +391 -0
- package/src/hooks/index.ts +4 -0
- package/src/llm/auth-bridge.ts +198 -0
- package/src/llm/circuit-breaker.ts +140 -0
- package/src/llm/config-loader.ts +201 -0
- package/src/llm/cost-calculator.ts +171 -0
- package/src/llm/index.ts +8 -0
- package/src/llm/model-aliases.ts +115 -0
- package/src/llm/provider-registry.ts +63 -0
- package/src/llm/providers/anthropic.ts +433 -0
- package/src/llm/providers/bedrock.ts +477 -0
- package/src/llm/providers/google.ts +405 -0
- package/src/llm/providers/ollama.ts +767 -0
- package/src/llm/providers/openai-compatible.ts +340 -0
- package/src/llm/providers/openai.ts +328 -0
- package/src/llm/providers/openrouter.ts +338 -0
- package/src/llm/router.ts +1035 -0
- package/src/llm/types.ts +232 -0
- package/src/lsp/client.ts +298 -0
- package/src/lsp/languages.ts +116 -0
- package/src/lsp/manager.ts +278 -0
- package/src/mcp/client.ts +402 -0
- package/src/mcp/index.ts +5 -0
- package/src/mcp/manager.ts +133 -0
- package/src/nimbus.ts +214 -0
- package/src/plugins/index.ts +27 -0
- package/src/plugins/loader.ts +334 -0
- package/src/plugins/manager.ts +376 -0
- package/src/plugins/types.ts +284 -0
- package/src/scanners/cicd-scanner.ts +258 -0
- package/src/scanners/cloud-scanner.ts +466 -0
- package/src/scanners/framework-scanner.ts +469 -0
- package/src/scanners/iac-scanner.ts +388 -0
- package/src/scanners/index.ts +539 -0
- package/src/scanners/language-scanner.ts +276 -0
- package/src/scanners/package-manager-scanner.ts +277 -0
- package/src/scanners/types.ts +172 -0
- package/src/sessions/manager.ts +365 -0
- package/src/sessions/types.ts +44 -0
- package/src/sharing/sync.ts +296 -0
- package/src/sharing/viewer.ts +97 -0
- package/src/snapshots/index.ts +2 -0
- package/src/snapshots/manager.ts +530 -0
- package/src/state/artifacts.ts +147 -0
- package/src/state/audit.ts +137 -0
- package/src/state/billing.ts +240 -0
- package/src/state/checkpoints.ts +117 -0
- package/src/state/config.ts +67 -0
- package/src/state/conversations.ts +14 -0
- package/src/state/credentials.ts +154 -0
- package/src/state/db.ts +58 -0
- package/src/state/index.ts +26 -0
- package/src/state/messages.ts +115 -0
- package/src/state/projects.ts +123 -0
- package/src/state/schema.ts +236 -0
- package/src/state/sessions.ts +147 -0
- package/src/state/teams.ts +200 -0
- package/src/telemetry.ts +108 -0
- package/src/tools/aws-ops.ts +952 -0
- package/src/tools/azure-ops.ts +579 -0
- package/src/tools/file-ops.ts +593 -0
- package/src/tools/gcp-ops.ts +625 -0
- package/src/tools/git-ops.ts +773 -0
- package/src/tools/github-ops.ts +799 -0
- package/src/tools/helm-ops.ts +943 -0
- package/src/tools/index.ts +17 -0
- package/src/tools/k8s-ops.ts +819 -0
- package/src/tools/schemas/converter.ts +184 -0
- package/src/tools/schemas/devops.ts +612 -0
- package/src/tools/schemas/index.ts +73 -0
- package/src/tools/schemas/standard.ts +1144 -0
- package/src/tools/schemas/types.ts +705 -0
- package/src/tools/terraform-ops.ts +862 -0
- package/src/types/ambient.d.ts +193 -0
- package/src/types/config.ts +83 -0
- package/src/types/drift.ts +116 -0
- package/src/types/enterprise.ts +335 -0
- package/src/types/index.ts +20 -0
- package/src/types/plan.ts +44 -0
- package/src/types/request.ts +65 -0
- package/src/types/response.ts +54 -0
- package/src/types/service.ts +51 -0
- package/src/ui/App.tsx +997 -0
- package/src/ui/DeployPreview.tsx +169 -0
- package/src/ui/Header.tsx +68 -0
- package/src/ui/InputBox.tsx +350 -0
- package/src/ui/MessageList.tsx +585 -0
- package/src/ui/PermissionPrompt.tsx +151 -0
- package/src/ui/StatusBar.tsx +158 -0
- package/src/ui/ToolCallDisplay.tsx +409 -0
- package/src/ui/chat-ui.ts +853 -0
- package/src/ui/index.ts +33 -0
- package/src/ui/ink/index.ts +711 -0
- package/src/ui/streaming.ts +176 -0
- package/src/ui/types.ts +57 -0
- package/src/utils/analytics.ts +72 -0
- package/src/utils/cost-warning.ts +27 -0
- package/src/utils/env.ts +46 -0
- package/src/utils/errors.ts +69 -0
- package/src/utils/event-bus.ts +38 -0
- package/src/utils/index.ts +24 -0
- package/src/utils/logger.ts +171 -0
- package/src/utils/rate-limiter.ts +121 -0
- package/src/utils/service-auth.ts +49 -0
- package/src/utils/validation.ts +53 -0
- package/src/version.ts +4 -0
- package/src/watcher/index.ts +163 -0
- package/src/wizard/approval.ts +383 -0
- package/src/wizard/index.ts +25 -0
- package/src/wizard/prompts.ts +338 -0
- package/src/wizard/types.ts +171 -0
- package/src/wizard/ui.ts +556 -0
- package/src/wizard/wizard.ts +304 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Azure CLI Commands
|
|
3
|
+
*
|
|
4
|
+
* Wrapper for Azure CLI operations with enhanced output and safety checks
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* nimbus azure vm list
|
|
8
|
+
* nimbus azure storage account list
|
|
9
|
+
* nimbus azure aks list
|
|
10
|
+
* nimbus azure functions list
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { logger } from '../../utils';
|
|
14
|
+
import { ui } from '../../wizard/ui';
|
|
15
|
+
import { vmCommand } from './vm';
|
|
16
|
+
import { storageCommand } from './storage';
|
|
17
|
+
import { aksCommand } from './aks';
|
|
18
|
+
import { functionsCommand } from './functions';
|
|
19
|
+
|
|
20
|
+
export interface AzureCommandOptions {
|
|
21
|
+
subscription?: string;
|
|
22
|
+
resourceGroup?: string;
|
|
23
|
+
output?: 'json' | 'table' | 'tsv';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Parse common Azure options from args
|
|
28
|
+
*/
|
|
29
|
+
export function parseAzureOptions(args: string[]): AzureCommandOptions {
|
|
30
|
+
const options: AzureCommandOptions = {};
|
|
31
|
+
|
|
32
|
+
for (let i = 0; i < args.length; i++) {
|
|
33
|
+
const arg = args[i];
|
|
34
|
+
|
|
35
|
+
if ((arg === '--subscription' || arg === '-s') && args[i + 1]) {
|
|
36
|
+
options.subscription = args[++i];
|
|
37
|
+
} else if ((arg === '--resource-group' || arg === '-g') && args[i + 1]) {
|
|
38
|
+
options.resourceGroup = args[++i];
|
|
39
|
+
} else if ((arg === '--output' || arg === '-o') && args[i + 1]) {
|
|
40
|
+
options.output = args[++i] as 'json' | 'table' | 'tsv';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return options;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Main Azure command router
|
|
49
|
+
*/
|
|
50
|
+
export async function azureCommand(subcommand: string, args: string[]): Promise<void> {
|
|
51
|
+
logger.info('Running Azure command', { subcommand, args });
|
|
52
|
+
|
|
53
|
+
const options = parseAzureOptions(args);
|
|
54
|
+
const positionalArgs = args.filter(arg => !arg.startsWith('-') && !arg.startsWith('--'));
|
|
55
|
+
|
|
56
|
+
switch (subcommand) {
|
|
57
|
+
case 'vm':
|
|
58
|
+
await vmCommand(positionalArgs[0], positionalArgs.slice(1), options);
|
|
59
|
+
break;
|
|
60
|
+
|
|
61
|
+
case 'storage':
|
|
62
|
+
await storageCommand(positionalArgs[0], positionalArgs.slice(1), options);
|
|
63
|
+
break;
|
|
64
|
+
|
|
65
|
+
case 'aks':
|
|
66
|
+
await aksCommand(positionalArgs[0], positionalArgs.slice(1), options);
|
|
67
|
+
break;
|
|
68
|
+
|
|
69
|
+
case 'functions':
|
|
70
|
+
await functionsCommand(positionalArgs[0], positionalArgs.slice(1), options);
|
|
71
|
+
break;
|
|
72
|
+
|
|
73
|
+
default:
|
|
74
|
+
showAzureHelp();
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Show Azure command help
|
|
81
|
+
*/
|
|
82
|
+
function showAzureHelp(): void {
|
|
83
|
+
ui.header('Nimbus Azure Commands');
|
|
84
|
+
ui.newLine();
|
|
85
|
+
|
|
86
|
+
ui.print('Usage: nimbus azure <service> <action> [options]');
|
|
87
|
+
ui.newLine();
|
|
88
|
+
|
|
89
|
+
ui.print(ui.bold('Services:'));
|
|
90
|
+
ui.print(' vm Virtual Machine operations');
|
|
91
|
+
ui.print(' storage Storage account and blob operations');
|
|
92
|
+
ui.print(' aks Azure Kubernetes Service operations');
|
|
93
|
+
ui.print(' functions Azure Functions operations');
|
|
94
|
+
ui.newLine();
|
|
95
|
+
|
|
96
|
+
ui.print(ui.bold('Common Options:'));
|
|
97
|
+
ui.print(' --subscription, -s Azure subscription ID');
|
|
98
|
+
ui.print(' --resource-group, -g Resource group name');
|
|
99
|
+
ui.print(' --output, -o Output format (json, table, tsv)');
|
|
100
|
+
ui.newLine();
|
|
101
|
+
|
|
102
|
+
ui.print(ui.bold('Examples:'));
|
|
103
|
+
ui.print(' nimbus azure vm list List all VMs');
|
|
104
|
+
ui.print(' nimbus azure vm show my-vm -g my-rg Show VM details');
|
|
105
|
+
ui.print(' nimbus azure storage account list List storage accounts');
|
|
106
|
+
ui.print(' nimbus azure aks list List AKS clusters');
|
|
107
|
+
ui.print(' nimbus azure functions list List function apps');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Re-export subcommands
|
|
111
|
+
export { vmCommand } from './vm';
|
|
112
|
+
export { storageCommand } from './storage';
|
|
113
|
+
export { aksCommand } from './aks';
|
|
114
|
+
export { functionsCommand } from './functions';
|
|
115
|
+
|
|
116
|
+
export default azureCommand;
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Azure Storage CLI Commands
|
|
3
|
+
*
|
|
4
|
+
* Operations for Azure Storage accounts and blobs
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { execFile } from 'child_process';
|
|
8
|
+
import { promisify } from 'util';
|
|
9
|
+
import { logger } from '../../utils';
|
|
10
|
+
import { ui } from '../../wizard/ui';
|
|
11
|
+
import {
|
|
12
|
+
loadSafetyPolicy,
|
|
13
|
+
evaluateSafety,
|
|
14
|
+
type SafetyContext,
|
|
15
|
+
type SafetyCheckResult,
|
|
16
|
+
} from '../../config/safety-policy';
|
|
17
|
+
import { promptForApproval, displaySafetySummary } from '../../wizard/approval';
|
|
18
|
+
import type { AzureCommandOptions } from './index';
|
|
19
|
+
|
|
20
|
+
const execFileAsync = promisify(execFile);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Run storage safety checks
|
|
24
|
+
*/
|
|
25
|
+
async function runStorageSafetyChecks(
|
|
26
|
+
action: string,
|
|
27
|
+
target: string,
|
|
28
|
+
options: AzureCommandOptions
|
|
29
|
+
): Promise<SafetyCheckResult> {
|
|
30
|
+
const safetyPolicy = loadSafetyPolicy();
|
|
31
|
+
|
|
32
|
+
const context: SafetyContext = {
|
|
33
|
+
operation: action,
|
|
34
|
+
type: 'azure',
|
|
35
|
+
environment: options.subscription || 'default',
|
|
36
|
+
resources: [target],
|
|
37
|
+
metadata: {
|
|
38
|
+
resourceType: 'storage',
|
|
39
|
+
resourceGroup: options.resourceGroup,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
return evaluateSafety(context, safetyPolicy);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Main Storage command router
|
|
48
|
+
*/
|
|
49
|
+
export async function storageCommand(
|
|
50
|
+
action: string,
|
|
51
|
+
args: string[],
|
|
52
|
+
options: AzureCommandOptions
|
|
53
|
+
): Promise<void> {
|
|
54
|
+
logger.info('Running Azure Storage command', { action, args, options });
|
|
55
|
+
|
|
56
|
+
switch (action) {
|
|
57
|
+
case 'account':
|
|
58
|
+
await accountCommand(args[0], args.slice(1), options);
|
|
59
|
+
break;
|
|
60
|
+
|
|
61
|
+
case 'container':
|
|
62
|
+
await containerCommand(args[0], args.slice(1), options);
|
|
63
|
+
break;
|
|
64
|
+
|
|
65
|
+
case 'blob':
|
|
66
|
+
await blobCommand(args[0], args.slice(1), options);
|
|
67
|
+
break;
|
|
68
|
+
|
|
69
|
+
default:
|
|
70
|
+
showStorageHelp();
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Storage account subcommand
|
|
77
|
+
*/
|
|
78
|
+
async function accountCommand(
|
|
79
|
+
action: string,
|
|
80
|
+
args: string[],
|
|
81
|
+
options: AzureCommandOptions
|
|
82
|
+
): Promise<void> {
|
|
83
|
+
switch (action) {
|
|
84
|
+
case 'list':
|
|
85
|
+
await listAccounts(options);
|
|
86
|
+
break;
|
|
87
|
+
|
|
88
|
+
case 'show':
|
|
89
|
+
if (!args[0]) {
|
|
90
|
+
ui.error('Account name required');
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
await showAccount(args[0], options);
|
|
94
|
+
break;
|
|
95
|
+
|
|
96
|
+
default:
|
|
97
|
+
ui.print(ui.bold('Storage Account Commands:'));
|
|
98
|
+
ui.print(' list List all storage accounts');
|
|
99
|
+
ui.print(' show <name> -g <rg> Show account details');
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Container subcommand
|
|
106
|
+
*/
|
|
107
|
+
async function containerCommand(
|
|
108
|
+
action: string,
|
|
109
|
+
args: string[],
|
|
110
|
+
options: AzureCommandOptions
|
|
111
|
+
): Promise<void> {
|
|
112
|
+
switch (action) {
|
|
113
|
+
case 'list':
|
|
114
|
+
if (!args[0]) {
|
|
115
|
+
ui.error('Account name required');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
await listContainers(args[0], options);
|
|
119
|
+
break;
|
|
120
|
+
|
|
121
|
+
case 'delete':
|
|
122
|
+
if (!args[0] || !args[1]) {
|
|
123
|
+
ui.error('Account name and container name required');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
await deleteContainer(args[0], args[1], options);
|
|
127
|
+
break;
|
|
128
|
+
|
|
129
|
+
default:
|
|
130
|
+
ui.print(ui.bold('Container Commands:'));
|
|
131
|
+
ui.print(' list <account> List containers in account');
|
|
132
|
+
ui.print(' delete <account> <container> Delete container (requires approval)');
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Blob subcommand
|
|
139
|
+
*/
|
|
140
|
+
async function blobCommand(
|
|
141
|
+
action: string,
|
|
142
|
+
args: string[],
|
|
143
|
+
options: AzureCommandOptions
|
|
144
|
+
): Promise<void> {
|
|
145
|
+
switch (action) {
|
|
146
|
+
case 'list':
|
|
147
|
+
if (!args[0] || !args[1]) {
|
|
148
|
+
ui.error('Account name and container name required');
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
await listBlobs(args[0], args[1], options);
|
|
152
|
+
break;
|
|
153
|
+
|
|
154
|
+
default:
|
|
155
|
+
ui.print(ui.bold('Blob Commands:'));
|
|
156
|
+
ui.print(' list <account> <container> List blobs in container');
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* List storage accounts
|
|
163
|
+
*/
|
|
164
|
+
async function listAccounts(options: AzureCommandOptions): Promise<void> {
|
|
165
|
+
ui.header('Azure Storage Accounts');
|
|
166
|
+
ui.newLine();
|
|
167
|
+
|
|
168
|
+
const azArgs = ['storage', 'account', 'list', '-o', 'json'];
|
|
169
|
+
if (options.subscription) {
|
|
170
|
+
azArgs.push('--subscription', options.subscription);
|
|
171
|
+
}
|
|
172
|
+
if (options.resourceGroup) {
|
|
173
|
+
azArgs.push('-g', options.resourceGroup);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
ui.startSpinner({ message: 'Fetching storage accounts...' });
|
|
178
|
+
const { stdout } = await execFileAsync('az', azArgs);
|
|
179
|
+
ui.stopSpinnerSuccess('Accounts fetched');
|
|
180
|
+
|
|
181
|
+
const accounts = JSON.parse(stdout || '[]');
|
|
182
|
+
|
|
183
|
+
if (accounts.length === 0) {
|
|
184
|
+
ui.info('No storage accounts found');
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
ui.print(`Found ${accounts.length} account(s)\n`);
|
|
189
|
+
|
|
190
|
+
// Display table
|
|
191
|
+
ui.print(
|
|
192
|
+
ui.color(
|
|
193
|
+
`${
|
|
194
|
+
'Name'.padEnd(30) +
|
|
195
|
+
'Resource Group'.padEnd(25) +
|
|
196
|
+
'Location'.padEnd(15) +
|
|
197
|
+
'Kind'.padEnd(15)
|
|
198
|
+
}Status`,
|
|
199
|
+
'cyan'
|
|
200
|
+
)
|
|
201
|
+
);
|
|
202
|
+
ui.print('─'.repeat(100));
|
|
203
|
+
|
|
204
|
+
for (const account of accounts) {
|
|
205
|
+
const name = account.name?.substring(0, 29) || '';
|
|
206
|
+
const rg = account.resourceGroup?.substring(0, 24) || '';
|
|
207
|
+
const location = account.location?.substring(0, 14) || '';
|
|
208
|
+
const kind = account.kind?.substring(0, 14) || '';
|
|
209
|
+
const status = account.provisioningState || '';
|
|
210
|
+
|
|
211
|
+
const statusColor = status === 'Succeeded' ? 'green' : status === 'Failed' ? 'red' : 'white';
|
|
212
|
+
|
|
213
|
+
ui.print(
|
|
214
|
+
`${name.padEnd(30)}${rg.padEnd(25)}${location.padEnd(15)}${kind.padEnd(15)}${ui.color(status, statusColor as 'green' | 'red' | 'white')}`
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
} catch (error: unknown) {
|
|
218
|
+
ui.stopSpinnerFail('Failed to fetch accounts');
|
|
219
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
220
|
+
logger.error('Failed to list storage accounts', { error: message });
|
|
221
|
+
ui.error(`Failed to list accounts: ${message}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Show storage account details
|
|
227
|
+
*/
|
|
228
|
+
async function showAccount(accountName: string, options: AzureCommandOptions): Promise<void> {
|
|
229
|
+
ui.header(`Storage Account: ${accountName}`);
|
|
230
|
+
ui.newLine();
|
|
231
|
+
|
|
232
|
+
if (!options.resourceGroup) {
|
|
233
|
+
ui.error('Resource group required (use -g)');
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const azArgs = [
|
|
238
|
+
'storage',
|
|
239
|
+
'account',
|
|
240
|
+
'show',
|
|
241
|
+
'-n',
|
|
242
|
+
accountName,
|
|
243
|
+
'-g',
|
|
244
|
+
options.resourceGroup,
|
|
245
|
+
'-o',
|
|
246
|
+
'json',
|
|
247
|
+
];
|
|
248
|
+
if (options.subscription) {
|
|
249
|
+
azArgs.push('--subscription', options.subscription);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
ui.startSpinner({ message: 'Fetching account details...' });
|
|
254
|
+
const { stdout } = await execFileAsync('az', azArgs);
|
|
255
|
+
ui.stopSpinnerSuccess('Details fetched');
|
|
256
|
+
|
|
257
|
+
const account = JSON.parse(stdout);
|
|
258
|
+
|
|
259
|
+
ui.print(ui.bold('Basic Information:'));
|
|
260
|
+
ui.print(` Name: ${account.name}`);
|
|
261
|
+
ui.print(` Resource Group: ${account.resourceGroup}`);
|
|
262
|
+
ui.print(` Location: ${account.location}`);
|
|
263
|
+
ui.print(` Kind: ${account.kind}`);
|
|
264
|
+
ui.print(` Status: ${account.provisioningState}`);
|
|
265
|
+
ui.newLine();
|
|
266
|
+
|
|
267
|
+
ui.print(ui.bold('Properties:'));
|
|
268
|
+
ui.print(` SKU: ${account.sku?.name}`);
|
|
269
|
+
ui.print(` Tier: ${account.sku?.tier}`);
|
|
270
|
+
ui.print(` Access Tier: ${account.accessTier || 'N/A'}`);
|
|
271
|
+
ui.print(` HTTPS Only: ${account.enableHttpsTrafficOnly ? 'Yes' : 'No'}`);
|
|
272
|
+
ui.newLine();
|
|
273
|
+
|
|
274
|
+
ui.print(ui.bold('Encryption:'));
|
|
275
|
+
ui.print(` Services: ${Object.keys(account.encryption?.services || {}).join(', ')}`);
|
|
276
|
+
ui.print(` Key Source: ${account.encryption?.keySource}`);
|
|
277
|
+
ui.newLine();
|
|
278
|
+
|
|
279
|
+
ui.print(ui.bold('Endpoints:'));
|
|
280
|
+
const endpoints = account.primaryEndpoints || {};
|
|
281
|
+
if (endpoints.blob) {
|
|
282
|
+
ui.print(` Blob: ${endpoints.blob}`);
|
|
283
|
+
}
|
|
284
|
+
if (endpoints.file) {
|
|
285
|
+
ui.print(` File: ${endpoints.file}`);
|
|
286
|
+
}
|
|
287
|
+
if (endpoints.queue) {
|
|
288
|
+
ui.print(` Queue: ${endpoints.queue}`);
|
|
289
|
+
}
|
|
290
|
+
if (endpoints.table) {
|
|
291
|
+
ui.print(` Table: ${endpoints.table}`);
|
|
292
|
+
}
|
|
293
|
+
} catch (error: unknown) {
|
|
294
|
+
ui.stopSpinnerFail('Failed to fetch details');
|
|
295
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
296
|
+
logger.error('Failed to show account', { error: message });
|
|
297
|
+
ui.error(`Failed to show account: ${message}`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* List containers in a storage account
|
|
303
|
+
*/
|
|
304
|
+
async function listContainers(accountName: string, options: AzureCommandOptions): Promise<void> {
|
|
305
|
+
ui.header(`Containers in ${accountName}`);
|
|
306
|
+
ui.newLine();
|
|
307
|
+
|
|
308
|
+
const azArgs = [
|
|
309
|
+
'storage',
|
|
310
|
+
'container',
|
|
311
|
+
'list',
|
|
312
|
+
'--account-name',
|
|
313
|
+
accountName,
|
|
314
|
+
'-o',
|
|
315
|
+
'json',
|
|
316
|
+
'--auth-mode',
|
|
317
|
+
'login',
|
|
318
|
+
];
|
|
319
|
+
if (options.subscription) {
|
|
320
|
+
azArgs.push('--subscription', options.subscription);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
try {
|
|
324
|
+
ui.startSpinner({ message: 'Fetching containers...' });
|
|
325
|
+
const { stdout } = await execFileAsync('az', azArgs);
|
|
326
|
+
ui.stopSpinnerSuccess('Containers fetched');
|
|
327
|
+
|
|
328
|
+
const containers = JSON.parse(stdout || '[]');
|
|
329
|
+
|
|
330
|
+
if (containers.length === 0) {
|
|
331
|
+
ui.info('No containers found');
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
ui.print(`Found ${containers.length} container(s)\n`);
|
|
336
|
+
|
|
337
|
+
for (const container of containers) {
|
|
338
|
+
ui.print(` ${ui.color(container.name, 'cyan')}`);
|
|
339
|
+
if (container.properties?.lastModified) {
|
|
340
|
+
ui.print(ui.dim(` Last Modified: ${container.properties.lastModified}`));
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
} catch (error: unknown) {
|
|
344
|
+
ui.stopSpinnerFail('Failed to fetch containers');
|
|
345
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
346
|
+
logger.error('Failed to list containers', { error: message });
|
|
347
|
+
ui.error(`Failed to list containers: ${message}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Delete a container (requires safety approval)
|
|
353
|
+
*/
|
|
354
|
+
async function deleteContainer(
|
|
355
|
+
accountName: string,
|
|
356
|
+
containerName: string,
|
|
357
|
+
options: AzureCommandOptions
|
|
358
|
+
): Promise<void> {
|
|
359
|
+
// Run safety checks
|
|
360
|
+
const safetyResult = await runStorageSafetyChecks(
|
|
361
|
+
'delete',
|
|
362
|
+
`${accountName}/${containerName}`,
|
|
363
|
+
options
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
displaySafetySummary({
|
|
367
|
+
operation: `delete container ${containerName}`,
|
|
368
|
+
risks: safetyResult.risks,
|
|
369
|
+
passed: safetyResult.passed,
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
if (safetyResult.requiresApproval) {
|
|
373
|
+
const result = await promptForApproval({
|
|
374
|
+
title: 'Delete Storage Container',
|
|
375
|
+
operation: `az storage container delete --name ${containerName} --account-name ${accountName}`,
|
|
376
|
+
risks: safetyResult.risks,
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
if (!result.approved) {
|
|
380
|
+
ui.warning('Operation cancelled');
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const azArgs = [
|
|
386
|
+
'storage',
|
|
387
|
+
'container',
|
|
388
|
+
'delete',
|
|
389
|
+
'--name',
|
|
390
|
+
containerName,
|
|
391
|
+
'--account-name',
|
|
392
|
+
accountName,
|
|
393
|
+
'--auth-mode',
|
|
394
|
+
'login',
|
|
395
|
+
];
|
|
396
|
+
if (options.subscription) {
|
|
397
|
+
azArgs.push('--subscription', options.subscription);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
try {
|
|
401
|
+
ui.startSpinner({ message: `Deleting container ${containerName}...` });
|
|
402
|
+
await execFileAsync('az', azArgs);
|
|
403
|
+
ui.stopSpinnerSuccess(`Container ${containerName} deleted`);
|
|
404
|
+
} catch (error: unknown) {
|
|
405
|
+
ui.stopSpinnerFail('Failed to delete container');
|
|
406
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
407
|
+
logger.error('Failed to delete container', { error: message });
|
|
408
|
+
ui.error(`Failed to delete container: ${message}`);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* List blobs in a container
|
|
414
|
+
*/
|
|
415
|
+
async function listBlobs(
|
|
416
|
+
accountName: string,
|
|
417
|
+
containerName: string,
|
|
418
|
+
options: AzureCommandOptions
|
|
419
|
+
): Promise<void> {
|
|
420
|
+
ui.header(`Blobs in ${accountName}/${containerName}`);
|
|
421
|
+
ui.newLine();
|
|
422
|
+
|
|
423
|
+
const azArgs = [
|
|
424
|
+
'storage',
|
|
425
|
+
'blob',
|
|
426
|
+
'list',
|
|
427
|
+
'--container-name',
|
|
428
|
+
containerName,
|
|
429
|
+
'--account-name',
|
|
430
|
+
accountName,
|
|
431
|
+
'-o',
|
|
432
|
+
'json',
|
|
433
|
+
'--auth-mode',
|
|
434
|
+
'login',
|
|
435
|
+
];
|
|
436
|
+
if (options.subscription) {
|
|
437
|
+
azArgs.push('--subscription', options.subscription);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
try {
|
|
441
|
+
ui.startSpinner({ message: 'Fetching blobs...' });
|
|
442
|
+
const { stdout } = await execFileAsync('az', azArgs);
|
|
443
|
+
ui.stopSpinnerSuccess('Blobs fetched');
|
|
444
|
+
|
|
445
|
+
const blobs = JSON.parse(stdout || '[]');
|
|
446
|
+
|
|
447
|
+
if (blobs.length === 0) {
|
|
448
|
+
ui.info('No blobs found');
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
ui.print(`Found ${blobs.length} blob(s)\n`);
|
|
453
|
+
|
|
454
|
+
for (const blob of blobs) {
|
|
455
|
+
const size = blob.properties?.contentLength
|
|
456
|
+
? `${Math.round(blob.properties.contentLength / 1024)} KB`
|
|
457
|
+
: '';
|
|
458
|
+
ui.print(` ${blob.name} ${ui.dim(size)}`);
|
|
459
|
+
}
|
|
460
|
+
} catch (error: unknown) {
|
|
461
|
+
ui.stopSpinnerFail('Failed to fetch blobs');
|
|
462
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
463
|
+
logger.error('Failed to list blobs', { error: message });
|
|
464
|
+
ui.error(`Failed to list blobs: ${message}`);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Show Storage help
|
|
470
|
+
*/
|
|
471
|
+
function showStorageHelp(): void {
|
|
472
|
+
ui.print(ui.bold('Storage Commands:'));
|
|
473
|
+
ui.print(' account list List storage accounts');
|
|
474
|
+
ui.print(' account show <name> -g <rg> Show account details');
|
|
475
|
+
ui.print(' container list <account> List containers');
|
|
476
|
+
ui.print(' container delete <account> <name> Delete container (requires approval)');
|
|
477
|
+
ui.print(' blob list <account> <container> List blobs');
|
|
478
|
+
}
|