kandev 0.59.0 → 0.61.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/cli.js CHANGED
@@ -131,6 +131,7 @@ async function main() {
131
131
  webPort,
132
132
  verbose: options.verbose,
133
133
  debug: options.debug,
134
+ headless: options.headless,
134
135
  });
135
136
  return;
136
137
  }
package/dist/dev.js CHANGED
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.runDev = runDev;
7
7
  exports.resolveDevBackendEnv = resolveDevBackendEnv;
8
- const node_child_process_1 = require("node:child_process");
9
8
  const node_fs_1 = __importDefault(require("node:fs"));
10
9
  const node_path_1 = __importDefault(require("node:path"));
11
10
  const backup_1 = require("./backup");
@@ -14,6 +13,7 @@ const health_1 = require("./health");
14
13
  const kandev_env_1 = require("./kandev-env");
15
14
  const process_1 = require("./process");
16
15
  const shared_1 = require("./shared");
16
+ const backend_1 = require("./supervisor/backend");
17
17
  const web_1 = require("./web");
18
18
  async function runDev({ repoRoot, backendPort, webPort }) {
19
19
  const ports = await (0, shared_1.pickPorts)(backendPort, webPort);
@@ -52,16 +52,20 @@ async function runDev({ repoRoot, backendPort, webPort }) {
52
52
  node_path_1.default.join("apps", "backend"),
53
53
  "dev",
54
54
  ]);
