@tolgamorf/env2op-cli 0.2.0 → 0.2.2
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 +25 -5
- package/dist/cli.js +375 -69
- package/dist/index.d.ts +3 -1
- package/dist/index.js +48 -28
- package/dist/op2env-cli.js +365 -59
- package/package.json +1 -1
package/dist/op2env-cli.js
CHANGED
|
@@ -22,7 +22,7 @@ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports,
|
|
|
22
22
|
var require_package = __commonJS((exports, module) => {
|
|
23
23
|
module.exports = {
|
|
24
24
|
name: "@tolgamorf/env2op-cli",
|
|
25
|
-
version: "0.2.
|
|
25
|
+
version: "0.2.2",
|
|
26
26
|
description: "Convert .env files to 1Password Secure Notes and generate templates for op inject/run",
|
|
27
27
|
type: "module",
|
|
28
28
|
main: "dist/index.js",
|
|
@@ -102,16 +102,15 @@ var require_package = __commonJS((exports, module) => {
|
|
|
102
102
|
});
|
|
103
103
|
|
|
104
104
|
// src/op2env-cli.ts
|
|
105
|
-
import
|
|
105
|
+
import pc5 from "picocolors";
|
|
106
106
|
|
|
107
107
|
// src/commands/inject.ts
|
|
108
|
-
import { existsSync
|
|
108
|
+
import { existsSync, readFileSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
109
109
|
import { basename } from "node:path";
|
|
110
|
-
import { setTimeout } from "node:timers/promises";
|
|
111
110
|
import * as p2 from "@clack/prompts";
|
|
112
111
|
|
|
113
112
|
// src/core/env-parser.ts
|
|
114
|
-
import {
|
|
113
|
+
import { readFile } from "node:fs/promises";
|
|
115
114
|
|
|
116
115
|
// src/utils/errors.ts
|
|
117
116
|
class Env2OpError extends Error {
|
|
@@ -134,6 +133,7 @@ var ErrorCodes = {
|
|
|
134
133
|
VAULT_CREATE_FAILED: "VAULT_CREATE_FAILED",
|
|
135
134
|
ITEM_EXISTS: "ITEM_EXISTS",
|
|
136
135
|
ITEM_CREATE_FAILED: "ITEM_CREATE_FAILED",
|
|
136
|
+
ITEM_EDIT_FAILED: "ITEM_EDIT_FAILED",
|
|
137
137
|
PARSE_ERROR: "PARSE_ERROR",
|
|
138
138
|
TEMPLATE_NOT_FOUND: "TEMPLATE_NOT_FOUND",
|
|
139
139
|
INJECT_FAILED: "INJECT_FAILED"
|
|
@@ -147,6 +147,7 @@ var errors = {
|
|
|
147
147
|
vaultCreateFailed: (message) => new Env2OpError(`Failed to create vault: ${message}`, ErrorCodes.VAULT_CREATE_FAILED),
|
|
148
148
|
itemExists: (title, vault) => new Env2OpError(`Item "${title}" already exists in vault "${vault}"`, ErrorCodes.ITEM_EXISTS, "Use default behavior (overwrites) or choose a different item name"),
|
|
149
149
|
itemCreateFailed: (message) => new Env2OpError(`Failed to create 1Password item: ${message}`, ErrorCodes.ITEM_CREATE_FAILED),
|
|
150
|
+
itemEditFailed: (message) => new Env2OpError(`Failed to edit 1Password item: ${message}`, ErrorCodes.ITEM_EDIT_FAILED),
|
|
150
151
|
parseError: (line, message) => new Env2OpError(`Parse error at line ${line}: ${message}`, ErrorCodes.PARSE_ERROR)
|
|
151
152
|
};
|
|
152
153
|
|
|
@@ -194,12 +195,20 @@ function parseValue(raw) {
|
|
|
194
195
|
const parts = trimmed.split(/\s+#/);
|
|
195
196
|
return (parts[0] ?? trimmed).trim();
|
|
196
197
|
}
|
|
197
|
-
function
|
|
198
|
-
if (
|
|
198
|
+
function stripBom(content) {
|
|
199
|
+
if (content.charCodeAt(0) === 65279) {
|
|
200
|
+
return content.slice(1);
|
|
201
|
+
}
|
|
202
|
+
return content;
|
|
203
|
+
}
|
|
204
|
+
async function parseEnvFile(filePath) {
|
|
205
|
+
let rawContent;
|
|
206
|
+
try {
|
|
207
|
+
rawContent = await readFile(filePath, "utf-8");
|
|
208
|
+
} catch {
|
|
199
209
|
throw errors.envFileNotFound(filePath);
|
|
200
210
|
}
|
|
201
|
-
const
|
|
202
|
-
const content = stripHeaders(rawContent);
|
|
211
|
+
const content = stripHeaders(stripBom(rawContent));
|
|
203
212
|
const rawLines = content.split(`
|
|
204
213
|
`);
|
|
205
214
|
const variables = [];
|
|
@@ -264,33 +273,34 @@ async function exec(command, args = [], options = {}) {
|
|
|
264
273
|
const proc = spawn(command, args, {
|
|
265
274
|
stdio: ["ignore", "pipe", "pipe"]
|
|
266
275
|
});
|
|
267
|
-
|
|
268
|
-
|
|
276
|
+
const stdoutChunks = [];
|
|
277
|
+
const stderrChunks = [];
|
|
269
278
|
proc.stdout?.on("data", (data) => {
|
|
270
|
-
const text = data.toString();
|
|
271
|
-
|
|
279
|
+
const text = Buffer.isBuffer(data) ? data.toString() : String(data);
|
|
280
|
+
stdoutChunks.push(text);
|
|
272
281
|
if (verbose) {
|
|
273
282
|
process.stdout.write(text);
|
|
274
283
|
}
|
|
275
284
|
});
|
|
276
285
|
proc.stderr?.on("data", (data) => {
|
|
277
|
-
const text = data.toString();
|
|
278
|
-
|
|
286
|
+
const text = Buffer.isBuffer(data) ? data.toString() : String(data);
|
|
287
|
+
stderrChunks.push(text);
|
|
279
288
|
if (verbose) {
|
|
280
289
|
process.stderr.write(text);
|
|
281
290
|
}
|
|
282
291
|
});
|
|
283
292
|
proc.on("close", (code) => {
|
|
284
293
|
resolve({
|
|
285
|
-
stdout,
|
|
286
|
-
stderr,
|
|
287
|
-
exitCode: code ??
|
|
294
|
+
stdout: stdoutChunks.join(""),
|
|
295
|
+
stderr: stderrChunks.join(""),
|
|
296
|
+
exitCode: code ?? 1
|
|
288
297
|
});
|
|
289
298
|
});
|
|
290
|
-
proc.on("error", () => {
|
|
299
|
+
proc.on("error", (err) => {
|
|
300
|
+
stderrChunks.push(err.message);
|
|
291
301
|
resolve({
|
|
292
|
-
stdout,
|
|
293
|
-
stderr,
|
|
302
|
+
stdout: stdoutChunks.join(""),
|
|
303
|
+
stderr: stderrChunks.join(""),
|
|
294
304
|
exitCode: 1
|
|
295
305
|
});
|
|
296
306
|
});
|
|
@@ -306,27 +316,36 @@ async function execWithStdin(command, args = [], options) {
|
|
|
306
316
|
const proc = spawn(command, args, {
|
|
307
317
|
stdio: ["pipe", "pipe", "pipe"]
|
|
308
318
|
});
|
|
309
|
-
|
|
310
|
-
|
|
319
|
+
const stdoutChunks = [];
|
|
320
|
+
const stderrChunks = [];
|
|
311
321
|
proc.stdin?.write(stdinContent);
|
|
312
322
|
proc.stdin?.end();
|
|
313
323
|
proc.stdout?.on("data", (data) => {
|
|
314
|
-
const text = data.toString();
|
|
315
|
-
|
|
324
|
+
const text = Buffer.isBuffer(data) ? data.toString() : String(data);
|
|
325
|
+
stdoutChunks.push(text);
|
|
316
326
|
if (verbose)
|
|
317
327
|
process.stdout.write(text);
|
|
318
328
|
});
|
|
319
329
|
proc.stderr?.on("data", (data) => {
|
|
320
|
-
const text = data.toString();
|
|
321
|
-
|
|
330
|
+
const text = Buffer.isBuffer(data) ? data.toString() : String(data);
|
|
331
|
+
stderrChunks.push(text);
|
|
322
332
|
if (verbose)
|
|
323
333
|
process.stderr.write(text);
|
|
324
334
|
});
|
|
325
335
|
proc.on("close", (code) => {
|
|
326
|
-
resolve({
|
|
336
|
+
resolve({
|
|
337
|
+
stdout: stdoutChunks.join(""),
|
|
338
|
+
stderr: stderrChunks.join(""),
|
|
339
|
+
exitCode: code ?? 1
|
|
340
|
+
});
|
|
327
341
|
});
|
|
328
|
-
proc.on("error", () => {
|
|
329
|
-
|
|
342
|
+
proc.on("error", (err) => {
|
|
343
|
+
stderrChunks.push(err.message);
|
|
344
|
+
resolve({
|
|
345
|
+
stdout: stdoutChunks.join(""),
|
|
346
|
+
stderr: stderrChunks.join(""),
|
|
347
|
+
exitCode: 1
|
|
348
|
+
});
|
|
330
349
|
});
|
|
331
350
|
});
|
|
332
351
|
}
|
|
@@ -446,7 +465,7 @@ async function editSecureNote(options) {
|
|
|
446
465
|
};
|
|
447
466
|
} catch (error) {
|
|
448
467
|
const message = error instanceof Error ? error.message : String(error);
|
|
449
|
-
throw errors.
|
|
468
|
+
throw errors.itemEditFailed(message);
|
|
450
469
|
}
|
|
451
470
|
}
|
|
452
471
|
|
|
@@ -607,12 +626,15 @@ ${pc2.bold(pc2.underline(title))}`);
|
|
|
607
626
|
}
|
|
608
627
|
};
|
|
609
628
|
|
|
610
|
-
// src/
|
|
629
|
+
// src/utils/timing.ts
|
|
630
|
+
import { setTimeout } from "node:timers/promises";
|
|
611
631
|
var MIN_SPINNER_TIME = 500;
|
|
612
632
|
async function withMinTime(promise, minTime = MIN_SPINNER_TIME) {
|
|
613
633
|
const [result] = await Promise.all([promise, setTimeout(minTime)]);
|
|
614
634
|
return result;
|
|
615
635
|
}
|
|
636
|
+
|
|
637
|
+
// src/commands/inject.ts
|
|
616
638
|
function deriveOutputPath(templatePath) {
|
|
617
639
|
if (templatePath.endsWith(".tpl")) {
|
|
618
640
|
return templatePath.slice(0, -4);
|
|
@@ -625,7 +647,7 @@ async function runInject(options) {
|
|
|
625
647
|
const pkg2 = await Promise.resolve().then(() => __toESM(require_package(), 1));
|
|
626
648
|
logger.intro("op2env", pkg2.version, dryRun);
|
|
627
649
|
try {
|
|
628
|
-
if (!
|
|
650
|
+
if (!existsSync(templateFile)) {
|
|
629
651
|
throw new Env2OpError(`Template file not found: ${templateFile}`, "TEMPLATE_NOT_FOUND", "Ensure the file exists and the path is correct");
|
|
630
652
|
}
|
|
631
653
|
logger.success(`Found template: ${basename(templateFile)}`);
|
|
@@ -653,7 +675,7 @@ async function runInject(options) {
|
|
|
653
675
|
}
|
|
654
676
|
authSpinner.stop("1Password CLI ready");
|
|
655
677
|
}
|
|
656
|
-
const outputExists =
|
|
678
|
+
const outputExists = existsSync(outputPath);
|
|
657
679
|
if (dryRun) {
|
|
658
680
|
if (outputExists) {
|
|
659
681
|
logger.warn(`Would overwrite: ${outputPath}`);
|
|
@@ -679,7 +701,7 @@ async function runInject(options) {
|
|
|
679
701
|
if (result.exitCode !== 0) {
|
|
680
702
|
throw new Error(result.stderr);
|
|
681
703
|
}
|
|
682
|
-
const rawContent =
|
|
704
|
+
const rawContent = readFileSync(outputPath, "utf-8");
|
|
683
705
|
const envContent = stripHeaders(rawContent);
|
|
684
706
|
const header = generateEnvHeader(basename(outputPath)).join(`
|
|
685
707
|
`);
|
|
@@ -711,6 +733,274 @@ async function runInject(options) {
|
|
|
711
733
|
}
|
|
712
734
|
}
|
|
713
735
|
|
|
736
|
+
// src/commands/update.ts
|
|
737
|
+
import * as p4 from "@clack/prompts";
|
|
738
|
+
import pc4 from "picocolors";
|
|
739
|
+
|
|
740
|
+
// src/lib/package-manager.ts
|
|
741
|
+
var UPDATE_COMMANDS = {
|
|
742
|
+
homebrew: "brew upgrade tolgamorf/tap/env2op-cli",
|
|
743
|
+
npm: "npm update -g @tolgamorf/env2op-cli",
|
|
744
|
+
bun: "bun update -g @tolgamorf/env2op-cli",
|
|
745
|
+
pnpm: "pnpm update -g @tolgamorf/env2op-cli",
|
|
746
|
+
unknown: "npm update -g @tolgamorf/env2op-cli"
|
|
747
|
+
};
|
|
748
|
+
var DISPLAY_NAMES = {
|
|
749
|
+
homebrew: "Homebrew",
|
|
750
|
+
npm: "npm",
|
|
751
|
+
bun: "Bun",
|
|
752
|
+
pnpm: "pnpm",
|
|
753
|
+
unknown: "npm (default)"
|
|
754
|
+
};
|
|
755
|
+
function detectFromPath() {
|
|
756
|
+
const binPath = process.argv[1] ?? "";
|
|
757
|
+
if (binPath.includes("/Cellar/") || binPath.includes("/homebrew/") || binPath.includes("/opt/homebrew/") || binPath.includes("/home/linuxbrew/")) {
|
|
758
|
+
return "homebrew";
|
|
759
|
+
}
|
|
760
|
+
if (binPath.includes("/.bun/")) {
|
|
761
|
+
return "bun";
|
|
762
|
+
}
|
|
763
|
+
if (binPath.includes("/pnpm/") || binPath.includes("/.pnpm/")) {
|
|
764
|
+
return "pnpm";
|
|
765
|
+
}
|
|
766
|
+
if (binPath.includes("/node_modules/")) {
|
|
767
|
+
return "npm";
|
|
768
|
+
}
|
|
769
|
+
return null;
|
|
770
|
+
}
|
|
771
|
+
async function detectFromCommands() {
|
|
772
|
+
const brewResult = await exec("brew", ["list", "env2op-cli"], { verbose: false });
|
|
773
|
+
if (brewResult.exitCode === 0) {
|
|
774
|
+
return "homebrew";
|
|
775
|
+
}
|
|
776
|
+
return "npm";
|
|
777
|
+
}
|
|
778
|
+
async function detectPackageManager() {
|
|
779
|
+
const fromPath = detectFromPath();
|
|
780
|
+
if (fromPath) {
|
|
781
|
+
return {
|
|
782
|
+
type: fromPath,
|
|
783
|
+
updateCommand: UPDATE_COMMANDS[fromPath],
|
|
784
|
+
displayName: DISPLAY_NAMES[fromPath]
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
const fromCommands = await detectFromCommands();
|
|
788
|
+
return {
|
|
789
|
+
type: fromCommands,
|
|
790
|
+
updateCommand: UPDATE_COMMANDS[fromCommands],
|
|
791
|
+
displayName: DISPLAY_NAMES[fromCommands]
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
// src/lib/update.ts
|
|
796
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
797
|
+
import { homedir } from "node:os";
|
|
798
|
+
import { join } from "node:path";
|
|
799
|
+
var CACHE_DIR = join(homedir(), ".env2op");
|
|
800
|
+
var CACHE_FILE = join(CACHE_DIR, "update-check.json");
|
|
801
|
+
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
802
|
+
function getCliVersion() {
|
|
803
|
+
try {
|
|
804
|
+
const pkg2 = require_package();
|
|
805
|
+
return pkg2.version ?? "0.0.0";
|
|
806
|
+
} catch {
|
|
807
|
+
return "0.0.0";
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
function loadCache() {
|
|
811
|
+
try {
|
|
812
|
+
if (existsSync2(CACHE_FILE)) {
|
|
813
|
+
const content = readFileSync2(CACHE_FILE, "utf-8");
|
|
814
|
+
return JSON.parse(content);
|
|
815
|
+
}
|
|
816
|
+
} catch {}
|
|
817
|
+
return { lastCheck: 0, latestVersion: null };
|
|
818
|
+
}
|
|
819
|
+
function saveCache(cache) {
|
|
820
|
+
try {
|
|
821
|
+
if (!existsSync2(CACHE_DIR)) {
|
|
822
|
+
mkdirSync(CACHE_DIR, { recursive: true });
|
|
823
|
+
}
|
|
824
|
+
writeFileSync3(CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
825
|
+
} catch {}
|
|
826
|
+
}
|
|
827
|
+
function shouldCheckForUpdate(cache) {
|
|
828
|
+
const now = Date.now();
|
|
829
|
+
return now - cache.lastCheck > CHECK_INTERVAL_MS;
|
|
830
|
+
}
|
|
831
|
+
async function fetchLatestVersion() {
|
|
832
|
+
try {
|
|
833
|
+
const response = await fetch("https://registry.npmjs.org/@tolgamorf/env2op-cli/latest");
|
|
834
|
+
if (!response.ok)
|
|
835
|
+
return null;
|
|
836
|
+
const data = await response.json();
|
|
837
|
+
return data.version ?? null;
|
|
838
|
+
} catch {
|
|
839
|
+
return null;
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
function compareVersions(v1, v2) {
|
|
843
|
+
const parts1 = v1.split(".").map(Number);
|
|
844
|
+
const parts2 = v2.split(".").map(Number);
|
|
845
|
+
for (let i = 0;i < 3; i++) {
|
|
846
|
+
const p1 = parts1[i] || 0;
|
|
847
|
+
const p22 = parts2[i] || 0;
|
|
848
|
+
if (p1 < p22)
|
|
849
|
+
return -1;
|
|
850
|
+
if (p1 > p22)
|
|
851
|
+
return 1;
|
|
852
|
+
}
|
|
853
|
+
return 0;
|
|
854
|
+
}
|
|
855
|
+
async function checkForUpdate(forceCheck = false) {
|
|
856
|
+
const currentVersion = getCliVersion();
|
|
857
|
+
const cache = loadCache();
|
|
858
|
+
if (!forceCheck && !shouldCheckForUpdate(cache) && cache.latestVersion) {
|
|
859
|
+
const updateAvailable2 = compareVersions(currentVersion, cache.latestVersion) < 0;
|
|
860
|
+
const isSkipped2 = cache.skipVersion === cache.latestVersion;
|
|
861
|
+
return {
|
|
862
|
+
currentVersion,
|
|
863
|
+
latestVersion: cache.latestVersion,
|
|
864
|
+
updateAvailable: updateAvailable2,
|
|
865
|
+
isSkipped: isSkipped2,
|
|
866
|
+
fromCache: true
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
const latestVersion = await fetchLatestVersion();
|
|
870
|
+
saveCache({
|
|
871
|
+
...cache,
|
|
872
|
+
lastCheck: Date.now(),
|
|
873
|
+
latestVersion
|
|
874
|
+
});
|
|
875
|
+
if (!latestVersion) {
|
|
876
|
+
return {
|
|
877
|
+
currentVersion,
|
|
878
|
+
latestVersion: null,
|
|
879
|
+
updateAvailable: false,
|
|
880
|
+
isSkipped: false,
|
|
881
|
+
fromCache: false
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
const updateAvailable = compareVersions(currentVersion, latestVersion) < 0;
|
|
885
|
+
const isSkipped = cache.skipVersion === latestVersion;
|
|
886
|
+
return {
|
|
887
|
+
currentVersion,
|
|
888
|
+
latestVersion,
|
|
889
|
+
updateAvailable,
|
|
890
|
+
isSkipped,
|
|
891
|
+
fromCache: false
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
async function performUpdate(pm) {
|
|
895
|
+
const packageManager = pm ?? await detectPackageManager();
|
|
896
|
+
try {
|
|
897
|
+
const [command, ...args] = packageManager.updateCommand.split(" ");
|
|
898
|
+
const result = await exec(command, args, { verbose: false });
|
|
899
|
+
if (result.exitCode !== 0) {
|
|
900
|
+
return {
|
|
901
|
+
success: false,
|
|
902
|
+
error: result.stderr || `Command exited with code ${result.exitCode}`
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
return { success: true };
|
|
906
|
+
} catch (error) {
|
|
907
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
908
|
+
return { success: false, error: message };
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
function skipVersion(version) {
|
|
912
|
+
const cache = loadCache();
|
|
913
|
+
cache.skipVersion = version;
|
|
914
|
+
saveCache(cache);
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
// src/lib/update-prompts.ts
|
|
918
|
+
import * as p3 from "@clack/prompts";
|
|
919
|
+
import pc3 from "picocolors";
|
|
920
|
+
var S_BAR_START = "┌";
|
|
921
|
+
var S_BAR_END = "└";
|
|
922
|
+
function showUpdateNotification(result, cliName = "env2op") {
|
|
923
|
+
console.log();
|
|
924
|
+
console.log(`${pc3.gray(S_BAR_START)}${pc3.gray("─")} ${pc3.yellow("Update available:")} ${pc3.dim(result.currentVersion)} ${pc3.dim("→")} ${pc3.green(result.latestVersion)}`);
|
|
925
|
+
console.log(`${pc3.gray(S_BAR_END)}${pc3.gray("─")} Run ${pc3.cyan(`'${cliName} update'`)} to update`);
|
|
926
|
+
}
|
|
927
|
+
async function askToUpdate(result) {
|
|
928
|
+
const response = await p3.select({
|
|
929
|
+
message: "Would you like to update?",
|
|
930
|
+
options: [
|
|
931
|
+
{ value: "update", label: "Update now", hint: "Download and install the latest version" },
|
|
932
|
+
{ value: "later", label: "Remind me later", hint: "Ask again next time" },
|
|
933
|
+
{ value: "skip", label: "Skip this version", hint: `Don't ask about ${result.latestVersion} again` }
|
|
934
|
+
]
|
|
935
|
+
});
|
|
936
|
+
if (p3.isCancel(response)) {
|
|
937
|
+
return "later";
|
|
938
|
+
}
|
|
939
|
+
return response;
|
|
940
|
+
}
|
|
941
|
+
function showUpdateAvailable(result) {
|
|
942
|
+
p3.log.success(`Update available: ${pc3.dim(result.currentVersion)} ${pc3.dim("→")} ${pc3.green(result.latestVersion)}`);
|
|
943
|
+
}
|
|
944
|
+
function showUpToDate(currentVersion) {
|
|
945
|
+
p3.log.success(`You're on the latest version ${pc3.green(`(${currentVersion})`)}`);
|
|
946
|
+
}
|
|
947
|
+
function showPackageManagerInfo(pm) {
|
|
948
|
+
console.log();
|
|
949
|
+
console.log(` ${pc3.dim("Detected:")} ${pm.displayName} installation`);
|
|
950
|
+
console.log(` ${pc3.dim("Command:")} ${pc3.cyan(pm.updateCommand)}`);
|
|
951
|
+
console.log();
|
|
952
|
+
}
|
|
953
|
+
function showUpdateSuccess(newVersion) {
|
|
954
|
+
p3.log.success(`Updated to version ${pc3.green(newVersion)}`);
|
|
955
|
+
p3.log.info("Please restart to use the new version.");
|
|
956
|
+
}
|
|
957
|
+
function showUpdateError(error, pm) {
|
|
958
|
+
if (error) {
|
|
959
|
+
p3.log.error(pc3.dim(error));
|
|
960
|
+
}
|
|
961
|
+
p3.log.info(`Try running manually: ${pc3.cyan(pm.updateCommand)}`);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// src/commands/update.ts
|
|
965
|
+
async function runUpdate(options) {
|
|
966
|
+
const { force = false, cliName = "env2op" } = options;
|
|
967
|
+
p4.intro(pc4.bgCyan(pc4.black(` ${cliName} update `)));
|
|
968
|
+
const spinner4 = p4.spinner();
|
|
969
|
+
spinner4.start("Checking for updates...");
|
|
970
|
+
const result = await checkForUpdate(true);
|
|
971
|
+
spinner4.stop("Checked for updates");
|
|
972
|
+
if (!result.updateAvailable || !result.latestVersion) {
|
|
973
|
+
showUpToDate(result.currentVersion);
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
976
|
+
showUpdateAvailable(result);
|
|
977
|
+
const pm = await detectPackageManager();
|
|
978
|
+
showPackageManagerInfo(pm);
|
|
979
|
+
if (!force) {
|
|
980
|
+
const choice = await askToUpdate(result);
|
|
981
|
+
if (choice === "skip") {
|
|
982
|
+
skipVersion(result.latestVersion);
|
|
983
|
+
p4.log.info(`Skipped version ${result.latestVersion}`);
|
|
984
|
+
return;
|
|
985
|
+
}
|
|
986
|
+
if (choice === "later") {
|
|
987
|
+
p4.log.info("Update postponed");
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
const updateSpinner = p4.spinner();
|
|
992
|
+
updateSpinner.start(`Updating to ${result.latestVersion}...`);
|
|
993
|
+
const updateResult = await performUpdate(pm);
|
|
994
|
+
if (updateResult.success) {
|
|
995
|
+
updateSpinner.stop("Update completed");
|
|
996
|
+
showUpdateSuccess(result.latestVersion);
|
|
997
|
+
} else {
|
|
998
|
+
updateSpinner.stop("Update failed");
|
|
999
|
+
showUpdateError(updateResult.error, pm);
|
|
1000
|
+
process.exit(1);
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
714
1004
|
// src/op2env-cli.ts
|
|
715
1005
|
var pkg2 = await Promise.resolve().then(() => __toESM(require_package(), 1));
|
|
716
1006
|
var args = process.argv.slice(2);
|
|
@@ -737,10 +1027,19 @@ for (let i = 0;i < args.length; i++) {
|
|
|
737
1027
|
}
|
|
738
1028
|
var hasHelp = flags.has("h") || flags.has("help");
|
|
739
1029
|
var hasVersion = flags.has("v") || flags.has("version");
|
|
1030
|
+
var hasUpdate = flags.has("update");
|
|
740
1031
|
if (hasVersion) {
|
|
741
1032
|
console.log(pkg2.version);
|
|
742
1033
|
process.exit(0);
|
|
743
1034
|
}
|
|
1035
|
+
if (hasUpdate) {
|
|
1036
|
+
await runUpdate({
|
|
1037
|
+
force: flags.has("f") || flags.has("force"),
|
|
1038
|
+
verbose: flags.has("verbose"),
|
|
1039
|
+
cliName: "op2env"
|
|
1040
|
+
});
|
|
1041
|
+
process.exit(0);
|
|
1042
|
+
}
|
|
744
1043
|
if (hasHelp || positional.length === 0) {
|
|
745
1044
|
showHelp();
|
|
746
1045
|
process.exit(0);
|
|
@@ -753,41 +1052,48 @@ await runInject({
|
|
|
753
1052
|
force: flags.has("f") || flags.has("force"),
|
|
754
1053
|
verbose: flags.has("verbose")
|
|
755
1054
|
});
|
|
1055
|
+
try {
|
|
1056
|
+
const updateResult = await checkForUpdate();
|
|
1057
|
+
if (updateResult.updateAvailable && !updateResult.isSkipped) {
|
|
1058
|
+
showUpdateNotification(updateResult, "op2env");
|
|
1059
|
+
}
|
|
1060
|
+
} catch {}
|
|
756
1061
|
function showHelp() {
|
|
757
|
-
const name =
|
|
758
|
-
const version =
|
|
1062
|
+
const name = pc5.bold(pc5.cyan("op2env"));
|
|
1063
|
+
const version = pc5.dim(`v${pkg2.version}`);
|
|
759
1064
|
console.log(`
|
|
760
1065
|
${name} ${version}
|
|
761
1066
|
Pull secrets from 1Password to generate .env files
|
|
762
1067
|
|
|
763
|
-
${
|
|
764
|
-
${
|
|
1068
|
+
${pc5.bold("USAGE")}
|
|
1069
|
+
${pc5.cyan("$")} op2env ${pc5.yellow("<template_file>")} ${pc5.dim("[options]")}
|
|
765
1070
|
|
|
766
|
-
${
|
|
767
|
-
${
|
|
1071
|
+
${pc5.bold("ARGUMENTS")}
|
|
1072
|
+
${pc5.yellow("template_file")} Path to .env.tpl template file
|
|
768
1073
|
|
|
769
|
-
${
|
|
770
|
-
${
|
|
771
|
-
${
|
|
772
|
-
${
|
|
773
|
-
${
|
|
774
|
-
${
|
|
775
|
-
${
|
|
1074
|
+
${pc5.bold("OPTIONS")}
|
|
1075
|
+
${pc5.cyan("-o, --output")} Output .env path (default: template without .tpl)
|
|
1076
|
+
${pc5.cyan("-f, --force")} Overwrite without prompting
|
|
1077
|
+
${pc5.cyan(" --dry-run")} Preview actions without executing
|
|
1078
|
+
${pc5.cyan(" --verbose")} Show op CLI output
|
|
1079
|
+
${pc5.cyan(" --update")} Check for and install updates
|
|
1080
|
+
${pc5.cyan("-v, --version")} Show version
|
|
1081
|
+
${pc5.cyan("-h, --help")} Show this help message
|
|
776
1082
|
|
|
777
|
-
${
|
|
778
|
-
${
|
|
779
|
-
${
|
|
1083
|
+
${pc5.bold("EXAMPLES")}
|
|
1084
|
+
${pc5.dim("# Basic usage - generates .env from .env.tpl")}
|
|
1085
|
+
${pc5.cyan("$")} op2env .env.tpl
|
|
780
1086
|
|
|
781
|
-
${
|
|
782
|
-
${
|
|
1087
|
+
${pc5.dim("# Custom output path")}
|
|
1088
|
+
${pc5.cyan("$")} op2env .env.tpl -o .env.local
|
|
783
1089
|
|
|
784
|
-
${
|
|
785
|
-
${
|
|
1090
|
+
${pc5.dim("# Preview without making changes")}
|
|
1091
|
+
${pc5.cyan("$")} op2env .env.tpl --dry-run
|
|
786
1092
|
|
|
787
|
-
${
|
|
788
|
-
${
|
|
1093
|
+
${pc5.dim("# Overwrite existing .env without prompting")}
|
|
1094
|
+
${pc5.cyan("$")} op2env .env.tpl -f
|
|
789
1095
|
|
|
790
|
-
${
|
|
791
|
-
${
|
|
1096
|
+
${pc5.bold("DOCUMENTATION")}
|
|
1097
|
+
${pc5.dim("https://github.com/tolgamorf/env2op-cli")}
|
|
792
1098
|
`);
|
|
793
1099
|
}
|