xtra-cli 0.1.10 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/access.js +2 -2
- package/dist/commands/branch.js +8 -12
- package/dist/commands/checkout.js +3 -4
- package/dist/commands/diff.js +4 -5
- package/dist/commands/doctor.js +50 -62
- package/dist/commands/env.js +2 -2
- package/dist/commands/export.js +4 -5
- package/dist/commands/generate.js +3 -4
- package/dist/commands/history.js +2 -2
- package/dist/commands/import.js +3 -4
- package/dist/commands/integration.js +6 -6
- package/dist/commands/local.js +20 -20
- package/dist/commands/rollback.js +2 -3
- package/dist/commands/rotate.js +3 -4
- package/dist/commands/run.js +9 -18
- package/dist/commands/secrets.js +9 -8
- package/dist/commands/simulate.js +8 -8
- package/dist/commands/status.js +8 -9
- package/dist/commands/template.js +21 -21
- package/dist/commands/ui.js +168 -97
- package/dist/commands/watch.js +9 -9
- package/dist/lib/config.js +22 -1
- package/package.json +1 -1
package/dist/commands/access.js
CHANGED
|
@@ -29,7 +29,7 @@ exports.accessCommand = new commander_1.Command("access")
|
|
|
29
29
|
.action(async (options) => {
|
|
30
30
|
let { project, secret, duration, reason } = options;
|
|
31
31
|
if (!project) {
|
|
32
|
-
project = (0, config_1.
|
|
32
|
+
project = (0, config_1.getRcConfig)().project;
|
|
33
33
|
}
|
|
34
34
|
if (!project) {
|
|
35
35
|
console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
|
|
@@ -97,7 +97,7 @@ exports.accessCommand = new commander_1.Command("access")
|
|
|
97
97
|
if (result.expiresAt) {
|
|
98
98
|
console.log(chalk_1.default.blue(`Access granted until: ${new Date(result.expiresAt).toLocaleString()}`));
|
|
99
99
|
}
|
|
100
|
-
// Audit log
|
|
100
|
+
// Audit log — privileged action
|
|
101
101
|
logAuditSafe(options.decision === "approved" ? "ACCESS_APPROVED" : "ACCESS_REJECTED", null, { requestId, decision: options.decision, expiresAt: result.expiresAt });
|
|
102
102
|
}
|
|
103
103
|
catch (error) {
|
package/dist/commands/branch.js
CHANGED
|
@@ -22,9 +22,8 @@ exports.branchCommand
|
|
|
22
22
|
// Access parent options (project ID)
|
|
23
23
|
const parentOpts = exports.branchCommand.opts();
|
|
24
24
|
let { project } = parentOpts;
|
|
25
|
-
if (!project)
|
|
26
|
-
project = (0, config_1.
|
|
27
|
-
}
|
|
25
|
+
if (!project)
|
|
26
|
+
project = (0, config_1.getRcConfig)().project;
|
|
28
27
|
if (!project) {
|
|
29
28
|
console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or checkout a branch."));
|
|
30
29
|
process.exit(1);
|
|
@@ -78,9 +77,8 @@ exports.branchCommand
|
|
|
78
77
|
const parentOpts = exports.branchCommand.opts();
|
|
79
78
|
let { project } = parentOpts;
|
|
80
79
|
const { description } = options;
|
|
81
|
-
if (!project)
|
|
82
|
-
project = (0, config_1.
|
|
83
|
-
}
|
|
80
|
+
if (!project)
|
|
81
|
+
project = (0, config_1.getRcConfig)().project;
|
|
84
82
|
if (!project) {
|
|
85
83
|
console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
|
|
86
84
|
process.exit(1);
|
|
@@ -110,9 +108,8 @@ exports.branchCommand
|
|
|
110
108
|
const parentOpts = exports.branchCommand.opts();
|
|
111
109
|
let { project } = parentOpts;
|
|
112
110
|
const { yes } = options;
|
|
113
|
-
if (!project)
|
|
114
|
-
project = (0, config_1.
|
|
115
|
-
}
|
|
111
|
+
if (!project)
|
|
112
|
+
project = (0, config_1.getRcConfig)().project;
|
|
116
113
|
if (!project) {
|
|
117
114
|
console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
|
|
118
115
|
process.exit(1);
|
|
@@ -176,9 +173,8 @@ exports.branchCommand
|
|
|
176
173
|
const parentOpts = exports.branchCommand.opts();
|
|
177
174
|
let { project } = parentOpts;
|
|
178
175
|
const { newName, description } = options;
|
|
179
|
-
if (!project)
|
|
180
|
-
project = (0, config_1.
|
|
181
|
-
}
|
|
176
|
+
if (!project)
|
|
177
|
+
project = (0, config_1.getRcConfig)().project;
|
|
182
178
|
if (!project) {
|
|
183
179
|
console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or checkout a branch."));
|
|
184
180
|
process.exit(1);
|
|
@@ -17,9 +17,8 @@ exports.checkoutCommand = new commander_1.Command("checkout")
|
|
|
17
17
|
.action(async (branchName, options) => {
|
|
18
18
|
let { project } = options;
|
|
19
19
|
// Try to get project from config if not provided
|
|
20
|
-
if (!project)
|
|
21
|
-
project = (0, config_1.
|
|
22
|
-
}
|
|
20
|
+
if (!project)
|
|
21
|
+
project = (0, config_1.getRcConfig)().project;
|
|
23
22
|
if (!project) {
|
|
24
23
|
console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
|
|
25
24
|
process.exit(1);
|
|
@@ -60,7 +59,7 @@ exports.checkoutCommand = new commander_1.Command("checkout")
|
|
|
60
59
|
// Save to config
|
|
61
60
|
(0, config_1.setConfig)("branch", selectedBranch);
|
|
62
61
|
(0, config_1.setConfig)("project", project);
|
|
63
|
-
console.log(chalk_1.default.green(
|
|
62
|
+
console.log(chalk_1.default.green(`✔ Switched to branch '${selectedBranch}'`));
|
|
64
63
|
}
|
|
65
64
|
catch (error) {
|
|
66
65
|
spinner.fail("Failed to fetch branches");
|
package/dist/commands/diff.js
CHANGED
|
@@ -55,11 +55,10 @@ exports.diffCommand = new commander_1.Command("diff")
|
|
|
55
55
|
.action(async (env1, env2, options) => {
|
|
56
56
|
let { project, env, branch, show } = options;
|
|
57
57
|
// Use config fallback
|
|
58
|
-
if (!project)
|
|
59
|
-
project = (0, config_1.
|
|
60
|
-
}
|
|
58
|
+
if (!project)
|
|
59
|
+
project = (0, config_1.getRcConfig)().project;
|
|
61
60
|
if (!branch) {
|
|
62
|
-
branch = (0, config_1.
|
|
61
|
+
branch = (0, config_1.getRcConfig)().branch || "main";
|
|
63
62
|
}
|
|
64
63
|
if (!project) {
|
|
65
64
|
console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
|
|
@@ -155,7 +154,7 @@ function compareSecrets(source, target, show) {
|
|
|
155
154
|
}
|
|
156
155
|
});
|
|
157
156
|
if (!hasDiff) {
|
|
158
|
-
console.log(chalk_1.default.green("
|
|
157
|
+
console.log(chalk_1.default.green("✔ No differences found."));
|
|
159
158
|
}
|
|
160
159
|
else if (!show) {
|
|
161
160
|
console.log(chalk_1.default.gray("\n(Use --show to reveal secret values)"));
|
package/dist/commands/doctor.js
CHANGED
|
@@ -39,9 +39,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
39
39
|
exports.doctorCommand = void 0;
|
|
40
40
|
/**
|
|
41
41
|
* doctor.ts — Diagnose common xtra-cli setup issues
|
|
42
|
-
*
|
|
43
|
-
* Runs a series of self-diagnostic checks and reports
|
|
44
|
-
* pass / warn / fail for each one.
|
|
45
42
|
*/
|
|
46
43
|
const commander_1 = require("commander");
|
|
47
44
|
const chalk_1 = __importDefault(require("chalk"));
|
|
@@ -49,128 +46,119 @@ const fs = __importStar(require("fs"));
|
|
|
49
46
|
const path = __importStar(require("path"));
|
|
50
47
|
const axios_1 = __importDefault(require("axios"));
|
|
51
48
|
const config_1 = require("../lib/config");
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
const
|
|
49
|
+
// ─── Box Drawing Helpers ─────────────────────────────────────────────────────
|
|
50
|
+
const W = 65;
|
|
51
|
+
const B = { tl: "╭", tr: "╮", bl: "╰", br: "╯", h: "─", v: "│" };
|
|
52
|
+
function hline(w) { return B.h.repeat(w); }
|
|
53
|
+
const PASS = chalk_1.default.green("✓ ");
|
|
54
|
+
const FAIL = chalk_1.default.red("✗ ");
|
|
55
|
+
const WARN = chalk_1.default.yellow("⚠ ");
|
|
55
56
|
async function runChecks() {
|
|
56
57
|
const checks = [];
|
|
57
58
|
const config = (0, config_1.getConfig)();
|
|
58
|
-
//
|
|
59
|
+
// 1. Node Version
|
|
59
60
|
const nodeMajor = parseInt(process.versions.node.split(".")[0]);
|
|
60
61
|
checks.push({
|
|
61
62
|
name: "Node.js Version",
|
|
62
63
|
status: nodeMajor >= 18 ? "pass" : "fail",
|
|
63
64
|
message: `v${process.versions.node} ${nodeMajor >= 18 ? "(OK)" : "(requires >=18)"}`,
|
|
64
65
|
});
|
|
65
|
-
//
|
|
66
|
+
// 2. Auth Token
|
|
66
67
|
const token = (0, config_1.getAuthToken)();
|
|
67
68
|
checks.push({
|
|
68
69
|
name: "Auth Token",
|
|
69
70
|
status: token ? "pass" : "fail",
|
|
70
71
|
message: token ? `Set (${token.substring(0, 8)}...)` : "Not set — run 'xtra login'",
|
|
71
72
|
});
|
|
72
|
-
//
|
|
73
|
-
const apiUrl = config.apiUrl || process.env.XTRA_API_URL;
|
|
73
|
+
// 3. API URL Configured
|
|
74
|
+
const apiUrl = config.apiUrl || process.env.XTRA_API_URL || "https://xtra-security.vercel.app/api";
|
|
74
75
|
checks.push({
|
|
75
76
|
name: "API URL",
|
|
76
|
-
status: apiUrl ? "pass" : "warn",
|
|
77
|
-
message: apiUrl
|
|
77
|
+
status: config.apiUrl || process.env.XTRA_API_URL ? "pass" : "warn",
|
|
78
|
+
message: apiUrl,
|
|
78
79
|
});
|
|
79
|
-
//
|
|
80
|
+
// 4. API Reachability
|
|
80
81
|
try {
|
|
81
|
-
const res = await axios_1.default.get(`${
|
|
82
|
+
const res = await axios_1.default.get(`${apiUrl}/health`, { timeout: 4000 });
|
|
82
83
|
checks.push({
|
|
83
84
|
name: "API Connectivity",
|
|
84
85
|
status: res.status === 200 ? "pass" : "warn",
|
|
85
|
-
message: `${
|
|
86
|
+
message: `${res.status} ${res.statusText}`,
|
|
86
87
|
});
|
|
87
88
|
}
|
|
88
89
|
catch (e) {
|
|
89
|
-
const msg = e.code === "ECONNREFUSED"
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
const msg = e.code === "ECONNREFUSED" ? "Connection refused (offline?)"
|
|
91
|
+
: e.code === "ETIMEDOUT" ? "Timed out (unreachable)"
|
|
92
|
+
: e.response?.status === 404 ? "API reachable (health endpoint missing)"
|
|
93
|
+
: e.message;
|
|
94
|
+
// Special case: if it hits a 404 it means DNS and port work, but route is missing
|
|
95
|
+
const status = e.response?.status === 404 ? "pass" : "fail";
|
|
96
|
+
checks.push({ name: "API Connectivity", status, message: msg });
|
|
95
97
|
}
|
|
96
|
-
//
|
|
97
|
-
const project = (0, config_1.
|
|
98
|
+
// 5. Active Project
|
|
99
|
+
const project = (0, config_1.getRcConfig)().project;
|
|
98
100
|
checks.push({
|
|
99
101
|
name: "Active Project",
|
|
100
102
|
status: project ? "pass" : "warn",
|
|
101
103
|
message: project ? project : "Not set — run 'xtra project set <id>'",
|
|
102
104
|
});
|
|
103
|
-
//
|
|
104
|
-
const branch = (0, config_1.
|
|
105
|
+
// 6. Active Branch
|
|
106
|
+
const branch = (0, config_1.getRcConfig)().branch || "main";
|
|
105
107
|
checks.push({
|
|
106
108
|
name: "Active Branch",
|
|
107
109
|
status: "pass",
|
|
108
|
-
message: branch
|
|
110
|
+
message: branch,
|
|
109
111
|
});
|
|
110
|
-
//
|
|
112
|
+
// 7. Config files
|
|
111
113
|
const rcPath = path.join(process.cwd(), ".xtrarc");
|
|
112
114
|
const jsonPath = path.join(process.cwd(), "xtra.json");
|
|
113
|
-
const
|
|
115
|
+
const hasConfig = fs.existsSync(rcPath) || fs.existsSync(jsonPath);
|
|
114
116
|
checks.push({
|
|
115
|
-
name: "Project Config
|
|
116
|
-
status:
|
|
117
|
-
message:
|
|
118
|
-
? fs.existsSync(rcPath) ? ".xtrarc found" : "xtra.json found"
|
|
119
|
-
: "Not found — run 'xtra init' to create one",
|
|
120
|
-
});
|
|
121
|
-
// ── 8. .env file present ────────────────────────────────────────────────────
|
|
122
|
-
const envPath = path.join(process.cwd(), ".env");
|
|
123
|
-
checks.push({
|
|
124
|
-
name: ".env File",
|
|
125
|
-
status: "pass",
|
|
126
|
-
message: fs.existsSync(envPath) ? ".env found" : "No .env (not required if using xtra run)",
|
|
127
|
-
});
|
|
128
|
-
// ── 9. XTRA_MACHINE_TOKEN (for CI) ─────────────────────────────────────────
|
|
129
|
-
const machineToken = process.env.XTRA_MACHINE_TOKEN;
|
|
130
|
-
checks.push({
|
|
131
|
-
name: "CI Machine Token",
|
|
132
|
-
status: "pass", // Always pass — optional
|
|
133
|
-
message: machineToken ? "XTRA_MACHINE_TOKEN is set ✔" : "Not set (only needed for CI/CD pipelines)",
|
|
117
|
+
name: "Project Config",
|
|
118
|
+
status: hasConfig ? "pass" : "warn",
|
|
119
|
+
message: hasConfig ? (fs.existsSync(rcPath) ? ".xtrarc found" : "xtra.json found") : "Not found (run 'xtra init')",
|
|
134
120
|
});
|
|
135
121
|
return checks;
|
|
136
122
|
}
|
|
137
123
|
exports.doctorCommand = new commander_1.Command("doctor")
|
|
138
|
-
.description("Diagnose
|
|
124
|
+
.description("Diagnose CLI configuration and API connectivity")
|
|
139
125
|
.option("--json", "Output results as JSON", false)
|
|
140
126
|
.action(async (options) => {
|
|
141
127
|
if (!options.json) {
|
|
142
|
-
console.log(
|
|
128
|
+
console.log();
|
|
129
|
+
console.log(chalk_1.default.bold.cyan(" ⚕ XtraSecurity Diagnostics"));
|
|
130
|
+
console.log(chalk_1.default.hex("#4a5568")(" " + B.tl + hline(W) + B.tr));
|
|
143
131
|
}
|
|
144
132
|
const checks = await runChecks();
|
|
145
133
|
if (options.json) {
|
|
146
134
|
process.stdout.write(JSON.stringify(checks, null, 2) + "\n");
|
|
147
135
|
return;
|
|
148
136
|
}
|
|
149
|
-
let failures = 0;
|
|
150
|
-
let warnings = 0;
|
|
137
|
+
let failures = 0, warnings = 0;
|
|
151
138
|
for (const c of checks) {
|
|
152
|
-
const icon = c.status === "pass" ? PASS : c.status === "warn" ? WARN : FAIL;
|
|
153
|
-
const nameStr = chalk_1.default.bold(c.name.padEnd(22));
|
|
154
|
-
const msgStr = c.status === "fail"
|
|
155
|
-
? chalk_1.default.red(c.message)
|
|
156
|
-
: c.status === "warn"
|
|
157
|
-
? chalk_1.default.yellow(c.message)
|
|
158
|
-
: chalk_1.default.gray(c.message);
|
|
159
|
-
console.log(`${icon} ${nameStr}${msgStr}`);
|
|
160
139
|
if (c.status === "fail")
|
|
161
140
|
failures++;
|
|
162
141
|
if (c.status === "warn")
|
|
163
142
|
warnings++;
|
|
143
|
+
const icon = c.status === "pass" ? PASS : c.status === "warn" ? WARN : FAIL;
|
|
144
|
+
const name = chalk_1.default.bold(chalk_1.default.white(c.name.padEnd(20)));
|
|
145
|
+
const msg = c.status === "pass" ? chalk_1.default.hex("#94a3b8")(c.message)
|
|
146
|
+
: c.status === "warn" ? chalk_1.default.yellow(c.message)
|
|
147
|
+
: chalk_1.default.red(c.message);
|
|
148
|
+
console.log(chalk_1.default.hex("#4a5568")(" " + B.v) + ` ${icon}${name} ${msg}`.padEnd(W) + chalk_1.default.hex("#4a5568")(B.v));
|
|
164
149
|
}
|
|
150
|
+
console.log(chalk_1.default.hex("#4a5568")(" " + B.bl + hline(W) + B.br));
|
|
165
151
|
console.log();
|
|
166
152
|
if (failures === 0 && warnings === 0) {
|
|
167
|
-
console.log(chalk_1.default.green
|
|
153
|
+
console.log(chalk_1.default.green(" ✓ All systems operational. The CLI is ready to use."));
|
|
168
154
|
}
|
|
169
155
|
else {
|
|
156
|
+
const parts = [];
|
|
170
157
|
if (failures > 0)
|
|
171
|
-
|
|
158
|
+
parts.push(chalk_1.default.red(`${failures} error(s)`));
|
|
172
159
|
if (warnings > 0)
|
|
173
|
-
|
|
160
|
+
parts.push(chalk_1.default.yellow(`${warnings} warning(s)`));
|
|
161
|
+
console.log(` Found ${parts.join(" and ")}.`);
|
|
174
162
|
}
|
|
175
163
|
console.log();
|
|
176
164
|
});
|
package/dist/commands/env.js
CHANGED
|
@@ -21,9 +21,9 @@ exports.envCommand
|
|
|
21
21
|
.action(async (options) => {
|
|
22
22
|
try {
|
|
23
23
|
let projectId = options.project;
|
|
24
|
-
const branch = options.branch || (0, config_1.
|
|
24
|
+
const branch = options.branch || (0, config_1.getRcConfig)().branch || "main";
|
|
25
25
|
if (!projectId) {
|
|
26
|
-
projectId = (0, config_1.
|
|
26
|
+
projectId = (0, config_1.getRcConfig)().project;
|
|
27
27
|
if (!projectId) {
|
|
28
28
|
console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
|
|
29
29
|
process.exit(1);
|
package/dist/commands/export.js
CHANGED
|
@@ -21,11 +21,10 @@ exports.exportCommand = new commander_1.Command("export")
|
|
|
21
21
|
.action(async (options) => {
|
|
22
22
|
let { project, env, branch, format, output } = options;
|
|
23
23
|
// Use config fallback
|
|
24
|
-
if (!project)
|
|
25
|
-
project = (0, config_1.
|
|
26
|
-
}
|
|
24
|
+
if (!project)
|
|
25
|
+
project = (0, config_1.getRcConfig)().project;
|
|
27
26
|
if (!branch) {
|
|
28
|
-
branch = (0, config_1.
|
|
27
|
+
branch = (0, config_1.getRcConfig)().branch || "main";
|
|
29
28
|
}
|
|
30
29
|
// Normalize Env
|
|
31
30
|
const envMap = { dev: "development", stg: "staging", prod: "production" };
|
|
@@ -63,7 +62,7 @@ exports.exportCommand = new commander_1.Command("export")
|
|
|
63
62
|
if (output) {
|
|
64
63
|
const outputPath = path_1.default.resolve(process.cwd(), output);
|
|
65
64
|
fs_1.default.writeFileSync(outputPath, content, "utf-8");
|
|
66
|
-
console.log(chalk_1.default.green(
|
|
65
|
+
console.log(chalk_1.default.green(`✔ Secrets exported to ${outputPath}`));
|
|
67
66
|
}
|
|
68
67
|
else {
|
|
69
68
|
console.log(content);
|
|
@@ -80,11 +80,10 @@ exports.generateCommand = new commander_1.Command("generate")
|
|
|
80
80
|
.action(async (options) => {
|
|
81
81
|
let { project, env, branch, output, format, force } = options;
|
|
82
82
|
// Use config fallback
|
|
83
|
-
if (!project)
|
|
84
|
-
project = (0, config_1.
|
|
85
|
-
}
|
|
83
|
+
if (!project)
|
|
84
|
+
project = (0, config_1.getRcConfig)().project;
|
|
86
85
|
if (!branch) {
|
|
87
|
-
branch = (0, config_1.
|
|
86
|
+
branch = (0, config_1.getRcConfig)().branch || "main";
|
|
88
87
|
}
|
|
89
88
|
// Normalize Env
|
|
90
89
|
const envMap = { dev: "development", stg: "staging", prod: "production" };
|
package/dist/commands/history.js
CHANGED
|
@@ -18,7 +18,7 @@ exports.historyCommand
|
|
|
18
18
|
try {
|
|
19
19
|
let projectId = options.project;
|
|
20
20
|
if (!projectId) {
|
|
21
|
-
projectId = (0, config_1.
|
|
21
|
+
projectId = (0, config_1.getRcConfig)().project;
|
|
22
22
|
if (!projectId) {
|
|
23
23
|
console.error(chalk_1.default.red("Error: Project ID not found. Use -p <id> or run 'xtra project set' first."));
|
|
24
24
|
process.exit(1);
|
|
@@ -56,7 +56,7 @@ exports.rollbackCommand
|
|
|
56
56
|
try {
|
|
57
57
|
let projectId = options.project;
|
|
58
58
|
if (!projectId) {
|
|
59
|
-
projectId = (0, config_1.
|
|
59
|
+
projectId = (0, config_1.getRcConfig)().project;
|
|
60
60
|
if (!projectId) {
|
|
61
61
|
console.error(chalk_1.default.red("Error: Project ID not found. Use -p <id> or run 'xtra project set' first."));
|
|
62
62
|
process.exit(1);
|
package/dist/commands/import.js
CHANGED
|
@@ -24,11 +24,10 @@ exports.importCommand = new commander_1.Command("import")
|
|
|
24
24
|
.action(async (file, options) => {
|
|
25
25
|
let { project, env, branch, format, prefix } = options;
|
|
26
26
|
// Use config fallback
|
|
27
|
-
if (!project)
|
|
28
|
-
project = (0, config_1.
|
|
29
|
-
}
|
|
27
|
+
if (!project)
|
|
28
|
+
project = (0, config_1.getRcConfig)().project;
|
|
30
29
|
if (!branch) {
|
|
31
|
-
branch = (0, config_1.
|
|
30
|
+
branch = (0, config_1.getRcConfig)().branch || "main";
|
|
32
31
|
}
|
|
33
32
|
// Normalize Env
|
|
34
33
|
const envMap = { dev: "development", stg: "staging", prod: "production" };
|
|
@@ -23,7 +23,7 @@ exports.integrationCommand
|
|
|
23
23
|
try {
|
|
24
24
|
let projectId = options.project;
|
|
25
25
|
if (!projectId) {
|
|
26
|
-
projectId = (0, config_1.
|
|
26
|
+
projectId = (0, config_1.getRcConfig)().project;
|
|
27
27
|
if (!projectId) {
|
|
28
28
|
console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
|
|
29
29
|
process.exit(1);
|
|
@@ -48,7 +48,7 @@ exports.integrationCommand
|
|
|
48
48
|
name: "repo",
|
|
49
49
|
message: "Select a repository to sync to:",
|
|
50
50
|
choices: repos.map((r) => ({
|
|
51
|
-
name: `${r.fullName} ${r.private ? "(
|
|
51
|
+
name: `${r.fullName} ${r.private ? "(🔒)" : ""}`,
|
|
52
52
|
value: r.id.toString(),
|
|
53
53
|
short: r.fullName
|
|
54
54
|
}))
|
|
@@ -84,10 +84,10 @@ exports.integrationCommand
|
|
|
84
84
|
// Show details
|
|
85
85
|
result.results.forEach((r) => {
|
|
86
86
|
if (r.success) {
|
|
87
|
-
console.log(chalk_1.default.green(
|
|
87
|
+
console.log(chalk_1.default.green(`✓ ${r.key}`));
|
|
88
88
|
}
|
|
89
89
|
else {
|
|
90
|
-
console.log(chalk_1.default.red(
|
|
90
|
+
console.log(chalk_1.default.red(`✗ ${r.key}: ${r.error}`));
|
|
91
91
|
}
|
|
92
92
|
});
|
|
93
93
|
}
|
|
@@ -109,7 +109,7 @@ exports.kubernetesCommand
|
|
|
109
109
|
try {
|
|
110
110
|
let projectId = options.project;
|
|
111
111
|
if (!projectId) {
|
|
112
|
-
projectId = (0, config_1.
|
|
112
|
+
projectId = (0, config_1.getRcConfig)().project;
|
|
113
113
|
if (!projectId) {
|
|
114
114
|
console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
|
|
115
115
|
process.exit(1);
|
|
@@ -153,7 +153,7 @@ exports.kubernetesCommand
|
|
|
153
153
|
}
|
|
154
154
|
let projectId = options.project;
|
|
155
155
|
if (!projectId) {
|
|
156
|
-
projectId = (0, config_1.
|
|
156
|
+
projectId = (0, config_1.getRcConfig)().project;
|
|
157
157
|
if (!projectId) {
|
|
158
158
|
console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
|
|
159
159
|
process.exit(1);
|
package/dist/commands/local.js
CHANGED
|
@@ -38,12 +38,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.localCommand = void 0;
|
|
40
40
|
/**
|
|
41
|
-
* local.ts
|
|
41
|
+
* local.ts — Toggle between cloud/local-only mode for offline development
|
|
42
42
|
*
|
|
43
43
|
* In "local" mode:
|
|
44
44
|
* - xtra run reads from .env.local instead of calling the API
|
|
45
45
|
* - A flag XTRA_LOCAL_MODE=true is written to the CLI config
|
|
46
|
-
* - All API calls are bypassed
|
|
46
|
+
* - All API calls are bypassed — completely offline capable
|
|
47
47
|
*
|
|
48
48
|
* Usage:
|
|
49
49
|
* xtra local on # Enable local mode (reads from .env.local)
|
|
@@ -73,11 +73,11 @@ This allows fully offline development without any API calls.
|
|
|
73
73
|
Examples:
|
|
74
74
|
$ xtra local status # Check current mode
|
|
75
75
|
$ xtra local on # Enable offline (local) mode
|
|
76
|
-
$ xtra local off # Disable
|
|
77
|
-
$ xtra local sync # Pull cloud secrets
|
|
76
|
+
$ xtra local off # Disable — back to cloud mode
|
|
77
|
+
$ xtra local sync # Pull cloud secrets → .env.local
|
|
78
78
|
$ xtra local sync -p proj -e production # Pull production to .env.local
|
|
79
79
|
`);
|
|
80
|
-
//
|
|
80
|
+
// ── status ────────────────────────────────────────────────────────────────────
|
|
81
81
|
exports.localCommand
|
|
82
82
|
.command("status")
|
|
83
83
|
.description("Show current cloud/local mode")
|
|
@@ -86,7 +86,7 @@ exports.localCommand
|
|
|
86
86
|
const envFilePath = path.join(process.cwd(), LOCAL_ENV_FILE);
|
|
87
87
|
const hasLocalFile = fs.existsSync(envFilePath);
|
|
88
88
|
console.log(chalk_1.default.bold("\nMode Status:\n"));
|
|
89
|
-
console.log(` Mode : ${mode ? chalk_1.default.yellow("
|
|
89
|
+
console.log(` Mode : ${mode ? chalk_1.default.yellow("🔌 LOCAL (offline)") : chalk_1.default.green("☠CLOUD")}`);
|
|
90
90
|
console.log(` .env.local : ${hasLocalFile ? chalk_1.default.green("Found") : chalk_1.default.gray("Not found")}`);
|
|
91
91
|
console.log(` Config flag : ${chalk_1.default.gray((0, config_1.getConfigValue)("localMode") ? "true" : "false")}`);
|
|
92
92
|
console.log(` Env var : ${chalk_1.default.gray(process.env.XTRA_LOCAL_MODE || "(not set)")}`);
|
|
@@ -97,34 +97,34 @@ exports.localCommand
|
|
|
97
97
|
else {
|
|
98
98
|
console.log(chalk_1.default.gray(" Run 'xtra local off' to switch back to cloud mode."));
|
|
99
99
|
if (!hasLocalFile) {
|
|
100
|
-
console.log(chalk_1.default.yellow("
|
|
100
|
+
console.log(chalk_1.default.yellow(" âš No .env.local file found. Run 'xtra local sync' to pull secrets."));
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
console.log();
|
|
104
104
|
});
|
|
105
|
-
//
|
|
105
|
+
// ── on ────────────────────────────────────────────────────────────────────────
|
|
106
106
|
exports.localCommand
|
|
107
107
|
.command("on")
|
|
108
|
-
.description("Enable local mode
|
|
108
|
+
.description("Enable local mode — secrets read from .env.local")
|
|
109
109
|
.action(() => {
|
|
110
110
|
(0, config_1.setConfig)("localMode", true);
|
|
111
|
-
console.log(chalk_1.default.yellow("
|
|
111
|
+
console.log(chalk_1.default.yellow("🔌 Local mode ENABLED."));
|
|
112
112
|
console.log(chalk_1.default.gray(" 'xtra run' will now read from .env.local instead of the cloud."));
|
|
113
113
|
const localFilePath = path.join(process.cwd(), LOCAL_ENV_FILE);
|
|
114
114
|
if (!fs.existsSync(localFilePath)) {
|
|
115
|
-
console.log(chalk_1.default.yellow(`
|
|
115
|
+
console.log(chalk_1.default.yellow(` âš No .env.local file found. Run 'xtra local sync' to populate it.`));
|
|
116
116
|
}
|
|
117
117
|
});
|
|
118
|
-
//
|
|
118
|
+
// ── off ───────────────────────────────────────────────────────────────────────
|
|
119
119
|
exports.localCommand
|
|
120
120
|
.command("off")
|
|
121
|
-
.description("Disable local mode
|
|
121
|
+
.description("Disable local mode — secrets fetched from cloud again")
|
|
122
122
|
.action(() => {
|
|
123
123
|
(0, config_1.setConfig)("localMode", false);
|
|
124
|
-
console.log(chalk_1.default.green("
|
|
124
|
+
console.log(chalk_1.default.green("☠Cloud mode ENABLED."));
|
|
125
125
|
console.log(chalk_1.default.gray(" 'xtra run' will now fetch secrets from XtraSecurity Cloud."));
|
|
126
126
|
});
|
|
127
|
-
//
|
|
127
|
+
// ── sync ─────────────────────────────────────────────────────────────────────
|
|
128
128
|
exports.localCommand
|
|
129
129
|
.command("sync")
|
|
130
130
|
.description("Pull cloud secrets to .env.local for offline use")
|
|
@@ -138,7 +138,7 @@ exports.localCommand
|
|
|
138
138
|
const envMap = { dev: "development", stg: "staging", prod: "production" };
|
|
139
139
|
env = envMap[env] || env;
|
|
140
140
|
if (!project)
|
|
141
|
-
project = (0, config_1.
|
|
141
|
+
project = (0, config_1.getRcConfig)().project;
|
|
142
142
|
if (!project) {
|
|
143
143
|
console.error(chalk_1.default.red("Error: Project ID required. Use -p <id>."));
|
|
144
144
|
process.exit(1);
|
|
@@ -146,7 +146,7 @@ exports.localCommand
|
|
|
146
146
|
const outputPath = path.resolve(process.cwd(), output);
|
|
147
147
|
// Warn if production
|
|
148
148
|
if (env === "production" && !overwrite) {
|
|
149
|
-
console.log(chalk_1.default.red(
|
|
149
|
+
console.log(chalk_1.default.red(`âš You are syncing PRODUCTION secrets to ${output}.`));
|
|
150
150
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
151
151
|
const confirmed = await new Promise(resolve => {
|
|
152
152
|
rl.question(chalk_1.default.yellow("Type 'yes' to confirm: "), (ans) => {
|
|
@@ -170,14 +170,14 @@ exports.localCommand
|
|
|
170
170
|
}
|
|
171
171
|
// Write dotenv format
|
|
172
172
|
const lines = [
|
|
173
|
-
`# xtra local sync
|
|
173
|
+
`# xtra local sync — ${env}/${branch}`,
|
|
174
174
|
`# Generated: ${new Date().toISOString()}`,
|
|
175
175
|
`# DO NOT COMMIT THIS FILE`,
|
|
176
176
|
"",
|
|
177
177
|
...Object.entries(secrets).map(([k, v]) => `${k}=${v}`)
|
|
178
178
|
];
|
|
179
179
|
fs.writeFileSync(outputPath, lines.join("\n") + "\n", "utf8");
|
|
180
|
-
console.log(chalk_1.default.green(
|
|
180
|
+
console.log(chalk_1.default.green(`✅ Synced ${count} secrets to ${output}`));
|
|
181
181
|
console.log(chalk_1.default.gray(" Run 'xtra local on' to switch to local mode."));
|
|
182
182
|
// Remind about .gitignore
|
|
183
183
|
const gitignorePath = path.join(process.cwd(), ".gitignore");
|
|
@@ -187,7 +187,7 @@ exports.localCommand
|
|
|
187
187
|
}
|
|
188
188
|
catch (_) { }
|
|
189
189
|
if (!gitignore.includes(output)) {
|
|
190
|
-
console.log(chalk_1.default.yellow(`\n
|
|
190
|
+
console.log(chalk_1.default.yellow(`\n âš Remember to add '${output}' to your .gitignore!`));
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
catch (e) {
|
|
@@ -19,9 +19,8 @@ exports.rollbackCommand = new commander_1.Command("rollback")
|
|
|
19
19
|
.action(async (key, options) => {
|
|
20
20
|
let { project, env } = options;
|
|
21
21
|
// Use config fallback
|
|
22
|
-
if (!project)
|
|
23
|
-
project = (0, config_1.
|
|
24
|
-
}
|
|
22
|
+
if (!project)
|
|
23
|
+
project = (0, config_1.getRcConfig)().project;
|
|
25
24
|
if (!project) {
|
|
26
25
|
console.error(chalk_1.default.red("Error: Project ID is required. Use -p <id> or run 'xtra project set' first."));
|
|
27
26
|
process.exit(1);
|
package/dist/commands/rotate.js
CHANGED
|
@@ -20,9 +20,8 @@ exports.rotateCommand = new commander_1.Command("rotate")
|
|
|
20
20
|
.action(async (key, options) => {
|
|
21
21
|
let { project, env, strategy, promote, value } = options;
|
|
22
22
|
// Use config fallback
|
|
23
|
-
if (!project)
|
|
24
|
-
project = (0, config_1.
|
|
25
|
-
}
|
|
23
|
+
if (!project)
|
|
24
|
+
project = (0, config_1.getRcConfig)().project;
|
|
26
25
|
// Normalize Env
|
|
27
26
|
const envMap = { dev: "development", stg: "staging", prod: "production" };
|
|
28
27
|
env = envMap[env] || env;
|
|
@@ -36,7 +35,7 @@ exports.rotateCommand = new commander_1.Command("rotate")
|
|
|
36
35
|
const { confirmProd } = await inquirer.prompt([{
|
|
37
36
|
type: "confirm",
|
|
38
37
|
name: "confirmProd",
|
|
39
|
-
message: chalk_1.default.red(
|
|
38
|
+
message: chalk_1.default.red(`âš You are about to rotate a secret in PRODUCTION (${key}). Proceed?`),
|
|
40
39
|
default: false,
|
|
41
40
|
}]);
|
|
42
41
|
if (!confirmProd) {
|