@envmanager-cli/cli 0.1.4 → 0.1.6
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 +12 -1
- package/dist/bin/envmanager.js +113 -11
- package/dist/bin/envmanager.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,6 +44,7 @@ envmanager diff
|
|
|
44
44
|
| `template` | Manage .env templates |
|
|
45
45
|
| `validate` | Validate against schema |
|
|
46
46
|
| `completion` | Generate shell completion script |
|
|
47
|
+
| `debug` | Collect diagnostic info for troubleshooting |
|
|
47
48
|
|
|
48
49
|
## Shell Completion
|
|
49
50
|
|
|
@@ -91,9 +92,19 @@ envmanager pull --project 1 --environment development
|
|
|
91
92
|
envmanager pull --project my-api --environment production
|
|
92
93
|
```
|
|
93
94
|
|
|
95
|
+
### Default Environment
|
|
96
|
+
|
|
97
|
+
When `-e` / `--environment` is omitted, it defaults to `development`. You can override the default in `envmanager.json`:
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"environment": "staging"
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
94
105
|
### Multiple Organizations
|
|
95
106
|
|
|
96
|
-
If you belong to multiple organizations,
|
|
107
|
+
If you belong to multiple organizations, the CLI auto-detects the organization from your project when possible. Use `--org` to specify explicitly if needed:
|
|
97
108
|
|
|
98
109
|
```bash
|
|
99
110
|
envmanager pull --org "My Company" --project 1 --environment staging
|
package/dist/bin/envmanager.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/bin/envmanager.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command15 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/commands/login.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -88,7 +88,7 @@ function escapeHtml(str) {
|
|
|
88
88
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
89
89
|
}
|
|
90
90
|
async function startCallbackServer(expectedState, port = 8976) {
|
|
91
|
-
return new Promise((
|
|
91
|
+
return new Promise((resolve9, reject) => {
|
|
92
92
|
const timeout = setTimeout(() => {
|
|
93
93
|
server.close();
|
|
94
94
|
reject(new Error("Authentication timed out after 5 minutes"));
|
|
@@ -161,9 +161,9 @@ async function startCallbackServer(expectedState, port = 8976) {
|
|
|
161
161
|
clearTimeout(timeout);
|
|
162
162
|
server.close();
|
|
163
163
|
if (apiKey) {
|
|
164
|
-
|
|
164
|
+
resolve9({ apiKey });
|
|
165
165
|
} else {
|
|
166
|
-
|
|
166
|
+
resolve9({
|
|
167
167
|
accessToken,
|
|
168
168
|
refreshToken,
|
|
169
169
|
expiresIn: parseInt(expiresIn || "3600", 10)
|
|
@@ -1287,7 +1287,7 @@ var diffCommand = new Command6("diff").description("Show differences between loc
|
|
|
1287
1287
|
import { Command as Command7 } from "commander";
|
|
1288
1288
|
import chalk8 from "chalk";
|
|
1289
1289
|
import ora6 from "ora";
|
|
1290
|
-
var listCommand = new Command7("list").description("List projects, environments, or variables").argument("[resource]", "Resource to list: projects, environments, variables", "projects").option("--org <name>", "Organization name (required if you belong to multiple)").option("-p, --project <name-or-id>", "Project name or ID (for environments/variables)").option("-e, --environment <name>",
|
|
1290
|
+
var listCommand = new Command7("list").description("List projects, environments, or variables").argument("[resource]", "Resource to list: projects, environments, variables", "projects").option("--org <name>", "Organization name (required if you belong to multiple)").option("-p, --project <name-or-id>", "Project name or ID (for environments/variables)").option("-e, --environment <name>", 'Environment name (default: "development")').option("-v, --verbose", "Show IDs").action(async (resource, options) => {
|
|
1291
1291
|
const spinner = ora6("Connecting...").start();
|
|
1292
1292
|
try {
|
|
1293
1293
|
const config = loadConfig();
|
|
@@ -1511,11 +1511,11 @@ async function subscribeToVariableChanges(environmentId, onEvent, onStatus) {
|
|
|
1511
1511
|
onStatus?.("connected");
|
|
1512
1512
|
}
|
|
1513
1513
|
});
|
|
1514
|
-
const subscription = await new Promise((
|
|
1514
|
+
const subscription = await new Promise((resolve9, reject) => {
|
|
1515
1515
|
channel.subscribe(async (status, err) => {
|
|
1516
1516
|
if (status === "SUBSCRIBED") {
|
|
1517
1517
|
onStatus?.("connected");
|
|
1518
|
-
|
|
1518
|
+
resolve9({
|
|
1519
1519
|
channel,
|
|
1520
1520
|
environmentId,
|
|
1521
1521
|
unsubscribe: async () => {
|
|
@@ -2234,7 +2234,7 @@ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsS
|
|
|
2234
2234
|
import { resolve as resolve6 } from "path";
|
|
2235
2235
|
import { parse as parseDotenv4 } from "dotenv";
|
|
2236
2236
|
var templateCommand = new Command11("template").description("Manage environment templates");
|
|
2237
|
-
templateCommand.command("generate").description("Generate .env file from template and EnvManager values").option("-t, --template <file>", "Template file (default: .env.template or .env.template.yaml)").option("-o, --output <file>", "Output file (default: .env)").option("-e, --environment <name>",
|
|
2237
|
+
templateCommand.command("generate").description("Generate .env file from template and EnvManager values").option("-t, --template <file>", "Template file (default: .env.template or .env.template.yaml)").option("-o, --output <file>", "Output file (default: .env)").option("-e, --environment <name>", 'Environment name (default: "development")').option("-p, --project <id>", "Project ID (default: from config)").option("-f, --force", "Overwrite existing output file").action(async (options) => {
|
|
2238
2238
|
const spinner = ora9("Generating .env from template...").start();
|
|
2239
2239
|
try {
|
|
2240
2240
|
const config = loadConfig();
|
|
@@ -2336,7 +2336,7 @@ File ${outputPath} already exists. Use --force to overwrite.`));
|
|
|
2336
2336
|
process.exit(1);
|
|
2337
2337
|
}
|
|
2338
2338
|
});
|
|
2339
|
-
templateCommand.command("sync").description("Compare template with EnvManager and report differences").option("-t, --template <file>", "Template file (default: .env.template or .env.template.yaml)").option("-e, --environment <name>",
|
|
2339
|
+
templateCommand.command("sync").description("Compare template with EnvManager and report differences").option("-t, --template <file>", "Template file (default: .env.template or .env.template.yaml)").option("-e, --environment <name>", 'Environment name (default: "development")').option("-p, --project <id>", "Project ID (default: from config)").action(async (options) => {
|
|
2340
2340
|
const spinner = ora9("Comparing template with EnvManager...").start();
|
|
2341
2341
|
try {
|
|
2342
2342
|
const config = loadConfig();
|
|
@@ -2652,7 +2652,7 @@ function jsonToSchema(json) {
|
|
|
2652
2652
|
}
|
|
2653
2653
|
|
|
2654
2654
|
// src/commands/validate.ts
|
|
2655
|
-
var validateCommand = new Command12("validate").description("Validate local .env file against schema from EnvManager or local file").option("-e, --environment <name>",
|
|
2655
|
+
var validateCommand = new Command12("validate").description("Validate local .env file against schema from EnvManager or local file").option("-e, --environment <name>", 'Environment name (default: "development")').option("-p, --project <id>", "Project ID (default: from config)").option("--org <name>", "Organization name (required if you belong to multiple)").option("-i, --input <file>", "Input .env file (default: .env)").option("-s, --schema <file>", "Local schema JSON file (skip fetching from EnvManager)").option("--strict", "Fail on warnings (extra variables not in schema)").action(async (options) => {
|
|
2656
2656
|
const spinner = ora10("Validating environment...").start();
|
|
2657
2657
|
try {
|
|
2658
2658
|
const config = loadConfig();
|
|
@@ -2978,8 +2978,109 @@ var completionCommand = new Command13("completion").description("Generate shell
|
|
|
2978
2978
|
}
|
|
2979
2979
|
});
|
|
2980
2980
|
|
|
2981
|
+
// src/commands/debug.ts
|
|
2982
|
+
import { Command as Command14 } from "commander";
|
|
2983
|
+
import chalk14 from "chalk";
|
|
2984
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
2985
|
+
import { fileURLToPath } from "url";
|
|
2986
|
+
import { dirname as dirname2, resolve as resolve8 } from "path";
|
|
2987
|
+
function getCliVersion() {
|
|
2988
|
+
try {
|
|
2989
|
+
const __dirname2 = dirname2(fileURLToPath(import.meta.url));
|
|
2990
|
+
const pkg = JSON.parse(readFileSync9(resolve8(__dirname2, "../../package.json"), "utf-8"));
|
|
2991
|
+
return pkg.version || "unknown";
|
|
2992
|
+
} catch {
|
|
2993
|
+
return "unknown";
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
var debugCommand = new Command14("debug").description("Collect diagnostic info for troubleshooting").action(async () => {
|
|
2997
|
+
const lines = [];
|
|
2998
|
+
const log = (msg) => lines.push(msg);
|
|
2999
|
+
log("=== EnvManager CLI Debug Report ===");
|
|
3000
|
+
log(`Timestamp: ${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
3001
|
+
log(`CLI Version: ${getCliVersion()}`);
|
|
3002
|
+
log(`Node: ${process.version}`);
|
|
3003
|
+
log(`Platform: ${process.platform} ${process.arch}`);
|
|
3004
|
+
log("");
|
|
3005
|
+
log("--- Config ---");
|
|
3006
|
+
const configPath = getConfigPath();
|
|
3007
|
+
const config = loadConfig();
|
|
3008
|
+
log(`Config file: ${configPath || "not found"}`);
|
|
3009
|
+
if (config) {
|
|
3010
|
+
log(` project_id: ${config.project_id || "not set"}`);
|
|
3011
|
+
log(` project_name: ${config.project_name || "not set"}`);
|
|
3012
|
+
log(` environment: ${config.environment || "not set"}`);
|
|
3013
|
+
log(` organization_id: ${config.organization_id || "not set"}`);
|
|
3014
|
+
log(` api_url: ${config.api_url || "not set"}`);
|
|
3015
|
+
}
|
|
3016
|
+
log("");
|
|
3017
|
+
log("--- Authentication ---");
|
|
3018
|
+
const envApiKey = getApiKeyFromEnv();
|
|
3019
|
+
const storedApiKey = getStoredApiKey();
|
|
3020
|
+
const storedApiUrl = getStoredApiUrl();
|
|
3021
|
+
const creds = getCredentials();
|
|
3022
|
+
if (envApiKey) {
|
|
3023
|
+
log(`Auth method: Environment API key (${envApiKey.substring(0, 11)}...)`);
|
|
3024
|
+
} else if (storedApiKey) {
|
|
3025
|
+
log(`Auth method: CLI session key (${storedApiKey.substring(0, 11)}...)`);
|
|
3026
|
+
} else if (creds?.accessToken) {
|
|
3027
|
+
log("Auth method: Legacy session tokens");
|
|
3028
|
+
if (creds.expiresAt) {
|
|
3029
|
+
const remaining = Math.round((creds.expiresAt - Date.now()) / 1e3);
|
|
3030
|
+
log(` Token expires in: ${remaining > 0 ? `${remaining}s` : "EXPIRED"}`);
|
|
3031
|
+
}
|
|
3032
|
+
} else {
|
|
3033
|
+
log("Auth method: Not authenticated");
|
|
3034
|
+
}
|
|
3035
|
+
log(`API URL: ${storedApiUrl || process.env.ENVMANAGER_API_URL || "default (production)"}`);
|
|
3036
|
+
log("");
|
|
3037
|
+
log("--- API Connection ---");
|
|
3038
|
+
try {
|
|
3039
|
+
const start = Date.now();
|
|
3040
|
+
const client = await createClient();
|
|
3041
|
+
const authTime = Date.now() - start;
|
|
3042
|
+
log(`Auth exchange: ${authTime}ms`);
|
|
3043
|
+
const userStart = Date.now();
|
|
3044
|
+
const { data: { user }, error: userError } = await client.auth.getUser();
|
|
3045
|
+
const userTime = Date.now() - userStart;
|
|
3046
|
+
log(`getUser: ${userTime}ms`);
|
|
3047
|
+
if (userError) {
|
|
3048
|
+
log(` ERROR: ${userError.message}`);
|
|
3049
|
+
} else if (user) {
|
|
3050
|
+
log(` User ID: ${user.id}`);
|
|
3051
|
+
log(` Email: ${user.email}`);
|
|
3052
|
+
}
|
|
3053
|
+
if (user) {
|
|
3054
|
+
const orgStart = Date.now();
|
|
3055
|
+
const { data: memberships, error: orgError } = await client.from("organization_members").select("organization_id, role, organizations(id, name)").eq("user_id", user.id);
|
|
3056
|
+
const orgTime = Date.now() - orgStart;
|
|
3057
|
+
log(`Org query: ${orgTime}ms`);
|
|
3058
|
+
if (orgError) {
|
|
3059
|
+
log(` ERROR: ${orgError.message}`);
|
|
3060
|
+
} else if (memberships) {
|
|
3061
|
+
log(` Organizations (${memberships.length}):`);
|
|
3062
|
+
memberships.forEach((m) => {
|
|
3063
|
+
const org = m.organizations;
|
|
3064
|
+
const orgName = Array.isArray(org) ? org[0]?.name : org?.name || "Unknown";
|
|
3065
|
+
const orgId = Array.isArray(org) ? org[0]?.id : org?.id || "?";
|
|
3066
|
+
log(` - ${orgName} (${m.role}) [${orgId.substring(0, 8)}...]`);
|
|
3067
|
+
});
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
} catch (error) {
|
|
3071
|
+
log(` ERROR: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
3072
|
+
}
|
|
3073
|
+
log("");
|
|
3074
|
+
log("=== End Debug Report ===");
|
|
3075
|
+
const output = lines.join("\n");
|
|
3076
|
+
console.log(output);
|
|
3077
|
+
console.log("");
|
|
3078
|
+
console.log(chalk14.gray("Copy the output above and share it for troubleshooting."));
|
|
3079
|
+
console.log(chalk14.gray("Note: API keys are partially redacted. No secrets are exposed."));
|
|
3080
|
+
});
|
|
3081
|
+
|
|
2981
3082
|
// src/bin/envmanager.ts
|
|
2982
|
-
var program = new
|
|
3083
|
+
var program = new Command15();
|
|
2983
3084
|
program.name("envmanager").description("CLI for EnvManager - secure environment variable management").version("0.1.0");
|
|
2984
3085
|
program.addCommand(loginCommand);
|
|
2985
3086
|
program.addCommand(logoutCommand);
|
|
@@ -2995,5 +3096,6 @@ program.addCommand(templateCommand);
|
|
|
2995
3096
|
program.addCommand(validateCommand);
|
|
2996
3097
|
program.addCommand(completionCommand);
|
|
2997
3098
|
program.addCommand(completeCommand);
|
|
3099
|
+
program.addCommand(debugCommand);
|
|
2998
3100
|
program.parse();
|
|
2999
3101
|
//# sourceMappingURL=envmanager.js.map
|