@alook/daemon 0.1.30 → 0.1.32

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 +989 -195
  2. package/dist/index.js +840 -118
  3. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -15979,6 +15979,7 @@ var TERMINAL_MEETING_STATUSES = [
15979
15979
  MeetingStatus.COMPLETED,
15980
15980
  MeetingStatus.FAILED
15981
15981
  ];
15982
+ var COMMUNITY_BOT_LIMIT_PER_OWNER = 20;
15982
15983
  var COMMUNITY_BOT_NAME_MIN = 1;
15983
15984
  var COMMUNITY_BOT_NAME_MAX = 32;
15984
15985
  var COMMUNITY_BOT_DESCRIPTION_MAX = 1024;
@@ -16853,6 +16854,13 @@ var HostCommandSchema = exports_external.discriminatedUnion("type", [
16853
16854
  launchId: exports_external.string().min(1),
16854
16855
  unreadNotice: exports_external.unknown()
16855
16856
  }),
16857
+ exports_external.object({
16858
+ type: exports_external.literal("agent:event"),
16859
+ agentId: exports_external.string().min(1),
16860
+ config: exports_external.unknown(),
16861
+ launchId: exports_external.string().min(1),
16862
+ prompt: exports_external.string().min(1).max(32768)
16863
+ }),
16856
16864
  exports_external.object({
16857
16865
  type: exports_external.literal("agent:stop"),
16858
16866
  agentId: exports_external.string().min(1)
@@ -17762,6 +17770,10 @@ var CommunityBotPatchRequestSchema = exports_external.object({
17762
17770
  var CommunityBotAddToServerRequestSchema = exports_external.object({
17763
17771
  botId: exports_external.string().min(1)
17764
17772
  });
17773
+ var CommunityServerOnboardRequestSchema = exports_external.strictObject({
17774
+ botIds: exports_external.array(exports_external.string().min(1).max(128)).min(1).max(COMMUNITY_BOT_LIMIT_PER_OWNER).refine((ids) => new Set(ids).size === ids.length, "botIds must be unique"),
17775
+ wakePrompt: exports_external.string().max(32768).refine((value) => value.trim().length > 0, "wakePrompt is required")
17776
+ });
17765
17777
  var CommunityAgentMessageContentSchema = exports_external.object({ text: exports_external.string().max(MAX_MESSAGE_CONTENT_LENGTH).default("") }).catchall(exports_external.unknown());
17766
17778
  var CommunityAgentSeqSchema = exports_external.number().int().min(0);
17767
17779
  var CommunityAgentPositiveSeqSchema = exports_external.number().int().min(1);
@@ -17856,6 +17868,9 @@ var AuditLogThinkingPayloadSchema = exports_external.object({
17856
17868
  truncated: exports_external.boolean(),
17857
17869
  chars: exports_external.number().int().nonnegative()
17858
17870
  });
17871
+ var AuditLogTurnInterruptPayloadSchema = exports_external.object({
17872
+ status: exports_external.literal("accepted")
17873
+ });
17859
17874
  var AuditLogWakeTriggerPayloadSchema = exports_external.object({
17860
17875
  messageId: exports_external.string().min(1),
17861
17876
  channel: exports_external.string().min(1),
@@ -17888,6 +17903,7 @@ var BotAuditEventSchema = exports_external.discriminatedUnion("kind", [
17888
17903
  exports_external.object({ kind: exports_external.literal("cli_invocation"), payload: AuditLogCliInvocationPayloadSchema }),
17889
17904
  exports_external.object({ kind: exports_external.literal("tool_call"), payload: AuditLogToolCallPayloadSchema }),
17890
17905
  exports_external.object({ kind: exports_external.literal("thinking"), payload: AuditLogThinkingPayloadSchema }),
17906
+ exports_external.object({ kind: exports_external.literal("turn_interrupt"), payload: AuditLogTurnInterruptPayloadSchema }),
17891
17907
  exports_external.object({ kind: exports_external.literal("wake_trigger"), payload: AuditLogWakeTriggerPayloadSchema }),
17892
17908
  exports_external.object({ kind: exports_external.literal("session_reset"), payload: AuditLogSessionResetPayloadSchema }),
17893
17909
  exports_external.object({ kind: exports_external.literal("nap"), payload: AuditLogNapPayloadSchema }),
@@ -17899,6 +17915,7 @@ var BotAuditEventKindSchema = exports_external.enum([
17899
17915
  "cli_invocation",
17900
17916
  "tool_call",
17901
17917
  "thinking",
17918
+ "turn_interrupt",
17902
17919
  "wake_trigger",
17903
17920
  "session_reset",
17904
17921
  "nap",
@@ -18855,7 +18872,7 @@ var communityBotAuditEventSchema = exports_external.strictObject({
18855
18872
  type: exports_external.literal("community:bot.audit_event"),
18856
18873
  botId: string4,
18857
18874
  id: string4,
18858
- kind: exports_external.enum(["cli_invocation", "tool_call", "thinking", "wake_trigger", "session_reset", "nap", "model_changed", "provider_changed", "error"]),
18875
+ kind: exports_external.enum(["cli_invocation", "tool_call", "thinking", "turn_interrupt", "wake_trigger", "session_reset", "nap", "model_changed", "provider_changed", "error"]),
18859
18876
  payload: exports_external.unknown(),
18860
18877
  sessionId: nullableString.optional(),
18861
18878
  launchId: nullableString.optional(),
@@ -19552,13 +19569,13 @@ function createProxyServerApi(config2) {
19552
19569
 
19553
19570
  // src/cli/daemonStart.ts
19554
19571
  import * as fs12 from "fs";
19555
- import * as path13 from "path";
19572
+ import * as path17 from "path";
19556
19573
  import * as crypto5 from "crypto";
19557
19574
  import * as os3 from "os";
19558
- import { homedir as homedir6 } from "os";
19575
+ import { homedir as homedir8 } from "os";
19559
19576
 
19560
19577
  // src/discovery.ts
19561
- import * as path9 from "path";
19578
+ import * as path13 from "path";
19562
19579
  import * as fs6 from "fs";
19563
19580
  import { fileURLToPath } from "url";
19564
19581
  // agent-driver/dist/host/default-host.js
@@ -20702,6 +20719,12 @@ function tryParseJsonLine(line) {
20702
20719
  return null;
20703
20720
  }
20704
20721
  }
20722
+ function asRecord(value) {
20723
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
20724
+ }
20725
+ function tryParseJsonRecord(line) {
20726
+ return asRecord(tryParseJsonLine(line));
20727
+ }
20705
20728
 
20706
20729
  // agent-driver/dist/adapters/claude/normalizer.js
20707
20730
  var API_ERROR_RE = /API Error:.*(?:Connection error|\b[45]\d{2}\b)/i;
@@ -21200,6 +21223,241 @@ class ClaudeTurnProtocol {
21200
21223
  }
21201
21224
  }
21202
21225
 
21226
+ // agent-driver/dist/adapters/claude/recent-context.js
21227
+ import { createReadStream as createReadStream2 } from "node:fs";
21228
+ import { homedir } from "node:os";
21229
+ import path7 from "node:path";
21230
+ import { createInterface } from "node:readline";
21231
+
21232
+ // agent-driver/dist/internal/recent-context.js
21233
+ import path6 from "node:path";
21234
+ import { createReadStream } from "node:fs";
21235
+ import { readdir, stat } from "node:fs/promises";
21236
+ function normalizeAbsolutePath(value) {
21237
+ if (typeof value !== "string" || !path6.isAbsolute(value))
21238
+ return null;
21239
+ return path6.normalize(value);
21240
+ }
21241
+ function normalizeModifiedAt(value) {
21242
+ const date5 = value instanceof Date ? value : typeof value === "string" || typeof value === "number" ? new Date(value) : null;
21243
+ if (!date5 || !Number.isFinite(date5.getTime()))
21244
+ return null;
21245
+ return date5.toISOString();
21246
+ }
21247
+ function isValidRecentContextTopK(value) {
21248
+ return Number.isSafeInteger(value) && value >= 0;
21249
+ }
21250
+ function isMissingPathError(error51) {
21251
+ return error51?.code === "ENOENT";
21252
+ }
21253
+ async function readFirstLine(filePath, maxBytes = 65536) {
21254
+ const stream = createReadStream(filePath, { highWaterMark: 1 });
21255
+ const bytes = [];
21256
+ let length = 0;
21257
+ try {
21258
+ for await (const chunk2 of stream) {
21259
+ const byte = Buffer.isBuffer(chunk2) ? chunk2 : Buffer.from(chunk2);
21260
+ if (byte[0] === 10)
21261
+ break;
21262
+ if (length >= maxBytes)
21263
+ return null;
21264
+ bytes.push(byte);
21265
+ length += byte.length;
21266
+ }
21267
+ return length === 0 ? null : Buffer.concat(bytes, length).toString("utf8").replace(/\r$/, "");
21268
+ } catch (error51) {
21269
+ if (isMissingPathError(error51))
21270
+ return null;
21271
+ throw error51;
21272
+ } finally {
21273
+ stream.destroy();
21274
+ }
21275
+ }
21276
+ async function collectJsonlFileCandidates(root, options = {}) {
21277
+ const candidates = [];
21278
+ const readDirectory = options.readDirectory ?? ((directory) => readdir(directory, { withFileTypes: true }));
21279
+ const statPath = options.statPath ?? stat;
21280
+ const visit = async (directory, remainingDepth, includeFiles) => {
21281
+ let entries;
21282
+ try {
21283
+ entries = await readDirectory(directory);
21284
+ } catch (error51) {
21285
+ if (isMissingPathError(error51))
21286
+ return;
21287
+ throw error51;
21288
+ }
21289
+ await Promise.all(entries.map(async (entry) => {
21290
+ const entryPath = path6.join(directory, entry.name);
21291
+ if (entry.isDirectory() && remainingDepth > 0) {
21292
+ await visit(entryPath, remainingDepth - 1, true);
21293
+ } else if (includeFiles && entry.isFile() && entry.name.endsWith(".jsonl")) {
21294
+ try {
21295
+ const metadata = await statPath(entryPath);
21296
+ if (metadata.isFile())
21297
+ candidates.push({ filePath: entryPath, modifiedAt: metadata.mtime });
21298
+ } catch (error51) {
21299
+ if (!isMissingPathError(error51))
21300
+ throw error51;
21301
+ }
21302
+ }
21303
+ }));
21304
+ };
21305
+ await visit(root, options.maxDepth ?? Number.POSITIVE_INFINITY, options.includeRootFiles ?? true);
21306
+ return candidates;
21307
+ }
21308
+ function retainNewest(values, key, value, topK) {
21309
+ const existing = values.get(key);
21310
+ if (existing) {
21311
+ if (value.modifiedAt > existing.modifiedAt)
21312
+ values.set(key, value);
21313
+ return;
21314
+ }
21315
+ if (values.size < topK) {
21316
+ values.set(key, value);
21317
+ return;
21318
+ }
21319
+ let oldest;
21320
+ for (const entry of values) {
21321
+ if (!oldest || entry[1].modifiedAt < oldest[1].modifiedAt)
21322
+ oldest = entry;
21323
+ }
21324
+ if (oldest && value.modifiedAt > oldest[1].modifiedAt) {
21325
+ values.delete(oldest[0]);
21326
+ values.set(key, value);
21327
+ }
21328
+ }
21329
+
21330
+ class RecentContextCollector {
21331
+ request;
21332
+ sessionFileCapability;
21333
+ sessions = new Map;
21334
+ projects = new Map;
21335
+ constructor(request, sessionFileCapability) {
21336
+ this.request = request;
21337
+ this.sessionFileCapability = sessionFileCapability;
21338
+ }
21339
+ add(candidate, target2 = "both") {
21340
+ const projectPath = normalizeAbsolutePath(candidate.projectPath);
21341
+ const modifiedAt = normalizeModifiedAt(candidate.modifiedAt);
21342
+ if (!projectPath || !modifiedAt)
21343
+ return;
21344
+ if (target2 !== "session") {
21345
+ retainNewest(this.projects, projectPath, { projectPath, modifiedAt }, this.request.recentProjectsTopK);
21346
+ }
21347
+ if (target2 === "project" || this.sessionFileCapability !== "supported")
21348
+ return;
21349
+ const sessionFilePath = normalizeAbsolutePath(candidate.sessionFilePath);
21350
+ if (!sessionFilePath)
21351
+ return;
21352
+ retainNewest(this.sessions, sessionFilePath, { sessionFilePath, projectPath, modifiedAt }, this.request.recentSessionFilesTopK);
21353
+ }
21354
+ get satisfied() {
21355
+ const sessionsSatisfied = this.sessionFileCapability === "unavailable" || this.sessions.size >= this.request.recentSessionFilesTopK;
21356
+ return sessionsSatisfied && this.projects.size >= this.request.recentProjectsTopK;
21357
+ }
21358
+ result() {
21359
+ const newestFirst = (left, right) => right.modifiedAt.localeCompare(left.modifiedAt);
21360
+ return {
21361
+ sessionFiles: {
21362
+ capability: this.sessionFileCapability,
21363
+ items: [...this.sessions.values()].sort(newestFirst).slice(0, this.request.recentSessionFilesTopK)
21364
+ },
21365
+ recentProjects: [...this.projects.values()].sort(newestFirst).slice(0, this.request.recentProjectsTopK)
21366
+ };
21367
+ }
21368
+ }
21369
+ function sanitizeRecentContextData(value, request) {
21370
+ if (!value || typeof value !== "object" || Array.isArray(value))
21371
+ return null;
21372
+ const candidate = value;
21373
+ if (!candidate.sessionFiles || typeof candidate.sessionFiles !== "object" || Array.isArray(candidate.sessionFiles)) {
21374
+ return null;
21375
+ }
21376
+ const sessionFiles = candidate.sessionFiles;
21377
+ const capability = sessionFiles.capability;
21378
+ if (capability !== "supported" && capability !== "unavailable" || !Array.isArray(sessionFiles.items)) {
21379
+ return null;
21380
+ }
21381
+ if (!Array.isArray(candidate.recentProjects))
21382
+ return null;
21383
+ const collector = new RecentContextCollector(request, capability);
21384
+ if (capability === "supported") {
21385
+ for (const item of sessionFiles.items) {
21386
+ if (!item || typeof item !== "object" || Array.isArray(item))
21387
+ continue;
21388
+ const record2 = item;
21389
+ collector.add({
21390
+ sessionFilePath: record2.sessionFilePath,
21391
+ projectPath: record2.projectPath,
21392
+ modifiedAt: record2.modifiedAt
21393
+ }, "session");
21394
+ }
21395
+ }
21396
+ for (const item of candidate.recentProjects) {
21397
+ if (!item || typeof item !== "object" || Array.isArray(item))
21398
+ continue;
21399
+ const record2 = item;
21400
+ collector.add({ projectPath: record2.projectPath, modifiedAt: record2.modifiedAt }, "project");
21401
+ }
21402
+ return collector.result();
21403
+ }
21404
+
21405
+ // agent-driver/dist/adapters/claude/recent-context.js
21406
+ async function readClaudeProjectPath(filePath) {
21407
+ const input = createReadStream2(filePath);
21408
+ const lines = createInterface({ input, crlfDelay: Infinity });
21409
+ try {
21410
+ for await (const line of lines) {
21411
+ let record2;
21412
+ try {
21413
+ record2 = JSON.parse(line);
21414
+ } catch {
21415
+ continue;
21416
+ }
21417
+ if (!record2 || typeof record2 !== "object")
21418
+ continue;
21419
+ const cwd = record2.cwd;
21420
+ if (typeof cwd === "string" && path7.isAbsolute(cwd))
21421
+ return cwd;
21422
+ }
21423
+ return null;
21424
+ } catch (error51) {
21425
+ if (isMissingPathError(error51))
21426
+ return null;
21427
+ throw error51;
21428
+ } finally {
21429
+ lines.close();
21430
+ input.destroy();
21431
+ }
21432
+ }
21433
+ async function discoverClaudeRecentContext(request, dependencies = {}) {
21434
+ const collector = new RecentContextCollector(request, "supported");
21435
+ if (collector.satisfied)
21436
+ return collector.result();
21437
+ const projectsRoot = path7.resolve(dependencies.projectsRoot ?? path7.join(process.env.CLAUDE_CONFIG_DIR || path7.join(homedir(), ".claude"), "projects"));
21438
+ const readProjectPath = dependencies.readProjectPath ?? readClaudeProjectPath;
21439
+ const candidates = await collectJsonlFileCandidates(projectsRoot, {
21440
+ includeRootFiles: false,
21441
+ maxDepth: 1,
21442
+ readDirectory: dependencies.readDirectory,
21443
+ statPath: dependencies.statPath
21444
+ });
21445
+ candidates.sort((left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime());
21446
+ for (const candidate of candidates) {
21447
+ const projectPath = await readProjectPath(candidate.filePath);
21448
+ if (!projectPath)
21449
+ continue;
21450
+ collector.add({
21451
+ sessionFilePath: candidate.filePath,
21452
+ projectPath,
21453
+ modifiedAt: candidate.modifiedAt
21454
+ });
21455
+ if (collector.satisfied)
21456
+ break;
21457
+ }
21458
+ return collector.result();
21459
+ }
21460
+
21203
21461
  // agent-driver/dist/adapters/claude/index.js
21204
21462
  var CLAUDE_MODEL_CATALOG = {
21205
21463
  updateMode: "unsupported",
@@ -21221,6 +21479,9 @@ class ClaudeDriver {
21221
21479
  turnProtocol = new ClaudeTurnProtocol;
21222
21480
  eventNormalizer = new ClaudeEventNormalizer(this.turnProtocol);
21223
21481
  pendingInterrupt;
21482
+ discoverRecentContext(request) {
21483
+ return discoverClaudeRecentContext(request);
21484
+ }
21224
21485
  beginTurn() {
21225
21486
  this.pendingInterrupt = undefined;
21226
21487
  const receipt = this.turnProtocol.beginTurn();
@@ -21484,16 +21745,16 @@ function normalizeFileChangeInput(item) {
21484
21745
  for (const candidate of changePaths) {
21485
21746
  if (typeof candidate !== "string")
21486
21747
  continue;
21487
- const path6 = candidate.trim();
21488
- if (!path6 || seen.has(path6))
21748
+ const path8 = candidate.trim();
21749
+ if (!path8 || seen.has(path8))
21489
21750
  continue;
21490
- seen.add(path6);
21491
- paths.push(path6);
21751
+ seen.add(path8);
21752
+ paths.push(path8);
21492
21753
  }
21493
21754
  if (paths.length === 0 && typeof item?.path === "string") {
21494
- const path6 = item.path.trim();
21495
- if (path6)
21496
- paths.push(path6);
21755
+ const path8 = item.path.trim();
21756
+ if (path8)
21757
+ paths.push(path8);
21497
21758
  }
21498
21759
  return paths.length > 0 ? { path: paths.join(", ") } : {};
21499
21760
  }
@@ -21862,7 +22123,7 @@ class CodexEventNormalizer {
21862
22123
 
21863
22124
  // agent-driver/dist/adapters/codex/home.js
21864
22125
  import * as os from "os";
21865
- import * as path6 from "path";
22126
+ import * as path8 from "path";
21866
22127
  function readConfiguredCodexHome(env) {
21867
22128
  const raw = env.CODEX_HOME;
21868
22129
  return typeof raw === "string" && raw.trim().length > 0 ? raw : null;
@@ -21870,8 +22131,8 @@ function readConfiguredCodexHome(env) {
21870
22131
  function resolveCodexHomeRootFromEnv(env = process.env, opts = {}) {
21871
22132
  const raw = readConfiguredCodexHome(env);
21872
22133
  if (raw)
21873
- return path6.resolve(opts.cwd ?? process.cwd(), raw);
21874
- return path6.join(opts.defaultHomeDir ?? os.homedir(), ".codex");
22134
+ return path8.resolve(opts.cwd ?? process.cwd(), raw);
22135
+ return path8.join(opts.defaultHomeDir ?? os.homedir(), ".codex");
21875
22136
  }
21876
22137
 
21877
22138
  // agent-driver/dist/internal/errors.js
@@ -21964,6 +22225,49 @@ function parsePiModelCatalog(values) {
21964
22225
  return catalogFromIds(ids);
21965
22226
  }
21966
22227
 
22228
+ // agent-driver/dist/adapters/codex/recent-context.js
22229
+ import path9 from "node:path";
22230
+ function isChildSession(payload) {
22231
+ if (payload.parentThreadId != null || payload.parent_thread_id != null)
22232
+ return true;
22233
+ const source = payload.source;
22234
+ if (typeof source === "string")
22235
+ return source.toLowerCase().startsWith("subagent");
22236
+ const sourceRecord = asRecord(source);
22237
+ return sourceRecord != null && (("subagent" in sourceRecord) || ("subAgent" in sourceRecord));
22238
+ }
22239
+ async function discoverCodexRecentContext(request, dependencies = {}) {
22240
+ const collector = new RecentContextCollector(request, "supported");
22241
+ if (collector.satisfied)
22242
+ return collector.result();
22243
+ const sessionsRoot = path9.resolve(dependencies.sessionsRoot ?? path9.join(resolveCodexHomeRootFromEnv(), "sessions"));
22244
+ const readHeader = dependencies.readHeader ?? readFirstLine;
22245
+ const candidates = await collectJsonlFileCandidates(sessionsRoot, {
22246
+ readDirectory: dependencies.readDirectory,
22247
+ statPath: dependencies.statPath
22248
+ });
22249
+ candidates.sort((left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime());
22250
+ for (const candidate of candidates) {
22251
+ const line = await readHeader(candidate.filePath);
22252
+ if (!line)
22253
+ continue;
22254
+ const header = tryParseJsonRecord(line);
22255
+ if (!header)
22256
+ continue;
22257
+ const payload = asRecord(header.payload);
22258
+ if (header.type !== "session_meta" || !payload || isChildSession(payload))
22259
+ continue;
22260
+ collector.add({
22261
+ sessionFilePath: candidate.filePath,
22262
+ projectPath: payload.cwd,
22263
+ modifiedAt: candidate.modifiedAt
22264
+ });
22265
+ if (collector.satisfied)
22266
+ break;
22267
+ }
22268
+ return collector.result();
22269
+ }
22270
+
21967
22271
  // agent-driver/dist/adapters/codex/index.js
21968
22272
  var SETTINGS_UPDATE_TIMEOUT_MS = 5000;
21969
22273
  var MODEL_LIST_TIMEOUT_MS = 5000;
@@ -21992,6 +22296,9 @@ class CodexDriver {
21992
22296
  eventNormalizer = new CodexEventNormalizer;
21993
22297
  pendingAccountReadRequestIds = new Set;
21994
22298
  requestId = 0;
22299
+ discoverRecentContext(request) {
22300
+ return discoverCodexRecentContext(request);
22301
+ }
21995
22302
  codexHomeRoot = null;
21996
22303
  proc = null;
21997
22304
  pendingInitialPrompt = null;
@@ -23168,6 +23475,196 @@ class CursorAcpLane {
23168
23475
  }
23169
23476
  }
23170
23477
 
23478
+ // agent-driver/dist/internal/discovery-process.js
23479
+ import { StringDecoder } from "node:string_decoder";
23480
+ function toBuffer(chunk2) {
23481
+ if (Buffer.isBuffer(chunk2))
23482
+ return chunk2;
23483
+ if (chunk2 instanceof Uint8Array)
23484
+ return Buffer.from(chunk2.buffer, chunk2.byteOffset, chunk2.byteLength);
23485
+ return Buffer.from(String(chunk2));
23486
+ }
23487
+ async function cleanupProcess(process3, label) {
23488
+ if (process3.pid)
23489
+ await killProcessTree(process3.pid, { graceMs: 250 });
23490
+ else if (process3.exitCode === null && process3.signalCode === null && !process3.kill("SIGTERM")) {
23491
+ throw new Error(`${label} discovery cleanup failed`);
23492
+ }
23493
+ }
23494
+ function onStream(stream, event, listener) {
23495
+ stream?.on?.(event, listener);
23496
+ }
23497
+ function runBoundedDiscoveryProcess(options) {
23498
+ return new Promise((resolve2, reject) => {
23499
+ const decoder = new StringDecoder("utf8");
23500
+ let settled = false;
23501
+ let decoderEnded = false;
23502
+ let outputBytes = 0;
23503
+ const settle = (result, error51) => {
23504
+ if (settled)
23505
+ return;
23506
+ settled = true;
23507
+ clearTimeout(timer);
23508
+ if (!decoderEnded)
23509
+ decoder.end();
23510
+ Promise.resolve().then(() => options.cleanup?.(options.process) ?? cleanupProcess(options.process, options.label)).then(() => error51 ? reject(error51) : resolve2(result), () => reject(error51 ?? new Error(`${options.label} discovery cleanup failed`)));
23511
+ };
23512
+ const control = {
23513
+ get outputBytes() {
23514
+ return outputBytes;
23515
+ },
23516
+ finish: (result) => settle(result),
23517
+ fail: (message2) => settle(undefined, new Error(message2)),
23518
+ flushStdout: () => {
23519
+ if (settled || decoderEnded)
23520
+ return;
23521
+ decoderEnded = true;
23522
+ options.onStdout(decoder.end(), true, control);
23523
+ },
23524
+ write: (line) => {
23525
+ const stdin = options.process.stdin;
23526
+ if (!stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false) {
23527
+ return control.fail(`${options.label} discovery transport is unavailable`);
23528
+ }
23529
+ try {
23530
+ stdin.write(line);
23531
+ } catch {
23532
+ control.fail(`${options.label} discovery transport write failed`);
23533
+ }
23534
+ }
23535
+ };
23536
+ const addBytes = (chunk2, decode3) => {
23537
+ if (settled)
23538
+ return;
23539
+ const bytes = toBuffer(chunk2);
23540
+ outputBytes += bytes.byteLength;
23541
+ if (outputBytes > options.outputMaxBytes) {
23542
+ control.fail(`${options.label} discovery output exceeded its bound`);
23543
+ } else if (decode3)
23544
+ options.onStdout(decoder.write(bytes), false, control);
23545
+ };
23546
+ const timer = setTimeout(() => control.fail(`${options.label} discovery timed out`), Math.max(1, options.timeoutMs));
23547
+ timer.unref?.();
23548
+ options.process.stdout?.on("data", (chunk2) => addBytes(chunk2, true));
23549
+ options.process.stderr?.on("data", (chunk2) => addBytes(chunk2, false));
23550
+ onStream(options.process.stdout, "end", control.flushStdout);
23551
+ for (const stream of [options.process.stdin, options.process.stdout, options.process.stderr]) {
23552
+ onStream(stream, "error", () => control.fail(`${options.label} discovery transport failed`));
23553
+ }
23554
+ options.process.on("error", () => control.fail(`${options.label} discovery process failed`));
23555
+ options.process.on(options.exitEvent, (code, signal) => options.onExit(code, signal, control));
23556
+ options.onStart?.(control);
23557
+ });
23558
+ }
23559
+
23560
+ // agent-driver/dist/adapters/cursor/recent-context.js
23561
+ var ACP_PROTOCOL_VERSION3 = 1;
23562
+ var AUTH_METHOD_ID3 = "cursor_login";
23563
+ var CURSOR_DISCOVERY_TIMEOUT_MS = 30000;
23564
+ var CURSOR_DISCOVERY_OUTPUT_MAX_BYTES = 4 * 1024 * 1024;
23565
+ async function discoverCursorRecentContext(request, dependencies = {}) {
23566
+ const collector = new RecentContextCollector(request, "unavailable");
23567
+ if (collector.satisfied)
23568
+ return collector.result();
23569
+ const spec = resolveSpawnSpec("cursor-agent", ["acp"], request.command);
23570
+ const processHandle = (dependencies.spawn ?? spawnAgentProcess)(spec.command, spec.args, {
23571
+ cwd: dependencies.cwd ?? process.cwd(),
23572
+ env: { ...process.env, CI: "1" },
23573
+ shell: spec.shell
23574
+ });
23575
+ let buffer = "";
23576
+ let requestId = 0;
23577
+ let expectedId = 0;
23578
+ let expectedMethod = "";
23579
+ const seenCursors = new Set;
23580
+ const requestRpc = (method, params, control) => {
23581
+ expectedId = ++requestId;
23582
+ expectedMethod = method;
23583
+ control.write(`${jsonRpcRequest(method, params, expectedId)}
23584
+ `);
23585
+ };
23586
+ const requestPage = (control, cursor) => requestRpc("session/list", cursor ? { cursor } : {}, control);
23587
+ const onLine = (line, control) => {
23588
+ const message2 = asRecord(tryParseJsonLine(line));
23589
+ if (!message2 || message2.id !== expectedId)
23590
+ return;
23591
+ if (message2.error !== undefined)
23592
+ return control.fail("Cursor discovery request failed");
23593
+ const result = asRecord(message2.result);
23594
+ if (!result)
23595
+ return control.fail("Cursor discovery returned an invalid response");
23596
+ if (expectedMethod === "initialize") {
23597
+ if (result.protocolVersion !== ACP_PROTOCOL_VERSION3) {
23598
+ return control.fail("Cursor discovery protocol is incompatible");
23599
+ }
23600
+ const capabilities = asRecord(result.agentCapabilities);
23601
+ const sessionCapabilities = asRecord(capabilities?.sessionCapabilities);
23602
+ if (sessionCapabilities?.list !== true && !asRecord(sessionCapabilities?.list)) {
23603
+ return control.fail("Cursor session listing is unavailable");
23604
+ }
23605
+ const authMethods = Array.isArray(result.authMethods) ? result.authMethods : [];
23606
+ if (!authMethods.some((method) => asRecord(method)?.id === AUTH_METHOD_ID3)) {
23607
+ return control.fail("Cursor discovery authentication is unavailable");
23608
+ }
23609
+ requestRpc("authenticate", { methodId: AUTH_METHOD_ID3 }, control);
23610
+ return;
23611
+ }
23612
+ if (expectedMethod === "authenticate") {
23613
+ requestPage(control);
23614
+ return;
23615
+ }
23616
+ if (expectedMethod !== "session/list")
23617
+ return control.fail("Cursor discovery state is invalid");
23618
+ const sessions = Array.isArray(result.sessions) ? result.sessions : Array.isArray(result.data) ? result.data : [];
23619
+ for (const value of sessions) {
23620
+ const session2 = asRecord(value);
23621
+ if (!session2)
23622
+ continue;
23623
+ collector.add({ projectPath: session2.cwd, modifiedAt: session2.updatedAt });
23624
+ if (collector.satisfied)
23625
+ return control.finish(collector.result());
23626
+ }
23627
+ const nextCursor = typeof result.nextCursor === "string" && result.nextCursor ? result.nextCursor : undefined;
23628
+ if (!nextCursor)
23629
+ return control.finish(collector.result());
23630
+ if (seenCursors.has(nextCursor))
23631
+ return control.fail("Cursor discovery cursor repeated");
23632
+ seenCursors.add(nextCursor);
23633
+ requestPage(control, nextCursor);
23634
+ };
23635
+ return runBoundedDiscoveryProcess({
23636
+ process: processHandle,
23637
+ label: "Cursor",
23638
+ timeoutMs: dependencies.timeoutMs ?? CURSOR_DISCOVERY_TIMEOUT_MS,
23639
+ outputMaxBytes: dependencies.outputMaxBytes ?? CURSOR_DISCOVERY_OUTPUT_MAX_BYTES,
23640
+ cleanup: dependencies.cleanup,
23641
+ exitEvent: "exit",
23642
+ onStdout: (text2, final, control) => {
23643
+ buffer += text2;
23644
+ const lines = buffer.split(`
23645
+ `);
23646
+ buffer = lines.pop() ?? "";
23647
+ for (const line of lines)
23648
+ if (line.trim())
23649
+ onLine(line, control);
23650
+ if (final && buffer.trim()) {
23651
+ const line = buffer;
23652
+ buffer = "";
23653
+ onLine(line, control);
23654
+ }
23655
+ },
23656
+ onExit: (_code, _signal, control) => control.fail("Cursor discovery process exited early"),
23657
+ onStart: (control) => requestRpc("initialize", {
23658
+ protocolVersion: ACP_PROTOCOL_VERSION3,
23659
+ clientCapabilities: {
23660
+ fs: { readTextFile: false, writeTextFile: false },
23661
+ terminal: false
23662
+ },
23663
+ clientInfo: { name: "alook-agent-driver-discovery", version: "0.1.31" }
23664
+ }, control)
23665
+ });
23666
+ }
23667
+
23171
23668
  // agent-driver/dist/adapters/cursor/index.js
23172
23669
  class CursorDriver {
23173
23670
  catalogProbe;
@@ -23179,6 +23676,9 @@ class CursorDriver {
23179
23676
  wakeStart: "immediate",
23180
23677
  terminalOwnership: "transport_request"
23181
23678
  };
23679
+ discoverRecentContext(request) {
23680
+ return discoverCursorRecentContext(request);
23681
+ }
23182
23682
  constructor(catalogProbe = probeCursorAcpCatalog) {
23183
23683
  this.catalogProbe = catalogProbe;
23184
23684
  }
@@ -23673,7 +24173,7 @@ class OpenCodeServiceLane {
23673
24173
  "/api/session/{sessionID}/permission/{requestID}/reply",
23674
24174
  "/api/event"
23675
24175
  ];
23676
- if (!paths || required2.some((path7) => !record4(paths[path7]))) {
24176
+ if (!paths || required2.some((path10) => !record4(paths[path10]))) {
23677
24177
  throw new OpenCodeIncompatibleError("Installed OpenCode service is missing required v2 session capabilities");
23678
24178
  }
23679
24179
  }
@@ -23731,8 +24231,8 @@ class OpenCodeServiceLane {
23731
24231
  const controller = new AbortController;
23732
24232
  this.durableAbort = controller;
23733
24233
  try {
23734
- const path7 = `/api/session/${encodeURIComponent(this.sessionId)}/event?after=${this.lastDurableSeq}`;
23735
- const response = await this.openStream(path7, controller, "durable event stream");
24234
+ const path10 = `/api/session/${encodeURIComponent(this.sessionId)}/event?after=${this.lastDurableSeq}`;
24235
+ const response = await this.openStream(path10, controller, "durable event stream");
23736
24236
  await this.catchUpHistory(true);
23737
24237
  if (!this.isIdentity(identity))
23738
24238
  return;
@@ -23806,12 +24306,12 @@ class OpenCodeServiceLane {
23806
24306
  return;
23807
24307
  this.protocolFailure(`OpenCode ${kind} stream stopped unexpectedly`, error51);
23808
24308
  }
23809
- async openStream(path7, lifecycle, operation) {
24309
+ async openStream(path10, lifecycle, operation) {
23810
24310
  const deadline = new AbortController;
23811
24311
  const timeout = setTimeout(() => deadline.abort(), this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS);
23812
24312
  timeout.unref?.();
23813
24313
  try {
23814
- const response = await this.fetchFn(`${this.baseUrl}${path7}`, {
24314
+ const response = await this.fetchFn(`${this.baseUrl}${path10}`, {
23815
24315
  method: "GET",
23816
24316
  headers: this.headers({ accept: "text/event-stream" }),
23817
24317
  signal: AbortSignal.any([lifecycle.signal, deadline.signal])
@@ -24238,8 +24738,8 @@ class OpenCodeServiceLane {
24238
24738
  turnOwner: root.receipt
24239
24739
  });
24240
24740
  }
24241
- async requestNoContent(path7, method, body, operation) {
24242
- const response = await this.fetchWithTimeout(path7, {
24741
+ async requestNoContent(path10, method, body, operation) {
24742
+ const response = await this.fetchWithTimeout(path10, {
24243
24743
  method,
24244
24744
  ...body ? {
24245
24745
  headers: { "content-type": "application/json" },
@@ -24249,7 +24749,7 @@ class OpenCodeServiceLane {
24249
24749
  if (!response.ok)
24250
24750
  throw new OpenCodeHttpError(response.status, operation);
24251
24751
  }
24252
- async fetchWithTimeout(path7, init, operation, timeoutMs = this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS) {
24752
+ async fetchWithTimeout(path10, init, operation, timeoutMs = this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS) {
24253
24753
  if (this.stopping)
24254
24754
  throw new Error("OpenCode service lane is stopping");
24255
24755
  const controller = new AbortController;
@@ -24257,7 +24757,7 @@ class OpenCodeServiceLane {
24257
24757
  const timer = setTimeout(() => controller.abort(), timeoutMs);
24258
24758
  timer.unref?.();
24259
24759
  try {
24260
- return await this.fetchFn(`${this.baseUrl}${path7}`, {
24760
+ return await this.fetchFn(`${this.baseUrl}${path10}`, {
24261
24761
  ...init,
24262
24762
  headers: this.headers(init.headers),
24263
24763
  signal: controller.signal
@@ -24269,7 +24769,7 @@ class OpenCodeServiceLane {
24269
24769
  this.requestControllers.delete(controller);
24270
24770
  }
24271
24771
  }
24272
- async fetchJsonWithTimeout(path7, init, operation, timeoutMs = this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS) {
24772
+ async fetchJsonWithTimeout(path10, init, operation, timeoutMs = this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS) {
24273
24773
  if (this.stopping)
24274
24774
  throw new OpenCodeStoppedError("OpenCode service lane is stopping");
24275
24775
  const controller = new AbortController;
@@ -24281,7 +24781,7 @@ class OpenCodeServiceLane {
24281
24781
  }, timeoutMs);
24282
24782
  timer.unref?.();
24283
24783
  try {
24284
- const response = await this.fetchFn(`${this.baseUrl}${path7}`, {
24784
+ const response = await this.fetchFn(`${this.baseUrl}${path10}`, {
24285
24785
  ...init,
24286
24786
  headers: this.headers(init.headers),
24287
24787
  signal: controller.signal
@@ -24374,6 +24874,75 @@ class OpenCodeServiceLane {
24374
24874
  }
24375
24875
  }
24376
24876
 
24877
+ // agent-driver/dist/adapters/opencode/recent-context.js
24878
+ var OPENCODE_DISCOVERY_TIMEOUT_MS = 15000;
24879
+ var OPENCODE_DISCOVERY_OUTPUT_MAX_BYTES = 4 * 1024 * 1024;
24880
+ function collectCommandOutput(command, args, shell, dependencies, timeoutMs, outputMaxBytes) {
24881
+ const processHandle = (dependencies.spawn ?? spawnAgentProcess)(command, args, {
24882
+ cwd: dependencies.cwd ?? process.cwd(),
24883
+ env: { ...process.env, CI: "1" },
24884
+ shell,
24885
+ stdin: "ignore"
24886
+ });
24887
+ let output = "";
24888
+ return runBoundedDiscoveryProcess({
24889
+ process: processHandle,
24890
+ label: "OpenCode",
24891
+ timeoutMs,
24892
+ outputMaxBytes,
24893
+ cleanup: dependencies.cleanup,
24894
+ exitEvent: "close",
24895
+ onStdout: (text2) => {
24896
+ output += text2;
24897
+ },
24898
+ onExit: (code, _signal, control) => {
24899
+ if (code !== 0)
24900
+ return control.fail("OpenCode session listing failed");
24901
+ control.flushStdout();
24902
+ control.finish({ output, outputBytes: control.outputBytes });
24903
+ }
24904
+ });
24905
+ }
24906
+ async function discoverOpenCodeRecentContext(request, dependencies = {}) {
24907
+ const collector = new RecentContextCollector(request, "unavailable");
24908
+ if (collector.satisfied)
24909
+ return collector.result();
24910
+ const startedAt = Date.now();
24911
+ const timeoutMs = dependencies.timeoutMs ?? OPENCODE_DISCOVERY_TIMEOUT_MS;
24912
+ let remainingOutputBytes = dependencies.outputMaxBytes ?? OPENCODE_DISCOVERY_OUTPUT_MAX_BYTES;
24913
+ let maxCount = Math.max(1, Math.min(Number.MAX_SAFE_INTEGER, request.recentProjectsTopK * 10));
24914
+ while (!collector.satisfied) {
24915
+ const remainingTimeoutMs = timeoutMs - (Date.now() - startedAt);
24916
+ if (remainingTimeoutMs <= 0)
24917
+ throw new Error("OpenCode discovery timed out");
24918
+ const spec = resolveSpawnSpec("opencode", ["session", "list", "--format", "json", "--max-count", String(maxCount), "--pure"], request.command);
24919
+ const commandOutput = await collectCommandOutput(spec.command, spec.args, spec.shell, dependencies, remainingTimeoutMs, remainingOutputBytes);
24920
+ remainingOutputBytes -= commandOutput.outputBytes;
24921
+ let parsed;
24922
+ try {
24923
+ parsed = JSON.parse(commandOutput.output);
24924
+ } catch {
24925
+ throw new Error("OpenCode session listing returned invalid JSON");
24926
+ }
24927
+ if (!Array.isArray(parsed))
24928
+ throw new Error("OpenCode session listing returned an invalid response");
24929
+ for (const value of parsed) {
24930
+ const session2 = asRecord(value);
24931
+ if (!session2)
24932
+ continue;
24933
+ const modifiedAt = session2.updated ?? session2.updatedAt;
24934
+ collector.add({ projectPath: session2.directory, modifiedAt });
24935
+ }
24936
+ if (collector.satisfied || parsed.length < maxCount)
24937
+ break;
24938
+ const nextMaxCount = Math.min(Number.MAX_SAFE_INTEGER, maxCount * 2);
24939
+ if (nextMaxCount === maxCount)
24940
+ throw new Error("OpenCode session listing could not prove the requested Top-K");
24941
+ maxCount = nextMaxCount;
24942
+ }
24943
+ return collector.result();
24944
+ }
24945
+
24377
24946
  // agent-driver/dist/adapters/opencode/index.js
24378
24947
  function createOpenCodeMessageId() {
24379
24948
  return `msg_${randomBytes3(16).toString("hex")}`;
@@ -24392,6 +24961,9 @@ class OpenCodeDriver {
24392
24961
  constructor(outputProbe = probeCommandOutput) {
24393
24962
  this.outputProbe = outputProbe;
24394
24963
  }
24964
+ discoverRecentContext(request) {
24965
+ return discoverOpenCodeRecentContext(request);
24966
+ }
24395
24967
  probe(command) {
24396
24968
  const result = probeCliRuntime("opencode", {}, command);
24397
24969
  if (result.status !== "healthy")
@@ -24438,8 +25010,8 @@ class OpenCodeDriver {
24438
25010
  // agent-driver/dist/adapters/pi/index.js
24439
25011
  import { createRequire as createRequire2 } from "module";
24440
25012
  import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3, realpathSync } from "fs";
24441
- import { homedir as homedir2 } from "os";
24442
- import * as path8 from "path";
25013
+ import { homedir as homedir4 } from "os";
25014
+ import * as path12 from "path";
24443
25015
 
24444
25016
  // agent-driver/dist/controller/sdk-host.js
24445
25017
  import { EventEmitter as EventEmitter4 } from "events";
@@ -24554,7 +25126,7 @@ class SdkLane {
24554
25126
 
24555
25127
  // agent-driver/dist/adapters/pi/sessionDeps.js
24556
25128
  import { readFileSync as readFileSync2 } from "fs";
24557
- import * as path7 from "path";
25129
+ import * as path10 from "path";
24558
25130
  import { pathToFileURL } from "url";
24559
25131
  var PI_SDK_PACKAGE_NAME = "@earendil-works/pi-coding-agent";
24560
25132
  var cachedSdkPromise = null;
@@ -24563,9 +25135,9 @@ async function importPiSdkFromGlobalInstall() {
24563
25135
  if (!dir) {
24564
25136
  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`);
24565
25137
  }
24566
- const pkg = JSON.parse(readFileSync2(path7.join(dir, "package.json"), "utf-8"));
25138
+ const pkg = JSON.parse(readFileSync2(path10.join(dir, "package.json"), "utf-8"));
24567
25139
  const entry = pkg.exports?.["."]?.import ?? pkg.main ?? "./dist/index.js";
24568
- const entryPath = path7.join(dir, entry);
25140
+ const entryPath = path10.join(dir, entry);
24569
25141
  const barrel = await import(pathToFileURL(entryPath).href);
24570
25142
  return withSessionDirHelper(barrel, entryPath);
24571
25143
  }
@@ -24573,7 +25145,7 @@ async function withSessionDirHelper(barrel, entryPath) {
24573
25145
  if (typeof barrel.getDefaultSessionDir === "function")
24574
25146
  return barrel;
24575
25147
  try {
24576
- const deepPath = path7.join(path7.dirname(entryPath), "core", "session-manager.js");
25148
+ const deepPath = path10.join(path10.dirname(entryPath), "core", "session-manager.js");
24577
25149
  const deep = await import(pathToFileURL(deepPath).href);
24578
25150
  if (typeof deep.getDefaultSessionDir !== "function")
24579
25151
  return barrel;
@@ -24653,6 +25225,51 @@ function createPiSessionDependencies(ctx, loadSdk = loadPiSdkModule) {
24653
25225
  };
24654
25226
  }
24655
25227
 
25228
+ // agent-driver/dist/adapters/pi/recent-context.js
25229
+ import { homedir as homedir3 } from "node:os";
25230
+ import path11 from "node:path";
25231
+ function expandTildePath(value) {
25232
+ if (value === "~")
25233
+ return homedir3();
25234
+ if (value.startsWith("~/"))
25235
+ return path11.join(homedir3(), value.slice(2));
25236
+ return value;
25237
+ }
25238
+ async function discoverPiRecentContext(request, dependencies = {}) {
25239
+ const collector = new RecentContextCollector(request, "supported");
25240
+ if (collector.satisfied)
25241
+ return collector.result();
25242
+ const customSessionDirectory = process.env.PI_CODING_AGENT_SESSION_DIR;
25243
+ const sessionsRoot = path11.resolve(expandTildePath(dependencies.sessionsRoot ?? customSessionDirectory ?? path11.join(process.env.PI_CODING_AGENT_DIR || path11.join(homedir3(), ".pi", "agent"), "sessions")));
25244
+ const scanDirectSessions = dependencies.sessionsRoot == null && customSessionDirectory != null;
25245
+ const readHeader = dependencies.readHeader ?? readFirstLine;
25246
+ const candidates = await collectJsonlFileCandidates(sessionsRoot, {
25247
+ includeRootFiles: scanDirectSessions,
25248
+ maxDepth: 1,
25249
+ readDirectory: dependencies.readDirectory,
25250
+ statPath: dependencies.statPath
25251
+ });
25252
+ candidates.sort((left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime());
25253
+ for (const candidate of candidates) {
25254
+ const line = await readHeader(candidate.filePath);
25255
+ if (!line)
25256
+ continue;
25257
+ const header = tryParseJsonRecord(line);
25258
+ if (!header)
25259
+ continue;
25260
+ if (header.type !== "session" || header.parentSession != null)
25261
+ continue;
25262
+ collector.add({
25263
+ sessionFilePath: candidate.filePath,
25264
+ projectPath: header.cwd,
25265
+ modifiedAt: candidate.modifiedAt
25266
+ });
25267
+ if (collector.satisfied)
25268
+ break;
25269
+ }
25270
+ return collector.result();
25271
+ }
25272
+
24656
25273
  // agent-driver/dist/adapters/pi/index.js
24657
25274
  var PI_SDK_PACKAGE_NAME2 = "@earendil-works/pi-coding-agent";
24658
25275
  var PI_MODEL_PROBE_TIMEOUT_MS = 5000;
@@ -24671,15 +25288,15 @@ function resolvePiSdkPackageDir(deps = {}) {
24671
25288
  if (!binPath)
24672
25289
  return;
24673
25290
  try {
24674
- let dir = path8.dirname(realpathSync(binPath));
25291
+ let dir = path12.dirname(realpathSync(binPath));
24675
25292
  const MAX_DEPTH = 8;
24676
25293
  for (let i = 0;i < MAX_DEPTH; i++) {
24677
- if (isPiSdkPackageJson(path8.join(dir, "package.json")))
25294
+ if (isPiSdkPackageJson(path12.join(dir, "package.json")))
24678
25295
  return dir;
24679
- const siblingDir = path8.join(dir, "node_modules", PI_SDK_PACKAGE_NAME2);
24680
- if (isPiSdkPackageJson(path8.join(siblingDir, "package.json")))
25296
+ const siblingDir = path12.join(dir, "node_modules", PI_SDK_PACKAGE_NAME2);
25297
+ if (isPiSdkPackageJson(path12.join(siblingDir, "package.json")))
24681
25298
  return siblingDir;
24682
- const parent = path8.dirname(dir);
25299
+ const parent = path12.dirname(dir);
24683
25300
  if (parent === dir)
24684
25301
  break;
24685
25302
  dir = parent;
@@ -24696,21 +25313,21 @@ function findPiSessionFile(sessionDir, sessionId) {
24696
25313
  }
24697
25314
  const suffix = `_${sessionId}.jsonl`;
24698
25315
  const match = entries.find((entry) => entry.endsWith(suffix));
24699
- return match ? path8.join(sessionDir, match) : null;
25316
+ return match ? path12.join(sessionDir, match) : null;
24700
25317
  }
24701
25318
  function resolvePiSessionDir(sdk, cwd) {
24702
25319
  if (typeof sdk.getDefaultSessionDir === "function")
24703
25320
  return sdk.getDefaultSessionDir(cwd);
24704
- const agentDir = typeof sdk.getAgentDir === "function" ? sdk.getAgentDir() : path8.join(homedir2(), ".pi", "agent");
24705
- const encoded = `--${path8.resolve(cwd).replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
24706
- return path8.join(agentDir, "sessions", encoded);
25321
+ const agentDir = typeof sdk.getAgentDir === "function" ? sdk.getAgentDir() : path12.join(homedir4(), ".pi", "agent");
25322
+ const encoded = `--${path12.resolve(cwd).replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
25323
+ return path12.join(agentDir, "sessions", encoded);
24707
25324
  }
24708
25325
  function resolvePiSdkVersionFromPath(deps = {}) {
24709
25326
  const dir = resolvePiSdkPackageDir(deps);
24710
25327
  if (!dir)
24711
25328
  return;
24712
25329
  try {
24713
- const pkg = JSON.parse(readFileSync3(path8.join(dir, "package.json"), "utf-8"));
25330
+ const pkg = JSON.parse(readFileSync3(path12.join(dir, "package.json"), "utf-8"));
24714
25331
  return pkg.version;
24715
25332
  } catch {
24716
25333
  return;
@@ -24814,6 +25431,9 @@ class PiDriver {
24814
25431
  };
24815
25432
  sessionId = null;
24816
25433
  terminalSequence = 0;
25434
+ discoverRecentContext(request) {
25435
+ return discoverPiRecentContext(request);
25436
+ }
24817
25437
  constructor(dependenciesFor = createPiSessionDependencies, loadSdk = loadPiSdkModule, readVersion = readPiSdkVersion) {
24818
25438
  this.dependenciesFor = dependenciesFor;
24819
25439
  this.loadSdk = loadSdk;
@@ -24959,6 +25579,9 @@ function assertAdapterCompatibility(registrationId, registeredCapabilities, adap
24959
25579
  if (typeof candidate[method] !== "function")
24960
25580
  throw new Error(`Adapter ${registrationId} is missing ${method}()`);
24961
25581
  }
25582
+ if (candidate.discoverRecentContext !== undefined && typeof candidate.discoverRecentContext !== "function") {
25583
+ throw new Error(`Adapter ${registrationId} has an invalid discoverRecentContext()`);
25584
+ }
24962
25585
  const instruction = candidate.instructionDelivery;
24963
25586
  if (!instruction || instruction.kind !== "native" && instruction.kind !== "workspace_file") {
24964
25587
  throw new Error(`Adapter ${registrationId} has an invalid instructionDelivery declaration`);
@@ -25180,8 +25803,8 @@ function ensureSymlinks(workDir, canonical = CANONICAL_FILE, aliases = SYMLINK_A
25180
25803
  continue;
25181
25804
  const aliasPath = join8(workDir, alias2);
25182
25805
  try {
25183
- const stat = lstatSync(aliasPath);
25184
- if (stat.isSymbolicLink()) {
25806
+ const stat2 = lstatSync(aliasPath);
25807
+ if (stat2.isSymbolicLink()) {
25185
25808
  const target2 = readlinkSync(aliasPath);
25186
25809
  if (target2 === canonical)
25187
25810
  continue;
@@ -25344,6 +25967,7 @@ class LogicalAgentSession {
25344
25967
  steeringDeliveries = new Set;
25345
25968
  laneAdmissionTail = Promise.resolve();
25346
25969
  laneAdmissionPending = 0;
25970
+ toolBoundaryOpen = true;
25347
25971
  toolBoundaryFlushDisabled = false;
25348
25972
  safeBoundaryFlush;
25349
25973
  safeBoundaryDelivery;
@@ -25624,6 +26248,8 @@ class LogicalAgentSession {
25624
26248
  this.turnError = undefined;
25625
26249
  this.interruptedTurnId = undefined;
25626
26250
  this.processTurnEnded = false;
26251
+ this.toolBoundaryOpen = true;
26252
+ this.toolBoundaryFlushDisabled = false;
25627
26253
  this.state = "starting";
25628
26254
  const generation = this.lifecycleGeneration;
25629
26255
  const text2 = messages.map((message2) => message2.text).join(`
@@ -25856,6 +26482,7 @@ class LogicalAgentSession {
25856
26482
  }
25857
26483
  if (!this.startToolUse(event.callId))
25858
26484
  return;
26485
+ this.toolBoundaryOpen = false;
25859
26486
  const startedCallId = this.toolCallId(event.callId);
25860
26487
  this.emit({
25861
26488
  type: "tool_started",
@@ -25872,6 +26499,7 @@ class LogicalAgentSession {
25872
26499
  }
25873
26500
  if (!this.finishToolUse(event.callId))
25874
26501
  return;
26502
+ this.toolBoundaryOpen = true;
25875
26503
  const finishedCallId = this.toolCallId(event.callId);
25876
26504
  this.emit({
25877
26505
  type: "tool_finished",
@@ -25879,7 +26507,7 @@ class LogicalAgentSession {
25879
26507
  ...finishedCallId ? { callId: finishedCallId } : {},
25880
26508
  name: event.name
25881
26509
  });
25882
- if (this.outstandingToolUseCount() === 0 && !this.toolBoundaryFlushDisabled)
26510
+ if (!this.toolBoundaryFlushDisabled)
25883
26511
  this.flushSafeBoundaryQueue();
25884
26512
  return;
25885
26513
  case "compaction_started":
@@ -26025,6 +26653,7 @@ class LogicalAgentSession {
26025
26653
  this.clearOutstandingToolUses();
26026
26654
  this.compacting = false;
26027
26655
  this.reviewing = false;
26656
+ this.toolBoundaryOpen = true;
26028
26657
  this.toolBoundaryFlushDisabled = false;
26029
26658
  this.state = "idle";
26030
26659
  if (this.adapter.execution.lifetime === "turn") {
@@ -26046,7 +26675,7 @@ class LogicalAgentSession {
26046
26675
  return this.safeBoundaryFlush;
26047
26676
  }
26048
26677
  canFlushSafeBoundaryQueue() {
26049
- return this.state === "working" && this.behavior.midTurnDelivery === "safe_boundary_queue" && this.outstandingToolUseCount() === 0 && !this.compacting && !this.reviewing && this.activeTurn !== undefined && this.lane !== null && this.queued.length > 0;
26678
+ return this.state === "working" && this.behavior.midTurnDelivery === "safe_boundary_queue" && this.toolBoundaryOpen && !this.toolBoundaryFlushDisabled && !this.compacting && !this.reviewing && this.activeTurn !== undefined && this.lane !== null && this.queued.length > 0;
26050
26679
  }
26051
26680
  async drainSafeBoundaryQueue() {
26052
26681
  while (this.canFlushSafeBoundaryQueue()) {
@@ -26561,6 +27190,57 @@ function createAgentDriverSdkWithRegistry(options) {
26561
27190
  const registry2 = options.registry;
26562
27191
  return {
26563
27192
  backendIds: registry2.backendIds,
27193
+ async discoverRecentContext(input) {
27194
+ if (!isValidRecentContextTopK(input.recentSessionFilesTopK) || !isValidRecentContextTopK(input.recentProjectsTopK)) {
27195
+ return {
27196
+ ok: false,
27197
+ error: {
27198
+ category: "configuration",
27199
+ code: "invalid_recent_context_top_k",
27200
+ message: "Recent-context Top-K values must be non-negative safe integers",
27201
+ retryable: false
27202
+ }
27203
+ };
27204
+ }
27205
+ const registration = registry2.get(input.backend);
27206
+ try {
27207
+ assertRegistrationShape(registration);
27208
+ const adapter = registration.createAdapter();
27209
+ assertAdapterCompatibility(String(registration.id), registration.capabilities, adapter);
27210
+ if (!adapter.discoverRecentContext) {
27211
+ return {
27212
+ ok: false,
27213
+ error: {
27214
+ category: "configuration",
27215
+ code: "recent_context_discovery_unsupported",
27216
+ message: `Backend ${input.backend} does not support recent-context discovery`,
27217
+ retryable: false
27218
+ }
27219
+ };
27220
+ }
27221
+ const command = registration.capabilities.commandOverride ? input.command : undefined;
27222
+ const discovered = await adapter.discoverRecentContext({
27223
+ recentSessionFilesTopK: input.recentSessionFilesTopK,
27224
+ recentProjectsTopK: input.recentProjectsTopK,
27225
+ ...command ? { command } : {}
27226
+ });
27227
+ const sanitized = sanitizeRecentContextData(discovered, input);
27228
+ if (!sanitized)
27229
+ throw new Error(`Adapter ${input.backend} returned invalid recent-context data`);
27230
+ return { ok: true, ...sanitized };
27231
+ } catch (error51) {
27232
+ const contractInvalid = error51 instanceof Error && (error51.message.startsWith("Adapter ") || error51.message.startsWith("Agent backend registration "));
27233
+ return {
27234
+ ok: false,
27235
+ error: {
27236
+ category: contractInvalid ? "internal" : "runtime_unavailable",
27237
+ code: contractInvalid ? "adapter_contract_invalid" : "recent_context_discovery_failed",
27238
+ message: contractInvalid ? `Backend ${input.backend} adapter contract is invalid` : `Backend ${input.backend} recent-context discovery failed`,
27239
+ retryable: !contractInvalid
27240
+ }
27241
+ };
27242
+ }
27243
+ },
26564
27244
  async probe(input) {
26565
27245
  const registration = registry2.get(input.backend);
26566
27246
  const capabilities2 = registration.capabilities;
@@ -26699,22 +27379,22 @@ function listRuntimeIds() {
26699
27379
 
26700
27380
  // src/discovery.ts
26701
27381
  function resolveAlookCliPath(moduleDir) {
26702
- const thisDir = moduleDir ?? path9.dirname(fileURLToPath(import.meta.url));
26703
- const target2 = path9.basename(thisDir) === "dist" ? path9.resolve(thisDir, "cli", "index.js") : path9.resolve(thisDir, "..", "scripts", "alook-shim.mjs");
27382
+ const thisDir = moduleDir ?? path13.dirname(fileURLToPath(import.meta.url));
27383
+ const target2 = path13.basename(thisDir) === "dist" ? path13.resolve(thisDir, "cli", "index.js") : path13.resolve(thisDir, "..", "scripts", "alook-shim.mjs");
26704
27384
  return fs6.existsSync(target2) ? target2 : null;
26705
27385
  }
26706
27386
  function deriveCliFallbackCandidates(cliPath) {
26707
27387
  if (!cliPath)
26708
27388
  return [];
26709
- const normalized = cliPath.split(path9.sep).join("/");
27389
+ const normalized = cliPath.split(path13.sep).join("/");
26710
27390
  const marker = "/node_modules/";
26711
27391
  const idx = normalized.indexOf(marker);
26712
27392
  if (idx === -1)
26713
27393
  return [];
26714
27394
  const globalRoot = cliPath.slice(0, idx + marker.length - 1);
26715
- const tail = path9.join("dist", "cli", "index.js");
27395
+ const tail = path13.join("dist", "cli", "index.js");
26716
27396
  return [
26717
- path9.join(globalRoot, "@alook", "daemon", tail)
27397
+ path13.join(globalRoot, "@alook", "daemon", tail)
26718
27398
  ].filter((candidate) => candidate !== cliPath);
26719
27399
  }
26720
27400
  function resolveAlookCliPathWithFallback(primary) {
@@ -26856,11 +27536,11 @@ function readDaemonVersion() {
26856
27536
 
26857
27537
  // src/cli/daemonRunner.ts
26858
27538
  import * as fs11 from "node:fs";
26859
- import * as path12 from "node:path";
27539
+ import * as path16 from "node:path";
26860
27540
  import { WebSocket } from "ws";
26861
27541
 
26862
27542
  // src/daemon/createDaemon.ts
26863
- import { homedir as homedir5 } from "os";
27543
+ import { homedir as homedir7 } from "os";
26864
27544
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8 } from "node:fs";
26865
27545
 
26866
27546
  // src/util/rotatingFileSink.ts
@@ -26877,7 +27557,7 @@ import {
26877
27557
  statSync,
26878
27558
  unlinkSync as unlinkSync3
26879
27559
  } from "node:fs";
26880
- function createRotatingFileSink(path10, maxBytes, opts = {}) {
27560
+ function createRotatingFileSink(path14, maxBytes, opts = {}) {
26881
27561
  const report = (operation, error51) => {
26882
27562
  try {
26883
27563
  opts.onError?.({ operation, error: error51 });
@@ -26887,8 +27567,8 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26887
27567
  if (!existsSync6(filePath))
26888
27568
  return true;
26889
27569
  try {
26890
- const stat = lstatSync2(filePath);
26891
- if (!stat.isFile()) {
27570
+ const stat2 = lstatSync2(filePath);
27571
+ if (!stat2.isFile()) {
26892
27572
  if (opts.mode === undefined && !opts.hardMaxBytes)
26893
27573
  return true;
26894
27574
  report("unsafe_generation", new Error("log generation is not a regular file"));
@@ -26896,7 +27576,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26896
27576
  }
26897
27577
  if (opts.mode !== undefined)
26898
27578
  chmodSync(filePath, opts.mode);
26899
- if (opts.hardMaxBytes && maxBytes > 0 && stat.size > maxBytes) {
27579
+ if (opts.hardMaxBytes && maxBytes > 0 && stat2.size > maxBytes) {
26900
27580
  try {
26901
27581
  unlinkSync3(filePath);
26902
27582
  } catch (error51) {
@@ -26913,9 +27593,9 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26913
27593
  };
26914
27594
  const rotate = () => {
26915
27595
  try {
26916
- renameSync2(path10, `${path10}.1`);
27596
+ renameSync2(path14, `${path14}.1`);
26917
27597
  if (opts.mode !== undefined)
26918
- chmodSync(`${path10}.1`, opts.mode);
27598
+ chmodSync(`${path14}.1`, opts.mode);
26919
27599
  return true;
26920
27600
  } catch (error51) {
26921
27601
  report("rotate", error51);
@@ -26924,7 +27604,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26924
27604
  };
26925
27605
  const currentSize = () => {
26926
27606
  try {
26927
- return existsSync6(path10) ? statSync(path10).size : 0;
27607
+ return existsSync6(path14) ? statSync(path14).size : 0;
26928
27608
  } catch (error51) {
26929
27609
  report("stat", error51);
26930
27610
  return null;
@@ -26932,7 +27612,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26932
27612
  };
26933
27613
  const sink = {
26934
27614
  secure() {
26935
- return secureGeneration(`${path10}.1`) && secureGeneration(path10);
27615
+ return secureGeneration(`${path14}.1`) && secureGeneration(path14);
26936
27616
  },
26937
27617
  write(line) {
26938
27618
  try {
@@ -26952,7 +27632,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26952
27632
  const shouldRotate = maxBytes > 0 && (opts.hardMaxBytes ? currentBytes > 0 && currentBytes + serializedBytes > maxBytes : currentBytes >= maxBytes);
26953
27633
  if (shouldRotate && !rotate() && opts.hardMaxBytes)
26954
27634
  return;
26955
- appendFileSync(path10, serialized, opts.mode === undefined ? undefined : { mode: opts.mode });
27635
+ appendFileSync(path14, serialized, opts.mode === undefined ? undefined : { mode: opts.mode });
26956
27636
  } catch (error51) {
26957
27637
  report("append", error51);
26958
27638
  }
@@ -26960,7 +27640,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26960
27640
  openSnapshot() {
26961
27641
  const files = [];
26962
27642
  try {
26963
- for (const candidate of [`${path10}.1`, path10]) {
27643
+ for (const candidate of [`${path14}.1`, path14]) {
26964
27644
  if (!existsSync6(candidate))
26965
27645
  continue;
26966
27646
  if (!secureGeneration(candidate))
@@ -26968,10 +27648,10 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26968
27648
  const noFollow = "O_NOFOLLOW" in constants ? constants.O_NOFOLLOW : 0;
26969
27649
  const fd = openSync(candidate, constants.O_RDONLY | noFollow);
26970
27650
  try {
26971
- const stat = fstatSync(fd);
26972
- if (!stat.isFile())
27651
+ const stat2 = fstatSync(fd);
27652
+ if (!stat2.isFile())
26973
27653
  throw new Error("snapshot source is not a regular file");
26974
- files.push({ path: candidate, fd, size: stat.size });
27654
+ files.push({ path: candidate, fd, size: stat2.size });
26975
27655
  } catch (error51) {
26976
27656
  closeSync(fd);
26977
27657
  throw error51;
@@ -27121,11 +27801,11 @@ function createTraceSampler(emit, throttleMs = DEFAULT_TRACE_SAMPLE_MS) {
27121
27801
 
27122
27802
  // src/util/statusFile.ts
27123
27803
  import { writeFileSync as writeFileSync4, renameSync as renameSync3 } from "node:fs";
27124
- function writeStatusFile(path10, snapshot) {
27804
+ function writeStatusFile(path14, snapshot) {
27125
27805
  try {
27126
- const tmp = `${path10}.tmp`;
27806
+ const tmp = `${path14}.tmp`;
27127
27807
  writeFileSync4(tmp, JSON.stringify(snapshot));
27128
- renameSync3(tmp, path10);
27808
+ renameSync3(tmp, path14);
27129
27809
  } catch {}
27130
27810
  }
27131
27811
 
@@ -27807,7 +28487,7 @@ import * as fs7 from "fs";
27807
28487
  import * as http from "http";
27808
28488
  import * as https from "https";
27809
28489
  import * as os2 from "os";
27810
- import * as path10 from "path";
28490
+ import * as path14 from "path";
27811
28491
  import { URL as URL2 } from "url";
27812
28492
  var LOCAL_MESSAGE_REMINDER_PATH = "/__alook/local/message-reminder";
27813
28493
  var LOCAL_MESSAGE_REMINDER_BODY_MAX_BYTES = 4 * 1024;
@@ -27839,15 +28519,15 @@ class CredentialBroker {
27839
28519
  this.voucherPrefix = config2.voucherPrefix ?? "vch_";
27840
28520
  this.clientLabel = config2.clientLabel ?? "cli";
27841
28521
  this.headerNames = config2.headerNames ?? DEFAULT_HEADER_NAMES;
27842
- this.voucherDir = config2.voucherDir ?? path10.join(os2.tmpdir(), "agent-vouchers");
28522
+ this.voucherDir = config2.voucherDir ?? path14.join(os2.tmpdir(), "agent-vouchers");
27843
28523
  }
27844
28524
  mint(agentId, launchId, capabilities2, runnerKey) {
27845
28525
  if (!runnerKey)
27846
28526
  throw new Error("CredentialBroker.mint: runnerKey is required (per-agent tier-2 credential)");
27847
28527
  const voucher = randomVoucher(this.voucherPrefix);
27848
- const dir = path10.join(this.voucherDir, sanitizeIdSegment(agentId));
28528
+ const dir = path14.join(this.voucherDir, sanitizeIdSegment(agentId));
27849
28529
  fs7.mkdirSync(dir, { recursive: true });
27850
- const voucherFile = path10.join(dir, `${sanitizeIdSegment(launchId)}.token`);
28530
+ const voucherFile = path14.join(dir, `${sanitizeIdSegment(launchId)}.token`);
27851
28531
  fs7.writeFileSync(voucherFile, voucher, { mode: 384 });
27852
28532
  this.registrations.set(voucher, {
27853
28533
  agentId,
@@ -28915,7 +29595,7 @@ function runtimeModelName(config2) {
28915
29595
  // agent-driver/dist/provider-quota.js
28916
29596
  import { execFile } from "node:child_process";
28917
29597
  import { readFile } from "node:fs/promises";
28918
- import { homedir as homedir3 } from "node:os";
29598
+ import { homedir as homedir5 } from "node:os";
28919
29599
  import { join as join11 } from "node:path";
28920
29600
  import { promisify } from "node:util";
28921
29601
  import { randomBytes as randomBytes5 } from "node:crypto";
@@ -28944,7 +29624,7 @@ async function claudeCredentials(options) {
28944
29624
  } catch {}
28945
29625
  }
28946
29626
  const env = options.env ?? process.env;
28947
- const root = env.CLAUDE_CONFIG_DIR || join11(options.home ?? homedir3(), ".claude");
29627
+ const root = env.CLAUDE_CONFIG_DIR || join11(options.home ?? homedir5(), ".claude");
28948
29628
  try {
28949
29629
  const value = options.readCredentialsFile ? await options.readCredentialsFile(join11(root, ".credentials.json")) : await readFile(join11(root, ".credentials.json"), "utf8");
28950
29630
  return parseCredentials(value);
@@ -29946,7 +30626,19 @@ class AgentProcessManager {
29946
30626
  const session2 = this.sessions.get(agentId);
29947
30627
  if (!session2)
29948
30628
  return;
29949
- await session2.interrupt({ requestId: randomUUID6(), reason: "owner_request" });
30629
+ const result = await session2.interrupt({ requestId: randomUUID6(), reason: "owner_request" });
30630
+ if (result.status !== "accepted")
30631
+ return;
30632
+ this.log.info("agent turn interrupt accepted", {
30633
+ agentId,
30634
+ sessionInstanceId: session2.sessionInstanceId,
30635
+ turnId: result.turnId
30636
+ });
30637
+ try {
30638
+ this.opts.onBotAuditEvent?.(agentId, { kind: "turn_interrupt", payload: { status: "accepted" } }, this.auditContext(agentId));
30639
+ } catch (err) {
30640
+ this.log.debug("audit emit failed (turn interrupt)", { agentId, err: String(err) });
30641
+ }
29950
30642
  }
29951
30643
  async stopAll() {
29952
30644
  if (this.tickTimer) {
@@ -30288,6 +30980,10 @@ ${this.opts.wakePromptFooter}` : text2;
30288
30980
  sent = session2.send(input);
30289
30981
  if (exactOwner)
30290
30982
  this.markPendingDeliveryObserved(exactOwner, input.id);
30983
+ this.log.info("steering message submitted to logical session", {
30984
+ agentId: effect.agentId,
30985
+ mode: effect.mode
30986
+ });
30291
30987
  } catch (error51) {
30292
30988
  if (exactOwner) {
30293
30989
  this.settlePendingDelivery(exactOwner, input.id);
@@ -30333,7 +31029,6 @@ ${this.opts.wakePromptFooter}` : text2;
30333
31029
  mode: effect.mode
30334
31030
  });
30335
31031
  }
30336
- this.log.info("steering message sent to running agent", { agentId: effect.agentId, mode: effect.mode });
30337
31032
  break;
30338
31033
  }
30339
31034
  case "stop":
@@ -31379,6 +32074,26 @@ class AgentRouter {
31379
32074
  return;
31380
32075
  }
31381
32076
  break;
32077
+ case "agent:event":
32078
+ this.log.info("agent:event received", { agentId: cmd.agentId });
32079
+ try {
32080
+ await this.opts.onBeforeAgent?.(cmd.agentId);
32081
+ this.opts.manager.register(cmd.agentId, {
32082
+ runtimeConfig: cmd.config,
32083
+ launchId: cmd.launchId
32084
+ });
32085
+ this.running.add(cmd.agentId);
32086
+ this.opts.manager.deliver(cmd.agentId, {
32087
+ id: `${cmd.agentId}:event:${cmd.launchId}`,
32088
+ text: cmd.prompt
32089
+ });
32090
+ } catch (err) {
32091
+ this.log.warn("agent:event failed", {
32092
+ agentId: cmd.agentId,
32093
+ err: err instanceof Error ? err.message : String(err)
32094
+ });
32095
+ }
32096
+ break;
31382
32097
  case "agent:reset":
31383
32098
  await this.runRestartCommand(cmd.agentId, cmd.launchId, "agent:reset", () => this.opts.manager.resetSession(cmd.agentId, {
31384
32099
  runtimeConfig: cmd.config,
@@ -31609,11 +32324,11 @@ function timelineRowHash(line) {
31609
32324
  }
31610
32325
  function timelineFileGeneration(filePath, lines) {
31611
32326
  try {
31612
- const stat = fs9.lstatSync(filePath, { bigint: true });
31613
- if (!stat.isFile())
32327
+ const stat2 = fs9.lstatSync(filePath, { bigint: true });
32328
+ if (!stat2.isFile())
31614
32329
  return null;
31615
32330
  const digest = createHash2("sha256");
31616
- digest.update(`${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}
32331
+ digest.update(`${stat2.dev}:${stat2.ino}:${stat2.size}:${stat2.mtimeNs}:${stat2.ctimeNs}
31617
32332
  `);
31618
32333
  for (const line of lines)
31619
32334
  digest.update(line.text, "utf8").update(`
@@ -31671,9 +32386,9 @@ function compactLines(input) {
31671
32386
  }
31672
32387
  return suffix;
31673
32388
  }
31674
- function isRealDirectory(path11) {
32389
+ function isRealDirectory(path15) {
31675
32390
  try {
31676
- return fs9.lstatSync(path11).isDirectory();
32391
+ return fs9.lstatSync(path15).isDirectory();
31677
32392
  } catch {
31678
32393
  return false;
31679
32394
  }
@@ -31713,8 +32428,8 @@ function scanTimelineFile(filePath) {
31713
32428
  let fd = null;
31714
32429
  try {
31715
32430
  fd = fs9.openSync(filePath, fs9.constants.O_RDONLY | (fs9.constants.O_NOFOLLOW ?? 0));
31716
- const stat = fs9.fstatSync(fd);
31717
- if (!stat.isFile())
32431
+ const stat2 = fs9.fstatSync(fd);
32432
+ if (!stat2.isFile())
31718
32433
  return null;
31719
32434
  const chunk2 = Buffer.allocUnsafe(TIMELINE_READ_CHUNK_BYTES);
31720
32435
  const newest = [];
@@ -31727,9 +32442,9 @@ function scanTimelineFile(filePath) {
31727
32442
  let oversized = false;
31728
32443
  let stop = false;
31729
32444
  let discardIncompleteTail = false;
31730
- if (stat.size > 0) {
32445
+ if (stat2.size > 0) {
31731
32446
  const last = Buffer.allocUnsafe(1);
31732
- fs9.readSync(fd, last, 0, 1, stat.size - 1);
32447
+ fs9.readSync(fd, last, 0, 1, stat2.size - 1);
31733
32448
  discardIncompleteTail = last[0] !== 10;
31734
32449
  }
31735
32450
  const resetPhysicalLine = () => {
@@ -31788,7 +32503,7 @@ function scanTimelineFile(filePath) {
31788
32503
  }
31789
32504
  resetPhysicalLine();
31790
32505
  };
31791
- let position = stat.size;
32506
+ let position = stat2.size;
31792
32507
  while (position > 0 && !stop) {
31793
32508
  const start = Math.max(0, position - chunk2.length);
31794
32509
  const requested = position - start;
@@ -31940,11 +32655,11 @@ function readResumeControlState(timelineDir) {
31940
32655
  let fd = null;
31941
32656
  try {
31942
32657
  fd = fs9.openSync(filePath, fs9.constants.O_RDONLY | (fs9.constants.O_NOFOLLOW ?? 0));
31943
- const stat = fs9.fstatSync(fd);
31944
- if (!stat.isFile() || stat.size <= 0 || stat.size > RESUME_CONTROL_MAX_BYTES) {
32658
+ const stat2 = fs9.fstatSync(fd);
32659
+ if (!stat2.isFile() || stat2.size <= 0 || stat2.size > RESUME_CONTROL_MAX_BYTES) {
31945
32660
  return { kind: "invalid" };
31946
32661
  }
31947
- const bounded = Buffer.allocUnsafe(stat.size + 1);
32662
+ const bounded = Buffer.allocUnsafe(stat2.size + 1);
31948
32663
  let bytesRead = 0;
31949
32664
  while (bytesRead < bounded.length) {
31950
32665
  const count = fs9.readSync(fd, bounded, bytesRead, bounded.length - bytesRead, bytesRead);
@@ -31952,7 +32667,7 @@ function readResumeControlState(timelineDir) {
31952
32667
  break;
31953
32668
  bytesRead += count;
31954
32669
  }
31955
- if (bytesRead !== stat.size)
32670
+ if (bytesRead !== stat2.size)
31956
32671
  return { kind: "invalid" };
31957
32672
  const raw = bounded.subarray(0, bytesRead).toString("utf8");
31958
32673
  const value = JSON.parse(raw);
@@ -32878,7 +33593,7 @@ class MessageReminderScheduler {
32878
33593
 
32879
33594
  // src/manager/agentDriverHost.ts
32880
33595
  import { randomUUID as randomUUID7 } from "node:crypto";
32881
- import { homedir as homedir4 } from "node:os";
33596
+ import { homedir as homedir6 } from "node:os";
32882
33597
  import { join as join13 } from "node:path";
32883
33598
 
32884
33599
  // src/drivers/gitIdentityEnv.ts
@@ -33004,7 +33719,7 @@ function createDaemonAgentDriverHost(ctx, onRawLine) {
33004
33719
  hostUser: readHostGitIdentity() ?? undefined
33005
33720
  }),
33006
33721
  platformProtected: {
33007
- ALOOK_HOME: process.env.ALOOK_HOME ?? join13(homedir4(), ".alook"),
33722
+ ALOOK_HOME: process.env.ALOOK_HOME ?? join13(homedir6(), ".alook"),
33008
33723
  ALOOK_ID: ctx.agentId,
33009
33724
  ALOOK_CLI: ctx.agentCliPath,
33010
33725
  ALOOK_SERVER_URL: ctx.config.serverUrl,
@@ -33325,13 +34040,13 @@ function createRuntimeRawLineTap(args) {
33325
34040
  const maxBytes = args.maxBytes ?? RUNTIME_RAW_TRACE_MAX_BYTES;
33326
34041
  const sinks = new Map;
33327
34042
  const warned = new Set;
33328
- const warnOnce = (agentId, path11, operation, error51) => {
34043
+ const warnOnce = (agentId, path15, operation, error51) => {
33329
34044
  if (warned.has(agentId))
33330
34045
  return;
33331
34046
  warned.add(agentId);
33332
34047
  args.logger.warn("runtime raw trace sink failed", {
33333
34048
  agentId,
33334
- path: path11,
34049
+ path: path15,
33335
34050
  operation,
33336
34051
  error: error51 instanceof Error ? error51.message : String(error51)
33337
34052
  });
@@ -33340,10 +34055,10 @@ function createRuntimeRawLineTap(args) {
33340
34055
  if (!args.enabledAgentIds.has(agentId))
33341
34056
  return;
33342
34057
  const encodedAgentId = encodeURIComponent(agentId).replace(/\./g, "%2E");
33343
- const path11 = `${traceDir}/runtime-raw-events-${encodedAgentId}.jsonl`;
34058
+ const path15 = `${traceDir}/runtime-raw-events-${encodedAgentId}.jsonl`;
33344
34059
  const serializedBytes = Buffer.byteLength(line, "utf8") + 1;
33345
34060
  if (serializedBytes > maxBytes) {
33346
- warnOnce(agentId, path11, "oversize", new Error(`raw line is ${serializedBytes} bytes; max is ${maxBytes}`));
34061
+ warnOnce(agentId, path15, "oversize", new Error(`raw line is ${serializedBytes} bytes; max is ${maxBytes}`));
33347
34062
  return;
33348
34063
  }
33349
34064
  let sink = sinks.get(agentId);
@@ -33351,12 +34066,12 @@ function createRuntimeRawLineTap(args) {
33351
34066
  try {
33352
34067
  mkdirSync8(traceDir, { recursive: true });
33353
34068
  } catch (error51) {
33354
- warnOnce(agentId, path11, "mkdir", error51);
34069
+ warnOnce(agentId, path15, "mkdir", error51);
33355
34070
  }
33356
- sink = createRotatingFileSink(path11, maxBytes, {
34071
+ sink = createRotatingFileSink(path15, maxBytes, {
33357
34072
  mode: 384,
33358
34073
  hardMaxBytes: true,
33359
- onError: ({ operation, error: error51 }) => warnOnce(agentId, path11, operation, error51)
34074
+ onError: ({ operation, error: error51 }) => warnOnce(agentId, path15, operation, error51)
33360
34075
  });
33361
34076
  sinks.set(agentId, sink);
33362
34077
  }
@@ -33448,7 +34163,7 @@ function createBuiltinDaemonSessionFactory(onRuntimeRawLine) {
33448
34163
  }
33449
34164
  async function createDaemon(opts) {
33450
34165
  const log2 = opts.logger ?? createLogger2({ header: "@alook/daemon" });
33451
- const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${homedir5()}/.alook`) + "/daemon";
34166
+ const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${homedir7()}/.alook`) + "/daemon";
33452
34167
  const workingDirectoryBase = opts.workingDirectoryBase ?? fallbackBase;
33453
34168
  const workdirFor = (agentId) => `${workingDirectoryBase}/${agentId}`;
33454
34169
  const dailyTokenUsage2 = new DailyTokenUsageStore(workingDirectoryBase);
@@ -34154,12 +34869,12 @@ async function readPinnedJsonFile(args) {
34154
34869
  }
34155
34870
  }
34156
34871
  fd = openSync3(args.path, constants3.O_RDONLY | noFollow);
34157
- const stat = fstatSync3(fd);
34158
- if (!stat.isFile())
34872
+ const stat2 = fstatSync3(fd);
34873
+ if (!stat2.isFile())
34159
34874
  return { value: null, warnings: ["source_unavailable"] };
34160
- if (stat.size > args.maxBytes)
34875
+ if (stat2.size > args.maxBytes)
34161
34876
  return { value: null, warnings: ["line_too_long"] };
34162
- const bytes = readPinnedBytes(fd, stat.size);
34877
+ const bytes = readPinnedBytes(fd, stat2.size);
34163
34878
  try {
34164
34879
  return { value: JSON.parse(bytes.toString("utf8")), warnings: [] };
34165
34880
  } catch {
@@ -34237,7 +34952,7 @@ var DAEMON_LOG_DIAGNOSTIC_POLICY = [
34237
34952
  reason: string5(32, { values: ["turn_end", "stopped", "terminate_stalled", "exit"] }),
34238
34953
  sessionId: string5(256, { scrub: true })
34239
34954
  } },
34240
- { header: "@alook/daemon:manager", message: "steering message sent to running agent", scope: "target", fields: {
34955
+ { header: "@alook/daemon:manager", message: "steering message submitted to logical session", scope: "target", fields: {
34241
34956
  agentId: AGENT,
34242
34957
  mode: string5(8, { values: ["busy", "idle"] })
34243
34958
  } },
@@ -34792,7 +35507,7 @@ import { createHash as createHash4, randomBytes as randomBytes7 } from "node:cry
34792
35507
  import {
34793
35508
  chmodSync as chmodSync2,
34794
35509
  closeSync as closeSync4,
34795
- createReadStream,
35510
+ createReadStream as createReadStream3,
34796
35511
  existsSync as existsSync7,
34797
35512
  fsyncSync as fsyncSync2,
34798
35513
  lstatSync as lstatSync5,
@@ -34815,7 +35530,7 @@ class CoordinatorError extends Error {
34815
35530
  function defaultFsOps() {
34816
35531
  return {
34817
35532
  randomSuffix: () => randomBytes7(12).toString("hex"),
34818
- open: (path11, flags, mode) => openSync4(path11, flags, mode),
35533
+ open: (path15, flags, mode) => openSync4(path15, flags, mode),
34819
35534
  write: (fd, bytes) => {
34820
35535
  writeSync(fd, bytes);
34821
35536
  },
@@ -34828,10 +35543,10 @@ function defaultFsOps() {
34828
35543
  rename: (from, to) => {
34829
35544
  renameSync5(from, to);
34830
35545
  },
34831
- fsyncDirectory: (path11) => {
35546
+ fsyncDirectory: (path15) => {
34832
35547
  if (process.platform === "win32")
34833
35548
  return;
34834
- const fd = openSync4(path11, "r");
35549
+ const fd = openSync4(path15, "r");
34835
35550
  try {
34836
35551
  fsyncSync2(fd);
34837
35552
  } finally {
@@ -34882,8 +35597,8 @@ function createDiagnosticReportCoordinator(args) {
34882
35597
  const sidecarPath = (reportId) => join15(dir, `report-${reportId}.json`);
34883
35598
  const ensureDir = () => {
34884
35599
  if (existsSync7(dir)) {
34885
- const stat = lstatSync5(dir);
34886
- if (!stat.isDirectory() || stat.isSymbolicLink())
35600
+ const stat2 = lstatSync5(dir);
35601
+ if (!stat2.isDirectory() || stat2.isSymbolicLink())
34887
35602
  throw new CoordinatorError("local_artifact_invalid");
34888
35603
  if (process.platform !== "win32")
34889
35604
  chmodSync2(dir, 448);
@@ -34896,11 +35611,11 @@ function createDiagnosticReportCoordinator(args) {
34896
35611
  args.logger?.warn("diagnostic local artifact invalid", { reportId, code: "local_artifact_invalid" });
34897
35612
  } catch {}
34898
35613
  };
34899
- const removeExact = (path11) => {
35614
+ const removeExact = (path15) => {
34900
35615
  try {
34901
- const stat = lstatSync5(path11);
34902
- if (stat.isFile() && !stat.isSymbolicLink())
34903
- unlinkSync6(path11);
35616
+ const stat2 = lstatSync5(path15);
35617
+ if (stat2.isFile() && !stat2.isSymbolicLink())
35618
+ unlinkSync6(path15);
34904
35619
  } catch {}
34905
35620
  };
34906
35621
  const cleanup = (reportId) => {
@@ -34938,12 +35653,12 @@ function createDiagnosticReportCoordinator(args) {
34938
35653
  checkpoint(sidecar.phase === "collecting" ? "collecting_dir_fsynced" : "ready_dir_fsynced");
34939
35654
  };
34940
35655
  const committedArchive = (reportId) => {
34941
- const path11 = archivePath(reportId);
35656
+ const path15 = archivePath(reportId);
34942
35657
  try {
34943
- const stat = lstatSync5(path11);
34944
- if (!stat.isFile() || stat.isSymbolicLink())
35658
+ const stat2 = lstatSync5(path15);
35659
+ if (!stat2.isFile() || stat2.isSymbolicLink())
34945
35660
  return null;
34946
- const bytes = readFileSync6(path11);
35661
+ const bytes = readFileSync6(path15);
34947
35662
  return { sizeBytes: bytes.byteLength, sha256: createHash4("sha256").update(bytes).digest("hex") };
34948
35663
  } catch {
34949
35664
  return null;
@@ -35004,7 +35719,7 @@ function createDiagnosticReportCoordinator(args) {
35004
35719
  if (stopped)
35005
35720
  throw new CoordinatorError("coordinator_shutdown");
35006
35721
  checkpoint("before_upload");
35007
- const result = await args.transport.upload({ reportId: sidecar.reportId, sizeBytes: sidecar.sizeBytes, sha256: sidecar.sha256 }, createReadStream(archivePath(sidecar.reportId)));
35722
+ const result = await args.transport.upload({ reportId: sidecar.reportId, sizeBytes: sidecar.sizeBytes, sha256: sidecar.sha256 }, createReadStream3(archivePath(sidecar.reportId)));
35008
35723
  checkpoint("after_upload");
35009
35724
  if (result.kind === "terminal") {
35010
35725
  cleanup(sidecar.reportId);
@@ -35068,12 +35783,12 @@ function createDiagnosticReportCoordinator(args) {
35068
35783
  return uploadReady(ready);
35069
35784
  };
35070
35785
  const readSidecar = (reportId) => {
35071
- const path11 = sidecarPath(reportId);
35786
+ const path15 = sidecarPath(reportId);
35072
35787
  try {
35073
- const stat = lstatSync5(path11);
35074
- if (!stat.isFile() || stat.isSymbolicLink())
35788
+ const stat2 = lstatSync5(path15);
35789
+ if (!stat2.isFile() || stat2.isSymbolicLink())
35075
35790
  return null;
35076
- return parseSidecar(JSON.parse(readFileSync6(path11, "utf8")));
35791
+ return parseSidecar(JSON.parse(readFileSync6(path15, "utf8")));
35077
35792
  } catch {
35078
35793
  return null;
35079
35794
  }
@@ -35161,9 +35876,9 @@ function createDiagnosticReportCoordinator(args) {
35161
35876
  }
35162
35877
  // src/diagnostics/httpTransport.ts
35163
35878
  import { Readable as Readable2 } from "node:stream";
35164
- function endpoint(serverUrl, path11) {
35879
+ function endpoint(serverUrl, path15) {
35165
35880
  const base = serverUrl.endsWith("/") ? serverUrl : `${serverUrl}/`;
35166
- return new URL(path11.replace(/^\//, ""), base).toString();
35881
+ return new URL(path15.replace(/^\//, ""), base).toString();
35167
35882
  }
35168
35883
  async function strictOutcome(response, allowed) {
35169
35884
  try {
@@ -35227,29 +35942,29 @@ function createDiagnosticHttpTransport(args) {
35227
35942
  // src/cli/daemonUpdate.ts
35228
35943
  import * as crypto4 from "node:crypto";
35229
35944
  import * as fs10 from "node:fs";
35230
- import * as path11 from "node:path";
35945
+ import * as path15 from "node:path";
35231
35946
  import { spawn as spawn2 } from "node:child_process";
35232
35947
  var UPDATE_INTENT_SCHEMA_VERSION = 1;
35233
35948
  var UPDATE_LOG_MAX_BYTES = 512 * 1024;
35234
35949
  var UPDATE_LOG_KEEP_BYTES = 256 * 1024;
35235
35950
  var REQUEST_ID_PATTERN = /^[A-Za-z0-9_-]{16,128}$/;
35236
35951
  function intentPath(baseDir, machineId) {
35237
- return path11.join(daemonDirById(baseDir, machineId), "update-intent.json");
35952
+ return path15.join(daemonDirById(baseDir, machineId), "update-intent.json");
35238
35953
  }
35239
35954
  function updateLogPath(baseDir, machineId) {
35240
- return path11.join(daemonDirById(baseDir, machineId), "update.log");
35955
+ return path15.join(daemonDirById(baseDir, machineId), "update.log");
35241
35956
  }
35242
35957
  function updatePackageMapPath(baseDir, machineId) {
35243
- return path11.join(daemonDirById(baseDir, machineId), "update-package-map.json");
35958
+ return path15.join(daemonDirById(baseDir, machineId), "update-package-map.json");
35244
35959
  }
35245
35960
  function ensurePrivateDir(dir) {
35246
35961
  fs10.mkdirSync(dir, { recursive: true, mode: 448 });
35247
35962
  fs10.chmodSync(dir, 448);
35248
35963
  }
35249
35964
  function writePrivateJsonAtomic(filePath, value) {
35250
- const dir = path11.dirname(filePath);
35965
+ const dir = path15.dirname(filePath);
35251
35966
  ensurePrivateDir(dir);
35252
- const tempPath = path11.join(dir, `.${path11.basename(filePath)}.${process.pid}.${crypto4.randomBytes(8).toString("hex")}.tmp`);
35967
+ const tempPath = path15.join(dir, `.${path15.basename(filePath)}.${process.pid}.${crypto4.randomBytes(8).toString("hex")}.tmp`);
35253
35968
  let fd = fs10.openSync(tempPath, "wx", 384);
35254
35969
  try {
35255
35970
  fs10.writeFileSync(fd, JSON.stringify(value));
@@ -35274,7 +35989,7 @@ function scrub(value) {
35274
35989
  }
35275
35990
  function appendUpdateLog(baseDir, machineId, event, fields = {}) {
35276
35991
  const filePath = updateLogPath(baseDir, machineId);
35277
- ensurePrivateDir(path11.dirname(filePath));
35992
+ ensurePrivateDir(path15.dirname(filePath));
35278
35993
  try {
35279
35994
  if (fs10.existsSync(filePath) && fs10.statSync(filePath).size > UPDATE_LOG_MAX_BYTES) {
35280
35995
  const data = fs10.readFileSync(filePath);
@@ -35301,8 +36016,8 @@ function tuplesEqual(value, expected) {
35301
36016
  }
35302
36017
  function readIntent(baseDir, machineId) {
35303
36018
  const filePath = intentPath(baseDir, machineId);
35304
- const stat = fs10.lstatSync(filePath);
35305
- if (!stat.isFile())
36019
+ const stat2 = fs10.lstatSync(filePath);
36020
+ if (!stat2.isFile())
35306
36021
  throw new Error("unsafe daemon update intent type");
35307
36022
  fs10.chmodSync(filePath, 384);
35308
36023
  const value = JSON.parse(fs10.readFileSync(filePath, "utf8"));
@@ -35317,12 +36032,81 @@ function removeIntentIfMatches(baseDir, machineId, requestId) {
35317
36032
  fs10.unlinkSync(intentPath(baseDir, machineId));
35318
36033
  } catch {}
35319
36034
  }
35320
- function npmExecPath(explicit) {
35321
- const value = explicit ?? process.env.npm_execpath;
35322
- if (!value || !path11.isAbsolute(value) || !fs10.existsSync(value)) {
35323
- throw new Error("npm launch context unavailable; daemon remains online");
36035
+ var defaultNpmLaunchFileProbe = {
36036
+ isFile(filePath) {
36037
+ try {
36038
+ return fs10.statSync(filePath).isFile();
36039
+ } catch {
36040
+ return false;
36041
+ }
36042
+ },
36043
+ isExecutable(filePath) {
36044
+ try {
36045
+ fs10.accessSync(filePath, fs10.constants.X_OK);
36046
+ return true;
36047
+ } catch {
36048
+ return false;
36049
+ }
35324
36050
  }
35325
- return value;
36051
+ };
36052
+ function pathEnvironment(env, platform) {
36053
+ if (platform !== "win32")
36054
+ return env.PATH;
36055
+ const entry = Object.entries(env).find(([key]) => key.toLowerCase() === "path");
36056
+ return entry?.[1];
36057
+ }
36058
+ function launchFromNpmPath(args) {
36059
+ const pathApi = args.platform === "win32" ? path15.win32 : path15.posix;
36060
+ if (!pathApi.isAbsolute(args.npmPath) || !args.probe.isFile(args.npmPath))
36061
+ return null;
36062
+ const extension = pathApi.extname(args.npmPath).toLowerCase();
36063
+ if ([".js", ".cjs", ".mjs"].includes(extension)) {
36064
+ return { file: args.nodePath, prefixArgs: [args.npmPath] };
36065
+ }
36066
+ if (args.platform === "win32" && [".cmd", ".bat"].includes(extension)) {
36067
+ const cliPath = pathApi.join(pathApi.dirname(args.npmPath), "node_modules", "npm", "bin", "npm-cli.js");
36068
+ return args.probe.isFile(cliPath) ? { file: args.nodePath, prefixArgs: [cliPath] } : null;
36069
+ }
36070
+ if (args.requireExecutable && !args.probe.isExecutable(args.npmPath))
36071
+ return null;
36072
+ return { file: args.npmPath, prefixArgs: [] };
36073
+ }
36074
+ function resolveNpmLaunchCommand(options = {}) {
36075
+ const env = options.env ?? process.env;
36076
+ const platform = options.platform ?? process.platform;
36077
+ const nodePath = options.nodePath ?? process.execPath;
36078
+ const probe = options.probe ?? defaultNpmLaunchFileProbe;
36079
+ const inherited = options.npmExecPath ?? env.npm_execpath;
36080
+ if (inherited) {
36081
+ const launch = launchFromNpmPath({
36082
+ npmPath: inherited,
36083
+ platform,
36084
+ nodePath,
36085
+ probe,
36086
+ requireExecutable: platform !== "win32"
36087
+ });
36088
+ if (launch)
36089
+ return launch;
36090
+ }
36091
+ const pathApi = platform === "win32" ? path15.win32 : path15.posix;
36092
+ const names = platform === "win32" ? ["npm.exe", "npm.cmd", "npm.bat", "npm"] : ["npm"];
36093
+ const pathValue = pathEnvironment(env, platform);
36094
+ for (const directory of pathValue?.split(pathApi.delimiter) ?? []) {
36095
+ if (!directory || !pathApi.isAbsolute(directory))
36096
+ continue;
36097
+ for (const name of names) {
36098
+ const launch = launchFromNpmPath({
36099
+ npmPath: pathApi.join(directory, name),
36100
+ platform,
36101
+ nodePath,
36102
+ probe,
36103
+ requireExecutable: platform !== "win32"
36104
+ });
36105
+ if (launch)
36106
+ return launch;
36107
+ }
36108
+ }
36109
+ throw new Error("npm launch context unavailable and no safe npm executable was found on PATH; daemon remains online");
35326
36110
  }
35327
36111
  function readTestPackageMap(baseDir, machineId) {
35328
36112
  if (true)
@@ -35330,10 +36114,10 @@ function readTestPackageMap(baseDir, machineId) {
35330
36114
  const filePath = updatePackageMapPath(baseDir, machineId);
35331
36115
  if (!fs10.existsSync(filePath))
35332
36116
  return null;
35333
- const stat = fs10.lstatSync(filePath);
35334
- if (!stat.isFile())
36117
+ const stat2 = fs10.lstatSync(filePath);
36118
+ if (!stat2.isFile())
35335
36119
  throw new Error("unsafe daemon update package map type");
35336
- if (process.platform !== "win32" && (stat.mode & 63) !== 0) {
36120
+ if (process.platform !== "win32" && (stat2.mode & 63) !== 0) {
35337
36121
  throw new Error("daemon update package map must be mode 0600");
35338
36122
  }
35339
36123
  const parsed = JSON.parse(fs10.readFileSync(filePath, "utf8"));
@@ -35343,7 +36127,7 @@ function readTestPackageMap(baseDir, machineId) {
35343
36127
  for (const [key, value] of Object.entries(parsed)) {
35344
36128
  if (key !== "latest" && !parseReleaseVersion(key))
35345
36129
  throw new Error("invalid daemon update package map key");
35346
- if (typeof value !== "string" || !path11.isAbsolute(value))
36130
+ if (typeof value !== "string" || !path15.isAbsolute(value))
35347
36131
  throw new Error("invalid daemon update package map value");
35348
36132
  result[key] = value;
35349
36133
  }
@@ -35357,9 +36141,9 @@ function packageSpec(baseDir, machineId, version3) {
35357
36141
  }
35358
36142
  function fixedNpmArgs(args) {
35359
36143
  return [
35360
- args.npmPath,
35361
36144
  "exec",
35362
36145
  "--yes",
36146
+ "--no-audit",
35363
36147
  `--package=${args.packageSpec}`,
35364
36148
  "--",
35365
36149
  "alook-daemon",
@@ -35390,7 +36174,13 @@ function createDaemonSelfUpdateHandler(context, deps = {}) {
35390
36174
  const current = pidTuple(readPidFile(pidfilePathById(context.baseDir, context.machineId)));
35391
36175
  if (!current || current.pid !== context.pid || current.machineId !== context.machineId || current.startedAt !== context.startedAt || current.ownerToken !== context.ownerToken)
35392
36176
  throw new Error("daemon ownership changed before update launch");
35393
- const npmPath = npmExecPath(deps.npmExecPath);
36177
+ const npmLaunch = resolveNpmLaunchCommand({
36178
+ npmExecPath: deps.npmExecPath,
36179
+ env: deps.npmLaunchEnv,
36180
+ platform: deps.npmLaunchPlatform,
36181
+ nodePath: deps.npmLaunchNodePath,
36182
+ probe: deps.npmLaunchFileProbe
36183
+ });
35394
36184
  requestId = crypto4.randomUUID();
35395
36185
  const intent = {
35396
36186
  schemaVersion: UPDATE_INTENT_SCHEMA_VERSION,
@@ -35400,14 +36190,16 @@ function createDaemonSelfUpdateHandler(context, deps = {}) {
35400
36190
  writePrivateJsonAtomic(intentPath(context.baseDir, context.machineId), intent);
35401
36191
  const logFd = openUpdateLog(context.baseDir, context.machineId);
35402
36192
  try {
35403
- const child = (deps.spawnProcess ?? spawn2)(process.execPath, fixedNpmArgs({
35404
- npmPath,
35405
- packageSpec: packageSpec(context.baseDir, context.machineId, "latest"),
35406
- command: "replace",
35407
- machineId: context.machineId,
35408
- baseDir: context.baseDir,
35409
- requestId
35410
- }), {
36193
+ const child = (deps.spawnProcess ?? spawn2)(npmLaunch.file, [
36194
+ ...npmLaunch.prefixArgs,
36195
+ ...fixedNpmArgs({
36196
+ packageSpec: packageSpec(context.baseDir, context.machineId, "latest"),
36197
+ command: "replace",
36198
+ machineId: context.machineId,
36199
+ baseDir: context.baseDir,
36200
+ requestId
36201
+ })
36202
+ ], {
35411
36203
  detached: true,
35412
36204
  shell: false,
35413
36205
  stdio: ["ignore", logFd, logFd]
@@ -35448,14 +36240,16 @@ function removeOldPidfileIfMatches(baseDir, intent) {
35448
36240
  async function runPinnedResume(args) {
35449
36241
  const fd = openUpdateLog(args.baseDir, args.machineId);
35450
36242
  try {
35451
- const child = spawn2(process.execPath, fixedNpmArgs({
35452
- npmPath: args.npmPath,
35453
- packageSpec: packageSpec(args.baseDir, args.machineId, args.version),
35454
- command: "resume",
35455
- machineId: args.machineId,
35456
- baseDir: args.baseDir,
35457
- requestId: args.requestId
35458
- }), {
36243
+ const child = spawn2(args.npmLaunch.file, [
36244
+ ...args.npmLaunch.prefixArgs,
36245
+ ...fixedNpmArgs({
36246
+ packageSpec: packageSpec(args.baseDir, args.machineId, args.version),
36247
+ command: "resume",
36248
+ machineId: args.machineId,
36249
+ baseDir: args.baseDir,
36250
+ requestId: args.requestId
36251
+ })
36252
+ ], {
35459
36253
  shell: false,
35460
36254
  stdio: ["ignore", fd, fd]
35461
36255
  });
@@ -35499,7 +36293,7 @@ async function daemonReplace(opts) {
35499
36293
  removeIntentIfMatches(baseDir, opts.id, opts.requestId);
35500
36294
  throw new Error("daemon ownership changed before replacement");
35501
36295
  }
35502
- const npmPath = npmExecPath();
36296
+ const npmLaunch = resolveNpmLaunchCommand();
35503
36297
  const acquired = acquireDaemonReplacementLock({ baseDir, machineId: opts.id, requestId: opts.requestId });
35504
36298
  let oldStopped = false;
35505
36299
  try {
@@ -35519,7 +36313,7 @@ async function daemonReplace(opts) {
35519
36313
  } catch (error51) {
35520
36314
  appendUpdateLog(baseDir, opts.id, "replacement_start_failed", { error: error51 });
35521
36315
  await runPinnedResume({
35522
- npmPath,
36316
+ npmLaunch,
35523
36317
  version: launch.daemonVersion,
35524
36318
  machineId: opts.id,
35525
36319
  baseDir,
@@ -35642,7 +36436,7 @@ async function buildRunnerDiagnosticBundle(args) {
35642
36436
  function createDaemonProcessLogger(daemonDir, foreground) {
35643
36437
  fs11.mkdirSync(daemonDir, { recursive: true, mode: 448 });
35644
36438
  fs11.chmodSync(daemonDir, 448);
35645
- const logPath = path12.join(daemonDir, "daemon.log");
36439
+ const logPath = path16.join(daemonDir, "daemon.log");
35646
36440
  let warnedOversize = false;
35647
36441
  const sink = createRotatingFileSink(logPath, DAEMON_LOG_MAX_BYTES, {
35648
36442
  mode: 384,
@@ -35878,16 +36672,16 @@ var LEGACY_DAEMON_ID_PATTERN = /^[a-f0-9]{12}$/;
35878
36672
  var DEFAULT_SERVER_URL = "https://alook.ai";
35879
36673
  var DEFAULT_WS_URL = "wss://alook.ai/api/ws/community-daemon";
35880
36674
  function resolveDefaultBaseDir() {
35881
- const root = process.env.ALOOK_PROJECT_ROOT || path13.join(homedir6(), ".alook");
35882
- return path13.join(root, "daemon");
36675
+ const root = process.env.ALOOK_PROJECT_ROOT || path17.join(homedir8(), ".alook");
36676
+ return path17.join(root, "daemon");
35883
36677
  }
35884
36678
  var DEFAULT_BASE_DIR = resolveDefaultBaseDir();
35885
36679
  var log2 = createLogger2({ header: "@alook/daemon" });
35886
36680
  function daemonsDir(baseDir) {
35887
- return path13.join(baseDir, "daemons");
36681
+ return path17.join(baseDir, "daemons");
35888
36682
  }
35889
36683
  function daemonDirById(baseDir, id) {
35890
- return path13.join(daemonsDir(baseDir), validateDaemonId(id));
36684
+ return path17.join(daemonsDir(baseDir), validateDaemonId(id));
35891
36685
  }
35892
36686
  function validateMachineId(machineId) {
35893
36687
  if (!MACHINE_ID_PATTERN.test(machineId))
@@ -35903,10 +36697,10 @@ function validateDaemonId(id) {
35903
36697
  return id;
35904
36698
  }
35905
36699
  function pidfilePathById(baseDir, id) {
35906
- return path13.join(daemonDirById(baseDir, id), "daemon.pid");
36700
+ return path17.join(daemonDirById(baseDir, id), "daemon.pid");
35907
36701
  }
35908
36702
  function statusFilePathById(baseDir, id) {
35909
- return path13.join(daemonDirById(baseDir, id), "status.json");
36703
+ return path17.join(daemonDirById(baseDir, id), "status.json");
35910
36704
  }
35911
36705
  function isProcessAlive(pid) {
35912
36706
  try {
@@ -35966,9 +36760,9 @@ function syncDirectory(dir) {
35966
36760
  }
35967
36761
  }
35968
36762
  function writeExclusive(filePath, value) {
35969
- const dir = path13.dirname(filePath);
36763
+ const dir = path17.dirname(filePath);
35970
36764
  ensurePrivateDir2(dir);
35971
- const tempPath = path13.join(dir, `.${path13.basename(filePath)}.${process.pid}.${crypto5.randomBytes(12).toString("hex")}.tmp`);
36765
+ const tempPath = path17.join(dir, `.${path17.basename(filePath)}.${process.pid}.${crypto5.randomBytes(12).toString("hex")}.tmp`);
35972
36766
  let fd = fs12.openSync(tempPath, "wx", 384);
35973
36767
  try {
35974
36768
  fs12.writeFileSync(fd, JSON.stringify(value));
@@ -35990,9 +36784,9 @@ function writeExclusive(filePath, value) {
35990
36784
  }
35991
36785
  }
35992
36786
  function writePrivateJsonAtomic2(filePath, value) {
35993
- const dir = path13.dirname(filePath);
36787
+ const dir = path17.dirname(filePath);
35994
36788
  ensurePrivateDir2(dir);
35995
- const tempPath = path13.join(dir, `.${path13.basename(filePath)}.${process.pid}.${crypto5.randomBytes(12).toString("hex")}.tmp`);
36789
+ const tempPath = path17.join(dir, `.${path17.basename(filePath)}.${process.pid}.${crypto5.randomBytes(12).toString("hex")}.tmp`);
35996
36790
  let fd = fs12.openSync(tempPath, "wx", 384);
35997
36791
  try {
35998
36792
  fs12.writeFileSync(fd, JSON.stringify(value));
@@ -36016,8 +36810,8 @@ function writePrivateJsonAtomic2(filePath, value) {
36016
36810
  function secureExistingFile(filePath) {
36017
36811
  if (!fs12.existsSync(filePath))
36018
36812
  return;
36019
- const stat = fs12.lstatSync(filePath);
36020
- if (!stat.isFile())
36813
+ const stat2 = fs12.lstatSync(filePath);
36814
+ if (!stat2.isFile())
36021
36815
  throw new Error("unsafe daemon ownership file type");
36022
36816
  fs12.chmodSync(filePath, 384);
36023
36817
  }
@@ -36079,14 +36873,14 @@ function clearStaleOwnership(filePath, liveError) {
36079
36873
  } catch {}
36080
36874
  }
36081
36875
  function replacementLockPathById(baseDir, machineId) {
36082
- return path13.join(daemonDirById(baseDir, machineId), "daemon.replace.lock");
36876
+ return path17.join(daemonDirById(baseDir, machineId), "daemon.replace.lock");
36083
36877
  }
36084
36878
  function readReplacementLock(filePath) {
36085
36879
  if (!fs12.existsSync(filePath))
36086
36880
  return null;
36087
36881
  try {
36088
- const stat = fs12.lstatSync(filePath);
36089
- if (!stat.isFile())
36882
+ const stat2 = fs12.lstatSync(filePath);
36883
+ if (!stat2.isFile())
36090
36884
  throw new Error("unsafe daemon replacement lock type");
36091
36885
  fs12.chmodSync(filePath, 384);
36092
36886
  const content = JSON.parse(fs12.readFileSync(filePath, "utf8"));
@@ -36149,7 +36943,7 @@ function checkReplacementLock(baseDir, machineId, resumeRequestId) {
36149
36943
  }
36150
36944
  function acquireDaemonReplacementLock(args) {
36151
36945
  const lockPath = replacementLockPathById(args.baseDir, args.machineId);
36152
- ensurePrivateDir2(path13.dirname(lockPath));
36946
+ ensurePrivateDir2(path17.dirname(lockPath));
36153
36947
  checkReplacementLock(args.baseDir, args.machineId);
36154
36948
  const lock = {
36155
36949
  pid: process.pid,
@@ -36162,11 +36956,11 @@ function acquireDaemonReplacementLock(args) {
36162
36956
  return { path: lockPath, lock };
36163
36957
  }
36164
36958
  function coarseStartLockPath(baseDir) {
36165
- return path13.join(daemonsDir(baseDir), ".start.lock");
36959
+ return path17.join(daemonsDir(baseDir), ".start.lock");
36166
36960
  }
36167
36961
  function acquireCoarseLock(baseDir, ownerToken) {
36168
36962
  const lf = coarseStartLockPath(baseDir);
36169
- ensurePrivateDir2(path13.dirname(lf));
36963
+ ensurePrivateDir2(path17.dirname(lf));
36170
36964
  secureExistingFile(lf);
36171
36965
  clearStaleOwnership(lf, (pid) => new Error(`another daemon start is in progress on this machine (pid ${pid})`));
36172
36966
  writeExclusive(lf, { pid: process.pid, machineId: "coarse", startedAt: new Date().toISOString(), ownerToken });
@@ -36175,7 +36969,7 @@ function acquireCoarseLock(baseDir, ownerToken) {
36175
36969
  function acquireLaunchLock(baseDir, machineId, ownerToken, resumeRequestId) {
36176
36970
  const daemonDir = daemonDirById(baseDir, machineId);
36177
36971
  ensurePrivateDir2(daemonDir);
36178
- const lockPath = path13.join(daemonDir, "daemon.launch.lock");
36972
+ const lockPath = path17.join(daemonDir, "daemon.launch.lock");
36179
36973
  const finalPath = pidfilePathById(baseDir, machineId);
36180
36974
  checkReplacementLock(baseDir, machineId, resumeRequestId);
36181
36975
  secureExistingFile(lockPath);
@@ -36197,9 +36991,9 @@ function legacyPidfileCandidates(baseDir) {
36197
36991
  const candidates = [];
36198
36992
  for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
36199
36993
  if (entry.isDirectory()) {
36200
- candidates.push(path13.join(dir, entry.name, "daemon.pid"));
36994
+ candidates.push(path17.join(dir, entry.name, "daemon.pid"));
36201
36995
  } else if (entry.isFile() && entry.name.endsWith(".pid")) {
36202
- candidates.push(path13.join(dir, entry.name));
36996
+ candidates.push(path17.join(dir, entry.name));
36203
36997
  }
36204
36998
  }
36205
36999
  return candidates;
@@ -36271,7 +37065,7 @@ function daemonList(opts) {
36271
37065
  for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
36272
37066
  if (entry.isDirectory() && isDaemonId(entry.name)) {
36273
37067
  const id = entry.name;
36274
- pushRow(id, path13.join(dir, id, "daemon.pid"), path13.join(dir, id, "status.json"));
37068
+ pushRow(id, path17.join(dir, id, "daemon.pid"), path17.join(dir, id, "status.json"));
36275
37069
  }
36276
37070
  }
36277
37071
  return results;
@@ -36319,7 +37113,7 @@ function daemonIdsWithStatus(baseDir) {
36319
37113
  return [];
36320
37114
  const ids = [];
36321
37115
  for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
36322
- if (entry.isDirectory() && isDaemonId(entry.name) && fs12.existsSync(path13.join(dir, entry.name, "status.json"))) {
37116
+ if (entry.isDirectory() && isDaemonId(entry.name) && fs12.existsSync(path17.join(dir, entry.name, "status.json"))) {
36323
37117
  ids.push(entry.name);
36324
37118
  }
36325
37119
  }
@@ -36382,16 +37176,16 @@ async function stopByPidfile(pf, notFoundHint) {
36382
37176
  }
36383
37177
  async function daemonStop(opts) {
36384
37178
  const baseDir = opts.baseDir || process.env.ALOOK_DATA_DIR || DEFAULT_BASE_DIR;
36385
- await stopByPidfile(path13.join(daemonDirById(baseDir, opts.id), "daemon.pid"), `no daemon with id '${opts.id}' (pidfile not found — check \`alook daemon list\`)`);
37179
+ await stopByPidfile(path17.join(daemonDirById(baseDir, opts.id), "daemon.pid"), `no daemon with id '${opts.id}' (pidfile not found — check \`alook daemon list\`)`);
36386
37180
  }
36387
37181
  function credentialFilePathByMachineId(baseDir, machineId) {
36388
- return path13.join(daemonsDir(baseDir), `${validateMachineId(machineId)}.credential.json`);
37182
+ return path17.join(daemonsDir(baseDir), `${validateMachineId(machineId)}.credential.json`);
36389
37183
  }
36390
37184
  function readCredentialFile(filePath) {
36391
37185
  if (!fs12.existsSync(filePath))
36392
37186
  return null;
36393
- const stat = fs12.lstatSync(filePath);
36394
- if (!stat.isFile())
37187
+ const stat2 = fs12.lstatSync(filePath);
37188
+ if (!stat2.isFile())
36395
37189
  throw new Error("unsafe daemon credential file type");
36396
37190
  fs12.chmodSync(filePath, 384);
36397
37191
  try {
@@ -36432,7 +37226,7 @@ function findExistingCredentialForBearer(baseDir, bearer) {
36432
37226
  for (const file2 of fs12.readdirSync(dir)) {
36433
37227
  if (!file2.endsWith(".credential.json"))
36434
37228
  continue;
36435
- const parsed = readCredentialFile(path13.join(dir, file2));
37229
+ const parsed = readCredentialFile(path17.join(dir, file2));
36436
37230
  if (parsed && parsed.credential === bearer)
36437
37231
  return parsed;
36438
37232
  }
@@ -36713,7 +37507,7 @@ function waitForReceipt(child, prepared) {
36713
37507
  };
36714
37508
  const configuredTestTimeout = NaN;
36715
37509
  const receiptTimeoutMs = Number.isFinite(configuredTestTimeout) && configuredTestTimeout > 0 ? configuredTestTimeout : START_RECEIPT_TIMEOUT_MS;
36716
- const timeout = setTimeout(() => settle(new Error(`daemon start timed out; inspect ${path13.join(prepared.daemonDir, "daemon.log")}`)), receiptTimeoutMs);
37510
+ const timeout = setTimeout(() => settle(new Error(`daemon start timed out; inspect ${path17.join(prepared.daemonDir, "daemon.log")}`)), receiptTimeoutMs);
36717
37511
  child.on("message", (message2) => {
36718
37512
  const accepted = message2;
36719
37513
  if (accepted.type === "daemon:accepted") {
@@ -36732,7 +37526,7 @@ function waitForReceipt(child, prepared) {
36732
37526
  settle(undefined, receipt);
36733
37527
  });
36734
37528
  child.once("exit", (code, signal) => {
36735
- settle(new Error(`daemon child exited before ready (${signal ?? code}); inspect ${path13.join(prepared.daemonDir, "daemon.log")}`));
37529
+ settle(new Error(`daemon child exited before ready (${signal ?? code}); inspect ${path17.join(prepared.daemonDir, "daemon.log")}`));
36736
37530
  });
36737
37531
  child.once("error", (error51) => settle(error51));
36738
37532
  });