55
- const backendProc = (0, node_child_process_1.spawn)(backendCmd, backendArgs, {
55
+ const backend = await (0, backend_1.launchRestartableBackend)({
56
+ command: backendCmd,
57
+ args: backendArgs,
56
58
  cwd: repoRoot,
57
59
  env: backendEnv,
60
+ homeDir: backendEnv.KANDEV_HOME_DIR ?? (0, constants_1.devKandevHome)(repoRoot),
61
+ ports,
62
+ mode: "dev",
58
63
  stdio: "inherit",
64
+ supervisor,
59
65
  });
60
- supervisor.children.push(backendProc);
61
- (0, shared_1.attachBackendExitHandler)(backendProc, supervisor);
62
66
  const healthTimeoutMs = (0, health_1.resolveHealthTimeoutMs)(constants_1.HEALTH_TIMEOUT_MS_DEV);
63
67
  console.log("[kandev] starting backend...");
64
- await (0, health_1.waitForHealth)(ports.backendUrl, backendProc, healthTimeoutMs);
68
+ await (0, health_1.waitForHealth)(ports.backendUrl, backend.proc, healthTimeoutMs);
65
69
  console.log(`[kandev] backend ready at ${ports.backendUrl}`);
66
70
  console.log("[kandev] starting web...");
67
71
  const webProc = (0, web_1.launchWebApp)({
package/dist/run.js CHANGED
@@ -7,7 +7,6 @@ exports.findCachedRelease = findCachedRelease;
7
7
  exports.cleanOldReleases = cleanOldReleases;
8
8
  exports.attachRingBuffer = attachRingBuffer;
9
9
  exports.runRelease = runRelease;
10
- const node_child_process_1 = require("node:child_process");
11
10
  const node_fs_1 = __importDefault(require("node:fs"));
12
11
  const node_path_1 = __importDefault(require("node:path"));
13
12
  const bundle_1 = require("./bundle");
@@ -20,6 +19,7 @@ const ports_1 = require("./ports");
20
19
  const process_1 = require("./process");
21
20
  const runtime_1 = require("./runtime");
22
21
  const shared_1 = require("./shared");
22
+ const backend_1 = require("./supervisor/backend");
23
23
  const web_1 = require("./web");
24
24
  /**
25
25
  * Find a cached release binary to use when GitHub is unreachable.
@@ -199,7 +199,7 @@ function attachRingBuffer(stream, maxChars = 64 * 1024) {
199
199
  });
200
200
  return () => buf;
201
201
  }
202
- function launchBundle(prepared) {
202
+ async function launchBundle(prepared) {
203
203
  (0, shared_1.logStartupInfo)({
204
204
  header: `release: ${prepared.releaseTag}`,
205
205
  ports: {
@@ -213,12 +213,23 @@ function launchBundle(prepared) {
213
213
  });
214
214
  const supervisor = (0, process_1.createProcessSupervisor)();
215
215
  supervisor.attachSignalHandlers();
216
- const backendProc = (0, node_child_process_1.spawn)(prepared.backendBin, [], {
216
+ const backend = await (0, backend_1.launchRestartableBackend)({
217
+ command: prepared.backendBin,
218
+ args: [],
217
219
  cwd: node_path_1.default.dirname(prepared.backendBin),
218
220
  env: prepared.backendEnv,
221
+ homeDir: (0, constants_1.resolveKandevHomeDir)(),
222
+ ports: {
223
+ backendPort: Number(prepared.backendEnv.KANDEV_SERVER_PORT),
224
+ webPort: prepared.webPort,
225
+ agentctlPort: prepared.agentctlPort,
226
+ backendUrl: prepared.backendUrl,
227
+ },
228
+ mode: "run",
219
229
  stdio: prepared.showOutput ? ["ignore", "inherit", "inherit"] : ["ignore", "pipe", "inherit"],
230
+ supervisor,
220
231
  });
221
- supervisor.children.push(backendProc);
232
+ const backendProc = backend.proc;
222
233
  const readBuffered = prepared.showOutput ? () => "" : attachRingBuffer(backendProc.stdout);
223
234
  let dumped = false;
224
235
  const dumpBackendLogs = () => {
@@ -232,7 +243,6 @@ function launchBundle(prepared) {
232
243
  console.error(buffered.trimEnd());
233
244
  console.error("[kandev] --- end backend stdout ---");
234
245
  };
235
- (0, shared_1.attachBackendExitHandler)(backendProc, supervisor);
236
246
  const webServerPath = (0, bundle_1.resolveWebServerPath)(prepared.bundleDir);
237
247
  if (!webServerPath) {
238
248
  throw new Error("Web server entry (server.js) not found in bundle");
@@ -247,7 +257,7 @@ async function runRelease({ runtimeVersion, backendPort, webPort, verbose = fals
247
257
  verbose,
248
258
  debug,
249
259
  });
250
- const { supervisor, backendProc, webServerPath, dumpBackendLogs } = launchBundle(prepared);
260
+ const { supervisor, backendProc, webServerPath, dumpBackendLogs } = await launchBundle(prepared);
251
261
  const healthTimeoutMs = (0, health_1.resolveHealthTimeoutMs)(constants_1.HEALTH_TIMEOUT_MS_RELEASE);
252
262
  console.log("[kandev] starting backend...");
253
263
  await (0, health_1.waitForHealth)(prepared.backendUrl, backendProc, healthTimeoutMs, dumpBackendLogs);
package/dist/shared.js CHANGED
@@ -202,9 +202,12 @@ function networkUrlsForPort(port, hosts) {
202
202
  * @param backendProc - The backend child process
203
203
  * @param supervisor - The process supervisor managing child processes
204
204
  */
205
- function attachBackendExitHandler(backendProc, supervisor) {
205
+ function attachBackendExitHandler(backendProc, supervisor, options = {}) {
206
206
  backendProc.on("exit", (code, signal) => {
207
207
  console.error(`[kandev] backend exited (code=${code}, signal=${signal})`);
208
+ if (options.shouldShutdown && !options.shouldShutdown()) {
209
+ return;
210
+ }
208
211
  const exitCode = signal ? 0 : (code ?? 1);
209
212
  void supervisor.shutdown("backend exit").then(() => process.exit(exitCode));
210
213
  });
package/dist/start.js CHANGED
@@ -17,7 +17,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.resolveStandaloneServerPath = resolveStandaloneServerPath;
19
19
  exports.runStart = runStart;
20
- const node_child_process_1 = require("node:child_process");
21
20
  const node_fs_1 = __importDefault(require("node:fs"));
22
21
  const node_path_1 = __importDefault(require("node:path"));
23
22
  const constants_1 = require("./constants");
@@ -25,6 +24,7 @@ const health_1 = require("./health");
25
24
  const platform_1 = require("./platform");
26
25
  const process_1 = require("./process");
27
26
  const shared_1 = require("./shared");
27
+ const backend_1 = require("./supervisor/backend");
28
28
  const web_1 = require("./web");
29
29
  /**
30
30
  * Locates the standalone Next.js `server.js` inside `apps/web/.next/standalone/`.
@@ -83,7 +83,7 @@ function findWebServerJs(dir) {
83
83
  * @param options - Configuration for the start command
84
84
  * @throws Error if backend binary or web build is not found
85
85
  */
86
- async function runStart({ repoRoot, backendPort, webPort, verbose = false, debug = false, }) {
86
+ async function runStart({ repoRoot, backendPort, webPort, verbose = false, debug = false, headless = false, }) {
87
87
  const ports = await (0, shared_1.pickPorts)(backendPort, webPort);
88
88
  const backendBin = node_path_1.default.join(repoRoot, "apps", "backend", "bin", (0, platform_1.getBinaryName)("kandev"));
89
89
  if (!node_fs_1.default.existsSync(backendBin)) {
@@ -151,16 +151,20 @@ async function runStart({ repoRoot, backendPort, webPort, verbose = false, debug
151
151
  supervisor.attachSignalHandlers();
152
152
  // Start backend: ignore stdin, show stdout only in verbose/debug mode, always show stderr
153
153
  // Stderr is always inherited to ensure error messages are visible immediately (no pipe buffering)
154
- const backendProc = (0, node_child_process_1.spawn)(backendBin, [], {
154
+ const backend = await (0, backend_1.launchRestartableBackend)({
155
+ command: backendBin,
156
+ args: [],
155
157
  cwd: node_path_1.default.dirname(backendBin),
156
158
  env: backendEnv,
159
+ homeDir: (0, constants_1.resolveKandevHomeDir)(),
160
+ ports,
161
+ mode: "start",
157
162
  stdio: showOutput ? ["ignore", "inherit", "inherit"] : ["ignore", "ignore", "inherit"],
163
+ supervisor,
158
164
  });
159
- supervisor.children.push(backendProc);
160
- (0, shared_1.attachBackendExitHandler)(backendProc, supervisor);
161
165
  const healthTimeoutMs = (0, health_1.resolveHealthTimeoutMs)(constants_1.HEALTH_TIMEOUT_MS_RELEASE);
162
166
  console.log("[kandev] starting backend...");
163
- await (0, health_1.waitForHealth)(ports.backendUrl, backendProc, healthTimeoutMs);
167
+ await (0, health_1.waitForHealth)(ports.backendUrl, backend.proc, healthTimeoutMs);
164
168
  console.log(`[kandev] backend ready at ${ports.backendUrl}`);
165
169
  // Use standalone server.js directly (not pnpm start)
166
170
  const webUrl = `http://localhost:${ports.webPort}`;
@@ -176,5 +180,9 @@ async function runStart({ repoRoot, backendPort, webPort, verbose = false, debug
176
180
  });
177
181
  await (0, health_1.waitForUrlReady)(webUrl, webProc, healthTimeoutMs);
178
182
  console.log("[kandev] open: " + ports.backendUrl);
183
+ if (headless) {
184
+ console.log(`[kandev] ready (headless) at ${ports.backendUrl}`);
185
+ return;
186
+ }
179
187
  (0, web_1.openBrowser)(ports.backendUrl);
180
188
  }
@@ -0,0 +1,83 @@
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.launchRestartableBackend = launchRestartableBackend;
7
+ exports.shouldUseSupervisor = shouldUseSupervisor;
8
+ exports.withSupervisorEnv = withSupervisorEnv;
9
+ const node_child_process_1 = require("node:child_process");
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ const shared_1 = require("../shared");
12
+ const manifest_1 = require("./manifest");
13
+ const paths_1 = require("./paths");
14
+ const child_1 = require("./child");
15
+ const control_1 = require("./control");
16
+ async function launchRestartableBackend({ command, args, cwd, env, homeDir, ports, mode, stdio, supervisor, }) {
17
+ if (!shouldUseSupervisor(env)) {
18
+ const proc = (0, node_child_process_1.spawn)(command, args, { cwd, env, stdio });
19
+ supervisor.children.push(proc);
20
+ (0, shared_1.attachBackendExitHandler)(proc, supervisor);
21
+ return { proc, control: null, env };
22
+ }
23
+ const supervisorEnv = withSupervisorEnv(env, homeDir);
24
+ const manifest = (0, manifest_1.buildLaunchManifest)({
25
+ backend_executable: resolveExecutable(command),
26
+ argv: args,
27
+ cwd,
28
+ env: supervisorEnv,
29
+ home_dir: homeDir,
30
+ port: ports.backendPort,
31
+ mode,
32
+ });
33
+ (0, manifest_1.writeLaunchManifest)(manifest, supervisorEnv.KANDEV_SUPERVISOR_MANIFEST);
34
+ const child = (0, child_1.createRestartableChild)(manifest, { stdio, extraEnv: supervisorEnv });
35
+ let restarting = false;
36
+ const attachExit = (proc) => {
37
+ (0, shared_1.attachBackendExitHandler)(proc, supervisor, {
38
+ shouldShutdown: () => !restarting,
39
+ });
40
+ };
41
+ const proc = child.start();
42
+ supervisor.children.push(proc);
43
+ attachExit(proc);
44
+ const control = await (0, control_1.startControlServer)(supervisorEnv.KANDEV_SUPERVISOR_SOCKET, async () => {
45
+ restarting = true;
46
+ try {
47
+ const next = await child.restart();
48
+ supervisor.children.push(next);
49
+ attachExit(next);
50
+ }
51
+ finally {
52
+ restarting = false;
53
+ }
54
+ });
55
+ return { proc, control, env: supervisorEnv };
56
+ }
57
+ function shouldUseSupervisor(env = process.env) {
58
+ return env.KANDEV_NO_SUPERVISOR !== "true";
59
+ }
60
+ function withSupervisorEnv(env, homeDir) {
61
+ (0, paths_1.prepareSupervisorDir)(homeDir);
62
+ return {
63
+ ...env,
64
+ KANDEV_SUPERVISOR_SOCKET: (0, paths_1.socketPath)(homeDir),
65
+ KANDEV_SUPERVISOR_MANIFEST: (0, paths_1.manifestPath)(homeDir),
66
+ KANDEV_RESTART_ADAPTER: "supervisor",
67
+ };
68
+ }
69
+ function resolveExecutable(command) {
70
+ if (node_path_1.default.isAbsolute(command))
71
+ return command;
72
+ const found = (0, node_child_process_1.spawnSync)(process.platform === "win32" ? "where" : "which", [command], {
73
+ encoding: "utf8",
74
+ });
75
+ const first = found.stdout
76
+ ?.split(/\r?\n/)
77
+ .map((line) => line.trim())
78
+ .find(Boolean);
79
+ if (!first) {
80
+ throw new Error(`Unable to resolve executable ${command}`);
81
+ }
82
+ return first;
83
+ }
@@ -0,0 +1,64 @@
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.createRestartableChild = createRestartableChild;
7
+ const node_child_process_1 = require("node:child_process");
8
+ const tree_kill_1 = __importDefault(require("tree-kill"));
9
+ const RESTART_TIMEOUT_MS = 10000;
10
+ function createRestartableChild(manifest, options = {}) {
11
+ let child = null;
12
+ const start = () => {
13
+ child = (0, node_child_process_1.spawn)(manifest.backend_executable, manifest.argv, {
14
+ cwd: manifest.cwd,
15
+ env: {
16
+ ...process.env,
17
+ ...manifest.env,
18
+ ...options.extraEnv,
19
+ },
20
+ stdio: options.stdio ?? "inherit",
21
+ });
22
+ return child;
23
+ };
24
+ const stop = async () => {
25
+ if (!child?.pid || child.exitCode !== null)
26
+ return;
27
+ await terminate(child, RESTART_TIMEOUT_MS);
28
+ };
29
+ const restart = async () => {
30
+ await stop();
31
+ return start();
32
+ };
33
+ return {
34
+ current: () => child,
35
+ start,
36
+ restart,
37
+ stop,
38
+ };
39
+ }
40
+ function terminate(proc, timeoutMs) {
41
+ return new Promise((resolve) => {
42
+ const pid = proc.pid;
43
+ if (!pid) {
44
+ resolve();
45
+ return;
46
+ }
47
+ let done = false;
48
+ const finish = () => {
49
+ if (done)
50
+ return;
51
+ done = true;
52
+ clearTimeout(timeout);
53
+ resolve();
54
+ };
55
+ const timeout = setTimeout(() => {
56
+ (0, tree_kill_1.default)(pid, process.platform === "win32" ? undefined : "SIGKILL", finish);
57
+ }, timeoutMs);
58
+ proc.once("exit", finish);
59
+ (0, tree_kill_1.default)(pid, process.platform === "win32" ? undefined : "SIGTERM", (err) => {
60
+ if (err)
61
+ finish();
62
+ });
63
+ });
64
+ }
@@ -0,0 +1,97 @@
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.startControlServer = startControlServer;
7
+ exports.requestRestart = requestRestart;
8
+ const node_net_1 = __importDefault(require("node:net"));
9
+ const node_fs_1 = __importDefault(require("node:fs"));
10
+ function startControlServer(socket, onRestart) {
11
+ let restartInProgress = false;
12
+ const scheduleRestart = () => {
13
+ if (restartInProgress)
14
+ return false;
15
+ restartInProgress = true;
16
+ setTimeout(() => {
17
+ void onRestart().finally(() => {
18
+ restartInProgress = false;
19
+ });
20
+ }, 0);
21
+ return true;
22
+ };
23
+ if (process.platform !== "win32" && node_fs_1.default.existsSync(socket)) {
24
+ node_fs_1.default.unlinkSync(socket);
25
+ }
26
+ const server = node_net_1.default.createServer((conn) => {
27
+ let buf = "";
28
+ conn.setEncoding("utf8");
29
+ conn.on("data", (chunk) => {
30
+ buf += chunk;
31
+ if (!buf.includes("\n"))
32
+ return;
33
+ const line = buf.slice(0, buf.indexOf("\n"));
34
+ void handleControlLine(line, scheduleRestart)
35
+ .then((resp) => {
36
+ conn.end(`${JSON.stringify(resp)}\n`);
37
+ })
38
+ .catch((err) => {
39
+ conn.end(`${JSON.stringify({
40
+ accepted: false,
41
+ message: err instanceof Error ? err.message : String(err),
42
+ })}\n`);
43
+ });
44
+ });
45
+ });
46
+ return new Promise((resolve, reject) => {
47
+ server.once("error", reject);
48
+ server.listen(socket, () => {
49
+ server.off("error", reject);
50
+ resolve({
51
+ close: () => new Promise((closeResolve, closeReject) => {
52
+ server.close((err) => {
53
+ if (process.platform !== "win32" && node_fs_1.default.existsSync(socket)) {
54
+ node_fs_1.default.unlinkSync(socket);
55
+ }
56
+ if (err)
57
+ closeReject(err);
58
+ else
59
+ closeResolve();
60
+ });
61
+ }),
62
+ });
63
+ });
64
+ });
65
+ }
66
+ function requestRestart(socket) {
67
+ return new Promise((resolve, reject) => {
68
+ const conn = node_net_1.default.createConnection(socket);
69
+ let buf = "";
70
+ conn.setEncoding("utf8");
71
+ conn.on("connect", () => {
72
+ conn.write(`${JSON.stringify({ action: "restart" })}\n`);
73
+ });
74
+ conn.on("data", (chunk) => {
75
+ buf += chunk;
76
+ });
77
+ conn.on("error", reject);
78
+ conn.on("end", () => {
79
+ try {
80
+ resolve(JSON.parse(buf.trim()));
81
+ }
82
+ catch (err) {
83
+ reject(err);
84
+ }
85
+ });
86
+ });
87
+ }
88
+ async function handleControlLine(line, scheduleRestart) {
89
+ const req = JSON.parse(line);
90
+ if (req.action !== "restart") {
91
+ return { accepted: false, message: `unsupported action ${String(req.action)}` };
92
+ }
93
+ if (!scheduleRestart()) {
94
+ return { accepted: false, message: "Restart already in progress" };
95
+ }
96
+ return { accepted: true, message: "Restart accepted" };
97
+ }
@@ -0,0 +1,74 @@
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.buildLaunchManifest = buildLaunchManifest;
7
+ exports.writeLaunchManifest = writeLaunchManifest;
8
+ exports.readLaunchManifest = readLaunchManifest;
9
+ exports.allowedEnv = allowedEnv;
10
+ const node_fs_1 = __importDefault(require("node:fs"));
11
+ const node_path_1 = __importDefault(require("node:path"));
12
+ const paths_1 = require("./paths");
13
+ const ENV_ALLOWLIST = new Set([
14
+ "KANDEV_HOME_DIR",
15
+ "KANDEV_DATABASE_PATH",
16
+ "KANDEV_SERVER_PORT",
17
+ "KANDEV_WEB_INTERNAL_URL",
18
+ "KANDEV_AGENT_STANDALONE_PORT",
19
+ "KANDEV_LOG_LEVEL",
20
+ "KANDEV_DEBUG_DEV_MODE",
21
+ "KANDEV_DEBUG_AGENT_MESSAGES",
22
+ "KANDEV_DEBUG_PPROF_ENABLED",
23
+ "KANDEV_E2E_MOCK",
24
+ "KANDEV_MOCK_AGENT",
25
+ "KANDEV_MOCK_GITHUB",
26
+ "KANDEV_MOCK_JIRA",
27
+ "KANDEV_MOCK_LINEAR",
28
+ "KANDEV_SUPERVISOR_SOCKET",
29
+ "KANDEV_SUPERVISOR_MANIFEST",
30
+ "KANDEV_RESTART_ADAPTER",
31
+ ]);
32
+ function buildLaunchManifest(input) {
33
+ if (!node_path_1.default.isAbsolute(input.backend_executable)) {
34
+ throw new Error("backend_executable must be absolute");
35
+ }
36
+ if (!node_path_1.default.isAbsolute(input.cwd)) {
37
+ throw new Error("cwd must be absolute");
38
+ }
39
+ if (!node_path_1.default.isAbsolute(input.home_dir)) {
40
+ throw new Error("home_dir must be absolute");
41
+ }
42
+ return {
43
+ version: 1,
44
+ backend_executable: input.backend_executable,
45
+ argv: [...input.argv],
46
+ cwd: input.cwd,
47
+ env: allowedEnv(input.env),
48
+ home_dir: input.home_dir,
49
+ port: input.port,
50
+ mode: input.mode,
51
+ created_at: (input.now ?? new Date()).toISOString(),
52
+ };
53
+ }
54
+ function writeLaunchManifest(manifest, targetPath = (0, paths_1.manifestPath)(manifest.home_dir)) {
55
+ (0, paths_1.prepareSupervisorDir)(manifest.home_dir);
56
+ node_fs_1.default.writeFileSync(targetPath, `${JSON.stringify(manifest, null, 2)}\n`, { mode: 0o600 });
57
+ if (process.platform !== "win32") {
58
+ node_fs_1.default.chmodSync(targetPath, 0o600);
59
+ }
60
+ return targetPath;
61
+ }
62
+ function readLaunchManifest(targetPath) {
63
+ return JSON.parse(node_fs_1.default.readFileSync(targetPath, "utf8"));
64
+ }
65
+ function allowedEnv(env) {
66
+ const out = {};
67
+ for (const key of ENV_ALLOWLIST) {
68
+ const value = env[key];
69
+ if (value !== undefined) {
70
+ out[key] = value;
71
+ }
72
+ }
73
+ return out;
74
+ }
@@ -0,0 +1,33 @@
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.supervisorDir = supervisorDir;
7
+ exports.manifestPath = manifestPath;
8
+ exports.socketPath = socketPath;
9
+ exports.prepareSupervisorDir = prepareSupervisorDir;
10
+ const node_fs_1 = __importDefault(require("node:fs"));
11
+ const node_path_1 = __importDefault(require("node:path"));
12
+ const constants_1 = require("../constants");
13
+ function supervisorDir(homeDir = (0, constants_1.resolveKandevHomeDir)()) {
14
+ return node_path_1.default.join(homeDir, "supervisor");
15
+ }
16
+ function manifestPath(homeDir = (0, constants_1.resolveKandevHomeDir)()) {
17
+ return node_path_1.default.join(supervisorDir(homeDir), "launch.json");
18
+ }
19
+ function socketPath(homeDir = (0, constants_1.resolveKandevHomeDir)()) {
20
+ if (process.platform === "win32") {
21
+ const safe = homeDir.replace(/[^a-zA-Z0-9_.-]/g, "-");
22
+ return `\\\\.\\pipe\\kandev-${safe}-supervisor`;
23
+ }
24
+ return node_path_1.default.join(supervisorDir(homeDir), "control.sock");
25
+ }
26
+ function prepareSupervisorDir(homeDir = (0, constants_1.resolveKandevHomeDir)()) {
27
+ const dir = supervisorDir(homeDir);
28
+ node_fs_1.default.mkdirSync(dir, { recursive: true, mode: 0o700 });
29
+ if (process.platform !== "win32") {
30
+ node_fs_1.default.chmodSync(dir, 0o700);
31
+ }
32
+ return dir;
33
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kandev",
3
- "version": "0.59.0",
3
+ "version": "0.61.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",
@@ -22,11 +22,11 @@
22
22
  "npm": ">=7"
23
23
  },
24
24
  "optionalDependencies": {
25
- "@kdlbs/runtime-linux-x64": "0.59.0",
26
- "@kdlbs/runtime-linux-arm64": "0.59.0",
27
- "@kdlbs/runtime-darwin-x64": "0.59.0",
28
- "@kdlbs/runtime-darwin-arm64": "0.59.0",
29
- "@kdlbs/runtime-win32-x64": "0.59.0"
25
+ "@kdlbs/runtime-linux-x64": "0.61.0",
26
+ "@kdlbs/runtime-linux-arm64": "0.61.0",
27
+ "@kdlbs/runtime-darwin-x64": "0.61.0",
28
+ "@kdlbs/runtime-darwin-arm64": "0.61.0",
29
+ "@kdlbs/runtime-win32-x64": "0.61.0"
30
30
  },
31
31
  "dependencies": {
32
32
  "tar": "^7.5.11",