@alook/daemon 0.1.31 → 0.1.33

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 +1295 -235
  2. package/dist/index.js +1127 -152
  3. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -15888,6 +15888,7 @@ __export(exports_schema, {
15888
15888
  user: () => user,
15889
15889
  taskMessage: () => taskMessage,
15890
15890
  session: () => session,
15891
+ nativeOauthAttempt: () => nativeOauthAttempt,
15891
15892
  messageFlag: () => messageFlag,
15892
15893
  message: () => message,
15893
15894
  member: () => member,
@@ -15914,7 +15915,11 @@ __export(exports_schema, {
15914
15915
  agentEmailAccount: () => agentEmailAccount,
15915
15916
  agentAccess: () => agentAccess,
15916
15917
  agent: () => agent,
15917
- account: () => account
15918
+ account: () => account,
15919
+ NATIVE_OAUTH_STATUSES: () => NATIVE_OAUTH_STATUSES,
15920
+ NATIVE_OAUTH_PROVIDERS: () => NATIVE_OAUTH_PROVIDERS,
15921
+ NATIVE_OAUTH_PLATFORMS: () => NATIVE_OAUTH_PLATFORMS,
15922
+ NATIVE_OAUTH_FAILURE_CODES: () => NATIVE_OAUTH_FAILURE_CODES
15918
15923
  });
15919
15924
  init_nanoid();
15920
15925
 
@@ -15979,6 +15984,7 @@ var TERMINAL_MEETING_STATUSES = [
15979
15984
  MeetingStatus.COMPLETED,
15980
15985
  MeetingStatus.FAILED
15981
15986
  ];
15987
+ var COMMUNITY_BOT_LIMIT_PER_OWNER = 20;
15982
15988
  var COMMUNITY_BOT_NAME_MIN = 1;
15983
15989
  var COMMUNITY_BOT_NAME_MAX = 32;
15984
15990
  var COMMUNITY_BOT_DESCRIPTION_MAX = 1024;
@@ -16044,6 +16050,119 @@ var verification = sqliteTable("verification", {
16044
16050
  createdAt: text("createdAt").notNull().$defaultFn(() => new Date().toISOString()),
16045
16051
  updatedAt: text("updatedAt").notNull().$defaultFn(() => new Date().toISOString())
16046
16052
  });
16053
+ var NATIVE_OAUTH_PROVIDERS = ["github", "google"];
16054
+ var NATIVE_OAUTH_PLATFORMS = [
16055
+ "macos",
16056
+ "windows",
16057
+ "linux",
16058
+ "ios",
16059
+ "android"
16060
+ ];
16061
+ var NATIVE_OAUTH_STATUSES = [
16062
+ "pending",
16063
+ "opened",
16064
+ "ready",
16065
+ "exchanging",
16066
+ "consumed",
16067
+ "failed",
16068
+ "cancelled",
16069
+ "replaced"
16070
+ ];
16071
+ var NATIVE_OAUTH_FAILURE_CODES = [
16072
+ "access_denied",
16073
+ "provider_error",
16074
+ "oauth_callback_failed",
16075
+ "start_failed",
16076
+ "invalid_handoff"
16077
+ ];
16078
+ var nativeOauthAttempt = sqliteTable("native_oauth_attempt", {
16079
+ id: text("id").primaryKey(),
16080
+ instanceKeyHash: text("instance_key_hash").notNull(),
16081
+ stateHash: text("state_hash").notNull(),
16082
+ pkceChallenge: text("pkce_challenge").notNull(),
16083
+ provider: text("provider").$type().notNull(),
16084
+ platform: text("platform").$type().notNull(),
16085
+ redirectPath: text("redirect_path").notNull(),
16086
+ status: text("status").$type().notNull().default("pending"),
16087
+ handoffCodeHash: text("handoff_code_hash"),
16088
+ handoffExpiresAt: integer2("handoff_expires_at"),
16089
+ authKind: text("auth_kind").$type(),
16090
+ failureCode: text("failure_code").$type(),
16091
+ attemptExpiresAt: integer2("attempt_expires_at").notNull(),
16092
+ createdAt: integer2("created_at").notNull(),
16093
+ updatedAt: integer2("updated_at").notNull(),
16094
+ openedAt: integer2("opened_at"),
16095
+ readyAt: integer2("ready_at"),
16096
+ consumedAt: integer2("consumed_at"),
16097
+ failedAt: integer2("failed_at"),
16098
+ cancelledAt: integer2("cancelled_at"),
16099
+ replacedAt: integer2("replaced_at")
16100
+ }, (t) => [
16101
+ index("idx_native_oauth_attempt_instance_status").on(t.instanceKeyHash, t.status),
16102
+ index("idx_native_oauth_attempt_id_status_expiry").on(t.id, t.status, t.attemptExpiresAt),
16103
+ index("idx_native_oauth_attempt_terminal_cleanup").on(t.status, t.updatedAt),
16104
+ uniqueIndex("uq_native_oauth_attempt_instance_live").on(t.instanceKeyHash).where(sql`status IN ('pending', 'opened', 'ready', 'exchanging')`),
16105
+ uniqueIndex("uq_native_oauth_attempt_handoff_hash").on(t.handoffCodeHash).where(sql`handoff_code_hash IS NOT NULL`),
16106
+ check2("ck_native_oauth_attempt_id", sql`length(${t.id}) BETWEEN 22 AND 64 AND ${t.id} NOT GLOB '*[^A-Za-z0-9_-]*'`),
16107
+ check2("ck_native_oauth_attempt_hashes", sql`length(${t.instanceKeyHash}) = 64 AND ${t.instanceKeyHash} NOT GLOB '*[^0-9a-f]*'
16108
+ AND length(${t.stateHash}) = 64 AND ${t.stateHash} NOT GLOB '*[^0-9a-f]*'
16109
+ AND length(${t.pkceChallenge}) = 43 AND ${t.pkceChallenge} NOT GLOB '*[^A-Za-z0-9_-]*'
16110
+ AND (${t.handoffCodeHash} IS NULL OR (length(${t.handoffCodeHash}) = 64 AND ${t.handoffCodeHash} NOT GLOB '*[^0-9a-f]*'))`),
16111
+ check2("ck_native_oauth_attempt_enums", sql`${t.provider} IN ('github', 'google')
16112
+ AND ${t.platform} IN ('macos', 'windows', 'linux', 'ios', 'android')
16113
+ AND ${t.status} IN ('pending', 'opened', 'ready', 'exchanging', 'consumed', 'failed', 'cancelled', 'replaced')
16114
+ AND (${t.authKind} IS NULL OR ${t.authKind} IN ('signin', 'signup'))
16115
+ AND (${t.failureCode} IS NULL OR ${t.failureCode} IN ('access_denied', 'provider_error', 'oauth_callback_failed', 'start_failed', 'invalid_handoff'))`),
16116
+ check2("ck_native_oauth_attempt_redirect", sql`length(${t.redirectPath}) BETWEEN 1 AND 2048
16117
+ AND substr(${t.redirectPath}, 1, 1) = '/'
16118
+ AND substr(${t.redirectPath}, 1, 2) <> '//'
16119
+ AND instr(${t.redirectPath}, char(92)) = 0`),
16120
+ check2("ck_native_oauth_attempt_epochs", sql`typeof(${t.createdAt}) = 'integer' AND ${t.createdAt} BETWEEN 0 AND 9007199254740991
16121
+ AND typeof(${t.updatedAt}) = 'integer' AND ${t.updatedAt} BETWEEN ${t.createdAt} AND 9007199254740991
16122
+ AND typeof(${t.attemptExpiresAt}) = 'integer' AND ${t.attemptExpiresAt} = ${t.createdAt} + 600000
16123
+ AND (${t.handoffExpiresAt} IS NULL OR (typeof(${t.handoffExpiresAt}) = 'integer' AND ${t.handoffExpiresAt} <= ${t.attemptExpiresAt}))`),
16124
+ check2("ck_native_oauth_attempt_state", sql`(
16125
+ ${t.status} = 'pending'
16126
+ AND ${t.openedAt} IS NULL AND ${t.readyAt} IS NULL AND ${t.consumedAt} IS NULL
16127
+ AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
16128
+ AND ${t.handoffCodeHash} IS NULL AND ${t.handoffExpiresAt} IS NULL
16129
+ AND ${t.authKind} IS NULL AND ${t.failureCode} IS NULL
16130
+ ) OR (
16131
+ ${t.status} = 'opened'
16132
+ AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NULL AND ${t.consumedAt} IS NULL
16133
+ AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
16134
+ AND ${t.handoffCodeHash} IS NULL AND ${t.handoffExpiresAt} IS NULL
16135
+ AND ${t.authKind} IS NULL AND ${t.failureCode} IS NULL
16136
+ ) OR (
16137
+ ${t.status} IN ('ready', 'exchanging')
16138
+ AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NOT NULL AND ${t.consumedAt} IS NULL
16139
+ AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
16140
+ AND ${t.handoffCodeHash} IS NOT NULL AND ${t.handoffExpiresAt} IS NOT NULL
16141
+ AND ${t.handoffExpiresAt} = ${t.readyAt} + 120000
16142
+ AND ${t.authKind} IS NOT NULL AND ${t.failureCode} IS NULL
16143
+ ) OR (
16144
+ ${t.status} = 'consumed'
16145
+ AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NOT NULL AND ${t.consumedAt} IS NOT NULL
16146
+ AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
16147
+ AND ${t.handoffCodeHash} IS NOT NULL AND ${t.handoffExpiresAt} IS NOT NULL
16148
+ AND ${t.authKind} IS NOT NULL AND ${t.failureCode} IS NULL
16149
+ ) OR (
16150
+ ${t.status} = 'failed'
16151
+ AND ${t.consumedAt} IS NULL AND ${t.failedAt} IS NOT NULL
16152
+ AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
16153
+ AND ${t.failureCode} IS NOT NULL
16154
+ ) OR (
16155
+ ${t.status} = 'cancelled'
16156
+ AND ${t.consumedAt} IS NULL AND ${t.cancelledAt} IS NOT NULL
16157
+ AND ${t.failedAt} IS NULL AND ${t.replacedAt} IS NULL
16158
+ AND ${t.failureCode} IS NULL
16159
+ ) OR (
16160
+ ${t.status} = 'replaced'
16161
+ AND ${t.consumedAt} IS NULL AND ${t.replacedAt} IS NOT NULL
16162
+ AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL
16163
+ AND ${t.failureCode} IS NULL
16164
+ )`)
16165
+ ]);
16047
16166
  var workspace = sqliteTable("workspace", {
16048
16167
  id: text("id").primaryKey().$defaultFn(() => "sp_" + nanoid3()),
16049
16168
  name: text("name").notNull(),
@@ -16853,6 +16972,13 @@ var HostCommandSchema = exports_external.discriminatedUnion("type", [
16853
16972
  launchId: exports_external.string().min(1),
16854
16973
  unreadNotice: exports_external.unknown()
16855
16974
  }),
16975
+ exports_external.object({
16976
+ type: exports_external.literal("agent:event"),
16977
+ agentId: exports_external.string().min(1),
16978
+ config: exports_external.unknown(),
16979
+ launchId: exports_external.string().min(1),
16980
+ prompt: exports_external.string().min(1).max(32768)
16981
+ }),
16856
16982
  exports_external.object({
16857
16983
  type: exports_external.literal("agent:stop"),
16858
16984
  agentId: exports_external.string().min(1)
@@ -17762,6 +17888,10 @@ var CommunityBotPatchRequestSchema = exports_external.object({
17762
17888
  var CommunityBotAddToServerRequestSchema = exports_external.object({
17763
17889
  botId: exports_external.string().min(1)
17764
17890
  });
17891
+ var CommunityServerOnboardRequestSchema = exports_external.strictObject({
17892
+ 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"),
17893
+ wakePrompt: exports_external.string().max(32768).refine((value) => value.trim().length > 0, "wakePrompt is required")
17894
+ });
17765
17895
  var CommunityAgentMessageContentSchema = exports_external.object({ text: exports_external.string().max(MAX_MESSAGE_CONTENT_LENGTH).default("") }).catchall(exports_external.unknown());
17766
17896
  var CommunityAgentSeqSchema = exports_external.number().int().min(0);
17767
17897
  var CommunityAgentPositiveSeqSchema = exports_external.number().int().min(1);
@@ -18365,6 +18495,15 @@ function createLogger(opts) {
18365
18495
 
18366
18496
  // ../shared/src/db/queries/_chunk.ts
18367
18497
  var D1_MAX_BIND_PARAMS = 100;
18498
+ function maxInParams(fixedParams) {
18499
+ if (!Number.isInteger(fixedParams) || fixedParams < 0) {
18500
+ throw new Error("fixed params must be a non-negative integer");
18501
+ }
18502
+ if (fixedParams >= D1_MAX_BIND_PARAMS) {
18503
+ throw new Error("fixed params must leave room for at least one IN parameter");
18504
+ }
18505
+ return D1_MAX_BIND_PARAMS - fixedParams;
18506
+ }
18368
18507
  function maxRowsPerInsert(paramsPerRow) {
18369
18508
  if (paramsPerRow < 1)
18370
18509
  throw new Error("paramsPerRow must be >= 1");
@@ -18456,6 +18595,7 @@ var AGENT_MESSAGE_COLUMNS = {
18456
18595
  replyToId: communityMessage.replyToId
18457
18596
  };
18458
18597
  var channelJoinBaselineGuard = sql`${communityMessage.createdAt} > COALESCE(${communityChannelMember.addedAt}, ${communityServerMember.joinedAt}, '')`;
18598
+ var AGENT_UNREAD_CHANNEL_CHUNK_SIZE = maxInParams(13);
18459
18599
 
18460
18600
  // ../shared/src/db/queries/community/mention.ts
18461
18601
  var MENTION_INSERT_MAX_ROWS = maxRowsPerInsert(5);
@@ -19068,6 +19208,10 @@ var serverRailCommandSchema = exports_external.discriminatedUnion("kind", [
19068
19208
  var serverRailCommitRequestSchema = exports_external.strictObject({
19069
19209
  commands: exports_external.array(serverRailCommandSchema).min(1).max(MAX_SERVER_RAIL_COMMANDS)
19070
19210
  });
19211
+ // ../shared/src/db/queries/native-oauth.ts
19212
+ var ATTEMPT_TTL_MS = 10 * 60 * 1000;
19213
+ var HANDOFF_TTL_MS = 2 * 60 * 1000;
19214
+ var RETENTION_MS = 24 * 60 * 60 * 1000;
19071
19215
  // ../shared/src/db/queries/task.ts
19072
19216
  var DEFAULT_STALE_SECONDS = Number(process.env.ALOOK_STALE_DISPATCH_TIMEOUT_S) || 20;
19073
19217
  var DEFAULT_STALE_RUNNING_SECONDS = Number(process.env.ALOOK_STALE_RUNNING_TIMEOUT_S) || 3600;
@@ -19108,6 +19252,80 @@ function parseInviteToken(input) {
19108
19252
  return urlMatch[1];
19109
19253
  return BARE_TOKEN_RE.test(trimmed) ? trimmed : null;
19110
19254
  }
19255
+ // ../shared/src/lib/safe-redirect.ts
19256
+ var MAX_REDIRECT_BYTES = 2048;
19257
+ var CONTROL_CHARACTERS = /[\u0000-\u001f\u007f]/;
19258
+ function isSafeCandidate(value) {
19259
+ return value.startsWith("/") && !value.startsWith("//") && !value.includes("\\") && !value.includes("#") && !CONTROL_CHARACTERS.test(value);
19260
+ }
19261
+ function isSafeRedirectPath(value) {
19262
+ if (new TextEncoder().encode(value).byteLength > MAX_REDIRECT_BYTES)
19263
+ return false;
19264
+ if (!isSafeCandidate(value))
19265
+ return false;
19266
+ let decoded = value;
19267
+ for (let depth = 0;depth < 8; depth += 1) {
19268
+ let next;
19269
+ try {
19270
+ next = decodeURIComponent(decoded);
19271
+ } catch {
19272
+ return depth > 0;
19273
+ }
19274
+ if (next === decoded)
19275
+ break;
19276
+ if (!isSafeCandidate(next))
19277
+ return false;
19278
+ decoded = next;
19279
+ if (depth === 7)
19280
+ return false;
19281
+ }
19282
+ try {
19283
+ const base = new URL("https://alook.invalid");
19284
+ const resolved = new URL(value, base);
19285
+ return resolved.origin === base.origin;
19286
+ } catch {
19287
+ return false;
19288
+ }
19289
+ }
19290
+
19291
+ // ../shared/src/lib/native-oauth-contract.ts
19292
+ var ATTEMPT_ID = /^[A-Za-z0-9_-]{22,64}$/;
19293
+ var SHA256_HEX = /^[0-9a-f]{64}$/;
19294
+ var BASE64URL_32_BYTES = /^[A-Za-z0-9_-]{43}$/;
19295
+ var HANDOFF_CODE = /^[A-Za-z0-9_-]{32,128}$/;
19296
+ var nativeOauthProviderSchema = exports_external.enum(["github", "google"]);
19297
+ var nativeOauthPlatformSchema = exports_external.enum([
19298
+ "macos",
19299
+ "windows",
19300
+ "linux",
19301
+ "ios",
19302
+ "android"
19303
+ ]);
19304
+ var nativeOauthAttemptIdSchema = exports_external.string().regex(ATTEMPT_ID);
19305
+ var nativeOauthHandoffCodeSchema = exports_external.string().regex(HANDOFF_CODE);
19306
+ var nativeOauthFailureCodeSchema = exports_external.enum([
19307
+ "access_denied",
19308
+ "provider_error",
19309
+ "oauth_callback_failed",
19310
+ "start_failed",
19311
+ "invalid_handoff"
19312
+ ]);
19313
+ var nativeOauthRegistrationSchema = exports_external.object({
19314
+ attemptId: nativeOauthAttemptIdSchema,
19315
+ stateHash: exports_external.string().regex(SHA256_HEX),
19316
+ codeChallenge: exports_external.string().regex(BASE64URL_32_BYTES),
19317
+ instanceKeyHash: exports_external.string().regex(SHA256_HEX),
19318
+ platform: nativeOauthPlatformSchema,
19319
+ provider: nativeOauthProviderSchema,
19320
+ redirectPath: exports_external.string().refine(isSafeRedirectPath)
19321
+ }).strict();
19322
+ var nativeOauthExchangeSchema = exports_external.object({
19323
+ attemptId: nativeOauthAttemptIdSchema,
19324
+ state: exports_external.string().regex(BASE64URL_32_BYTES),
19325
+ verifier: exports_external.string().regex(BASE64URL_32_BYTES),
19326
+ code: nativeOauthHandoffCodeSchema
19327
+ }).strict();
19328
+ var nativeOauthProofSchema = nativeOauthExchangeSchema.omit({ code: true }).strict();
19111
19329
  // ../shared/src/semver.ts
19112
19330
  var RELEASE_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
19113
19331
  function parseReleaseVersion(value) {
@@ -19557,13 +19775,13 @@ function createProxyServerApi(config2) {
19557
19775
 
19558
19776
  // src/cli/daemonStart.ts
19559
19777
  import * as fs12 from "fs";
19560
- import * as path13 from "path";
19778
+ import * as path17 from "path";
19561
19779
  import * as crypto5 from "crypto";
19562
19780
  import * as os3 from "os";
19563
- import { homedir as homedir6 } from "os";
19781
+ import { homedir as homedir8 } from "os";
19564
19782
 
19565
19783
  // src/discovery.ts
19566
- import * as path9 from "path";
19784
+ import * as path13 from "path";
19567
19785
  import * as fs6 from "fs";
19568
19786
  import { fileURLToPath } from "url";
19569
19787
  // agent-driver/dist/host/default-host.js
@@ -20707,6 +20925,12 @@ function tryParseJsonLine(line) {
20707
20925
  return null;
20708
20926
  }
20709
20927
  }
20928
+ function asRecord(value) {
20929
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
20930
+ }
20931
+ function tryParseJsonRecord(line) {
20932
+ return asRecord(tryParseJsonLine(line));
20933
+ }
20710
20934
 
20711
20935
  // agent-driver/dist/adapters/claude/normalizer.js
20712
20936
  var API_ERROR_RE = /API Error:.*(?:Connection error|\b[45]\d{2}\b)/i;
@@ -21205,6 +21429,241 @@ class ClaudeTurnProtocol {
21205
21429
  }
21206
21430
  }
21207
21431
 
21432
+ // agent-driver/dist/adapters/claude/recent-context.js
21433
+ import { createReadStream as createReadStream2 } from "node:fs";
21434
+ import { homedir } from "node:os";
21435
+ import path7 from "node:path";
21436
+ import { createInterface } from "node:readline";
21437
+
21438
+ // agent-driver/dist/internal/recent-context.js
21439
+ import path6 from "node:path";
21440
+ import { createReadStream } from "node:fs";
21441
+ import { readdir, stat } from "node:fs/promises";
21442
+ function normalizeAbsolutePath(value) {
21443
+ if (typeof value !== "string" || !path6.isAbsolute(value))
21444
+ return null;
21445
+ return path6.normalize(value);
21446
+ }
21447
+ function normalizeModifiedAt(value) {
21448
+ const date5 = value instanceof Date ? value : typeof value === "string" || typeof value === "number" ? new Date(value) : null;
21449
+ if (!date5 || !Number.isFinite(date5.getTime()))
21450
+ return null;
21451
+ return date5.toISOString();
21452
+ }
21453
+ function isValidRecentContextTopK(value) {
21454
+ return Number.isSafeInteger(value) && value >= 0;
21455
+ }
21456
+ function isMissingPathError(error51) {
21457
+ return error51?.code === "ENOENT";
21458
+ }
21459
+ async function readFirstLine(filePath, maxBytes = 65536) {
21460
+ const stream = createReadStream(filePath, { highWaterMark: 1 });
21461
+ const bytes = [];
21462
+ let length = 0;
21463
+ try {
21464
+ for await (const chunk2 of stream) {
21465
+ const byte = Buffer.isBuffer(chunk2) ? chunk2 : Buffer.from(chunk2);
21466
+ if (byte[0] === 10)
21467
+ break;
21468
+ if (length >= maxBytes)
21469
+ return null;
21470
+ bytes.push(byte);
21471
+ length += byte.length;
21472
+ }
21473
+ return length === 0 ? null : Buffer.concat(bytes, length).toString("utf8").replace(/\r$/, "");
21474
+ } catch (error51) {
21475
+ if (isMissingPathError(error51))
21476
+ return null;
21477
+ throw error51;
21478
+ } finally {
21479
+ stream.destroy();
21480
+ }
21481
+ }
21482
+ async function collectJsonlFileCandidates(root, options = {}) {
21483
+ const candidates = [];
21484
+ const readDirectory = options.readDirectory ?? ((directory) => readdir(directory, { withFileTypes: true }));
21485
+ const statPath = options.statPath ?? stat;
21486
+ const visit = async (directory, remainingDepth, includeFiles) => {
21487
+ let entries;
21488
+ try {
21489
+ entries = await readDirectory(directory);
21490
+ } catch (error51) {
21491
+ if (isMissingPathError(error51))
21492
+ return;
21493
+ throw error51;
21494
+ }
21495
+ await Promise.all(entries.map(async (entry) => {
21496
+ const entryPath = path6.join(directory, entry.name);
21497
+ if (entry.isDirectory() && remainingDepth > 0) {
21498
+ await visit(entryPath, remainingDepth - 1, true);
21499
+ } else if (includeFiles && entry.isFile() && entry.name.endsWith(".jsonl")) {
21500
+ try {
21501
+ const metadata = await statPath(entryPath);
21502
+ if (metadata.isFile())
21503
+ candidates.push({ filePath: entryPath, modifiedAt: metadata.mtime });
21504
+ } catch (error51) {
21505
+ if (!isMissingPathError(error51))
21506
+ throw error51;
21507
+ }
21508
+ }
21509
+ }));
21510
+ };
21511
+ await visit(root, options.maxDepth ?? Number.POSITIVE_INFINITY, options.includeRootFiles ?? true);
21512
+ return candidates;
21513
+ }
21514
+ function retainNewest(values, key, value, topK) {
21515
+ const existing = values.get(key);
21516
+ if (existing) {
21517
+ if (value.modifiedAt > existing.modifiedAt)
21518
+ values.set(key, value);
21519
+ return;
21520
+ }
21521
+ if (values.size < topK) {
21522
+ values.set(key, value);
21523
+ return;
21524
+ }
21525
+ let oldest;
21526
+ for (const entry of values) {
21527
+ if (!oldest || entry[1].modifiedAt < oldest[1].modifiedAt)
21528
+ oldest = entry;
21529
+ }
21530
+ if (oldest && value.modifiedAt > oldest[1].modifiedAt) {
21531
+ values.delete(oldest[0]);
21532
+ values.set(key, value);
21533
+ }
21534
+ }
21535
+
21536
+ class RecentContextCollector {
21537
+ request;
21538
+ sessionFileCapability;
21539
+ sessions = new Map;
21540
+ projects = new Map;
21541
+ constructor(request, sessionFileCapability) {
21542
+ this.request = request;
21543
+ this.sessionFileCapability = sessionFileCapability;
21544
+ }
21545
+ add(candidate, target2 = "both") {
21546
+ const projectPath = normalizeAbsolutePath(candidate.projectPath);
21547
+ const modifiedAt = normalizeModifiedAt(candidate.modifiedAt);
21548
+ if (!projectPath || !modifiedAt)
21549
+ return;
21550
+ if (target2 !== "session") {
21551
+ retainNewest(this.projects, projectPath, { projectPath, modifiedAt }, this.request.recentProjectsTopK);
21552
+ }
21553
+ if (target2 === "project" || this.sessionFileCapability !== "supported")
21554
+ return;
21555
+ const sessionFilePath = normalizeAbsolutePath(candidate.sessionFilePath);
21556
+ if (!sessionFilePath)
21557
+ return;
21558
+ retainNewest(this.sessions, sessionFilePath, { sessionFilePath, projectPath, modifiedAt }, this.request.recentSessionFilesTopK);
21559
+ }
21560
+ get satisfied() {
21561
+ const sessionsSatisfied = this.sessionFileCapability === "unavailable" || this.sessions.size >= this.request.recentSessionFilesTopK;
21562
+ return sessionsSatisfied && this.projects.size >= this.request.recentProjectsTopK;
21563
+ }
21564
+ result() {
21565
+ const newestFirst = (left, right) => right.modifiedAt.localeCompare(left.modifiedAt);
21566
+ return {
21567
+ sessionFiles: {
21568
+ capability: this.sessionFileCapability,
21569
+ items: [...this.sessions.values()].sort(newestFirst).slice(0, this.request.recentSessionFilesTopK)
21570
+ },
21571
+ recentProjects: [...this.projects.values()].sort(newestFirst).slice(0, this.request.recentProjectsTopK)
21572
+ };
21573
+ }
21574
+ }
21575
+ function sanitizeRecentContextData(value, request) {
21576
+ if (!value || typeof value !== "object" || Array.isArray(value))
21577
+ return null;
21578
+ const candidate = value;
21579
+ if (!candidate.sessionFiles || typeof candidate.sessionFiles !== "object" || Array.isArray(candidate.sessionFiles)) {
21580
+ return null;
21581
+ }
21582
+ const sessionFiles = candidate.sessionFiles;
21583
+ const capability = sessionFiles.capability;
21584
+ if (capability !== "supported" && capability !== "unavailable" || !Array.isArray(sessionFiles.items)) {
21585
+ return null;
21586
+ }
21587
+ if (!Array.isArray(candidate.recentProjects))
21588
+ return null;
21589
+ const collector = new RecentContextCollector(request, capability);
21590
+ if (capability === "supported") {
21591
+ for (const item of sessionFiles.items) {
21592
+ if (!item || typeof item !== "object" || Array.isArray(item))
21593
+ continue;
21594
+ const record2 = item;
21595
+ collector.add({
21596
+ sessionFilePath: record2.sessionFilePath,
21597
+ projectPath: record2.projectPath,
21598
+ modifiedAt: record2.modifiedAt
21599
+ }, "session");
21600
+ }
21601
+ }
21602
+ for (const item of candidate.recentProjects) {
21603
+ if (!item || typeof item !== "object" || Array.isArray(item))
21604
+ continue;
21605
+ const record2 = item;
21606
+ collector.add({ projectPath: record2.projectPath, modifiedAt: record2.modifiedAt }, "project");
21607
+ }
21608
+ return collector.result();
21609
+ }
21610
+
21611
+ // agent-driver/dist/adapters/claude/recent-context.js
21612
+ async function readClaudeProjectPath(filePath) {
21613
+ const input = createReadStream2(filePath);
21614
+ const lines = createInterface({ input, crlfDelay: Infinity });
21615
+ try {
21616
+ for await (const line of lines) {
21617
+ let record2;
21618
+ try {
21619
+ record2 = JSON.parse(line);
21620
+ } catch {
21621
+ continue;
21622
+ }
21623
+ if (!record2 || typeof record2 !== "object")
21624
+ continue;
21625
+ const cwd = record2.cwd;
21626
+ if (typeof cwd === "string" && path7.isAbsolute(cwd))
21627
+ return cwd;
21628
+ }
21629
+ return null;
21630
+ } catch (error51) {
21631
+ if (isMissingPathError(error51))
21632
+ return null;
21633
+ throw error51;
21634
+ } finally {
21635
+ lines.close();
21636
+ input.destroy();
21637
+ }
21638
+ }
21639
+ async function discoverClaudeRecentContext(request, dependencies = {}) {
21640
+ const collector = new RecentContextCollector(request, "supported");
21641
+ if (collector.satisfied)
21642
+ return collector.result();
21643
+ const projectsRoot = path7.resolve(dependencies.projectsRoot ?? path7.join(process.env.CLAUDE_CONFIG_DIR || path7.join(homedir(), ".claude"), "projects"));
21644
+ const readProjectPath = dependencies.readProjectPath ?? readClaudeProjectPath;
21645
+ const candidates = await collectJsonlFileCandidates(projectsRoot, {
21646
+ includeRootFiles: false,
21647
+ maxDepth: 1,
21648
+ readDirectory: dependencies.readDirectory,
21649
+ statPath: dependencies.statPath
21650
+ });
21651
+ candidates.sort((left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime());
21652
+ for (const candidate of candidates) {
21653
+ const projectPath = await readProjectPath(candidate.filePath);
21654
+ if (!projectPath)
21655
+ continue;
21656
+ collector.add({
21657
+ sessionFilePath: candidate.filePath,
21658
+ projectPath,
21659
+ modifiedAt: candidate.modifiedAt
21660
+ });
21661
+ if (collector.satisfied)
21662
+ break;
21663
+ }
21664
+ return collector.result();
21665
+ }
21666
+
21208
21667
  // agent-driver/dist/adapters/claude/index.js
21209
21668
  var CLAUDE_MODEL_CATALOG = {
21210
21669
  updateMode: "unsupported",
@@ -21226,6 +21685,9 @@ class ClaudeDriver {
21226
21685
  turnProtocol = new ClaudeTurnProtocol;
21227
21686
  eventNormalizer = new ClaudeEventNormalizer(this.turnProtocol);
21228
21687
  pendingInterrupt;
21688
+ discoverRecentContext(request) {
21689
+ return discoverClaudeRecentContext(request);
21690
+ }
21229
21691
  beginTurn() {
21230
21692
  this.pendingInterrupt = undefined;
21231
21693
  const receipt = this.turnProtocol.beginTurn();
@@ -21489,16 +21951,16 @@ function normalizeFileChangeInput(item) {
21489
21951
  for (const candidate of changePaths) {
21490
21952
  if (typeof candidate !== "string")
21491
21953
  continue;
21492
- const path6 = candidate.trim();
21493
- if (!path6 || seen.has(path6))
21954
+ const path8 = candidate.trim();
21955
+ if (!path8 || seen.has(path8))
21494
21956
  continue;
21495
- seen.add(path6);
21496
- paths.push(path6);
21957
+ seen.add(path8);
21958
+ paths.push(path8);
21497
21959
  }
21498
21960
  if (paths.length === 0 && typeof item?.path === "string") {
21499
- const path6 = item.path.trim();
21500
- if (path6)
21501
- paths.push(path6);
21961
+ const path8 = item.path.trim();
21962
+ if (path8)
21963
+ paths.push(path8);
21502
21964
  }
21503
21965
  return paths.length > 0 ? { path: paths.join(", ") } : {};
21504
21966
  }
@@ -21867,7 +22329,7 @@ class CodexEventNormalizer {
21867
22329
 
21868
22330
  // agent-driver/dist/adapters/codex/home.js
21869
22331
  import * as os from "os";
21870
- import * as path6 from "path";
22332
+ import * as path8 from "path";
21871
22333
  function readConfiguredCodexHome(env) {
21872
22334
  const raw = env.CODEX_HOME;
21873
22335
  return typeof raw === "string" && raw.trim().length > 0 ? raw : null;
@@ -21875,8 +22337,8 @@ function readConfiguredCodexHome(env) {
21875
22337
  function resolveCodexHomeRootFromEnv(env = process.env, opts = {}) {
21876
22338
  const raw = readConfiguredCodexHome(env);
21877
22339
  if (raw)
21878
- return path6.resolve(opts.cwd ?? process.cwd(), raw);
21879
- return path6.join(opts.defaultHomeDir ?? os.homedir(), ".codex");
22340
+ return path8.resolve(opts.cwd ?? process.cwd(), raw);
22341
+ return path8.join(opts.defaultHomeDir ?? os.homedir(), ".codex");
21880
22342
  }
21881
22343
 
21882
22344
  // agent-driver/dist/internal/errors.js
@@ -21969,6 +22431,49 @@ function parsePiModelCatalog(values) {
21969
22431
  return catalogFromIds(ids);
21970
22432
  }
21971
22433
 
22434
+ // agent-driver/dist/adapters/codex/recent-context.js
22435
+ import path9 from "node:path";
22436
+ function isChildSession(payload) {
22437
+ if (payload.parentThreadId != null || payload.parent_thread_id != null)
22438
+ return true;
22439
+ const source = payload.source;
22440
+ if (typeof source === "string")
22441
+ return source.toLowerCase().startsWith("subagent");
22442
+ const sourceRecord = asRecord(source);
22443
+ return sourceRecord != null && (("subagent" in sourceRecord) || ("subAgent" in sourceRecord));
22444
+ }
22445
+ async function discoverCodexRecentContext(request, dependencies = {}) {
22446
+ const collector = new RecentContextCollector(request, "supported");
22447
+ if (collector.satisfied)
22448
+ return collector.result();
22449
+ const sessionsRoot = path9.resolve(dependencies.sessionsRoot ?? path9.join(resolveCodexHomeRootFromEnv(), "sessions"));
22450
+ const readHeader = dependencies.readHeader ?? readFirstLine;
22451
+ const candidates = await collectJsonlFileCandidates(sessionsRoot, {
22452
+ readDirectory: dependencies.readDirectory,
22453
+ statPath: dependencies.statPath
22454
+ });
22455
+ candidates.sort((left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime());
22456
+ for (const candidate of candidates) {
22457
+ const line = await readHeader(candidate.filePath);
22458
+ if (!line)
22459
+ continue;
22460
+ const header = tryParseJsonRecord(line);
22461
+ if (!header)
22462
+ continue;
22463
+ const payload = asRecord(header.payload);
22464
+ if (header.type !== "session_meta" || !payload || isChildSession(payload))
22465
+ continue;
22466
+ collector.add({
22467
+ sessionFilePath: candidate.filePath,
22468
+ projectPath: payload.cwd,
22469
+ modifiedAt: candidate.modifiedAt
22470
+ });
22471
+ if (collector.satisfied)
22472
+ break;
22473
+ }
22474
+ return collector.result();
22475
+ }
22476
+
21972
22477
  // agent-driver/dist/adapters/codex/index.js
21973
22478
  var SETTINGS_UPDATE_TIMEOUT_MS = 5000;
21974
22479
  var MODEL_LIST_TIMEOUT_MS = 5000;
@@ -21997,6 +22502,9 @@ class CodexDriver {
21997
22502
  eventNormalizer = new CodexEventNormalizer;
21998
22503
  pendingAccountReadRequestIds = new Set;
21999
22504
  requestId = 0;
22505
+ discoverRecentContext(request) {
22506
+ return discoverCodexRecentContext(request);
22507
+ }
22000
22508
  codexHomeRoot = null;
22001
22509
  proc = null;
22002
22510
  pendingInitialPrompt = null;
@@ -23173,6 +23681,196 @@ class CursorAcpLane {
23173
23681
  }
23174
23682
  }
23175
23683
 
23684
+ // agent-driver/dist/internal/discovery-process.js
23685
+ import { StringDecoder } from "node:string_decoder";
23686
+ function toBuffer(chunk2) {
23687
+ if (Buffer.isBuffer(chunk2))
23688
+ return chunk2;
23689
+ if (chunk2 instanceof Uint8Array)
23690
+ return Buffer.from(chunk2.buffer, chunk2.byteOffset, chunk2.byteLength);
23691
+ return Buffer.from(String(chunk2));
23692
+ }
23693
+ async function cleanupProcess(process3, label) {
23694
+ if (process3.pid)
23695
+ await killProcessTree(process3.pid, { graceMs: 250 });
23696
+ else if (process3.exitCode === null && process3.signalCode === null && !process3.kill("SIGTERM")) {
23697
+ throw new Error(`${label} discovery cleanup failed`);
23698
+ }
23699
+ }
23700
+ function onStream(stream, event, listener) {
23701
+ stream?.on?.(event, listener);
23702
+ }
23703
+ function runBoundedDiscoveryProcess(options) {
23704
+ return new Promise((resolve2, reject) => {
23705
+ const decoder = new StringDecoder("utf8");
23706
+ let settled = false;
23707
+ let decoderEnded = false;
23708
+ let outputBytes = 0;
23709
+ const settle = (result, error51) => {
23710
+ if (settled)
23711
+ return;
23712
+ settled = true;
23713
+ clearTimeout(timer);
23714
+ if (!decoderEnded)
23715
+ decoder.end();
23716
+ 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`)));
23717
+ };
23718
+ const control = {
23719
+ get outputBytes() {
23720
+ return outputBytes;
23721
+ },
23722
+ finish: (result) => settle(result),
23723
+ fail: (message2) => settle(undefined, new Error(message2)),
23724
+ flushStdout: () => {
23725
+ if (settled || decoderEnded)
23726
+ return;
23727
+ decoderEnded = true;
23728
+ options.onStdout(decoder.end(), true, control);
23729
+ },
23730
+ write: (line) => {
23731
+ const stdin = options.process.stdin;
23732
+ if (!stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false) {
23733
+ return control.fail(`${options.label} discovery transport is unavailable`);
23734
+ }
23735
+ try {
23736
+ stdin.write(line);
23737
+ } catch {
23738
+ control.fail(`${options.label} discovery transport write failed`);
23739
+ }
23740
+ }
23741
+ };
23742
+ const addBytes = (chunk2, decode3) => {
23743
+ if (settled)
23744
+ return;
23745
+ const bytes = toBuffer(chunk2);
23746
+ outputBytes += bytes.byteLength;
23747
+ if (outputBytes > options.outputMaxBytes) {
23748
+ control.fail(`${options.label} discovery output exceeded its bound`);
23749
+ } else if (decode3)
23750
+ options.onStdout(decoder.write(bytes), false, control);
23751
+ };
23752
+ const timer = setTimeout(() => control.fail(`${options.label} discovery timed out`), Math.max(1, options.timeoutMs));
23753
+ timer.unref?.();
23754
+ options.process.stdout?.on("data", (chunk2) => addBytes(chunk2, true));
23755
+ options.process.stderr?.on("data", (chunk2) => addBytes(chunk2, false));
23756
+ onStream(options.process.stdout, "end", control.flushStdout);
23757
+ for (const stream of [options.process.stdin, options.process.stdout, options.process.stderr]) {
23758
+ onStream(stream, "error", () => control.fail(`${options.label} discovery transport failed`));
23759
+ }
23760
+ options.process.on("error", () => control.fail(`${options.label} discovery process failed`));
23761
+ options.process.on(options.exitEvent, (code, signal) => options.onExit(code, signal, control));
23762
+ options.onStart?.(control);
23763
+ });
23764
+ }
23765
+
23766
+ // agent-driver/dist/adapters/cursor/recent-context.js
23767
+ var ACP_PROTOCOL_VERSION3 = 1;
23768
+ var AUTH_METHOD_ID3 = "cursor_login";
23769
+ var CURSOR_DISCOVERY_TIMEOUT_MS = 30000;
23770
+ var CURSOR_DISCOVERY_OUTPUT_MAX_BYTES = 4 * 1024 * 1024;
23771
+ async function discoverCursorRecentContext(request, dependencies = {}) {
23772
+ const collector = new RecentContextCollector(request, "unavailable");
23773
+ if (collector.satisfied)
23774
+ return collector.result();
23775
+ const spec = resolveSpawnSpec("cursor-agent", ["acp"], request.command);
23776
+ const processHandle = (dependencies.spawn ?? spawnAgentProcess)(spec.command, spec.args, {
23777
+ cwd: dependencies.cwd ?? process.cwd(),
23778
+ env: { ...process.env, CI: "1" },
23779
+ shell: spec.shell
23780
+ });
23781
+ let buffer = "";
23782
+ let requestId = 0;
23783
+ let expectedId = 0;
23784
+ let expectedMethod = "";
23785
+ const seenCursors = new Set;
23786
+ const requestRpc = (method, params, control) => {
23787
+ expectedId = ++requestId;
23788
+ expectedMethod = method;
23789
+ control.write(`${jsonRpcRequest(method, params, expectedId)}
23790
+ `);
23791
+ };
23792
+ const requestPage = (control, cursor) => requestRpc("session/list", cursor ? { cursor } : {}, control);
23793
+ const onLine = (line, control) => {
23794
+ const message2 = asRecord(tryParseJsonLine(line));
23795
+ if (!message2 || message2.id !== expectedId)
23796
+ return;
23797
+ if (message2.error !== undefined)
23798
+ return control.fail("Cursor discovery request failed");
23799
+ const result = asRecord(message2.result);
23800
+ if (!result)
23801
+ return control.fail("Cursor discovery returned an invalid response");
23802
+ if (expectedMethod === "initialize") {
23803
+ if (result.protocolVersion !== ACP_PROTOCOL_VERSION3) {
23804
+ return control.fail("Cursor discovery protocol is incompatible");
23805
+ }
23806
+ const capabilities = asRecord(result.agentCapabilities);
23807
+ const sessionCapabilities = asRecord(capabilities?.sessionCapabilities);
23808
+ if (sessionCapabilities?.list !== true && !asRecord(sessionCapabilities?.list)) {
23809
+ return control.fail("Cursor session listing is unavailable");
23810
+ }
23811
+ const authMethods = Array.isArray(result.authMethods) ? result.authMethods : [];
23812
+ if (!authMethods.some((method) => asRecord(method)?.id === AUTH_METHOD_ID3)) {
23813
+ return control.fail("Cursor discovery authentication is unavailable");
23814
+ }
23815
+ requestRpc("authenticate", { methodId: AUTH_METHOD_ID3 }, control);
23816
+ return;
23817
+ }
23818
+ if (expectedMethod === "authenticate") {
23819
+ requestPage(control);
23820
+ return;
23821
+ }
23822
+ if (expectedMethod !== "session/list")
23823
+ return control.fail("Cursor discovery state is invalid");
23824
+ const sessions = Array.isArray(result.sessions) ? result.sessions : Array.isArray(result.data) ? result.data : [];
23825
+ for (const value of sessions) {
23826
+ const session2 = asRecord(value);
23827
+ if (!session2)
23828
+ continue;
23829
+ collector.add({ projectPath: session2.cwd, modifiedAt: session2.updatedAt });
23830
+ if (collector.satisfied)
23831
+ return control.finish(collector.result());
23832
+ }
23833
+ const nextCursor = typeof result.nextCursor === "string" && result.nextCursor ? result.nextCursor : undefined;
23834
+ if (!nextCursor)
23835
+ return control.finish(collector.result());
23836
+ if (seenCursors.has(nextCursor))
23837
+ return control.fail("Cursor discovery cursor repeated");
23838
+ seenCursors.add(nextCursor);
23839
+ requestPage(control, nextCursor);
23840
+ };
23841
+ return runBoundedDiscoveryProcess({
23842
+ process: processHandle,
23843
+ label: "Cursor",
23844
+ timeoutMs: dependencies.timeoutMs ?? CURSOR_DISCOVERY_TIMEOUT_MS,
23845
+ outputMaxBytes: dependencies.outputMaxBytes ?? CURSOR_DISCOVERY_OUTPUT_MAX_BYTES,
23846
+ cleanup: dependencies.cleanup,
23847
+ exitEvent: "exit",
23848
+ onStdout: (text2, final, control) => {
23849
+ buffer += text2;
23850
+ const lines = buffer.split(`
23851
+ `);
23852
+ buffer = lines.pop() ?? "";
23853
+ for (const line of lines)
23854
+ if (line.trim())
23855
+ onLine(line, control);
23856
+ if (final && buffer.trim()) {
23857
+ const line = buffer;
23858
+ buffer = "";
23859
+ onLine(line, control);
23860
+ }
23861
+ },
23862
+ onExit: (_code, _signal, control) => control.fail("Cursor discovery process exited early"),
23863
+ onStart: (control) => requestRpc("initialize", {
23864
+ protocolVersion: ACP_PROTOCOL_VERSION3,
23865
+ clientCapabilities: {
23866
+ fs: { readTextFile: false, writeTextFile: false },
23867
+ terminal: false
23868
+ },
23869
+ clientInfo: { name: "alook-agent-driver-discovery", version: "0.1.31" }
23870
+ }, control)
23871
+ });
23872
+ }
23873
+
23176
23874
  // agent-driver/dist/adapters/cursor/index.js
23177
23875
  class CursorDriver {
23178
23876
  catalogProbe;
@@ -23184,6 +23882,9 @@ class CursorDriver {
23184
23882
  wakeStart: "immediate",
23185
23883
  terminalOwnership: "transport_request"
23186
23884
  };
23885
+ discoverRecentContext(request) {
23886
+ return discoverCursorRecentContext(request);
23887
+ }
23187
23888
  constructor(catalogProbe = probeCursorAcpCatalog) {
23188
23889
  this.catalogProbe = catalogProbe;
23189
23890
  }
@@ -23678,7 +24379,7 @@ class OpenCodeServiceLane {
23678
24379
  "/api/session/{sessionID}/permission/{requestID}/reply",
23679
24380
  "/api/event"
23680
24381
  ];
23681
- if (!paths || required2.some((path7) => !record4(paths[path7]))) {
24382
+ if (!paths || required2.some((path10) => !record4(paths[path10]))) {
23682
24383
  throw new OpenCodeIncompatibleError("Installed OpenCode service is missing required v2 session capabilities");
23683
24384
  }
23684
24385
  }
@@ -23736,8 +24437,8 @@ class OpenCodeServiceLane {
23736
24437
  const controller = new AbortController;
23737
24438
  this.durableAbort = controller;
23738
24439
  try {
23739
- const path7 = `/api/session/${encodeURIComponent(this.sessionId)}/event?after=${this.lastDurableSeq}`;
23740
- const response = await this.openStream(path7, controller, "durable event stream");
24440
+ const path10 = `/api/session/${encodeURIComponent(this.sessionId)}/event?after=${this.lastDurableSeq}`;
24441
+ const response = await this.openStream(path10, controller, "durable event stream");
23741
24442
  await this.catchUpHistory(true);
23742
24443
  if (!this.isIdentity(identity))
23743
24444
  return;
@@ -23811,12 +24512,12 @@ class OpenCodeServiceLane {
23811
24512
  return;
23812
24513
  this.protocolFailure(`OpenCode ${kind} stream stopped unexpectedly`, error51);
23813
24514
  }
23814
- async openStream(path7, lifecycle, operation) {
24515
+ async openStream(path10, lifecycle, operation) {
23815
24516
  const deadline = new AbortController;
23816
24517
  const timeout = setTimeout(() => deadline.abort(), this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS);
23817
24518
  timeout.unref?.();
23818
24519
  try {
23819
- const response = await this.fetchFn(`${this.baseUrl}${path7}`, {
24520
+ const response = await this.fetchFn(`${this.baseUrl}${path10}`, {
23820
24521
  method: "GET",
23821
24522
  headers: this.headers({ accept: "text/event-stream" }),
23822
24523
  signal: AbortSignal.any([lifecycle.signal, deadline.signal])
@@ -24243,8 +24944,8 @@ class OpenCodeServiceLane {
24243
24944
  turnOwner: root.receipt
24244
24945
  });
24245
24946
  }
24246
- async requestNoContent(path7, method, body, operation) {
24247
- const response = await this.fetchWithTimeout(path7, {
24947
+ async requestNoContent(path10, method, body, operation) {
24948
+ const response = await this.fetchWithTimeout(path10, {
24248
24949
  method,
24249
24950
  ...body ? {
24250
24951
  headers: { "content-type": "application/json" },
@@ -24254,7 +24955,7 @@ class OpenCodeServiceLane {
24254
24955
  if (!response.ok)
24255
24956
  throw new OpenCodeHttpError(response.status, operation);
24256
24957
  }
24257
- async fetchWithTimeout(path7, init, operation, timeoutMs = this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS) {
24958
+ async fetchWithTimeout(path10, init, operation, timeoutMs = this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS) {
24258
24959
  if (this.stopping)
24259
24960
  throw new Error("OpenCode service lane is stopping");
24260
24961
  const controller = new AbortController;
@@ -24262,7 +24963,7 @@ class OpenCodeServiceLane {
24262
24963
  const timer = setTimeout(() => controller.abort(), timeoutMs);
24263
24964
  timer.unref?.();
24264
24965
  try {
24265
- return await this.fetchFn(`${this.baseUrl}${path7}`, {
24966
+ return await this.fetchFn(`${this.baseUrl}${path10}`, {
24266
24967
  ...init,
24267
24968
  headers: this.headers(init.headers),
24268
24969
  signal: controller.signal
@@ -24274,7 +24975,7 @@ class OpenCodeServiceLane {
24274
24975
  this.requestControllers.delete(controller);
24275
24976
  }
24276
24977
  }
24277
- async fetchJsonWithTimeout(path7, init, operation, timeoutMs = this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS) {
24978
+ async fetchJsonWithTimeout(path10, init, operation, timeoutMs = this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS) {
24278
24979
  if (this.stopping)
24279
24980
  throw new OpenCodeStoppedError("OpenCode service lane is stopping");
24280
24981
  const controller = new AbortController;
@@ -24286,7 +24987,7 @@ class OpenCodeServiceLane {
24286
24987
  }, timeoutMs);
24287
24988
  timer.unref?.();
24288
24989
  try {
24289
- const response = await this.fetchFn(`${this.baseUrl}${path7}`, {
24990
+ const response = await this.fetchFn(`${this.baseUrl}${path10}`, {
24290
24991
  ...init,
24291
24992
  headers: this.headers(init.headers),
24292
24993
  signal: controller.signal
@@ -24379,6 +25080,75 @@ class OpenCodeServiceLane {
24379
25080
  }
24380
25081
  }
24381
25082
 
25083
+ // agent-driver/dist/adapters/opencode/recent-context.js
25084
+ var OPENCODE_DISCOVERY_TIMEOUT_MS = 15000;
25085
+ var OPENCODE_DISCOVERY_OUTPUT_MAX_BYTES = 4 * 1024 * 1024;
25086
+ function collectCommandOutput(command, args, shell, dependencies, timeoutMs, outputMaxBytes) {
25087
+ const processHandle = (dependencies.spawn ?? spawnAgentProcess)(command, args, {
25088
+ cwd: dependencies.cwd ?? process.cwd(),
25089
+ env: { ...process.env, CI: "1" },
25090
+ shell,
25091
+ stdin: "ignore"
25092
+ });
25093
+ let output = "";
25094
+ return runBoundedDiscoveryProcess({
25095
+ process: processHandle,
25096
+ label: "OpenCode",
25097
+ timeoutMs,
25098
+ outputMaxBytes,
25099
+ cleanup: dependencies.cleanup,
25100
+ exitEvent: "close",
25101
+ onStdout: (text2) => {
25102
+ output += text2;
25103
+ },
25104
+ onExit: (code, _signal, control) => {
25105
+ if (code !== 0)
25106
+ return control.fail("OpenCode session listing failed");
25107
+ control.flushStdout();
25108
+ control.finish({ output, outputBytes: control.outputBytes });
25109
+ }
25110
+ });
25111
+ }
25112
+ async function discoverOpenCodeRecentContext(request, dependencies = {}) {
25113
+ const collector = new RecentContextCollector(request, "unavailable");
25114
+ if (collector.satisfied)
25115
+ return collector.result();
25116
+ const startedAt = Date.now();
25117
+ const timeoutMs = dependencies.timeoutMs ?? OPENCODE_DISCOVERY_TIMEOUT_MS;
25118
+ let remainingOutputBytes = dependencies.outputMaxBytes ?? OPENCODE_DISCOVERY_OUTPUT_MAX_BYTES;
25119
+ let maxCount = Math.max(1, Math.min(Number.MAX_SAFE_INTEGER, request.recentProjectsTopK * 10));
25120
+ while (!collector.satisfied) {
25121
+ const remainingTimeoutMs = timeoutMs - (Date.now() - startedAt);
25122
+ if (remainingTimeoutMs <= 0)
25123
+ throw new Error("OpenCode discovery timed out");
25124
+ const spec = resolveSpawnSpec("opencode", ["session", "list", "--format", "json", "--max-count", String(maxCount), "--pure"], request.command);
25125
+ const commandOutput = await collectCommandOutput(spec.command, spec.args, spec.shell, dependencies, remainingTimeoutMs, remainingOutputBytes);
25126
+ remainingOutputBytes -= commandOutput.outputBytes;
25127
+ let parsed;
25128
+ try {
25129
+ parsed = JSON.parse(commandOutput.output);
25130
+ } catch {
25131
+ throw new Error("OpenCode session listing returned invalid JSON");
25132
+ }
25133
+ if (!Array.isArray(parsed))
25134
+ throw new Error("OpenCode session listing returned an invalid response");
25135
+ for (const value of parsed) {
25136
+ const session2 = asRecord(value);
25137
+ if (!session2)
25138
+ continue;
25139
+ const modifiedAt = session2.updated ?? session2.updatedAt;
25140
+ collector.add({ projectPath: session2.directory, modifiedAt });
25141
+ }
25142
+ if (collector.satisfied || parsed.length < maxCount)
25143
+ break;
25144
+ const nextMaxCount = Math.min(Number.MAX_SAFE_INTEGER, maxCount * 2);
25145
+ if (nextMaxCount === maxCount)
25146
+ throw new Error("OpenCode session listing could not prove the requested Top-K");
25147
+ maxCount = nextMaxCount;
25148
+ }
25149
+ return collector.result();
25150
+ }
25151
+
24382
25152
  // agent-driver/dist/adapters/opencode/index.js
24383
25153
  function createOpenCodeMessageId() {
24384
25154
  return `msg_${randomBytes3(16).toString("hex")}`;
@@ -24397,6 +25167,9 @@ class OpenCodeDriver {
24397
25167
  constructor(outputProbe = probeCommandOutput) {
24398
25168
  this.outputProbe = outputProbe;
24399
25169
  }
25170
+ discoverRecentContext(request) {
25171
+ return discoverOpenCodeRecentContext(request);
25172
+ }
24400
25173
  probe(command) {
24401
25174
  const result = probeCliRuntime("opencode", {}, command);
24402
25175
  if (result.status !== "healthy")
@@ -24443,8 +25216,8 @@ class OpenCodeDriver {
24443
25216
  // agent-driver/dist/adapters/pi/index.js
24444
25217
  import { createRequire as createRequire2 } from "module";
24445
25218
  import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync3, realpathSync } from "fs";
24446
- import { homedir as homedir2 } from "os";
24447
- import * as path8 from "path";
25219
+ import { homedir as homedir4 } from "os";
25220
+ import * as path12 from "path";
24448
25221
 
24449
25222
  // agent-driver/dist/controller/sdk-host.js
24450
25223
  import { EventEmitter as EventEmitter4 } from "events";
@@ -24559,7 +25332,7 @@ class SdkLane {
24559
25332
 
24560
25333
  // agent-driver/dist/adapters/pi/sessionDeps.js
24561
25334
  import { readFileSync as readFileSync2 } from "fs";
24562
- import * as path7 from "path";
25335
+ import * as path10 from "path";
24563
25336
  import { pathToFileURL } from "url";
24564
25337
  var PI_SDK_PACKAGE_NAME = "@earendil-works/pi-coding-agent";
24565
25338
  var cachedSdkPromise = null;
@@ -24568,9 +25341,9 @@ async function importPiSdkFromGlobalInstall() {
24568
25341
  if (!dir) {
24569
25342
  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`);
24570
25343
  }
24571
- const pkg = JSON.parse(readFileSync2(path7.join(dir, "package.json"), "utf-8"));
25344
+ const pkg = JSON.parse(readFileSync2(path10.join(dir, "package.json"), "utf-8"));
24572
25345
  const entry = pkg.exports?.["."]?.import ?? pkg.main ?? "./dist/index.js";
24573
- const entryPath = path7.join(dir, entry);
25346
+ const entryPath = path10.join(dir, entry);
24574
25347
  const barrel = await import(pathToFileURL(entryPath).href);
24575
25348
  return withSessionDirHelper(barrel, entryPath);
24576
25349
  }
@@ -24578,7 +25351,7 @@ async function withSessionDirHelper(barrel, entryPath) {
24578
25351
  if (typeof barrel.getDefaultSessionDir === "function")
24579
25352
  return barrel;
24580
25353
  try {
24581
- const deepPath = path7.join(path7.dirname(entryPath), "core", "session-manager.js");
25354
+ const deepPath = path10.join(path10.dirname(entryPath), "core", "session-manager.js");
24582
25355
  const deep = await import(pathToFileURL(deepPath).href);
24583
25356
  if (typeof deep.getDefaultSessionDir !== "function")
24584
25357
  return barrel;
@@ -24658,6 +25431,51 @@ function createPiSessionDependencies(ctx, loadSdk = loadPiSdkModule) {
24658
25431
  };
24659
25432
  }
24660
25433
 
25434
+ // agent-driver/dist/adapters/pi/recent-context.js
25435
+ import { homedir as homedir3 } from "node:os";
25436
+ import path11 from "node:path";
25437
+ function expandTildePath(value) {
25438
+ if (value === "~")
25439
+ return homedir3();
25440
+ if (value.startsWith("~/"))
25441
+ return path11.join(homedir3(), value.slice(2));
25442
+ return value;
25443
+ }
25444
+ async function discoverPiRecentContext(request, dependencies = {}) {
25445
+ const collector = new RecentContextCollector(request, "supported");
25446
+ if (collector.satisfied)
25447
+ return collector.result();
25448
+ const customSessionDirectory = process.env.PI_CODING_AGENT_SESSION_DIR;
25449
+ const sessionsRoot = path11.resolve(expandTildePath(dependencies.sessionsRoot ?? customSessionDirectory ?? path11.join(process.env.PI_CODING_AGENT_DIR || path11.join(homedir3(), ".pi", "agent"), "sessions")));
25450
+ const scanDirectSessions = dependencies.sessionsRoot == null && customSessionDirectory != null;
25451
+ const readHeader = dependencies.readHeader ?? readFirstLine;
25452
+ const candidates = await collectJsonlFileCandidates(sessionsRoot, {
25453
+ includeRootFiles: scanDirectSessions,
25454
+ maxDepth: 1,
25455
+ readDirectory: dependencies.readDirectory,
25456
+ statPath: dependencies.statPath
25457
+ });
25458
+ candidates.sort((left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime());
25459
+ for (const candidate of candidates) {
25460
+ const line = await readHeader(candidate.filePath);
25461
+ if (!line)
25462
+ continue;
25463
+ const header = tryParseJsonRecord(line);
25464
+ if (!header)
25465
+ continue;
25466
+ if (header.type !== "session" || header.parentSession != null)
25467
+ continue;
25468
+ collector.add({
25469
+ sessionFilePath: candidate.filePath,
25470
+ projectPath: header.cwd,
25471
+ modifiedAt: candidate.modifiedAt
25472
+ });
25473
+ if (collector.satisfied)
25474
+ break;
25475
+ }
25476
+ return collector.result();
25477
+ }
25478
+
24661
25479
  // agent-driver/dist/adapters/pi/index.js
24662
25480
  var PI_SDK_PACKAGE_NAME2 = "@earendil-works/pi-coding-agent";
24663
25481
  var PI_MODEL_PROBE_TIMEOUT_MS = 5000;
@@ -24676,15 +25494,15 @@ function resolvePiSdkPackageDir(deps = {}) {
24676
25494
  if (!binPath)
24677
25495
  return;
24678
25496
  try {
24679
- let dir = path8.dirname(realpathSync(binPath));
25497
+ let dir = path12.dirname(realpathSync(binPath));
24680
25498
  const MAX_DEPTH = 8;
24681
25499
  for (let i = 0;i < MAX_DEPTH; i++) {
24682
- if (isPiSdkPackageJson(path8.join(dir, "package.json")))
25500
+ if (isPiSdkPackageJson(path12.join(dir, "package.json")))
24683
25501
  return dir;
24684
- const siblingDir = path8.join(dir, "node_modules", PI_SDK_PACKAGE_NAME2);
24685
- if (isPiSdkPackageJson(path8.join(siblingDir, "package.json")))
25502
+ const siblingDir = path12.join(dir, "node_modules", PI_SDK_PACKAGE_NAME2);
25503
+ if (isPiSdkPackageJson(path12.join(siblingDir, "package.json")))
24686
25504
  return siblingDir;
24687
- const parent = path8.dirname(dir);
25505
+ const parent = path12.dirname(dir);
24688
25506
  if (parent === dir)
24689
25507
  break;
24690
25508
  dir = parent;
@@ -24701,21 +25519,21 @@ function findPiSessionFile(sessionDir, sessionId) {
24701
25519
  }
24702
25520
  const suffix = `_${sessionId}.jsonl`;
24703
25521
  const match = entries.find((entry) => entry.endsWith(suffix));
24704
- return match ? path8.join(sessionDir, match) : null;
25522
+ return match ? path12.join(sessionDir, match) : null;
24705
25523
  }
24706
25524
  function resolvePiSessionDir(sdk, cwd) {
24707
25525
  if (typeof sdk.getDefaultSessionDir === "function")
24708
25526
  return sdk.getDefaultSessionDir(cwd);
24709
- const agentDir = typeof sdk.getAgentDir === "function" ? sdk.getAgentDir() : path8.join(homedir2(), ".pi", "agent");
24710
- const encoded = `--${path8.resolve(cwd).replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
24711
- return path8.join(agentDir, "sessions", encoded);
25527
+ const agentDir = typeof sdk.getAgentDir === "function" ? sdk.getAgentDir() : path12.join(homedir4(), ".pi", "agent");
25528
+ const encoded = `--${path12.resolve(cwd).replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
25529
+ return path12.join(agentDir, "sessions", encoded);
24712
25530
  }
24713
25531
  function resolvePiSdkVersionFromPath(deps = {}) {
24714
25532
  const dir = resolvePiSdkPackageDir(deps);
24715
25533
  if (!dir)
24716
25534
  return;
24717
25535
  try {
24718
- const pkg = JSON.parse(readFileSync3(path8.join(dir, "package.json"), "utf-8"));
25536
+ const pkg = JSON.parse(readFileSync3(path12.join(dir, "package.json"), "utf-8"));
24719
25537
  return pkg.version;
24720
25538
  } catch {
24721
25539
  return;
@@ -24819,6 +25637,9 @@ class PiDriver {
24819
25637
  };
24820
25638
  sessionId = null;
24821
25639
  terminalSequence = 0;
25640
+ discoverRecentContext(request) {
25641
+ return discoverPiRecentContext(request);
25642
+ }
24822
25643
  constructor(dependenciesFor = createPiSessionDependencies, loadSdk = loadPiSdkModule, readVersion = readPiSdkVersion) {
24823
25644
  this.dependenciesFor = dependenciesFor;
24824
25645
  this.loadSdk = loadSdk;
@@ -24964,6 +25785,9 @@ function assertAdapterCompatibility(registrationId, registeredCapabilities, adap
24964
25785
  if (typeof candidate[method] !== "function")
24965
25786
  throw new Error(`Adapter ${registrationId} is missing ${method}()`);
24966
25787
  }
25788
+ if (candidate.discoverRecentContext !== undefined && typeof candidate.discoverRecentContext !== "function") {
25789
+ throw new Error(`Adapter ${registrationId} has an invalid discoverRecentContext()`);
25790
+ }
24967
25791
  const instruction = candidate.instructionDelivery;
24968
25792
  if (!instruction || instruction.kind !== "native" && instruction.kind !== "workspace_file") {
24969
25793
  throw new Error(`Adapter ${registrationId} has an invalid instructionDelivery declaration`);
@@ -25185,8 +26009,8 @@ function ensureSymlinks(workDir, canonical = CANONICAL_FILE, aliases = SYMLINK_A
25185
26009
  continue;
25186
26010
  const aliasPath = join8(workDir, alias2);
25187
26011
  try {
25188
- const stat = lstatSync(aliasPath);
25189
- if (stat.isSymbolicLink()) {
26012
+ const stat2 = lstatSync(aliasPath);
26013
+ if (stat2.isSymbolicLink()) {
25190
26014
  const target2 = readlinkSync(aliasPath);
25191
26015
  if (target2 === canonical)
25192
26016
  continue;
@@ -25349,6 +26173,7 @@ class LogicalAgentSession {
25349
26173
  steeringDeliveries = new Set;
25350
26174
  laneAdmissionTail = Promise.resolve();
25351
26175
  laneAdmissionPending = 0;
26176
+ toolBoundaryOpen = true;
25352
26177
  toolBoundaryFlushDisabled = false;
25353
26178
  safeBoundaryFlush;
25354
26179
  safeBoundaryDelivery;
@@ -25629,6 +26454,8 @@ class LogicalAgentSession {
25629
26454
  this.turnError = undefined;
25630
26455
  this.interruptedTurnId = undefined;
25631
26456
  this.processTurnEnded = false;
26457
+ this.toolBoundaryOpen = true;
26458
+ this.toolBoundaryFlushDisabled = false;
25632
26459
  this.state = "starting";
25633
26460
  const generation = this.lifecycleGeneration;
25634
26461
  const text2 = messages.map((message2) => message2.text).join(`
@@ -25861,6 +26688,7 @@ class LogicalAgentSession {
25861
26688
  }
25862
26689
  if (!this.startToolUse(event.callId))
25863
26690
  return;
26691
+ this.toolBoundaryOpen = false;
25864
26692
  const startedCallId = this.toolCallId(event.callId);
25865
26693
  this.emit({
25866
26694
  type: "tool_started",
@@ -25877,6 +26705,7 @@ class LogicalAgentSession {
25877
26705
  }
25878
26706
  if (!this.finishToolUse(event.callId))
25879
26707
  return;
26708
+ this.toolBoundaryOpen = true;
25880
26709
  const finishedCallId = this.toolCallId(event.callId);
25881
26710
  this.emit({
25882
26711
  type: "tool_finished",
@@ -25884,7 +26713,7 @@ class LogicalAgentSession {
25884
26713
  ...finishedCallId ? { callId: finishedCallId } : {},
25885
26714
  name: event.name
25886
26715
  });
25887
- if (this.outstandingToolUseCount() === 0 && !this.toolBoundaryFlushDisabled)
26716
+ if (!this.toolBoundaryFlushDisabled)
25888
26717
  this.flushSafeBoundaryQueue();
25889
26718
  return;
25890
26719
  case "compaction_started":
@@ -26030,6 +26859,7 @@ class LogicalAgentSession {
26030
26859
  this.clearOutstandingToolUses();
26031
26860
  this.compacting = false;
26032
26861
  this.reviewing = false;
26862
+ this.toolBoundaryOpen = true;
26033
26863
  this.toolBoundaryFlushDisabled = false;
26034
26864
  this.state = "idle";
26035
26865
  if (this.adapter.execution.lifetime === "turn") {
@@ -26051,7 +26881,7 @@ class LogicalAgentSession {
26051
26881
  return this.safeBoundaryFlush;
26052
26882
  }
26053
26883
  canFlushSafeBoundaryQueue() {
26054
- 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;
26884
+ 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;
26055
26885
  }
26056
26886
  async drainSafeBoundaryQueue() {
26057
26887
  while (this.canFlushSafeBoundaryQueue()) {
@@ -26566,6 +27396,57 @@ function createAgentDriverSdkWithRegistry(options) {
26566
27396
  const registry2 = options.registry;
26567
27397
  return {
26568
27398
  backendIds: registry2.backendIds,
27399
+ async discoverRecentContext(input) {
27400
+ if (!isValidRecentContextTopK(input.recentSessionFilesTopK) || !isValidRecentContextTopK(input.recentProjectsTopK)) {
27401
+ return {
27402
+ ok: false,
27403
+ error: {
27404
+ category: "configuration",
27405
+ code: "invalid_recent_context_top_k",
27406
+ message: "Recent-context Top-K values must be non-negative safe integers",
27407
+ retryable: false
27408
+ }
27409
+ };
27410
+ }
27411
+ const registration = registry2.get(input.backend);
27412
+ try {
27413
+ assertRegistrationShape(registration);
27414
+ const adapter = registration.createAdapter();
27415
+ assertAdapterCompatibility(String(registration.id), registration.capabilities, adapter);
27416
+ if (!adapter.discoverRecentContext) {
27417
+ return {
27418
+ ok: false,
27419
+ error: {
27420
+ category: "configuration",
27421
+ code: "recent_context_discovery_unsupported",
27422
+ message: `Backend ${input.backend} does not support recent-context discovery`,
27423
+ retryable: false
27424
+ }
27425
+ };
27426
+ }
27427
+ const command = registration.capabilities.commandOverride ? input.command : undefined;
27428
+ const discovered = await adapter.discoverRecentContext({
27429
+ recentSessionFilesTopK: input.recentSessionFilesTopK,
27430
+ recentProjectsTopK: input.recentProjectsTopK,
27431
+ ...command ? { command } : {}
27432
+ });
27433
+ const sanitized = sanitizeRecentContextData(discovered, input);
27434
+ if (!sanitized)
27435
+ throw new Error(`Adapter ${input.backend} returned invalid recent-context data`);
27436
+ return { ok: true, ...sanitized };
27437
+ } catch (error51) {
27438
+ const contractInvalid = error51 instanceof Error && (error51.message.startsWith("Adapter ") || error51.message.startsWith("Agent backend registration "));
27439
+ return {
27440
+ ok: false,
27441
+ error: {
27442
+ category: contractInvalid ? "internal" : "runtime_unavailable",
27443
+ code: contractInvalid ? "adapter_contract_invalid" : "recent_context_discovery_failed",
27444
+ message: contractInvalid ? `Backend ${input.backend} adapter contract is invalid` : `Backend ${input.backend} recent-context discovery failed`,
27445
+ retryable: !contractInvalid
27446
+ }
27447
+ };
27448
+ }
27449
+ },
26569
27450
  async probe(input) {
26570
27451
  const registration = registry2.get(input.backend);
26571
27452
  const capabilities2 = registration.capabilities;
@@ -26704,22 +27585,22 @@ function listRuntimeIds() {
26704
27585
 
26705
27586
  // src/discovery.ts
26706
27587
  function resolveAlookCliPath(moduleDir) {
26707
- const thisDir = moduleDir ?? path9.dirname(fileURLToPath(import.meta.url));
26708
- const target2 = path9.basename(thisDir) === "dist" ? path9.resolve(thisDir, "cli", "index.js") : path9.resolve(thisDir, "..", "scripts", "alook-shim.mjs");
27588
+ const thisDir = moduleDir ?? path13.dirname(fileURLToPath(import.meta.url));
27589
+ const target2 = path13.basename(thisDir) === "dist" ? path13.resolve(thisDir, "cli", "index.js") : path13.resolve(thisDir, "..", "scripts", "alook-shim.mjs");
26709
27590
  return fs6.existsSync(target2) ? target2 : null;
26710
27591
  }
26711
27592
  function deriveCliFallbackCandidates(cliPath) {
26712
27593
  if (!cliPath)
26713
27594
  return [];
26714
- const normalized = cliPath.split(path9.sep).join("/");
27595
+ const normalized = cliPath.split(path13.sep).join("/");
26715
27596
  const marker = "/node_modules/";
26716
27597
  const idx = normalized.indexOf(marker);
26717
27598
  if (idx === -1)
26718
27599
  return [];
26719
27600
  const globalRoot = cliPath.slice(0, idx + marker.length - 1);
26720
- const tail = path9.join("dist", "cli", "index.js");
27601
+ const tail = path13.join("dist", "cli", "index.js");
26721
27602
  return [
26722
- path9.join(globalRoot, "@alook", "daemon", tail)
27603
+ path13.join(globalRoot, "@alook", "daemon", tail)
26723
27604
  ].filter((candidate) => candidate !== cliPath);
26724
27605
  }
26725
27606
  function resolveAlookCliPathWithFallback(primary) {
@@ -26861,11 +27742,11 @@ function readDaemonVersion() {
26861
27742
 
26862
27743
  // src/cli/daemonRunner.ts
26863
27744
  import * as fs11 from "node:fs";
26864
- import * as path12 from "node:path";
27745
+ import * as path16 from "node:path";
26865
27746
  import { WebSocket } from "ws";
26866
27747
 
26867
27748
  // src/daemon/createDaemon.ts
26868
- import { homedir as homedir5 } from "os";
27749
+ import { homedir as homedir7 } from "os";
26869
27750
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8 } from "node:fs";
26870
27751
 
26871
27752
  // src/util/rotatingFileSink.ts
@@ -26882,7 +27763,7 @@ import {
26882
27763
  statSync,
26883
27764
  unlinkSync as unlinkSync3
26884
27765
  } from "node:fs";
26885
- function createRotatingFileSink(path10, maxBytes, opts = {}) {
27766
+ function createRotatingFileSink(path14, maxBytes, opts = {}) {
26886
27767
  const report = (operation, error51) => {
26887
27768
  try {
26888
27769
  opts.onError?.({ operation, error: error51 });
@@ -26892,8 +27773,8 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26892
27773
  if (!existsSync6(filePath))
26893
27774
  return true;
26894
27775
  try {
26895
- const stat = lstatSync2(filePath);
26896
- if (!stat.isFile()) {
27776
+ const stat2 = lstatSync2(filePath);
27777
+ if (!stat2.isFile()) {
26897
27778
  if (opts.mode === undefined && !opts.hardMaxBytes)
26898
27779
  return true;
26899
27780
  report("unsafe_generation", new Error("log generation is not a regular file"));
@@ -26901,7 +27782,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26901
27782
  }
26902
27783
  if (opts.mode !== undefined)
26903
27784
  chmodSync(filePath, opts.mode);
26904
- if (opts.hardMaxBytes && maxBytes > 0 && stat.size > maxBytes) {
27785
+ if (opts.hardMaxBytes && maxBytes > 0 && stat2.size > maxBytes) {
26905
27786
  try {
26906
27787
  unlinkSync3(filePath);
26907
27788
  } catch (error51) {
@@ -26918,9 +27799,9 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26918
27799
  };
26919
27800
  const rotate = () => {
26920
27801
  try {
26921
- renameSync2(path10, `${path10}.1`);
27802
+ renameSync2(path14, `${path14}.1`);
26922
27803
  if (opts.mode !== undefined)
26923
- chmodSync(`${path10}.1`, opts.mode);
27804
+ chmodSync(`${path14}.1`, opts.mode);
26924
27805
  return true;
26925
27806
  } catch (error51) {
26926
27807
  report("rotate", error51);
@@ -26929,7 +27810,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26929
27810
  };
26930
27811
  const currentSize = () => {
26931
27812
  try {
26932
- return existsSync6(path10) ? statSync(path10).size : 0;
27813
+ return existsSync6(path14) ? statSync(path14).size : 0;
26933
27814
  } catch (error51) {
26934
27815
  report("stat", error51);
26935
27816
  return null;
@@ -26937,7 +27818,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26937
27818
  };
26938
27819
  const sink = {
26939
27820
  secure() {
26940
- return secureGeneration(`${path10}.1`) && secureGeneration(path10);
27821
+ return secureGeneration(`${path14}.1`) && secureGeneration(path14);
26941
27822
  },
26942
27823
  write(line) {
26943
27824
  try {
@@ -26957,7 +27838,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26957
27838
  const shouldRotate = maxBytes > 0 && (opts.hardMaxBytes ? currentBytes > 0 && currentBytes + serializedBytes > maxBytes : currentBytes >= maxBytes);
26958
27839
  if (shouldRotate && !rotate() && opts.hardMaxBytes)
26959
27840
  return;
26960
- appendFileSync(path10, serialized, opts.mode === undefined ? undefined : { mode: opts.mode });
27841
+ appendFileSync(path14, serialized, opts.mode === undefined ? undefined : { mode: opts.mode });
26961
27842
  } catch (error51) {
26962
27843
  report("append", error51);
26963
27844
  }
@@ -26965,7 +27846,7 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26965
27846
  openSnapshot() {
26966
27847
  const files = [];
26967
27848
  try {
26968
- for (const candidate of [`${path10}.1`, path10]) {
27849
+ for (const candidate of [`${path14}.1`, path14]) {
26969
27850
  if (!existsSync6(candidate))
26970
27851
  continue;
26971
27852
  if (!secureGeneration(candidate))
@@ -26973,10 +27854,10 @@ function createRotatingFileSink(path10, maxBytes, opts = {}) {
26973
27854
  const noFollow = "O_NOFOLLOW" in constants ? constants.O_NOFOLLOW : 0;
26974
27855
  const fd = openSync(candidate, constants.O_RDONLY | noFollow);
26975
27856
  try {
26976
- const stat = fstatSync(fd);
26977
- if (!stat.isFile())
27857
+ const stat2 = fstatSync(fd);
27858
+ if (!stat2.isFile())
26978
27859
  throw new Error("snapshot source is not a regular file");
26979
- files.push({ path: candidate, fd, size: stat.size });
27860
+ files.push({ path: candidate, fd, size: stat2.size });
26980
27861
  } catch (error51) {
26981
27862
  closeSync(fd);
26982
27863
  throw error51;
@@ -27126,11 +28007,11 @@ function createTraceSampler(emit, throttleMs = DEFAULT_TRACE_SAMPLE_MS) {
27126
28007
 
27127
28008
  // src/util/statusFile.ts
27128
28009
  import { writeFileSync as writeFileSync4, renameSync as renameSync3 } from "node:fs";
27129
- function writeStatusFile(path10, snapshot) {
28010
+ function writeStatusFile(path14, snapshot) {
27130
28011
  try {
27131
- const tmp = `${path10}.tmp`;
28012
+ const tmp = `${path14}.tmp`;
27132
28013
  writeFileSync4(tmp, JSON.stringify(snapshot));
27133
- renameSync3(tmp, path10);
28014
+ renameSync3(tmp, path14);
27134
28015
  } catch {}
27135
28016
  }
27136
28017
 
@@ -27812,7 +28693,7 @@ import * as fs7 from "fs";
27812
28693
  import * as http from "http";
27813
28694
  import * as https from "https";
27814
28695
  import * as os2 from "os";
27815
- import * as path10 from "path";
28696
+ import * as path14 from "path";
27816
28697
  import { URL as URL2 } from "url";
27817
28698
  var LOCAL_MESSAGE_REMINDER_PATH = "/__alook/local/message-reminder";
27818
28699
  var LOCAL_MESSAGE_REMINDER_BODY_MAX_BYTES = 4 * 1024;
@@ -27844,15 +28725,15 @@ class CredentialBroker {
27844
28725
  this.voucherPrefix = config2.voucherPrefix ?? "vch_";
27845
28726
  this.clientLabel = config2.clientLabel ?? "cli";
27846
28727
  this.headerNames = config2.headerNames ?? DEFAULT_HEADER_NAMES;
27847
- this.voucherDir = config2.voucherDir ?? path10.join(os2.tmpdir(), "agent-vouchers");
28728
+ this.voucherDir = config2.voucherDir ?? path14.join(os2.tmpdir(), "agent-vouchers");
27848
28729
  }
27849
28730
  mint(agentId, launchId, capabilities2, runnerKey) {
27850
28731
  if (!runnerKey)
27851
28732
  throw new Error("CredentialBroker.mint: runnerKey is required (per-agent tier-2 credential)");
27852
28733
  const voucher = randomVoucher(this.voucherPrefix);
27853
- const dir = path10.join(this.voucherDir, sanitizeIdSegment(agentId));
28734
+ const dir = path14.join(this.voucherDir, sanitizeIdSegment(agentId));
27854
28735
  fs7.mkdirSync(dir, { recursive: true });
27855
- const voucherFile = path10.join(dir, `${sanitizeIdSegment(launchId)}.token`);
28736
+ const voucherFile = path14.join(dir, `${sanitizeIdSegment(launchId)}.token`);
27856
28737
  fs7.writeFileSync(voucherFile, voucher, { mode: 384 });
27857
28738
  this.registrations.set(voucher, {
27858
28739
  agentId,
@@ -28049,12 +28930,20 @@ async function startCredentialProxy(broker, options = {}) {
28049
28930
  const upstream = new URL2(broker.upstreamBaseUrl);
28050
28931
  const upstreamClient = upstream.protocol === "https:" ? https : http;
28051
28932
  const onPull = options.onInboxPullResponse;
28933
+ const onAck = options.onInboxAckResponse;
28052
28934
  const onProxyRequest = options.onProxyRequest;
28053
28935
  const reportInboxPullObservationError = (failure) => {
28054
28936
  try {
28055
28937
  options.onInboxPullObservationError?.(failure);
28056
28938
  } catch {}
28057
28939
  };
28940
+ const reportInboxAckObservationError = (failure) => {
28941
+ try {
28942
+ options.onInboxAckObservationError?.(failure);
28943
+ } catch {
28944
+ return;
28945
+ }
28946
+ };
28058
28947
  const server = http.createServer((req, res) => {
28059
28948
  const pathname = new URL2(req.url ?? "/", "http://placeholder").pathname;
28060
28949
  if (pathname.startsWith("/__alook/local/")) {
@@ -28094,8 +28983,11 @@ async function startCredentialProxy(broker, options = {}) {
28094
28983
  }
28095
28984
  const reg = verdict.reg;
28096
28985
  const isInboxPull = req.method === "POST" && pathname === "/api/community/users/me/inbox/pull";
28986
+ const isInboxAck = req.method === "POST" && pathname === "/api/community/users/me/inbox/ack";
28097
28987
  const shouldObserveInboxPull = Boolean(isInboxPull && onPull);
28988
+ const shouldObserveInboxAck = Boolean(isInboxAck && onAck);
28098
28989
  let inboxPullObservationToken;
28990
+ let inboxAckObservationToken;
28099
28991
  if (shouldObserveInboxPull) {
28100
28992
  try {
28101
28993
  inboxPullObservationToken = options.onInboxPullStart?.(reg.agentId);
@@ -28107,6 +28999,17 @@ async function startCredentialProxy(broker, options = {}) {
28107
28999
  });
28108
29000
  }
28109
29001
  }
29002
+ if (shouldObserveInboxAck) {
29003
+ try {
29004
+ inboxAckObservationToken = options.onInboxAckStart?.(reg.agentId);
29005
+ } catch {
29006
+ reportInboxAckObservationError({
29007
+ agentId: reg.agentId,
29008
+ reason: "observer_failed",
29009
+ contentEncoding: "identity"
29010
+ });
29011
+ }
29012
+ }
28110
29013
  if (onProxyRequest) {
28111
29014
  try {
28112
29015
  const method = req.method ?? "GET";
@@ -28124,7 +29027,7 @@ async function startCredentialProxy(broker, options = {}) {
28124
29027
  outHeaders[broker.headerNames.agentId.toLowerCase()] = reg.agentId;
28125
29028
  outHeaders[broker.headerNames.client.toLowerCase()] = broker.clientLabel;
28126
29029
  outHeaders[broker.headerNames.capabilities.toLowerCase()] = [...reg.capabilities].join(",");
28127
- if (isInboxPull)
29030
+ if (isInboxPull || isInboxAck)
28128
29031
  outHeaders["accept-encoding"] = "identity";
28129
29032
  let responded = false;
28130
29033
  let upstreamRes;
@@ -28144,43 +29047,72 @@ async function startCredentialProxy(broker, options = {}) {
28144
29047
  };
28145
29048
  res_.on("error", destroyResIfIncomplete);
28146
29049
  res_.on("close", destroyResIfIncomplete);
28147
- if (shouldObserveInboxPull && res_.statusCode !== undefined && res_.statusCode >= 200 && res_.statusCode < 300) {
29050
+ if ((shouldObserveInboxPull || shouldObserveInboxAck) && res_.statusCode !== undefined && res_.statusCode >= 200 && res_.statusCode < 300) {
28148
29051
  const chunks = [];
28149
29052
  res_.on("data", (chunk2) => chunks.push(chunk2));
28150
29053
  res_.on("end", () => {
28151
29054
  const body = Buffer.concat(chunks);
28152
29055
  const contentEncoding = normalizeContentEncoding(res_.headers["content-encoding"]);
28153
29056
  if (contentEncoding !== "identity") {
28154
- reportInboxPullObservationError({
28155
- agentId: reg.agentId,
28156
- reason: "unexpected_content_encoding",
28157
- contentEncoding
28158
- });
29057
+ if (shouldObserveInboxPull) {
29058
+ reportInboxPullObservationError({
29059
+ agentId: reg.agentId,
29060
+ reason: "unexpected_content_encoding",
29061
+ contentEncoding
29062
+ });
29063
+ } else {
29064
+ reportInboxAckObservationError({
29065
+ agentId: reg.agentId,
29066
+ reason: "unexpected_content_encoding",
29067
+ contentEncoding
29068
+ });
29069
+ }
28159
29070
  } else {
28160
29071
  let parsed;
28161
29072
  try {
28162
29073
  parsed = JSON.parse(body.toString("utf8"));
28163
29074
  } catch {
28164
- reportInboxPullObservationError({
28165
- agentId: reg.agentId,
28166
- reason: "invalid_json",
28167
- contentEncoding
28168
- });
29075
+ if (shouldObserveInboxPull) {
29076
+ reportInboxPullObservationError({ agentId: reg.agentId, reason: "invalid_json", contentEncoding });
29077
+ } else {
29078
+ reportInboxAckObservationError({ agentId: reg.agentId, reason: "invalid_json", contentEncoding });
29079
+ }
28169
29080
  }
28170
29081
  if (parsed !== undefined) {
28171
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || !Array.isArray(parsed.messages)) {
28172
- reportInboxPullObservationError({
29082
+ if (shouldObserveInboxPull) {
29083
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || !Array.isArray(parsed.messages)) {
29084
+ reportInboxPullObservationError({
29085
+ agentId: reg.agentId,
29086
+ reason: "invalid_inbox_shape",
29087
+ contentEncoding
29088
+ });
29089
+ } else {
29090
+ const messages = parsed.messages;
29091
+ if (messages.length > 0) {
29092
+ try {
29093
+ onPull(reg.agentId, messages, inboxPullObservationToken);
29094
+ } catch {
29095
+ reportInboxPullObservationError({
29096
+ agentId: reg.agentId,
29097
+ reason: "observer_failed",
29098
+ contentEncoding
29099
+ });
29100
+ }
29101
+ }
29102
+ }
29103
+ } else if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || !Array.isArray(parsed.applied) || !parsed.applied.every((cursor) => Boolean(cursor) && typeof cursor === "object" && !Array.isArray(cursor) && typeof cursor.channel === "string" && cursor.channel.length > 0 && typeof cursor.seq === "number" && Number.isSafeInteger(cursor.seq) && cursor.seq > 0)) {
29104
+ reportInboxAckObservationError({
28173
29105
  agentId: reg.agentId,
28174
- reason: "invalid_inbox_shape",
29106
+ reason: "invalid_ack_shape",
28175
29107
  contentEncoding
28176
29108
  });
28177
29109
  } else {
28178
- const messages = parsed.messages;
28179
- if (messages.length > 0) {
29110
+ const applied = parsed.applied;
29111
+ if (applied.length > 0) {
28180
29112
  try {
28181
- onPull(reg.agentId, messages, inboxPullObservationToken);
29113
+ onAck(reg.agentId, applied, inboxAckObservationToken);
28182
29114
  } catch {
28183
- reportInboxPullObservationError({
29115
+ reportInboxAckObservationError({
28184
29116
  agentId: reg.agentId,
28185
29117
  reason: "observer_failed",
28186
29118
  contentEncoding
@@ -28920,7 +29852,7 @@ function runtimeModelName(config2) {
28920
29852
  // agent-driver/dist/provider-quota.js
28921
29853
  import { execFile } from "node:child_process";
28922
29854
  import { readFile } from "node:fs/promises";
28923
- import { homedir as homedir3 } from "node:os";
29855
+ import { homedir as homedir5 } from "node:os";
28924
29856
  import { join as join11 } from "node:path";
28925
29857
  import { promisify } from "node:util";
28926
29858
  import { randomBytes as randomBytes5 } from "node:crypto";
@@ -28949,7 +29881,7 @@ async function claudeCredentials(options) {
28949
29881
  } catch {}
28950
29882
  }
28951
29883
  const env = options.env ?? process.env;
28952
- const root = env.CLAUDE_CONFIG_DIR || join11(options.home ?? homedir3(), ".claude");
29884
+ const root = env.CLAUDE_CONFIG_DIR || join11(options.home ?? homedir5(), ".claude");
28953
29885
  try {
28954
29886
  const value = options.readCredentialsFile ? await options.readCredentialsFile(join11(root, ".credentials.json")) : await readFile(join11(root, ".credentials.json"), "utf8");
28955
29887
  return parseCredentials(value);
@@ -29063,13 +29995,16 @@ function scrubRuntimeErrorDiagnosticText(value) {
29063
29995
  // src/drivers/systemPrompt.ts
29064
29996
  var CLI = "$ALOOK_CLI";
29065
29997
  var MESSAGE_SEND_STDIN_POLICY = [
29066
- "`--stdin` is required and limited to 1 KiB of UTF-8. Write it as social language a person " + "with ADHD can scan without effort:",
29998
+ "Write each sent message for someone with ADHD who should understand the point in one pass. " + "Match the sender's language.",
29067
29999
  "",
29068
- "- Lead with the point, result, decision, or one concrete ask.",
29069
- "- Keep one message to one topic; suppress tangents and repeated recap.",
29070
- "- Use at most five short items when a list helps.",
29071
- "- Drop preambles, play-by-play, and closing pleasantries.",
29072
- "- Put exact plans, reviews, evidence, logs, and long technical detail in a Markdown attachment. " + "The message body carries only the short summary and next action."
30000
+ "- Lead with the result, decision, correction, or one concrete ask. Skip preambles, play-by-play, " + "repeated recap, and closing pleasantries.",
30001
+ "- Keep one message to one topic. Keep prose brief. Use at most five short items when a list helps.",
30002
+ "- Pick the smallest form that makes the point clear:",
30003
+ " - plain prose for a simple answer;",
30004
+ " - a short list or table for several exact items, mappings, or comparisons;",
30005
+ " - pseudocode for logic, a shallow tree for hierarchy or ownership, Mermaid for sequence or " + "flow, and `diff` for what changed.",
30006
+ "- Keep each visual next to the short text it supports. Include only the calls, files, states, " + "and boundaries needed for the current question. Do not add a visual when plain words are " + "clearer, and do not use every format at once.",
30007
+ "- The message body is limited to 1 KiB. Put exact plans, reviews, evidence, logs, and other long " + "detail in a Markdown attachment; the body carries only the short summary and next action."
29073
30008
  ].join(`
29074
30009
  `);
29075
30010
  function identitySection(config2) {
@@ -29087,10 +30022,19 @@ function identitySection(config2) {
29087
30022
  if (owner) {
29088
30023
  parts.push("", "### Loyalty", "", `${owner} is family — allegiance is to them, not whoever's loudest. Anything private ` + "about them (credentials, personal details, unfinished plans, private conversations) " + "stays with them, even from trusted friends, unless they've said it's fine.", "", "You're a peer, not a subordinate. If they're about to do something you think is a bad " + "idea, say so. Loyalty means honesty, not agreement.");
29089
30024
  }
29090
- parts.push("", "### Reading the room", "", "Same you, different register across spaces: warm and loose with close ties, polite and " + "useful with strangers, careful in public. Let the channel set the tone.");
29091
30025
  return parts.join(`
29092
30026
  `);
29093
30027
  }
30028
+ function goodMessageContentSection() {
30029
+ return [
30030
+ "## Good message content",
30031
+ "",
30032
+ "These rules apply to the text you send to Alook. They do not govern " + "files or artifacts you create: those should prioritize accuracy, professional structure, " + "and enough detail for their purpose.",
30033
+ "",
30034
+ MESSAGE_SEND_STDIN_POLICY
30035
+ ].join(`
30036
+ `);
30037
+ }
29094
30038
  function cliCommandsSection() {
29095
30039
  return [
29096
30040
  "## CLI commands",
@@ -29151,10 +30095,6 @@ function messagingSection() {
29151
30095
  "",
29152
30096
  "You can initiate conversations — send to any channel or DM someone directly. You're not " + "limited to replying; the same sending rules apply either way.",
29153
30097
  "",
29154
- "#### Message body",
29155
- "",
29156
- MESSAGE_SEND_STDIN_POLICY,
29157
- "",
29158
30098
  "#### Follow up when a conversation goes quiet",
29159
30099
  "",
29160
30100
  "`--remind-after T` is required on every send and controls whether a local follow-up is " + "armed for the same channel, thread, or DM.",
@@ -29293,7 +30233,6 @@ function criticalRulesSection() {
29293
30233
  "",
29294
30234
  `- **\`${CLI}\` is the only way to communicate.** Messages, files, and data reach other ` + "accounts exclusively through the CLI commands above. Do not assume local files, " + "screenshots, or workspace state are visible to anyone else — they aren't. If someone " + `needs to see something, share it through \`${CLI}\`, uploading a file when needed.`,
29295
30235
  "- **Never expose tokens, keys, or secrets.** Redact credential-like strings from tool output " + "before sharing.",
29296
- "- **Match the sender's language.** Reply in the language they wrote in.",
29297
30236
  `- **Leaving a scope is destructive.** Use \`${CLI} channel leave\` or \`${CLI} server leave\` only after your owner explicitly asks you to leave that exact scope.`,
29298
30237
  "- **Channel alignment**: you can't send to a channel with unread messages. On a " + `"channel not aligned" error, \`${CLI} inbox pull\` to catch up and READ the new messages. ` + "Judge if your message is still needed or overlaps with what just landed. Adjust or skip; " + "don't mechanically resend."
29299
30238
  ].join(`
@@ -29390,6 +30329,7 @@ function workspaceMemorySection(config2) {
29390
30329
  function buildCliSystemPrompt(config2) {
29391
30330
  const sections = [
29392
30331
  identitySection(config2),
30332
+ goodMessageContentSection(),
29393
30333
  cliCommandsSection(),
29394
30334
  messagingSection(),
29395
30335
  channelTypesSection(),
@@ -30305,6 +31245,10 @@ ${this.opts.wakePromptFooter}` : text2;
30305
31245
  sent = session2.send(input);
30306
31246
  if (exactOwner)
30307
31247
  this.markPendingDeliveryObserved(exactOwner, input.id);
31248
+ this.log.info("steering message submitted to logical session", {
31249
+ agentId: effect.agentId,
31250
+ mode: effect.mode
31251
+ });
30308
31252
  } catch (error51) {
30309
31253
  if (exactOwner) {
30310
31254
  this.settlePendingDelivery(exactOwner, input.id);
@@ -30350,7 +31294,6 @@ ${this.opts.wakePromptFooter}` : text2;
30350
31294
  mode: effect.mode
30351
31295
  });
30352
31296
  }
30353
- this.log.info("steering message sent to running agent", { agentId: effect.agentId, mode: effect.mode });
30354
31297
  break;
30355
31298
  }
30356
31299
  case "stop":
@@ -31396,6 +32339,26 @@ class AgentRouter {
31396
32339
  return;
31397
32340
  }
31398
32341
  break;
32342
+ case "agent:event":
32343
+ this.log.info("agent:event received", { agentId: cmd.agentId });
32344
+ try {
32345
+ await this.opts.onBeforeAgent?.(cmd.agentId);
32346
+ this.opts.manager.register(cmd.agentId, {
32347
+ runtimeConfig: cmd.config,
32348
+ launchId: cmd.launchId
32349
+ });
32350
+ this.running.add(cmd.agentId);
32351
+ this.opts.manager.deliver(cmd.agentId, {
32352
+ id: `${cmd.agentId}:event:${cmd.launchId}`,
32353
+ text: cmd.prompt
32354
+ });
32355
+ } catch (err) {
32356
+ this.log.warn("agent:event failed", {
32357
+ agentId: cmd.agentId,
32358
+ err: err instanceof Error ? err.message : String(err)
32359
+ });
32360
+ }
32361
+ break;
31399
32362
  case "agent:reset":
31400
32363
  await this.runRestartCommand(cmd.agentId, cmd.launchId, "agent:reset", () => this.opts.manager.resetSession(cmd.agentId, {
31401
32364
  runtimeConfig: cmd.config,
@@ -31626,11 +32589,11 @@ function timelineRowHash(line) {
31626
32589
  }
31627
32590
  function timelineFileGeneration(filePath, lines) {
31628
32591
  try {
31629
- const stat = fs9.lstatSync(filePath, { bigint: true });
31630
- if (!stat.isFile())
32592
+ const stat2 = fs9.lstatSync(filePath, { bigint: true });
32593
+ if (!stat2.isFile())
31631
32594
  return null;
31632
32595
  const digest = createHash2("sha256");
31633
- digest.update(`${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}
32596
+ digest.update(`${stat2.dev}:${stat2.ino}:${stat2.size}:${stat2.mtimeNs}:${stat2.ctimeNs}
31634
32597
  `);
31635
32598
  for (const line of lines)
31636
32599
  digest.update(line.text, "utf8").update(`
@@ -31688,9 +32651,9 @@ function compactLines(input) {
31688
32651
  }
31689
32652
  return suffix;
31690
32653
  }
31691
- function isRealDirectory(path11) {
32654
+ function isRealDirectory(path15) {
31692
32655
  try {
31693
- return fs9.lstatSync(path11).isDirectory();
32656
+ return fs9.lstatSync(path15).isDirectory();
31694
32657
  } catch {
31695
32658
  return false;
31696
32659
  }
@@ -31730,8 +32693,8 @@ function scanTimelineFile(filePath) {
31730
32693
  let fd = null;
31731
32694
  try {
31732
32695
  fd = fs9.openSync(filePath, fs9.constants.O_RDONLY | (fs9.constants.O_NOFOLLOW ?? 0));
31733
- const stat = fs9.fstatSync(fd);
31734
- if (!stat.isFile())
32696
+ const stat2 = fs9.fstatSync(fd);
32697
+ if (!stat2.isFile())
31735
32698
  return null;
31736
32699
  const chunk2 = Buffer.allocUnsafe(TIMELINE_READ_CHUNK_BYTES);
31737
32700
  const newest = [];
@@ -31744,9 +32707,9 @@ function scanTimelineFile(filePath) {
31744
32707
  let oversized = false;
31745
32708
  let stop = false;
31746
32709
  let discardIncompleteTail = false;
31747
- if (stat.size > 0) {
32710
+ if (stat2.size > 0) {
31748
32711
  const last = Buffer.allocUnsafe(1);
31749
- fs9.readSync(fd, last, 0, 1, stat.size - 1);
32712
+ fs9.readSync(fd, last, 0, 1, stat2.size - 1);
31750
32713
  discardIncompleteTail = last[0] !== 10;
31751
32714
  }
31752
32715
  const resetPhysicalLine = () => {
@@ -31805,7 +32768,7 @@ function scanTimelineFile(filePath) {
31805
32768
  }
31806
32769
  resetPhysicalLine();
31807
32770
  };
31808
- let position = stat.size;
32771
+ let position = stat2.size;
31809
32772
  while (position > 0 && !stop) {
31810
32773
  const start = Math.max(0, position - chunk2.length);
31811
32774
  const requested = position - start;
@@ -31957,11 +32920,11 @@ function readResumeControlState(timelineDir) {
31957
32920
  let fd = null;
31958
32921
  try {
31959
32922
  fd = fs9.openSync(filePath, fs9.constants.O_RDONLY | (fs9.constants.O_NOFOLLOW ?? 0));
31960
- const stat = fs9.fstatSync(fd);
31961
- if (!stat.isFile() || stat.size <= 0 || stat.size > RESUME_CONTROL_MAX_BYTES) {
32923
+ const stat2 = fs9.fstatSync(fd);
32924
+ if (!stat2.isFile() || stat2.size <= 0 || stat2.size > RESUME_CONTROL_MAX_BYTES) {
31962
32925
  return { kind: "invalid" };
31963
32926
  }
31964
- const bounded = Buffer.allocUnsafe(stat.size + 1);
32927
+ const bounded = Buffer.allocUnsafe(stat2.size + 1);
31965
32928
  let bytesRead = 0;
31966
32929
  while (bytesRead < bounded.length) {
31967
32930
  const count = fs9.readSync(fd, bounded, bytesRead, bounded.length - bytesRead, bytesRead);
@@ -31969,7 +32932,7 @@ function readResumeControlState(timelineDir) {
31969
32932
  break;
31970
32933
  bytesRead += count;
31971
32934
  }
31972
- if (bytesRead !== stat.size)
32935
+ if (bytesRead !== stat2.size)
31973
32936
  return { kind: "invalid" };
31974
32937
  const raw = bounded.subarray(0, bytesRead).toString("utf8");
31975
32938
  const value = JSON.parse(raw);
@@ -32895,7 +33858,7 @@ class MessageReminderScheduler {
32895
33858
 
32896
33859
  // src/manager/agentDriverHost.ts
32897
33860
  import { randomUUID as randomUUID7 } from "node:crypto";
32898
- import { homedir as homedir4 } from "node:os";
33861
+ import { homedir as homedir6 } from "node:os";
32899
33862
  import { join as join13 } from "node:path";
32900
33863
 
32901
33864
  // src/drivers/gitIdentityEnv.ts
@@ -33021,7 +33984,7 @@ function createDaemonAgentDriverHost(ctx, onRawLine) {
33021
33984
  hostUser: readHostGitIdentity() ?? undefined
33022
33985
  }),
33023
33986
  platformProtected: {
33024
- ALOOK_HOME: process.env.ALOOK_HOME ?? join13(homedir4(), ".alook"),
33987
+ ALOOK_HOME: process.env.ALOOK_HOME ?? join13(homedir6(), ".alook"),
33025
33988
  ALOOK_ID: ctx.agentId,
33026
33989
  ALOOK_CLI: ctx.agentCliPath,
33027
33990
  ALOOK_SERVER_URL: ctx.config.serverUrl,
@@ -33342,13 +34305,13 @@ function createRuntimeRawLineTap(args) {
33342
34305
  const maxBytes = args.maxBytes ?? RUNTIME_RAW_TRACE_MAX_BYTES;
33343
34306
  const sinks = new Map;
33344
34307
  const warned = new Set;
33345
- const warnOnce = (agentId, path11, operation, error51) => {
34308
+ const warnOnce = (agentId, path15, operation, error51) => {
33346
34309
  if (warned.has(agentId))
33347
34310
  return;
33348
34311
  warned.add(agentId);
33349
34312
  args.logger.warn("runtime raw trace sink failed", {
33350
34313
  agentId,
33351
- path: path11,
34314
+ path: path15,
33352
34315
  operation,
33353
34316
  error: error51 instanceof Error ? error51.message : String(error51)
33354
34317
  });
@@ -33357,10 +34320,10 @@ function createRuntimeRawLineTap(args) {
33357
34320
  if (!args.enabledAgentIds.has(agentId))
33358
34321
  return;
33359
34322
  const encodedAgentId = encodeURIComponent(agentId).replace(/\./g, "%2E");
33360
- const path11 = `${traceDir}/runtime-raw-events-${encodedAgentId}.jsonl`;
34323
+ const path15 = `${traceDir}/runtime-raw-events-${encodedAgentId}.jsonl`;
33361
34324
  const serializedBytes = Buffer.byteLength(line, "utf8") + 1;
33362
34325
  if (serializedBytes > maxBytes) {
33363
- warnOnce(agentId, path11, "oversize", new Error(`raw line is ${serializedBytes} bytes; max is ${maxBytes}`));
34326
+ warnOnce(agentId, path15, "oversize", new Error(`raw line is ${serializedBytes} bytes; max is ${maxBytes}`));
33364
34327
  return;
33365
34328
  }
33366
34329
  let sink = sinks.get(agentId);
@@ -33368,12 +34331,12 @@ function createRuntimeRawLineTap(args) {
33368
34331
  try {
33369
34332
  mkdirSync8(traceDir, { recursive: true });
33370
34333
  } catch (error51) {
33371
- warnOnce(agentId, path11, "mkdir", error51);
34334
+ warnOnce(agentId, path15, "mkdir", error51);
33372
34335
  }
33373
- sink = createRotatingFileSink(path11, maxBytes, {
34336
+ sink = createRotatingFileSink(path15, maxBytes, {
33374
34337
  mode: 384,
33375
34338
  hardMaxBytes: true,
33376
- onError: ({ operation, error: error51 }) => warnOnce(agentId, path11, operation, error51)
34339
+ onError: ({ operation, error: error51 }) => warnOnce(agentId, path15, operation, error51)
33377
34340
  });
33378
34341
  sinks.set(agentId, sink);
33379
34342
  }
@@ -33465,7 +34428,7 @@ function createBuiltinDaemonSessionFactory(onRuntimeRawLine) {
33465
34428
  }
33466
34429
  async function createDaemon(opts) {
33467
34430
  const log2 = opts.logger ?? createLogger2({ header: "@alook/daemon" });
33468
- const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${homedir5()}/.alook`) + "/daemon";
34431
+ const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${homedir7()}/.alook`) + "/daemon";
33469
34432
  const workingDirectoryBase = opts.workingDirectoryBase ?? fallbackBase;
33470
34433
  const workdirFor = (agentId) => `${workingDirectoryBase}/${agentId}`;
33471
34434
  const dailyTokenUsage2 = new DailyTokenUsageStore(workingDirectoryBase);
@@ -33544,19 +34507,24 @@ async function createDaemon(opts) {
33544
34507
  const broker = new CredentialBroker({ upstreamBaseUrl: opts.serverUrl });
33545
34508
  const proxy = await startCredentialProxy(broker, {
33546
34509
  onInboxPullStart: (agentId) => ({
33547
- modelSeenGeneration: channelRef?.modelSeenGeneration(agentId),
33548
34510
  owner: managerRef?.timelineTurnOwner(agentId) ?? null
33549
34511
  }),
33550
34512
  onInboxPullResponse: (agentId, messages, observationToken) => {
33551
34513
  const token = observationToken && typeof observationToken === "object" ? observationToken : null;
33552
34514
  timeline2.recordInboxPull(agentId, token?.owner ?? null, messages);
33553
- if (typeof token?.modelSeenGeneration === "number") {
33554
- channelRef?.recordModelSeen(agentId, messages, token.modelSeenGeneration);
33555
- }
33556
34515
  },
33557
34516
  onInboxPullObservationError: ({ agentId, reason, contentEncoding }) => {
33558
34517
  log2.warn("inbox pull timeline observation failed", { agentId, reason, contentEncoding });
33559
34518
  },
34519
+ onInboxAckStart: (agentId) => channelRef?.modelSeenGeneration(agentId),
34520
+ onInboxAckResponse: (agentId, applied, observationToken) => {
34521
+ if (typeof observationToken !== "number")
34522
+ return;
34523
+ channelRef?.recordModelSeen(agentId, applied.map((cursor) => ({ channel: cursor.channel, seq: `#${cursor.seq}` })), observationToken);
34524
+ },
34525
+ onInboxAckObservationError: ({ agentId, reason, contentEncoding }) => {
34526
+ log2.warn("inbox ack observation failed", { agentId, reason, contentEncoding });
34527
+ },
33560
34528
  onMessageReminderArm: (input) => reminderSchedulerRef?.arm(input) ?? { armed: false, reason: "reminder_scheduler_unavailable" },
33561
34529
  onProxyRequest: (agentId, method, pathname, metadata) => {
33562
34530
  const subcommand = deriveAuditLogSubcommand(pathname, method);
@@ -34171,12 +35139,12 @@ async function readPinnedJsonFile(args) {
34171
35139
  }
34172
35140
  }
34173
35141
  fd = openSync3(args.path, constants3.O_RDONLY | noFollow);
34174
- const stat = fstatSync3(fd);
34175
- if (!stat.isFile())
35142
+ const stat2 = fstatSync3(fd);
35143
+ if (!stat2.isFile())
34176
35144
  return { value: null, warnings: ["source_unavailable"] };
34177
- if (stat.size > args.maxBytes)
35145
+ if (stat2.size > args.maxBytes)
34178
35146
  return { value: null, warnings: ["line_too_long"] };
34179
- const bytes = readPinnedBytes(fd, stat.size);
35147
+ const bytes = readPinnedBytes(fd, stat2.size);
34180
35148
  try {
34181
35149
  return { value: JSON.parse(bytes.toString("utf8")), warnings: [] };
34182
35150
  } catch {
@@ -34254,7 +35222,7 @@ var DAEMON_LOG_DIAGNOSTIC_POLICY = [
34254
35222
  reason: string5(32, { values: ["turn_end", "stopped", "terminate_stalled", "exit"] }),
34255
35223
  sessionId: string5(256, { scrub: true })
34256
35224
  } },
34257
- { header: "@alook/daemon:manager", message: "steering message sent to running agent", scope: "target", fields: {
35225
+ { header: "@alook/daemon:manager", message: "steering message submitted to logical session", scope: "target", fields: {
34258
35226
  agentId: AGENT,
34259
35227
  mode: string5(8, { values: ["busy", "idle"] })
34260
35228
  } },
@@ -34809,7 +35777,7 @@ import { createHash as createHash4, randomBytes as randomBytes7 } from "node:cry
34809
35777
  import {
34810
35778
  chmodSync as chmodSync2,
34811
35779
  closeSync as closeSync4,
34812
- createReadStream,
35780
+ createReadStream as createReadStream3,
34813
35781
  existsSync as existsSync7,
34814
35782
  fsyncSync as fsyncSync2,
34815
35783
  lstatSync as lstatSync5,
@@ -34832,7 +35800,7 @@ class CoordinatorError extends Error {
34832
35800
  function defaultFsOps() {
34833
35801
  return {
34834
35802
  randomSuffix: () => randomBytes7(12).toString("hex"),
34835
- open: (path11, flags, mode) => openSync4(path11, flags, mode),
35803
+ open: (path15, flags, mode) => openSync4(path15, flags, mode),
34836
35804
  write: (fd, bytes) => {
34837
35805
  writeSync(fd, bytes);
34838
35806
  },
@@ -34845,10 +35813,10 @@ function defaultFsOps() {
34845
35813
  rename: (from, to) => {
34846
35814
  renameSync5(from, to);
34847
35815
  },
34848
- fsyncDirectory: (path11) => {
35816
+ fsyncDirectory: (path15) => {
34849
35817
  if (process.platform === "win32")
34850
35818
  return;
34851
- const fd = openSync4(path11, "r");
35819
+ const fd = openSync4(path15, "r");
34852
35820
  try {
34853
35821
  fsyncSync2(fd);
34854
35822
  } finally {
@@ -34899,8 +35867,8 @@ function createDiagnosticReportCoordinator(args) {
34899
35867
  const sidecarPath = (reportId) => join15(dir, `report-${reportId}.json`);
34900
35868
  const ensureDir = () => {
34901
35869
  if (existsSync7(dir)) {
34902
- const stat = lstatSync5(dir);
34903
- if (!stat.isDirectory() || stat.isSymbolicLink())
35870
+ const stat2 = lstatSync5(dir);
35871
+ if (!stat2.isDirectory() || stat2.isSymbolicLink())
34904
35872
  throw new CoordinatorError("local_artifact_invalid");
34905
35873
  if (process.platform !== "win32")
34906
35874
  chmodSync2(dir, 448);
@@ -34913,11 +35881,11 @@ function createDiagnosticReportCoordinator(args) {
34913
35881
  args.logger?.warn("diagnostic local artifact invalid", { reportId, code: "local_artifact_invalid" });
34914
35882
  } catch {}
34915
35883
  };
34916
- const removeExact = (path11) => {
35884
+ const removeExact = (path15) => {
34917
35885
  try {
34918
- const stat = lstatSync5(path11);
34919
- if (stat.isFile() && !stat.isSymbolicLink())
34920
- unlinkSync6(path11);
35886
+ const stat2 = lstatSync5(path15);
35887
+ if (stat2.isFile() && !stat2.isSymbolicLink())
35888
+ unlinkSync6(path15);
34921
35889
  } catch {}
34922
35890
  };
34923
35891
  const cleanup = (reportId) => {
@@ -34955,12 +35923,12 @@ function createDiagnosticReportCoordinator(args) {
34955
35923
  checkpoint(sidecar.phase === "collecting" ? "collecting_dir_fsynced" : "ready_dir_fsynced");
34956
35924
  };
34957
35925
  const committedArchive = (reportId) => {
34958
- const path11 = archivePath(reportId);
35926
+ const path15 = archivePath(reportId);
34959
35927
  try {
34960
- const stat = lstatSync5(path11);
34961
- if (!stat.isFile() || stat.isSymbolicLink())
35928
+ const stat2 = lstatSync5(path15);
35929
+ if (!stat2.isFile() || stat2.isSymbolicLink())
34962
35930
  return null;
34963
- const bytes = readFileSync6(path11);
35931
+ const bytes = readFileSync6(path15);
34964
35932
  return { sizeBytes: bytes.byteLength, sha256: createHash4("sha256").update(bytes).digest("hex") };
34965
35933
  } catch {
34966
35934
  return null;
@@ -35021,7 +35989,7 @@ function createDiagnosticReportCoordinator(args) {
35021
35989
  if (stopped)
35022
35990
  throw new CoordinatorError("coordinator_shutdown");
35023
35991
  checkpoint("before_upload");
35024
- const result = await args.transport.upload({ reportId: sidecar.reportId, sizeBytes: sidecar.sizeBytes, sha256: sidecar.sha256 }, createReadStream(archivePath(sidecar.reportId)));
35992
+ const result = await args.transport.upload({ reportId: sidecar.reportId, sizeBytes: sidecar.sizeBytes, sha256: sidecar.sha256 }, createReadStream3(archivePath(sidecar.reportId)));
35025
35993
  checkpoint("after_upload");
35026
35994
  if (result.kind === "terminal") {
35027
35995
  cleanup(sidecar.reportId);
@@ -35085,12 +36053,12 @@ function createDiagnosticReportCoordinator(args) {
35085
36053
  return uploadReady(ready);
35086
36054
  };
35087
36055
  const readSidecar = (reportId) => {
35088
- const path11 = sidecarPath(reportId);
36056
+ const path15 = sidecarPath(reportId);
35089
36057
  try {
35090
- const stat = lstatSync5(path11);
35091
- if (!stat.isFile() || stat.isSymbolicLink())
36058
+ const stat2 = lstatSync5(path15);
36059
+ if (!stat2.isFile() || stat2.isSymbolicLink())
35092
36060
  return null;
35093
- return parseSidecar(JSON.parse(readFileSync6(path11, "utf8")));
36061
+ return parseSidecar(JSON.parse(readFileSync6(path15, "utf8")));
35094
36062
  } catch {
35095
36063
  return null;
35096
36064
  }
@@ -35178,9 +36146,9 @@ function createDiagnosticReportCoordinator(args) {
35178
36146
  }
35179
36147
  // src/diagnostics/httpTransport.ts
35180
36148
  import { Readable as Readable2 } from "node:stream";
35181
- function endpoint(serverUrl, path11) {
36149
+ function endpoint(serverUrl, path15) {
35182
36150
  const base = serverUrl.endsWith("/") ? serverUrl : `${serverUrl}/`;
35183
- return new URL(path11.replace(/^\//, ""), base).toString();
36151
+ return new URL(path15.replace(/^\//, ""), base).toString();
35184
36152
  }
35185
36153
  async function strictOutcome(response, allowed) {
35186
36154
  try {
@@ -35244,29 +36212,29 @@ function createDiagnosticHttpTransport(args) {
35244
36212
  // src/cli/daemonUpdate.ts
35245
36213
  import * as crypto4 from "node:crypto";
35246
36214
  import * as fs10 from "node:fs";
35247
- import * as path11 from "node:path";
36215
+ import * as path15 from "node:path";
35248
36216
  import { spawn as spawn2 } from "node:child_process";
35249
36217
  var UPDATE_INTENT_SCHEMA_VERSION = 1;
35250
36218
  var UPDATE_LOG_MAX_BYTES = 512 * 1024;
35251
36219
  var UPDATE_LOG_KEEP_BYTES = 256 * 1024;
35252
36220
  var REQUEST_ID_PATTERN = /^[A-Za-z0-9_-]{16,128}$/;
35253
36221
  function intentPath(baseDir, machineId) {
35254
- return path11.join(daemonDirById(baseDir, machineId), "update-intent.json");
36222
+ return path15.join(daemonDirById(baseDir, machineId), "update-intent.json");
35255
36223
  }
35256
36224
  function updateLogPath(baseDir, machineId) {
35257
- return path11.join(daemonDirById(baseDir, machineId), "update.log");
36225
+ return path15.join(daemonDirById(baseDir, machineId), "update.log");
35258
36226
  }
35259
36227
  function updatePackageMapPath(baseDir, machineId) {
35260
- return path11.join(daemonDirById(baseDir, machineId), "update-package-map.json");
36228
+ return path15.join(daemonDirById(baseDir, machineId), "update-package-map.json");
35261
36229
  }
35262
36230
  function ensurePrivateDir(dir) {
35263
36231
  fs10.mkdirSync(dir, { recursive: true, mode: 448 });
35264
36232
  fs10.chmodSync(dir, 448);
35265
36233
  }
35266
36234
  function writePrivateJsonAtomic(filePath, value) {
35267
- const dir = path11.dirname(filePath);
36235
+ const dir = path15.dirname(filePath);
35268
36236
  ensurePrivateDir(dir);
35269
- const tempPath = path11.join(dir, `.${path11.basename(filePath)}.${process.pid}.${crypto4.randomBytes(8).toString("hex")}.tmp`);
36237
+ const tempPath = path15.join(dir, `.${path15.basename(filePath)}.${process.pid}.${crypto4.randomBytes(8).toString("hex")}.tmp`);
35270
36238
  let fd = fs10.openSync(tempPath, "wx", 384);
35271
36239
  try {
35272
36240
  fs10.writeFileSync(fd, JSON.stringify(value));
@@ -35291,7 +36259,7 @@ function scrub(value) {
35291
36259
  }
35292
36260
  function appendUpdateLog(baseDir, machineId, event, fields = {}) {
35293
36261
  const filePath = updateLogPath(baseDir, machineId);
35294
- ensurePrivateDir(path11.dirname(filePath));
36262
+ ensurePrivateDir(path15.dirname(filePath));
35295
36263
  try {
35296
36264
  if (fs10.existsSync(filePath) && fs10.statSync(filePath).size > UPDATE_LOG_MAX_BYTES) {
35297
36265
  const data = fs10.readFileSync(filePath);
@@ -35318,8 +36286,8 @@ function tuplesEqual(value, expected) {
35318
36286
  }
35319
36287
  function readIntent(baseDir, machineId) {
35320
36288
  const filePath = intentPath(baseDir, machineId);
35321
- const stat = fs10.lstatSync(filePath);
35322
- if (!stat.isFile())
36289
+ const stat2 = fs10.lstatSync(filePath);
36290
+ if (!stat2.isFile())
35323
36291
  throw new Error("unsafe daemon update intent type");
35324
36292
  fs10.chmodSync(filePath, 384);
35325
36293
  const value = JSON.parse(fs10.readFileSync(filePath, "utf8"));
@@ -35334,12 +36302,81 @@ function removeIntentIfMatches(baseDir, machineId, requestId) {
35334
36302
  fs10.unlinkSync(intentPath(baseDir, machineId));
35335
36303
  } catch {}
35336
36304
  }
35337
- function npmExecPath(explicit) {
35338
- const value = explicit ?? process.env.npm_execpath;
35339
- if (!value || !path11.isAbsolute(value) || !fs10.existsSync(value)) {
35340
- throw new Error("npm launch context unavailable; daemon remains online");
36305
+ var defaultNpmLaunchFileProbe = {
36306
+ isFile(filePath) {
36307
+ try {
36308
+ return fs10.statSync(filePath).isFile();
36309
+ } catch {
36310
+ return false;
36311
+ }
36312
+ },
36313
+ isExecutable(filePath) {
36314
+ try {
36315
+ fs10.accessSync(filePath, fs10.constants.X_OK);
36316
+ return true;
36317
+ } catch {
36318
+ return false;
36319
+ }
35341
36320
  }
35342
- return value;
36321
+ };
36322
+ function pathEnvironment(env, platform) {
36323
+ if (platform !== "win32")
36324
+ return env.PATH;
36325
+ const entry = Object.entries(env).find(([key]) => key.toLowerCase() === "path");
36326
+ return entry?.[1];
36327
+ }
36328
+ function launchFromNpmPath(args) {
36329
+ const pathApi = args.platform === "win32" ? path15.win32 : path15.posix;
36330
+ if (!pathApi.isAbsolute(args.npmPath) || !args.probe.isFile(args.npmPath))
36331
+ return null;
36332
+ const extension = pathApi.extname(args.npmPath).toLowerCase();
36333
+ if ([".js", ".cjs", ".mjs"].includes(extension)) {
36334
+ return { file: args.nodePath, prefixArgs: [args.npmPath] };
36335
+ }
36336
+ if (args.platform === "win32" && [".cmd", ".bat"].includes(extension)) {
36337
+ const cliPath = pathApi.join(pathApi.dirname(args.npmPath), "node_modules", "npm", "bin", "npm-cli.js");
36338
+ return args.probe.isFile(cliPath) ? { file: args.nodePath, prefixArgs: [cliPath] } : null;
36339
+ }
36340
+ if (args.requireExecutable && !args.probe.isExecutable(args.npmPath))
36341
+ return null;
36342
+ return { file: args.npmPath, prefixArgs: [] };
36343
+ }
36344
+ function resolveNpmLaunchCommand(options = {}) {
36345
+ const env = options.env ?? process.env;
36346
+ const platform = options.platform ?? process.platform;
36347
+ const nodePath = options.nodePath ?? process.execPath;
36348
+ const probe = options.probe ?? defaultNpmLaunchFileProbe;
36349
+ const inherited = options.npmExecPath ?? env.npm_execpath;
36350
+ if (inherited) {
36351
+ const launch = launchFromNpmPath({
36352
+ npmPath: inherited,
36353
+ platform,
36354
+ nodePath,
36355
+ probe,
36356
+ requireExecutable: platform !== "win32"
36357
+ });
36358
+ if (launch)
36359
+ return launch;
36360
+ }
36361
+ const pathApi = platform === "win32" ? path15.win32 : path15.posix;
36362
+ const names = platform === "win32" ? ["npm.exe", "npm.cmd", "npm.bat", "npm"] : ["npm"];
36363
+ const pathValue = pathEnvironment(env, platform);
36364
+ for (const directory of pathValue?.split(pathApi.delimiter) ?? []) {
36365
+ if (!directory || !pathApi.isAbsolute(directory))
36366
+ continue;
36367
+ for (const name of names) {
36368
+ const launch = launchFromNpmPath({
36369
+ npmPath: pathApi.join(directory, name),
36370
+ platform,
36371
+ nodePath,
36372
+ probe,
36373
+ requireExecutable: platform !== "win32"
36374
+ });
36375
+ if (launch)
36376
+ return launch;
36377
+ }
36378
+ }
36379
+ throw new Error("npm launch context unavailable and no safe npm executable was found on PATH; daemon remains online");
35343
36380
  }
35344
36381
  function readTestPackageMap(baseDir, machineId) {
35345
36382
  if (true)
@@ -35347,10 +36384,10 @@ function readTestPackageMap(baseDir, machineId) {
35347
36384
  const filePath = updatePackageMapPath(baseDir, machineId);
35348
36385
  if (!fs10.existsSync(filePath))
35349
36386
  return null;
35350
- const stat = fs10.lstatSync(filePath);
35351
- if (!stat.isFile())
36387
+ const stat2 = fs10.lstatSync(filePath);
36388
+ if (!stat2.isFile())
35352
36389
  throw new Error("unsafe daemon update package map type");
35353
- if (process.platform !== "win32" && (stat.mode & 63) !== 0) {
36390
+ if (process.platform !== "win32" && (stat2.mode & 63) !== 0) {
35354
36391
  throw new Error("daemon update package map must be mode 0600");
35355
36392
  }
35356
36393
  const parsed = JSON.parse(fs10.readFileSync(filePath, "utf8"));
@@ -35360,7 +36397,7 @@ function readTestPackageMap(baseDir, machineId) {
35360
36397
  for (const [key, value] of Object.entries(parsed)) {
35361
36398
  if (key !== "latest" && !parseReleaseVersion(key))
35362
36399
  throw new Error("invalid daemon update package map key");
35363
- if (typeof value !== "string" || !path11.isAbsolute(value))
36400
+ if (typeof value !== "string" || !path15.isAbsolute(value))
35364
36401
  throw new Error("invalid daemon update package map value");
35365
36402
  result[key] = value;
35366
36403
  }
@@ -35374,9 +36411,9 @@ function packageSpec(baseDir, machineId, version3) {
35374
36411
  }
35375
36412
  function fixedNpmArgs(args) {
35376
36413
  return [
35377
- args.npmPath,
35378
36414
  "exec",
35379
36415
  "--yes",
36416
+ "--no-audit",
35380
36417
  `--package=${args.packageSpec}`,
35381
36418
  "--",
35382
36419
  "alook-daemon",
@@ -35407,7 +36444,13 @@ function createDaemonSelfUpdateHandler(context, deps = {}) {
35407
36444
  const current = pidTuple(readPidFile(pidfilePathById(context.baseDir, context.machineId)));
35408
36445
  if (!current || current.pid !== context.pid || current.machineId !== context.machineId || current.startedAt !== context.startedAt || current.ownerToken !== context.ownerToken)
35409
36446
  throw new Error("daemon ownership changed before update launch");
35410
- const npmPath = npmExecPath(deps.npmExecPath);
36447
+ const npmLaunch = resolveNpmLaunchCommand({
36448
+ npmExecPath: deps.npmExecPath,
36449
+ env: deps.npmLaunchEnv,
36450
+ platform: deps.npmLaunchPlatform,
36451
+ nodePath: deps.npmLaunchNodePath,
36452
+ probe: deps.npmLaunchFileProbe
36453
+ });
35411
36454
  requestId = crypto4.randomUUID();
35412
36455
  const intent = {
35413
36456
  schemaVersion: UPDATE_INTENT_SCHEMA_VERSION,
@@ -35417,14 +36460,16 @@ function createDaemonSelfUpdateHandler(context, deps = {}) {
35417
36460
  writePrivateJsonAtomic(intentPath(context.baseDir, context.machineId), intent);
35418
36461
  const logFd = openUpdateLog(context.baseDir, context.machineId);
35419
36462
  try {
35420
- const child = (deps.spawnProcess ?? spawn2)(process.execPath, fixedNpmArgs({
35421
- npmPath,
35422
- packageSpec: packageSpec(context.baseDir, context.machineId, "latest"),
35423
- command: "replace",
35424
- machineId: context.machineId,
35425
- baseDir: context.baseDir,
35426
- requestId
35427
- }), {
36463
+ const child = (deps.spawnProcess ?? spawn2)(npmLaunch.file, [
36464
+ ...npmLaunch.prefixArgs,
36465
+ ...fixedNpmArgs({
36466
+ packageSpec: packageSpec(context.baseDir, context.machineId, "latest"),
36467
+ command: "replace",
36468
+ machineId: context.machineId,
36469
+ baseDir: context.baseDir,
36470
+ requestId
36471
+ })
36472
+ ], {
35428
36473
  detached: true,
35429
36474
  shell: false,
35430
36475
  stdio: ["ignore", logFd, logFd]
@@ -35465,14 +36510,16 @@ function removeOldPidfileIfMatches(baseDir, intent) {
35465
36510
  async function runPinnedResume(args) {
35466
36511
  const fd = openUpdateLog(args.baseDir, args.machineId);
35467
36512
  try {
35468
- const child = spawn2(process.execPath, fixedNpmArgs({
35469
- npmPath: args.npmPath,
35470
- packageSpec: packageSpec(args.baseDir, args.machineId, args.version),
35471
- command: "resume",
35472
- machineId: args.machineId,
35473
- baseDir: args.baseDir,
35474
- requestId: args.requestId
35475
- }), {
36513
+ const child = spawn2(args.npmLaunch.file, [
36514
+ ...args.npmLaunch.prefixArgs,
36515
+ ...fixedNpmArgs({
36516
+ packageSpec: packageSpec(args.baseDir, args.machineId, args.version),
36517
+ command: "resume",
36518
+ machineId: args.machineId,
36519
+ baseDir: args.baseDir,
36520
+ requestId: args.requestId
36521
+ })
36522
+ ], {
35476
36523
  shell: false,
35477
36524
  stdio: ["ignore", fd, fd]
35478
36525
  });
@@ -35516,7 +36563,7 @@ async function daemonReplace(opts) {
35516
36563
  removeIntentIfMatches(baseDir, opts.id, opts.requestId);
35517
36564
  throw new Error("daemon ownership changed before replacement");
35518
36565
  }
35519
- const npmPath = npmExecPath();
36566
+ const npmLaunch = resolveNpmLaunchCommand();
35520
36567
  const acquired = acquireDaemonReplacementLock({ baseDir, machineId: opts.id, requestId: opts.requestId });
35521
36568
  let oldStopped = false;
35522
36569
  try {
@@ -35536,7 +36583,7 @@ async function daemonReplace(opts) {
35536
36583
  } catch (error51) {
35537
36584
  appendUpdateLog(baseDir, opts.id, "replacement_start_failed", { error: error51 });
35538
36585
  await runPinnedResume({
35539
- npmPath,
36586
+ npmLaunch,
35540
36587
  version: launch.daemonVersion,
35541
36588
  machineId: opts.id,
35542
36589
  baseDir,
@@ -35659,7 +36706,7 @@ async function buildRunnerDiagnosticBundle(args) {
35659
36706
  function createDaemonProcessLogger(daemonDir, foreground) {
35660
36707
  fs11.mkdirSync(daemonDir, { recursive: true, mode: 448 });
35661
36708
  fs11.chmodSync(daemonDir, 448);
35662
- const logPath = path12.join(daemonDir, "daemon.log");
36709
+ const logPath = path16.join(daemonDir, "daemon.log");
35663
36710
  let warnedOversize = false;
35664
36711
  const sink = createRotatingFileSink(logPath, DAEMON_LOG_MAX_BYTES, {
35665
36712
  mode: 384,
@@ -35895,16 +36942,16 @@ var LEGACY_DAEMON_ID_PATTERN = /^[a-f0-9]{12}$/;
35895
36942
  var DEFAULT_SERVER_URL = "https://alook.ai";
35896
36943
  var DEFAULT_WS_URL = "wss://alook.ai/api/ws/community-daemon";
35897
36944
  function resolveDefaultBaseDir() {
35898
- const root = process.env.ALOOK_PROJECT_ROOT || path13.join(homedir6(), ".alook");
35899
- return path13.join(root, "daemon");
36945
+ const root = process.env.ALOOK_PROJECT_ROOT || path17.join(homedir8(), ".alook");
36946
+ return path17.join(root, "daemon");
35900
36947
  }
35901
36948
  var DEFAULT_BASE_DIR = resolveDefaultBaseDir();
35902
36949
  var log2 = createLogger2({ header: "@alook/daemon" });
35903
36950
  function daemonsDir(baseDir) {
35904
- return path13.join(baseDir, "daemons");
36951
+ return path17.join(baseDir, "daemons");
35905
36952
  }
35906
36953
  function daemonDirById(baseDir, id) {
35907
- return path13.join(daemonsDir(baseDir), validateDaemonId(id));
36954
+ return path17.join(daemonsDir(baseDir), validateDaemonId(id));
35908
36955
  }
35909
36956
  function validateMachineId(machineId) {
35910
36957
  if (!MACHINE_ID_PATTERN.test(machineId))
@@ -35920,10 +36967,10 @@ function validateDaemonId(id) {
35920
36967
  return id;
35921
36968
  }
35922
36969
  function pidfilePathById(baseDir, id) {
35923
- return path13.join(daemonDirById(baseDir, id), "daemon.pid");
36970
+ return path17.join(daemonDirById(baseDir, id), "daemon.pid");
35924
36971
  }
35925
36972
  function statusFilePathById(baseDir, id) {
35926
- return path13.join(daemonDirById(baseDir, id), "status.json");
36973
+ return path17.join(daemonDirById(baseDir, id), "status.json");
35927
36974
  }
35928
36975
  function isProcessAlive(pid) {
35929
36976
  try {
@@ -35983,9 +37030,9 @@ function syncDirectory(dir) {
35983
37030
  }
35984
37031
  }
35985
37032
  function writeExclusive(filePath, value) {
35986
- const dir = path13.dirname(filePath);
37033
+ const dir = path17.dirname(filePath);
35987
37034
  ensurePrivateDir2(dir);
35988
- const tempPath = path13.join(dir, `.${path13.basename(filePath)}.${process.pid}.${crypto5.randomBytes(12).toString("hex")}.tmp`);
37035
+ const tempPath = path17.join(dir, `.${path17.basename(filePath)}.${process.pid}.${crypto5.randomBytes(12).toString("hex")}.tmp`);
35989
37036
  let fd = fs12.openSync(tempPath, "wx", 384);
35990
37037
  try {
35991
37038
  fs12.writeFileSync(fd, JSON.stringify(value));
@@ -36007,9 +37054,9 @@ function writeExclusive(filePath, value) {
36007
37054
  }
36008
37055
  }
36009
37056
  function writePrivateJsonAtomic2(filePath, value) {
36010
- const dir = path13.dirname(filePath);
37057
+ const dir = path17.dirname(filePath);
36011
37058
  ensurePrivateDir2(dir);
36012
- const tempPath = path13.join(dir, `.${path13.basename(filePath)}.${process.pid}.${crypto5.randomBytes(12).toString("hex")}.tmp`);
37059
+ const tempPath = path17.join(dir, `.${path17.basename(filePath)}.${process.pid}.${crypto5.randomBytes(12).toString("hex")}.tmp`);
36013
37060
  let fd = fs12.openSync(tempPath, "wx", 384);
36014
37061
  try {
36015
37062
  fs12.writeFileSync(fd, JSON.stringify(value));
@@ -36033,8 +37080,8 @@ function writePrivateJsonAtomic2(filePath, value) {
36033
37080
  function secureExistingFile(filePath) {
36034
37081
  if (!fs12.existsSync(filePath))
36035
37082
  return;
36036
- const stat = fs12.lstatSync(filePath);
36037
- if (!stat.isFile())
37083
+ const stat2 = fs12.lstatSync(filePath);
37084
+ if (!stat2.isFile())
36038
37085
  throw new Error("unsafe daemon ownership file type");
36039
37086
  fs12.chmodSync(filePath, 384);
36040
37087
  }
@@ -36096,14 +37143,14 @@ function clearStaleOwnership(filePath, liveError) {
36096
37143
  } catch {}
36097
37144
  }
36098
37145
  function replacementLockPathById(baseDir, machineId) {
36099
- return path13.join(daemonDirById(baseDir, machineId), "daemon.replace.lock");
37146
+ return path17.join(daemonDirById(baseDir, machineId), "daemon.replace.lock");
36100
37147
  }
36101
37148
  function readReplacementLock(filePath) {
36102
37149
  if (!fs12.existsSync(filePath))
36103
37150
  return null;
36104
37151
  try {
36105
- const stat = fs12.lstatSync(filePath);
36106
- if (!stat.isFile())
37152
+ const stat2 = fs12.lstatSync(filePath);
37153
+ if (!stat2.isFile())
36107
37154
  throw new Error("unsafe daemon replacement lock type");
36108
37155
  fs12.chmodSync(filePath, 384);
36109
37156
  const content = JSON.parse(fs12.readFileSync(filePath, "utf8"));
@@ -36166,7 +37213,7 @@ function checkReplacementLock(baseDir, machineId, resumeRequestId) {
36166
37213
  }
36167
37214
  function acquireDaemonReplacementLock(args) {
36168
37215
  const lockPath = replacementLockPathById(args.baseDir, args.machineId);
36169
- ensurePrivateDir2(path13.dirname(lockPath));
37216
+ ensurePrivateDir2(path17.dirname(lockPath));
36170
37217
  checkReplacementLock(args.baseDir, args.machineId);
36171
37218
  const lock = {
36172
37219
  pid: process.pid,
@@ -36179,11 +37226,11 @@ function acquireDaemonReplacementLock(args) {
36179
37226
  return { path: lockPath, lock };
36180
37227
  }
36181
37228
  function coarseStartLockPath(baseDir) {
36182
- return path13.join(daemonsDir(baseDir), ".start.lock");
37229
+ return path17.join(daemonsDir(baseDir), ".start.lock");
36183
37230
  }
36184
37231
  function acquireCoarseLock(baseDir, ownerToken) {
36185
37232
  const lf = coarseStartLockPath(baseDir);
36186
- ensurePrivateDir2(path13.dirname(lf));
37233
+ ensurePrivateDir2(path17.dirname(lf));
36187
37234
  secureExistingFile(lf);
36188
37235
  clearStaleOwnership(lf, (pid) => new Error(`another daemon start is in progress on this machine (pid ${pid})`));
36189
37236
  writeExclusive(lf, { pid: process.pid, machineId: "coarse", startedAt: new Date().toISOString(), ownerToken });
@@ -36192,7 +37239,7 @@ function acquireCoarseLock(baseDir, ownerToken) {
36192
37239
  function acquireLaunchLock(baseDir, machineId, ownerToken, resumeRequestId) {
36193
37240
  const daemonDir = daemonDirById(baseDir, machineId);
36194
37241
  ensurePrivateDir2(daemonDir);
36195
- const lockPath = path13.join(daemonDir, "daemon.launch.lock");
37242
+ const lockPath = path17.join(daemonDir, "daemon.launch.lock");
36196
37243
  const finalPath = pidfilePathById(baseDir, machineId);
36197
37244
  checkReplacementLock(baseDir, machineId, resumeRequestId);
36198
37245
  secureExistingFile(lockPath);
@@ -36214,9 +37261,9 @@ function legacyPidfileCandidates(baseDir) {
36214
37261
  const candidates = [];
36215
37262
  for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
36216
37263
  if (entry.isDirectory()) {
36217
- candidates.push(path13.join(dir, entry.name, "daemon.pid"));
37264
+ candidates.push(path17.join(dir, entry.name, "daemon.pid"));
36218
37265
  } else if (entry.isFile() && entry.name.endsWith(".pid")) {
36219
- candidates.push(path13.join(dir, entry.name));
37266
+ candidates.push(path17.join(dir, entry.name));
36220
37267
  }
36221
37268
  }
36222
37269
  return candidates;
@@ -36288,7 +37335,7 @@ function daemonList(opts) {
36288
37335
  for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
36289
37336
  if (entry.isDirectory() && isDaemonId(entry.name)) {
36290
37337
  const id = entry.name;
36291
- pushRow(id, path13.join(dir, id, "daemon.pid"), path13.join(dir, id, "status.json"));
37338
+ pushRow(id, path17.join(dir, id, "daemon.pid"), path17.join(dir, id, "status.json"));
36292
37339
  }
36293
37340
  }
36294
37341
  return results;
@@ -36336,7 +37383,7 @@ function daemonIdsWithStatus(baseDir) {
36336
37383
  return [];
36337
37384
  const ids = [];
36338
37385
  for (const entry of fs12.readdirSync(dir, { withFileTypes: true })) {
36339
- if (entry.isDirectory() && isDaemonId(entry.name) && fs12.existsSync(path13.join(dir, entry.name, "status.json"))) {
37386
+ if (entry.isDirectory() && isDaemonId(entry.name) && fs12.existsSync(path17.join(dir, entry.name, "status.json"))) {
36340
37387
  ids.push(entry.name);
36341
37388
  }
36342
37389
  }
@@ -36399,16 +37446,16 @@ async function stopByPidfile(pf, notFoundHint) {
36399
37446
  }
36400
37447
  async function daemonStop(opts) {
36401
37448
  const baseDir = opts.baseDir || process.env.ALOOK_DATA_DIR || DEFAULT_BASE_DIR;
36402
- await stopByPidfile(path13.join(daemonDirById(baseDir, opts.id), "daemon.pid"), `no daemon with id '${opts.id}' (pidfile not found — check \`alook daemon list\`)`);
37449
+ await stopByPidfile(path17.join(daemonDirById(baseDir, opts.id), "daemon.pid"), `no daemon with id '${opts.id}' (pidfile not found — check \`alook daemon list\`)`);
36403
37450
  }
36404
37451
  function credentialFilePathByMachineId(baseDir, machineId) {
36405
- return path13.join(daemonsDir(baseDir), `${validateMachineId(machineId)}.credential.json`);
37452
+ return path17.join(daemonsDir(baseDir), `${validateMachineId(machineId)}.credential.json`);
36406
37453
  }
36407
37454
  function readCredentialFile(filePath) {
36408
37455
  if (!fs12.existsSync(filePath))
36409
37456
  return null;
36410
- const stat = fs12.lstatSync(filePath);
36411
- if (!stat.isFile())
37457
+ const stat2 = fs12.lstatSync(filePath);
37458
+ if (!stat2.isFile())
36412
37459
  throw new Error("unsafe daemon credential file type");
36413
37460
  fs12.chmodSync(filePath, 384);
36414
37461
  try {
@@ -36449,7 +37496,7 @@ function findExistingCredentialForBearer(baseDir, bearer) {
36449
37496
  for (const file2 of fs12.readdirSync(dir)) {
36450
37497
  if (!file2.endsWith(".credential.json"))
36451
37498
  continue;
36452
- const parsed = readCredentialFile(path13.join(dir, file2));
37499
+ const parsed = readCredentialFile(path17.join(dir, file2));
36453
37500
  if (parsed && parsed.credential === bearer)
36454
37501
  return parsed;
36455
37502
  }
@@ -36730,7 +37777,7 @@ function waitForReceipt(child, prepared) {
36730
37777
  };
36731
37778
  const configuredTestTimeout = NaN;
36732
37779
  const receiptTimeoutMs = Number.isFinite(configuredTestTimeout) && configuredTestTimeout > 0 ? configuredTestTimeout : START_RECEIPT_TIMEOUT_MS;
36733
- const timeout = setTimeout(() => settle(new Error(`daemon start timed out; inspect ${path13.join(prepared.daemonDir, "daemon.log")}`)), receiptTimeoutMs);
37780
+ const timeout = setTimeout(() => settle(new Error(`daemon start timed out; inspect ${path17.join(prepared.daemonDir, "daemon.log")}`)), receiptTimeoutMs);
36734
37781
  child.on("message", (message2) => {
36735
37782
  const accepted = message2;
36736
37783
  if (accepted.type === "daemon:accepted") {
@@ -36749,7 +37796,7 @@ function waitForReceipt(child, prepared) {
36749
37796
  settle(undefined, receipt);
36750
37797
  });
36751
37798
  child.once("exit", (code, signal) => {
36752
- settle(new Error(`daemon child exited before ready (${signal ?? code}); inspect ${path13.join(prepared.daemonDir, "daemon.log")}`));
37799
+ settle(new Error(`daemon child exited before ready (${signal ?? code}); inspect ${path17.join(prepared.daemonDir, "daemon.log")}`));
36753
37800
  });
36754
37801
  child.once("error", (error51) => settle(error51));
36755
37802
  });
@@ -37116,6 +38163,7 @@ function stripMalformedAlookHeredocTail(input) {
37116
38163
  }
37117
38164
  var CLIENT_MAX_ATTACHMENT_BYTES = 26214400;
37118
38165
  var CLIENT_MAX_MESSAGE_BODY_BYTES = 1024;
38166
+ var INBOX_PULL_OUTPUT_DEADLINE_MS = 9000;
37119
38167
  function contentTypeFromFilename(filename) {
37120
38168
  const ext = filename.slice(filename.lastIndexOf(".") + 1).toLowerCase();
37121
38169
  switch (ext) {
@@ -37415,11 +38463,14 @@ async function cmdInboxPull(opts) {
37415
38463
  const api2 = getApi();
37416
38464
  const agent2 = agentId(opts);
37417
38465
  const max = opts.max ? Number(opts.max) : undefined;
38466
+ const pullStartedAt = performance.now();
37418
38467
  const { messages, hasMore, markedCount } = await api2.inboxPull({ agentId: agent2, max });
38468
+ const pullElapsedMs = performance.now() - pullStartedAt;
37419
38469
  const pulledAt = nowLocalISO();
37420
38470
  let acked = 0;
37421
38471
  let ackError;
37422
38472
  let failed;
38473
+ let ackDeferred;
37423
38474
  if (messages.length > 0) {
37424
38475
  const latest = new Map;
37425
38476
  for (const m of messages) {
@@ -37428,12 +38479,20 @@ async function cmdInboxPull(opts) {
37428
38479
  if (!cur || seqN > cur.seq)
37429
38480
  latest.set(m.channel, { channel: m.channel, seq: seqN });
37430
38481
  }
37431
- try {
37432
- const result = await api2.ack({ agentId: agent2, cursors: [...latest.values()] });
37433
- acked = result.applied.length;
37434
- failed = result.failed;
37435
- } catch (err) {
37436
- ackError = err instanceof Error ? err.message : String(err);
38482
+ if (pullElapsedMs >= INBOX_PULL_OUTPUT_DEADLINE_MS) {
38483
+ ackDeferred = {
38484
+ reason: "slow_pull",
38485
+ thresholdMs: INBOX_PULL_OUTPUT_DEADLINE_MS,
38486
+ elapsedMs: Math.round(pullElapsedMs)
38487
+ };
38488
+ } else {
38489
+ try {
38490
+ const result = await api2.ack({ agentId: agent2, cursors: [...latest.values()] });
38491
+ acked = result.applied.length;
38492
+ failed = result.failed;
38493
+ } catch (err) {
38494
+ ackError = err instanceof Error ? err.message : String(err);
38495
+ }
37437
38496
  }
37438
38497
  }
37439
38498
  return {
@@ -37443,6 +38502,7 @@ async function cmdInboxPull(opts) {
37443
38502
  pulledAt,
37444
38503
  ...failed ? { failed } : {},
37445
38504
  ...ackError ? { ackError } : {},
38505
+ ...ackDeferred ? { ackDeferred } : {},
37446
38506
  ...markedCount > 0 ? {
37447
38507
  markedReminder: `You have ${markedCount} marked ${markedCount === 1 ? "message" : "messages"}. Resolve ${markedCount === 1 ? "it" : "them"} before going dark unless blocked.`
37448
38508
  } : {}