@kynver-app/runtime 0.1.2 → 0.1.3

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import { mkdirSync as mkdirSync5 } from "node:fs";
5
- import path12 from "node:path";
5
+ import path13 from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
 
8
8
  // src/config.ts
@@ -243,12 +243,12 @@ var DEFAULT_CRITICAL_FREE_BYTES = 15 * 1024 * 1024 * 1024;
243
243
  var DEFAULT_MAX_USED_PERCENT = 80;
244
244
  var DEFAULT_HARD_MAX_USED_PERCENT = 90;
245
245
  function observeRunnerDiskGate(input = {}) {
246
- const path13 = input.diskPath?.trim() || "/";
246
+ const path14 = input.diskPath?.trim() || "/";
247
247
  const warnBelowBytes = input.diskFreeWarnBytes ?? DEFAULT_WARN_FREE_BYTES;
248
248
  const criticalBelowBytes = input.diskFreeCriticalBytes ?? DEFAULT_CRITICAL_FREE_BYTES;
249
249
  const maxUsedPercent = input.diskMaxUsedPercent ?? DEFAULT_MAX_USED_PERCENT;
250
250
  const hardMaxUsedPercent = input.diskHardMaxUsedPercent ?? DEFAULT_HARD_MAX_USED_PERCENT;
251
- const stats = statfsSync(path13);
251
+ const stats = statfsSync(path14);
252
252
  const freeBytes = Number(stats.bavail) * Number(stats.bsize);
253
253
  const totalBytes = Number(stats.blocks) * Number(stats.bsize);
254
254
  const usedPercent = totalBytes > 0 ? (totalBytes - freeBytes) / totalBytes * 100 : 100;
@@ -268,7 +268,7 @@ function observeRunnerDiskGate(input = {}) {
268
268
  }
269
269
  return {
270
270
  ok,
271
- path: path13,
271
+ path: path14,
272
272
  freeBytes,
273
273
  totalBytes,
274
274
  usedPercent,
@@ -379,7 +379,8 @@ function parseClaudeStream(file) {
379
379
  for (const line of lines) {
380
380
  const event = safeJson(line);
381
381
  if (!event) continue;
382
- const ts = event.timestamp || event.ts;
382
+ const tsMs = event.timestamp_ms;
383
+ const ts = event.timestamp || event.ts || (tsMs ? new Date(tsMs).toISOString() : void 0);
383
384
  if (ts) {
384
385
  result.firstEventAt ||= ts;
385
386
  result.lastEventAt = ts;
@@ -638,8 +639,8 @@ function observeRunnerResourceGate(input) {
638
639
  }
639
640
 
640
641
  // src/supervisor.ts
641
- import { existsSync as existsSync6, mkdirSync as mkdirSync3 } from "node:fs";
642
- import path6 from "node:path";
642
+ import { existsSync as existsSync7, mkdirSync as mkdirSync3 } from "node:fs";
643
+ import path7 from "node:path";
643
644
 
644
645
  // src/prompt.ts
645
646
  function buildPrompt(input) {
@@ -699,11 +700,44 @@ var claudeProvider = {
699
700
  };
700
701
 
701
702
  // src/providers/cursor.ts
702
- import { closeSync as closeSync2, openSync as openSync2 } from "node:fs";
703
+ import { closeSync as closeSync2, existsSync as existsSync6, openSync as openSync2, readdirSync as readdirSync2 } from "node:fs";
703
704
  import { spawn as spawn2 } from "node:child_process";
705
+ import path6 from "node:path";
704
706
  var DEFAULT_CURSOR_MODEL = "composer-2.5";
707
+ function latestVersionDir(versionsRoot) {
708
+ if (!existsSync6(versionsRoot)) return null;
709
+ const versions = readdirSync2(versionsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && /^\d{4}\.\d/.test(entry.name)).map((entry) => entry.name).sort((a, b) => b.localeCompare(a));
710
+ return versions[0] ? path6.join(versionsRoot, versions[0]) : null;
711
+ }
712
+ function resolveBundledCursor(versionDir) {
713
+ const nodeExe = path6.join(versionDir, "node.exe");
714
+ const indexJs = path6.join(versionDir, "index.js");
715
+ if (!existsSync6(nodeExe) || !existsSync6(indexJs)) return null;
716
+ return { executable: nodeExe, prefixArgs: [indexJs], shell: false, detached: true };
717
+ }
718
+ function resolveWindowsCursorSpawn(agentBin) {
719
+ const agentRoot = path6.dirname(agentBin);
720
+ const direct = resolveBundledCursor(agentRoot);
721
+ if (direct) return direct;
722
+ const versionDir = latestVersionDir(path6.join(agentRoot, "versions"));
723
+ return versionDir ? resolveBundledCursor(versionDir) : null;
724
+ }
725
+ function resolveCursorSpawn(agentBin) {
726
+ if (process.platform === "win32" && /\.(cmd|bat)$/i.test(agentBin)) {
727
+ const bundled = resolveWindowsCursorSpawn(agentBin);
728
+ if (bundled) return bundled;
729
+ return { executable: agentBin, prefixArgs: [], shell: true, detached: false };
730
+ }
731
+ return { executable: agentBin, prefixArgs: [], shell: false, detached: true };
732
+ }
705
733
  function resolveAgentBin() {
706
- return process.env.KYNVER_CURSOR_AGENT_BIN?.trim() || process.env.CURSOR_AGENT_BIN?.trim() || "agent";
734
+ const configured = process.env.KYNVER_CURSOR_AGENT_BIN?.trim() || process.env.CURSOR_AGENT_BIN?.trim();
735
+ if (configured) return configured;
736
+ if (process.platform === "win32") {
737
+ const localAgent = path6.join(process.env.LOCALAPPDATA || "", "cursor-agent", "agent.cmd");
738
+ if (existsSync6(localAgent)) return localAgent;
739
+ }
740
+ return "agent";
707
741
  }
708
742
  var cursorProvider = {
709
743
  name: "cursor",
@@ -712,9 +746,11 @@ var cursorProvider = {
712
746
  const stdoutFd = openSync2(opts.stdoutPath, "a");
713
747
  const stderrFd = openSync2(opts.stderrPath, "a");
714
748
  const agentBin = resolveAgentBin();
749
+ const spawnTarget = resolveCursorSpawn(agentBin);
715
750
  const child = spawn2(
716
- agentBin,
751
+ spawnTarget.executable,
717
752
  [
753
+ ...spawnTarget.prefixArgs,
718
754
  "-p",
719
755
  "--force",
720
756
  "--trust",
@@ -729,9 +765,13 @@ var cursorProvider = {
729
765
  ],
730
766
  {
731
767
  cwd: opts.worktreePath,
732
- detached: true,
768
+ detached: spawnTarget.detached,
769
+ shell: spawnTarget.shell,
733
770
  stdio: ["ignore", stdoutFd, stderrFd],
734
- env: process.env
771
+ env: {
772
+ ...process.env,
773
+ ...spawnTarget.prefixArgs.length > 0 ? { CURSOR_INVOKED_AS: path6.basename(agentBin) } : {}
774
+ }
735
775
  }
736
776
  );
737
777
  closeSync2(stdoutFd);
@@ -769,16 +809,16 @@ function spawnWorkerProcess(run, opts) {
769
809
  if (run.workers?.[name]) throw new Error(`worker already exists in run ${run.id}: ${name}`);
770
810
  if (!opts.task) throw new Error(`missing task text for worker ${name}`);
771
811
  const { worktreesDir } = getPaths();
772
- const workerDir = path6.join(runDirectory(run.id), "workers", name);
812
+ const workerDir = path7.join(runDirectory(run.id), "workers", name);
773
813
  mkdirSync3(workerDir, { recursive: true });
774
- const worktreePath = path6.join(worktreesDir, run.id, name);
814
+ const worktreePath = path7.join(worktreesDir, run.id, name);
775
815
  const branch = opts.branch || `agent/${run.id}/${name}`;
776
- if (existsSync6(worktreePath)) throw new Error(`worktree path already exists: ${worktreePath}`);
816
+ if (existsSync7(worktreePath)) throw new Error(`worktree path already exists: ${worktreePath}`);
777
817
  git(run.repo, ["fetch", "origin", "--prune"], { allowFailure: true });
778
818
  git(run.repo, ["worktree", "add", "-b", branch, worktreePath, run.baseCommit], { throwError: true });
779
- const stdoutPath = path6.join(workerDir, "stdout.jsonl");
780
- const stderrPath = path6.join(workerDir, "stderr.log");
781
- const heartbeatPath = path6.join(workerDir, "heartbeat.jsonl");
819
+ const stdoutPath = path7.join(workerDir, "stdout.jsonl");
820
+ const stderrPath = path7.join(workerDir, "stderr.log");
821
+ const heartbeatPath = path7.join(workerDir, "heartbeat.jsonl");
782
822
  const prompt = buildPrompt({
783
823
  task: opts.task,
784
824
  ownedPaths: opts.ownedPaths || [],
@@ -827,7 +867,7 @@ function spawnWorkerProcess(run, opts) {
827
867
  startedAt: (/* @__PURE__ */ new Date()).toISOString()
828
868
  };
829
869
  saveWorker(run.id, worker);
830
- run.workers = { ...run.workers || {}, [name]: { workerDir, statusPath: path6.join(workerDir, "worker.json") } };
870
+ run.workers = { ...run.workers || {}, [name]: { workerDir, statusPath: path7.join(workerDir, "worker.json") } };
831
871
  run.status = "running";
832
872
  saveRun(run);
833
873
  return worker;
@@ -1023,7 +1063,7 @@ async function dispatchRun(args) {
1023
1063
  }
1024
1064
 
1025
1065
  // src/sweep.ts
1026
- import path7 from "node:path";
1066
+ import path8 from "node:path";
1027
1067
  async function sweepRun(args) {
1028
1068
  const pipeline = args.pipeline === true || args.pipeline === "true";
1029
1069
  try {
@@ -1035,7 +1075,7 @@ async function sweepRun(args) {
1035
1075
  const releasedLocalOrphans = [];
1036
1076
  for (const name of Object.keys(run.workers || {})) {
1037
1077
  const worker = readJson(
1038
- path7.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
1078
+ path8.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
1039
1079
  null
1040
1080
  );
1041
1081
  if (!worker || !worker.dispatched || !worker.taskId) continue;
@@ -1078,11 +1118,11 @@ async function sweepRun(args) {
1078
1118
  }
1079
1119
 
1080
1120
  // src/worktree.ts
1081
- import { existsSync as existsSync7, mkdirSync as mkdirSync4 } from "node:fs";
1082
- import path9 from "node:path";
1121
+ import { existsSync as existsSync8, mkdirSync as mkdirSync4 } from "node:fs";
1122
+ import path10 from "node:path";
1083
1123
 
1084
1124
  // src/validate.ts
1085
- import path8 from "node:path";
1125
+ import path9 from "node:path";
1086
1126
  var RUN_ID_RE = /^[a-z0-9][a-z0-9._-]{0,127}$/i;
1087
1127
  function validateRunId(runId) {
1088
1128
  const trimmed = runId.trim();
@@ -1090,7 +1130,7 @@ function validateRunId(runId) {
1090
1130
  return trimmed;
1091
1131
  }
1092
1132
  function validateRepo(repo) {
1093
- const resolved = path8.resolve(repo);
1133
+ const resolved = path9.resolve(repo);
1094
1134
  if (resolved.includes("..")) throw new Error("repo path must not contain .. segments");
1095
1135
  return resolved;
1096
1136
  }
@@ -1101,7 +1141,7 @@ function createRun(args) {
1101
1141
  ensureGitRepo(repo);
1102
1142
  const id = args.id ? validateRunId(String(args.id)) : timestampSlug(String(args.name || "run"));
1103
1143
  const dir = runDirectory(id);
1104
- if (existsSync7(dir)) failExists(`run already exists: ${id}`);
1144
+ if (existsSync8(dir)) failExists(`run already exists: ${id}`);
1105
1145
  mkdirSync4(dir, { recursive: true });
1106
1146
  const base = String(args.base || "origin/main");
1107
1147
  const baseCommit = git(repo, ["rev-parse", base]).trim();
@@ -1115,12 +1155,12 @@ function createRun(args) {
1115
1155
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
1116
1156
  workers: {}
1117
1157
  };
1118
- writeJson(path9.join(dir, "run.json"), run);
1158
+ writeJson(path10.join(dir, "run.json"), run);
1119
1159
  console.log(JSON.stringify({ runId: id, runDir: dir, repo, base, baseCommit }, null, 2));
1120
1160
  }
1121
1161
  function listRuns() {
1122
1162
  const { runsDir } = getPaths();
1123
- const rows = listRunIds(runsDir).map((id) => readJson(path9.join(runDirectory(id), "run.json"), null)).filter(Boolean).map((run) => ({
1163
+ const rows = listRunIds(runsDir).map((id) => readJson(path10.join(runDirectory(id), "run.json"), null)).filter(Boolean).map((run) => ({
1124
1164
  id: run.id,
1125
1165
  name: run.name,
1126
1166
  status: run.status,
@@ -1135,7 +1175,7 @@ function failExists(message) {
1135
1175
  }
1136
1176
 
1137
1177
  // src/worker-ops.ts
1138
- import path10 from "node:path";
1178
+ import path11 from "node:path";
1139
1179
  async function tryCompleteWorker(args) {
1140
1180
  const worker = loadWorker(String(args.run), String(args.name));
1141
1181
  const status = computeWorkerStatus(worker);
@@ -1228,7 +1268,7 @@ async function completeWorker(args) {
1228
1268
  function workerStatus(args) {
1229
1269
  const worker = loadWorker(String(args.run), String(args.name));
1230
1270
  const status = computeWorkerStatus(worker);
1231
- writeJson(path10.join(worker.workerDir, "last-status.json"), status);
1271
+ writeJson(path11.join(worker.workerDir, "last-status.json"), status);
1232
1272
  console.log(JSON.stringify(status, null, 2));
1233
1273
  }
1234
1274
  function runStatus(args) {
@@ -1236,7 +1276,7 @@ function runStatus(args) {
1236
1276
  const names = Object.keys(run.workers || {});
1237
1277
  const workers = names.map((name) => {
1238
1278
  const worker = readJson(
1239
- path10.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
1279
+ path11.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
1240
1280
  null
1241
1281
  );
1242
1282
  if (!worker) {
@@ -1268,7 +1308,7 @@ function runStatus(args) {
1268
1308
  needsAttention: workers.filter((w) => w.attention && w.attention !== "ok" && w.attention !== "done").map((w) => w.worker),
1269
1309
  workers
1270
1310
  };
1271
- writeJson(path10.join(runDirectory(run.id), "last-board.json"), board);
1311
+ writeJson(path11.join(runDirectory(run.id), "last-board.json"), board);
1272
1312
  console.log(JSON.stringify(board, null, 2));
1273
1313
  }
1274
1314
  function tailWorker(args) {
@@ -1301,7 +1341,7 @@ function stopWorker(args) {
1301
1341
  }
1302
1342
 
1303
1343
  // src/pipeline-tick.ts
1304
- import path11 from "node:path";
1344
+ import path12 from "node:path";
1305
1345
 
1306
1346
  // src/workspace-runtime-config.ts
1307
1347
  async function fetchWorkspaceRuntimePreferences(agentOsId, args) {
@@ -1330,7 +1370,7 @@ async function completeFinishedWorkers(runId, args) {
1330
1370
  const outcomes = [];
1331
1371
  for (const name of Object.keys(run.workers || {})) {
1332
1372
  const worker = readJson(
1333
- path11.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
1373
+ path12.join(runDirectory(run.id), "workers", safeSlug(name), "worker.json"),
1334
1374
  null
1335
1375
  );
1336
1376
  if (!worker?.dispatched || !worker.taskId) continue;
@@ -1509,7 +1549,7 @@ async function main(argv = process.argv.slice(2)) {
1509
1549
  if (scope === "worker" && action === "complete") return void await completeWorker(args);
1510
1550
  unknownCommand(scope, action);
1511
1551
  }
1512
- var isCliEntry = process.argv[1] && path12.resolve(process.argv[1]) === path12.resolve(fileURLToPath(import.meta.url));
1552
+ var isCliEntry = process.argv[1] && path13.resolve(process.argv[1]) === path13.resolve(fileURLToPath(import.meta.url));
1513
1553
  if (isCliEntry) {
1514
1554
  void main().catch((error) => {
1515
1555
  console.error(error);