kandev 0.14.0 → 0.16.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/dist/constants.js +22 -6
- package/dist/dev.js +48 -6
- package/dist/kandev-env.js +28 -0
- package/dist/start.js +55 -3
- package/package.json +2 -2
package/dist/constants.js
CHANGED
|
@@ -3,14 +3,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.DATA_DIR = exports.CACHE_DIR = exports.HEALTH_TIMEOUT_MS_DEV = exports.HEALTH_TIMEOUT_MS_RELEASE = exports.RANDOM_PORT_RETRIES = exports.RANDOM_PORT_MAX = exports.RANDOM_PORT_MIN = exports.DEFAULT_MCP_PORT = exports.DEFAULT_AGENTCTL_PORT = exports.DEFAULT_WEB_PORT = exports.DEFAULT_BACKEND_PORT = void 0;
|
|
6
|
+
exports.DEV_KANDEV_DOTDIR = exports.DATA_DIR = exports.CACHE_DIR = exports.KANDEV_TASKS_DIR = exports.KANDEV_HOME_DIR = exports.KANDEV_DOTDIR = exports.HEALTH_TIMEOUT_MS_DEV = exports.HEALTH_TIMEOUT_MS_RELEASE = exports.RANDOM_PORT_RETRIES = exports.RANDOM_PORT_MAX = exports.RANDOM_PORT_MIN = exports.DEFAULT_MCP_PORT = exports.DEFAULT_AGENTCTL_PORT = exports.DEFAULT_WEB_PORT = exports.DEFAULT_BACKEND_PORT = void 0;
|
|
7
|
+
exports.devKandevHome = devKandevHome;
|
|
7
8
|
const node_os_1 = __importDefault(require("node:os"));
|
|
8
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
10
|
// Default service ports (will auto-fallback if busy).
|
|
10
|
-
|
|
11
|
+
// Clustered near the web port (37429) to avoid collisions with commonly used
|
|
12
|
+
// ports (8080, 9090, 9999, etc.) while keeping the numbers memorable.
|
|
13
|
+
exports.DEFAULT_BACKEND_PORT = 38429;
|
|
11
14
|
exports.DEFAULT_WEB_PORT = 37429;
|
|
12
|
-
exports.DEFAULT_AGENTCTL_PORT =
|
|
13
|
-
exports.DEFAULT_MCP_PORT =
|
|
15
|
+
exports.DEFAULT_AGENTCTL_PORT = 39429;
|
|
16
|
+
exports.DEFAULT_MCP_PORT = 40429;
|
|
14
17
|
// Random fallback range for port selection.
|
|
15
18
|
exports.RANDOM_PORT_MIN = 10000;
|
|
16
19
|
exports.RANDOM_PORT_MAX = 60000;
|
|
@@ -18,6 +21,19 @@ exports.RANDOM_PORT_RETRIES = 10;
|
|
|
18
21
|
// Backend healthcheck timeout during startup.
|
|
19
22
|
exports.HEALTH_TIMEOUT_MS_RELEASE = 45000;
|
|
20
23
|
exports.HEALTH_TIMEOUT_MS_DEV = 600000;
|
|
24
|
+
// Kandev root directory. Single source of truth for the dotdir name and
|
|
25
|
+
// everything derived from it (data, tasks, bin). Dev mode uses a separate
|
|
26
|
+
// root under the repo (see DEV_KANDEV_DOTDIR).
|
|
27
|
+
exports.KANDEV_DOTDIR = ".kandev";
|
|
28
|
+
exports.KANDEV_HOME_DIR = node_path_1.default.join(node_os_1.default.homedir(), exports.KANDEV_DOTDIR);
|
|
29
|
+
exports.KANDEV_TASKS_DIR = node_path_1.default.join(exports.KANDEV_HOME_DIR, "tasks");
|
|
21
30
|
// Local user cache/data directories for release bundles and DB.
|
|
22
|
-
exports.CACHE_DIR = node_path_1.default.join(
|
|
23
|
-
exports.DATA_DIR = node_path_1.default.join(
|
|
31
|
+
exports.CACHE_DIR = node_path_1.default.join(exports.KANDEV_HOME_DIR, "bin");
|
|
32
|
+
exports.DATA_DIR = node_path_1.default.join(exports.KANDEV_HOME_DIR, "data");
|
|
33
|
+
// Dev-mode root: an isolated kandev home inside the repo so that running
|
|
34
|
+
// `make dev` from inside a kandev-spawned task workspace does not touch the
|
|
35
|
+
// user's production state.
|
|
36
|
+
exports.DEV_KANDEV_DOTDIR = ".kandev-dev";
|
|
37
|
+
function devKandevHome(repoRoot) {
|
|
38
|
+
return node_path_1.default.join(repoRoot, exports.DEV_KANDEV_DOTDIR);
|
|
39
|
+
}
|
package/dist/dev.js
CHANGED
|
@@ -4,21 +4,18 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.runDev = runDev;
|
|
7
|
+
exports.resolveDevBackendEnv = resolveDevBackendEnv;
|
|
7
8
|
const node_child_process_1 = require("node:child_process");
|
|
8
9
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
10
|
const constants_1 = require("./constants");
|
|
10
11
|
const health_1 = require("./health");
|
|
12
|
+
const kandev_env_1 = require("./kandev-env");
|
|
11
13
|
const process_1 = require("./process");
|
|
12
14
|
const shared_1 = require("./shared");
|
|
13
15
|
const web_1 = require("./web");
|
|
14
16
|
async function runDev({ repoRoot, backendPort, webPort }) {
|
|
15
17
|
const ports = await (0, shared_1.pickPorts)(backendPort, webPort);
|
|
16
|
-
const dbPath
|
|
17
|
-
const extra = {
|
|
18
|
-
KANDEV_DATABASE_PATH: dbPath,
|
|
19
|
-
KANDEV_MOCK_AGENT: process.env.KANDEV_MOCK_AGENT || "true",
|
|
20
|
-
KANDEV_DEBUG_PPROF_ENABLED: "true",
|
|
21
|
-
};
|
|
18
|
+
const { dbPath, extra } = resolveDevBackendEnv(repoRoot);
|
|
22
19
|
const backendEnv = (0, shared_1.buildBackendEnv)({ ports, extra });
|
|
23
20
|
const webEnv = (0, shared_1.buildWebEnv)({ ports, debug: true });
|
|
24
21
|
const logLevel = process.env.KANDEV_LOGGING_LEVEL?.trim() || process.env.KANDEV_LOG_LEVEL?.trim() || "info";
|
|
@@ -55,3 +52,48 @@ async function runDev({ repoRoot, backendPort, webPort }) {
|
|
|
55
52
|
console.log(`[kandev] web ready at ${webUrl}`);
|
|
56
53
|
(0, web_1.openBrowser)(webUrl);
|
|
57
54
|
}
|
|
55
|
+
// Computes the dev-mode backend env. Dev mode always roots kandev under
|
|
56
|
+
// <repo>/.kandev-dev so state is isolated from the user's production ~/.kandev
|
|
57
|
+
// and so `make clean-db` (which removes .kandev-dev/) matches what `make dev`
|
|
58
|
+
// writes.
|
|
59
|
+
//
|
|
60
|
+
// When invoked from inside a kandev task workspace, any KANDEV_DATABASE_PATH
|
|
61
|
+
// is assumed to be leaked from the parent backend and is ignored. In a normal
|
|
62
|
+
// shell, an explicit KANDEV_DATABASE_PATH is honored as an escape hatch.
|
|
63
|
+
function resolveDevBackendEnv(repoRoot) {
|
|
64
|
+
const baseExtra = {
|
|
65
|
+
KANDEV_MOCK_AGENT: process.env.KANDEV_MOCK_AGENT || "true",
|
|
66
|
+
KANDEV_DEBUG_PPROF_ENABLED: "true",
|
|
67
|
+
};
|
|
68
|
+
const devHome = (0, constants_1.devKandevHome)(repoRoot);
|
|
69
|
+
// Display only; the backend derives its own DB path from KANDEV_HOME_DIR
|
|
70
|
+
// via ResolvedDataDir(). Both resolve to the same location.
|
|
71
|
+
const devDbPath = node_path_1.default.join(devHome, "data", "kandev.db");
|
|
72
|
+
if ((0, kandev_env_1.isInsideKandevTask)(repoRoot)) {
|
|
73
|
+
console.log("[kandev] task workspace detected → using local dev state");
|
|
74
|
+
return {
|
|
75
|
+
dbPath: devDbPath,
|
|
76
|
+
extra: {
|
|
77
|
+
...baseExtra,
|
|
78
|
+
KANDEV_HOME_DIR: devHome,
|
|
79
|
+
// Clear a parent-leaked DB path so the backend uses the HomeDir-derived default.
|
|
80
|
+
KANDEV_DATABASE_PATH: "",
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const override = process.env.KANDEV_DATABASE_PATH;
|
|
85
|
+
if (override) {
|
|
86
|
+
return {
|
|
87
|
+
dbPath: override,
|
|
88
|
+
extra: { ...baseExtra, KANDEV_DATABASE_PATH: override },
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
dbPath: devDbPath,
|
|
93
|
+
extra: {
|
|
94
|
+
...baseExtra,
|
|
95
|
+
KANDEV_HOME_DIR: devHome,
|
|
96
|
+
KANDEV_DATABASE_PATH: "",
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
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.isInsideKandevTask = isInsideKandevTask;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const constants_1 = require("./constants");
|
|
9
|
+
/**
|
|
10
|
+
* Returns true when the current process looks like it was spawned inside a
|
|
11
|
+
* kandev-created task workspace. Two signals:
|
|
12
|
+
* 1. The parent kandev backend exports KANDEV_TASK_ID into every task shell.
|
|
13
|
+
* 2. Task worktrees live under ~/.kandev/tasks/ (see KANDEV_TASKS_DIR).
|
|
14
|
+
*
|
|
15
|
+
* Used by dev mode to auto-isolate the backend onto a local dev root so that
|
|
16
|
+
* `make dev` never mutates the user's production state.
|
|
17
|
+
*
|
|
18
|
+
* Note: the path-prefix fallback is a defensive secondary signal for nested
|
|
19
|
+
* shells where KANDEV_TASK_ID was stripped. It is case-sensitive and does not
|
|
20
|
+
* resolve symlinks, so a realpath'd repoRoot may miss a symlinked HOME on
|
|
21
|
+
* macOS / Windows. KANDEV_TASK_ID remains the primary guarantee.
|
|
22
|
+
*/
|
|
23
|
+
function isInsideKandevTask(repoRoot) {
|
|
24
|
+
if (process.env.KANDEV_TASK_ID) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
return repoRoot.startsWith(constants_1.KANDEV_TASKS_DIR + node_path_1.default.sep);
|
|
28
|
+
}
|
package/dist/start.js
CHANGED
|
@@ -15,6 +15,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
15
15
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
16
16
|
};
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.resolveStandaloneServerPath = resolveStandaloneServerPath;
|
|
18
19
|
exports.runStart = runStart;
|
|
19
20
|
const node_child_process_1 = require("node:child_process");
|
|
20
21
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
@@ -25,6 +26,50 @@ const platform_1 = require("./platform");
|
|
|
25
26
|
const process_1 = require("./process");
|
|
26
27
|
const shared_1 = require("./shared");
|
|
27
28
|
const web_1 = require("./web");
|
|
29
|
+
/**
|
|
30
|
+
* Locates the standalone Next.js `server.js` inside `apps/web/.next/standalone/`.
|
|
31
|
+
*
|
|
32
|
+
* Normally this sits at `.next/standalone/web/server.js`, but Turbopack may
|
|
33
|
+
* place it under a deeper path (e.g. `.next/standalone/Users/.../web/server.js`)
|
|
34
|
+
* when it detects the wrong project root (typically caused by a stray
|
|
35
|
+
* `package-lock.json` in a parent directory). We look for any `web/server.js`
|
|
36
|
+
* below the standalone directory so `kandev start` keeps working.
|
|
37
|
+
*
|
|
38
|
+
* @returns absolute path to `server.js`, or null if it cannot be found.
|
|
39
|
+
*/
|
|
40
|
+
function resolveStandaloneServerPath(repoRoot) {
|
|
41
|
+
const standaloneDir = node_path_1.default.join(repoRoot, "apps", "web", ".next", "standalone");
|
|
42
|
+
const expected = node_path_1.default.join(standaloneDir, "web", "server.js");
|
|
43
|
+
if (node_fs_1.default.existsSync(expected))
|
|
44
|
+
return expected;
|
|
45
|
+
if (!node_fs_1.default.existsSync(standaloneDir))
|
|
46
|
+
return null;
|
|
47
|
+
return findWebServerJs(standaloneDir);
|
|
48
|
+
}
|
|
49
|
+
// Walks `dir` manually instead of relying on `Dirent.parentPath` (Node 20.12+),
|
|
50
|
+
// so the CLI keeps working on older Node 20.x runtimes installed via npx.
|
|
51
|
+
function findWebServerJs(dir) {
|
|
52
|
+
const stack = [dir];
|
|
53
|
+
while (stack.length > 0) {
|
|
54
|
+
const current = stack.pop();
|
|
55
|
+
let entries;
|
|
56
|
+
try {
|
|
57
|
+
entries = node_fs_1.default.readdirSync(current, { withFileTypes: true });
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
for (const entry of entries) {
|
|
63
|
+
if (entry.isDirectory() && entry.name !== "node_modules") {
|
|
64
|
+
stack.push(node_path_1.default.join(current, entry.name));
|
|
65
|
+
}
|
|
66
|
+
else if (entry.isFile() && entry.name === "server.js" && node_path_1.default.basename(current) === "web") {
|
|
67
|
+
return node_path_1.default.join(current, entry.name);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
28
73
|
/**
|
|
29
74
|
* Runs the application in production mode using local builds.
|
|
30
75
|
*
|
|
@@ -45,9 +90,16 @@ async function runStart({ repoRoot, backendPort, webPort, verbose = false, debug
|
|
|
45
90
|
throw new Error("Backend binary not found. Run `make build` first.");
|
|
46
91
|
}
|
|
47
92
|
// Check for standalone build (Next.js standalone output)
|
|
48
|
-
const webServerPath =
|
|
49
|
-
if (!
|
|
50
|
-
|
|
93
|
+
const webServerPath = resolveStandaloneServerPath(repoRoot);
|
|
94
|
+
if (!webServerPath) {
|
|
95
|
+
const standaloneDir = node_path_1.default.join(repoRoot, "apps", "web", ".next", "standalone");
|
|
96
|
+
if (!node_fs_1.default.existsSync(standaloneDir)) {
|
|
97
|
+
throw new Error("Web standalone build not found. Run `make build` first.");
|
|
98
|
+
}
|
|
99
|
+
throw new Error(`Web standalone build is missing server.js under ${standaloneDir}. ` +
|
|
100
|
+
"This can happen when Next.js/Turbopack detects a different project root " +
|
|
101
|
+
"(e.g. a stray package-lock.json in a parent directory). " +
|
|
102
|
+
"Remove the stray lockfile and re-run `make build`.");
|
|
51
103
|
}
|
|
52
104
|
const webStandaloneDir = node_path_1.default.dirname(webServerPath);
|
|
53
105
|
const webStaticDir = node_path_1.default.join(repoRoot, "apps", "web", ".next", "static");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kandev",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "NPX launcher for Kandev",
|
|
6
6
|
"license": "AGPL-3.0-only",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"vitest": "^1.6.0"
|
|
25
25
|
},
|
|
26
26
|
"scripts": {
|
|
27
|
-
"dev": "tsx src/cli.ts",
|
|
27
|
+
"dev": "unset npm_config_prefix && tsx src/cli.ts",
|
|
28
28
|
"build": "tsc -p tsconfig.json",
|
|
29
29
|
"start": "node dist/cli.js",
|
|
30
30
|
"test": "vitest run",
|