@standardagents/code 0.11.7 → 0.11.9

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/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import os8, { homedir } from 'os';
3
3
  import path4 from 'path';
4
- import readline2 from 'readline/promises';
4
+ import readline3 from 'readline/promises';
5
5
  import { stdout, stdin } from 'process';
6
6
  import net from 'net';
7
7
  import fs5 from 'fs';
@@ -938,6 +938,7 @@ var TunnelManager = class {
938
938
  let opened = false;
939
939
  const socket = net.connect({ host, port });
940
940
  socket.setNoDelay(true);
941
+ socket.setKeepAlive(true, 15e3);
941
942
  this.tunnels.set(id, { socket });
942
943
  socket.on("connect", () => {
943
944
  opened = true;
@@ -6490,7 +6491,7 @@ function readVersion() {
6490
6491
  if (typeof pkg.version === "string" && pkg.version) return pkg.version;
6491
6492
  } catch {
6492
6493
  }
6493
- return "0.11.7" ;
6494
+ return "0.11.9" ;
6494
6495
  }
6495
6496
  function isLocalHost(host) {
6496
6497
  return host === "localhost" || host === "127.0.0.1" || host === "::1" || host.endsWith(".local") || host.endsWith(".localhost") || /^10\./.test(host) || /^192\.168\./.test(host) || /^172\.(1[6-9]|2\d|3[01])\./.test(host);
@@ -6605,6 +6606,13 @@ async function readFsResponse(api, machineId) {
6605
6606
  async function readFsRequest(api, machineId) {
6606
6607
  return parseFsRequest(await api.userKvGet(fsRequestKey(machineId)));
6607
6608
  }
6609
+ var FS_POLL_HOT_MS = 1e3;
6610
+ var FS_POLL_IDLE_MS = 5e3;
6611
+ var FS_HOT_WINDOW_MS = 5 * 6e4;
6612
+ function fsPollDelay(lastRequestSeenAt, now) {
6613
+ if (lastRequestSeenAt !== null && now - lastRequestSeenAt < FS_HOT_WINDOW_MS) return FS_POLL_HOT_MS;
6614
+ return FS_POLL_IDLE_MS;
6615
+ }
6608
6616
  async function writeFsResponse(api, machineId, res) {
6609
6617
  await api.userKvSet(fsResponseKey(machineId), { ...res, responded_at: Date.now() });
6610
6618
  }
@@ -6879,16 +6887,16 @@ async function clearMachineCommands(api, machineId, appliedIds) {
6879
6887
  async function applyMachineCommand(api, identity, cmd) {
6880
6888
  switch (cmd.kind) {
6881
6889
  case "add_project": {
6882
- const path15 = typeof cmd.args?.path === "string" ? cmd.args.path : "";
6883
- if (!path15) return "add_project: ignored (no path)";
6884
- await registerProject(api, identity, path15);
6885
- return `added project ${path15}`;
6890
+ const path16 = typeof cmd.args?.path === "string" ? cmd.args.path : "";
6891
+ if (!path16) return "add_project: ignored (no path)";
6892
+ await registerProject(api, identity, path16);
6893
+ return `added project ${path16}`;
6886
6894
  }
6887
6895
  case "remove_project": {
6888
- const path15 = typeof cmd.args?.path === "string" ? cmd.args.path : "";
6889
- if (!path15) return "remove_project: ignored (no path)";
6890
- await unregisterProject(api, identity, path15);
6891
- return `removed project ${path15}`;
6896
+ const path16 = typeof cmd.args?.path === "string" ? cmd.args.path : "";
6897
+ if (!path16) return "remove_project: ignored (no path)";
6898
+ await unregisterProject(api, identity, path16);
6899
+ return `removed project ${path16}`;
6892
6900
  }
6893
6901
  case "update":
6894
6902
  return "update requested";
@@ -7516,7 +7524,6 @@ function runUpdate(pm) {
7516
7524
  // src/daemon.ts
7517
7525
  var HEARTBEAT_MS = 3e4;
7518
7526
  var COMMAND_POLL_MS = 8e3;
7519
- var FS_POLL_MS = 1e3;
7520
7527
  var RECLAIM_PROBE_MS = 2 * 6e4;
7521
7528
  var UPDATE_CHECK_MS = 6 * 60 * 6e4;
7522
7529
  var SWEEP_MS = 10 * 6e4;
@@ -7867,12 +7874,14 @@ Run \`standardcode daemon install\` (or plain \`standardcode\`) once to sign in.
7867
7874
  void drainCommands();
7868
7875
  const commandTimer = setInterval(() => void drainCommands(), COMMAND_POLL_MS);
7869
7876
  let lastFsNonce = null;
7877
+ let lastFsRequestSeenAt = null;
7870
7878
  let fsBusy = false;
7871
7879
  const drainFsRequests = async () => {
7872
7880
  if (fsBusy) return;
7873
7881
  fsBusy = true;
7874
7882
  try {
7875
7883
  const req = await readFsRequest(api, identity.machine_id).catch(() => null);
7884
+ if (req) lastFsRequestSeenAt = Math.max(lastFsRequestSeenAt ?? 0, req.requested_at);
7876
7885
  if (!req || req.nonce === lastFsNonce) return;
7877
7886
  lastFsNonce = req.nonce;
7878
7887
  let ok = true;
@@ -7890,7 +7899,15 @@ Run \`standardcode daemon install\` (or plain \`standardcode\`) once to sign in.
7890
7899
  fsBusy = false;
7891
7900
  }
7892
7901
  };
7893
- const fsTimer = setInterval(() => void drainFsRequests(), FS_POLL_MS);
7902
+ let fsTimer = null;
7903
+ let fsStopped = false;
7904
+ const scheduleFsPoll = () => {
7905
+ if (fsStopped) return;
7906
+ fsTimer = setTimeout(() => {
7907
+ void drainFsRequests().finally(scheduleFsPoll);
7908
+ }, fsPollDelay(lastFsRequestSeenAt, Date.now()));
7909
+ };
7910
+ scheduleFsPoll();
7894
7911
  const sweeper = setInterval(() => {
7895
7912
  if (updateReady && ![...workers.values()].some((w) => w.busy)) {
7896
7913
  daemonLog("restarting to apply the installed update");
@@ -7904,7 +7921,8 @@ Run \`standardcode daemon install\` (or plain \`standardcode\`) once to sign in.
7904
7921
  clearInterval(reclaim);
7905
7922
  clearInterval(updateTimer);
7906
7923
  clearInterval(commandTimer);
7907
- clearInterval(fsTimer);
7924
+ fsStopped = true;
7925
+ if (fsTimer) clearTimeout(fsTimer);
7908
7926
  clearInterval(sweeper);
7909
7927
  for (const worker of workers.values()) worker.stop();
7910
7928
  events.close();
@@ -8181,7 +8199,7 @@ async function installCommand(endpointFlag) {
8181
8199
  const identity = loadMachineIdentity();
8182
8200
  const existing = await loadMachine(api, identity.machine_id).catch(() => null);
8183
8201
  const suggested = machineDisplayName(existing ?? { hostname: os8.hostname(), id: identity.machine_id });
8184
- const rl = readline2.createInterface({ input: stdin, output: stdout });
8202
+ const rl = readline3.createInterface({ input: stdin, output: stdout });
8185
8203
  const answer = (await rl.question(
8186
8204
  `${c3.bold}Machine name${c3.reset} ${c3.dim}(shown in the session picker)${c3.reset} [${suggested}]: `
8187
8205
  )).trim();
@@ -8339,6 +8357,29 @@ async function runDaemonCommand(argv) {
8339
8357
  }
8340
8358
  }
8341
8359
  }
8360
+ var DIR2 = path4.join(os8.homedir(), ".standardagents");
8361
+ var FILE2 = path4.join(DIR2, "prefs.json");
8362
+ function loadPrefs(file2 = FILE2) {
8363
+ try {
8364
+ return JSON.parse(fs5.readFileSync(file2, "utf8"));
8365
+ } catch {
8366
+ return {};
8367
+ }
8368
+ }
8369
+ function savePrefs(update, file2 = FILE2) {
8370
+ const merged = { ...loadPrefs(file2), ...update };
8371
+ fs5.mkdirSync(path4.dirname(file2), { recursive: true });
8372
+ fs5.writeFileSync(file2, JSON.stringify(merged, null, 2));
8373
+ }
8374
+ function shouldOfferDaemonInstall(facts) {
8375
+ if (facts.optedOutEnv) return false;
8376
+ if (!facts.interactive) return false;
8377
+ if (facts.platform === "win32") return false;
8378
+ if (facts.serviceInstalled) return false;
8379
+ if (facts.daemonOnline) return false;
8380
+ if (facts.declinedAt !== void 0) return false;
8381
+ return true;
8382
+ }
8342
8383
 
8343
8384
  // src/auth-cli.ts
8344
8385
  var c4 = {
@@ -8729,7 +8770,7 @@ ${c5.dim}Press Control-C again to exit${c5.reset}
8729
8770
  };
8730
8771
  const ask = async (question) => {
8731
8772
  if (!reader.rl) {
8732
- reader.rl = readline2.createInterface({ input: stdin, output: stdout });
8773
+ reader.rl = readline3.createInterface({ input: stdin, output: stdout });
8733
8774
  reader.rl.on("SIGINT", onPreflightSigint);
8734
8775
  reader.rl.on("close", () => {
8735
8776
  if (handoffClosing) return;
@@ -8912,6 +8953,42 @@ ${c5.dim}Press Control-C again to exit${c5.reset}
8912
8953
  session.suggestDaemonInstall = machines.every((m) => !m.daemon);
8913
8954
  const remoteTargets = machines.filter((m) => m.id !== identity.machine_id && daemonOnline(m));
8914
8955
  const self = machines.find((m) => m.id === identity.machine_id);
8956
+ if (shouldOfferDaemonInstall({
8957
+ platform: process.platform,
8958
+ interactive: Boolean(stdin.isTTY && stdout.isTTY),
8959
+ serviceInstalled: serviceStatus().installed,
8960
+ daemonOnline: Boolean(self && daemonOnline(self)),
8961
+ declinedAt: loadPrefs().daemon_install_declined_at,
8962
+ optedOutEnv: Boolean(process.env.STANDARD_CODE_NO_DAEMON_PROMPT)
8963
+ })) {
8964
+ stdout.write(
8965
+ `
8966
+ ${c5.bold}This machine has no always-on daemon${c5.reset} ${c5.dim}\u2014 sessions stop when this terminal closes.${c5.reset}
8967
+ `
8968
+ );
8969
+ const promptRl = readline3.createInterface({ input: stdin, output: stdout });
8970
+ let answer = "";
8971
+ try {
8972
+ answer = (await promptRl.question(
8973
+ `${c5.white}Install it now so sessions keep running and start from anywhere?${c5.reset} ${c5.dim}[Y/n]${c5.reset} `
8974
+ )).trim().toLowerCase();
8975
+ } catch {
8976
+ answer = "n";
8977
+ } finally {
8978
+ promptRl.close();
8979
+ }
8980
+ if (answer === "" || answer === "y" || answer === "yes") {
8981
+ await runDaemonCommand(endpointOverride ? ["install", "--endpoint", endpoint] : ["install"]);
8982
+ stdout.write("\n");
8983
+ } else {
8984
+ savePrefs({ daemon_install_declined_at: Date.now() });
8985
+ stdout.write(
8986
+ `${c5.dim}Okay \u2014 \`standardcode daemon install\` sets it up any time.${c5.reset}
8987
+
8988
+ `
8989
+ );
8990
+ }
8991
+ }
8915
8992
  const launchDir = projectDir;
8916
8993
  let tags = [];
8917
8994
  let resumeTags = [];