dotenvx-tui 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -0
- package/bin/cli.js +29 -0
- package/install.js +100 -0
- package/package.json +33 -0
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# dotenvx-tui
|
|
2
|
+
|
|
3
|
+
Full-screen terminal UI for managing [dotenvx](https://dotenvx.com)-encrypted environment variables.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
┌─ Scopes ────┐ ┌─ Envs ───┐ ┌─ Keys ──────────────┐
|
|
7
|
+
│ > apps/api │ │ > local │ │ [x] DATABASE_URL │
|
|
8
|
+
│ apps/web │ │ staging│ │ [ ] API_KEY │
|
|
9
|
+
│ pkg/db │ │ prod │ │ [x] REDIS_URL │
|
|
10
|
+
└─────────────┘ └──────────┘ └─────────────────────┘
|
|
11
|
+
┌─ Preview ────────────────────────────────────────┐
|
|
12
|
+
│ DATABASE_URL = post•••••••••••••••••• │
|
|
13
|
+
└──────────────────────────────────────────────────┘
|
|
14
|
+
s:set g:get d:diff i:import e:export c:copy
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g dotenvx-tui
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Run in current directory (must have dotenvx-encrypted .env.* files)
|
|
27
|
+
dotenvx-tui
|
|
28
|
+
|
|
29
|
+
# Or specify a project directory
|
|
30
|
+
dotenvx-tui ~/my-project
|
|
31
|
+
|
|
32
|
+
# Or run without installing
|
|
33
|
+
npx dotenvx-tui
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Prerequisites
|
|
37
|
+
|
|
38
|
+
[dotenvx](https://dotenvx.com) must be installed: `brew install dotenvx/brew/dotenvx`
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
|
|
42
|
+
- Three-panel browser (Scopes | Environments | Keys)
|
|
43
|
+
- Keyboard-driven navigation with circular wrapping
|
|
44
|
+
- Multi-select batch operations
|
|
45
|
+
- Set, get, diff, import, export, and copy to clipboard
|
|
46
|
+
- Live file watching (auto-refresh on changes)
|
|
47
|
+
- Masked value preview with auto-mask timer
|
|
48
|
+
- Memory-safe secret handling
|
|
49
|
+
|
|
50
|
+
Full documentation: [github.com/warui1/dotenvx-tui](https://github.com/warui1/dotenvx-tui)
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
MIT
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawn } = require("child_process");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
|
|
7
|
+
const NAME = "dotenvx-tui";
|
|
8
|
+
const binPath = path.join(__dirname, NAME);
|
|
9
|
+
|
|
10
|
+
if (!fs.existsSync(binPath)) {
|
|
11
|
+
console.error(
|
|
12
|
+
`${NAME} binary not found. Try reinstalling:\n` +
|
|
13
|
+
` npm install -g dotenvx-tui`
|
|
14
|
+
);
|
|
15
|
+
process.exit(1);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const child = spawn(binPath, process.argv.slice(2), {
|
|
19
|
+
stdio: "inherit",
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
child.on("error", (err) => {
|
|
23
|
+
console.error(`Failed to start ${NAME}: ${err.message}`);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
child.on("close", (code) => {
|
|
28
|
+
process.exit(code ?? 1);
|
|
29
|
+
});
|
package/install.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Postinstall script: downloads the correct binary from GitHub Releases.
|
|
4
|
+
// No external dependencies — uses Node.js built-in https/fs/child_process.
|
|
5
|
+
|
|
6
|
+
const https = require("https");
|
|
7
|
+
const fs = require("fs");
|
|
8
|
+
const path = require("path");
|
|
9
|
+
const { execSync } = require("child_process");
|
|
10
|
+
const { createGunzip } = require("zlib");
|
|
11
|
+
|
|
12
|
+
const REPO = "SpyrosBou/dotenvx-tui";
|
|
13
|
+
const NAME = "dotenvx-tui";
|
|
14
|
+
const VERSION = require("./package.json").version;
|
|
15
|
+
|
|
16
|
+
const PLATFORM_MAP = {
|
|
17
|
+
darwin: "darwin",
|
|
18
|
+
linux: "linux",
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const ARCH_MAP = {
|
|
22
|
+
x64: "amd64",
|
|
23
|
+
arm64: "arm64",
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function getTarget() {
|
|
27
|
+
const platform = PLATFORM_MAP[process.platform];
|
|
28
|
+
const arch = ARCH_MAP[process.arch];
|
|
29
|
+
|
|
30
|
+
if (!platform || !arch) {
|
|
31
|
+
console.error(
|
|
32
|
+
`Unsupported platform: ${process.platform}-${process.arch}\n` +
|
|
33
|
+
`Supported: darwin-arm64, darwin-x64, linux-arm64, linux-x64\n` +
|
|
34
|
+
`Build from source: go install github.com/${REPO}@latest`
|
|
35
|
+
);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return { platform, arch };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function downloadFile(url) {
|
|
43
|
+
return new Promise((resolve, reject) => {
|
|
44
|
+
https
|
|
45
|
+
.get(url, (res) => {
|
|
46
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
47
|
+
return downloadFile(res.headers.location).then(resolve, reject);
|
|
48
|
+
}
|
|
49
|
+
if (res.statusCode !== 200) {
|
|
50
|
+
return reject(new Error(`Download failed: HTTP ${res.statusCode}`));
|
|
51
|
+
}
|
|
52
|
+
const chunks = [];
|
|
53
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
54
|
+
res.on("end", () => resolve(Buffer.concat(chunks)));
|
|
55
|
+
res.on("error", reject);
|
|
56
|
+
})
|
|
57
|
+
.on("error", reject);
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function extractTarGz(buffer, destDir) {
|
|
62
|
+
// Write to temp file and use system tar (available on macOS + Linux)
|
|
63
|
+
const tmpFile = path.join(destDir, "_archive.tar.gz");
|
|
64
|
+
fs.writeFileSync(tmpFile, buffer);
|
|
65
|
+
execSync(`tar -xzf "${tmpFile}" -C "${destDir}" "${NAME}"`, { stdio: "ignore" });
|
|
66
|
+
fs.unlinkSync(tmpFile);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function main() {
|
|
70
|
+
const { platform, arch } = getTarget();
|
|
71
|
+
const archiveName = `${NAME}_${VERSION}_${platform}_${arch}.tar.gz`;
|
|
72
|
+
const url = `https://github.com/${REPO}/releases/download/v${VERSION}/${archiveName}`;
|
|
73
|
+
const binDir = path.join(__dirname, "bin");
|
|
74
|
+
|
|
75
|
+
// Skip if binary already exists
|
|
76
|
+
const binPath = path.join(binDir, NAME);
|
|
77
|
+
if (fs.existsSync(binPath)) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(`Downloading ${NAME} v${VERSION} for ${platform}/${arch}...`);
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
const buffer = await downloadFile(url);
|
|
85
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
86
|
+
extractTarGz(buffer, binDir);
|
|
87
|
+
fs.chmodSync(binPath, 0o755);
|
|
88
|
+
console.log(`Installed ${NAME} to ${binPath}`);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
console.error(
|
|
91
|
+
`Failed to download ${NAME}: ${err.message}\n\n` +
|
|
92
|
+
`You can install manually:\n` +
|
|
93
|
+
` go install github.com/${REPO}@latest\n` +
|
|
94
|
+
` # or download from: https://github.com/${REPO}/releases`
|
|
95
|
+
);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dotenvx-tui",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Full-screen terminal UI for managing dotenvx-encrypted environment variables",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/warui1/dotenvx-tui.git"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"author": "warui1",
|
|
11
|
+
"bin": {
|
|
12
|
+
"dotenvx-tui": "bin/cli.js"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"postinstall": "node install.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"bin/cli.js",
|
|
19
|
+
"install.js"
|
|
20
|
+
],
|
|
21
|
+
"keywords": [
|
|
22
|
+
"dotenvx",
|
|
23
|
+
"dotenv",
|
|
24
|
+
"env",
|
|
25
|
+
"secrets",
|
|
26
|
+
"tui",
|
|
27
|
+
"terminal",
|
|
28
|
+
"encryption"
|
|
29
|
+
],
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=16"
|
|
32
|
+
}
|
|
33
|
+
}
|