kangentic 0.1.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/LICENSE +5 -0
- package/README.md +60 -0
- package/bin/kangentic.js +409 -0
- package/package.json +31 -0
package/LICENSE
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Kangentic
|
|
2
|
+
|
|
3
|
+
**Visual Agent Orchestration for Claude Code**
|
|
4
|
+
|
|
5
|
+
One command to install and launch [Kangentic](https://github.com/Kangentic/kangentic) -- a cross-platform desktop Kanban for Claude Code agents.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx kangentic
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This downloads the pre-built binary for your platform from GitHub Releases, installs it, and launches the app. After the first run, the app manages its own updates automatically (Windows and macOS).
|
|
14
|
+
|
|
15
|
+
### Open a specific project
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx kangentic /path/to/your/project
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## How it works
|
|
22
|
+
|
|
23
|
+
1. Detects your platform (Windows, macOS, Linux) and architecture (x64, arm64)
|
|
24
|
+
2. Downloads the matching installer from [GitHub Releases](https://github.com/Kangentic/kangentic/releases)
|
|
25
|
+
3. Installs per platform:
|
|
26
|
+
- **Windows:** Runs NSIS installer silently to `%LOCALAPPDATA%\Programs\Kangentic\`
|
|
27
|
+
- **macOS:** Extracts .zip to `~/Applications/Kangentic.app`
|
|
28
|
+
- **Linux:** Installs .deb via `sudo dpkg -i` (prompts for password)
|
|
29
|
+
4. Launches the app
|
|
30
|
+
|
|
31
|
+
## Updates
|
|
32
|
+
|
|
33
|
+
After the initial install, you generally don't need to run `npx kangentic` again:
|
|
34
|
+
|
|
35
|
+
- **Windows:** electron-updater installs new versions silently on restart.
|
|
36
|
+
- **macOS:** Built-in auto-updater downloads in the background and prompts to restart. (Requires code signing.)
|
|
37
|
+
- **Linux:** No auto-update. Re-run `npx kangentic` or download from [GitHub Releases](https://github.com/Kangentic/kangentic/releases).
|
|
38
|
+
|
|
39
|
+
### Install a specific version
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx kangentic@0.2.0
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
The launcher version matches the app version. Specifying a version downloads that exact release.
|
|
46
|
+
|
|
47
|
+
## Prerequisites
|
|
48
|
+
|
|
49
|
+
- **[Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code)** installed and on your PATH
|
|
50
|
+
- **[Git 2.25+](https://git-scm.com/)** for worktree support
|
|
51
|
+
|
|
52
|
+
## Links
|
|
53
|
+
|
|
54
|
+
- [GitHub](https://github.com/Kangentic/kangentic)
|
|
55
|
+
- [Documentation](https://github.com/Kangentic/kangentic/tree/main/docs)
|
|
56
|
+
- [Installation Guide](https://github.com/Kangentic/kangentic/blob/main/docs/installation.md)
|
|
57
|
+
|
|
58
|
+
## License
|
|
59
|
+
|
|
60
|
+
[AGPL-3.0-only](https://github.com/Kangentic/kangentic/blob/main/LICENSE)
|
package/bin/kangentic.js
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Kangentic npx launcher
|
|
4
|
+
// Downloads, installs, and launches Kangentic from GitHub Releases.
|
|
5
|
+
// Zero dependencies -- pure Node.js built-ins only.
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const https = require('https');
|
|
10
|
+
const http = require('http');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const os = require('os');
|
|
14
|
+
const { execFileSync, spawn } = require('child_process');
|
|
15
|
+
|
|
16
|
+
const VERSION = require('../package.json').version;
|
|
17
|
+
const REPO_OWNER = 'Kangentic';
|
|
18
|
+
const REPO_NAME = 'kangentic';
|
|
19
|
+
const MAX_REDIRECTS = 5;
|
|
20
|
+
|
|
21
|
+
// --- Platform detection ---
|
|
22
|
+
|
|
23
|
+
function getPlatformInfo() {
|
|
24
|
+
const platform = process.platform;
|
|
25
|
+
const arch = process.arch;
|
|
26
|
+
|
|
27
|
+
if (platform === 'win32') {
|
|
28
|
+
return { platform: 'win32', arch: 'x64', extension: 'exe' };
|
|
29
|
+
}
|
|
30
|
+
if (platform === 'darwin') {
|
|
31
|
+
return { platform: 'darwin', arch, extension: 'zip' };
|
|
32
|
+
}
|
|
33
|
+
if (platform === 'linux') {
|
|
34
|
+
return { platform: 'linux', arch: 'x64', extension: 'deb' };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// --- Install path detection ---
|
|
41
|
+
|
|
42
|
+
function getInstallPath(platformInfo) {
|
|
43
|
+
if (platformInfo.platform === 'win32') {
|
|
44
|
+
const localAppData = process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local');
|
|
45
|
+
return path.join(localAppData, 'Programs', 'Kangentic', 'Kangentic.exe');
|
|
46
|
+
}
|
|
47
|
+
if (platformInfo.platform === 'darwin') {
|
|
48
|
+
const userApps = path.join(os.homedir(), 'Applications', 'Kangentic.app');
|
|
49
|
+
const systemApps = '/Applications/Kangentic.app';
|
|
50
|
+
if (fs.existsSync(userApps)) return userApps;
|
|
51
|
+
if (fs.existsSync(systemApps)) return systemApps;
|
|
52
|
+
return userApps; // default install target
|
|
53
|
+
}
|
|
54
|
+
if (platformInfo.platform === 'linux') {
|
|
55
|
+
return '/usr/bin/kangentic';
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function isInstalled(platformInfo) {
|
|
61
|
+
const installPath = getInstallPath(platformInfo);
|
|
62
|
+
if (!fs.existsSync(installPath)) return false;
|
|
63
|
+
|
|
64
|
+
// On Windows, the exe existing is sufficient (NSIS install)
|
|
65
|
+
if (platformInfo.platform === 'win32') {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// On macOS, check the app bundle's version in Info.plist
|
|
70
|
+
if (platformInfo.platform === 'darwin') {
|
|
71
|
+
try {
|
|
72
|
+
const plistPath = path.join(installPath, 'Contents', 'Info.plist');
|
|
73
|
+
const plistContent = fs.readFileSync(plistPath, 'utf-8');
|
|
74
|
+
const versionMatch = plistContent.match(/<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/);
|
|
75
|
+
if (versionMatch && versionMatch[1] !== VERSION) return false;
|
|
76
|
+
} catch {
|
|
77
|
+
// Can't read plist, treat as not installed
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// On Linux, check `kangentic --version` output
|
|
83
|
+
if (platformInfo.platform === 'linux') {
|
|
84
|
+
try {
|
|
85
|
+
const output = execFileSync(installPath, ['--version'], { encoding: 'utf-8', timeout: 5000 }).trim();
|
|
86
|
+
if (!output.includes(VERSION)) return false;
|
|
87
|
+
} catch {
|
|
88
|
+
// Can't check version, treat as installed (binary exists)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// --- Download URL construction ---
|
|
96
|
+
|
|
97
|
+
function getArtifactFilename(platformInfo) {
|
|
98
|
+
const version = VERSION;
|
|
99
|
+
|
|
100
|
+
if (platformInfo.platform === 'win32') {
|
|
101
|
+
// NSIS produces "Kangentic-Setup-X.Y.Z.exe"
|
|
102
|
+
return `Kangentic-Setup-${version}.exe`;
|
|
103
|
+
}
|
|
104
|
+
if (platformInfo.platform === 'darwin') {
|
|
105
|
+
return `Kangentic-${version}-${platformInfo.arch}-mac.zip`;
|
|
106
|
+
}
|
|
107
|
+
if (platformInfo.platform === 'linux') {
|
|
108
|
+
// Check if rpm-based system
|
|
109
|
+
try {
|
|
110
|
+
execFileSync('which', ['rpm'], { stdio: 'ignore' });
|
|
111
|
+
const hasApt = (() => {
|
|
112
|
+
try {
|
|
113
|
+
execFileSync('which', ['apt'], { stdio: 'ignore' });
|
|
114
|
+
return true;
|
|
115
|
+
} catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
})();
|
|
119
|
+
if (!hasApt) {
|
|
120
|
+
return `kangentic-${version}-1.x86_64.rpm`;
|
|
121
|
+
}
|
|
122
|
+
} catch {
|
|
123
|
+
// not rpm-based, use deb
|
|
124
|
+
}
|
|
125
|
+
return `kangentic_${version}_amd64.deb`;
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function getDownloadUrl(platformInfo) {
|
|
131
|
+
const filename = getArtifactFilename(platformInfo);
|
|
132
|
+
if (!filename) return null;
|
|
133
|
+
return `https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/download/v${VERSION}/${filename}`;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// --- HTTP download with redirect following ---
|
|
137
|
+
|
|
138
|
+
function download(url, destinationPath, redirectCount) {
|
|
139
|
+
if (redirectCount === undefined) redirectCount = 0;
|
|
140
|
+
|
|
141
|
+
return new Promise((resolve, reject) => {
|
|
142
|
+
if (redirectCount > MAX_REDIRECTS) {
|
|
143
|
+
reject(new Error('Too many redirects'));
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const protocol = url.startsWith('https') ? https : http;
|
|
148
|
+
const request = protocol.get(url, (response) => {
|
|
149
|
+
// Follow redirects (GitHub -> S3)
|
|
150
|
+
if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
|
|
151
|
+
download(response.headers.location, destinationPath, redirectCount + 1)
|
|
152
|
+
.then(resolve)
|
|
153
|
+
.catch(reject);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (response.statusCode !== 200) {
|
|
158
|
+
reject(new Error(`Download failed: HTTP ${response.statusCode}`));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const totalBytes = parseInt(response.headers['content-length'] || '0', 10);
|
|
163
|
+
let downloadedBytes = 0;
|
|
164
|
+
|
|
165
|
+
const fileStream = fs.createWriteStream(destinationPath);
|
|
166
|
+
response.on('data', (chunk) => {
|
|
167
|
+
downloadedBytes += chunk.length;
|
|
168
|
+
if (totalBytes > 0) {
|
|
169
|
+
const megabytesDownloaded = (downloadedBytes / 1024 / 1024).toFixed(1);
|
|
170
|
+
const megabytesTotal = (totalBytes / 1024 / 1024).toFixed(1);
|
|
171
|
+
const percent = Math.round((downloadedBytes / totalBytes) * 100);
|
|
172
|
+
process.stdout.write(`\rDownloading... ${megabytesDownloaded}/${megabytesTotal} MB (${percent}%)`);
|
|
173
|
+
} else {
|
|
174
|
+
const megabytesDownloaded = (downloadedBytes / 1024 / 1024).toFixed(1);
|
|
175
|
+
process.stdout.write(`\rDownloading... ${megabytesDownloaded} MB`);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
response.pipe(fileStream);
|
|
180
|
+
|
|
181
|
+
fileStream.on('finish', () => {
|
|
182
|
+
process.stdout.write('\n');
|
|
183
|
+
fileStream.close();
|
|
184
|
+
resolve();
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
fileStream.on('error', reject);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
request.on('error', reject);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// --- Platform-specific install ---
|
|
195
|
+
|
|
196
|
+
function installWindows(artifactPath) {
|
|
197
|
+
console.log('Installing Kangentic (NSIS installer)...');
|
|
198
|
+
execFileSync(artifactPath, ['/S'], { stdio: 'ignore' });
|
|
199
|
+
console.log('Installation complete.');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function installMacOS(artifactPath) {
|
|
203
|
+
const tempDir = path.dirname(artifactPath);
|
|
204
|
+
const extractDir = path.join(tempDir, 'kangentic-extract');
|
|
205
|
+
|
|
206
|
+
console.log('Extracting Kangentic.app...');
|
|
207
|
+
fs.mkdirSync(extractDir, { recursive: true });
|
|
208
|
+
execFileSync('unzip', ['-o', '-q', artifactPath, '-d', extractDir]);
|
|
209
|
+
|
|
210
|
+
const appSource = path.join(extractDir, 'Kangentic.app');
|
|
211
|
+
const appTarget = path.join(os.homedir(), 'Applications', 'Kangentic.app');
|
|
212
|
+
|
|
213
|
+
// Ensure ~/Applications exists
|
|
214
|
+
const userAppsDir = path.join(os.homedir(), 'Applications');
|
|
215
|
+
fs.mkdirSync(userAppsDir, { recursive: true });
|
|
216
|
+
|
|
217
|
+
// Remove old install if present
|
|
218
|
+
if (fs.existsSync(appTarget)) {
|
|
219
|
+
fs.rmSync(appTarget, { recursive: true, force: true });
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
console.log(`Installing to ${appTarget}...`);
|
|
223
|
+
fs.renameSync(appSource, appTarget);
|
|
224
|
+
|
|
225
|
+
// Clean up extract dir
|
|
226
|
+
fs.rmSync(extractDir, { recursive: true, force: true });
|
|
227
|
+
|
|
228
|
+
console.log('Installation complete.');
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function installLinux(artifactPath) {
|
|
232
|
+
console.log('Installing Kangentic...');
|
|
233
|
+
if (artifactPath.endsWith('.deb')) {
|
|
234
|
+
console.log('Running: sudo dpkg -i (you may be prompted for your password)');
|
|
235
|
+
execFileSync('sudo', ['dpkg', '-i', artifactPath], { stdio: 'inherit' });
|
|
236
|
+
} else if (artifactPath.endsWith('.rpm')) {
|
|
237
|
+
console.log('Running: sudo rpm -i (you may be prompted for your password)');
|
|
238
|
+
execFileSync('sudo', ['rpm', '-i', artifactPath], { stdio: 'inherit' });
|
|
239
|
+
}
|
|
240
|
+
console.log('Installation complete.');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function install(platformInfo, artifactPath) {
|
|
244
|
+
if (platformInfo.platform === 'win32') {
|
|
245
|
+
installWindows(artifactPath);
|
|
246
|
+
} else if (platformInfo.platform === 'darwin') {
|
|
247
|
+
installMacOS(artifactPath);
|
|
248
|
+
} else if (platformInfo.platform === 'linux') {
|
|
249
|
+
installLinux(artifactPath);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// --- Launch ---
|
|
254
|
+
|
|
255
|
+
function launch(platformInfo, targetDir, dataDir) {
|
|
256
|
+
const installPath = getInstallPath(platformInfo);
|
|
257
|
+
|
|
258
|
+
if (!fs.existsSync(installPath)) {
|
|
259
|
+
console.error('Error: Kangentic installation not found after install.');
|
|
260
|
+
console.error(`Expected at: ${installPath}`);
|
|
261
|
+
process.exit(1);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
console.log('Launching Kangentic...');
|
|
265
|
+
|
|
266
|
+
const childEnv = { ...process.env };
|
|
267
|
+
if (dataDir) {
|
|
268
|
+
childEnv.KANGENTIC_DATA_DIR = dataDir;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (platformInfo.platform === 'win32') {
|
|
272
|
+
const child = spawn(installPath, [`--cwd=${targetDir}`], {
|
|
273
|
+
detached: true,
|
|
274
|
+
stdio: 'ignore',
|
|
275
|
+
env: childEnv,
|
|
276
|
+
});
|
|
277
|
+
child.unref();
|
|
278
|
+
} else if (platformInfo.platform === 'darwin') {
|
|
279
|
+
const openArgs = ['-a', installPath, '--args', `--cwd=${targetDir}`];
|
|
280
|
+
if (dataDir) {
|
|
281
|
+
openArgs.push(`--data-dir=${dataDir}`);
|
|
282
|
+
}
|
|
283
|
+
execFileSync('open', openArgs);
|
|
284
|
+
} else if (platformInfo.platform === 'linux') {
|
|
285
|
+
const child = spawn(installPath, [`--cwd=${targetDir}`], {
|
|
286
|
+
detached: true,
|
|
287
|
+
stdio: 'ignore',
|
|
288
|
+
env: childEnv,
|
|
289
|
+
});
|
|
290
|
+
child.unref();
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// --- Config directory for temp downloads ---
|
|
295
|
+
|
|
296
|
+
function getTempDir() {
|
|
297
|
+
const platform = process.platform;
|
|
298
|
+
let base;
|
|
299
|
+
if (platform === 'win32') {
|
|
300
|
+
base = process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming');
|
|
301
|
+
} else if (platform === 'darwin') {
|
|
302
|
+
base = path.join(os.homedir(), 'Library', 'Application Support');
|
|
303
|
+
} else {
|
|
304
|
+
base = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config');
|
|
305
|
+
}
|
|
306
|
+
const tempDir = path.join(base, 'kangentic', 'launcher');
|
|
307
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
308
|
+
return tempDir;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// --- Main ---
|
|
312
|
+
|
|
313
|
+
function parseDataDir(arguments_) {
|
|
314
|
+
for (let index = 0; index < arguments_.length; index++) {
|
|
315
|
+
const argument = arguments_[index];
|
|
316
|
+
if (argument.startsWith('--data-dir=')) {
|
|
317
|
+
return argument.slice('--data-dir='.length);
|
|
318
|
+
}
|
|
319
|
+
if (argument === '--data-dir' && index + 1 < arguments_.length) {
|
|
320
|
+
const nextArgument = arguments_[index + 1];
|
|
321
|
+
if (!nextArgument.startsWith('-')) {
|
|
322
|
+
return nextArgument;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function findTargetDir(arguments_) {
|
|
330
|
+
for (let index = 0; index < arguments_.length; index++) {
|
|
331
|
+
const argument = arguments_[index];
|
|
332
|
+
if (argument.startsWith('-')) {
|
|
333
|
+
// Skip --data-dir's value argument
|
|
334
|
+
if (argument === '--data-dir' && index + 1 < arguments_.length) {
|
|
335
|
+
index++;
|
|
336
|
+
}
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
return path.resolve(argument);
|
|
340
|
+
}
|
|
341
|
+
return process.cwd();
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
async function main() {
|
|
345
|
+
const arguments_ = process.argv.slice(2);
|
|
346
|
+
|
|
347
|
+
// Determine target directory (first positional argument, skipping flags and their values)
|
|
348
|
+
const targetDir = findTargetDir(arguments_);
|
|
349
|
+
|
|
350
|
+
// Resolve data directory: env var takes priority, then --data-dir flag
|
|
351
|
+
const dataDirFlag = parseDataDir(arguments_);
|
|
352
|
+
const dataDir = process.env.KANGENTIC_DATA_DIR || dataDirFlag;
|
|
353
|
+
|
|
354
|
+
// Detect platform
|
|
355
|
+
const platformInfo = getPlatformInfo();
|
|
356
|
+
if (!platformInfo) {
|
|
357
|
+
console.error(`Unsupported platform: ${process.platform} ${process.arch}`);
|
|
358
|
+
console.error(`Download manually from: https://github.com/${REPO_OWNER}/${REPO_NAME}/releases`);
|
|
359
|
+
process.exit(1);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Check if already installed
|
|
363
|
+
if (isInstalled(platformInfo)) {
|
|
364
|
+
console.log(`Kangentic v${VERSION} is already installed.`);
|
|
365
|
+
launch(platformInfo, targetDir, dataDir);
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Download
|
|
370
|
+
const downloadUrl = getDownloadUrl(platformInfo);
|
|
371
|
+
const artifactFilename = getArtifactFilename(platformInfo).replace(/%20/g, ' ');
|
|
372
|
+
const tempDir = getTempDir();
|
|
373
|
+
const artifactPath = path.join(tempDir, artifactFilename);
|
|
374
|
+
|
|
375
|
+
console.log(`Kangentic v${VERSION} is not installed. Downloading...`);
|
|
376
|
+
console.log(`URL: ${downloadUrl.replace(/%20/g, ' ')}`);
|
|
377
|
+
|
|
378
|
+
try {
|
|
379
|
+
await download(downloadUrl, artifactPath);
|
|
380
|
+
} catch (error) {
|
|
381
|
+
console.error(`\nDownload failed: ${error.message}`);
|
|
382
|
+
console.error(`\nDownload manually from: https://github.com/${REPO_OWNER}/${REPO_NAME}/releases/tag/v${VERSION}`);
|
|
383
|
+
process.exit(1);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// Install
|
|
387
|
+
try {
|
|
388
|
+
install(platformInfo, artifactPath);
|
|
389
|
+
} catch (error) {
|
|
390
|
+
console.error(`\nInstallation failed: ${error.message}`);
|
|
391
|
+
console.error(`\nTry installing manually. The downloaded file is at: ${artifactPath}`);
|
|
392
|
+
process.exit(1);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Clean up downloaded artifact
|
|
396
|
+
try {
|
|
397
|
+
fs.unlinkSync(artifactPath);
|
|
398
|
+
} catch {
|
|
399
|
+
// ignore cleanup errors
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Launch
|
|
403
|
+
launch(platformInfo, targetDir, dataDir);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
main().catch((error) => {
|
|
407
|
+
console.error(`Unexpected error: ${error.message}`);
|
|
408
|
+
process.exit(1);
|
|
409
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "kangentic",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Install and launch Kangentic -- visual agent orchestration for Claude Code",
|
|
5
|
+
"bin": {
|
|
6
|
+
"kangentic": "./bin/kangentic.js"
|
|
7
|
+
},
|
|
8
|
+
"repository": "https://github.com/Kangentic/kangentic",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"kangentic",
|
|
11
|
+
"kanban",
|
|
12
|
+
"claude",
|
|
13
|
+
"claude-code",
|
|
14
|
+
"agent",
|
|
15
|
+
"electron",
|
|
16
|
+
"desktop"
|
|
17
|
+
],
|
|
18
|
+
"author": {
|
|
19
|
+
"name": "Kangentic",
|
|
20
|
+
"url": "https://github.com/Kangentic"
|
|
21
|
+
},
|
|
22
|
+
"license": "AGPL-3.0-only",
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"bin/",
|
|
28
|
+
"LICENSE",
|
|
29
|
+
"README.md"
|
|
30
|
+
]
|
|
31
|
+
}
|