@sma1lboy/kobe 0.9.45 → 0.9.47

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.
@@ -1,6 +1,137 @@
1
1
  import { createRequire } from "node:module";
2
2
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
3
3
 
4
+ // ../kobe-daemon/src/daemon/log-rotate.ts
5
+ import { existsSync, renameSync, statSync } from "node:fs";
6
+ var DEFAULT_LOG_ROTATE_CAP_BYTES = 10 * 1024 * 1024;
7
+ function shouldRotateLog(sizeBytes, capBytes = DEFAULT_LOG_ROTATE_CAP_BYTES) {
8
+ return sizeBytes > capBytes;
9
+ }
10
+ function rotateLogIfNeeded(path, capBytes = DEFAULT_LOG_ROTATE_CAP_BYTES) {
11
+ try {
12
+ if (!existsSync(path))
13
+ return;
14
+ const { size } = statSync(path);
15
+ if (!shouldRotateLog(size, capBytes))
16
+ return;
17
+ renameSync(path, `${path}.old`);
18
+ } catch {}
19
+ }
20
+
21
+ // ../kobe-daemon/src/daemon/paths.ts
22
+ import { createHash } from "node:crypto";
23
+ import { existsSync as existsSync2, readFileSync } from "node:fs";
24
+ import { homedir, tmpdir } from "node:os";
25
+ import { join } from "node:path";
26
+
27
+ // ../kobe-daemon/src/compat-env.ts
28
+ var ROVE_ENV_PREFIX = "ROVE_";
29
+ var LEGACY_KOBE_ENV_PREFIX = "KOBE_";
30
+ var ROVE_STATE_DIR_BASENAME = ".rove";
31
+ var COMPAT_STATE_DIR_BASENAME = ".kobe";
32
+ function readRoveEnv(suffix, env = process.env) {
33
+ return env[`${ROVE_ENV_PREFIX}${suffix}`] ?? env[`${LEGACY_KOBE_ENV_PREFIX}${suffix}`];
34
+ }
35
+
36
+ // ../kobe-daemon/src/daemon/paths.ts
37
+ function stateDirs(homeDir) {
38
+ return { canonical: join(homeDir, ROVE_STATE_DIR_BASENAME), legacy: join(homeDir, COMPAT_STATE_DIR_BASENAME) };
39
+ }
40
+ function pidIsLive(pidPath) {
41
+ try {
42
+ const pid = Number.parseInt(readFileSync(pidPath, "utf8").trim(), 10);
43
+ if (!Number.isInteger(pid) || pid <= 1)
44
+ return false;
45
+ process.kill(pid, 0);
46
+ return true;
47
+ } catch {
48
+ return false;
49
+ }
50
+ }
51
+ function runtimePath(homeDir, name, pidName) {
52
+ const { canonical, legacy } = stateDirs(homeDir);
53
+ const canonicalPath = join(canonical, name);
54
+ if (existsSync2(canonicalPath))
55
+ return canonicalPath;
56
+ const legacyPath = join(legacy, name);
57
+ if (existsSync2(legacyPath) && pidIsLive(join(legacy, pidName)))
58
+ return legacyPath;
59
+ return canonicalPath;
60
+ }
61
+ function legacyRuntimePath(homeDir, name) {
62
+ return join(homeDir, COMPAT_STATE_DIR_BASENAME, name);
63
+ }
64
+ function legacyPtyHostSocketPath(homeDir) {
65
+ return legacyRuntimePath(homeDir, "pty.sock");
66
+ }
67
+ function legacyPtyHostPidPath(homeDir) {
68
+ return legacyRuntimePath(homeDir, "pty.pid");
69
+ }
70
+ function runtimeDataPath(homeDir, name) {
71
+ const { canonical, legacy } = stateDirs(homeDir);
72
+ const canonicalPath = join(canonical, name);
73
+ if (existsSync2(canonicalPath))
74
+ return canonicalPath;
75
+ const legacyPath = join(legacy, name);
76
+ return existsSync2(legacyPath) ? legacyPath : canonicalPath;
77
+ }
78
+ var SOCKET_PATH_SAFETY_LIMIT = 100;
79
+ function shortHomeTag(homeDir) {
80
+ return createHash("sha1").update(homeDir).digest("hex").slice(0, 8);
81
+ }
82
+ function fitSocketPath(naturalPath, homeDir, role, pidTag) {
83
+ if (Buffer.byteLength(naturalPath, "utf8") <= SOCKET_PATH_SAFETY_LIMIT)
84
+ return naturalPath;
85
+ const tag = shortHomeTag(homeDir);
86
+ const suffix = pidTag === undefined ? "" : `-${pidTag}`;
87
+ const fallback = join(tmpdir(), `kobe-${tag}-${role}${suffix}.sock`);
88
+ if (Buffer.byteLength(fallback, "utf8") <= SOCKET_PATH_SAFETY_LIMIT)
89
+ return fallback;
90
+ throw new Error(`daemon socket path exceeds ${SOCKET_PATH_SAFETY_LIMIT} bytes even after fallback: ${fallback}`);
91
+ }
92
+ function resolveDaemonHomeDir(homeDir) {
93
+ const explicit = homeDir ?? readRoveEnv("HOME_DIR");
94
+ return explicit && explicit.length > 0 ? explicit : homedir();
95
+ }
96
+ function isWindowsPipePath(path) {
97
+ return path.startsWith("\\\\.\\pipe\\") || path.startsWith("//./pipe/");
98
+ }
99
+ function windowsPipePath(homeDir, role) {
100
+ return `\\\\.\\pipe\\kobe-${shortHomeTag(homeDir)}-${role}`;
101
+ }
102
+ function defaultPtyHostSocketPath(homeDir, platform = process.platform) {
103
+ const override = readRoveEnv("PTY_SOCKET_PATH");
104
+ if (override && override.length > 0)
105
+ return override;
106
+ const explicit = homeDir ?? readRoveEnv("HOME_DIR");
107
+ if (platform === "win32")
108
+ return windowsPipePath(explicit || homedir(), "pty");
109
+ if (explicit && explicit.length > 0) {
110
+ return fitSocketPath(runtimePath(explicit, "pty.sock", "pty.pid"), explicit, "pty");
111
+ }
112
+ const runtimeDir = process.env.XDG_RUNTIME_DIR;
113
+ if (runtimeDir && runtimeDir.length > 0) {
114
+ return fitSocketPath(join(runtimeDir, "kobe-pty.sock"), runtimeDir, "pty");
115
+ }
116
+ const home = homedir();
117
+ return fitSocketPath(runtimePath(home, "pty.sock", "pty.pid"), home, "pty");
118
+ }
119
+ function defaultPtyHostPidPath(homeDir = readRoveEnv("HOME_DIR") ?? homedir()) {
120
+ const override = readRoveEnv("PTY_PID_PATH");
121
+ if (override && override.length > 0)
122
+ return override;
123
+ return runtimePath(homeDir, "pty.pid", "pty.pid");
124
+ }
125
+ function defaultPtyHostLogPath(homeDir = readRoveEnv("HOME_DIR") ?? homedir()) {
126
+ return join(homeDir, ROVE_STATE_DIR_BASENAME, "pty.log");
127
+ }
128
+ function defaultPtyExitsPath(homeDir = readRoveEnv("HOME_DIR") ?? homedir()) {
129
+ return runtimeDataPath(homeDir, "pty-exits.json");
130
+ }
131
+ function defaultPtyFreezeDir(homeDir = readRoveEnv("HOME_DIR") ?? homedir()) {
132
+ return runtimeDataPath(homeDir, "pty-sessions");
133
+ }
134
+
4
135
  // ../kobe-daemon/src/daemon/pty-driver.ts
