kandev 0.65.0 → 0.69.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 +2 -10
- package/bin/cli.js +3 -1
- package/bin/native-shim.js +94 -0
- package/package.json +14 -16
- package/dist/args.js +0 -123
- package/dist/backup.js +0 -98
- package/dist/bundle.js +0 -80
- package/dist/cli.js +0 -155
- package/dist/constants.js +0 -54
- package/dist/dev.js +0 -157
- package/dist/github.js +0 -221
- package/dist/health.js +0 -71
- package/dist/kandev-env.js +0 -28
- package/dist/platform.js +0 -53
- package/dist/ports.js +0 -142
- package/dist/process.js +0 -122
- package/dist/run.js +0 -283
- package/dist/runtime.js +0 -76
- package/dist/service/args.js +0 -131
- package/dist/service/config.js +0 -111
- package/dist/service/health_check.js +0 -84
- package/dist/service/index.js +0 -70
- package/dist/service/install_helpers.js +0 -51
- package/dist/service/launchctl.js +0 -73
- package/dist/service/linux.js +0 -165
- package/dist/service/macos.js +0 -221
- package/dist/service/metadata.js +0 -46
- package/dist/service/paths.js +0 -168
- package/dist/service/self_update.js +0 -223
- package/dist/service/stale_check.js +0 -78
- package/dist/service/templates.js +0 -229
- package/dist/shared.js +0 -214
- package/dist/start.js +0 -188
- package/dist/supervisor/backend.js +0 -83
- package/dist/supervisor/child.js +0 -64
- package/dist/supervisor/control.js +0 -97
- package/dist/supervisor/manifest.js +0 -74
- package/dist/supervisor/paths.js +0 -33
- package/dist/version.js +0 -57
- package/dist/web.js +0 -68
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ kandev
|
|
|
17
17
|
npx kandev@latest
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
Either install path resolves a platform-matched runtime (Go backend, agentctl,
|
|
20
|
+
Either install path resolves a platform-matched runtime (Go backend, agentctl, and static Vite web assets), launches the backend, and opens your browser. Data (worktrees, SQLite DB) is stored in `~/.kandev` by default.
|
|
21
21
|
|
|
22
22
|
## Version and Updates
|
|
23
23
|
|
|
@@ -27,14 +27,6 @@ The package manager owns the runtime version. `kandev@X.Y.Z` ships with the matc
|
|
|
27
27
|
- **Update via npm/npx**: `npx kandev@latest` or `npm install -g kandev@latest`
|
|
28
28
|
- **Print CLI version**: `kandev --version`
|
|
29
29
|
|
|
30
|
-
### Advanced: pin a specific runtime tag
|
|
31
|
-
|
|
32
|
-
`--runtime-version <tag>` downloads a specific GitHub release runtime instead of using the installed one. For debugging compatibility issues only:
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
kandev --runtime-version v0.16.0
|
|
36
|
-
```
|
|
37
|
-
|
|
38
30
|
## Run as a Service
|
|
39
31
|
|
|
40
32
|
Install kandev as a systemd (Linux) or launchd (macOS) service so it auto-starts and stays running across reboots:
|
|
@@ -71,7 +63,7 @@ See [docs/run-as-a-service.md](../../docs/run-as-a-service.md) for the full guid
|
|
|
71
63
|
|
|
72
64
|
## Requirements
|
|
73
65
|
|
|
74
|
-
- Node.js (for `npx`)
|
|
66
|
+
- Node.js (only for `npx` / npm-based installs and development tooling)
|
|
75
67
|
- Git
|
|
76
68
|
- Docker (optional - needed for container runtimes)
|
|
77
69
|
|
package/bin/cli.js
CHANGED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
const { spawnSync } = require("node:child_process");
|
|
6
|
+
|
|
7
|
+
const PLATFORM_PACKAGES = {
|
|
8
|
+
"linux-x64": "@kdlbs/runtime-linux-x64",
|
|
9
|
+
"linux-arm64": "@kdlbs/runtime-linux-arm64",
|
|
10
|
+
"darwin-x64": "@kdlbs/runtime-darwin-x64",
|
|
11
|
+
"darwin-arm64": "@kdlbs/runtime-darwin-arm64",
|
|
12
|
+
"win32-x64": "@kdlbs/runtime-win32-x64",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function platformPackage(platform = process.platform, arch = process.arch) {
|
|
16
|
+
const packageName = PLATFORM_PACKAGES[`${platform}-${arch}`];
|
|
17
|
+
if (!packageName) {
|
|
18
|
+
throw new Error(`Unsupported Kandev platform: ${platform}-${arch}`);
|
|
19
|
+
}
|
|
20
|
+
return packageName;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function binaryName(name, platform = process.platform) {
|
|
24
|
+
return platform === "win32" ? `${name}.exe` : name;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function resolveRuntime(env = process.env, resolver = require.resolve) {
|
|
28
|
+
if (env.KANDEV_BUNDLE_DIR) {
|
|
29
|
+
return validateRuntime(env.KANDEV_BUNDLE_DIR);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const packageName = platformPackage();
|
|
33
|
+
let packageJSON;
|
|
34
|
+
try {
|
|
35
|
+
packageJSON = resolver(`${packageName}/package.json`);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
const message =
|
|
38
|
+
`No Kandev runtime package found for ${process.platform}-${process.arch}.\n` +
|
|
39
|
+
`Install with npm 7+ so optional dependencies are installed, or use Homebrew.`;
|
|
40
|
+
const runtimeError = new Error(message);
|
|
41
|
+
runtimeError.cause = error;
|
|
42
|
+
throw runtimeError;
|
|
43
|
+
}
|
|
44
|
+
return validateRuntime(path.dirname(packageJSON));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function validateRuntime(bundleDir) {
|
|
48
|
+
const executable = path.join(bundleDir, "bin", binaryName("kandev"));
|
|
49
|
+
if (!fs.existsSync(executable)) {
|
|
50
|
+
throw new Error(`Kandev native binary not found at ${executable}`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const agentctl = path.join(bundleDir, "bin", binaryName("agentctl"));
|
|
54
|
+
if (!fs.existsSync(agentctl)) {
|
|
55
|
+
throw new Error(`agentctl binary not found at ${agentctl}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { bundleDir, executable };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function run(argv, env = process.env) {
|
|
62
|
+
let runtime;
|
|
63
|
+
try {
|
|
64
|
+
runtime = resolveRuntime(env);
|
|
65
|
+
} catch (error) {
|
|
66
|
+
console.error(`[kandev] ${error.message}`);
|
|
67
|
+
return 1;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const child = spawnSync(runtime.executable, argv, {
|
|
71
|
+
stdio: "inherit",
|
|
72
|
+
env: {
|
|
73
|
+
...env,
|
|
74
|
+
KANDEV_BUNDLE_DIR: runtime.bundleDir,
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (child.error) {
|
|
79
|
+
console.error(`[kandev] failed to launch native binary: ${child.error.message}`);
|
|
80
|
+
return 1;
|
|
81
|
+
}
|
|
82
|
+
if (child.signal) {
|
|
83
|
+
return 1;
|
|
84
|
+
}
|
|
85
|
+
return child.status === null ? 1 : child.status;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = {
|
|
89
|
+
binaryName,
|
|
90
|
+
platformPackage,
|
|
91
|
+
resolveRuntime,
|
|
92
|
+
run,
|
|
93
|
+
validateRuntime,
|
|
94
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kandev",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.69.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Launcher for Kandev — manage tasks, orchestrate agents, review changes, and ship value",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -13,37 +13,35 @@
|
|
|
13
13
|
"bin": {
|
|
14
14
|
"kandev": "bin/cli.js"
|
|
15
15
|
},
|
|
16
|
-
"main": "
|
|
16
|
+
"main": "bin/native-shim.js",
|
|
17
17
|
"files": [
|
|
18
|
-
"bin",
|
|
19
|
-
"
|
|
18
|
+
"bin/cli.js",
|
|
19
|
+
"bin/native-shim.js"
|
|
20
20
|
],
|
|
21
21
|
"engines": {
|
|
22
22
|
"npm": ">=7"
|
|
23
23
|
},
|
|
24
24
|
"optionalDependencies": {
|
|
25
|
-
"@kdlbs/runtime-linux-x64": "0.
|
|
26
|
-
"@kdlbs/runtime-linux-arm64": "0.
|
|
27
|
-
"@kdlbs/runtime-darwin-x64": "0.
|
|
28
|
-
"@kdlbs/runtime-darwin-arm64": "0.
|
|
29
|
-
"@kdlbs/runtime-win32-x64": "0.
|
|
30
|
-
},
|
|
31
|
-
"dependencies": {
|
|
32
|
-
"tar": "^7.5.11",
|
|
33
|
-
"tree-kill": "^1.2.2"
|
|
25
|
+
"@kdlbs/runtime-linux-x64": "0.69.0",
|
|
26
|
+
"@kdlbs/runtime-linux-arm64": "0.69.0",
|
|
27
|
+
"@kdlbs/runtime-darwin-x64": "0.69.0",
|
|
28
|
+
"@kdlbs/runtime-darwin-arm64": "0.69.0",
|
|
29
|
+
"@kdlbs/runtime-win32-x64": "0.69.0"
|
|
34
30
|
},
|
|
35
31
|
"devDependencies": {
|
|
36
32
|
"@types/node": "^20",
|
|
37
33
|
"esbuild": "^0.24.0",
|
|
34
|
+
"tar": "^7.5.11",
|
|
35
|
+
"tree-kill": "^1.2.2",
|
|
38
36
|
"tsx": "^4.15.7",
|
|
39
37
|
"typescript": "^5",
|
|
40
38
|
"vitest": "^1.6.0"
|
|
41
39
|
},
|
|
42
40
|
"scripts": {
|
|
43
41
|
"dev": "tsx src/cli.ts",
|
|
44
|
-
"build": "
|
|
45
|
-
"bundle": "
|
|
46
|
-
"start": "node
|
|
42
|
+
"build": "node -c bin/cli.js && node -c bin/native-shim.js",
|
|
43
|
+
"bundle": "pnpm build",
|
|
44
|
+
"start": "node bin/cli.js",
|
|
47
45
|
"test": "vitest run",
|
|
48
46
|
"prepublishOnly": "pnpm build"
|
|
49
47
|
}
|
package/dist/args.js
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ParseError = void 0;
|
|
4
|
-
exports.parseArgs = parseArgs;
|
|
5
|
-
exports.resolvePorts = resolvePorts;
|
|
6
|
-
class ParseError extends Error {
|
|
7
|
-
}
|
|
8
|
-
exports.ParseError = ParseError;
|
|
9
|
-
function parseArgs(argv) {
|
|
10
|
-
const opts = { command: "run" };
|
|
11
|
-
let showHelp = false;
|
|
12
|
-
const deprecatedFlags = [];
|
|
13
|
-
const noteDeprecated = (flag) => {
|
|
14
|
-
if (!deprecatedFlags.includes(flag))
|
|
15
|
-
deprecatedFlags.push(flag);
|
|
16
|
-
};
|
|
17
|
-
for (let i = 0; i < argv.length; i += 1) {
|
|
18
|
-
const arg = argv[i];
|
|
19
|
-
if (arg === "--help" || arg === "-h") {
|
|
20
|
-
showHelp = true;
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
if (arg === "--version" || arg === "-V") {
|
|
24
|
-
opts.showVersion = true;
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
if (arg === "dev" || arg === "run" || arg === "start") {
|
|
28
|
-
opts.command = arg;
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
|
-
if (arg === "--runtime-version") {
|
|
32
|
-
opts.runtimeVersion = takeValue(argv, i, "--runtime-version");
|
|
33
|
-
i += 1;
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
if (arg.startsWith("--runtime-version=")) {
|
|
37
|
-
const value = arg.slice("--runtime-version=".length);
|
|
38
|
-
if (value.length === 0)
|
|
39
|
-
throw new ParseError("--runtime-version requires a value");
|
|
40
|
-
opts.runtimeVersion = value;
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
if (arg === "--dev") {
|
|
44
|
-
opts.command = "dev";
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
// --port is an alias for --backend-port (the user-facing port in run/start).
|
|
48
|
-
if (arg === "--port" || arg === "--backend-port") {
|
|
49
|
-
opts.backendPort = parsePort(takeValue(argv, i, arg), arg);
|
|
50
|
-
i += 1;
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
if (arg.startsWith("--port=") || arg.startsWith("--backend-port=")) {
|
|
54
|
-
const flag = arg.startsWith("--port=") ? "--port" : "--backend-port";
|
|
55
|
-
opts.backendPort = parsePort(arg.slice(flag.length + 1), flag);
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
if (arg === "--web-internal-port") {
|
|
59
|
-
opts.webPort = parsePort(takeValue(argv, i, "--web-internal-port"), "--web-internal-port");
|
|
60
|
-
i += 1;
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
if (arg.startsWith("--web-internal-port=")) {
|
|
64
|
-
opts.webPort = parsePort(arg.slice("--web-internal-port=".length), "--web-internal-port");
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
if (arg === "--web-port") {
|
|
68
|
-
opts.webPort = parsePort(takeValue(argv, i, "--web-port"), "--web-port");
|
|
69
|
-
noteDeprecated("--web-port");
|
|
70
|
-
i += 1;
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
if (arg.startsWith("--web-port=")) {
|
|
74
|
-
opts.webPort = parsePort(arg.slice("--web-port=".length), "--web-port");
|
|
75
|
-
noteDeprecated("--web-port");
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
if (arg === "--verbose" || arg === "-v") {
|
|
79
|
-
opts.verbose = true;
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
if (arg === "--debug") {
|
|
83
|
-
opts.debug = true;
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
if (arg === "--headless" || arg === "--no-browser") {
|
|
87
|
-
opts.headless = true;
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return { options: opts, showHelp, deprecatedFlags };
|
|
92
|
-
}
|
|
93
|
-
function takeValue(argv, i, flag) {
|
|
94
|
-
const v = argv[i + 1];
|
|
95
|
-
if (v === undefined || v.startsWith("-")) {
|
|
96
|
-
throw new ParseError(`${flag} requires a value`);
|
|
97
|
-
}
|
|
98
|
-
return v;
|
|
99
|
-
}
|
|
100
|
-
function parsePort(raw, flag) {
|
|
101
|
-
const n = Number(raw);
|
|
102
|
-
if (raw === "" || !Number.isInteger(n) || n < 1 || n > 65535) {
|
|
103
|
-
throw new ParseError(`${flag} value must be an integer between 1 and 65535, got "${raw}"`);
|
|
104
|
-
}
|
|
105
|
-
return n;
|
|
106
|
-
}
|
|
107
|
-
// CLI flags beat env vars; KANDEV_PORT is an alias for KANDEV_BACKEND_PORT.
|
|
108
|
-
function resolvePorts(options, env) {
|
|
109
|
-
return {
|
|
110
|
-
backendPort: options.backendPort ?? envPort(env, "KANDEV_BACKEND_PORT") ?? envPort(env, "KANDEV_PORT"),
|
|
111
|
-
webPort: options.webPort ?? envPort(env, "KANDEV_WEB_PORT"),
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
function envPort(env, name) {
|
|
115
|
-
const val = env[name];
|
|
116
|
-
if (val === undefined)
|
|
117
|
-
return undefined;
|
|
118
|
-
const n = Number(val);
|
|
119
|
-
if (val === "" || !Number.isInteger(n) || n < 1 || n > 65535) {
|
|
120
|
-
throw new ParseError(`${name} must be an integer between 1 and 65535, got "${val}"`);
|
|
121
|
-
}
|
|
122
|
-
return n;
|
|
123
|
-
}
|
package/dist/backup.js
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.isProductionDb = isProductionDb;
|
|
7
|
-
exports.backupProductionDb = backupProductionDb;
|
|
8
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
-
const node_os_1 = __importDefault(require("node:os"));
|
|
10
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
-
// Prefix for dev-prod-db automatic snapshots. Distinct from the backend's
|
|
12
|
-
// "kandev-*" auto-snapshots and "manual-*" user snapshots so the families
|
|
13
|
-
// don't interfere with each other's retention policies.
|
|
14
|
-
const BACKUP_PREFIX = "dev-prod-db-";
|
|
15
|
-
const BACKUP_SUFFIX = ".db";
|
|
16
|
-
const MAX_BACKUPS = 5;
|
|
17
|
-
/**
|
|
18
|
-
* Returns true if the given dbPath points to a non-dev database that should
|
|
19
|
-
* be backed up before running dev mode. Dev-isolated databases live under
|
|
20
|
-
* <repo>/.kandev-dev/ and are considered disposable.
|
|
21
|
-
*/
|
|
22
|
-
function isProductionDb(dbPath) {
|
|
23
|
-
const normalized = node_path_1.default.normalize(dbPath);
|
|
24
|
-
const segments = normalized.split(node_path_1.default.sep).filter(Boolean);
|
|
25
|
-
return !segments.includes(".kandev-dev");
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Backs up the database at dbPath to <data-dir>/backups/ before dev mode
|
|
29
|
-
* runs against it. Keeps only the newest MAX_BACKUPS snapshots.
|
|
30
|
-
*
|
|
31
|
-
* Returns the path of the created backup, or null if the DB didn't exist
|
|
32
|
-
* or no backup was needed.
|
|
33
|
-
*
|
|
34
|
-
* The optional `homeDir` parameter is exposed for tests so they can redirect
|
|
35
|
-
* the backup location without mocking os.homedir(). The optional `now`
|
|
36
|
-
* parameter lets tests pass an explicit timestamp so back-to-back calls in
|
|
37
|
-
* the same millisecond produce distinct filenames + mtimes without sleeping.
|
|
38
|
-
*/
|
|
39
|
-
function backupProductionDb(dbPath, homeDir, now) {
|
|
40
|
-
if (!node_fs_1.default.existsSync(dbPath)) {
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
const root = homeDir ?? node_os_1.default.homedir();
|
|
44
|
-
// Backups are always placed under ~/.kandev/data/backups/ (or the
|
|
45
|
-
// caller-supplied homeDir in tests), even when dbPath points elsewhere.
|
|
46
|
-
// This matches the dev-prod-db default flow; custom KANDEV_DATABASE_PATH
|
|
47
|
-
// values are advanced usage where the user is responsible for backup location.
|
|
48
|
-
const dataDir = node_path_1.default.join(root, ".kandev", "data");
|
|
49
|
-
const backupDir = node_path_1.default.join(dataDir, "backups");
|
|
50
|
-
node_fs_1.default.mkdirSync(backupDir, { recursive: true });
|
|
51
|
-
const stamp = now ?? new Date();
|
|
52
|
-
const ts = stamp.toISOString().replace(/[:.]/g, "");
|
|
53
|
-
const name = `${BACKUP_PREFIX}${ts}${BACKUP_SUFFIX}`;
|
|
54
|
-
const dest = node_path_1.default.join(backupDir, name);
|
|
55
|
-
node_fs_1.default.copyFileSync(dbPath, dest);
|
|
56
|
-
// Stamp both atime + mtime so pruning (which sorts by mtime) is deterministic.
|
|
57
|
-
node_fs_1.default.utimesSync(dest, stamp, stamp);
|
|
58
|
-
pruneBackups(backupDir, MAX_BACKUPS);
|
|
59
|
-
return dest;
|
|
60
|
-
}
|
|
61
|
-
/**
|
|
62
|
-
* Keeps only the `keep` newest dev-prod-db backup files in `dir`, deleting
|
|
63
|
-
* older ones. Non-matching files are left untouched.
|
|
64
|
-
*/
|
|
65
|
-
function pruneBackups(dir, keep) {
|
|
66
|
-
let entries;
|
|
67
|
-
try {
|
|
68
|
-
entries = node_fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
69
|
-
}
|
|
70
|
-
catch {
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
const files = entries
|
|
74
|
-
.filter((e) => e.isFile() && e.name.startsWith(BACKUP_PREFIX) && e.name.endsWith(BACKUP_SUFFIX))
|
|
75
|
-
.map((e) => {
|
|
76
|
-
const fullPath = node_path_1.default.join(dir, e.name);
|
|
77
|
-
try {
|
|
78
|
-
const stat = node_fs_1.default.statSync(fullPath);
|
|
79
|
-
return { path: fullPath, mtime: stat.mtime };
|
|
80
|
-
}
|
|
81
|
-
catch {
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
})
|
|
85
|
-
.filter((f) => f !== null);
|
|
86
|
-
if (files.length <= keep) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
files.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
|
|
90
|
-
for (const f of files.slice(keep)) {
|
|
91
|
-
try {
|
|
92
|
-
node_fs_1.default.unlinkSync(f.path);
|
|
93
|
-
}
|
|
94
|
-
catch {
|
|
95
|
-
// Non-critical: don't fail the launch if one old backup can't be removed.
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
package/dist/bundle.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.extractTarGz = extractTarGz;
|
|
40
|
-
exports.ensureExtracted = ensureExtracted;
|
|
41
|
-
exports.findBundleRoot = findBundleRoot;
|
|
42
|
-
exports.resolveWebServerPath = resolveWebServerPath;
|
|
43
|
-
const tar = __importStar(require("tar"));
|
|
44
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
45
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
46
|
-
function extractTarGz(archivePath, destDir) {
|
|
47
|
-
tar.extract({ file: archivePath, cwd: destDir, sync: true });
|
|
48
|
-
}
|
|
49
|
-
function ensureExtracted(archivePath, destDir) {
|
|
50
|
-
const marker = node_path_1.default.join(destDir, ".extracted");
|
|
51
|
-
if (node_fs_1.default.existsSync(marker)) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
extractTarGz(archivePath, destDir);
|
|
55
|
-
node_fs_1.default.writeFileSync(marker, "");
|
|
56
|
-
}
|
|
57
|
-
function findBundleRoot(cacheDir) {
|
|
58
|
-
const candidate = node_path_1.default.join(cacheDir, "kandev");
|
|
59
|
-
if (node_fs_1.default.existsSync(candidate)) {
|
|
60
|
-
return candidate;
|
|
61
|
-
}
|
|
62
|
-
return cacheDir;
|
|
63
|
-
}
|
|
64
|
-
function resolveWebServerPath(bundleDir) {
|
|
65
|
-
// Next.js standalone output location depends on workspace structure:
|
|
66
|
-
// - non-monorepo: web/server.js
|
|
67
|
-
// - monorepo (apps/ root): web/web/server.js
|
|
68
|
-
// - monorepo (project root): web/apps/web/server.js
|
|
69
|
-
const candidates = [
|
|
70
|
-
node_path_1.default.join(bundleDir, "web", "server.js"),
|
|
71
|
-
node_path_1.default.join(bundleDir, "web", "web", "server.js"),
|
|
72
|
-
node_path_1.default.join(bundleDir, "web", "apps", "web", "server.js"),
|
|
73
|
-
];
|
|
74
|
-
for (const candidate of candidates) {
|
|
75
|
-
if (node_fs_1.default.existsSync(candidate)) {
|
|
76
|
-
return candidate;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return null;
|
|
80
|
-
}
|
package/dist/cli.js
DELETED
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
7
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
-
const package_json_1 = __importDefault(require("../package.json"));
|
|
9
|
-
const args_1 = require("./args");
|
|
10
|
-
const dev_1 = require("./dev");
|
|
11
|
-
const run_1 = require("./run");
|
|
12
|
-
const service_1 = require("./service");
|
|
13
|
-
const stale_check_1 = require("./service/stale_check");
|
|
14
|
-
const start_1 = require("./start");
|
|
15
|
-
const ports_1 = require("./ports");
|
|
16
|
-
function printHelp() {
|
|
17
|
-
console.log(`kandev launcher
|
|
18
|
-
|
|
19
|
-
Usage:
|
|
20
|
-
kandev run [--port <port>] [--verbose] [--debug]
|
|
21
|
-
kandev dev [--port <port>]
|
|
22
|
-
kandev start [--port <port>] [--verbose] [--debug]
|
|
23
|
-
kandev [--port <port>] [--verbose] [--debug]
|
|
24
|
-
kandev --dev [--port <port>]
|
|
25
|
-
kandev service install|uninstall|start|stop|restart|status|logs [--system]
|
|
26
|
-
|
|
27
|
-
Examples:
|
|
28
|
-
kandev
|
|
29
|
-
kandev run
|
|
30
|
-
kandev --dev
|
|
31
|
-
kandev dev
|
|
32
|
-
kandev start
|
|
33
|
-
kandev --version
|
|
34
|
-
kandev --port 3000
|
|
35
|
-
kandev --debug
|
|
36
|
-
|
|
37
|
-
Options:
|
|
38
|
-
dev Use local repo for dev (make dev + next dev) if available.
|
|
39
|
-
start Use local production build (make build + next start).
|
|
40
|
-
run Use installed runtime bundle (default).
|
|
41
|
-
service Manage kandev as an OS service (systemd / launchd).
|
|
42
|
-
Run 'kandev service --help' for details.
|
|
43
|
-
--dev Alias for "dev".
|
|
44
|
-
--version, -V Print CLI version and exit.
|
|
45
|
-
--port Port for the Go backend (the URL kandev opens on in
|
|
46
|
-
start/run). Alias for --backend-port. Also reads
|
|
47
|
-
KANDEV_PORT or KANDEV_BACKEND_PORT.
|
|
48
|
-
--verbose, -v Show info logs from backend + web.
|
|
49
|
-
--debug Show debug logs + agent message dumps.
|
|
50
|
-
--headless Skip opening the browser. Used by service units.
|
|
51
|
-
--help, -h Show help.
|
|
52
|
-
|
|
53
|
-
Advanced:
|
|
54
|
-
--backend-port Same as --port.
|
|
55
|
-
--web-internal-port Override the internal Next.js port. The Go backend
|
|
56
|
-
reverse-proxies to it; users hit the backend port.
|
|
57
|
-
Also reads KANDEV_WEB_PORT.
|
|
58
|
-
--web-port Deprecated alias for --web-internal-port.
|
|
59
|
-
--runtime-version <tag> Download and use a specific release tag instead of
|
|
60
|
-
the installed runtime. For debugging only.
|
|
61
|
-
Example: kandev --runtime-version v0.16.0
|
|
62
|
-
`);
|
|
63
|
-
}
|
|
64
|
-
function findRepoRoot(startDir) {
|
|
65
|
-
let current = node_path_1.default.resolve(startDir);
|
|
66
|
-
while (true) {
|
|
67
|
-
if (current.endsWith(`${node_path_1.default.sep}apps`)) {
|
|
68
|
-
const backendInApps = node_path_1.default.join(current, "backend");
|
|
69
|
-
const webInApps = node_path_1.default.join(current, "web");
|
|
70
|
-
if (node_fs_1.default.existsSync(backendInApps) && node_fs_1.default.existsSync(webInApps)) {
|
|
71
|
-
return node_path_1.default.dirname(current);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
const backendDir = node_path_1.default.join(current, "apps", "backend");
|
|
75
|
-
const webDir = node_path_1.default.join(current, "apps", "web");
|
|
76
|
-
if (node_fs_1.default.existsSync(backendDir) && node_fs_1.default.existsSync(webDir)) {
|
|
77
|
-
return current;
|
|
78
|
-
}
|
|
79
|
-
const parent = node_path_1.default.dirname(current);
|
|
80
|
-
if (parent === current) {
|
|
81
|
-
return null;
|
|
82
|
-
}
|
|
83
|
-
current = parent;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
async function main() {
|
|
87
|
-
// The `service` subcommand has its own argv parser (own subcommands, flags).
|
|
88
|
-
// Handle it before the top-level flag parser to keep the two parsers isolated.
|
|
89
|
-
if (process.argv[2] === "service") {
|
|
90
|
-
await (0, service_1.runServiceCommand)(process.argv.slice(3));
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
const { options, showHelp, deprecatedFlags } = (0, args_1.parseArgs)(process.argv.slice(2));
|
|
94
|
-
if (options.showVersion) {
|
|
95
|
-
console.log(package_json_1.default.version);
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
if (showHelp) {
|
|
99
|
-
printHelp();
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
for (const flag of deprecatedFlags) {
|
|
103
|
-
process.stderr.write(`[kandev] ${flag} is deprecated; use --web-internal-port\n`);
|
|
104
|
-
}
|
|
105
|
-
const resolved = (0, args_1.resolvePorts)(options, process.env);
|
|
106
|
-
const backendPort = (0, ports_1.ensureValidPort)(resolved.backendPort, "backend port");
|
|
107
|
-
const webPort = (0, ports_1.ensureValidPort)(resolved.webPort, "web port");
|
|
108
|
-
// After an npm/brew upgrade, paths baked into an installed service unit may
|
|
109
|
-
// be stale. Warn once before launch so the user knows to re-run install.
|
|
110
|
-
// Skip when invoked from a service unit (--headless) — the warning would
|
|
111
|
-
// land in journalctl/launchd logs and pile up on every restart.
|
|
112
|
-
if (!options.headless) {
|
|
113
|
-
(0, stale_check_1.warnIfStaleServiceUnit)();
|
|
114
|
-
}
|
|
115
|
-
if (options.command === "dev") {
|
|
116
|
-
const repoRoot = findRepoRoot(process.cwd());
|
|
117
|
-
if (!repoRoot) {
|
|
118
|
-
throw new Error("Unable to locate repo root for dev. Run from the repo.");
|
|
119
|
-
}
|
|
120
|
-
await (0, dev_1.runDev)({ repoRoot, backendPort, webPort });
|
|
121
|
-
return;
|
|
122
|
-
}
|
|
123
|
-
if (options.command === "start") {
|
|
124
|
-
const repoRoot = findRepoRoot(process.cwd());
|
|
125
|
-
if (!repoRoot) {
|
|
126
|
-
throw new Error("Unable to locate repo root for start. Run from the repo.");
|
|
127
|
-
}
|
|
128
|
-
await (0, start_1.runStart)({
|
|
129
|
-
repoRoot,
|
|
130
|
-
backendPort,
|
|
131
|
-
webPort,
|
|
132
|
-
verbose: options.verbose,
|
|
133
|
-
debug: options.debug,
|
|
134
|
-
headless: options.headless,
|
|
135
|
-
});
|
|
136
|
-
return;
|
|
137
|
-
}
|
|
138
|
-
await (0, run_1.runRelease)({
|
|
139
|
-
runtimeVersion: options.runtimeVersion,
|
|
140
|
-
backendPort,
|
|
141
|
-
webPort,
|
|
142
|
-
verbose: options.verbose,
|
|
143
|
-
debug: options.debug,
|
|
144
|
-
headless: options.headless,
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
main().catch((err) => {
|
|
148
|
-
if (err instanceof args_1.ParseError) {
|
|
149
|
-
console.error(`[kandev] ${err.message}`);
|
|
150
|
-
console.error("[kandev] run --help for usage");
|
|
151
|
-
process.exit(2);
|
|
152
|
-
}
|
|
153
|
-
console.error(`[kandev] ${err instanceof Error ? err.message : String(err)}`);
|
|
154
|
-
process.exit(1);
|
|
155
|
-
});
|