@oatnil/ud 0.33.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 +31 -0
- package/install.js +170 -0
- package/package.json +38 -0
- package/run.js +21 -0
package/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# @oatnil/ud
|
|
2
|
+
|
|
3
|
+
UnderControl CLI - task and expense management from the terminal.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @oatnil/ud
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Run directly
|
|
15
|
+
ud task list
|
|
16
|
+
ud query "status = 'todo'"
|
|
17
|
+
|
|
18
|
+
# Or use npx (no install needed)
|
|
19
|
+
npx @oatnil/ud task list
|
|
20
|
+
npx @oatnil/ud --help
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Other Installation Methods
|
|
24
|
+
|
|
25
|
+
- **Homebrew**: `brew tap oatnil-top/ud && brew install ud`
|
|
26
|
+
- **Direct download**: `curl -fsSL https://get.oatnil.com/ud | bash`
|
|
27
|
+
- **APT (Ubuntu/Debian)**: See [documentation](https://docs.oatnil.com/cli)
|
|
28
|
+
|
|
29
|
+
## License
|
|
30
|
+
|
|
31
|
+
MIT
|
package/install.js
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const https = require("https");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const { execSync } = require("child_process");
|
|
7
|
+
const zlib = require("zlib");
|
|
8
|
+
|
|
9
|
+
const CDN_BASE =
|
|
10
|
+
"https://pub-35d77f83ee8a41798bb4b2e1831ac70a.r2.dev/cli/releases";
|
|
11
|
+
|
|
12
|
+
const PLATFORM_MAP = {
|
|
13
|
+
darwin: "darwin",
|
|
14
|
+
linux: "linux",
|
|
15
|
+
win32: "windows",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const ARCH_MAP = {
|
|
19
|
+
x64: "amd64",
|
|
20
|
+
arm64: "arm64",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function getBinaryName(version, goos, goarch) {
|
|
24
|
+
const name = `ud_${version}_${goos}_${goarch}`;
|
|
25
|
+
return goos === "windows" ? `${name}.exe` : name;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getArchiveName(version, goos, goarch) {
|
|
29
|
+
const base = `ud_${version}_${goos}_${goarch}`;
|
|
30
|
+
return goos === "windows" ? `${base}.zip` : `${base}.tar.gz`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function fetch(url) {
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
https
|
|
36
|
+
.get(url, (res) => {
|
|
37
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
38
|
+
return fetch(res.headers.location).then(resolve, reject);
|
|
39
|
+
}
|
|
40
|
+
if (res.statusCode !== 200) {
|
|
41
|
+
return reject(new Error(`HTTP ${res.statusCode} for ${url}`));
|
|
42
|
+
}
|
|
43
|
+
const chunks = [];
|
|
44
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
45
|
+
res.on("end", () => resolve(Buffer.concat(chunks)));
|
|
46
|
+
res.on("error", reject);
|
|
47
|
+
})
|
|
48
|
+
.on("error", reject);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function extractTarGz(buffer, binaryName, destPath) {
|
|
53
|
+
// tar.gz: use tar command for simplicity
|
|
54
|
+
const tmpDir = path.join(path.dirname(destPath), ".ud-tmp");
|
|
55
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
56
|
+
|
|
57
|
+
const archivePath = path.join(tmpDir, "archive.tar.gz");
|
|
58
|
+
fs.writeFileSync(archivePath, buffer);
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
execSync(`tar -xzf "${archivePath}" -C "${tmpDir}"`, { stdio: "pipe" });
|
|
62
|
+
|
|
63
|
+
const extractedBinary = path.join(tmpDir, binaryName);
|
|
64
|
+
if (!fs.existsSync(extractedBinary)) {
|
|
65
|
+
// try finding any file in tmpDir
|
|
66
|
+
const files = fs.readdirSync(tmpDir).filter((f) => f !== "archive.tar.gz");
|
|
67
|
+
if (files.length === 0) {
|
|
68
|
+
throw new Error(`No binary found in archive`);
|
|
69
|
+
}
|
|
70
|
+
fs.renameSync(path.join(tmpDir, files[0]), destPath);
|
|
71
|
+
} else {
|
|
72
|
+
fs.renameSync(extractedBinary, destPath);
|
|
73
|
+
}
|
|
74
|
+
} finally {
|
|
75
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function extractZip(buffer, binaryName, destPath) {
|
|
80
|
+
const tmpDir = path.join(path.dirname(destPath), ".ud-tmp");
|
|
81
|
+
fs.mkdirSync(tmpDir, { recursive: true });
|
|
82
|
+
|
|
83
|
+
const archivePath = path.join(tmpDir, "archive.zip");
|
|
84
|
+
fs.writeFileSync(archivePath, buffer);
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
// Use PowerShell on Windows, unzip on others
|
|
88
|
+
if (process.platform === "win32") {
|
|
89
|
+
execSync(
|
|
90
|
+
`powershell -command "Expand-Archive -Path '${archivePath}' -DestinationPath '${tmpDir}'"`,
|
|
91
|
+
{ stdio: "pipe" }
|
|
92
|
+
);
|
|
93
|
+
} else {
|
|
94
|
+
execSync(`unzip -o "${archivePath}" -d "${tmpDir}"`, { stdio: "pipe" });
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const extractedBinary = path.join(tmpDir, binaryName);
|
|
98
|
+
if (!fs.existsSync(extractedBinary)) {
|
|
99
|
+
const files = fs
|
|
100
|
+
.readdirSync(tmpDir)
|
|
101
|
+
.filter((f) => f !== "archive.zip");
|
|
102
|
+
if (files.length === 0) {
|
|
103
|
+
throw new Error(`No binary found in archive`);
|
|
104
|
+
}
|
|
105
|
+
fs.renameSync(path.join(tmpDir, files[0]), destPath);
|
|
106
|
+
} else {
|
|
107
|
+
fs.renameSync(extractedBinary, destPath);
|
|
108
|
+
}
|
|
109
|
+
} finally {
|
|
110
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async function main() {
|
|
115
|
+
const pkg = require("./package.json");
|
|
116
|
+
const version = pkg.version;
|
|
117
|
+
|
|
118
|
+
const goos = PLATFORM_MAP[process.platform];
|
|
119
|
+
const goarch = ARCH_MAP[process.arch];
|
|
120
|
+
|
|
121
|
+
if (!goos) {
|
|
122
|
+
console.error(`Unsupported platform: ${process.platform}`);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
if (!goarch) {
|
|
126
|
+
console.error(`Unsupported architecture: ${process.arch}`);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const binDir = path.join(__dirname, "bin");
|
|
131
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
132
|
+
|
|
133
|
+
const binaryExt = goos === "windows" ? ".exe" : "";
|
|
134
|
+
const destPath = path.join(binDir, `ud${binaryExt}`);
|
|
135
|
+
|
|
136
|
+
// Skip if binary already exists
|
|
137
|
+
if (fs.existsSync(destPath)) {
|
|
138
|
+
console.log(`ud binary already exists at ${destPath}`);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const archiveName = getArchiveName(version, goos, goarch);
|
|
143
|
+
const binaryName = getBinaryName(version, goos, goarch);
|
|
144
|
+
const url = `${CDN_BASE}/${version}/${archiveName}`;
|
|
145
|
+
|
|
146
|
+
console.log(`Downloading ud v${version} for ${goos}/${goarch}...`);
|
|
147
|
+
console.log(` ${url}`);
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
const buffer = await fetch(url);
|
|
151
|
+
|
|
152
|
+
if (archiveName.endsWith(".zip")) {
|
|
153
|
+
extractZip(buffer, binaryName, destPath);
|
|
154
|
+
} else {
|
|
155
|
+
extractTarGz(buffer, binaryName, destPath);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Make executable
|
|
159
|
+
if (goos !== "windows") {
|
|
160
|
+
fs.chmodSync(destPath, 0o755);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
console.log(`ud v${version} installed successfully!`);
|
|
164
|
+
} catch (err) {
|
|
165
|
+
console.error(`Failed to install ud: ${err.message}`);
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oatnil/ud",
|
|
3
|
+
"version": "0.33.0",
|
|
4
|
+
"description": "UnderControl CLI - task and expense management from the terminal",
|
|
5
|
+
"homepage": "https://github.com/oatnil-top/ud",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/oatnil-top/ud.git"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"bin": {
|
|
12
|
+
"ud": "run.js"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"postinstall": "node install.js"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"cli",
|
|
19
|
+
"task",
|
|
20
|
+
"undercontrol",
|
|
21
|
+
"tui",
|
|
22
|
+
"productivity"
|
|
23
|
+
],
|
|
24
|
+
"os": [
|
|
25
|
+
"darwin",
|
|
26
|
+
"linux",
|
|
27
|
+
"win32"
|
|
28
|
+
],
|
|
29
|
+
"cpu": [
|
|
30
|
+
"x64",
|
|
31
|
+
"arm64"
|
|
32
|
+
],
|
|
33
|
+
"files": [
|
|
34
|
+
"install.js",
|
|
35
|
+
"run.js",
|
|
36
|
+
"README.md"
|
|
37
|
+
]
|
|
38
|
+
}
|
package/run.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { execFileSync } = require("child_process");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const fs = require("fs");
|
|
6
|
+
|
|
7
|
+
const ext = process.platform === "win32" ? ".exe" : "";
|
|
8
|
+
const binPath = path.join(__dirname, "bin", `ud${ext}`);
|
|
9
|
+
|
|
10
|
+
if (!fs.existsSync(binPath)) {
|
|
11
|
+
console.error(
|
|
12
|
+
"ud binary not found. Try reinstalling: npm install -g @oatnil/ud"
|
|
13
|
+
);
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
execFileSync(binPath, process.argv.slice(2), { stdio: "inherit" });
|
|
19
|
+
} catch (err) {
|
|
20
|
+
process.exit(err.status || 1);
|
|
21
|
+
}
|