5
136
  var TERMINAL_NAME = "xterm-256color";
6
137
  function bunTerminalDriver(spawn) {
@@ -208,117 +339,6 @@ function requireString(payload, key) {
208
339
  throw new Error(`${key} is required`);
209
340
  return value;
210
341
  }
211
-
212
- // ../kobe-daemon/src/daemon/paths.ts
213
- import { createHash } from "node:crypto";
214
- import { existsSync, readFileSync } from "node:fs";
215
- import { homedir, tmpdir } from "node:os";
216
- import { join } from "node:path";
217
-
218
- // ../kobe-daemon/src/compat-env.ts
219
- var ROVE_ENV_PREFIX = "ROVE_";
220
- var LEGACY_KOBE_ENV_PREFIX = "KOBE_";
221
- var ROVE_STATE_DIR_BASENAME = ".rove";
222
- var COMPAT_STATE_DIR_BASENAME = ".kobe";
223
- function readRoveEnv(suffix, env = process.env) {
224
- return env[`${ROVE_ENV_PREFIX}${suffix}`] ?? env[`${LEGACY_KOBE_ENV_PREFIX}${suffix}`];
225
- }
226
-
227
- // ../kobe-daemon/src/daemon/paths.ts
228
- function stateDirs(homeDir) {
229
- return { canonical: join(homeDir, ROVE_STATE_DIR_BASENAME), legacy: join(homeDir, COMPAT_STATE_DIR_BASENAME) };
230
- }
231
- function pidIsLive(pidPath) {
232
- try {
233
- const pid = Number.parseInt(readFileSync(pidPath, "utf8").trim(), 10);
234
- if (!Number.isInteger(pid) || pid <= 1)
235
- return false;
236
- process.kill(pid, 0);
237
- return true;
238
- } catch {
239
- return false;
240
- }
241
- }
242
- function runtimePath(homeDir, name, pidName) {
243
- const { canonical, legacy } = stateDirs(homeDir);
244
- const canonicalPath = join(canonical, name);
245
- if (existsSync(canonicalPath))
246
- return canonicalPath;
247
- const legacyPath = join(legacy, name);
248
- if (existsSync(legacyPath) && pidIsLive(join(legacy, pidName)))
249
- return legacyPath;
250
- return canonicalPath;
251
- }
252
- function legacyRuntimePath(homeDir, name) {
253
- return join(homeDir, COMPAT_STATE_DIR_BASENAME, name);
254
- }
255
- function legacyPtyHostSocketPath(homeDir) {
256
- return legacyRuntimePath(homeDir, "pty.sock");
257
- }
258
- function legacyPtyHostPidPath(homeDir) {
259
- return legacyRuntimePath(homeDir, "pty.pid");
260
- }
261
- function runtimeDataPath(homeDir, name) {
262
- const { canonical, legacy } = stateDirs(homeDir);
263
- const canonicalPath = join(canonical, name);
264
- if (existsSync(canonicalPath))
265
- return canonicalPath;
266
- const legacyPath = join(legacy, name);
267
- return existsSync(legacyPath) ? legacyPath : canonicalPath;
268
- }
269
- var SOCKET_PATH_SAFETY_LIMIT = 100;
270
- function shortHomeTag(homeDir) {
271
- return createHash("sha1").update(homeDir).digest("hex").slice(0, 8);
272
- }
273
- function fitSocketPath(naturalPath, homeDir, role, pidTag) {
274
- if (Buffer.byteLength(naturalPath, "utf8") <= SOCKET_PATH_SAFETY_LIMIT)
275
- return naturalPath;
276
- const tag = shortHomeTag(homeDir);
277
- const suffix = pidTag === undefined ? "" : `-${pidTag}`;
278
- const fallback = join(tmpdir(), `kobe-${tag}-${role}${suffix}.sock`);
279
- if (Buffer.byteLength(fallback, "utf8") <= SOCKET_PATH_SAFETY_LIMIT)
280
- return fallback;
281
- throw new Error(`daemon socket path exceeds ${SOCKET_PATH_SAFETY_LIMIT} bytes even after fallback: ${fallback}`);
282
- }
283
- function resolveDaemonHomeDir(homeDir) {
284
- const explicit = homeDir ?? readRoveEnv("HOME_DIR");
285
- return explicit && explicit.length > 0 ? explicit : homedir();
286
- }
287
- function isWindowsPipePath(path) {
288
- return path.startsWith("\\\\.\\pipe\\") || path.startsWith("//./pipe/");
289
- }
290
- function windowsPipePath(homeDir, role) {
291
- return `\\\\.\\pipe\\kobe-${shortHomeTag(homeDir)}-${role}`;
292
- }
293
- function defaultPtyHostSocketPath(homeDir, platform = process.platform) {
294
- const override = readRoveEnv("PTY_SOCKET_PATH");
295
- if (override && override.length > 0)
296
- return override;
297
- const explicit = homeDir ?? readRoveEnv("HOME_DIR");
298
- if (platform === "win32")
299
- return windowsPipePath(explicit || homedir(), "pty");
300
- if (explicit && explicit.length > 0) {
301
- return fitSocketPath(runtimePath(explicit, "pty.sock", "pty.pid"), explicit, "pty");
302
- }
303
- const runtimeDir = process.env.XDG_RUNTIME_DIR;
304
- if (runtimeDir && runtimeDir.length > 0) {
305
- return fitSocketPath(join(runtimeDir, "kobe-pty.sock"), runtimeDir, "pty");
306
- }
307
- const home = homedir();
308
- return fitSocketPath(runtimePath(home, "pty.sock", "pty.pid"), home, "pty");
309
- }
310
- function defaultPtyHostPidPath(homeDir = readRoveEnv("HOME_DIR") ?? homedir()) {
311
- const override = readRoveEnv("PTY_PID_PATH");
312
- if (override && override.length > 0)
313
- return override;
314
- return runtimePath(homeDir, "pty.pid", "pty.pid");
315
- }
316
- function defaultPtyExitsPath(homeDir = readRoveEnv("HOME_DIR") ?? homedir()) {
317
- return runtimeDataPath(homeDir, "pty-exits.json");
318
- }
319
- function defaultPtyFreezeDir(homeDir = readRoveEnv("HOME_DIR") ?? homedir()) {
320
- return runtimeDataPath(homeDir, "pty-sessions");
321
- }
322
342
  // ../kobe-plugin-sdk/dist/contract.js
323
343
  var DAEMON_CHANNELS = [
324
344
  "task.snapshot",
@@ -402,7 +422,7 @@ function writeRecord(storeKey, record, path) {
402
422
  }
403
423
 
404
424
  // ../kobe-daemon/src/daemon/pty-freeze-store.ts
405
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync3, readdirSync, renameSync, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
425
+ import { chmodSync, mkdirSync as mkdirSync2, readFileSync as readFileSync3, readdirSync, renameSync as renameSync2, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
406
426
  import { join as join2 } from "node:path";
407
427
  import { StringDecoder } from "node:string_decoder";
408
428
 
@@ -533,34 +553,75 @@ function parseRecord(raw) {
533
553
  return null;
534
554
  }
535
555
  }
536
- function loadFrozenSessions(dir = defaultPtyFreezeDir()) {
556
+ var FREEZE_TTL_MS = 14 * 24 * 60 * 60 * 1000;
557
+ var FREEZE_MAX_RECORDS = 64;
558
+ function updatedAtMs(record) {
559
+ const t = Date.parse(record.updatedAt);
560
+ return Number.isFinite(t) ? t : 0;
561
+ }
562
+ function loadFrozenSessions(dir = defaultPtyFreezeDir(), now = Date.now()) {
537
563
  let names;
538
564
  try {
539
565
  names = readdirSync(dir);
540
566
  } catch {
541
567
  return [];
542
568
  }
543
- const out = [];
569
+ const kept = [];
570
+ const stale = [];
571
+ for (const name of names) {
572
+ if (!name.endsWith(".json"))
573
+ continue;
574
+ let record = null;
575
+ try {
576
+ record = parseRecord(readFileSync3(join2(dir, name), "utf8"));
577
+ } catch {}
578
+ if (!record)
579
+ continue;
580
+ if (now - updatedAtMs(record) > FREEZE_TTL_MS)
581
+ stale.push(name);
582
+ else
583
+ kept.push({ name, record });
584
+ }
585
+ kept.sort((a, b) => updatedAtMs(b.record) - updatedAtMs(a.record));
586
+ for (const over of kept.splice(FREEZE_MAX_RECORDS))
587
+ stale.push(over.name);
588
+ for (const name of stale) {
589
+ try {
590
+ rmSync(join2(dir, name), { force: true });
591
+ } catch {}
592
+ }
593
+ return kept.map((entry) => entry.record);
594
+ }
595
+ var DIR_MODE = 448;
596
+ var FILE_MODE = 384;
597
+ function tightenExistingPermissions(dir) {
598
+ try {
599
+ chmodSync(dir, DIR_MODE);
600
+ } catch {}
601
+ let names;
602
+ try {
603
+ names = readdirSync(dir);
604
+ } catch {
605
+ return;
606
+ }
544
607
  for (const name of names) {
545
608
  if (!name.endsWith(".json"))
546
609
  continue;
547
610
  try {
548
- const record = parseRecord(readFileSync3(join2(dir, name), "utf8"));
549
- if (record)
550
- out.push(record);
611
+ chmodSync(join2(dir, name), FILE_MODE);
551
612
  } catch {}
552
613
  }
553
- return out;
554
614
  }
555
615
  function fileFreezeSink(dir = defaultPtyFreezeDir()) {
616
+ tightenExistingPermissions(dir);
556
617
  return {
557
618
  save(record) {
558
619
  try {
559
- mkdirSync2(dir, { recursive: true, mode: 448 });
620
+ mkdirSync2(dir, { recursive: true, mode: DIR_MODE });
560
621
  const target = recordFile(dir, record.key);
561
622
  const staging = `${target}.${process.pid}.tmp`;
562
- writeFileSync2(staging, JSON.stringify(record), { encoding: "utf8", mode: 384 });
563
- renameSync(staging, target);
623
+ writeFileSync2(staging, JSON.stringify(record), { encoding: "utf8", mode: FILE_MODE });
624
+ renameSync2(staging, target);
564
625
  } catch {}
565
626
  },
566
627
  drop(key) {
@@ -577,7 +638,7 @@ function clearFrozenSessions(dir = defaultPtyFreezeDir()) {
577
638
  }
578
639
 
579
640
  // ../kobe-daemon/src/daemon/platform-shell.js
580
- import { existsSync as existsSync2 } from "node:fs";
641
+ import { existsSync as existsSync3 } from "node:fs";
581
642
  function windowsBashCandidates(env) {
582
643
  const roots = [env.ProgramFiles, env["ProgramFiles(x86)"], env.LOCALAPPDATA && `${env.LOCALAPPDATA}\\Programs`];
583
644
  return roots.filter(Boolean).map((root) => `${root}\\Git\\bin\\bash.exe`);
@@ -591,7 +652,7 @@ function resolveLoginShell(options = {}) {
591
652
  const fallback = options.fallback ?? "/bin/bash";
592
653
  const platform = options.platform ?? process.platform;
593
654
  const env = options.env ?? process.env;
594
- const exists = options.exists ?? existsSync2;
655
+ const exists = options.exists ?? existsSync3;
595
656
  const cacheable = platform === process.platform && env === process.env && options.exists === undefined;
596
657
  if (cacheable) {
597
658
  const hit = cache.get(fallback);
@@ -1443,6 +1504,7 @@ function writeFrame(client, frame) {
1443
1504
 
1444
1505
  // ../kobe-daemon/src/daemon/pty-host-node-entry.ts
1445
1506
  async function main() {
1507
+ rotateLogIfNeeded(defaultPtyHostLogPath());
1446
1508
  process.on("uncaughtException", (err) => console.error(`[pty-host crash] ${err?.stack ?? String(err)}`));
1447
1509
  process.on("unhandledRejection", (err) => console.error(`[pty-host reject] ${String(err)}`));
1448
1510
  const driver = await nodePtyDriver();