@alook/daemon 0.1.46 → 0.1.48

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.
Files changed (3) hide show
  1. package/dist/cli/index.js +488 -354
  2. package/dist/index.js +436 -318
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -174,6 +174,18 @@ function resolveLaunchFieldsOrDefault(input) {
174
174
  // agent-driver/dist/internal/cliLink.js
175
175
  import * as fs from "fs";
176
176
  import * as path from "path";
177
+ function shellQuote(value) {
178
+ return `'${value.replaceAll("'", "'\\''")}'`;
179
+ }
180
+ function writeWindowsBashEnv(binDir, cliName, envPrefix, previous) {
181
+ const startup = path.join(binDir, `${cliName}.bash-env`).replaceAll("\\", "/");
182
+ const envValue = startup.replace(/[$`]/g, "\\$&");
183
+ const source = previous && previous !== envValue && previous.replaceAll("\\", "/") !== startup ? `. ${shellQuote(previous.replaceAll("\\", "/"))}
184
+ ` : "";
185
+ fs.writeFileSync(startup, source + `export ${shellQuote(`${envPrefix}_CLI=${path.join(binDir, cliName).replaceAll("\\", "/")}`)}
186
+ `);
187
+ return envValue;
188
+ }
177
189
  function writeCliLink(stateDir, cliName, hostCliPath, platform = process.platform) {
178
190
  const binDir = path.join(stateDir, "bin");
179
191
  fs.mkdirSync(binDir, { recursive: true });
@@ -181,10 +193,15 @@ function writeCliLink(stateDir, cliName, hostCliPath, platform = process.platfor
181
193
  return binDir;
182
194
  if (platform === "win32") {
183
195
  const cmdFile = path.join(binDir, `${cliName}.cmd`);
196
+ const executable = /\.(?:c|m)?js$/i.test(hostCliPath) ? `"${process.execPath}" "${hostCliPath}"` : `"${hostCliPath}"`;
184
197
  const body = `@echo off\r
185
- "${hostCliPath}" %*\r
198
+ ${executable} %*\r
186
199
  `;
187
200
  fs.writeFileSync(cmdFile, body);
201
+ const bashExecutable = /\.(?:c|m)?js$/i.test(hostCliPath) ? `${shellQuote(process.execPath.replaceAll("\\", "/"))} ${shellQuote(hostCliPath.replaceAll("\\", "/"))}` : shellQuote(hostCliPath.replaceAll("\\", "/"));
202
+ fs.writeFileSync(path.join(binDir, cliName), `#!/bin/sh
203
+ MSYS2_ARG_CONV_EXCL='*' exec ${bashExecutable} "$@"
204
+ `, { mode: 493 });
188
205
  return binDir;
189
206
  }
190
207
  const linkPath = path.join(binDir, cliName);
@@ -252,7 +269,12 @@ async function prepareCliTransport(ctx, extraEnv = {}, cli = DEFAULT_CLI_CONFIG,
252
269
  {
253
270
  name: "platformProtected",
254
271
  precedence: 40,
255
- vars: { ...resource.platformProtected, FORCE_COLOR: "0", NO_COLOR: "1" }
272
+ vars: {
273
+ ...resource.platformProtected,
274
+ ...platform === "win32" && hostCliPath ? { [`${cli.envPrefix}_CLI`]: path2.join(binDir, `${cli.cliName}.cmd`).replaceAll("\\", "/") } : {},
275
+ FORCE_COLOR: "0",
276
+ NO_COLOR: "1"
277
+ }
256
278
  },
257
279
  { name: "runtimeProtected", precedence: 50, vars: resource.runtimeProtected },
258
280
  {
@@ -269,15 +291,143 @@ async function prepareCliTransport(ctx, extraEnv = {}, cli = DEFAULT_CLI_CONFIG,
269
291
  }
270
292
  ];
271
293
  const { env: spawnEnv } = mergeEnvLayers(resource.base, layers);
294
+ if (platform === "win32" && hostCliPath) {
295
+ spawnEnv.BASH_ENV = writeWindowsBashEnv(binDir, cli.cliName, cli.envPrefix, spawnEnv.BASH_ENV);
296
+ }
272
297
  const tokenFile = String(resource.credentialSensitive.ALOOK_PROXY_TOKEN_FILE ?? "");
273
298
  return { stateDir, tokenFile, spawnEnv };
274
299
  }
275
300
 
276
301
  // agent-driver/dist/internal/killTree.js
277
- import { execFileSync, spawn } from "child_process";
302
+ import { execFileSync as execFileSync2, spawn } from "child_process";
278
303
  import { randomUUID as randomUUID2 } from "node:crypto";
279
304
  import { createServer } from "node:net";
280
305
  import { PassThrough } from "node:stream";
306
+
307
+ // agent-driver/dist/internal/probe.js
308
+ import { execFileSync } from "child_process";
309
+ import * as fs3 from "fs";
310
+ import * as path3 from "path";
311
+ import { homedir } from "os";
312
+ var PROBE_TIMEOUT_MS = 5000;
313
+ var PROBE_OUTPUT_MAX_BYTES = 1024 * 1024;
314
+ function resolveCommandOnPath(command, deps = {}) {
315
+ if (deps.which)
316
+ return deps.which(command);
317
+ try {
318
+ if (process.platform === "win32") {
319
+ const out2 = execFileSync("where", [command], { encoding: "utf8", timeout: PROBE_TIMEOUT_MS });
320
+ const first = out2.split(/\r?\n/).map((line) => line.trim()).find((line) => /\.(exe|com|cmd|bat)$/i.test(line));
321
+ return first || null;
322
+ }
323
+ const out = execFileSync("which", [command], { encoding: "utf8", timeout: PROBE_TIMEOUT_MS });
324
+ return out.trim() || null;
325
+ } catch {
326
+ return null;
327
+ }
328
+ }
329
+ function firstExistingPath(candidates) {
330
+ for (const c of candidates) {
331
+ if (c && fs3.existsSync(c))
332
+ return c;
333
+ }
334
+ return null;
335
+ }
336
+ function looksLikeVersion(line) {
337
+ return /\d+\.\d+/.test(line);
338
+ }
339
+ function needsWindowsShimShell(command, platform) {
340
+ return platform === "win32" && /\.(cmd|bat)$/i.test(command);
341
+ }
342
+ function quoteWindowsShimCommand(command, platform = process.platform) {
343
+ return needsWindowsShimShell(command, platform) && /\s/.test(command) ? `"${command}"` : command;
344
+ }
345
+ function probeCommandVersion(command, args = [], deps = {}, platform = process.platform) {
346
+ try {
347
+ const shell = needsWindowsShimShell(command, platform);
348
+ const out = execFileSync(quoteWindowsShimCommand(command, platform), [...args, "--version"], {
349
+ encoding: "utf8",
350
+ timeout: PROBE_TIMEOUT_MS,
351
+ shell,
352
+ input: "",
353
+ env: { ...process.env, CI: "1" }
354
+ });
355
+ const line = out.split(`
356
+ `)[0]?.trim();
357
+ if (!line)
358
+ return { ok: false, error: "empty_version_output" };
359
+ if (!looksLikeVersion(line))
360
+ return { ok: false, error: "invalid_version_output" };
361
+ return { ok: true, version: line };
362
+ } catch (err) {
363
+ const code = err?.code ?? err?.code ?? "version_probe_failed";
364
+ return { ok: false, error: String(code) };
365
+ }
366
+ }
367
+ function probeCommandOutput(command, args, platform = process.platform) {
368
+ try {
369
+ const output = execFileSync(quoteWindowsShimCommand(command, platform), args, {
370
+ encoding: "utf8",
371
+ timeout: PROBE_TIMEOUT_MS,
372
+ maxBuffer: PROBE_OUTPUT_MAX_BYTES,
373
+ shell: needsWindowsShimShell(command, platform),
374
+ stdio: ["pipe", "pipe", "ignore"],
375
+ input: "",
376
+ env: { ...process.env, CI: "1" }
377
+ });
378
+ return { ok: true, output };
379
+ } catch (err) {
380
+ const code = err?.code ?? "command_probe_failed";
381
+ return { ok: false, error: String(code) };
382
+ }
383
+ }
384
+ function resolveHomePath(relativePath, deps = {}) {
385
+ return path3.join(deps.homeDir || process.env.HOME || ".", relativePath);
386
+ }
387
+ function resolveSpawnSpec(command, args, override, deps = {}, platform = process.platform) {
388
+ const trimmed = override?.trim();
389
+ const target = trimmed && trimmed.length > 0 ? trimmed : command;
390
+ const looksLikePath = trimmed !== undefined && trimmed.length > 0 && /[\\/]/.test(trimmed);
391
+ const resolved = looksLikePath ? target : resolveCommandOnPath(target, deps) ?? target;
392
+ return { command: resolved, args, shell: needsWindowsShimShell(resolved, platform) };
393
+ }
394
+ function resolveClaudeCommand(deps = {}) {
395
+ const onPath = resolveCommandOnPath("claude", deps);
396
+ if (onPath)
397
+ return onPath;
398
+ if (process.platform === "win32") {
399
+ const home = deps.homeDir || process.env.USERPROFILE || process.env.HOME || homedir();
400
+ return firstExistingPath([path3.join(home, ".local", "bin", "claude.exe")]);
401
+ }
402
+ if (process.platform === "darwin") {
403
+ return firstExistingPath([
404
+ resolveHomePath("Applications/Claude Code URL Handler.app/Contents/MacOS/claude", deps),
405
+ "/Applications/Claude Code URL Handler.app/Contents/MacOS/claude"
406
+ ]);
407
+ }
408
+ return null;
409
+ }
410
+ function probeClaude(deps = {}) {
411
+ const command = resolveClaudeCommand(deps);
412
+ if (!command)
413
+ return { status: "unhealthy", lastError: "not_on_path" };
414
+ const r = probeCommandVersion(command, [], deps);
415
+ if (!r.ok)
416
+ return { status: "unhealthy", lastError: r.error };
417
+ return { status: "healthy", version: r.version };
418
+ }
419
+ function probeCliRuntime(binary, deps = {}, override) {
420
+ const explicit = override?.trim();
421
+ const command = explicit || resolveCommandOnPath(binary, deps);
422
+ if (!command)
423
+ return { status: "unhealthy", lastError: "not_on_path" };
424
+ const r = probeCommandVersion(command, [], deps);
425
+ if (!r.ok)
426
+ return { status: "unhealthy", lastError: r.error };
427
+ return { status: "healthy", version: r.version };
428
+ }
429
+
430
+ // agent-driver/dist/internal/killTree.js
281
431
  var POLL_MS = 100;
282
432
  var FORCE_EXIT_WAIT_MS = 2000;
283
433
  var TASKKILL_WAIT_MS = 2000;
@@ -627,7 +777,7 @@ function spawnAgentProcess(command, args, opts) {
627
777
  const env = {
628
778
  ...opts.env,
629
779
  [WINDOWS_JOB_NODE_ENV]: process.execPath,
630
- [WINDOWS_JOB_PAYLOAD_ENV]: Buffer.from(JSON.stringify({ command, args, cwd: opts.cwd, shell: opts.shell ?? false })).toString("base64"),
780
+ [WINDOWS_JOB_PAYLOAD_ENV]: Buffer.from(JSON.stringify({ command: opts.shell ? quoteWindowsShimCommand(command) : command, args, cwd: opts.cwd, shell: opts.shell ?? false })).toString("base64"),
631
781
  [WINDOWS_JOB_RUNNER_ENV]: WINDOWS_JOB_RUNNER,
632
782
  ...stdinPipe ? { [WINDOWS_JOB_STDIN_PIPE_ENV]: stdinPipe } : {}
633
783
  };
@@ -689,7 +839,7 @@ function capturePosixTreeTargets(rootPid, rootOwnsProcessGroup) {
689
839
  });
690
840
  let output;
691
841
  try {
692
- output = execFileSync("ps", ["-axo", "pid=,ppid=,pgid="], {
842
+ output = execFileSync2("ps", ["-axo", "pid=,ppid=,pgid="], {
693
843
  encoding: "utf8",
694
844
  timeout: POSIX_TREE_CAPTURE_TIMEOUT_MS,
695
845
  maxBuffer: POSIX_TREE_CAPTURE_MAX_BUFFER
@@ -753,6 +903,9 @@ function signalPosixTargets(targets, signal) {
753
903
  } catch {}
754
904
  }
755
905
  }
906
+
907
+ class WindowsTreeExitError extends Error {
908
+ }
756
909
  function taskkillTree(pid) {
757
910
  return new Promise((resolve, reject) => {
758
911
  const killer = spawn("taskkill.exe", ["/pid", String(pid), "/t", "/f"], {
@@ -783,17 +936,24 @@ function taskkillTree(pid) {
783
936
  settle("resolve");
784
937
  return;
785
938
  }
786
- settle("reject", new Error(`Windows process-tree termination failed (exit=${String(code)}, signal=${String(signal)})`));
939
+ settle("reject", new WindowsTreeExitError(`Windows process-tree termination failed (exit=${String(code)}, signal=${String(signal)})`));
787
940
  });
788
941
  });
789
942
  }
790
943
  async function killWindowsProcessTree(pid) {
791
944
  if (!isAlive(pid))
792
945
  return;
793
- await taskkillTree(pid);
946
+ let terminationError;
947
+ try {
948
+ await taskkillTree(pid);
949
+ } catch (error) {
950
+ if (!(error instanceof WindowsTreeExitError))
951
+ throw error;
952
+ terminationError = error;
953
+ }
794
954
  await waitForProcessExit(pid, FORCE_EXIT_WAIT_MS);
795
955
  if (isAlive(pid))
796
- throw new Error(`Windows process tree ${pid} remained alive after taskkill completed`);
956
+ throw terminationError ?? new Error(`Windows process tree ${pid} remained alive after taskkill completed`);
797
957
  }
798
958
  async function waitForProcessExit(pid, timeoutMs) {
799
959
  const deadline = Date.now() + timeoutMs;
@@ -836,8 +996,8 @@ async function killProcessTree(pid, opts) {
836
996
 
837
997
  // agent-driver/dist/adapters/antigravity/usage.js
838
998
  import { createHash } from "node:crypto";
839
- import { homedir } from "node:os";
840
- import { resolve, join as join3 } from "node:path";
999
+ import { homedir as homedir2 } from "node:os";
1000
+ import { resolve, join as join4 } from "node:path";
841
1001
 
842
1002
  // agent-driver/dist/adapters/antigravity/local-data.js
843
1003
  async function readLocalCommand(command, args, limit = 256 * 1024) {
@@ -935,7 +1095,7 @@ function parseNativeGeneration(data) {
935
1095
  return { usage: { input: count(usage, 2), output: count(usage, 3), cache: count(usage, 5) }, occurredAt };
936
1096
  }
937
1097
  function nativeUsageHome(env, cwd) {
938
- return resolve(cwd, env.GEMINI_HOME?.replace(/^~(?=[/\\]|$)/, homedir()) || join3(homedir(), ".gemini"));
1098
+ return resolve(cwd, env.GEMINI_HOME?.replace(/^~(?=[/\\]|$)/, homedir2()) || join4(homedir2(), ".gemini"));
939
1099
  }
940
1100
  var QUERY = "WITH pending AS (SELECT idx,data FROM gen_metadata WHERE idx>? ORDER BY idx LIMIT 128), batch AS (SELECT idx,data,sum(length(data)) OVER (ORDER BY idx) AS bytes FROM pending) SELECT idx,hex(substr(data,1,4194305)) AS data,(SELECT COUNT(*) FROM steps WHERE has_subtrajectory=1) AS has_children FROM batch WHERE bytes<=4194304 OR idx=(SELECT min(idx) FROM batch) ORDER BY idx";
941
1101
 
@@ -953,12 +1113,12 @@ class NativeUsageReader {
953
1113
  throw new Error("Invalid native usage session identity");
954
1114
  }
955
1115
  async read() {
956
- const path3 = join3(this.home, "antigravity-acp", "conversations", `${this.sessionId}.db`);
1116
+ const path4 = join4(this.home, "antigravity-acp", "conversations", `${this.sessionId}.db`);
957
1117
  let cursor = this.cursor;
958
1118
  let complete = false;
959
1119
  const result = [];
960
1120
  for (let batch = 0;batch < 16; batch++) {
961
- const rows = await this.readRows(path3, cursor);
1121
+ const rows = await this.readRows(path4, cursor);
962
1122
  for (const row of rows) {
963
1123
  if (!Number.isSafeInteger(row.idx) || row.idx <= cursor || !/^(?:[a-f0-9]{2})*$/i.test(row.data) || row.data.length > 8 * 1024 * 1024)
964
1124
  throw new Error("Invalid native usage row");
@@ -979,11 +1139,11 @@ class NativeUsageReader {
979
1139
  return { samples: result, complete, ...this.childTrajectories ? { incompleteScope: true } : {} };
980
1140
  }
981
1141
  }
982
- async function queryNativeRowsWithCli(path3, cursor) {
983
- const output = await readLocalCommand("sqlite3", ["-readonly", "-json", path3, QUERY.replace("idx>?", `idx>${cursor}`)], 16 * 1024 * 1024);
1142
+ async function queryNativeRowsWithCli(path4, cursor) {
1143
+ const output = await readLocalCommand("sqlite3", ["-readonly", "-json", path4, QUERY.replace("idx>?", `idx>${cursor}`)], 16 * 1024 * 1024);
984
1144
  return output.trim() ? JSON.parse(output) : [];
985
1145
  }
986
- async function queryNativeRows(path3, cursor, loadSqlite = async () => {
1146
+ async function queryNativeRows(path4, cursor, loadSqlite = async () => {
987
1147
  const module = "node:sqlite";
988
1148
  return await import(module);
989
1149
  }) {
@@ -991,9 +1151,9 @@ async function queryNativeRows(path3, cursor, loadSqlite = async () => {
991
1151
  try {
992
1152
  sqlite = await loadSqlite();
993
1153
  } catch {
994
- return queryNativeRowsWithCli(path3, cursor);
1154
+ return queryNativeRowsWithCli(path4, cursor);
995
1155
  }
996
- const db = new sqlite.DatabaseSync(path3, { readOnly: true });
1156
+ const db = new sqlite.DatabaseSync(path4, { readOnly: true });
997
1157
  try {
998
1158
  return db.prepare(QUERY).all(cursor);
999
1159
  } finally {
@@ -1881,132 +2041,15 @@ class AntigravityAcpLane {
1881
2041
  // agent-driver/dist/adapters/antigravity/probe.js
1882
2042
  import { createHash as createHash2, randomUUID as randomUUID4 } from "node:crypto";
1883
2043
  import { mkdirSync as mkdirSync2, readFileSync, renameSync, writeFileSync as writeFileSync2 } from "node:fs";
1884
- import { homedir as homedir2 } from "node:os";
2044
+ import { homedir as homedir3 } from "node:os";
1885
2045
  import { join as join5 } from "node:path";
1886
-
1887
- // agent-driver/dist/internal/probe.js
1888
- import { execFileSync as execFileSync2 } from "child_process";
1889
- import * as fs3 from "fs";
1890
- import * as path3 from "path";
1891
- var PROBE_TIMEOUT_MS = 5000;
1892
- var PROBE_OUTPUT_MAX_BYTES = 1024 * 1024;
1893
- function resolveCommandOnPath(command, deps = {}) {
1894
- if (deps.which)
1895
- return deps.which(command);
1896
- try {
1897
- if (process.platform === "win32") {
1898
- const out2 = execFileSync2("where", [command], { encoding: "utf8", timeout: PROBE_TIMEOUT_MS });
1899
- const first = out2.split(/\r?\n/).find((line) => line.trim().length > 0);
1900
- return first?.trim() || null;
1901
- }
1902
- const out = execFileSync2("which", [command], { encoding: "utf8", timeout: PROBE_TIMEOUT_MS });
1903
- return out.trim() || null;
1904
- } catch {
1905
- return null;
1906
- }
1907
- }
1908
- function firstExistingPath(candidates) {
1909
- for (const c of candidates) {
1910
- if (c && fs3.existsSync(c))
1911
- return c;
1912
- }
1913
- return null;
1914
- }
1915
- function looksLikeVersion(line) {
1916
- return /\d+\.\d+/.test(line);
1917
- }
1918
- function needsWindowsShimShell(command, platform) {
1919
- return platform === "win32" && /\.(cmd|bat)$/i.test(command);
1920
- }
1921
- function probeCommandVersion(command, args = [], deps = {}, platform = process.platform) {
1922
- try {
1923
- const shell = needsWindowsShimShell(command, platform);
1924
- const out = execFileSync2(command, [...args, "--version"], {
1925
- encoding: "utf8",
1926
- timeout: PROBE_TIMEOUT_MS,
1927
- shell,
1928
- input: "",
1929
- env: { ...process.env, CI: "1" }
1930
- });
1931
- const line = out.split(`
1932
- `)[0]?.trim();
1933
- if (!line)
1934
- return { ok: false, error: "empty_version_output" };
1935
- if (!looksLikeVersion(line))
1936
- return { ok: false, error: "invalid_version_output" };
1937
- return { ok: true, version: line };
1938
- } catch (err) {
1939
- const code = err?.code ?? err?.code ?? "version_probe_failed";
1940
- return { ok: false, error: String(code) };
1941
- }
1942
- }
1943
- function probeCommandOutput(command, args, platform = process.platform) {
1944
- try {
1945
- const output = execFileSync2(command, args, {
1946
- encoding: "utf8",
1947
- timeout: PROBE_TIMEOUT_MS,
1948
- maxBuffer: PROBE_OUTPUT_MAX_BYTES,
1949
- shell: needsWindowsShimShell(command, platform),
1950
- stdio: ["pipe", "pipe", "ignore"],
1951
- input: "",
1952
- env: { ...process.env, CI: "1" }
1953
- });
1954
- return { ok: true, output };
1955
- } catch (err) {
1956
- const code = err?.code ?? "command_probe_failed";
1957
- return { ok: false, error: String(code) };
1958
- }
1959
- }
1960
- function resolveHomePath(relativePath, deps = {}) {
1961
- return path3.join(deps.homeDir || process.env.HOME || ".", relativePath);
1962
- }
1963
- function resolveSpawnSpec(command, args, override, deps = {}, platform = process.platform) {
1964
- const trimmed = override?.trim();
1965
- const target = trimmed && trimmed.length > 0 ? trimmed : command;
1966
- const looksLikePath = trimmed !== undefined && trimmed.length > 0 && /[\\/]/.test(trimmed);
1967
- const resolved = looksLikePath ? target : resolveCommandOnPath(target, deps) ?? target;
1968
- return { command: resolved, args, shell: needsWindowsShimShell(resolved, platform) };
1969
- }
1970
- function resolveClaudeCommand(deps = {}) {
1971
- const onPath = resolveCommandOnPath("claude", deps);
1972
- if (onPath)
1973
- return onPath;
1974
- if (process.platform === "darwin") {
1975
- return firstExistingPath([
1976
- resolveHomePath("Applications/Claude Code URL Handler.app/Contents/MacOS/claude", deps),
1977
- "/Applications/Claude Code URL Handler.app/Contents/MacOS/claude"
1978
- ]);
1979
- }
1980
- return null;
1981
- }
1982
- function probeClaude(deps = {}) {
1983
- const command = resolveClaudeCommand(deps);
1984
- if (!command)
1985
- return { status: "unhealthy", lastError: "not_on_path" };
1986
- const r = probeCommandVersion(command, [], deps);
1987
- if (!r.ok)
1988
- return { status: "unhealthy", lastError: r.error };
1989
- return { status: "healthy", version: r.version };
1990
- }
1991
- function probeCliRuntime(binary, deps = {}, override) {
1992
- const explicit = override?.trim();
1993
- const command = explicit || resolveCommandOnPath(binary, deps);
1994
- if (!command)
1995
- return { status: "unhealthy", lastError: "not_on_path" };
1996
- const r = probeCommandVersion(command, [], deps);
1997
- if (!r.ok)
1998
- return { status: "unhealthy", lastError: r.error };
1999
- return { status: "healthy", version: r.version };
2000
- }
2001
-
2002
- // agent-driver/dist/adapters/antigravity/probe.js
2003
2046
  function antigravitySpawnSpec(command, platform = process.platform) {
2004
2047
  return resolveSpawnSpec(platform === "win32" ? "agy_acp_server.exe" : "agy_acp_server.par", platform === "linux" ? ["--uid="] : [], command);
2005
2048
  }
2006
2049
  async function probeAntigravity(command, options = {}) {
2007
2050
  const spec = antigravitySpawnSpec(command);
2008
2051
  const identity = createHash2("sha256").update(JSON.stringify([spec.command, process.env.GEMINI_HOME ?? ""])).digest("hex").slice(0, 16);
2009
- const directory = options.cacheDirectory ?? join5(homedir2(), ".cache", "alook", "antigravity-probe", identity);
2052
+ const directory = options.cacheDirectory ?? join5(homedir3(), ".cache", "alook", "antigravity-probe", identity);
2010
2053
  const cacheFile = join5(directory, "session");
2011
2054
  let cachedSessionId;
2012
2055
  try {
@@ -2053,7 +2096,7 @@ async function probeAntigravity(command, options = {}) {
2053
2096
  cleanup(proc).then(() => resolve2(result), () => resolve2({ status: "unhealthy", lastError: "antigravity_acp_cleanup_failed" }));
2054
2097
  };
2055
2098
  const fail = (lastError) => finish({ status: "unhealthy", lastError });
2056
- const timer = setTimeout(() => fail("antigravity_acp_timeout"), options.timeoutMs ?? 1e4);
2099
+ const timer = setTimeout(() => fail("antigravity_acp_timeout"), options.timeoutMs ?? (process.platform === "win32" ? 30000 : 1e4));
2057
2100
  const write = (value) => {
2058
2101
  try {
2059
2102
  if (!proc.stdin || proc.stdin.destroyed || proc.stdin.writableEnded || proc.stdin.writable === false) {
@@ -2958,7 +3001,7 @@ class ClaudeTurnProtocol {
2958
3001
 
2959
3002
  // agent-driver/dist/adapters/claude/recent-context.js
2960
3003
  import { createReadStream as createReadStream2 } from "node:fs";
2961
- import { homedir as homedir3 } from "node:os";
3004
+ import { homedir as homedir4 } from "node:os";
2962
3005
  import path6 from "node:path";
2963
3006
  import { createInterface } from "node:readline";
2964
3007
 
@@ -3167,7 +3210,7 @@ async function discoverClaudeRecentContext(request, dependencies = {}) {
3167
3210
  const collector = new RecentContextCollector(request, "supported");
3168
3211
  if (collector.satisfied)
3169
3212
  return collector.result();
3170
- const projectsRoot = path6.resolve(dependencies.projectsRoot ?? path6.join(process.env.CLAUDE_CONFIG_DIR || path6.join(homedir3(), ".claude"), "projects"));
3213
+ const projectsRoot = path6.resolve(dependencies.projectsRoot ?? path6.join(process.env.CLAUDE_CONFIG_DIR || path6.join(homedir4(), ".claude"), "projects"));
3171
3214
  const readProjectPath = dependencies.readProjectPath ?? readClaudeProjectPath;
3172
3215
  const candidates = await collectJsonlFileCandidates(projectsRoot, {
3173
3216
  includeRootFiles: false,
@@ -7764,6 +7807,59 @@ class OpenCodeServiceLane {
7764
7807
  }
7765
7808
  }
7766
7809
 
7810
+ // agent-driver/dist/adapters/opencode/legacy-auth.js
7811
+ import { open } from "node:fs/promises";
7812
+ import { homedir as homedir6 } from "node:os";
7813
+ import path9 from "node:path";
7814
+ function record5(value) {
7815
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : undefined;
7816
+ }
7817
+ function parse(value) {
7818
+ try {
7819
+ return record5(JSON.parse(value));
7820
+ } catch {
7821
+ return;
7822
+ }
7823
+ }
7824
+ async function readJson(filename, maxBytes) {
7825
+ try {
7826
+ const file = await open(filename, "r");
7827
+ try {
7828
+ if ((await file.stat()).size > maxBytes)
7829
+ return;
7830
+ return parse(await file.readFile("utf8"));
7831
+ } finally {
7832
+ await file.close();
7833
+ }
7834
+ } catch {
7835
+ return;
7836
+ }
7837
+ }
7838
+ function xdgRoot(value, fallback) {
7839
+ return value && path9.isAbsolute(value) ? value : fallback;
7840
+ }
7841
+ async function legacyOpenCodeApiEnvironment(environment, model) {
7842
+ if (!model || model.indexOf("/") < 1)
7843
+ return {};
7844
+ if (environment.OPENCODE_MODELS_URL && environment.OPENCODE_MODELS_URL !== "https://models.opencode.ai" && !environment.OPENCODE_MODELS_PATH)
7845
+ return {};
7846
+ const provider = model.slice(0, model.indexOf("/"));
7847
+ const home = (process.platform === "win32" ? environment.USERPROFILE : undefined) || environment.HOME || homedir6();
7848
+ const cache = xdgRoot(environment.XDG_CACHE_HOME, path9.join(home, ".cache"));
7849
+ const catalog = await readJson(environment.OPENCODE_MODELS_PATH || path9.join(cache, "opencode", "models.json"), 16 * 1024 * 1024);
7850
+ const providerInfo = record5(catalog?.[provider]);
7851
+ const names = Array.isArray(providerInfo?.env) ? providerInfo.env.filter((name2) => typeof name2 === "string") : [];
7852
+ if (names.some((name2) => environment[name2] !== undefined))
7853
+ return {};
7854
+ const name = names.find((name2) => /^[A-Z][A-Z0-9_]*(?:_API_KEY|_TOKEN)$/.test(name2));
7855
+ if (!name)
7856
+ return {};
7857
+ const data = xdgRoot(environment.XDG_DATA_HOME, path9.join(home, ".local", "share"));
7858
+ const auth = (environment.OPENCODE_AUTH_CONTENT ? parse(environment.OPENCODE_AUTH_CONTENT) : undefined) ?? await readJson(path9.join(data, "opencode", "auth.json"), 1024 * 1024);
7859
+ const credential = record5(auth?.[provider]);
7860
+ return credential?.type === "api" && typeof credential.key === "string" && credential.key.trim() ? { [name]: credential.key } : {};
7861
+ }
7862
+
7767
7863
  // agent-driver/dist/adapters/opencode/recent-context.js
7768
7864
  var OPENCODE_DISCOVERY_TIMEOUT_MS = 15000;
7769
7865
  var OPENCODE_DISCOVERY_OUTPUT_MAX_BYTES = 4 * 1024 * 1024;
@@ -7877,7 +7973,9 @@ class OpenCodeDriver {
7877
7973
  const { spawnEnv } = await prepareCliTransport(ctx, {
7878
7974
  OPENCODE_SERVER_PASSWORD: password
7879
7975
  });
7880
- const override = resolveLaunchFieldsOrDefault(ctx.config.runtimeConfig).command;
7976
+ const fields2 = resolveLaunchFieldsOrDefault(ctx.config.runtimeConfig);
7977
+ Object.assign(spawnEnv, await legacyOpenCodeApiEnvironment(spawnEnv, fields2.model));
7978
+ const override = fields2.command;
7881
7979
  const args = [
7882
7980
  "serve",
7883
7981
  "--pure",
@@ -7900,8 +7998,8 @@ class OpenCodeDriver {
7900
7998
  // agent-driver/dist/adapters/pi/index.js
7901
7999
  import { createRequire } from "module";
7902
8000
  import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3, realpathSync } from "fs";
7903
- import { homedir as homedir6 } from "os";
7904
- import * as path11 from "path";
8001
+ import { homedir as homedir8 } from "os";
8002
+ import * as path12 from "path";
7905
8003
 
7906
8004
  // agent-driver/dist/controller/sdk-host.js
7907
8005
  import { EventEmitter as EventEmitter6 } from "events";
@@ -8016,7 +8114,7 @@ class SdkLane {
8016
8114
 
8017
8115
  // agent-driver/dist/adapters/pi/sessionDeps.js
8018
8116
  import { readFileSync as readFileSync2 } from "fs";
8019
- import * as path9 from "path";
8117
+ import * as path10 from "path";
8020
8118
  import { pathToFileURL } from "url";
8021
8119
  var PI_SDK_PACKAGE_NAME = "@earendil-works/pi-coding-agent";
8022
8120
  var cachedSdkPromise = null;
@@ -8025,9 +8123,9 @@ async function importPiSdkFromGlobalInstall() {
8025
8123
  if (!dir) {
8026
8124
  throw new Error(`${PI_SDK_PACKAGE_NAME} not found — install it (e.g. \`npm install -g ${PI_SDK_PACKAGE_NAME}\`) before launching a pi agent`);
8027
8125
  }
8028
- const pkg = JSON.parse(readFileSync2(path9.join(dir, "package.json"), "utf-8"));
8126
+ const pkg = JSON.parse(readFileSync2(path10.join(dir, "package.json"), "utf-8"));
8029
8127
  const entry = pkg.exports?.["."]?.import ?? pkg.main ?? "./dist/index.js";
8030
- const entryPath = path9.join(dir, entry);
8128
+ const entryPath = path10.join(dir, entry);
8031
8129
  const barrel = await import(pathToFileURL(entryPath).href);
8032
8130
  return withSessionDirHelper(barrel, entryPath);
8033
8131
  }
@@ -8035,7 +8133,7 @@ async function withSessionDirHelper(barrel, entryPath) {
8035
8133
  if (typeof barrel.getDefaultSessionDir === "function")
8036
8134
  return barrel;
8037
8135
  try {
8038
- const deepPath = path9.join(path9.dirname(entryPath), "core", "session-manager.js");
8136
+ const deepPath = path10.join(path10.dirname(entryPath), "core", "session-manager.js");
8039
8137
  const deep = await import(pathToFileURL(deepPath).href);
8040
8138
  if (typeof deep.getDefaultSessionDir !== "function")
8041
8139
  return barrel;
@@ -8116,13 +8214,13 @@ function createPiSessionDependencies(ctx, loadSdk = loadPiSdkModule) {
8116
8214
  }
8117
8215
 
8118
8216
  // agent-driver/dist/adapters/pi/recent-context.js
8119
- import { homedir as homedir5 } from "node:os";
8120
- import path10 from "node:path";
8217
+ import { homedir as homedir7 } from "node:os";
8218
+ import path11 from "node:path";
8121
8219
  function expandTildePath(value) {
8122
8220
  if (value === "~")
8123
- return homedir5();
8221
+ return homedir7();
8124
8222
  if (value.startsWith("~/"))
8125
- return path10.join(homedir5(), value.slice(2));
8223
+ return path11.join(homedir7(), value.slice(2));
8126
8224
  return value;
8127
8225
  }
8128
8226
  async function discoverPiRecentContext(request, dependencies = {}) {
@@ -8130,7 +8228,7 @@ async function discoverPiRecentContext(request, dependencies = {}) {
8130
8228
  if (collector.satisfied)
8131
8229
  return collector.result();
8132
8230
  const customSessionDirectory = process.env.PI_CODING_AGENT_SESSION_DIR;
8133
- const sessionsRoot = path10.resolve(expandTildePath(dependencies.sessionsRoot ?? customSessionDirectory ?? path10.join(process.env.PI_CODING_AGENT_DIR || path10.join(homedir5(), ".pi", "agent"), "sessions")));
8231
+ const sessionsRoot = path11.resolve(expandTildePath(dependencies.sessionsRoot ?? customSessionDirectory ?? path11.join(process.env.PI_CODING_AGENT_DIR || path11.join(homedir7(), ".pi", "agent"), "sessions")));
8134
8232
  const scanDirectSessions = dependencies.sessionsRoot == null && customSessionDirectory != null;
8135
8233
  const readHeader = dependencies.readHeader ?? readFirstLine;
8136
8234
  const candidates = await collectJsonlFileCandidates(sessionsRoot, {
@@ -8178,15 +8276,15 @@ function resolvePiSdkPackageDir(deps = {}) {
8178
8276
  if (!binPath)
8179
8277
  return;
8180
8278
  try {
8181
- let dir = path11.dirname(realpathSync(binPath));
8279
+ let dir = path12.dirname(realpathSync(binPath));
8182
8280
  const MAX_DEPTH = 8;
8183
8281
  for (let i = 0;i < MAX_DEPTH; i++) {
8184
- if (isPiSdkPackageJson(path11.join(dir, "package.json")))
8282
+ if (isPiSdkPackageJson(path12.join(dir, "package.json")))
8185
8283
  return dir;
8186
- const siblingDir = path11.join(dir, "node_modules", PI_SDK_PACKAGE_NAME2);
8187
- if (isPiSdkPackageJson(path11.join(siblingDir, "package.json")))
8284
+ const siblingDir = path12.join(dir, "node_modules", PI_SDK_PACKAGE_NAME2);
8285
+ if (isPiSdkPackageJson(path12.join(siblingDir, "package.json")))
8188
8286
  return siblingDir;
8189
- const parent = path11.dirname(dir);
8287
+ const parent = path12.dirname(dir);
8190
8288
  if (parent === dir)
8191
8289
  break;
8192
8290
  dir = parent;
@@ -8203,21 +8301,21 @@ function findPiSessionFile(sessionDir, sessionId) {
8203
8301
  }
8204
8302
  const suffix = `_${sessionId}.jsonl`;
8205
8303
  const match = entries.find((entry) => entry.endsWith(suffix));
8206
- return match ? path11.join(sessionDir, match) : null;
8304
+ return match ? path12.join(sessionDir, match) : null;
8207
8305
  }
8208
8306
  function resolvePiSessionDir(sdk, cwd) {
8209
8307
  if (typeof sdk.getDefaultSessionDir === "function")
8210
8308
  return sdk.getDefaultSessionDir(cwd);
8211
- const agentDir = typeof sdk.getAgentDir === "function" ? sdk.getAgentDir() : path11.join(homedir6(), ".pi", "agent");
8212
- const encoded = `--${path11.resolve(cwd).replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
8213
- return path11.join(agentDir, "sessions", encoded);
8309
+ const agentDir = typeof sdk.getAgentDir === "function" ? sdk.getAgentDir() : path12.join(homedir8(), ".pi", "agent");
8310
+ const encoded = `--${path12.resolve(cwd).replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
8311
+ return path12.join(agentDir, "sessions", encoded);
8214
8312
  }
8215
8313
  function resolvePiSdkVersionFromPath(deps = {}) {
8216
8314
  const dir = resolvePiSdkPackageDir(deps);
8217
8315
  if (!dir)
8218
8316
  return;
8219
8317
  try {
8220
- const pkg = JSON.parse(readFileSync3(path11.join(dir, "package.json"), "utf-8"));
8318
+ const pkg = JSON.parse(readFileSync3(path12.join(dir, "package.json"), "utf-8"));
8221
8319
  return pkg.version;
8222
8320
  } catch {
8223
8321
  return;
@@ -10444,7 +10542,7 @@ import { createHash as createHash5 } from "crypto";
10444
10542
  // agent-driver/dist/adapters/antigravity/quota.js
10445
10543
  import { createHash as createHash4, randomBytes as randomBytes5 } from "node:crypto";
10446
10544
  import { readFile } from "node:fs/promises";
10447
- import { homedir as homedir7 } from "node:os";
10545
+ import { homedir as homedir9 } from "node:os";
10448
10546
  import { isAbsolute, join as join11 } from "node:path";
10449
10547
  var PROD = "https://cloudcode-pa.googleapis.com";
10450
10548
  var DAILY = "https://daily-cloudcode-pa.googleapis.com";
@@ -10516,10 +10614,10 @@ function parseAntigravityQuota(value) {
10516
10614
  }
10517
10615
  async function readAntigravityQuota(options = {}) {
10518
10616
  const env = options.env ?? process.env;
10519
- const home = options.home ?? homedir7();
10617
+ const home = options.home ?? homedir9();
10520
10618
  const configuredHome = env.GEMINI_HOME?.replace(/^~(?=[/\\]|$)/, home);
10521
10619
  const root = configuredHome ? isAbsolute(configuredHome) ? configuredHome : join11(process.cwd(), configuredHome) : join11(home, ".gemini");
10522
- const read = options.readCredentialsFile ?? ((path12) => readFile(path12, "utf8"));
10620
+ const read = options.readCredentialsFile ?? ((path13) => readFile(path13, "utf8"));
10523
10621
  let credentials = null;
10524
10622
  let authType;
10525
10623
  let storageUnavailable = false;
@@ -10638,7 +10736,7 @@ async function readAntigravityQuota(options = {}) {
10638
10736
  // agent-driver/dist/provider-quota.js
10639
10737
  import { execFile } from "node:child_process";
10640
10738
  import { readFile as readFile2 } from "node:fs/promises";
10641
- import { homedir as homedir8 } from "node:os";
10739
+ import { homedir as homedir10 } from "node:os";
10642
10740
  import { join as join12 } from "node:path";
10643
10741
  import { promisify } from "node:util";
10644
10742
  import { randomBytes as randomBytes6 } from "node:crypto";
@@ -10667,7 +10765,7 @@ async function claudeCredentials(options) {
10667
10765
  } catch {}
10668
10766
  }
10669
10767
  const env = options.env ?? process.env;
10670
- const root = env.CLAUDE_CONFIG_DIR || join12(options.home ?? homedir8(), ".claude");
10768
+ const root = env.CLAUDE_CONFIG_DIR || join12(options.home ?? homedir10(), ".claude");
10671
10769
  try {
10672
10770
  const value = options.readCredentialsFile ? await options.readCredentialsFile(join12(root, ".credentials.json")) : await readFile2(join12(root, ".credentials.json"), "utf8");
10673
10771
  return parseCredentials(value);
@@ -10756,8 +10854,8 @@ async function readClaudeQuota(options) {
10756
10854
  if (!body || typeof body !== "object") {
10757
10855
  return { status: "error", sourceEpoch: claudeSourceEpoch, code: "invalid_response", retryable: true };
10758
10856
  }
10759
- const record5 = body;
10760
- const limits = ["five_hour", "seven_day", "seven_day_sonnet", "seven_day_opus"].map((key) => claudeLimit(key, record5[key])).filter((limit) => limit !== null);
10857
+ const record6 = body;
10858
+ const limits = ["five_hour", "seven_day", "seven_day_sonnet", "seven_day_opus"].map((key) => claudeLimit(key, record6[key])).filter((limit) => limit !== null);
10761
10859
  if (limits.length === 0) {
10762
10860
  return { status: "error", sourceEpoch: claudeSourceEpoch, code: "invalid_response", retryable: true };
10763
10861
  }
@@ -11414,10 +11512,10 @@ function stableNormalizeApmHeldFreshness(value) {
11414
11512
  return value.map((item) => stableNormalizeApmHeldFreshness(item));
11415
11513
  if (!value || typeof value !== "object")
11416
11514
  return value;
11417
- const record5 = value;
11515
+ const record6 = value;
11418
11516
  const normalized = {};
11419
- for (const key of Object.keys(record5).sort()) {
11420
- normalized[key] = stableNormalizeApmHeldFreshness(record5[key]);
11517
+ for (const key of Object.keys(record6).sort()) {
11518
+ normalized[key] = stableNormalizeApmHeldFreshness(record6[key]);
11421
11519
  }
11422
11520
  return normalized;
11423
11521
  }
@@ -11533,13 +11631,13 @@ function reduceManager(state, event) {
11533
11631
  const existing = state.agents[event.agentId];
11534
11632
  if (!existing || existing.execution.sessionInstanceId !== event.sessionInstanceId)
11535
11633
  return { state, effects: [] };
11536
- const record5 = existing.pendingAdmissions.find((entry) => entry.sessionInstanceId === event.sessionInstanceId && entry.commandId === event.commandId);
11537
- if (!record5)
11634
+ const record6 = existing.pendingAdmissions.find((entry) => entry.sessionInstanceId === event.sessionInstanceId && entry.commandId === event.commandId);
11635
+ if (!record6)
11538
11636
  return { state, effects: [] };
11539
11637
  const agent = clone(existing);
11540
11638
  agent.pendingAdmissions = agent.pendingAdmissions.filter((entry) => entry.sessionInstanceId !== event.sessionInstanceId || entry.commandId !== event.commandId);
11541
11639
  syncExecutionProjection(agent);
11542
- return commit(state, agent, event.outcome === "failed" ? recoveryEffects(agent, [record5]) : []);
11640
+ return commit(state, agent, event.outcome === "failed" ? recoveryEffects(agent, [record6]) : []);
11543
11641
  }
11544
11642
  case "admission_acknowledged": {
11545
11643
  const existing = state.agents[event.agentId];
@@ -12062,11 +12160,11 @@ function syncExecutionProjection(agent) {
12062
12160
  agent.lastDeliverAt = agent.pendingAdmissions.length > 0 ? Math.max(...agent.pendingAdmissions.map((entry) => entry.admittedAt)) : null;
12063
12161
  }
12064
12162
  function recoveryEffects(agent, records) {
12065
- return records.filter((record5) => record5.requeueOnFailure).map((record5) => ({
12163
+ return records.filter((record6) => record6.requeueOnFailure).map((record6) => ({
12066
12164
  type: "requeue_delivery",
12067
12165
  agentId: agent.agentId,
12068
- message: record5.exactAgentMsg,
12069
- mode: record5.mode
12166
+ message: record6.exactAgentMsg,
12167
+ mode: record6.mode
12070
12168
  }));
12071
12169
  }
12072
12170
  function commit(state, agent, effects) {
@@ -12159,9 +12257,9 @@ function cliCommandsSection() {
12159
12257
  "### Messaging",
12160
12258
  "",
12161
12259
  `1. \`${CLI} inbox pull\` — fetch unread messages and advance their read waterlines.`,
12162
- `2. \`${CLI} message send --target <ref> --remind-after <0|Nm|Nh> --stdin\` — send to a ` + `channel, DM, or thread. ` + `The body is required through \`--stdin\` and limited to 1 KiB of UTF-8. ` + `Attach uploaded files with \`--attachment <id>\` (repeatable, order matters). ` + `\`--remind-after\` accepts \`0\`, or a whole-number duration from \`1m\` to \`24h\`.`,
12163
- `3. \`${CLI} message attachment upload --target <ref> --file <path>\` — upload a file; ` + `returns an id stable across pending→persisted.`,
12164
- `4. \`${CLI} message attachment download --id <id> [--out <path>]\` — download any ` + `attachment you can see (or your own pending uploads).`,
12260
+ `2. \`${CLI} message send --target <ref> --remind-after <0|Nm|Nh> --stdin\` — send to a ` + `channel, DM, or thread. ` + `The body is required through \`--stdin\` and limited to 1 KiB of UTF-8. ` + `Attach files with \`--attachment <id>\` (repeatable, order matters). ` + `\`--remind-after\` accepts \`0\`, or a whole-number duration from \`1m\` to \`24h\`.`,
12261
+ `3. \`${CLI} message attachment upload --file <path>\` — upload a local file and get a reusable attachment ID.`,
12262
+ `4. \`${CLI} message attachment download --id <id> [--out <path>]\` — download an attachment you can read, including your own unsent uploads.`,
12165
12263
  `5. \`${CLI} message property set --target <full-message-ref> --json <json>\` — add a supported property value to a message.`,
12166
12264
  `6. \`${CLI} message property list --target <full-message-ref>\` — list the message's current properties and supported capabilities.`,
12167
12265
  `7. \`${CLI} message property remove --target <full-message-ref> --json <json>\` — remove a supported property value from a message.`,
@@ -12222,7 +12320,8 @@ function messagingSection() {
12222
12320
  "#### Sending mechanics",
12223
12321
  "",
12224
12322
  `- Send body: use \`${CLI} message send --target <ref> --remind-after T --stdin\` with the ` + "quoted-heredoc form under *Message formatting*.",
12225
- `- Long detail: upload it with \`${CLI} message attachment upload --target <ref> --file <path>.md\`; ` + "add the returned id as `--attachment <id>` on the short stdin send.",
12323
+ `- Long detail: upload it with \`${CLI} message attachment upload --file <path>.md\`; ` + "add the returned id as `--attachment <id>` on the short stdin send.",
12324
+ "- Reuse files: to forward an attachment or send the same file again, pass its existing ID with `--attachment <id>`. " + "Do not download and upload it again. Reuse works across channels, DMs, and threads while you can still read the file. " + "Upload only a new or changed file.",
12226
12325
  `- Cite a specific message: add \`--reply "#37"\` — \`--reply\` takes the \`#N\` seq ` + "(within `--target`) of the message you're answering.",
12227
12326
  "",
12228
12327
  "Reply where the message came from. Post results in the channel that owns the topic. " + "When uncertain, read history (below) or DM the relevant people.",
@@ -12338,7 +12437,19 @@ function utilsSection() {
12338
12437
  "",
12339
12438
  "### Join a new server",
12340
12439
  "",
12341
- `If a message contains a \`/c/invite/...\` link, just run \`${CLI} server join --invite <link>\`. ` + "The server enforces owner-only: it accepts only invites your owner created and rejects the " + "rest with a reason. Safe to attempt without reasoning about who sent it."
12440
+ `If a message contains a \`/c/invite/...\` link, just run \`${CLI} server join --invite <link>\`. ` + "The server enforces owner-only: it accepts only invites your owner created and rejects the " + "rest with a reason. Safe to attempt without reasoning about who sent it.",
12441
+ "",
12442
+ "### Answer questions about Alook itself",
12443
+ "",
12444
+ "Alook frontend source code: https://github.com/alookai/alook/tree/main/src/web/src",
12445
+ "",
12446
+ "Only when a user specifically asks for Alook product guidance or clarification about " + "the product, read the relevant frontend code before answering. " + "Check the page, visible labels, and interaction handlers to verify the steps.",
12447
+ "",
12448
+ "Give clear UI click instructions in the user's language. Start with the page they are on. " + "Use simple positions such as top-left or left sidebar, visible icons, and button labels " + "to identify exactly where to click. Explain each click in order and what appears next. " + "Keep frontend code names and layout terms out of the user's instructions.",
12449
+ "",
12450
+ 'Bad: "Click thisReactButton, on the same layer as serverRailContainer."',
12451
+ "",
12452
+ 'Good: "From the channel chat page in XX server, look at the top-left corner. Click the ' + "Home button with the Alook logo. After Home opens, click My Bots near the top-left " + 'of the left sidebar."'
12342
12453
  ].join(`
12343
12454
  `);
12344
12455
  }
@@ -12514,14 +12625,14 @@ function createLogger(options = {}) {
12514
12625
  `));
12515
12626
  const err = options.err ?? ((line) => process.stderr.write(line + `
12516
12627
  `));
12517
- const record5 = options.record;
12628
+ const record6 = options.record;
12518
12629
  const emit = (level, message, data) => {
12519
12630
  if (LEVEL_RANK[level] < minRank)
12520
12631
  return;
12521
12632
  const time = now();
12522
12633
  const line = `${time} ${header} ${level.toUpperCase().padEnd(5)} ${message}${formatData(data)}`;
12523
12634
  try {
12524
- record5?.({ time, header, level, message, fields: recordFields(data) });
12635
+ record6?.({ time, header, level, message, fields: recordFields(data) });
12525
12636
  } catch {}
12526
12637
  (level === "warn" || level === "error" ? err : out)(line);
12527
12638
  };
@@ -14269,7 +14380,7 @@ __export(exports_external, {
14269
14380
  regexes: () => exports_regexes,
14270
14381
  regex: () => _regex,
14271
14382
  refine: () => refine,
14272
- record: () => record5,
14383
+ record: () => record6,
14273
14384
  readonly: () => readonly,
14274
14385
  property: () => _property,
14275
14386
  properties: () => _properties,
@@ -14281,7 +14392,7 @@ __export(exports_external, {
14281
14392
  pipe: () => pipe,
14282
14393
  partialRecord: () => partialRecord,
14283
14394
  parseAsync: () => parseAsync2,
14284
- parse: () => parse3,
14395
+ parse: () => parse4,
14285
14396
  overwrite: () => _overwrite,
14286
14397
  output: () => output,
14287
14398
  optional: () => optional,
@@ -14509,7 +14620,7 @@ __export(exports_core2, {
14509
14620
  prettifyError: () => prettifyError,
14510
14621
  parseURLObject: () => parseURLObject,
14511
14622
  parseAsync: () => parseAsync,
14512
- parse: () => parse,
14623
+ parse: () => parse2,
14513
14624
  meta: () => meta,
14514
14625
  mergeValues: () => mergeValues,
14515
14626
  memoizer: () => memoizer,
@@ -15030,10 +15141,10 @@ function mergeDefs(...defs) {
15030
15141
  function cloneDef(schema) {
15031
15142
  return mergeDefs(schema._zod.def);
15032
15143
  }
15033
- function getElementAtPath(obj, path12) {
15034
- if (!path12)
15144
+ function getElementAtPath(obj, path13) {
15145
+ if (!path13)
15035
15146
  return obj;
15036
- return path12.reduce((acc, key) => acc?.[key], obj);
15147
+ return path13.reduce((acc, key) => acc?.[key], obj);
15037
15148
  }
15038
15149
  function promiseAllObject(promisesObj) {
15039
15150
  const keys = Object.keys(promisesObj);
@@ -15369,11 +15480,11 @@ function explicitlyAborted(x, startIndex = 0) {
15369
15480
  }
15370
15481
  return false;
15371
15482
  }
15372
- function prefixIssues(path12, issues) {
15483
+ function prefixIssues(path13, issues) {
15373
15484
  return issues.map((iss) => {
15374
15485
  var _a;
15375
15486
  (_a = iss).path ?? (_a.path = []);
15376
- iss.path.unshift(path12);
15487
+ iss.path.unshift(path13);
15377
15488
  return iss;
15378
15489
  });
15379
15490
  }
@@ -15823,16 +15934,16 @@ function flattenError(error, mapper = (issue2) => issue2.message) {
15823
15934
  }
15824
15935
  function formatError(error, mapper = (issue2) => issue2.message) {
15825
15936
  const fieldErrors = { _errors: [] };
15826
- const processError = (error2, path12 = []) => {
15937
+ const processError = (error2, path13 = []) => {
15827
15938
  for (const issue2 of error2.issues) {
15828
15939
  if (issue2.code === "invalid_union" && issue2.errors.length) {
15829
- issue2.errors.map((issues) => processError({ issues }, [...path12, ...issue2.path]));
15940
+ issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
15830
15941
  } else if (issue2.code === "invalid_key") {
15831
- processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
15942
+ processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
15832
15943
  } else if (issue2.code === "invalid_element") {
15833
- processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
15944
+ processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
15834
15945
  } else {
15835
- const fullpath = [...path12, ...issue2.path];
15946
+ const fullpath = [...path13, ...issue2.path];
15836
15947
  if (fullpath.length === 0) {
15837
15948
  fieldErrors._errors.push(mapper(issue2));
15838
15949
  } else {
@@ -15871,17 +15982,17 @@ function formatError(error, mapper = (issue2) => issue2.message) {
15871
15982
  }
15872
15983
  function treeifyError(error, mapper = (issue2) => issue2.message) {
15873
15984
  const result = { errors: [] };
15874
- const processError = (error2, path12 = []) => {
15985
+ const processError = (error2, path13 = []) => {
15875
15986
  var _a2;
15876
15987
  for (const issue2 of error2.issues) {
15877
15988
  if (issue2.code === "invalid_union" && issue2.errors.length) {
15878
- issue2.errors.map((issues) => processError({ issues }, [...path12, ...issue2.path]));
15989
+ issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
15879
15990
  } else if (issue2.code === "invalid_key") {
15880
- processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
15991
+ processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
15881
15992
  } else if (issue2.code === "invalid_element") {
15882
- processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
15993
+ processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
15883
15994
  } else {
15884
- const fullpath = [...path12, ...issue2.path];
15995
+ const fullpath = [...path13, ...issue2.path];
15885
15996
  if (fullpath.length === 0) {
15886
15997
  result.errors.push(mapper(issue2));
15887
15998
  continue;
@@ -15920,8 +16031,8 @@ function treeifyError(error, mapper = (issue2) => issue2.message) {
15920
16031
  }
15921
16032
  function toDotPath(_path) {
15922
16033
  const segs = [];
15923
- const path12 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
15924
- for (const seg of path12) {
16034
+ const path13 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
16035
+ for (const seg of path13) {
15925
16036
  if (typeof seg === "number")
15926
16037
  segs.push(`[${seg}]`);
15927
16038
  else if (typeof seg === "symbol")
@@ -15968,7 +16079,7 @@ var _parse = (_Err) => {
15968
16079
  };
15969
16080
  return fn;
15970
16081
  };
15971
- var parse = /* @__PURE__ */ _parse($ZodRealError);
16082
+ var parse2 = /* @__PURE__ */ _parse($ZodRealError);
15972
16083
  var _parseAsync = (_Err) => {
15973
16084
  const fn = async (schema, value, _ctx, params) => {
15974
16085
  const ctx = _ctx ? { ..._ctx, async: true } : { async: true };
@@ -16056,18 +16167,18 @@ var validateAsync = async (schema, value, _ctx) => {
16056
16167
  return result.issues.length === 0;
16057
16168
  };
16058
16169
  var _encode = (_Err) => {
16059
- const parse2 = _parse(_Err);
16170
+ const parse3 = _parse(_Err);
16060
16171
  const fn = (schema, value, _ctx, _params) => {
16061
16172
  const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
16062
- return parse2(schema, value, ctx, finalizeParams(fn, _params));
16173
+ return parse3(schema, value, ctx, finalizeParams(fn, _params));
16063
16174
  };
16064
16175
  return fn;
16065
16176
  };
16066
16177
  var encode = /* @__PURE__ */ _encode($ZodRealError);
16067
16178
  var _decode = (_Err) => {
16068
- const parse2 = _parse(_Err);
16179
+ const parse3 = _parse(_Err);
16069
16180
  const fn = (schema, value, _ctx, _params) => {
16070
- return parse2(schema, value, _ctx, finalizeParams(fn, _params));
16181
+ return parse3(schema, value, _ctx, finalizeParams(fn, _params));
16071
16182
  };
16072
16183
  return fn;
16073
16184
  };
@@ -19082,10 +19193,10 @@ var $ZodFunction = /* @__PURE__ */ $constructor("$ZodFunction", (inst, def) => {
19082
19193
  throw new Error("implement() must be called with a function");
19083
19194
  }
19084
19195
  return Object.defineProperty(function(...args) {
19085
- const parsedArgs = inst._def.input ? parse(inst._def.input, args) : args;
19196
+ const parsedArgs = inst._def.input ? parse2(inst._def.input, args) : args;
19086
19197
  const result = Reflect.apply(func, this, parsedArgs);
19087
19198
  if (inst._def.output) {
19088
- return parse(inst._def.output, result);
19199
+ return parse2(inst._def.output, result);
19089
19200
  }
19090
19201
  return result;
19091
19202
  }, "_zod", { value: inst._zod, enumerable: false });
@@ -19367,7 +19478,7 @@ function bucketFor(state, inst) {
19367
19478
  return bucket;
19368
19479
  }
19369
19480
  var handoff;
19370
- var open = [];
19481
+ var open2 = [];
19371
19482
  var memo = {
19372
19483
  alloc(_inst, payload, empty) {
19373
19484
  const bucket = handoff;
@@ -19376,7 +19487,7 @@ var memo = {
19376
19487
  handoff = undefined;
19377
19488
  const entry = { value: empty, issues: null };
19378
19489
  bucket.set(payload.value, entry);
19379
- open.push(entry);
19490
+ open2.push(entry);
19380
19491
  return empty;
19381
19492
  },
19382
19493
  guard(inst) {
@@ -19447,10 +19558,10 @@ var memo = {
19447
19558
  return payload;
19448
19559
  }
19449
19560
  handoff = bucket;
19450
- const depth = open.length;
19561
+ const depth = open2.length;
19451
19562
  const result = base(payload, ctx);
19452
19563
  handoff = undefined;
19453
- const entry = open.length > depth ? open.pop() : undefined;
19564
+ const entry = open2.length > depth ? open2.pop() : undefined;
19454
19565
  if (result instanceof Promise) {
19455
19566
  return result.then((r) => {
19456
19567
  if (entry)
@@ -30589,8 +30700,8 @@ function rewriteKeyNames(ctx) {
30589
30700
  bySchema.set(entry.schema, entry);
30590
30701
  }
30591
30702
  const rewrites = new Map;
30592
- for (const record5 of pendingRecords.get(ctx) ?? []) {
30593
- const seen = ctx.seen.get(record5);
30703
+ for (const record6 of pendingRecords.get(ctx) ?? []) {
30704
+ const seen = ctx.seen.get(record6);
30594
30705
  const names = (seen?.def ?? seen?.schema)?.propertyNames;
30595
30706
  if (!names || names === true || rewrites.has(names))
30596
30707
  continue;
@@ -30916,7 +31027,7 @@ __export(exports_schemas2, {
30916
31027
  strictObject: () => strictObject,
30917
31028
  set: () => set,
30918
31029
  refine: () => refine,
30919
- record: () => record5,
31030
+ record: () => record6,
30920
31031
  readonly: () => readonly,
30921
31032
  promise: () => promise,
30922
31033
  preprocess: () => preprocess,
@@ -31150,7 +31261,7 @@ var ZodRealError = /* @__PURE__ */ $constructor("ZodError", initializer2, undefi
31150
31261
  });
31151
31262
 
31152
31263
  // ../../node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/classic/parse.js
31153
- var parse3 = /* @__PURE__ */ _parse(ZodRealError);
31264
+ var parse4 = /* @__PURE__ */ _parse(ZodRealError);
31154
31265
  var parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
31155
31266
  var safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
31156
31267
  var safeParseAsync2 = /* @__PURE__ */ _safeParseAsync(ZodRealError);
@@ -31286,7 +31397,7 @@ var ZodType = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
31286
31397
  exports_util.own(this, "~standard", value);
31287
31398
  },
31288
31399
  parse: function _parse2(data, params) {
31289
- return parse3(this, data, params, { callee: _parse2 });
31400
+ return parse4(this, data, params, { callee: _parse2 });
31290
31401
  },
31291
31402
  parseAsync: async function _parseAsync2(data, params) {
31292
31403
  return await parseAsync2(this, data, params, { callee: _parseAsync2 });
@@ -32121,7 +32232,7 @@ var ZodRecord = /* @__PURE__ */ $constructor("ZodRecord", (inst, def) => {
32121
32232
  inst.keyType = def.keyType;
32122
32233
  inst.valueType = def.valueType;
32123
32234
  });
32124
- function record5(keyType, valueType, params) {
32235
+ function record6(keyType, valueType, params) {
32125
32236
  if (!valueType || !valueType._zod) {
32126
32237
  return new ZodRecord({
32127
32238
  type: "record",
@@ -32594,7 +32705,7 @@ var stringbool = (...args) => _stringbool({
32594
32705
  }, ...args);
32595
32706
  function json(params) {
32596
32707
  const jsonSchema = lazy(() => {
32597
- return union([string2(params), number3(), boolean2(), _null3(), array(jsonSchema), record5(string2(), jsonSchema)]);
32708
+ return union([string2(params), number3(), boolean2(), _null3(), array(jsonSchema), record6(string2(), jsonSchema)]);
32598
32709
  });
32599
32710
  return jsonSchema;
32600
32711
  }
@@ -32742,13 +32853,13 @@ function resolveRef(ref, ctx) {
32742
32853
  if (!ref.startsWith("#")) {
32743
32854
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
32744
32855
  }
32745
- const path12 = ref.slice(1).split("/").filter(Boolean);
32746
- if (path12.length === 0) {
32856
+ const path13 = ref.slice(1).split("/").filter(Boolean);
32857
+ if (path13.length === 0) {
32747
32858
  return ctx.rootSchema;
32748
32859
  }
32749
32860
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
32750
- if (path12[0] === defsKey) {
32751
- const key = path12[1] === undefined ? undefined : decodeJSONPointerSegment(path12[1]);
32861
+ if (path13[0] === defsKey) {
32862
+ const key = path13[1] === undefined ? undefined : decodeJSONPointerSegment(path13[1]);
32752
32863
  if (!key || !ctx.defs[key]) {
32753
32864
  throw new Error(`Reference not found: ${ref}`);
32754
32865
  }
@@ -36712,7 +36823,7 @@ import * as fs5 from "fs";
36712
36823
  import * as http from "http";
36713
36824
  import * as https from "https";
36714
36825
  import * as os2 from "os";
36715
- import * as path12 from "path";
36826
+ import * as path13 from "path";
36716
36827
  import { URL as URL2 } from "url";
36717
36828
  var LOCAL_MESSAGE_REMINDER_PATH = "/__alook/local/message-reminder";
36718
36829
  var LOCAL_MESSAGE_REMINDER_BODY_MAX_BYTES = 4 * 1024;
@@ -36744,15 +36855,15 @@ class CredentialBroker {
36744
36855
  this.voucherPrefix = config2.voucherPrefix ?? "vch_";
36745
36856
  this.clientLabel = config2.clientLabel ?? "cli";
36746
36857
  this.headerNames = config2.headerNames ?? DEFAULT_HEADER_NAMES;
36747
- this.voucherDir = config2.voucherDir ?? path12.join(os2.tmpdir(), "agent-vouchers");
36858
+ this.voucherDir = config2.voucherDir ?? path13.join(os2.tmpdir(), "agent-vouchers");
36748
36859
  }
36749
36860
  mint(agentId, launchId, capabilities2, runnerKey) {
36750
36861
  if (!runnerKey)
36751
36862
  throw new Error("CredentialBroker.mint: runnerKey is required (per-agent tier-2 credential)");
36752
36863
  const voucher = randomVoucher(this.voucherPrefix);
36753
- const dir = path12.join(this.voucherDir, sanitizeIdSegment(agentId));
36864
+ const dir = path13.join(this.voucherDir, sanitizeIdSegment(agentId));
36754
36865
  fs5.mkdirSync(dir, { recursive: true });
36755
- const voucherFile = path12.join(dir, `${sanitizeIdSegment(launchId)}.token`);
36866
+ const voucherFile = path13.join(dir, `${sanitizeIdSegment(launchId)}.token`);
36756
36867
  fs5.writeFileSync(voucherFile, voucher, { mode: 384 });
36757
36868
  this.registrations.set(voucher, {
36758
36869
  agentId,
@@ -36880,20 +36991,20 @@ function parseLocalMessageReminderBody(body, agentId) {
36880
36991
  }
36881
36992
  if (!value || typeof value !== "object" || Array.isArray(value))
36882
36993
  return null;
36883
- const record6 = value;
36884
- if (Object.keys(record6).sort().join(",") !== "channel,remindAfterMs,sentSeq")
36994
+ const record7 = value;
36995
+ if (Object.keys(record7).sort().join(",") !== "channel,remindAfterMs,sentSeq")
36885
36996
  return null;
36886
- if (typeof record6.channel !== "string" || !isCanonicalChannelScope(record6.channel))
36997
+ if (typeof record7.channel !== "string" || !isCanonicalChannelScope(record7.channel))
36887
36998
  return null;
36888
- if (!Number.isSafeInteger(record6.sentSeq) || record6.sentSeq < 1)
36999
+ if (!Number.isSafeInteger(record7.sentSeq) || record7.sentSeq < 1)
36889
37000
  return null;
36890
- if (!Number.isSafeInteger(record6.remindAfterMs) || record6.remindAfterMs !== 0 && record6.remindAfterMs < LOCAL_MESSAGE_REMINDER_MIN_MS || record6.remindAfterMs > LOCAL_MESSAGE_REMINDER_MAX_MS)
37001
+ if (!Number.isSafeInteger(record7.remindAfterMs) || record7.remindAfterMs !== 0 && record7.remindAfterMs < LOCAL_MESSAGE_REMINDER_MIN_MS || record7.remindAfterMs > LOCAL_MESSAGE_REMINDER_MAX_MS)
36891
37002
  return null;
36892
37003
  return {
36893
37004
  agentId,
36894
- channel: record6.channel,
36895
- sentSeq: record6.sentSeq,
36896
- remindAfterMs: record6.remindAfterMs
37005
+ channel: record7.channel,
37006
+ sentSeq: record7.sentSeq,
37007
+ remindAfterMs: record7.remindAfterMs
36897
37008
  };
36898
37009
  }
36899
37010
  async function handleLocalMessageReminder(req, res, agentId, onArm) {
@@ -37198,7 +37309,7 @@ function joinPath(basePath, reqUrl) {
37198
37309
  return base + reqPath || "/";
37199
37310
  }
37200
37311
  // src/daemon/createDaemon.ts
37201
- import { homedir as homedir10 } from "os";
37312
+ import { homedir as homedir12 } from "os";
37202
37313
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8 } from "node:fs";
37203
37314
 
37204
37315
  // src/util/rotatingFileSink.ts
@@ -37215,7 +37326,7 @@ import {
37215
37326
  statSync,
37216
37327
  unlinkSync as unlinkSync3
37217
37328
  } from "node:fs";
37218
- function createRotatingFileSink(path13, maxBytes, opts = {}) {
37329
+ function createRotatingFileSink(path14, maxBytes, opts = {}) {
37219
37330
  const report = (operation, error62) => {
37220
37331
  try {
37221
37332
  opts.onError?.({ operation, error: error62 });
@@ -37251,9 +37362,9 @@ function createRotatingFileSink(path13, maxBytes, opts = {}) {
37251
37362
  };
37252
37363
  const rotate = () => {
37253
37364
  try {
37254
- renameSync2(path13, `${path13}.1`);
37365
+ renameSync2(path14, `${path14}.1`);
37255
37366
  if (opts.mode !== undefined)
37256
- chmodSync(`${path13}.1`, opts.mode);
37367
+ chmodSync(`${path14}.1`, opts.mode);
37257
37368
  return true;
37258
37369
  } catch (error62) {
37259
37370
  report("rotate", error62);
@@ -37262,7 +37373,7 @@ function createRotatingFileSink(path13, maxBytes, opts = {}) {
37262
37373
  };
37263
37374
  const currentSize = () => {
37264
37375
  try {
37265
- return existsSync5(path13) ? statSync(path13).size : 0;
37376
+ return existsSync5(path14) ? statSync(path14).size : 0;
37266
37377
  } catch (error62) {
37267
37378
  report("stat", error62);
37268
37379
  return null;
@@ -37270,7 +37381,7 @@ function createRotatingFileSink(path13, maxBytes, opts = {}) {
37270
37381
  };
37271
37382
  const sink = {
37272
37383
  secure() {
37273
- return secureGeneration(`${path13}.1`) && secureGeneration(path13);
37384
+ return secureGeneration(`${path14}.1`) && secureGeneration(path14);
37274
37385
  },
37275
37386
  write(line) {
37276
37387
  try {
@@ -37290,7 +37401,7 @@ function createRotatingFileSink(path13, maxBytes, opts = {}) {
37290
37401
  const shouldRotate = maxBytes > 0 && (opts.hardMaxBytes ? currentBytes > 0 && currentBytes + serializedBytes > maxBytes : currentBytes >= maxBytes);
37291
37402
  if (shouldRotate && !rotate() && opts.hardMaxBytes)
37292
37403
  return;
37293
- appendFileSync(path13, serialized, opts.mode === undefined ? undefined : { mode: opts.mode });
37404
+ appendFileSync(path14, serialized, opts.mode === undefined ? undefined : { mode: opts.mode });
37294
37405
  } catch (error62) {
37295
37406
  report("append", error62);
37296
37407
  }
@@ -37298,7 +37409,7 @@ function createRotatingFileSink(path13, maxBytes, opts = {}) {
37298
37409
  openSnapshot() {
37299
37410
  const files = [];
37300
37411
  try {
37301
- for (const candidate of [`${path13}.1`, path13]) {
37412
+ for (const candidate of [`${path14}.1`, path14]) {
37302
37413
  if (!existsSync5(candidate))
37303
37414
  continue;
37304
37415
  if (!secureGeneration(candidate))
@@ -37459,11 +37570,11 @@ function createTraceSampler(emit, throttleMs = DEFAULT_TRACE_SAMPLE_MS) {
37459
37570
 
37460
37571
  // src/util/statusFile.ts
37461
37572
  import { writeFileSync as writeFileSync5, renameSync as renameSync3 } from "node:fs";
37462
- function writeStatusFile(path13, snapshot) {
37573
+ function writeStatusFile(path14, snapshot) {
37463
37574
  try {
37464
- const tmp = `${path13}.tmp`;
37575
+ const tmp = `${path14}.tmp`;
37465
37576
  writeFileSync5(tmp, JSON.stringify(snapshot));
37466
- renameSync3(tmp, path13);
37577
+ renameSync3(tmp, path14);
37467
37578
  } catch {}
37468
37579
  }
37469
37580
  // ../shared/src/community-attention.ts
@@ -37666,7 +37777,7 @@ var MAX_PROFILE_ABOUT_LENGTH = 1000;
37666
37777
  var MAX_MESSAGE_CONTENT_LENGTH = 4000;
37667
37778
  var MAX_ATTACHMENTS_PER_MESSAGE = 10;
37668
37779
  var MAX_ATTACHMENT_SIZE_BYTES = 25 * 1024 * 1024;
37669
- var MAX_ATTACHMENT_THUMBNAIL_SIZE_BYTES = 512 * 1024;
37780
+ var MAX_ATTACHMENT_THUMBNAIL_SIZE_BYTES = 256 * 1024;
37670
37781
  var MAX_SERVER_ICON_SIZE_BYTES = 5 * 1024 * 1024;
37671
37782
  var ALLOWED_ICON_MIME_TYPES = [
37672
37783
  "image/png",
@@ -38814,6 +38925,7 @@ __export(exports_community_schema, {
38814
38925
  communityMessageTag: () => communityMessageTag,
38815
38926
  communityMessageSeq: () => communityMessageSeq,
38816
38927
  communityMessageMark: () => communityMessageMark,
38928
+ communityMessageAttachment: () => communityMessageAttachment,
38817
38929
  communityMessage: () => communityMessage,
38818
38930
  communityMention: () => communityMention,
38819
38931
  communityFriendship: () => communityFriendship,
@@ -38989,11 +39101,7 @@ var communityReaction = sqliteTable("community_reaction", {
38989
39101
  ]);
38990
39102
  var communityAttachment = sqliteTable("community_attachment", {
38991
39103
  id: text2("id").primaryKey().$defaultFn(() => nanoid3()),
38992
- messageId: text2("message_id").references(() => communityMessage.id, {
38993
- onDelete: "cascade"
38994
- }),
38995
39104
  uploaderId: text2("uploader_id").notNull(),
38996
- targetId: text2("target_id").notNull(),
38997
39105
  r2Key: text2("r2_key").notNull(),
38998
39106
  thumbnailR2Key: text2("thumbnail_r2_key"),
38999
39107
  filename: text2("filename").notNull(),
@@ -39001,10 +39109,20 @@ var communityAttachment = sqliteTable("community_attachment", {
39001
39109
  size: integer2("size"),
39002
39110
  width: integer2("width"),
39003
39111
  height: integer2("height"),
39004
- position: integer2("position"),
39005
39112
  createdAt: text2("created_at").notNull().$defaultFn(() => new Date().toISOString())
39006
39113
  }, (t) => [
39007
- index("idx_attachment_message").on(t.messageId, t.position)
39114
+ index("idx_attachment_uploader").on(t.uploaderId),
39115
+ index("idx_attachment_r2_key").on(t.r2Key),
39116
+ index("idx_attachment_thumbnail_r2_key").on(t.thumbnailR2Key)
39117
+ ]);
39118
+ var communityMessageAttachment = sqliteTable("community_message_attachment", {
39119
+ messageId: text2("message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
39120
+ attachmentId: text2("attachment_id").notNull().references(() => communityAttachment.id, { onDelete: "restrict" }),
39121
+ position: integer2("position").notNull()
39122
+ }, (t) => [
39123
+ primaryKey({ columns: [t.messageId, t.attachmentId] }),
39124
+ unique("uq_message_attachment_position").on(t.messageId, t.position),
39125
+ index("idx_message_attachment_file").on(t.attachmentId, t.messageId)
39008
39126
  ]);
39009
39127
  var communityPin = sqliteTable("community_pin", {
39010
39128
  id: text2("id").primaryKey().$defaultFn(() => nanoid3()),
@@ -39126,6 +39244,41 @@ var communityMessageTag = sqliteTable("community_message_tag", {
39126
39244
  index("idx_message_tag_tag").on(t.tag, t.messageId)
39127
39245
  ]);
39128
39246
 
39247
+ // ../shared/src/db/queries/_chunk.ts
39248
+ var D1_MAX_BIND_PARAMS = 100;
39249
+ function maxInParams(fixedParams) {
39250
+ if (!Number.isInteger(fixedParams) || fixedParams < 0) {
39251
+ throw new Error("fixed params must be a non-negative integer");
39252
+ }
39253
+ if (fixedParams >= D1_MAX_BIND_PARAMS) {
39254
+ throw new Error("fixed params must leave room for at least one IN parameter");
39255
+ }
39256
+ return D1_MAX_BIND_PARAMS - fixedParams;
39257
+ }
39258
+ function maxRowsPerInsert(paramsPerRow) {
39259
+ if (paramsPerRow < 1)
39260
+ throw new Error("paramsPerRow must be >= 1");
39261
+ return Math.floor(D1_MAX_BIND_PARAMS / paramsPerRow);
39262
+ }
39263
+
39264
+ // ../shared/src/db/queries/community/channel.ts
39265
+ var CHANNEL_COLUMNS = {
39266
+ id: communityChannel.id,
39267
+ serverId: communityChannel.serverId,
39268
+ categoryId: communityChannel.categoryId,
39269
+ name: communityChannel.name,
39270
+ type: communityChannel.type,
39271
+ topic: communityChannel.topic,
39272
+ position: communityChannel.position,
39273
+ parentChannelId: communityChannel.parentChannelId,
39274
+ creatorId: communityChannel.creatorId,
39275
+ messageCount: communityChannel.messageCount,
39276
+ archived: communityChannel.archived,
39277
+ parentMessageId: communityChannel.parentMessageId,
39278
+ lastMessageAt: communityChannel.lastMessageAt,
39279
+ createdAt: communityChannel.createdAt
39280
+ };
39281
+
39129
39282
  // ../shared/src/logger.ts
39130
39283
  var LEVELS = {
39131
39284
  debug: 0,
@@ -39206,23 +39359,6 @@ function createLogger2(opts) {
39206
39359
  return new Logger(opts);
39207
39360
  }
39208
39361
 
39209
- // ../shared/src/db/queries/_chunk.ts
39210
- var D1_MAX_BIND_PARAMS = 100;
39211
- function maxInParams(fixedParams) {
39212
- if (!Number.isInteger(fixedParams) || fixedParams < 0) {
39213
- throw new Error("fixed params must be a non-negative integer");
39214
- }
39215
- if (fixedParams >= D1_MAX_BIND_PARAMS) {
39216
- throw new Error("fixed params must leave room for at least one IN parameter");
39217
- }
39218
- return D1_MAX_BIND_PARAMS - fixedParams;
39219
- }
39220
- function maxRowsPerInsert(paramsPerRow) {
39221
- if (paramsPerRow < 1)
39222
- throw new Error("paramsPerRow must be >= 1");
39223
- return Math.floor(D1_MAX_BIND_PARAMS / paramsPerRow);
39224
- }
39225
-
39226
39362
  // ../shared/src/db/queries/community/message.ts
39227
39363
  var log = createLogger2({ service: "community-queries" });
39228
39364
  var messageProjection = {
@@ -39321,24 +39457,6 @@ var userProductPlan = sqliteTable("user_product_plan", {
39321
39457
  updatedAt: text2("updated_at").notNull().$defaultFn(() => new Date().toISOString())
39322
39458
  }, (t) => [index("idx_user_product_plan_plan").on(t.planId)]);
39323
39459
 
39324
- // ../shared/src/db/queries/community/channel.ts
39325
- var CHANNEL_COLUMNS = {
39326
- id: communityChannel.id,
39327
- serverId: communityChannel.serverId,
39328
- categoryId: communityChannel.categoryId,
39329
- name: communityChannel.name,
39330
- type: communityChannel.type,
39331
- topic: communityChannel.topic,
39332
- position: communityChannel.position,
39333
- parentChannelId: communityChannel.parentChannelId,
39334
- creatorId: communityChannel.creatorId,
39335
- messageCount: communityChannel.messageCount,
39336
- archived: communityChannel.archived,
39337
- parentMessageId: communityChannel.parentMessageId,
39338
- lastMessageAt: communityChannel.lastMessageAt,
39339
- createdAt: communityChannel.createdAt
39340
- };
39341
-
39342
39460
  // ../shared/src/db/queries/community/thread.ts
39343
39461
  var NOTIFY_CONFLICT_TARGET = [
39344
39462
  communityChannelMember.channelId,
@@ -41224,9 +41342,9 @@ function compactLines(input2) {
41224
41342
  }
41225
41343
  return suffix;
41226
41344
  }
41227
- function isRealDirectory(path13) {
41345
+ function isRealDirectory(path14) {
41228
41346
  try {
41229
- return fs7.lstatSync(path13).isDirectory();
41347
+ return fs7.lstatSync(path14).isDirectory();
41230
41348
  } catch {
41231
41349
  return false;
41232
41350
  }
@@ -42292,26 +42410,26 @@ function createTimelineRecorder(opts) {
42292
42410
  }
42293
42411
  }
42294
42412
  // src/discovery.ts
42295
- import * as path13 from "path";
42413
+ import * as path14 from "path";
42296
42414
  import * as fs8 from "fs";
42297
42415
  import { fileURLToPath } from "url";
42298
42416
  function resolveAlookCliPath(moduleDir) {
42299
- const thisDir = moduleDir ?? path13.dirname(fileURLToPath(import.meta.url));
42300
- const target2 = path13.basename(thisDir) === "dist" ? path13.resolve(thisDir, "cli", "index.js") : path13.resolve(thisDir, "..", "scripts", "alook-shim.mjs");
42417
+ const thisDir = moduleDir ?? path14.dirname(fileURLToPath(import.meta.url));
42418
+ const target2 = path14.basename(thisDir) === "dist" ? path14.resolve(thisDir, "cli", "index.js") : path14.resolve(thisDir, "..", "scripts", "alook-shim.mjs");
42301
42419
  return fs8.existsSync(target2) ? target2 : null;
42302
42420
  }
42303
42421
  function deriveCliFallbackCandidates(cliPath) {
42304
42422
  if (!cliPath)
42305
42423
  return [];
42306
- const normalized = cliPath.split(path13.sep).join("/");
42424
+ const normalized = cliPath.split(path14.sep).join("/");
42307
42425
  const marker = "/node_modules/";
42308
42426
  const idx = normalized.indexOf(marker);
42309
42427
  if (idx === -1)
42310
42428
  return [];
42311
42429
  const globalRoot = cliPath.slice(0, idx + marker.length - 1);
42312
- const tail = path13.join("dist", "cli", "index.js");
42430
+ const tail = path14.join("dist", "cli", "index.js");
42313
42431
  return [
42314
- path13.join(globalRoot, "@alook", "daemon", tail)
42432
+ path14.join(globalRoot, "@alook", "daemon", tail)
42315
42433
  ].filter((candidate) => candidate !== cliPath);
42316
42434
  }
42317
42435
  function resolveAlookCliPathWithFallback(primary) {
@@ -42446,15 +42564,15 @@ class MessageReminderScheduler {
42446
42564
  const startedAt = this.now();
42447
42565
  const dueAt = startedAt + input2.remindAfterMs;
42448
42566
  const sentRef = `${input2.channel}#${input2.sentSeq}`;
42449
- const record6 = {
42567
+ const record7 = {
42450
42568
  ...input2,
42451
42569
  sentRef,
42452
42570
  startedAt,
42453
42571
  dueAt,
42454
42572
  timer: undefined
42455
42573
  };
42456
- record6.timer = this.setTimer(() => {
42457
- if (this.reminders.get(key) !== record6)
42574
+ record7.timer = this.setTimer(() => {
42575
+ if (this.reminders.get(key) !== record7)
42458
42576
  return;
42459
42577
  this.reminders.delete(key);
42460
42578
  try {
@@ -42465,8 +42583,8 @@ class MessageReminderScheduler {
42465
42583
  Promise.resolve(delivery).catch(() => {});
42466
42584
  } catch {}
42467
42585
  }, input2.remindAfterMs);
42468
- record6.timer.unref?.();
42469
- this.reminders.set(key, record6);
42586
+ record7.timer.unref?.();
42587
+ this.reminders.set(key, record7);
42470
42588
  return { armed: true, dueAt };
42471
42589
  }
42472
42590
  observe(agentId, channel2, latestSeq) {
@@ -42506,7 +42624,7 @@ class MessageReminderScheduler {
42506
42624
 
42507
42625
  // src/manager/agentDriverHost.ts
42508
42626
  import { randomUUID as randomUUID8 } from "node:crypto";
42509
- import { homedir as homedir9 } from "node:os";
42627
+ import { homedir as homedir11 } from "node:os";
42510
42628
  import { join as join16 } from "node:path";
42511
42629
 
42512
42630
  // src/drivers/gitIdentityEnv.ts
@@ -42632,7 +42750,7 @@ function createDaemonAgentDriverHost(ctx, onRawLine) {
42632
42750
  hostUser: readHostGitIdentity() ?? undefined
42633
42751
  }),
42634
42752
  platformProtected: {
42635
- ALOOK_HOME: process.env.ALOOK_HOME ?? join16(homedir9(), ".alook"),
42753
+ ALOOK_HOME: process.env.ALOOK_HOME ?? join16(homedir11(), ".alook"),
42636
42754
  ALOOK_ID: ctx.agentId,
42637
42755
  ALOOK_CLI: ctx.agentCliPath,
42638
42756
  ALOOK_SERVER_URL: ctx.config.serverUrl,
@@ -42738,7 +42856,7 @@ class DaemonSelfSleepScheduler {
42738
42856
  }
42739
42857
 
42740
42858
  // src/telemetry/dailyTokenUsage.ts
42741
- import { chmod, mkdir, open as open2, readFile as readFile3, rename, rm } from "node:fs/promises";
42859
+ import { chmod, mkdir, open as open3, readFile as readFile3, rename, rm } from "node:fs/promises";
42742
42860
  import { dirname as dirname5, join as join17 } from "node:path";
42743
42861
  import { randomUUID as randomUUID9 } from "node:crypto";
42744
42862
  var TOKEN_USAGE_WINDOW_DAYS = 30;
@@ -42991,7 +43109,7 @@ class DailyTokenUsageStore {
42991
43109
  await mkdir(directory, { recursive: true, mode: 448 });
42992
43110
  const temporary = `${this.filePath}.${randomUUID9()}.tmp`;
42993
43111
  try {
42994
- const file2 = await open2(temporary, "wx", 384);
43112
+ const file2 = await open3(temporary, "wx", 384);
42995
43113
  try {
42996
43114
  await file2.writeFile(JSON.stringify(this.data), { encoding: "utf8" });
42997
43115
  await file2.sync();
@@ -43001,7 +43119,7 @@ class DailyTokenUsageStore {
43001
43119
  await rename(temporary, this.filePath);
43002
43120
  await chmod(this.filePath, 384);
43003
43121
  try {
43004
- const directoryHandle = await open2(directory, "r");
43122
+ const directoryHandle = await open3(directory, "r");
43005
43123
  try {
43006
43124
  await directoryHandle.sync();
43007
43125
  } finally {
@@ -43096,13 +43214,13 @@ function createRuntimeRawLineTap(args) {
43096
43214
  const maxBytes = args.maxBytes ?? RUNTIME_RAW_TRACE_MAX_BYTES;
43097
43215
  const sinks = new Map;
43098
43216
  const warned = new Set;
43099
- const warnOnce = (agentId, path14, operation, error62) => {
43217
+ const warnOnce = (agentId, path15, operation, error62) => {
43100
43218
  if (warned.has(agentId))
43101
43219
  return;
43102
43220
  warned.add(agentId);
43103
43221
  args.logger.warn("runtime raw trace sink failed", {
43104
43222
  agentId,
43105
- path: path14,
43223
+ path: path15,
43106
43224
  operation,
43107
43225
  error: error62 instanceof Error ? error62.message : String(error62)
43108
43226
  });
@@ -43111,10 +43229,10 @@ function createRuntimeRawLineTap(args) {
43111
43229
  if (!args.enabledAgentIds.has(agentId))
43112
43230
  return;
43113
43231
  const encodedAgentId = encodeURIComponent(agentId).replace(/\./g, "%2E");
43114
- const path14 = `${traceDir}/runtime-raw-events-${encodedAgentId}.jsonl`;
43232
+ const path15 = `${traceDir}/runtime-raw-events-${encodedAgentId}.jsonl`;
43115
43233
  const serializedBytes = Buffer.byteLength(line, "utf8") + 1;
43116
43234
  if (serializedBytes > maxBytes) {
43117
- warnOnce(agentId, path14, "oversize", new Error(`raw line is ${serializedBytes} bytes; max is ${maxBytes}`));
43235
+ warnOnce(agentId, path15, "oversize", new Error(`raw line is ${serializedBytes} bytes; max is ${maxBytes}`));
43118
43236
  return;
43119
43237
  }
43120
43238
  let sink = sinks.get(agentId);
@@ -43122,12 +43240,12 @@ function createRuntimeRawLineTap(args) {
43122
43240
  try {
43123
43241
  mkdirSync8(traceDir, { recursive: true });
43124
43242
  } catch (error62) {
43125
- warnOnce(agentId, path14, "mkdir", error62);
43243
+ warnOnce(agentId, path15, "mkdir", error62);
43126
43244
  }
43127
- sink = createRotatingFileSink(path14, maxBytes, {
43245
+ sink = createRotatingFileSink(path15, maxBytes, {
43128
43246
  mode: 384,
43129
43247
  hardMaxBytes: true,
43130
- onError: ({ operation, error: error62 }) => warnOnce(agentId, path14, operation, error62)
43248
+ onError: ({ operation, error: error62 }) => warnOnce(agentId, path15, operation, error62)
43131
43249
  });
43132
43250
  sinks.set(agentId, sink);
43133
43251
  }
@@ -43221,7 +43339,7 @@ async function createDaemon(opts) {
43221
43339
  const log2 = opts.logger ?? createLogger({ header: "@alook/daemon" });
43222
43340
  const recentContextSdk = createAgentDriverSdk();
43223
43341
  const appendRecentContext = createRecentContextPromptAppender((input2) => recentContextSdk.discoverRecentContext(input2));
43224
- const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${homedir10()}/.alook`) + "/daemon";
43342
+ const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${homedir12()}/.alook`) + "/daemon";
43225
43343
  const workingDirectoryBase = opts.workingDirectoryBase ?? fallbackBase;
43226
43344
  const workdirFor = (agentId) => `${workingDirectoryBase}/${agentId}`;
43227
43345
  const dailyTokenUsage2 = new DailyTokenUsageStore(workingDirectoryBase);