@detent/cli 0.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 +45 -0
- package/bin.js +12 -0
- package/install.js +124 -0
- package/package.json +58 -0
- package/uninstall.js +17 -0
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Detent CLI - npm Distribution
|
|
2
|
+
|
|
3
|
+
Run GitHub Actions locally with intelligent error troubleshooting. Detent executes workflows, parses errors, categorizes them intelligently, and leverages Claude AI with parallel iterations to troubleshoot issues automatically.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @detent/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
After installation, the `dt` command will be available globally.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
dt --help
|
|
17
|
+
dt --version
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## How It Works
|
|
21
|
+
|
|
22
|
+
Detent streamlines your CI/CD development workflow:
|
|
23
|
+
|
|
24
|
+
1. **Local Execution**: Runs GitHub Actions workflows on your local machine
|
|
25
|
+
2. **Error Detection**: Automatically parses and extracts errors from workflow outputs
|
|
26
|
+
3. **Smart Categorization**: Intelligently groups and categorizes error types
|
|
27
|
+
4. **AI Troubleshooting**: Prompts Claude in parallel with multiple iterations to diagnose and suggest fixes
|
|
28
|
+
5. **Iterative Refinement**: Continues troubleshooting across multiple rounds until issues are resolved
|
|
29
|
+
|
|
30
|
+
### Binary Distribution
|
|
31
|
+
|
|
32
|
+
This npm package automatically downloads the appropriate pre-built Go binary for your platform during installation:
|
|
33
|
+
|
|
34
|
+
- Linux: amd64, arm64
|
|
35
|
+
- macOS: amd64 (Intel), arm64 (Apple Silicon)
|
|
36
|
+
- Windows: amd64
|
|
37
|
+
|
|
38
|
+
## Troubleshooting
|
|
39
|
+
|
|
40
|
+
If the installation fails, you can manually download the binary from:
|
|
41
|
+
https://github.com/handleui/detent/releases
|
|
42
|
+
|
|
43
|
+
## License
|
|
44
|
+
|
|
45
|
+
MIT
|
package/bin.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { spawn } = require("node:child_process");
|
|
4
|
+
const { join } = require("node:path");
|
|
5
|
+
|
|
6
|
+
const binPath = join(__dirname, "bin", "dt");
|
|
7
|
+
|
|
8
|
+
const child = spawn(binPath, process.argv.slice(2), { stdio: "inherit" });
|
|
9
|
+
|
|
10
|
+
child.on("exit", (code) => {
|
|
11
|
+
process.exit(code);
|
|
12
|
+
});
|
package/install.js
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { existsSync, mkdirSync, chmodSync } = require("node:fs");
|
|
4
|
+
const { join } = require("node:path");
|
|
5
|
+
const { pipeline } = require("node:stream");
|
|
6
|
+
const { promisify } = require("node:util");
|
|
7
|
+
const https = require("node:https");
|
|
8
|
+
const { createGunzip } = require("node:zlib");
|
|
9
|
+
const tar = require("tar-fs");
|
|
10
|
+
|
|
11
|
+
const streamPipeline = promisify(pipeline);
|
|
12
|
+
|
|
13
|
+
const PACKAGE_JSON = require("./package.json");
|
|
14
|
+
|
|
15
|
+
const getPlatform = () => {
|
|
16
|
+
const platform = process.platform;
|
|
17
|
+
if (platform === "win32") {
|
|
18
|
+
return "windows";
|
|
19
|
+
}
|
|
20
|
+
if (platform === "darwin") {
|
|
21
|
+
return "darwin";
|
|
22
|
+
}
|
|
23
|
+
if (platform === "linux") {
|
|
24
|
+
return "linux";
|
|
25
|
+
}
|
|
26
|
+
throw new Error(`Unsupported platform: ${platform}`);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const getArch = () => {
|
|
30
|
+
const arch = process.arch;
|
|
31
|
+
if (arch === "x64") {
|
|
32
|
+
return "amd64";
|
|
33
|
+
}
|
|
34
|
+
if (arch === "arm64") {
|
|
35
|
+
return "arm64";
|
|
36
|
+
}
|
|
37
|
+
throw new Error(`Unsupported architecture: ${arch}`);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const getExtension = () => (process.platform === "win32" ? "zip" : "tar.gz");
|
|
41
|
+
|
|
42
|
+
const getBinaryName = () => (process.platform === "win32" ? "dt.exe" : "dt");
|
|
43
|
+
|
|
44
|
+
const download = (url) =>
|
|
45
|
+
new Promise((resolve, reject) => {
|
|
46
|
+
https
|
|
47
|
+
.get(url, (response) => {
|
|
48
|
+
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
49
|
+
return download(response.headers.location).then(resolve, reject);
|
|
50
|
+
}
|
|
51
|
+
if (response.statusCode !== 200) {
|
|
52
|
+
reject(new Error(`Failed to download: ${response.statusCode}`));
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
resolve(response);
|
|
56
|
+
})
|
|
57
|
+
.on("error", reject);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const install = async () => {
|
|
61
|
+
try {
|
|
62
|
+
const platform = getPlatform();
|
|
63
|
+
const arch = getArch();
|
|
64
|
+
const ext = getExtension();
|
|
65
|
+
const version = PACKAGE_JSON.version;
|
|
66
|
+
|
|
67
|
+
const url = PACKAGE_JSON.goBinary.url
|
|
68
|
+
.replace("{{version}}", version)
|
|
69
|
+
.replace("{{platform}}", platform)
|
|
70
|
+
.replace("{{arch}}", arch)
|
|
71
|
+
.replace("{{ext}}", ext);
|
|
72
|
+
|
|
73
|
+
const binDir = join(__dirname, PACKAGE_JSON.goBinary.path);
|
|
74
|
+
const binaryName = getBinaryName();
|
|
75
|
+
const binaryPath = join(binDir, binaryName);
|
|
76
|
+
|
|
77
|
+
if (!existsSync(binDir)) {
|
|
78
|
+
mkdirSync(binDir, { recursive: true });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log(`Downloading binary from ${url}...`);
|
|
82
|
+
|
|
83
|
+
const response = await download(url);
|
|
84
|
+
|
|
85
|
+
if (process.platform === "win32") {
|
|
86
|
+
const AdmZip = require("adm-zip");
|
|
87
|
+
const chunks = [];
|
|
88
|
+
|
|
89
|
+
await new Promise((resolve, reject) => {
|
|
90
|
+
response.on("data", (chunk) => chunks.push(chunk));
|
|
91
|
+
response.on("end", resolve);
|
|
92
|
+
response.on("error", reject);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const buffer = Buffer.concat(chunks);
|
|
96
|
+
const zip = new AdmZip(buffer);
|
|
97
|
+
zip.extractAllTo(binDir, true);
|
|
98
|
+
} else {
|
|
99
|
+
await streamPipeline(response, createGunzip(), tar.extract(binDir));
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (process.platform !== "win32") {
|
|
103
|
+
chmodSync(binaryPath, 0o755);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
console.log(`Binary installed successfully at ${binaryPath}`);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error("Failed to install binary:", error.message);
|
|
109
|
+
console.error("\nYou can manually download the binary from:");
|
|
110
|
+
console.error(
|
|
111
|
+
`https://github.com/handleui/detent/releases/tag/v${PACKAGE_JSON.version}`
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
// Exit gracefully in CI or during development (version 0.0.0)
|
|
115
|
+
if (process.env.CI || PACKAGE_JSON.version === "0.0.0") {
|
|
116
|
+
console.log("Skipping binary installation in CI/development mode");
|
|
117
|
+
process.exit(0);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
install();
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@detent/cli",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "Run GitHub Actions locally, intelligently parse errors, and troubleshoot with parallel Claude iterations",
|
|
5
|
+
"author": "handleui",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/handleui/detent.git",
|
|
9
|
+
"directory": "apps/cli"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/handleui/detent/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/handleui/detent#readme",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"cli",
|
|
17
|
+
"github-actions",
|
|
18
|
+
"local-runner",
|
|
19
|
+
"error-parsing",
|
|
20
|
+
"ai-troubleshooting",
|
|
21
|
+
"claude",
|
|
22
|
+
"detent"
|
|
23
|
+
],
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=20.0.0"
|
|
27
|
+
},
|
|
28
|
+
"bin": {
|
|
29
|
+
"dt": "bin.js"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"bin.js",
|
|
33
|
+
"install.js",
|
|
34
|
+
"uninstall.js",
|
|
35
|
+
"bin/",
|
|
36
|
+
"README.md"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "sh -c 'VERSION=$(node -p \"require(\\\"./package.json\\\").version\") && go build -ldflags \"-X github.com/detent/cli/cmd.Version=$VERSION\" -o dist/dt'",
|
|
40
|
+
"clean": "rm -rf dist bin",
|
|
41
|
+
"prepare-release": "npm run clean && mkdir -p bin",
|
|
42
|
+
"postinstall": "node ./install.js",
|
|
43
|
+
"preuninstall": "node ./uninstall.js"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"tar-fs": "^3.0.6",
|
|
47
|
+
"adm-zip": "^0.5.16"
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public",
|
|
51
|
+
"registry": "https://registry.npmjs.org/"
|
|
52
|
+
},
|
|
53
|
+
"goBinary": {
|
|
54
|
+
"name": "dt",
|
|
55
|
+
"path": "./bin",
|
|
56
|
+
"url": "https://github.com/handleui/detent/releases/download/v{{version}}/dt-{{platform}}-{{arch}}.{{ext}}"
|
|
57
|
+
}
|
|
58
|
+
}
|
package/uninstall.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { existsSync, rmSync } = require("node:fs");
|
|
4
|
+
const { join } = require("node:path");
|
|
5
|
+
|
|
6
|
+
const PACKAGE_JSON = require("./package.json");
|
|
7
|
+
|
|
8
|
+
const uninstall = () => {
|
|
9
|
+
const binDir = join(__dirname, PACKAGE_JSON.goBinary.path);
|
|
10
|
+
|
|
11
|
+
if (existsSync(binDir)) {
|
|
12
|
+
rmSync(binDir, { recursive: true, force: true });
|
|
13
|
+
console.log("Binary uninstalled successfully");
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
uninstall();
|