@alook/daemon 0.1.24 → 0.1.25

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 +1567 -194
  2. package/dist/index.js +1525 -204
  3. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -98,7 +98,7 @@ var init_nanoid = () => {};
98
98
  // src/cli/index.ts
99
99
  import { Command, CommanderError } from "commander";
100
100
  import { realpathSync as realpathSync2 } from "node:fs";
101
- import { randomUUID as randomUUID9 } from "node:crypto";
101
+ import { randomUUID as randomUUID10 } from "node:crypto";
102
102
  import { pathToFileURL as pathToFileURL2 } from "node:url";
103
103
 
104
104
  // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
@@ -14397,6 +14397,7 @@ var exports_community_machine_schema = {};
14397
14397
  __export(exports_community_machine_schema, {
14398
14398
  communityMachineToken: () => communityMachineToken,
14399
14399
  communityMachineCredential: () => communityMachineCredential,
14400
+ communityMachineBackendQuota: () => communityMachineBackendQuota,
14400
14401
  communityMachine: () => communityMachine,
14401
14402
  communityDiagnosticReport: () => communityDiagnosticReport,
14402
14403
  communityBotBinding: () => communityBotBinding,
@@ -16000,6 +16001,8 @@ var user = sqliteTable("user", {
16000
16001
  email: text("email").unique().notNull(),
16001
16002
  emailVerified: integer2("emailVerified", { mode: "boolean" }),
16002
16003
  image: text("image"),
16004
+ avatarVersion: integer2("avatarVersion").notNull().default(0),
16005
+ avatarObjectKey: text("avatarObjectKey"),
16003
16006
  createdAt: text("createdAt").notNull().$defaultFn(() => new Date().toISOString()),
16004
16007
  updatedAt: text("updatedAt").notNull().$defaultFn(() => new Date().toISOString()),
16005
16008
  isBot: integer2("isBot", { mode: "boolean" }).notNull().default(false),
@@ -16673,8 +16676,23 @@ var communityBotBinding = sqliteTable("community_bot_binding", {
16673
16676
  runtime: text("runtime").notNull(),
16674
16677
  instruction: text("instruction").notNull().default(""),
16675
16678
  modelName: text("model_name"),
16679
+ reasoningEffort: text("reasoning_effort"),
16680
+ runtimeConfigRevision: integer2("runtime_config_revision").notNull().default(0),
16676
16681
  createdAt: text("created_at").notNull().$defaultFn(() => new Date().toISOString())
16677
16682
  }, (t) => [index("idx_community_bot_binding_machine").on(t.machineId)]);
16683
+ var communityMachineBackendQuota = sqliteTable("community_machine_backend_quota", {
16684
+ machineId: text("machine_id").notNull().references(() => communityMachine.id, { onDelete: "cascade" }),
16685
+ agentBackendId: text("agent_backend_id").$type().notNull(),
16686
+ sourceEpoch: text("source_epoch").notNull(),
16687
+ status: text("status").$type().notNull(),
16688
+ planName: text("plan_name"),
16689
+ freshForSeconds: integer2("fresh_for_seconds"),
16690
+ limits: text("limits", { mode: "json" }).$type(),
16691
+ errorCode: text("error_code"),
16692
+ retryable: integer2("retryable", { mode: "boolean" }),
16693
+ observedAt: text("observed_at").notNull(),
16694
+ updatedAt: text("updated_at").notNull()
16695
+ }, (t) => [primaryKey({ columns: [t.machineId, t.agentBackendId] })]);
16678
16696
  var communityAgentRunnerKey = sqliteTable("community_agent_runner_key", {
16679
16697
  id: text("id").primaryKey().$defaultFn(() => "crkid_" + nanoid3()),
16680
16698
  userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
@@ -16853,6 +16871,11 @@ var HostCommandSchema = exports_external.discriminatedUnion("type", [
16853
16871
  config: exports_external.unknown(),
16854
16872
  launchId: exports_external.string().min(1)
16855
16873
  }),
16874
+ exports_external.object({
16875
+ type: exports_external.literal("agent:runtime_config_update"),
16876
+ agentId: exports_external.string().min(1),
16877
+ config: exports_external.unknown()
16878
+ }),
16856
16879
  exports_external.object({
16857
16880
  type: exports_external.literal("machine:reset_all"),
16858
16881
  resets: exports_external.array(exports_external.object({
@@ -16899,7 +16922,8 @@ var MAX_MESSAGE_CONTENT_LENGTH = 4000;
16899
16922
  var MAX_EMOJI_BYTES = 32;
16900
16923
  var MAX_ATTACHMENTS_PER_MESSAGE = 10;
16901
16924
  var MAX_ATTACHMENT_SIZE_BYTES = 25 * 1024 * 1024;
16902
- var MAX_ATTACHMENT_THUMBNAIL_SIZE_BYTES = 50 * 1024;
16925
+ var MAX_ATTACHMENT_THUMBNAIL_EDGE_PX = 1024;
16926
+ var MAX_ATTACHMENT_THUMBNAIL_SIZE_BYTES = 512 * 1024;
16903
16927
  var MAX_SERVER_ICON_SIZE_BYTES = 5 * 1024 * 1024;
16904
16928
  var ALLOWED_ICON_MIME_TYPES = [
16905
16929
  "image/png",
@@ -16908,6 +16932,92 @@ var ALLOWED_ICON_MIME_TYPES = [
16908
16932
  "image/gif"
16909
16933
  ];
16910
16934
  var MAX_ICON_SOURCE_FILE_SIZE_BYTES = 15 * 1024 * 1024;
16935
+ // ../shared/src/provider-telemetry.ts
16936
+ var safeToken = exports_external.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
16937
+ var boundedText = exports_external.string().min(1).refine((value) => new TextEncoder().encode(value).length <= 64, { message: "must be at most 64 UTF-8 bytes" });
16938
+ var DailyUsageMetricSchema = safeToken.nullable();
16939
+ var DailyUsageSnapshotSchema = exports_external.object({
16940
+ botId: exports_external.string().min(1),
16941
+ day: exports_external.string().regex(/^\d{4}-\d{2}-\d{2}$/),
16942
+ metrics: exports_external.object({
16943
+ input: DailyUsageMetricSchema,
16944
+ output: DailyUsageMetricSchema,
16945
+ cache: DailyUsageMetricSchema
16946
+ }).strict()
16947
+ }).strict();
16948
+ var QuotaProductIdentitySchema = exports_external.discriminatedUnion("kind", [
16949
+ exports_external.object({ kind: exports_external.literal("reported"), id: boundedText, displayName: boundedText }).strict(),
16950
+ exports_external.object({ kind: exports_external.literal("unknown"), displayName: boundedText }).strict()
16951
+ ]);
16952
+ var QuotaModelIdentitySchema = exports_external.discriminatedUnion("kind", [
16953
+ exports_external.object({ kind: exports_external.literal("reported"), id: boundedText }).strict(),
16954
+ exports_external.object({ kind: exports_external.literal("not_applicable") }).strict(),
16955
+ exports_external.object({ kind: exports_external.literal("unknown") }).strict()
16956
+ ]);
16957
+ var QuotaWindowIdentitySchema = exports_external.discriminatedUnion("kind", [
16958
+ exports_external.object({
16959
+ kind: exports_external.literal("rolling"),
16960
+ durationSeconds: exports_external.number().int().positive().max(Number.MAX_SAFE_INTEGER),
16961
+ displayName: boundedText
16962
+ }).strict(),
16963
+ exports_external.object({
16964
+ kind: exports_external.literal("calendar"),
16965
+ period: exports_external.enum(["day", "week", "month"]),
16966
+ displayName: boundedText
16967
+ }).strict(),
16968
+ exports_external.object({
16969
+ kind: exports_external.literal("provider_defined"),
16970
+ id: boundedText,
16971
+ durationSeconds: exports_external.number().int().positive().max(Number.MAX_SAFE_INTEGER).optional(),
16972
+ displayName: boundedText
16973
+ }).strict()
16974
+ ]);
16975
+ var QuotaLimitSchema = exports_external.object({
16976
+ bucket: exports_external.object({
16977
+ limitId: boundedText,
16978
+ product: QuotaProductIdentitySchema,
16979
+ model: QuotaModelIdentitySchema,
16980
+ window: QuotaWindowIdentitySchema
16981
+ }).strict(),
16982
+ usedPercent: exports_external.number().finite().min(0).max(100),
16983
+ resetsAt: exports_external.string().datetime({ offset: true }).optional()
16984
+ }).strict();
16985
+ function quotaIdentity(limit) {
16986
+ const { product, model, window: window2, limitId } = limit.bucket;
16987
+ const productKey = product.kind === "reported" ? `reported:${product.id}` : "unknown";
16988
+ const modelKey = model.kind === "reported" ? `reported:${model.id}` : model.kind;
16989
+ const windowKey = window2.kind === "rolling" ? `rolling:${window2.durationSeconds}` : window2.kind === "calendar" ? `calendar:${window2.period}` : `provider_defined:${window2.id}:${window2.durationSeconds === undefined ? "absent" : window2.durationSeconds}`;
16990
+ return `${productKey}\x00${modelKey}\x00${windowKey}\x00${limitId}`;
16991
+ }
16992
+ var AvailableQuotaObservationSchema = exports_external.object({
16993
+ status: exports_external.literal("available"),
16994
+ sourceEpoch: exports_external.string().regex(/^[A-Za-z0-9_-]{22}$/),
16995
+ planName: boundedText.optional(),
16996
+ freshForSeconds: exports_external.number().int().positive().max(86400),
16997
+ limits: exports_external.array(QuotaLimitSchema).min(1).max(8)
16998
+ }).strict().superRefine((value, ctx) => {
16999
+ const identities = new Set;
17000
+ for (const [index2, limit] of value.limits.entries()) {
17001
+ const identity = quotaIdentity(limit);
17002
+ if (identities.has(identity)) {
17003
+ ctx.addIssue({ code: "custom", message: "duplicate quota bucket identity", path: ["limits", index2] });
17004
+ }
17005
+ identities.add(identity);
17006
+ }
17007
+ });
17008
+ var ProviderQuotaObservationSchema = exports_external.union([
17009
+ AvailableQuotaObservationSchema,
17010
+ exports_external.object({
17011
+ status: exports_external.literal("error"),
17012
+ sourceEpoch: exports_external.string().regex(/^[A-Za-z0-9_-]{22}$/),
17013
+ code: exports_external.enum(["unavailable", "unauthorized", "network", "provider_error", "invalid_response"]),
17014
+ retryable: exports_external.boolean()
17015
+ }).strict()
17016
+ ]);
17017
+ var ProviderQuotaSnapshotSchema = exports_external.object({
17018
+ agentBackendId: exports_external.enum(["claude", "codex"]),
17019
+ observation: ProviderQuotaObservationSchema
17020
+ }).strict();
16911
17021
  // ../shared/src/utils/slug.ts
16912
17022
  init_nanoid();
16913
17023
  var slugId = customAlphabet("0123456789abcdefghijklmnopqrstuvwxyz");
@@ -17422,12 +17532,60 @@ var CreateThreadRequestSchema = exports_external.object({
17422
17532
  attachment_ids: exports_external.array(exports_external.string()).optional()
17423
17533
  });
17424
17534
  var RUNTIME_ID_RE = /^[A-Za-z0-9._@/-]+$/;
17535
+ var REASONING_EFFORT_RE = /^[A-Za-z0-9._-]+$/;
17536
+ var COMMUNITY_REASONING_EFFORT_MAX = 32;
17537
+ var COMMUNITY_REASONING_DESCRIPTION_MAX = 256;
17538
+ var COMMUNITY_REASONING_OPTIONS_MAX = 16;
17539
+ var COMMUNITY_REASONING_MODELS_MAX = 64;
17540
+ var ReasoningEffortSchema = exports_external.string().min(1).max(COMMUNITY_REASONING_EFFORT_MAX).regex(REASONING_EFFORT_RE, "invalid reasoning effort charset");
17541
+ var RuntimeReasoningOptionSchema = exports_external.object({
17542
+ value: ReasoningEffortSchema,
17543
+ description: exports_external.string().max(COMMUNITY_REASONING_DESCRIPTION_MAX).optional()
17544
+ });
17545
+ var RuntimeReasoningModelSchema = exports_external.object({
17546
+ id: exports_external.string().min(1).max(100),
17547
+ supportedReasoningEfforts: exports_external.array(exports_external.unknown()).max(COMMUNITY_REASONING_OPTIONS_MAX).transform((options) => {
17548
+ const seen = new Set;
17549
+ return options.flatMap((candidate) => {
17550
+ const parsed = RuntimeReasoningOptionSchema.safeParse(candidate);
17551
+ if (!parsed.success)
17552
+ return [];
17553
+ const option = parsed.data;
17554
+ if (seen.has(option.value))
17555
+ return [];
17556
+ seen.add(option.value);
17557
+ return [option];
17558
+ });
17559
+ }),
17560
+ defaultReasoningEffort: ReasoningEffortSchema.optional().catch(undefined)
17561
+ }).transform((model) => {
17562
+ const { defaultReasoningEffort, ...rest } = model;
17563
+ return defaultReasoningEffort !== undefined && model.supportedReasoningEfforts.some((option) => option.value === defaultReasoningEffort) ? { ...rest, defaultReasoningEffort } : rest;
17564
+ });
17565
+ var RuntimeReasoningCatalogSchema = exports_external.object({
17566
+ updateMode: exports_external.enum(["live_next_turn", "context_preserving_restart", "unsupported"]),
17567
+ defaultModelId: exports_external.string().min(1).max(100).optional().catch(undefined),
17568
+ models: exports_external.array(exports_external.unknown()).max(COMMUNITY_REASONING_MODELS_MAX).transform((models) => {
17569
+ const seen = new Set;
17570
+ return models.flatMap((candidate) => {
17571
+ const parsed = RuntimeReasoningModelSchema.safeParse(candidate);
17572
+ if (!parsed.success)
17573
+ return [];
17574
+ const model = parsed.data;
17575
+ if (seen.has(model.id))
17576
+ return [];
17577
+ seen.add(model.id);
17578
+ return [model];
17579
+ });
17580
+ })
17581
+ });
17425
17582
  var CommunityMachineRuntimeSchema = exports_external.object({
17426
17583
  id: exports_external.string().min(1).max(COMMUNITY_RUNTIME_ID_MAX).regex(RUNTIME_ID_RE, "invalid runtime id charset"),
17427
17584
  version: exports_external.string().max(COMMUNITY_RUNTIME_VERSION_MAX).optional(),
17428
17585
  status: exports_external.enum(["healthy", "unhealthy"]).catch("healthy").default("healthy"),
17429
17586
  lastError: exports_external.string().max(128).optional(),
17430
- lastErrorAt: exports_external.string().optional()
17587
+ lastErrorAt: exports_external.string().optional(),
17588
+ reasoning: RuntimeReasoningCatalogSchema.optional().catch(undefined)
17431
17589
  });
17432
17590
  var CommunityMachineRuntimeListSchema = exports_external.array(CommunityMachineRuntimeSchema).max(COMMUNITY_RUNTIME_LIST_MAX).transform((list) => {
17433
17591
  const seen = new Set;
@@ -17479,7 +17637,8 @@ var HostReadyMessageSchema = exports_external.object({
17479
17637
  platform: exports_external.string().optional(),
17480
17638
  arch: exports_external.string().optional(),
17481
17639
  osRelease: exports_external.string().optional(),
17482
- daemonVersion: exports_external.string().optional()
17640
+ daemonVersion: exports_external.string().optional(),
17641
+ providerQuotas: exports_external.array(ProviderQuotaSnapshotSchema).max(2).optional().default([])
17483
17642
  });
17484
17643
  var CommunityDaemonReadySchema = exports_external.object({
17485
17644
  runtimeReport: CommunityMachineRuntimeListSchema.optional(),
@@ -17500,7 +17659,9 @@ var SessionErrorFrameSchema = exports_external.object({
17500
17659
  var AgentActivityMessageSchema = exports_external.object({
17501
17660
  type: exports_external.literal("agent_activity"),
17502
17661
  agentId: exports_external.string(),
17503
- state: exports_external.enum(["idle", "starting", "running", "stopping"])
17662
+ state: exports_external.enum(["idle", "starting", "running", "stopping"]),
17663
+ dailyUsage: exports_external.array(DailyUsageSnapshotSchema).max(7).optional(),
17664
+ quota: ProviderQuotaSnapshotSchema.optional()
17504
17665
  });
17505
17666
  var AgentTypingMessageSchema = exports_external.object({
17506
17667
  type: exports_external.literal("agent_typing"),
@@ -17575,15 +17736,17 @@ var CommunityBotCreateRequestSchema = exports_external.object({
17575
17736
  machineId: exports_external.string().min(1),
17576
17737
  runtime: exports_external.string().min(1),
17577
17738
  image: BotImageUrlSchema.optional(),
17578
- model: exports_external.string().trim().min(1).max(100).nullable().optional()
17739
+ model: exports_external.string().trim().min(1).max(100).nullable().optional(),
17740
+ reasoningEffort: ReasoningEffortSchema.nullable().optional()
17579
17741
  });
17580
17742
  var CommunityBotPatchRequestSchema = exports_external.object({
17581
17743
  name: exports_external.string().trim().min(COMMUNITY_BOT_NAME_MIN).max(COMMUNITY_BOT_NAME_MAX).refine(isMentionSafeName, { message: MENTION_SAFE_NAME_MSG }).optional(),
17582
17744
  description: exports_external.string().max(COMMUNITY_BOT_DESCRIPTION_MAX).optional(),
17583
17745
  image: BotImageUrlSchema.nullable().optional(),
17584
17746
  model: exports_external.string().trim().min(1).max(100).nullable().optional(),
17585
- runtime: exports_external.string().trim().min(1).max(COMMUNITY_RUNTIME_ID_MAX).optional()
17586
- }).refine((v) => v.name !== undefined || v.description !== undefined || v.image !== undefined || v.runtime !== undefined || ("model" in v), {
17747
+ runtime: exports_external.string().trim().min(1).max(COMMUNITY_RUNTIME_ID_MAX).optional(),
17748
+ reasoningEffort: ReasoningEffortSchema.nullable().optional()
17749
+ }).refine((v) => v.name !== undefined || v.description !== undefined || v.image !== undefined || v.runtime !== undefined || ("reasoningEffort" in v) || ("model" in v), {
17587
17750
  message: "at least one field must be provided"
17588
17751
  });
17589
17752
  var CommunityBotAddToServerRequestSchema = exports_external.object({
@@ -17785,6 +17948,7 @@ __export(exports_community_schema, {
17785
17948
  communityChannelMember: () => communityChannelMember,
17786
17949
  communityChannel: () => communityChannel,
17787
17950
  communityCategory: () => communityCategory,
17951
+ communityBotDailyTokenUsage: () => communityBotDailyTokenUsage,
17788
17952
  communityBotDailyActivity: () => communityBotDailyActivity,
17789
17953
  communityBotApprovalRequest: () => communityBotApprovalRequest,
17790
17954
  communityBotActivityEvent: () => communityBotActivityEvent,
@@ -18037,6 +18201,17 @@ var communityBotDailyActivity = sqliteTable("community_bot_daily_activity", {
18037
18201
  handledCount: integer2("handled_count").notNull().default(0),
18038
18202
  sentCount: integer2("sent_count").notNull().default(0)
18039
18203
  }, (t) => [primaryKey({ columns: [t.botId, t.day] })]);
18204
+ var communityBotDailyTokenUsage = sqliteTable("community_bot_daily_token_usage", {
18205
+ botId: text("bot_id").notNull().references(() => user.id, { onDelete: "cascade" }),
18206
+ day: text("day").notNull(),
18207
+ inputTokens: integer2("input_tokens"),
18208
+ outputTokens: integer2("output_tokens"),
18209
+ cacheTokens: integer2("cache_tokens"),
18210
+ updatedAt: text("updated_at").notNull()
18211
+ }, (t) => [
18212
+ primaryKey({ columns: [t.botId, t.day] }),
18213
+ index("idx_community_bot_daily_token_usage_day").on(t.day)
18214
+ ]);
18040
18215
  var communityMessageMark = sqliteTable("community_message_mark", {
18041
18216
  id: text("id").primaryKey().$defaultFn(() => nanoid3()),
18042
18217
  userId: text("user_id").notNull().references(() => user.id, { onDelete: "cascade" }),
@@ -18161,7 +18336,8 @@ var listedMessageProjection = {
18161
18336
  clientNonce: communityMessage.clientNonce,
18162
18337
  authorName: user.name,
18163
18338
  authorEmail: user.email,
18164
- authorImage: user.image
18339
+ authorImage: user.image,
18340
+ authorAvatarVersion: user.avatarVersion
18165
18341
  };
18166
18342
 
18167
18343
  // ../shared/src/db/queries/user.ts
@@ -18171,6 +18347,7 @@ var publicUserColumns = {
18171
18347
  email: user.email,
18172
18348
  emailVerified: user.emailVerified,
18173
18349
  image: user.image,
18350
+ avatarVersion: user.avatarVersion,
18174
18351
  createdAt: user.createdAt,
18175
18352
  updatedAt: user.updatedAt,
18176
18353
  discriminator: user.discriminator
@@ -18181,6 +18358,12 @@ var internalUserColumns = {
18181
18358
  ownerUserId: user.ownerUserId,
18182
18359
  deletedAt: user.deletedAt
18183
18360
  };
18361
+ var avatarPublishColumns = {
18362
+ id: user.id,
18363
+ image: user.image,
18364
+ avatarVersion: user.avatarVersion,
18365
+ avatarObjectKey: user.avatarObjectKey
18366
+ };
18184
18367
 
18185
18368
  // ../shared/src/db/queries/community/channel.ts
18186
18369
  var CHANNEL_COLUMNS = {
@@ -18233,7 +18416,8 @@ var friendApprovalProfileSchema = exports_external.strictObject({
18233
18416
  id: string4,
18234
18417
  name: string4,
18235
18418
  discriminator: string4,
18236
- image: nullableString
18419
+ image: nullableString,
18420
+ avatarVersion: exports_external.number().int().nonnegative()
18237
18421
  });
18238
18422
  var FriendApprovalPayloadSchema = exports_external.strictObject({
18239
18423
  friendshipId: string4,
@@ -18259,6 +18443,7 @@ var messageSchema = exports_external.strictObject({
18259
18443
  authorId: string4,
18260
18444
  authorName: string4,
18261
18445
  authorAvatar: string4.optional(),
18446
+ authorAvatarVersion: exports_external.number().int().nonnegative(),
18262
18447
  content: string4,
18263
18448
  type: exports_external.enum(["chat", "system"]),
18264
18449
  systemKind: exports_external.literal("thread").optional(),
@@ -18266,6 +18451,7 @@ var messageSchema = exports_external.strictObject({
18266
18451
  replyToId: nullableString.optional(),
18267
18452
  replyTo: exports_external.strictObject({
18268
18453
  id: string4,
18454
+ authorId: string4.optional(),
18269
18455
  authorName: string4,
18270
18456
  text: string4,
18271
18457
  deleted: exports_external.boolean().optional()
@@ -18460,6 +18646,7 @@ var communityMemberJoinSchema = exports_external.strictObject({
18460
18646
  name: string4,
18461
18647
  discriminator: string4,
18462
18648
  avatar: string4.optional(),
18649
+ avatarVersion: exports_external.number().int().nonnegative(),
18463
18650
  role: string4,
18464
18651
  joinedAt: string4
18465
18652
  })
@@ -18562,6 +18749,22 @@ var communityStatusUpdateSchema = exports_external.strictObject({
18562
18749
  statusEmoji: nullableString,
18563
18750
  statusText: nullableString
18564
18751
  });
18752
+ var communityIdentityUpdateSchema = exports_external.strictObject({
18753
+ type: exports_external.literal("community:identity.update"),
18754
+ userId: string4,
18755
+ avatar: string4,
18756
+ avatarVersion: exports_external.number().int().positive()
18757
+ });
18758
+ var communityProfileUpdateSchema = exports_external.strictObject({
18759
+ type: exports_external.literal("community:profile.update"),
18760
+ userId: string4,
18761
+ name: string4,
18762
+ discriminator: string4,
18763
+ aboutMe: string4,
18764
+ bannerColor: nullableString,
18765
+ kind: exports_external.enum(["human", "bot"]),
18766
+ ownerUserId: nullableString
18767
+ });
18565
18768
  var machineRuntimeSchema = CommunityMachineRuntimeSchema.strict();
18566
18769
  var CommunityMachineSummarySchema2 = exports_external.strictObject({
18567
18770
  id: string4,
@@ -18650,6 +18853,8 @@ var CommunityWsEventDiscriminatedSchema = exports_external.discriminatedUnion("t
18650
18853
  communityInboxChangedSchema,
18651
18854
  communityPresenceUpdateSchema,
18652
18855
  communityStatusUpdateSchema,
18856
+ communityIdentityUpdateSchema,
18857
+ communityProfileUpdateSchema,
18653
18858
  communityMachineCreatedSchema,
18654
18859
  communityMachineStatusSchema,
18655
18860
  communityMachineUpdatedSchema,
@@ -18696,6 +18901,8 @@ var WS_EVENTS = {
18696
18901
  INBOX_CHANGED: "community:inbox.changed",
18697
18902
  PRESENCE_UPDATE: "community:presence.update",
18698
18903
  STATUS_UPDATE: "community:status.update",
18904
+ IDENTITY_UPDATE: "community:identity.update",
18905
+ PROFILE_UPDATE: "community:profile.update",
18699
18906
  MACHINE_CREATED: "community:machine.created",
18700
18907
  MACHINE_STATUS: "community:machine.status",
18701
18908
  MACHINE_UPDATED: "community:machine.updated",
@@ -19274,7 +19481,7 @@ import * as fs12 from "fs";
19274
19481
  import * as path13 from "path";
19275
19482
  import * as crypto5 from "crypto";
19276
19483
  import * as os3 from "os";
19277
- import { homedir as homedir5 } from "os";
19484
+ import { homedir as homedir6 } from "os";
19278
19485
 
19279
19486
  // src/discovery.ts
19280
19487
  import * as path9 from "path";
@@ -20054,6 +20261,9 @@ class ProcessLane {
20054
20261
  return false;
20055
20262
  return proc.kill("SIGINT");
20056
20263
  }
20264
+ updateSettings(input) {
20265
+ return this.driver.updateSettings?.(input) ?? Promise.resolve({ status: "unsupported" });
20266
+ }
20057
20267
  attachProcess(proc) {
20058
20268
  proc.stdout?.on("data", (chunk2) => {
20059
20269
  const chunkText = chunk2.toString();
@@ -20441,25 +20651,19 @@ class ClaudeEventNormalizer {
20441
20651
  }
20442
20652
  buildUsageTelemetry(event) {
20443
20653
  const u = event?.usage;
20444
- if (!u && event?.total_cost_usd == null)
20654
+ if (!u)
20445
20655
  return null;
20656
+ const metric = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
20657
+ const cacheParts = [u.cache_read_input_tokens, u.cache_creation_input_tokens].filter((value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0);
20658
+ const cache = cacheParts.length > 0 && Number.isSafeInteger(cacheParts.reduce((sum, value) => sum + value, 0)) ? cacheParts.reduce((sum, value) => sum + value, 0) : null;
20446
20659
  return {
20447
20660
  kind: "telemetry",
20448
20661
  name: "token_usage",
20449
20662
  source: "claude_result_usage",
20450
- usageKind: "per_turn",
20451
- attrs: {
20452
- inputTokens: u?.input_tokens,
20453
- outputTokens: u?.output_tokens,
20454
- cachedInputTokens: u?.cache_read_input_tokens,
20455
- cacheCreationInputTokens: u?.cache_creation_input_tokens,
20456
- totalCostUsd: event?.total_cost_usd,
20457
- durationMs: event?.duration_ms,
20458
- durationApiMs: event?.duration_api_ms,
20459
- numTurns: event?.num_turns,
20460
- resultSubtype: event?.subtype,
20461
- resultIsError: event?.is_error,
20462
- serviceTier: u?.service_tier
20663
+ usage: {
20664
+ input: metric(u.input_tokens),
20665
+ output: metric(u.output_tokens),
20666
+ cache
20463
20667
  }
20464
20668
  };
20465
20669
  }
@@ -20691,49 +20895,153 @@ class ClaudeDriver {
20691
20895
  }
20692
20896
 
20693
20897
  // agent-driver/dist/adapters/codex/telemetry.js
20694
- function mapCodexTelemetry(method, params) {
20898
+ function metric(value) {
20899
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
20900
+ }
20901
+ function nonCachedInput(input, cached2) {
20902
+ if (typeof input !== "number" || !Number.isSafeInteger(input) || input < 0 || typeof cached2 !== "number" || !Number.isSafeInteger(cached2) || cached2 < 0 || cached2 > input)
20903
+ return null;
20904
+ return input - cached2;
20905
+ }
20906
+ function canonicalId(value, fallback) {
20907
+ return typeof value === "string" && value.length > 0 && new TextEncoder().encode(value).length <= 64 ? value : fallback;
20908
+ }
20909
+ function mappedPlanName(value) {
20910
+ switch (value) {
20911
+ case "free":
20912
+ return "Free";
20913
+ case "plus":
20914
+ return "Plus";
20915
+ case "pro":
20916
+ return "Pro";
20917
+ case "team":
20918
+ return "Team";
20919
+ case "business":
20920
+ return "Business";
20921
+ case "enterprise":
20922
+ return "Enterprise";
20923
+ case "edu":
20924
+ return "Education";
20925
+ default:
20926
+ return;
20927
+ }
20928
+ }
20929
+ function quotaWindow(minutes, slot) {
20930
+ if (typeof minutes !== "number" || !Number.isSafeInteger(minutes) || minutes <= 0)
20931
+ return null;
20932
+ if (minutes === 1440)
20933
+ return { kind: "calendar", period: "day", displayName: "Daily usage limit" };
20934
+ if (minutes === 10080)
20935
+ return { kind: "calendar", period: "week", displayName: "Weekly usage limit" };
20936
+ if (minutes === 43200)
20937
+ return { kind: "calendar", period: "month", displayName: "Monthly usage limit" };
20938
+ return {
20939
+ kind: "rolling",
20940
+ durationSeconds: minutes * 60,
20941
+ displayName: slot === "primary" && minutes === 300 ? "5 hour usage limit" : `${minutes} minute usage limit`
20942
+ };
20943
+ }
20944
+ function resetIso(value) {
20945
+ if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
20946
+ const date5 = new Date(value < 10000000000 ? value * 1000 : value);
20947
+ return Number.isNaN(date5.getTime()) ? undefined : date5.toISOString();
20948
+ }
20949
+ if (typeof value === "string") {
20950
+ const date5 = new Date(value);
20951
+ return Number.isNaN(date5.getTime()) ? undefined : date5.toISOString();
20952
+ }
20953
+ return;
20954
+ }
20955
+ function mapCodexQuotaSnapshots(snapshots, sourceEpoch) {
20956
+ const limits = [];
20957
+ let planName;
20958
+ for (const snapshot of snapshots) {
20959
+ const limitId = canonicalId(snapshot?.limitId ?? snapshot?.limit_id, "codex");
20960
+ const spark = /spark/i.test(limitId) || /spark/i.test(String(snapshot?.limitName ?? snapshot?.limit_name ?? ""));
20961
+ const product = spark ? { kind: "reported", id: "codex-spark", displayName: "Spark" } : { kind: "reported", id: "codex", displayName: "Codex" };
20962
+ const model = spark ? { kind: "reported", id: "gpt-5.3-codex-spark" } : { kind: "not_applicable" };
20963
+ planName ??= mappedPlanName(snapshot?.planType ?? snapshot?.plan_type);
20964
+ for (const slot of ["primary", "secondary"]) {
20965
+ const value = snapshot?.[slot];
20966
+ const window2 = quotaWindow(value?.windowDurationMins ?? value?.window_duration_mins, slot);
20967
+ const usedPercent = value?.usedPercent ?? value?.used_percent;
20968
+ if (!window2 || typeof usedPercent !== "number" || !Number.isFinite(usedPercent) || usedPercent < 0 || usedPercent > 100)
20969
+ continue;
20970
+ const resetsAt = resetIso(value?.resetsAt ?? value?.resets_at);
20971
+ limits.push({
20972
+ bucket: { limitId, product, model, window: window2 },
20973
+ usedPercent,
20974
+ ...resetsAt ? { resetsAt } : {}
20975
+ });
20976
+ }
20977
+ }
20978
+ if (limits.length === 0) {
20979
+ return {
20980
+ kind: "telemetry",
20981
+ name: "rate_limits",
20982
+ source: "codex_account_rate_limits_updated",
20983
+ quota: { status: "error", sourceEpoch, code: "invalid_response", retryable: true }
20984
+ };
20985
+ }
20986
+ return {
20987
+ kind: "telemetry",
20988
+ name: "rate_limits",
20989
+ source: "codex_account_rate_limits_updated",
20990
+ quota: {
20991
+ status: "available",
20992
+ sourceEpoch,
20993
+ ...planName ? { planName } : {},
20994
+ freshForSeconds: 300,
20995
+ limits
20996
+ }
20997
+ };
20998
+ }
20999
+ function mapCodexTelemetry(method, params, sourceEpoch) {
20695
21000
  if (method === "thread/tokenUsage/updated") {
20696
- const u = params?.usage ?? params ?? {};
20697
- return [
20698
- {
20699
- kind: "telemetry",
20700
- name: "token_usage",
20701
- source: "codex_thread_token_usage_updated",
20702
- usageKind: "cumulative_session",
20703
- attrs: {
20704
- totalTokens: u.totalTokens ?? u.total_tokens,
20705
- inputTokens: u.inputTokens ?? u.input_tokens,
20706
- cachedInputTokens: u.cachedInputTokens ?? u.cached_input_tokens,
20707
- outputTokens: u.outputTokens ?? u.output_tokens,
20708
- reasoningOutputTokens: u.reasoningOutputTokens ?? u.reasoning_output_tokens,
20709
- modelContextWindow: u.modelContextWindow ?? u.model_context_window,
20710
- cachedInputRatio: u.cachedInputRatio,
20711
- contextUtilization: u.contextUtilization
20712
- }
21001
+ const u = params?.tokenUsage?.last ?? params?.token_usage?.last;
21002
+ if (!u)
21003
+ return [];
21004
+ const input = u.inputTokens ?? u.input_tokens;
21005
+ const cached2 = u.cachedInputTokens ?? u.cached_input_tokens;
21006
+ return [{
21007
+ kind: "telemetry",
21008
+ name: "token_usage",
21009
+ source: "codex_thread_token_usage_updated",
21010
+ usage: {
21011
+ input: nonCachedInput(input, cached2),
21012
+ output: metric(u.outputTokens ?? u.output_tokens),
21013
+ cache: metric(cached2)
20713
21014
  }
20714
- ];
21015
+ }];
20715
21016
  }
20716
21017
  if (method === "account/rateLimits/updated") {
20717
- const r = params ?? {};
20718
- return [
20719
- {
20720
- kind: "telemetry",
20721
- name: "rate_limits",
20722
- source: "codex_account_rate_limits_updated",
20723
- attrs: {
20724
- limitId: r.limitId,
20725
- planType: r.planType,
20726
- usedPercent: r.usedPercent,
20727
- windowDurationMins: r.windowDurationMins,
20728
- resetsAt: r.resetsAt
20729
- }
20730
- }
20731
- ];
21018
+ return [mapCodexQuotaSnapshots([params?.rateLimits ?? params ?? {}], sourceEpoch)];
20732
21019
  }
20733
21020
  return [];
20734
21021
  }
20735
21022
 
20736
21023
  // agent-driver/dist/adapters/codex/normalizer.js
21024
+ import { randomBytes } from "node:crypto";
21025
+ var codexQuotaSourceEpoch = randomBytes(16).toString("base64url");
21026
+ var codexQuotaSourceGeneration = 0;
21027
+ var codexAccountFingerprint = null;
21028
+ function rotateCodexQuotaSource() {
21029
+ codexQuotaSourceEpoch = randomBytes(16).toString("base64url");
21030
+ codexQuotaSourceGeneration += 1;
21031
+ codexAccountFingerprint = null;
21032
+ }
21033
+ function observeCodexAccount(result) {
21034
+ const account2 = result?.account;
21035
+ const fingerprint = account2 && typeof account2 === "object" ? JSON.stringify([
21036
+ account2.type ?? "unknown",
21037
+ account2.email ?? null,
21038
+ account2.planType ?? account2.plan_type ?? null
21039
+ ]) : "none";
21040
+ if (codexAccountFingerprint !== null && codexAccountFingerprint !== fingerprint) {
21041
+ rotateCodexQuotaSource();
21042
+ }
21043
+ codexAccountFingerprint = fingerprint;
21044
+ }
20737
21045
  function normalizeFileChangeInput(item) {
20738
21046
  const paths = [];
20739
21047
  const seen = new Set;
@@ -20756,6 +21064,12 @@ function normalizeFileChangeInput(item) {
20756
21064
  }
20757
21065
 
20758
21066
  class CodexEventNormalizer {
21067
+ quotaReadRequestIds = new Set;
21068
+ accountReadRequestIds = new Set;
21069
+ rateLimitSnapshots = new Map;
21070
+ quotaSnapshotInitialized = false;
21071
+ quotaSourceGeneration = codexQuotaSourceGeneration;
21072
+ pendingTurnUsage = null;
20759
21073
  threadId = null;
20760
21074
  turnId = null;
20761
21075
  terminalTurn = null;
@@ -20766,10 +21080,69 @@ class CodexEventNormalizer {
20766
21080
  get currentTurnId() {
20767
21081
  return this.turnId;
20768
21082
  }
21083
+ registerQuotaReadRequest(requestId) {
21084
+ this.quotaReadRequestIds.add(requestId);
21085
+ }
21086
+ registerAccountReadRequest(requestId) {
21087
+ this.accountReadRequestIds.add(requestId);
21088
+ }
21089
+ syncQuotaSourceGeneration() {
21090
+ if (this.quotaSourceGeneration === codexQuotaSourceGeneration)
21091
+ return;
21092
+ this.quotaSourceGeneration = codexQuotaSourceGeneration;
21093
+ this.rateLimitSnapshots.clear();
21094
+ this.quotaSnapshotInitialized = false;
21095
+ }
21096
+ quotaSnapshots(value) {
21097
+ const byLimitId = value?.rateLimitsByLimitId ?? value?.rate_limits_by_limit_id;
21098
+ if (byLimitId && typeof byLimitId === "object" && !Array.isArray(byLimitId)) {
21099
+ return Object.entries(byLimitId).flatMap(([key2, snapshot2]) => {
21100
+ if (!snapshot2 || typeof snapshot2 !== "object" || Array.isArray(snapshot2))
21101
+ return [];
21102
+ return [[key2, {
21103
+ ...snapshot2,
21104
+ limitId: snapshot2.limitId ?? snapshot2.limit_id ?? key2
21105
+ }]];
21106
+ });
21107
+ }
21108
+ const snapshot = value?.rateLimits ?? value?.rate_limits ?? value;
21109
+ if (!snapshot || typeof snapshot !== "object" || Array.isArray(snapshot))
21110
+ return [];
21111
+ const record2 = snapshot;
21112
+ const key = typeof record2.limitId === "string" ? record2.limitId : typeof record2.limit_id === "string" ? record2.limit_id : "codex";
21113
+ return [[key, { ...record2, limitId: key }]];
21114
+ }
21115
+ replaceQuotaSnapshots(value) {
21116
+ this.syncQuotaSourceGeneration();
21117
+ this.rateLimitSnapshots.clear();
21118
+ for (const [key, snapshot] of this.quotaSnapshots(value)) {
21119
+ this.rateLimitSnapshots.set(key, snapshot);
21120
+ }
21121
+ this.quotaSnapshotInitialized = true;
21122
+ return [mapCodexQuotaSnapshots([...this.rateLimitSnapshots.values()], codexQuotaSourceEpoch)];
21123
+ }
21124
+ mergeQuotaSnapshots(value) {
21125
+ this.syncQuotaSourceGeneration();
21126
+ for (const [key, update] of this.quotaSnapshots(value)) {
21127
+ const merged = {
21128
+ ...this.rateLimitSnapshots.get(key) ?? {},
21129
+ limitId: key
21130
+ };
21131
+ for (const [field, fieldValue] of Object.entries(update)) {
21132
+ if (fieldValue !== undefined && fieldValue !== null)
21133
+ merged[field] = fieldValue;
21134
+ }
21135
+ this.rateLimitSnapshots.set(key, merged);
21136
+ }
21137
+ if (!this.quotaSnapshotInitialized)
21138
+ return [];
21139
+ return [mapCodexQuotaSnapshots([...this.rateLimitSnapshots.values()], codexQuotaSourceEpoch)];
21140
+ }
20769
21141
  adoptThreadId(threadId) {
20770
21142
  if (threadId !== this.threadId) {
20771
21143
  this.turnId = null;
20772
21144
  this.terminalTurn = null;
21145
+ this.pendingTurnUsage = null;
20773
21146
  }
20774
21147
  this.threadId = threadId;
20775
21148
  }
@@ -20787,6 +21160,25 @@ class CodexEventNormalizer {
20787
21160
  const msg = tryParseJsonLine(line);
20788
21161
  if (!msg)
20789
21162
  return [];
21163
+ if (msg?.id !== undefined && this.accountReadRequestIds.delete(msg.id)) {
21164
+ if (!msg.error) {
21165
+ observeCodexAccount(msg.result);
21166
+ this.syncQuotaSourceGeneration();
21167
+ }
21168
+ return [];
21169
+ }
21170
+ if (msg?.id !== undefined && this.quotaReadRequestIds.delete(msg.id)) {
21171
+ this.syncQuotaSourceGeneration();
21172
+ if (msg.error) {
21173
+ return [{
21174
+ kind: "telemetry",
21175
+ name: "rate_limits",
21176
+ source: "codex_account_rate_limits_read",
21177
+ quota: { status: "error", sourceEpoch: codexQuotaSourceEpoch, code: "provider_error", retryable: true }
21178
+ }];
21179
+ }
21180
+ return this.replaceQuotaSnapshots(msg.result ?? {});
21181
+ }
20790
21182
  if (msg?.error && msg.id !== undefined) {
20791
21183
  return [{ kind: "error", message: msg.error?.message ?? "Codex RPC error" }];
20792
21184
  }
@@ -20811,6 +21203,7 @@ class CodexEventNormalizer {
20811
21203
  return [];
20812
21204
  this.turnId = params.turn.id;
20813
21205
  this.terminalTurn = null;
21206
+ this.pendingTurnUsage = null;
20814
21207
  return [
20815
21208
  {
20816
21209
  kind: "turn_owner",
@@ -20839,24 +21232,36 @@ class CodexEventNormalizer {
20839
21232
  case "turn/completed":
20840
21233
  if (!this.acceptRootTerminal(params))
20841
21234
  return [];
21235
+ const usage = this.pendingTurnUsage;
21236
+ this.pendingTurnUsage = null;
20842
21237
  if (params.turn.status === "failed") {
20843
21238
  return [
21239
+ ...usage ? [usage] : [],
20844
21240
  { kind: "error", message: "Codex turn failed" },
20845
21241
  { kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }
20846
21242
  ];
20847
21243
  }
20848
21244
  if (params.turn.status === "interrupted") {
20849
- return [{ kind: "error", message: "Codex turn interrupted" }, { kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
21245
+ return [...usage ? [usage] : [], { kind: "error", message: "Codex turn interrupted" }, { kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
20850
21246
  }
20851
- return [{ kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
21247
+ return [...usage ? [usage] : [], { kind: "turn_end", sessionId: this.threadId ?? undefined, turnOwner: this.turnReceipt(params.threadId, params.turn.id) }];
20852
21248
  case "error":
20853
21249
  if (params?.willRetry === true) {
20854
21250
  return [{ kind: "runtime_recovery", stage: "retrying", source: "codex_stream" }];
20855
21251
  }
20856
21252
  return [{ kind: "error", message: params?.error?.message ?? params?.message ?? "Codex error" }];
20857
- case "thread/tokenUsage/updated":
21253
+ case "thread/tokenUsage/updated": {
21254
+ const usage2 = mapCodexTelemetry(method, params, codexQuotaSourceEpoch)[0];
21255
+ if (usage2)
21256
+ this.pendingTurnUsage = usage2;
21257
+ return [];
21258
+ }
20858
21259
  case "account/rateLimits/updated":
20859
- return mapCodexTelemetry(method, params);
21260
+ return this.mergeQuotaSnapshots(params);
21261
+ case "account/updated":
21262
+ rotateCodexQuotaSource();
21263
+ this.syncQuotaSourceGeneration();
21264
+ return [];
20860
21265
  default:
20861
21266
  return [];
20862
21267
  }
@@ -20969,7 +21374,53 @@ function resolveCodexHomeRootFromEnv(env = process.env, opts = {}) {
20969
21374
  return path6.join(opts.defaultHomeDir ?? os.homedir(), ".codex");
20970
21375
  }
20971
21376
 
21377
+ // agent-driver/dist/internal/errors.js
21378
+ var MAX_PUBLIC_ERROR_MESSAGE = 1000;
21379
+ var CREDENTIAL_NAME = String.raw`(?:[A-Za-z0-9]{1,32}[_-]){0,4}(?:api[_-]?key|access[_-]?key|secret(?:[_-]?access[_-]?key)?|client[_-]?secret|access[_-]?token|auth(?:orization)?|password|passwd|token|voucher)(?:[_-][A-Za-z0-9]{1,32}){0,4}`;
21380
+ var QUOTED_CREDENTIAL_ASSIGNMENT = new RegExp(String.raw`(["'])(${CREDENTIAL_NAME})\1\s*[:=]\s*(["'])[^"'\r\n]*\3`, "gi");
21381
+ var CREDENTIAL_ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9_-])((?:${CREDENTIAL_NAME})\s*[:=]\s*)(?!\[redacted\])[^\s,;}\]]+`, "gi");
21382
+ function scrubDriverErrorMessage(value, fallback = "Runtime operation failed") {
21383
+ const text2 = value instanceof Error ? value.message : String(value ?? "");
21384
+ const scrubbed = text2.replace(/\b(?:cmk|cmt|crk)_[A-Za-z0-9_-]+\b/g, "[redacted-token]").replace(/(Authorization\s*:\s*)(?:Bearer|Basic)\s+[^\s,;]+/gi, "$1[redacted]").replace(/Bearer\s+[A-Za-z0-9._\-]+/gi, "Bearer [redacted]").replace(/\b(?:sk|sk-ant|sk-proj|xox[abprs])-[A-Za-z0-9._\-]+/gi, "[redacted-token]").replace(QUOTED_CREDENTIAL_ASSIGNMENT, "$1$2$1:$3[redacted]$3").replace(CREDENTIAL_ASSIGNMENT, "$1[redacted]").replace(/(?<![A-Za-z0-9._%+\-])[A-Za-z0-9._%+\-]{1,320}@[A-Za-z0-9.\-]{1,255}\.[A-Za-z]{2,63}/g, "[redacted-email]").replace(/([?&])([^=\s]+)=([^&\s]+)/g, "$1$2=[redacted]").replace(/\/(?:Users|home)\/[^\r\n,;]+/g, "[redacted-path]").replace(/[A-Za-z]:\\Users\\[^\r\n,;]+/gi, "[redacted-path]").replace(/\\\\[^\\\s]+\\[^\r\n,;]+/g, "[redacted-path]").replace(/(?:[A-Za-z]:\\|\/)(?:[^\s/:]+[\\/]){1,}[^\s:]*/g, "[redacted-path]").trim();
21385
+ return (scrubbed || fallback).slice(0, MAX_PUBLIC_ERROR_MESSAGE);
21386
+ }
21387
+ function scrubDriverError(error51) {
21388
+ return {
21389
+ ...error51,
21390
+ code: stableErrorCode(error51.code, "runtime_error"),
21391
+ message: scrubDriverErrorMessage(error51.message),
21392
+ ...error51.details ? { details: scrubDetails(error51.details) } : {}
21393
+ };
21394
+ }
21395
+ function scrubDetails(details) {
21396
+ const scrubValue = (value, key) => {
21397
+ if (key && /api[_-]?key|access[_-]?token|auth(?:orization)?|password|passwd|secret|token/i.test(key)) {
21398
+ return "[redacted]";
21399
+ }
21400
+ if (typeof value === "string")
21401
+ return scrubDriverErrorMessage(value, "[redacted]");
21402
+ if (Array.isArray(value))
21403
+ return value.map((item) => scrubValue(item));
21404
+ if (value && typeof value === "object") {
21405
+ return Object.fromEntries(Object.entries(value).map(([childKey, child]) => [
21406
+ childKey,
21407
+ scrubValue(child, childKey)
21408
+ ]));
21409
+ }
21410
+ return value;
21411
+ };
21412
+ return scrubValue(details);
21413
+ }
21414
+ function stableErrorCode(value, fallback) {
21415
+ const code = String(value ?? "");
21416
+ return /^[A-Za-z0-9_.-]{1,100}$/.test(code) ? code : fallback;
21417
+ }
21418
+
20972
21419
  // agent-driver/dist/adapters/codex/index.js
21420
+ var SETTINGS_UPDATE_TIMEOUT_MS = 5000;
21421
+ var MODEL_LIST_TIMEOUT_MS = 5000;
21422
+ var MODEL_LIST_MAX = 64;
21423
+ var MODEL_EFFORT_MAX = 16;
20973
21424
  function isCodexMissingRolloutError(message2) {
20974
21425
  return /\bno\s+rollout\s+found\b/i.test(message2) || /\bmissing\s+rollout\b/i.test(message2) || /\brollout\b.*\b(not found|missing)\b/i.test(message2) || /\b(not found|missing)\b.*\brollout\b/i.test(message2);
20975
21426
  }
@@ -20990,19 +21441,157 @@ class CodexDriver {
20990
21441
  }
20991
21442
  };
20992
21443
  eventNormalizer = new CodexEventNormalizer;
21444
+ pendingAccountReadRequestIds = new Set;
20993
21445
  requestId = 0;
20994
21446
  codexHomeRoot = null;
20995
21447
  proc = null;
20996
21448
  pendingInitialPrompt = null;
20997
21449
  pendingResumeFallbackParams = null;
21450
+ pendingSettingsUpdates = new Map;
20998
21451
  nextRequestId() {
20999
21452
  return ++this.requestId;
21000
21453
  }
21454
+ requestAccountQuotaSnapshot() {
21455
+ if (!this.proc?.stdin || this.proc.stdin.destroyed)
21456
+ return;
21457
+ const accountReadRequestId = this.nextRequestId();
21458
+ this.pendingAccountReadRequestIds.add(accountReadRequestId);
21459
+ this.eventNormalizer.registerAccountReadRequest(accountReadRequestId);
21460
+ this.proc.stdin.write(jsonRpcRequest("account/read", { refreshToken: false }, accountReadRequestId) + `
21461
+ `);
21462
+ }
21463
+ requestQuotaSnapshot() {
21464
+ if (!this.proc?.stdin || this.proc.stdin.destroyed)
21465
+ return;
21466
+ const quotaReadRequestId = this.nextRequestId();
21467
+ this.eventNormalizer.registerQuotaReadRequest(quotaReadRequestId);
21468
+ this.proc.stdin.write(jsonRpcRequest("account/rateLimits/read", {}, quotaReadRequestId) + `
21469
+ `);
21470
+ }
21001
21471
  get codexHome() {
21002
21472
  return this.codexHomeRoot;
21003
21473
  }
21004
- probe(command) {
21005
- return probeCliRuntime("codex", {}, command);
21474
+ async probe(command) {
21475
+ const result = await probeCliRuntime("codex", {}, command);
21476
+ if (result.status !== "healthy")
21477
+ return result;
21478
+ return {
21479
+ ...result,
21480
+ reasoning: await this.probeReasoningCatalog(command)
21481
+ };
21482
+ }
21483
+ async probeReasoningCatalog(command) {
21484
+ const spec = resolveSpawnSpec("codex", ["app-server", "--listen", "stdio://"], command);
21485
+ let proc;
21486
+ try {
21487
+ proc = spawnAgentProcess(spec.command, spec.args, {
21488
+ cwd: process.cwd(),
21489
+ env: { ...process.env, CI: "1" },
21490
+ shell: spec.shell
21491
+ });
21492
+ } catch {
21493
+ return;
21494
+ }
21495
+ return new Promise((resolve2) => {
21496
+ let settled = false;
21497
+ let buffer = "";
21498
+ let nextId = 0;
21499
+ let initializeId = 0;
21500
+ let listId = 0;
21501
+ const models = [];
21502
+ const seenModels = new Set;
21503
+ let defaultModelId;
21504
+ const finish = (catalog) => {
21505
+ if (settled)
21506
+ return;
21507
+ settled = true;
21508
+ clearTimeout(timer);
21509
+ const done = proc.pid ? killProcessTree(proc.pid, { graceMs: 250 }).catch(() => {}) : Promise.resolve().then(() => {
21510
+ proc.kill("SIGTERM");
21511
+ });
21512
+ done.finally(() => resolve2(catalog));
21513
+ };
21514
+ const requestModelPage = (cursor) => {
21515
+ listId = ++nextId;
21516
+ proc.stdin?.write(jsonRpcRequest("model/list", { limit: Math.min(MODEL_LIST_MAX - models.length, MODEL_LIST_MAX), includeHidden: false, ...cursor ? { cursor } : {} }, listId) + `
21517
+ `);
21518
+ };
21519
+ const consumeModel = (value) => {
21520
+ if (!value || typeof value !== "object" || models.length >= MODEL_LIST_MAX)
21521
+ return;
21522
+ const model = value;
21523
+ const id = typeof model.id === "string" ? model.id.trim() : "";
21524
+ if (!id || id.length > 100 || seenModels.has(id))
21525
+ return;
21526
+ const rawOptions = Array.isArray(model.supportedReasoningEfforts) ? model.supportedReasoningEfforts : [];
21527
+ const seenEfforts = new Set;
21528
+ const supportedReasoningEfforts = rawOptions.flatMap((raw) => {
21529
+ if (!raw || typeof raw !== "object")
21530
+ return [];
21531
+ const option = raw;
21532
+ const value2 = typeof option.reasoningEffort === "string" ? option.reasoningEffort.trim() : "";
21533
+ if (!value2 || value2.length > 32 || !/^[A-Za-z0-9._-]+$/.test(value2) || seenEfforts.has(value2))
21534
+ return [];
21535
+ seenEfforts.add(value2);
21536
+ const description = typeof option.description === "string" ? option.description.slice(0, 256) : undefined;
21537
+ return [{ value: value2, ...description ? { description } : {} }];
21538
+ }).slice(0, MODEL_EFFORT_MAX);
21539
+ const candidateDefault = typeof model.defaultReasoningEffort === "string" ? model.defaultReasoningEffort : undefined;
21540
+ seenModels.add(id);
21541
+ if (model.isDefault === true)
21542
+ defaultModelId = id;
21543
+ models.push({
21544
+ id,
21545
+ supportedReasoningEfforts,
21546
+ ...candidateDefault && supportedReasoningEfforts.some((item) => item.value === candidateDefault) ? { defaultReasoningEffort: candidateDefault } : {}
21547
+ });
21548
+ };
21549
+ const onLine = (line) => {
21550
+ let message2;
21551
+ try {
21552
+ message2 = JSON.parse(line);
21553
+ } catch {
21554
+ return;
21555
+ }
21556
+ if (message2.id === initializeId) {
21557
+ if (message2.error)
21558
+ return finish();
21559
+ requestModelPage();
21560
+ return;
21561
+ }
21562
+ if (message2.id !== listId)
21563
+ return;
21564
+ if (message2.error || !message2.result || typeof message2.result !== "object")
21565
+ return finish();
21566
+ const result = message2.result;
21567
+ for (const model of Array.isArray(result.data) ? result.data : [])
21568
+ consumeModel(model);
21569
+ const cursor = typeof result.nextCursor === "string" ? result.nextCursor : undefined;
21570
+ if (cursor && models.length < MODEL_LIST_MAX)
21571
+ return requestModelPage(cursor);
21572
+ finish({
21573
+ updateMode: "live_next_turn",
21574
+ ...defaultModelId ? { defaultModelId } : {},
21575
+ models
21576
+ });
21577
+ };
21578
+ const timer = setTimeout(() => finish(), MODEL_LIST_TIMEOUT_MS);
21579
+ timer.unref?.();
21580
+ proc.stdout?.on("data", (chunk2) => {
21581
+ buffer += chunk2.toString();
21582
+ const lines = buffer.split(`
21583
+ `);
21584
+ buffer = lines.pop() ?? "";
21585
+ for (const line of lines)
21586
+ if (line.trim())
21587
+ onLine(line);
21588
+ });
21589
+ proc.on("error", () => finish());
21590
+ proc.on("exit", () => finish());
21591
+ initializeId = ++nextId;
21592
+ proc.stdin?.write(jsonRpcRequest("initialize", { clientInfo: { name: "alook-agent-driver-probe", version: "0.1.24" }, capabilities: { experimentalApi: true } }, initializeId) + `
21593
+ `);
21594
+ });
21006
21595
  }
21007
21596
  async openLane(ctx, options) {
21008
21597
  return createProcessLane(this, ctx, { onRawStdoutLine: options?.onRawStdoutLine });
@@ -21018,6 +21607,9 @@ class CodexDriver {
21018
21607
  shell: spec.shell
21019
21608
  });
21020
21609
  this.proc = proc;
21610
+ proc.once("exit", () => {
21611
+ this.failPendingSettingsUpdates("settings_process_exited", "Codex exited before acknowledging the settings update");
21612
+ });
21021
21613
  const initialPrompt = ctx.prompt?.trim() ? ctx.prompt : null;
21022
21614
  this.pendingInitialPrompt = initialPrompt;
21023
21615
  queueMicrotask(() => {
@@ -21046,11 +21638,21 @@ class CodexDriver {
21046
21638
  proc.stdin?.write(jsonRpcRequest("thread/start", freshParams, this.nextRequestId()) + `
21047
21639
  `);
21048
21640
  }
21641
+ this.requestAccountQuotaSnapshot();
21049
21642
  });
21050
21643
  return { process: proc };
21051
21644
  }
21052
21645
  normalizeLine(line) {
21646
+ const settingsResponse = this.consumeSettingsUpdateResponse(line);
21647
+ if (settingsResponse)
21648
+ return [];
21649
+ const parsed = tryParseJsonLine(line);
21053
21650
  const events = this.eventNormalizer.normalizeLine(line);
21651
+ if (typeof parsed?.id === "number" && this.pendingAccountReadRequestIds.delete(parsed.id)) {
21652
+ this.requestQuotaSnapshot();
21653
+ }
21654
+ if (parsed?.method === "account/updated")
21655
+ this.requestAccountQuotaSnapshot();
21054
21656
  if (this.pendingResumeFallbackParams && this.proc?.stdin && !this.proc.stdin.destroyed) {
21055
21657
  const rolloutErr = events.find((e) => e.kind === "error" && isCodexMissingRolloutError(e.message));
21056
21658
  if (rolloutErr) {
@@ -21074,6 +21676,90 @@ class CodexDriver {
21074
21676
  }
21075
21677
  return events;
21076
21678
  }
21679
+ updateSettings(input) {
21680
+ const threadId = this.eventNormalizer.currentSessionId;
21681
+ const stdin = this.proc?.stdin;
21682
+ if (!threadId || !stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false) {
21683
+ return Promise.resolve({
21684
+ status: "failed",
21685
+ error: this.settingsError("process", "settings_thread_unavailable", "Codex thread is not available for a settings update", true)
21686
+ });
21687
+ }
21688
+ const id = this.nextRequestId();
21689
+ return new Promise((resolve2) => {
21690
+ const timer = setTimeout(() => {
21691
+ if (!this.pendingSettingsUpdates.delete(id))
21692
+ return;
21693
+ resolve2({
21694
+ status: "failed",
21695
+ error: this.settingsError("timeout", "settings_update_timeout", "Codex did not acknowledge the settings update before the deadline", true)
21696
+ });
21697
+ }, SETTINGS_UPDATE_TIMEOUT_MS);
21698
+ timer.unref?.();
21699
+ this.pendingSettingsUpdates.set(id, { resolve: resolve2, timer });
21700
+ try {
21701
+ stdin.write(jsonRpcRequest("thread/settings/update", { threadId, effort: input.reasoningEffort }, id) + `
21702
+ `);
21703
+ } catch (error51) {
21704
+ clearTimeout(timer);
21705
+ this.pendingSettingsUpdates.delete(id);
21706
+ resolve2({
21707
+ status: "failed",
21708
+ error: this.settingsError("process", "settings_update_write_failed", String(error51), true)
21709
+ });
21710
+ }
21711
+ });
21712
+ }
21713
+ consumeSettingsUpdateResponse(line) {
21714
+ let value;
21715
+ try {
21716
+ value = JSON.parse(line);
21717
+ } catch {
21718
+ return false;
21719
+ }
21720
+ if (!value || typeof value !== "object")
21721
+ return false;
21722
+ const record2 = value;
21723
+ if (typeof record2.id !== "number")
21724
+ return false;
21725
+ const pending = this.pendingSettingsUpdates.get(record2.id);
21726
+ if (!pending)
21727
+ return false;
21728
+ clearTimeout(pending.timer);
21729
+ this.pendingSettingsUpdates.delete(record2.id);
21730
+ const error51 = record2.error;
21731
+ if (!error51 || typeof error51 !== "object") {
21732
+ pending.resolve({ status: "applied" });
21733
+ return true;
21734
+ }
21735
+ const rpcError = error51;
21736
+ const message2 = typeof rpcError.message === "string" ? rpcError.message : "Codex rejected the settings update";
21737
+ if (rpcError.code === -32601 || /method\s+not\s+found/i.test(message2)) {
21738
+ pending.resolve({
21739
+ status: "unsupported",
21740
+ error: this.settingsError("protocol", "settings_update_unsupported", "Codex does not support live reasoning settings updates", false)
21741
+ });
21742
+ } else {
21743
+ pending.resolve({
21744
+ status: "failed",
21745
+ error: this.settingsError("protocol", "settings_update_rejected", message2, true)
21746
+ });
21747
+ }
21748
+ return true;
21749
+ }
21750
+ settingsError(category, code, message2, retryable) {
21751
+ return { category, code, message: scrubDriverErrorMessage(message2), retryable };
21752
+ }
21753
+ failPendingSettingsUpdates(code, message2) {
21754
+ for (const [id, pending] of this.pendingSettingsUpdates) {
21755
+ clearTimeout(pending.timer);
21756
+ this.pendingSettingsUpdates.delete(id);
21757
+ pending.resolve({
21758
+ status: "failed",
21759
+ error: this.settingsError("process", code, message2, true)
21760
+ });
21761
+ }
21762
+ }
21077
21763
  get currentSessionId() {
21078
21764
  return this.eventNormalizer.currentSessionId;
21079
21765
  }
@@ -21392,15 +22078,6 @@ class CursorAcpLane {
21392
22078
  }
21393
22079
  this.activePrompt = null;
21394
22080
  this.openToolCalls.clear();
21395
- const usage = record2(result.usage);
21396
- if (usage) {
21397
- this.events.emit("runtime_event", {
21398
- kind: "telemetry",
21399
- name: "token_usage",
21400
- source: "cursor.acp",
21401
- attrs: usage
21402
- });
21403
- }
21404
22081
  this.events.emit("runtime_event", {
21405
22082
  kind: "turn_end",
21406
22083
  sessionId: this.sessionId ?? undefined,
@@ -21750,10 +22427,10 @@ class CursorDriver {
21750
22427
  }
21751
22428
 
21752
22429
  // agent-driver/dist/adapters/opencode/index.js
21753
- import { randomBytes as randomBytes2 } from "node:crypto";
22430
+ import { randomBytes as randomBytes3 } from "node:crypto";
21754
22431
 
21755
22432
  // agent-driver/dist/adapters/opencode/service-lane.js
21756
- import { randomBytes } from "node:crypto";
22433
+ import { randomBytes as randomBytes2 } from "node:crypto";
21757
22434
  import { EventEmitter as EventEmitter3 } from "node:events";
21758
22435
  import { createServer as createServer2 } from "node:net";
21759
22436
  var SUPPORTED_VERSION = "1.17.20";
@@ -21892,7 +22569,7 @@ class OpenCodeServiceLane {
21892
22569
  this.ctx = ctx;
21893
22570
  this.options = options;
21894
22571
  this.fetchFn = options.fetch ?? fetch;
21895
- this.password = options.password ?? randomBytes(32).toString("base64url");
22572
+ this.password = options.password ?? randomBytes2(32).toString("base64url");
21896
22573
  }
21897
22574
  get currentSessionId() {
21898
22575
  return this.sessionId;
@@ -22506,12 +23183,20 @@ class OpenCodeServiceLane {
22506
23183
  });
22507
23184
  }
22508
23185
  const tokens = record3(data.tokens);
22509
- if (tokens) {
23186
+ if (tokens && data.finish !== "tool-calls") {
23187
+ const cache = record3(tokens.cache);
23188
+ const metric2 = (value2) => typeof value2 === "number" && Number.isSafeInteger(value2) && value2 >= 0 ? value2 : null;
23189
+ const cacheParts = [cache?.read, cache?.write].filter((value2) => typeof value2 === "number" && Number.isSafeInteger(value2) && value2 >= 0);
23190
+ const cacheTotal = cacheParts.reduce((sum, value2) => sum + value2, 0);
22510
23191
  this.events.emit("runtime_event", {
22511
23192
  kind: "telemetry",
22512
23193
  name: "token_usage",
22513
23194
  source: "opencode.v2",
22514
- attrs: tokens
23195
+ usage: {
23196
+ input: metric2(tokens.input),
23197
+ output: metric2(tokens.output),
23198
+ cache: cacheParts.length > 0 && Number.isSafeInteger(cacheTotal) ? cacheTotal : null
23199
+ }
22515
23200
  });
22516
23201
  }
22517
23202
  break;
@@ -22817,7 +23502,7 @@ class OpenCodeServiceLane {
22817
23502
  return headers;
22818
23503
  }
22819
23504
  newMessageId() {
22820
- return `msg_${randomBytes(16).toString("hex")}`;
23505
+ return `msg_${randomBytes2(16).toString("hex")}`;
22821
23506
  }
22822
23507
  diagnostic(severity, message2) {
22823
23508
  this.events.emit("runtime_event", {
@@ -22882,7 +23567,7 @@ class OpenCodeServiceLane {
22882
23567
 
22883
23568
  // agent-driver/dist/adapters/opencode/index.js
22884
23569
  function createOpenCodeMessageId() {
22885
- return `msg_${randomBytes2(16).toString("hex")}`;
23570
+ return `msg_${randomBytes3(16).toString("hex")}`;
22886
23571
  }
22887
23572
 
22888
23573
  class OpenCodeDriver {
@@ -23660,48 +24345,6 @@ function assertInstructionFileName(name) {
23660
24345
  }
23661
24346
  }
23662
24347
 
23663
- // agent-driver/dist/internal/errors.js
23664
- var MAX_PUBLIC_ERROR_MESSAGE = 1000;
23665
- var CREDENTIAL_NAME = String.raw`(?:[A-Za-z0-9]{1,32}[_-]){0,4}(?:api[_-]?key|access[_-]?key|secret(?:[_-]?access[_-]?key)?|client[_-]?secret|access[_-]?token|auth(?:orization)?|password|passwd|token|voucher)(?:[_-][A-Za-z0-9]{1,32}){0,4}`;
23666
- var QUOTED_CREDENTIAL_ASSIGNMENT = new RegExp(String.raw`(["'])(${CREDENTIAL_NAME})\1\s*[:=]\s*(["'])[^"'\r\n]*\3`, "gi");
23667
- var CREDENTIAL_ASSIGNMENT = new RegExp(String.raw`(?<![A-Za-z0-9_-])((?:${CREDENTIAL_NAME})\s*[:=]\s*)(?!\[redacted\])[^\s,;}\]]+`, "gi");
23668
- function scrubDriverErrorMessage(value, fallback = "Runtime operation failed") {
23669
- const text2 = value instanceof Error ? value.message : String(value ?? "");
23670
- const scrubbed = text2.replace(/\b(?:cmk|cmt|crk)_[A-Za-z0-9_-]+\b/g, "[redacted-token]").replace(/(Authorization\s*:\s*)(?:Bearer|Basic)\s+[^\s,;]+/gi, "$1[redacted]").replace(/Bearer\s+[A-Za-z0-9._\-]+/gi, "Bearer [redacted]").replace(/\b(?:sk|sk-ant|sk-proj|xox[abprs])-[A-Za-z0-9._\-]+/gi, "[redacted-token]").replace(QUOTED_CREDENTIAL_ASSIGNMENT, "$1$2$1:$3[redacted]$3").replace(CREDENTIAL_ASSIGNMENT, "$1[redacted]").replace(/(?<![A-Za-z0-9._%+\-])[A-Za-z0-9._%+\-]{1,320}@[A-Za-z0-9.\-]{1,255}\.[A-Za-z]{2,63}/g, "[redacted-email]").replace(/([?&])([^=\s]+)=([^&\s]+)/g, "$1$2=[redacted]").replace(/\/(?:Users|home)\/[^\r\n,;]+/g, "[redacted-path]").replace(/[A-Za-z]:\\Users\\[^\r\n,;]+/gi, "[redacted-path]").replace(/\\\\[^\\\s]+\\[^\r\n,;]+/g, "[redacted-path]").replace(/(?:[A-Za-z]:\\|\/)(?:[^\s/:]+[\\/]){1,}[^\s:]*/g, "[redacted-path]").trim();
23671
- return (scrubbed || fallback).slice(0, MAX_PUBLIC_ERROR_MESSAGE);
23672
- }
23673
- function scrubDriverError(error51) {
23674
- return {
23675
- ...error51,
23676
- code: stableErrorCode(error51.code, "runtime_error"),
23677
- message: scrubDriverErrorMessage(error51.message),
23678
- ...error51.details ? { details: scrubDetails(error51.details) } : {}
23679
- };
23680
- }
23681
- function scrubDetails(details) {
23682
- const scrubValue = (value, key) => {
23683
- if (key && /api[_-]?key|access[_-]?token|auth(?:orization)?|password|passwd|secret|token/i.test(key)) {
23684
- return "[redacted]";
23685
- }
23686
- if (typeof value === "string")
23687
- return scrubDriverErrorMessage(value, "[redacted]");
23688
- if (Array.isArray(value))
23689
- return value.map((item) => scrubValue(item));
23690
- if (value && typeof value === "object") {
23691
- return Object.fromEntries(Object.entries(value).map(([childKey, child]) => [
23692
- childKey,
23693
- scrubValue(child, childKey)
23694
- ]));
23695
- }
23696
- return value;
23697
- };
23698
- return scrubValue(details);
23699
- }
23700
- function stableErrorCode(value, fallback) {
23701
- const code = String(value ?? "");
23702
- return /^[A-Za-z0-9_.-]{1,100}$/.test(code) ? code : fallback;
23703
- }
23704
-
23705
24348
  // agent-driver/dist/controller/logical-session.js
23706
24349
  import { mkdirSync as mkdirSync4 } from "node:fs";
23707
24350
  var SEMANTIC_ASSEMBLER_MAX_BYTES = 1048576;
@@ -23819,6 +24462,8 @@ class LogicalAgentSession {
23819
24462
  toolBoundaryFlushDisabled = false;
23820
24463
  safeBoundaryFlush;
23821
24464
  safeBoundaryDelivery;
24465
+ settingsUpdateTail = Promise.resolve();
24466
+ settingsUpdatePending = false;
23822
24467
  turnAdmission;
23823
24468
  instructionsMaterialized = false;
23824
24469
  lifecycleGeneration = 0;
@@ -23874,6 +24519,35 @@ class LogicalAgentSession {
23874
24519
  send(message2) {
23875
24520
  return this.admit("send", message2);
23876
24521
  }
24522
+ updateSettings(input) {
24523
+ if (this.state === "closed" || this.state === "stopping" || this.finishing) {
24524
+ return Promise.resolve({
24525
+ status: "failed",
24526
+ error: driverError("process", "settings_session_closed", "Runtime session is closed", true)
24527
+ });
24528
+ }
24529
+ this.settingsUpdatePending = true;
24530
+ const operation = this.settingsUpdateTail.then(async () => {
24531
+ if (!this.lane?.updateSettings)
24532
+ return { status: "unsupported" };
24533
+ try {
24534
+ return await this.lane.updateSettings(input);
24535
+ } catch (error51) {
24536
+ return {
24537
+ status: "failed",
24538
+ error: driverError("process", "settings_update_failed", String(error51), true)
24539
+ };
24540
+ }
24541
+ });
24542
+ this.settingsUpdateTail = operation.then((result) => {
24543
+ if (result.status === "applied") {
24544
+ this.settingsUpdatePending = false;
24545
+ return;
24546
+ }
24547
+ return new Promise(() => {});
24548
+ });
24549
+ return operation;
24550
+ }
23877
24551
  async interrupt(input) {
23878
24552
  if (this.state === "closed" || this.state === "stopping" || this.finishing)
23879
24553
  return { status: "closed" };
@@ -24035,7 +24709,7 @@ class LogicalAgentSession {
24035
24709
  }
24036
24710
  return receipt;
24037
24711
  }
24038
- if (this.state === "idle" && (this.queued.length > 0 || this.safeBoundaryFlush !== undefined || this.safeBoundaryDelivery !== undefined)) {
24712
+ if (this.state === "idle" && (this.queued.length > 0 || this.safeBoundaryFlush !== undefined || this.safeBoundaryDelivery !== undefined || this.settingsUpdatePending)) {
24039
24713
  return this.queue(message2, "runtime_busy");
24040
24714
  }
24041
24715
  return this.startTurn([message2], "prompt");
@@ -24343,11 +25017,10 @@ class LogicalAgentSession {
24343
25017
  }
24344
25018
  return;
24345
25019
  case "telemetry": {
24346
- const details = jsonValue(event.attrs);
24347
25020
  if (event.name === "token_usage") {
24348
- this.emit({ type: "token_usage", turnId, source: event.source, usage: {}, details });
25021
+ this.emit({ type: "token_usage", turnId, source: event.source, usage: event.usage });
24349
25022
  } else {
24350
- this.emit({ type: "rate_limits", turnId, source: event.source, details });
25023
+ this.emit({ type: "rate_limits", turnId, source: event.source, quota: event.quota });
24351
25024
  }
24352
25025
  return;
24353
25026
  }
@@ -24448,7 +25121,7 @@ class LogicalAgentSession {
24448
25121
  if (this.adapter.execution.lifetime === "turn") {
24449
25122
  this.processTurnEnded = true;
24450
25123
  } else {
24451
- Promise.resolve().then(() => this.safeBoundaryFlush).then(() => this.startNextQueued());
25124
+ Promise.resolve().then(() => this.safeBoundaryFlush).then(() => this.settingsUpdateTail).then(() => this.startNextQueued());
24452
25125
  }
24453
25126
  }
24454
25127
  flushSafeBoundaryQueue() {
@@ -24948,8 +25621,14 @@ function createAgentDriverSdkWithRegistry(options) {
24948
25621
  assertAdapterCompatibility(String(registration.id), registration.capabilities, adapter);
24949
25622
  const command = capabilities2.commandOverride ? input.command : undefined;
24950
25623
  const result = await adapter.probe(command);
24951
- if (result.status === "healthy")
24952
- return { status: "healthy", version: result.version, capabilities: capabilities2 };
25624
+ if (result.status === "healthy") {
25625
+ return {
25626
+ status: "healthy",
25627
+ version: result.version,
25628
+ capabilities: capabilities2,
25629
+ reasoning: result.reasoning
25630
+ };
25631
+ }
24953
25632
  return {
24954
25633
  status: "unhealthy",
24955
25634
  error: {
@@ -24958,7 +25637,8 @@ function createAgentDriverSdkWithRegistry(options) {
24958
25637
  message: `Backend ${input.backend} is unavailable`,
24959
25638
  retryable: true
24960
25639
  },
24961
- capabilities: capabilities2
25640
+ capabilities: capabilities2,
25641
+ reasoning: result.reasoning
24962
25642
  };
24963
25643
  } catch (error51) {
24964
25644
  const contractInvalid = error51 instanceof Error && (error51.message.startsWith("Adapter ") || error51.message.startsWith("Agent backend registration "));
@@ -25110,7 +25790,12 @@ async function detectRuntimes() {
25110
25790
  const driver = getDriver(id);
25111
25791
  const probe = await driver.probe();
25112
25792
  if (probe.status === "healthy") {
25113
- results.push({ id, status: "healthy", version: probe.version });
25793
+ results.push({
25794
+ id,
25795
+ status: "healthy",
25796
+ version: probe.version,
25797
+ reasoning: probe.reasoning
25798
+ });
25114
25799
  } else {
25115
25800
  results.push({
25116
25801
  id,
@@ -25226,7 +25911,7 @@ import * as path12 from "node:path";
25226
25911
  import { WebSocket } from "ws";
25227
25912
 
25228
25913
  // src/daemon/createDaemon.ts
25229
- import { homedir as homedir4 } from "os";
25914
+ import { homedir as homedir5 } from "os";
25230
25915
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync8 } from "node:fs";
25231
25916
 
25232
25917
  // src/util/rotatingFileSink.ts
@@ -25914,23 +26599,43 @@ class WsControlChannel {
25914
26599
  this.ws.send(JSON.stringify(frame));
25915
26600
  }
25916
26601
  resyncOnConnect() {
26602
+ const sendActivities = (activities, counts) => {
26603
+ for (const activity of activities) {
26604
+ this.sendFrame({ type: "agent_activity", ...activity });
26605
+ }
26606
+ this.log.info("resync sent", {
26607
+ ready: counts.ready,
26608
+ sessions: counts.sessions,
26609
+ activities: activities.length,
26610
+ pendingAuditEvents: this.pendingBotAuditEvents.size
26611
+ });
26612
+ };
25917
26613
  if (this.resyncProvider) {
25918
- const { ready, sessions, activities } = this.resyncProvider();
25919
- this.sendFrame({ type: "ready", ...ready });
25920
- for (const s of sessions)
25921
- this.sendFrame({ type: "agent_session", ...s });
25922
- const liveActivities = activities ?? [];
25923
- for (const a of liveActivities)
25924
- this.sendFrame({ type: "agent_activity", ...a });
26614
+ const socketAtStart = this.ws;
26615
+ const snapshot = this.resyncProvider();
26616
+ this.sendFrame({ type: "ready", ...snapshot.ready });
26617
+ for (const session2 of snapshot.sessions) {
26618
+ this.sendFrame({ type: "agent_session", ...session2 });
26619
+ }
25925
26620
  for (const frame of this.pendingBotAuditEvents.values())
25926
26621
  this.sendFrame(frame);
25927
26622
  this.scheduleAuditRetry();
25928
- this.log.info("resync sent", {
25929
- ready: ready.runtimeReport.length,
25930
- sessions: sessions.length,
25931
- activities: liveActivities.length,
25932
- pendingAuditEvents: this.pendingBotAuditEvents.size
25933
- });
26623
+ const activities = snapshot.activities ?? [];
26624
+ const counts = {
26625
+ ready: snapshot.ready.runtimeReport.length,
26626
+ sessions: snapshot.sessions.length
26627
+ };
26628
+ if (activities instanceof Promise) {
26629
+ activities.then((resolved) => {
26630
+ if (this.ws === socketAtStart && this.statusValue === "open") {
26631
+ sendActivities(resolved, counts);
26632
+ }
26633
+ }).catch((err) => {
26634
+ this.log.warn("resync provider failed", { err: describeErr(err) });
26635
+ });
26636
+ } else {
26637
+ sendActivities(activities, counts);
26638
+ }
25934
26639
  }
25935
26640
  for (const hook of this.resyncHooks) {
25936
26641
  try {
@@ -26736,6 +27441,29 @@ function reduceManager(state, event) {
26736
27441
  a.inbox = [...a.inbox, event.message];
26737
27442
  a.idleSince = null;
26738
27443
  });
27444
+ case "runtime_config_queued":
27445
+ return mutate(state, event.agentId, (a) => {
27446
+ if (!a.inbox.some((message2) => message2.id === event.message.id)) {
27447
+ a.inbox = [...a.inbox, event.message];
27448
+ }
27449
+ syncExecutionProjection(a);
27450
+ a.idleSince = null;
27451
+ });
27452
+ case "runtime_config_applied": {
27453
+ const existing = state.agents[event.agentId];
27454
+ if (!existing)
27455
+ return { state, effects: [] };
27456
+ const agent2 = clone2(existing);
27457
+ if (agent2.status !== "running" || leaseIsWorking(agent2.execution.lease) || agent2.pendingAdmissions.length > 0 || agent2.inbox.length === 0)
27458
+ return { state, effects: [] };
27459
+ const messages = drainInbox(agent2);
27460
+ return commit(state, agent2, messages.map((message2) => ({
27461
+ type: "send",
27462
+ agentId: event.agentId,
27463
+ message: message2,
27464
+ mode: "idle"
27465
+ })));
27466
+ }
26739
27467
  case "turn_started": {
26740
27468
  const existing = state.agents[event.agentId];
26741
27469
  if (!existing || existing.execution.sessionInstanceId !== event.sessionInstanceId)
@@ -26943,7 +27671,7 @@ function onTurnCompleted(state, agentId, sessionInstanceId, nowMs, turnId, endRe
26943
27671
  agent2.stalledSessionId = null;
26944
27672
  syncExecutionProjection(agent2);
26945
27673
  const clearEffects = clearedStallSessionId === null ? [] : [{ type: "clear_stall_recovery", agentId, sessionId: clearedStallSessionId }];
26946
- if (agent2.inbox.length > 0) {
27674
+ if (agent2.inbox.length > 0 && !agent2.resetting) {
26947
27675
  const messages = drainInbox(agent2);
26948
27676
  return commit(state, agent2, [
26949
27677
  ...clearEffects,
@@ -27203,6 +27931,144 @@ function toAgentBackendSelection(config2) {
27203
27931
  function runtimeModelName(config2) {
27204
27932
  return config2?.model.kind === "default" ? undefined : config2?.model.name;
27205
27933
  }
27934
+ // agent-driver/dist/provider-quota.js
27935
+ import { execFile } from "node:child_process";
27936
+ import { readFile } from "node:fs/promises";
27937
+ import { homedir as homedir3 } from "node:os";
27938
+ import { join as join11 } from "node:path";
27939
+ import { promisify } from "node:util";
27940
+ import { randomBytes as randomBytes5 } from "node:crypto";
27941
+ var execFileAsync = promisify(execFile);
27942
+ var claudeAccessToken = null;
27943
+ var claudeSourceEpoch = randomBytes5(16).toString("base64url");
27944
+ function parseCredentials(value) {
27945
+ try {
27946
+ const parsed = JSON.parse(value);
27947
+ return parsed && typeof parsed === "object" ? parsed : null;
27948
+ } catch {
27949
+ return null;
27950
+ }
27951
+ }
27952
+ async function claudeCredentials(options) {
27953
+ const platform = options.platform ?? process.platform;
27954
+ if (platform === "darwin") {
27955
+ try {
27956
+ const value = options.readKeychain ? await options.readKeychain() : (await execFileAsync("security", ["find-generic-password", "-s", "Claude Code-credentials", "-w"], {
27957
+ timeout: 3000,
27958
+ maxBuffer: 256 * 1024
27959
+ })).stdout;
27960
+ const parsed = parseCredentials(value.trim());
27961
+ if (parsed)
27962
+ return parsed;
27963
+ } catch {}
27964
+ }
27965
+ const env = options.env ?? process.env;
27966
+ const root = env.CLAUDE_CONFIG_DIR || join11(options.home ?? homedir3(), ".claude");
27967
+ try {
27968
+ const value = options.readCredentialsFile ? await options.readCredentialsFile(join11(root, ".credentials.json")) : await readFile(join11(root, ".credentials.json"), "utf8");
27969
+ return parseCredentials(value);
27970
+ } catch {
27971
+ return null;
27972
+ }
27973
+ }
27974
+ function mappedPlanName2(value) {
27975
+ switch (value) {
27976
+ case "free":
27977
+ return "Free";
27978
+ case "pro":
27979
+ return "Pro";
27980
+ case "max":
27981
+ return "Max";
27982
+ case "team":
27983
+ return "Team";
27984
+ case "enterprise":
27985
+ return "Enterprise";
27986
+ default:
27987
+ return;
27988
+ }
27989
+ }
27990
+ function resetIso2(value) {
27991
+ if (typeof value !== "string")
27992
+ return;
27993
+ const date5 = new Date(value);
27994
+ return Number.isNaN(date5.getTime()) ? undefined : date5.toISOString();
27995
+ }
27996
+ function claudeLimit(key, value) {
27997
+ if (!value || typeof value !== "object")
27998
+ return null;
27999
+ const row = value;
28000
+ if (typeof row.utilization !== "number" || !Number.isFinite(row.utilization) || row.utilization < 0 || row.utilization > 100)
28001
+ return null;
28002
+ const model = key.includes("sonnet") ? { kind: "reported", id: "claude-sonnet" } : key.includes("opus") ? { kind: "reported", id: "claude-opus" } : { kind: "not_applicable" };
28003
+ const window2 = key === "five_hour" ? { kind: "rolling", durationSeconds: 18000, displayName: "5 hour usage limit" } : { kind: "rolling", durationSeconds: 604800, displayName: "7 day usage limit" };
28004
+ const resetsAt = resetIso2(row.resets_at ?? row.resetsAt);
28005
+ return {
28006
+ bucket: {
28007
+ limitId: key,
28008
+ product: { kind: "reported", id: "claude", displayName: "Claude" },
28009
+ model,
28010
+ window: window2
28011
+ },
28012
+ usedPercent: row.utilization,
28013
+ ...resetsAt ? { resetsAt } : {}
28014
+ };
28015
+ }
28016
+ async function readClaudeQuota(options) {
28017
+ const env = options.env ?? process.env;
28018
+ if (env.ANTHROPIC_API_KEY || env.ANTHROPIC_BASE_URL)
28019
+ return null;
28020
+ const credentials = await claudeCredentials(options);
28021
+ const token = credentials?.claudeAiOauth?.accessToken;
28022
+ if (typeof token !== "string" || token.length === 0)
28023
+ return null;
28024
+ if (claudeAccessToken !== token) {
28025
+ claudeAccessToken = token;
28026
+ claudeSourceEpoch = randomBytes5(16).toString("base64url");
28027
+ }
28028
+ let response;
28029
+ try {
28030
+ response = await (options.fetchUsage ?? fetch)("https://api.anthropic.com/api/oauth/usage", {
28031
+ headers: {
28032
+ authorization: `Bearer ${token}`,
28033
+ "anthropic-beta": "oauth-2025-04-20"
28034
+ },
28035
+ signal: AbortSignal.timeout(5000)
28036
+ });
28037
+ } catch {
28038
+ return { status: "error", sourceEpoch: claudeSourceEpoch, code: "network", retryable: true };
28039
+ }
28040
+ if (response.status === 401 || response.status === 403) {
28041
+ return { status: "error", sourceEpoch: claudeSourceEpoch, code: "unauthorized", retryable: false };
28042
+ }
28043
+ if (!response.ok) {
28044
+ return { status: "error", sourceEpoch: claudeSourceEpoch, code: "provider_error", retryable: response.status === 429 || response.status >= 500 };
28045
+ }
28046
+ let body;
28047
+ try {
28048
+ body = await response.json();
28049
+ } catch {
28050
+ return { status: "error", sourceEpoch: claudeSourceEpoch, code: "invalid_response", retryable: true };
28051
+ }
28052
+ if (!body || typeof body !== "object") {
28053
+ return { status: "error", sourceEpoch: claudeSourceEpoch, code: "invalid_response", retryable: true };
28054
+ }
28055
+ const record4 = body;
28056
+ const limits = ["five_hour", "seven_day", "seven_day_sonnet", "seven_day_opus"].map((key) => claudeLimit(key, record4[key])).filter((limit) => limit !== null);
28057
+ if (limits.length === 0) {
28058
+ return { status: "error", sourceEpoch: claudeSourceEpoch, code: "invalid_response", retryable: true };
28059
+ }
28060
+ const planName = mappedPlanName2(credentials?.claudeAiOauth?.subscriptionType);
28061
+ return {
28062
+ status: "available",
28063
+ sourceEpoch: claudeSourceEpoch,
28064
+ ...planName ? { planName } : {},
28065
+ freshForSeconds: 300,
28066
+ limits
28067
+ };
28068
+ }
28069
+ async function readBuiltinProviderQuota(backend, options = {}) {
28070
+ return backend === "claude" ? readClaudeQuota(options) : null;
28071
+ }
27206
28072
  // src/runtime/errorDiagnostics.ts
27207
28073
  function scrubRuntimeErrorDiagnosticText(value) {
27208
28074
  return scrubDriverErrorMessage(value);
@@ -27798,9 +28664,13 @@ class AgentProcessManager {
27798
28664
  state;
27799
28665
  sessions = new Map;
27800
28666
  runtimeConfigs = new Map;
28667
+ appliedRuntimeConfigs = new Map;
28668
+ pendingRuntimeConfigUpdates = new Map;
28669
+ runtimeConfigApplyRunning = new Set;
27801
28670
  resumeSessions = new Map;
27802
28671
  launchIds = new Map;
27803
28672
  liveSessions = new Map;
28673
+ liveBackendIds = new Map;
27804
28674
  activeSpawnState = new Map;
27805
28675
  publishedAgentActivity = new Map;
27806
28676
  traceProcessNonce = randomUUID5();
@@ -27829,19 +28699,156 @@ class AgentProcessManager {
27829
28699
  this.state = createInitialManagerState(this.opts.staleThresholdMs, this.opts.idleTimeoutMs, this.opts.resetStuckThresholdMs, this.opts.stoppingStuckThresholdMs, this.opts.idleResetTimeoutMs);
27830
28700
  }
27831
28701
  register(agentId, launch) {
27832
- if (launch?.runtimeConfig)
27833
- this.runtimeConfigs.set(agentId, launch.runtimeConfig);
28702
+ const runtimeConfigAcceptance = launch?.runtimeConfig ? this.acceptRuntimeConfig(agentId, launch.runtimeConfig) : undefined;
27834
28703
  if (launch?.sessionId)
27835
28704
  this.resumeSessions.set(agentId, launch.sessionId);
27836
28705
  if (launch?.launchId)
27837
28706
  this.launchIds.set(agentId, launch.launchId);
27838
28707
  this.dispatch({ type: "register", agentId });
28708
+ const registered = this.state.agents[agentId];
28709
+ if (launch?.runtimeConfig && launch.applyRuntimeConfig !== false && (runtimeConfigAcceptance === "accepted" || this.pendingRuntimeConfigUpdates.has(agentId)) && this.sessions.has(agentId) && registered && !isActivelyWorking(registered)) {
28710
+ this.convergeRuntimeConfig(agentId);
28711
+ }
28712
+ }
28713
+ async updateRuntimeConfig(agentId, config2) {
28714
+ const accepted = this.acceptRuntimeConfig(agentId, config2);
28715
+ if (accepted === "stale" || accepted === "idempotent")
28716
+ return accepted;
28717
+ const session2 = this.sessions.get(agentId);
28718
+ if (!session2) {
28719
+ this.pendingRuntimeConfigUpdates.delete(agentId);
28720
+ return "saved_for_start";
28721
+ }
28722
+ const agent2 = this.state.agents[agentId];
28723
+ if (agent2 && (agent2.turnActive || isActivelyWorking(agent2)))
28724
+ return "deferred";
28725
+ return this.convergeRuntimeConfig(agentId);
28726
+ }
28727
+ acceptRuntimeConfig(agentId, config2) {
28728
+ const desired = this.runtimeConfigs.get(agentId);
28729
+ const revision = config2.runtimeConfigRevision ?? 0;
28730
+ const desiredRevision = desired?.runtimeConfigRevision ?? 0;
28731
+ if (desired && revision < desiredRevision)
28732
+ return "stale";
28733
+ if (desired && revision === desiredRevision) {
28734
+ if (this.runtimeConfigTuple(desired) !== this.runtimeConfigTuple(config2)) {
28735
+ throw new Error(`Conflicting runtime config for ${agentId} at revision ${revision}`);
28736
+ }
28737
+ this.runtimeConfigs.set(agentId, config2);
28738
+ return "idempotent";
28739
+ }
28740
+ this.runtimeConfigs.set(agentId, config2);
28741
+ this.pendingRuntimeConfigUpdates.set(agentId, config2);
28742
+ return "accepted";
28743
+ }
28744
+ runtimeConfigTuple(config2) {
28745
+ return JSON.stringify({
28746
+ version: config2.version,
28747
+ runtime: config2.runtime,
28748
+ model: config2.model,
28749
+ mode: config2.mode,
28750
+ reasoningEffort: config2.reasoningEffort ?? null,
28751
+ provider: config2.provider ?? null,
28752
+ command: config2.command ?? null,
28753
+ disallowedTools: config2.disallowedTools ?? null,
28754
+ envVars: config2.envVars ?? null
28755
+ });
28756
+ }
28757
+ runtimeLaunchTuple(config2) {
28758
+ return JSON.stringify({
28759
+ version: config2.version,
28760
+ runtime: config2.runtime,
28761
+ model: config2.model,
28762
+ mode: config2.mode,
28763
+ provider: config2.provider ?? null,
28764
+ command: config2.command ?? null,
28765
+ disallowedTools: config2.disallowedTools ?? null,
28766
+ envVars: config2.envVars ?? null
28767
+ });
28768
+ }
28769
+ async convergeRuntimeConfig(agentId, restartOnFailure = true) {
28770
+ if (this.runtimeConfigApplyRunning.has(agentId))
28771
+ return "deferred";
28772
+ const session2 = this.sessions.get(agentId);
28773
+ if (!session2)
28774
+ return "saved_for_start";
28775
+ this.runtimeConfigApplyRunning.add(agentId);
28776
+ try {
28777
+ while (this.sessions.get(agentId) === session2) {
28778
+ const desired = this.pendingRuntimeConfigUpdates.get(agentId) ?? this.runtimeConfigs.get(agentId);
28779
+ if (!desired)
28780
+ return "idempotent";
28781
+ const desiredRevision = desired.runtimeConfigRevision ?? 0;
28782
+ const applied = this.appliedRuntimeConfigs.get(agentId);
28783
+ const appliedRevision = applied?.runtimeConfigRevision ?? -1;
28784
+ if (applied && desiredRevision <= appliedRevision) {
28785
+ this.pendingRuntimeConfigUpdates.delete(agentId);
28786
+ return desiredRevision === appliedRevision ? "idempotent" : "stale";
28787
+ }
28788
+ const canApplyNatively = applied && this.runtimeLaunchTuple(applied) === this.runtimeLaunchTuple(desired) && typeof session2.updateSettings === "function";
28789
+ let result = { status: "unsupported" };
28790
+ if (canApplyNatively) {
28791
+ try {
28792
+ result = await session2.updateSettings({
28793
+ reasoningEffort: desired.reasoningEffort ?? null
28794
+ });
28795
+ } catch (error51) {
28796
+ this.log.warn("runtime config live apply threw; restarting at safe boundary", {
28797
+ agentId,
28798
+ revision: desiredRevision,
28799
+ error: String(error51)
28800
+ });
28801
+ if (restartOnFailure)
28802
+ await this.restartForRuntimeConfig(agentId, session2);
28803
+ return "saved_for_start";
28804
+ }
28805
+ }
28806
+ if (result.status !== "applied") {
28807
+ this.log.warn("runtime config live apply unavailable; restarting at safe boundary", {
28808
+ agentId,
28809
+ revision: desiredRevision,
28810
+ status: result.status,
28811
+ code: result.error?.code
28812
+ });
28813
+ if (restartOnFailure)
28814
+ await this.restartForRuntimeConfig(agentId, session2);
28815
+ return "saved_for_start";
28816
+ }
28817
+ this.appliedRuntimeConfigs.set(agentId, desired);
28818
+ if ((this.pendingRuntimeConfigUpdates.get(agentId)?.runtimeConfigRevision ?? -1) === desiredRevision) {
28819
+ this.pendingRuntimeConfigUpdates.delete(agentId);
28820
+ }
28821
+ const latestRevision = this.runtimeConfigs.get(agentId)?.runtimeConfigRevision ?? 0;
28822
+ if (latestRevision <= desiredRevision) {
28823
+ this.dispatch({ type: "runtime_config_applied", agentId });
28824
+ return "applied";
28825
+ }
28826
+ }
28827
+ return "saved_for_start";
28828
+ } finally {
28829
+ this.runtimeConfigApplyRunning.delete(agentId);
28830
+ }
28831
+ }
28832
+ async restartForRuntimeConfig(agentId, session2) {
28833
+ if (this.sessions.get(agentId) !== session2)
28834
+ return;
28835
+ this.opts.timeline?.fenceSession(agentId);
28836
+ this.markResetting(agentId);
28837
+ await this.stop(agentId);
27839
28838
  }
27840
28839
  deliver(agentId, message2) {
27841
28840
  const normalized = message2.id ? message2 : {
27842
28841
  ...message2,
27843
28842
  id: message2.seq !== undefined ? `${agentId}:source:${message2.seq}` : `${agentId}:synthetic:${this.nextDeliveryOrdinal++}`
27844
28843
  };
28844
+ if (this.sessions.has(agentId) && this.pendingRuntimeConfigUpdates.has(agentId)) {
28845
+ this.dispatch({
28846
+ type: "runtime_config_queued",
28847
+ agentId,
28848
+ message: normalized
28849
+ });
28850
+ return this.state.agents[agentId] !== undefined;
28851
+ }
27845
28852
  const effects = this.dispatch({ type: "wake", agentId, message: normalized, nowMs: this.now() });
27846
28853
  return effects.length > 0;
27847
28854
  }
@@ -27885,7 +28892,11 @@ class AgentProcessManager {
27885
28892
  this.emitErrorAudit(agentId, "reset", "resume_control_update_failed", "Reset aborted because resume control could not be persisted");
27886
28893
  throw new Error("Reset aborted because resume control could not be persisted");
27887
28894
  }
27888
- this.register(agentId, { runtimeConfig: opts.runtimeConfig, launchId: opts.launchId });
28895
+ this.register(agentId, {
28896
+ runtimeConfig: opts.runtimeConfig,
28897
+ launchId: opts.launchId,
28898
+ applyRuntimeConfig: false
28899
+ });
27889
28900
  if (!opts.forgetSession)
27890
28901
  this.opts.timeline?.fenceSession(agentId);
27891
28902
  this.abortCurrentTurn(agentId, opts.abortCause);
@@ -27986,6 +28997,9 @@ class AgentProcessManager {
27986
28997
  const agent2 = this.state.agents[agentId];
27987
28998
  return agent2 ? this.deriveActivity(agent2) : null;
27988
28999
  }
29000
+ agentBackendId(agentId) {
29001
+ return this.liveBackendIds.get(agentId) ?? null;
29002
+ }
27989
29003
  statusProjection(nowMs) {
27990
29004
  return Object.values(this.state.agents).map((a) => ({
27991
29005
  agentId: a.agentId,
@@ -28511,6 +29525,7 @@ ${this.opts.wakePromptFooter}` : text2;
28511
29525
  throw new Error(`AgentProcessManager: spawn for ${agentId} has no command`);
28512
29526
  const prompt = this.withFooter(first.text);
28513
29527
  const driver = this.opts.driverFor(agentId, this.runtimeConfigs.get(agentId));
29528
+ this.liveBackendIds.set(agentId, driver.id);
28514
29529
  const base = this.opts.baseContextFor(agentId);
28515
29530
  const configuredRuntime = this.runtimeConfigs.get(agentId) ?? base.config?.runtimeConfig;
28516
29531
  this.log.info("spawning agent", {
@@ -28631,7 +29646,10 @@ ${this.opts.wakePromptFooter}` : text2;
28631
29646
  if (state.session && this.sessions.get(agentId) === state.session)
28632
29647
  this.sessions.delete(agentId);
28633
29648
  this.liveSessions.delete(agentId);
29649
+ if (this.activeSpawnState.get(agentId) === state)
29650
+ this.liveBackendIds.delete(agentId);
28634
29651
  if (this.activeSpawnState.get(agentId) === state) {
29652
+ this.appliedRuntimeConfigs.delete(agentId);
28635
29653
  this.activeSpawnState.delete(agentId);
28636
29654
  this.nonCleanEndMarker.delete(agentId);
28637
29655
  }
@@ -28679,6 +29697,10 @@ ${this.opts.wakePromptFooter}` : text2;
28679
29697
  state.session = session2;
28680
29698
  state.sessionInstanceId = session2.sessionInstanceId;
28681
29699
  this.sessions.set(agentId, session2);
29700
+ this.appliedRuntimeConfigs.set(agentId, runtimeConfig);
29701
+ if ((this.pendingRuntimeConfigUpdates.get(agentId)?.runtimeConfigRevision ?? -1) <= (runtimeConfig.runtimeConfigRevision ?? 0)) {
29702
+ this.pendingRuntimeConfigUpdates.delete(agentId);
29703
+ }
28682
29704
  this.dispatch({
28683
29705
  type: "attach_session",
28684
29706
  agentId,
@@ -28912,6 +29934,12 @@ ${this.opts.wakePromptFooter}` : text2;
28912
29934
  runtime: runtimeId
28913
29935
  });
28914
29936
  }
29937
+ if (event.type === "token_usage") {
29938
+ this.opts.onTokenUsage?.({ agentId, backendId: runtimeId, usage: event.usage });
29939
+ }
29940
+ if (event.type === "rate_limits") {
29941
+ this.opts.onProviderQuota?.({ agentId, backendId: runtimeId, quota: event.quota });
29942
+ }
28915
29943
  if (event.type === "turn_started") {
28916
29944
  const timelineTurnOwner = {
28917
29945
  sessionInstanceId: event.sessionInstanceId,
@@ -29026,7 +30054,7 @@ ${this.opts.wakePromptFooter}` : text2;
29026
30054
  this.logSessionEnded(agentId, "turn_end");
29027
30055
  const marker = this.nonCleanEndMarker.get(agentId);
29028
30056
  this.nonCleanEndMarker.delete(agentId);
29029
- this.dispatch(marker !== undefined ? {
30057
+ const completionEvent = marker !== undefined ? {
29030
30058
  type: "turn_completed",
29031
30059
  agentId,
29032
30060
  sessionInstanceId: event.sessionInstanceId,
@@ -29041,7 +30069,26 @@ ${this.opts.wakePromptFooter}` : text2;
29041
30069
  sessionInstanceId: event.sessionInstanceId,
29042
30070
  nowMs: this.now(),
29043
30071
  turnId: event.turnId
29044
- }, owner);
30072
+ };
30073
+ if (this.pendingRuntimeConfigUpdates.has(agentId) && this.sessions.get(agentId) === owner.session) {
30074
+ this.convergeRuntimeConfig(agentId, false).then((result) => {
30075
+ if (result === "saved_for_start" && owner.session)
30076
+ this.markResetting(agentId);
30077
+ this.dispatch(completionEvent, owner);
30078
+ if (result === "saved_for_start" && owner.session) {
30079
+ this.restartForRuntimeConfig(agentId, owner.session);
30080
+ }
30081
+ }).catch((error51) => {
30082
+ this.log.error("runtime config convergence failed", { agentId, error: String(error51) });
30083
+ if (owner.session)
30084
+ this.markResetting(agentId);
30085
+ this.dispatch(completionEvent, owner);
30086
+ if (owner.session)
30087
+ this.restartForRuntimeConfig(agentId, owner.session);
30088
+ });
30089
+ return;
30090
+ }
30091
+ this.dispatch(completionEvent, owner);
29045
30092
  }
29046
30093
  }
29047
30094
  }
@@ -29116,7 +30163,8 @@ class AgentRouter {
29116
30163
  version: r.version,
29117
30164
  status: r.status ?? "healthy",
29118
30165
  lastError: r.lastError,
29119
- lastErrorAt: r.lastErrorAt
30166
+ lastErrorAt: r.lastErrorAt,
30167
+ reasoning: r.reasoning
29120
30168
  });
29121
30169
  }
29122
30170
  }
@@ -29125,7 +30173,7 @@ class AgentRouter {
29125
30173
  this.opts.channel.onResync?.(() => ({
29126
30174
  ready: this.buildReady(),
29127
30175
  sessions: this.opts.manager.liveSessionReports(),
29128
- activities: this.opts.manager.liveAgentActivities()
30176
+ activities: this.opts.resyncActivities ? this.opts.resyncActivities() : this.opts.manager.liveAgentActivities()
29129
30177
  }));
29130
30178
  await this.opts.channel.reportReady(this.buildReady());
29131
30179
  }
@@ -29138,7 +30186,8 @@ class AgentRouter {
29138
30186
  platform: this.opts.platform,
29139
30187
  arch: this.opts.arch,
29140
30188
  osRelease: this.opts.osRelease,
29141
- daemonVersion: this.opts.daemonVersion
30189
+ daemonVersion: this.opts.daemonVersion,
30190
+ ...this.opts.providerQuotas ? { providerQuotas: this.opts.providerQuotas() } : {}
29142
30191
  };
29143
30192
  }
29144
30193
  healthyRuntimeIds() {
@@ -29360,6 +30409,27 @@ class AgentRouter {
29360
30409
  rewakePrompt: MODEL_SWITCH_REWAKE_PROMPT
29361
30410
  }));
29362
30411
  break;
30412
+ case "agent:runtime_config_update": {
30413
+ this.log.info("agent:runtime_config_update received", {
30414
+ agentId: cmd.agentId,
30415
+ revision: cmd.config.runtimeConfigRevision ?? 0
30416
+ });
30417
+ try {
30418
+ const result = await this.opts.manager.updateRuntimeConfig(cmd.agentId, cmd.config);
30419
+ this.log.info("agent:runtime_config_update accepted", {
30420
+ agentId: cmd.agentId,
30421
+ revision: cmd.config.runtimeConfigRevision ?? 0,
30422
+ result
30423
+ });
30424
+ } catch (err) {
30425
+ this.log.warn("agent:runtime_config_update rejected", {
30426
+ agentId: cmd.agentId,
30427
+ revision: cmd.config.runtimeConfigRevision ?? 0,
30428
+ error: err instanceof Error ? err.message : String(err)
30429
+ });
30430
+ }
30431
+ break;
30432
+ }
29363
30433
  case "agent:stop":
29364
30434
  this.log.info("agent:stop received", { agentId: cmd.agentId });
29365
30435
  try {
@@ -29417,8 +30487,8 @@ function createTypingScopeTracker() {
29417
30487
  }
29418
30488
  // src/timeline/timeline.ts
29419
30489
  import * as fs9 from "node:fs";
29420
- import { createHash as createHash2, randomBytes as randomBytes4 } from "node:crypto";
29421
- import { basename as basename3, dirname as dirname5, join as join11 } from "node:path";
30490
+ import { createHash as createHash2, randomBytes as randomBytes6 } from "node:crypto";
30491
+ import { basename as basename3, dirname as dirname5, join as join12 } from "node:path";
29422
30492
 
29423
30493
  // src/timeline/filelock.ts
29424
30494
  import * as fs8 from "fs";
@@ -29761,7 +30831,7 @@ function scanTimelineFile(filePath) {
29761
30831
  }
29762
30832
  }
29763
30833
  function atomicReplaceTimeline(filePath, lines) {
29764
- const tempPath = join11(dirname5(filePath), `.${basename3(filePath)}.${process.pid}.${randomBytes4(12).toString("hex")}.tmp`);
30834
+ const tempPath = join12(dirname5(filePath), `.${basename3(filePath)}.${process.pid}.${randomBytes6(12).toString("hex")}.tmp`);
29765
30835
  let fd = null;
29766
30836
  try {
29767
30837
  fd = fs9.openSync(tempPath, "wx", 384);
@@ -29845,14 +30915,14 @@ function readRecentEntries(timelineDir, opts = {}) {
29845
30915
  const filenames = recentFilenames(maxDays, now).reverse();
29846
30916
  const entries = [];
29847
30917
  for (const filename of filenames) {
29848
- entries.push(...readJsonl(join11(timelineDir, filename)));
30918
+ entries.push(...readJsonl(join12(timelineDir, filename)));
29849
30919
  }
29850
30920
  return entries;
29851
30921
  }
29852
30922
  function readResumeControlState(timelineDir) {
29853
30923
  if (timelineDirectoryState(timelineDir) !== "safe")
29854
30924
  return { kind: "missing" };
29855
- const filePath = join11(timelineDir, RESUME_CONTROL_FILENAME);
30925
+ const filePath = join12(timelineDir, RESUME_CONTROL_FILENAME);
29856
30926
  let source;
29857
30927
  try {
29858
30928
  source = fs9.lstatSync(filePath);
@@ -29928,8 +30998,8 @@ function updateResumeControlState(timelineDir, update) {
29928
30998
  `;
29929
30999
  if (Buffer.byteLength(body, "utf8") > RESUME_CONTROL_MAX_BYTES)
29930
31000
  return false;
29931
- const filePath = join11(timelineDir, RESUME_CONTROL_FILENAME);
29932
- const tempPath = join11(timelineDir, `.${RESUME_CONTROL_FILENAME}.${process.pid}.${randomBytes4(12).toString("hex")}.tmp`);
31001
+ const filePath = join12(timelineDir, RESUME_CONTROL_FILENAME);
31002
+ const tempPath = join12(timelineDir, `.${RESUME_CONTROL_FILENAME}.${process.pid}.${randomBytes6(12).toString("hex")}.tmp`);
29933
31003
  let fd = null;
29934
31004
  try {
29935
31005
  fd = fs9.openSync(tempPath, "wx", 384);
@@ -29959,7 +31029,7 @@ function appendTrackedEntry(timelineDir, entry, now = new Date) {
29959
31029
  if (timelineDirectoryState(timelineDir) !== "safe")
29960
31030
  return { status: "rejected", reason: "unsafe" };
29961
31031
  const filename = filenameForDate(now);
29962
- const filePath = join11(timelineDir, filename);
31032
+ const filePath = join12(timelineDir, filename);
29963
31033
  const lockPath = lockPathFor(timelineDir, filename);
29964
31034
  try {
29965
31035
  if (!acquireLock(lockPath))
@@ -29987,7 +31057,7 @@ function updateTrackedEntry(timelineDir, handle, update) {
29987
31057
  if (!DATE_FILENAME_PATTERN.test(handle.filename) || basename3(handle.filename) !== handle.filename) {
29988
31058
  return { status: "rejected", reason: "unsafe" };
29989
31059
  }
29990
- const filePath = join11(timelineDir, handle.filename);
31060
+ const filePath = join12(timelineDir, handle.filename);
29991
31061
  const lockPath = lockPathFor(timelineDir, handle.filename);
29992
31062
  try {
29993
31063
  if (!acquireLock(lockPath))
@@ -30046,10 +31116,10 @@ async function sweepTimelineHistory(workingDirectoryBase, opts = {}) {
30046
31116
  return;
30047
31117
  }
30048
31118
  for (const agentName of agentNames) {
30049
- const agentDir = join11(workingDirectoryBase, agentName);
31119
+ const agentDir = join12(workingDirectoryBase, agentName);
30050
31120
  if (!isRealDirectory(agentDir))
30051
31121
  continue;
30052
- const timelineDir = join11(agentDir, ".context_timeline");
31122
+ const timelineDir = join12(agentDir, ".context_timeline");
30053
31123
  if (!isRealDirectory(timelineDir))
30054
31124
  continue;
30055
31125
  let filenames;
@@ -30059,7 +31129,7 @@ async function sweepTimelineHistory(workingDirectoryBase, opts = {}) {
30059
31129
  continue;
30060
31130
  }
30061
31131
  for (const filename of filenames) {
30062
- const filePath = join11(timelineDir, filename);
31132
+ const filePath = join12(timelineDir, filename);
30063
31133
  let source;
30064
31134
  try {
30065
31135
  source = fs9.lstatSync(filePath);
@@ -30803,8 +31873,8 @@ class MessageReminderScheduler {
30803
31873
 
30804
31874
  // src/manager/agentDriverHost.ts
30805
31875
  import { randomUUID as randomUUID6 } from "node:crypto";
30806
- import { homedir as homedir3 } from "node:os";
30807
- import { join as join12 } from "node:path";
31876
+ import { homedir as homedir4 } from "node:os";
31877
+ import { join as join13 } from "node:path";
30808
31878
 
30809
31879
  // src/drivers/gitIdentityEnv.ts
30810
31880
  import { execFileSync as execFileSync3 } from "child_process";
@@ -30929,7 +31999,7 @@ function createDaemonAgentDriverHost(ctx, onRawLine) {
30929
31999
  hostUser: readHostGitIdentity() ?? undefined
30930
32000
  }),
30931
32001
  platformProtected: {
30932
- ALOOK_HOME: process.env.ALOOK_HOME ?? join12(homedir3(), ".alook"),
32002
+ ALOOK_HOME: process.env.ALOOK_HOME ?? join13(homedir4(), ".alook"),
30933
32003
  ALOOK_ID: ctx.agentId,
30934
32004
  ALOOK_CLI: ctx.agentCliPath,
30935
32005
  ALOOK_SERVER_URL: ctx.config.serverUrl,
@@ -31034,6 +32104,182 @@ class DaemonSelfSleepScheduler {
31034
32104
  }
31035
32105
  }
31036
32106
 
32107
+ // src/telemetry/dailyTokenUsage.ts
32108
+ import { chmod, mkdir, open, readFile as readFile2, rename, rm } from "node:fs/promises";
32109
+ import { dirname as dirname6, join as join14 } from "node:path";
32110
+ import { randomUUID as randomUUID7 } from "node:crypto";
32111
+ function dayKey(at) {
32112
+ return at.toISOString().slice(0, 10);
32113
+ }
32114
+ function retainedDays(at) {
32115
+ const days = new Set;
32116
+ for (let offset = 0;offset < 7; offset += 1) {
32117
+ days.add(dayKey(new Date(at.getTime() - offset * 86400000)));
32118
+ }
32119
+ return days;
32120
+ }
32121
+ function isMetric(value) {
32122
+ return value === null || typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
32123
+ }
32124
+ function isSnapshot(value) {
32125
+ if (!value || typeof value !== "object")
32126
+ return false;
32127
+ const snapshot = value;
32128
+ const metrics = snapshot.metrics;
32129
+ return typeof snapshot.botId === "string" && snapshot.botId.length > 0 && typeof snapshot.day === "string" && /^\d{4}-\d{2}-\d{2}$/.test(snapshot.day) && !!metrics && isMetric(metrics.input) && isMetric(metrics.output) && isMetric(metrics.cache);
32130
+ }
32131
+ function mergeMetric(existing, delta, hasExistingSnapshot) {
32132
+ if (delta === null)
32133
+ return null;
32134
+ if (!Number.isSafeInteger(delta) || delta < 0) {
32135
+ throw new RangeError("token usage delta must be a non-negative safe integer");
32136
+ }
32137
+ if (!hasExistingSnapshot)
32138
+ return delta;
32139
+ if (existing === null)
32140
+ return null;
32141
+ const sum = existing + delta;
32142
+ if (!Number.isSafeInteger(sum))
32143
+ throw new RangeError("daily token usage exceeds safe integer range");
32144
+ return sum;
32145
+ }
32146
+ function emptySnapshot(botId, day) {
32147
+ return {
32148
+ botId,
32149
+ day,
32150
+ metrics: {
32151
+ input: null,
32152
+ output: null,
32153
+ cache: null
32154
+ }
32155
+ };
32156
+ }
32157
+
32158
+ class DailyTokenUsageStore {
32159
+ now;
32160
+ tail = Promise.resolve();
32161
+ loaded = false;
32162
+ data = { version: 1, bots: {} };
32163
+ filePath;
32164
+ constructor(workingDirectoryBase, now = () => new Date) {
32165
+ this.now = now;
32166
+ this.filePath = join14(workingDirectoryBase, ".telemetry", "daily-token-usage.json");
32167
+ }
32168
+ record(botId, delta) {
32169
+ return this.enqueue(async () => {
32170
+ await this.load();
32171
+ const at = this.now();
32172
+ this.prune(at);
32173
+ const day = dayKey(at);
32174
+ const snapshots = this.data.bots[botId] ?? [];
32175
+ const existing = snapshots.find((snapshot) => snapshot.day === day);
32176
+ const next = existing ?? emptySnapshot(botId, day);
32177
+ next.metrics = {
32178
+ input: mergeMetric(next.metrics.input, delta.input, existing !== undefined),
32179
+ output: mergeMetric(next.metrics.output, delta.output, existing !== undefined),
32180
+ cache: mergeMetric(next.metrics.cache, delta.cache, existing !== undefined)
32181
+ };
32182
+ if (!existing)
32183
+ snapshots.push(next);
32184
+ snapshots.sort((a, b) => a.day.localeCompare(b.day));
32185
+ this.data.bots[botId] = snapshots;
32186
+ await this.persist();
32187
+ });
32188
+ }
32189
+ snapshots(botId) {
32190
+ let result = [];
32191
+ return this.enqueue(async () => {
32192
+ await this.load();
32193
+ if (this.prune(this.now()))
32194
+ await this.persist();
32195
+ result = (this.data.bots[botId] ?? []).map((snapshot) => structuredClone(snapshot));
32196
+ }).then(() => result);
32197
+ }
32198
+ enqueue(operation) {
32199
+ const result = this.tail.then(operation, operation);
32200
+ this.tail = result.then(() => {
32201
+ return;
32202
+ }, () => {
32203
+ return;
32204
+ });
32205
+ return result;
32206
+ }
32207
+ async load() {
32208
+ if (this.loaded)
32209
+ return;
32210
+ let source;
32211
+ try {
32212
+ source = await readFile2(this.filePath, "utf8");
32213
+ } catch (error51) {
32214
+ if (!error51 || typeof error51 !== "object" || !("code" in error51) || error51.code !== "ENOENT") {
32215
+ throw error51;
32216
+ }
32217
+ this.data = { version: 1, bots: {} };
32218
+ this.loaded = true;
32219
+ return;
32220
+ }
32221
+ const parsed = JSON.parse(source);
32222
+ if (!parsed || typeof parsed !== "object" || parsed.version !== 1) {
32223
+ throw new Error("invalid daily token usage file version");
32224
+ }
32225
+ const bots = parsed.bots;
32226
+ if (!bots || typeof bots !== "object" || Array.isArray(bots)) {
32227
+ throw new Error("invalid daily token usage bots map");
32228
+ }
32229
+ const valid = {};
32230
+ for (const [botId, value] of Object.entries(bots)) {
32231
+ if (!Array.isArray(value) || !value.every(isSnapshot) || value.some((snapshot) => snapshot.botId !== botId)) {
32232
+ throw new Error(`invalid daily token usage snapshots for bot ${botId}`);
32233
+ }
32234
+ if (value.length > 0) {
32235
+ valid[botId] = value;
32236
+ }
32237
+ }
32238
+ this.data = { version: 1, bots: valid };
32239
+ this.loaded = true;
32240
+ }
32241
+ prune(at) {
32242
+ const keep = retainedDays(at);
32243
+ let changed = false;
32244
+ for (const [botId, snapshots] of Object.entries(this.data.bots)) {
32245
+ const retained = snapshots.filter((snapshot) => keep.has(snapshot.day)).sort((a, b) => a.day.localeCompare(b.day)).slice(-7);
32246
+ if (retained.length !== snapshots.length || retained.some((snapshot, index2) => snapshot !== snapshots[index2]))
32247
+ changed = true;
32248
+ if (retained.length === 0)
32249
+ delete this.data.bots[botId];
32250
+ else
32251
+ this.data.bots[botId] = retained;
32252
+ }
32253
+ return changed;
32254
+ }
32255
+ async persist() {
32256
+ const directory = dirname6(this.filePath);
32257
+ await mkdir(directory, { recursive: true, mode: 448 });
32258
+ const temporary = `${this.filePath}.${randomUUID7()}.tmp`;
32259
+ try {
32260
+ const file2 = await open(temporary, "wx", 384);
32261
+ try {
32262
+ await file2.writeFile(JSON.stringify(this.data), { encoding: "utf8" });
32263
+ await file2.sync();
32264
+ } finally {
32265
+ await file2.close();
32266
+ }
32267
+ await rename(temporary, this.filePath);
32268
+ await chmod(this.filePath, 384);
32269
+ try {
32270
+ const directoryHandle = await open(directory, "r");
32271
+ try {
32272
+ await directoryHandle.sync();
32273
+ } finally {
32274
+ await directoryHandle.close();
32275
+ }
32276
+ } catch {}
32277
+ } catch (error51) {
32278
+ await rm(temporary, { force: true }).catch(() => {});
32279
+ throw error51;
32280
+ }
32281
+ }
32282
+ }
31037
32283
  // src/daemon/createDaemon.ts
31038
32284
  var WARMUP_BACKOFF_MS = [250, 500, 1000, 2000, 4000];
31039
32285
  var WARMUP_CEILING_MS = 30000;
@@ -31171,9 +32417,25 @@ function createBuiltinDaemonSessionFactory(onRuntimeRawLine) {
31171
32417
  }
31172
32418
  async function createDaemon(opts) {
31173
32419
  const log2 = opts.logger ?? createLogger2({ header: "@alook/daemon" });
31174
- const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${homedir4()}/.alook`) + "/daemon";
32420
+ const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${homedir5()}/.alook`) + "/daemon";
31175
32421
  const workingDirectoryBase = opts.workingDirectoryBase ?? fallbackBase;
31176
32422
  const workdirFor = (agentId) => `${workingDirectoryBase}/${agentId}`;
32423
+ const dailyTokenUsage2 = new DailyTokenUsageStore(workingDirectoryBase);
32424
+ const providerQuotaReader = opts.providerQuotaReader ?? (opts.sessionFactory ? async () => null : readBuiltinProviderQuota);
32425
+ const providerQuotaByBackend = new Map;
32426
+ let requestReadyQuotaResend = () => {};
32427
+ const recordProviderQuota = (backendId, quota) => {
32428
+ const previous = providerQuotaByBackend.get(backendId);
32429
+ if (previous?.observation.status === "available" && quota.status === "error" && previous.observation.sourceEpoch === quota.sourceEpoch)
32430
+ return;
32431
+ providerQuotaByBackend.set(backendId, {
32432
+ agentBackendId: backendId,
32433
+ observation: structuredClone(quota)
32434
+ });
32435
+ if (previous && previous.observation.sourceEpoch !== quota.sourceEpoch) {
32436
+ requestReadyQuotaResend();
32437
+ }
32438
+ };
31177
32439
  sweepTimelineHistory(workingDirectoryBase).catch(() => {
31178
32440
  log2.warn("timeline startup sweep failed");
31179
32441
  });
@@ -31189,6 +32451,27 @@ async function createDaemon(opts) {
31189
32451
  });
31190
32452
  let channelRef = null;
31191
32453
  let managerRef = null;
32454
+ const providerQuotaSnapshots = () => [...providerQuotaByBackend.values()].map((snapshot) => structuredClone(snapshot));
32455
+ const activityPayload = async (info) => {
32456
+ if (info.state !== "idle")
32457
+ return info;
32458
+ const backendId = managerRef?.agentBackendId(info.agentId);
32459
+ if (backendId === "claude") {
32460
+ const observed = await providerQuotaReader("claude");
32461
+ if (observed)
32462
+ recordProviderQuota("claude", observed);
32463
+ }
32464
+ const quota = backendId === "claude" || backendId === "codex" ? providerQuotaByBackend.get(backendId) : undefined;
32465
+ const dailyUsage = await dailyTokenUsage2.snapshots(info.agentId);
32466
+ return {
32467
+ ...info,
32468
+ ...dailyUsage.length > 0 ? { dailyUsage } : {},
32469
+ ...quota ? { quota: structuredClone(quota) } : {}
32470
+ };
32471
+ };
32472
+ let reportAgentActivity = (info) => {
32473
+ channelRef?.reportAgentActivity?.(info);
32474
+ };
31192
32475
  let reminderSchedulerRef = null;
31193
32476
  const selfSleepScheduler = opts.onSelfSleep ? new DaemonSelfSleepScheduler({
31194
32477
  onSleep: opts.onSelfSleep,
@@ -31253,7 +32536,7 @@ async function createDaemon(opts) {
31253
32536
  function reassertAgentActivity(agentId) {
31254
32537
  const state = managerRef?.agentActivity(agentId);
31255
32538
  if (state)
31256
- channel2.reportAgentActivity?.({ agentId, state });
32539
+ reportAgentActivity({ agentId, state });
31257
32540
  }
31258
32541
  function startTypingHeartbeat(agentId) {
31259
32542
  stopTypingHeartbeat(agentId);
@@ -31397,6 +32680,20 @@ async function createDaemon(opts) {
31397
32680
  logger: log2.child("ws")
31398
32681
  });
31399
32682
  channelRef = channel2;
32683
+ const activityReportTails = new Map;
32684
+ reportAgentActivity = (info) => {
32685
+ const prior = activityReportTails.get(info.agentId) ?? Promise.resolve();
32686
+ const next = prior.then(async () => {
32687
+ await channel2.reportAgentActivity(await activityPayload(info));
32688
+ }).catch(() => {
32689
+ log2.warn("agent activity telemetry report failed", { agentId: info.agentId, state: info.state });
32690
+ });
32691
+ activityReportTails.set(info.agentId, next);
32692
+ next.finally(() => {
32693
+ if (activityReportTails.get(info.agentId) === next)
32694
+ activityReportTails.delete(info.agentId);
32695
+ });
32696
+ };
31400
32697
  function restorePendingIdleResetEvents(agentId) {
31401
32698
  for (const pending of timeline2.pendingIdleResetEvents(agentId)) {
31402
32699
  channel2.restorePendingBotAuditEvent({
@@ -31515,7 +32812,7 @@ async function createDaemon(opts) {
31515
32812
  onAgentSession: (info) => void channel2.reportAgentSession(info),
31516
32813
  onAgentActivity: (info) => {
31517
32814
  selfSleepScheduler?.observeAgentActivity(info.agentId, info.state === "running");
31518
- channel2.reportAgentActivity?.(info);
32815
+ reportAgentActivity(info);
31519
32816
  if (info.state === "starting" || info.state === "running") {
31520
32817
  if (!typingHeartbeats.has(info.agentId)) {
31521
32818
  startTypingHeartbeat(info.agentId);
@@ -31524,6 +32821,16 @@ async function createDaemon(opts) {
31524
32821
  emitTypingStopsAndClear(info.agentId);
31525
32822
  }
31526
32823
  },
32824
+ onTokenUsage: ({ agentId, usage }) => {
32825
+ dailyTokenUsage2.record(agentId, usage).catch(() => {
32826
+ log2.warn("daily token usage persistence failed", { agentId });
32827
+ });
32828
+ },
32829
+ onProviderQuota: ({ backendId, quota }) => {
32830
+ if (backendId !== "claude" && backendId !== "codex")
32831
+ return;
32832
+ recordProviderQuota(backendId, quota);
32833
+ },
31527
32834
  onBotAuditEvent: (agentId, event, context) => emitBotAuditEvent(agentId, event, context),
31528
32835
  onAgentLocallyStopped: (info) => router?.markLocallyStopped(info.agentId),
31529
32836
  onRuntimeRawLine,
@@ -31570,6 +32877,11 @@ async function createDaemon(opts) {
31570
32877
  arch: opts.arch,
31571
32878
  osRelease: opts.osRelease,
31572
32879
  daemonVersion: opts.daemonVersion,
32880
+ providerQuotas: providerQuotaSnapshots,
32881
+ resyncActivities: async () => {
32882
+ const activities = await Promise.all(manager.liveAgentActivities().map((info) => activityPayload(info)));
32883
+ return activities.filter((activity) => manager.agentActivity(activity.agentId) === activity.state);
32884
+ },
31573
32885
  typingTracker,
31574
32886
  logger: log2.child("router"),
31575
32887
  onBeforeAgent: async (agentId) => {
@@ -31585,6 +32897,10 @@ async function createDaemon(opts) {
31585
32897
  await enrollAgent(agentId);
31586
32898
  }
31587
32899
  });
32900
+ requestReadyQuotaResend = () => {
32901
+ if (router)
32902
+ channel2.sendReady?.(router.buildReady());
32903
+ };
31588
32904
  channel2.onCommand(createSelfUpdateCommandListener(opts.handleSelfUpdate));
31589
32905
  channel2.onCommand(createDiagnosticsCommandListener({
31590
32906
  handleDiagnosticCommand: opts.handleDiagnosticCommand,
@@ -31614,6 +32930,11 @@ async function createDaemon(opts) {
31614
32930
  resyncPendingWakes();
31615
32931
  resyncPendingDiagnostics();
31616
32932
  });
32933
+ if (opts.runtimeReport.some((runtime) => runtime.id === "claude")) {
32934
+ const observed = await providerQuotaReader("claude");
32935
+ if (observed)
32936
+ recordProviderQuota("claude", observed);
32937
+ }
31617
32938
  channel2.connect();
31618
32939
  await router.start();
31619
32940
  selfSleepScheduler?.start();
@@ -32424,7 +33745,7 @@ async function buildDiagnosticBundle(args) {
32424
33745
  };
32425
33746
  }
32426
33747
  // src/diagnostics/coordinator.ts
32427
- import { createHash as createHash4, randomBytes as randomBytes5 } from "node:crypto";
33748
+ import { createHash as createHash4, randomBytes as randomBytes7 } from "node:crypto";
32428
33749
  import {
32429
33750
  chmodSync as chmodSync2,
32430
33751
  closeSync as closeSync4,
@@ -32440,7 +33761,7 @@ import {
32440
33761
  unlinkSync as unlinkSync6,
32441
33762
  writeSync
32442
33763
  } from "node:fs";
32443
- import { join as join13 } from "node:path";
33764
+ import { join as join15 } from "node:path";
32444
33765
  class CoordinatorError extends Error {
32445
33766
  code;
32446
33767
  constructor(code) {
@@ -32450,7 +33771,7 @@ class CoordinatorError extends Error {
32450
33771
  }
32451
33772
  function defaultFsOps() {
32452
33773
  return {
32453
- randomSuffix: () => randomBytes5(12).toString("hex"),
33774
+ randomSuffix: () => randomBytes7(12).toString("hex"),
32454
33775
  open: (path11, flags, mode) => openSync4(path11, flags, mode),
32455
33776
  write: (fd, bytes) => {
32456
33777
  writeSync(fd, bytes);
@@ -32507,15 +33828,15 @@ function commandFrom(sidecar) {
32507
33828
  }
32508
33829
  function createDiagnosticReportCoordinator(args) {
32509
33830
  const fsOps = args.fsOps ?? defaultFsOps();
32510
- const dir = join13(args.machineDir, "diagnostics");
33831
+ const dir = join15(args.machineDir, "diagnostics");
32511
33832
  let stopped = false;
32512
33833
  let active = null;
32513
33834
  const retryCancels = new Set;
32514
33835
  const checkpoint = (point) => {
32515
33836
  args.checkpoint?.(point);
32516
33837
  };
32517
- const archivePath = (reportId) => join13(dir, `report-${reportId}.ndjson.gz`);
32518
- const sidecarPath = (reportId) => join13(dir, `report-${reportId}.json`);
33838
+ const archivePath = (reportId) => join15(dir, `report-${reportId}.ndjson.gz`);
33839
+ const sidecarPath = (reportId) => join15(dir, `report-${reportId}.json`);
32519
33840
  const ensureDir = () => {
32520
33841
  if (existsSync7(dir)) {
32521
33842
  const stat = lstatSync5(dir);
@@ -32549,7 +33870,7 @@ function createDiagnosticReportCoordinator(args) {
32549
33870
  let temp = "";
32550
33871
  let fd = null;
32551
33872
  for (let attempt = 0;attempt < 32; attempt += 1) {
32552
- temp = join13(dir, `.${sidecar.reportId}.${sidecar.phase}.${fsOps.randomSuffix()}.tmp`);
33873
+ temp = join15(dir, `.${sidecar.reportId}.${sidecar.phase}.${fsOps.randomSuffix()}.tmp`);
32553
33874
  try {
32554
33875
  fd = fsOps.open(temp, "wx", 384);
32555
33876
  break;
@@ -32666,7 +33987,7 @@ function createDiagnosticReportCoordinator(args) {
32666
33987
  return ready;
32667
33988
  };
32668
33989
  const buildAndCommit = async (command, collecting) => {
32669
- const temp = join13(dir, `.${command.reportId}.archive.${fsOps.randomSuffix()}.tmp`);
33990
+ const temp = join15(dir, `.${command.reportId}.archive.${fsOps.randomSuffix()}.tmp`);
32670
33991
  const artifact2 = await args.buildBundle({ command, outputPath: temp });
32671
33992
  checkpoint("archive_temp_written");
32672
33993
  const fd = fsOps.open(artifact2.path, "r+");
@@ -33514,7 +34835,7 @@ var LEGACY_DAEMON_ID_PATTERN = /^[a-f0-9]{12}$/;
33514
34835
  var DEFAULT_SERVER_URL = "https://alook.ai";
33515
34836
  var DEFAULT_WS_URL = "wss://alook.ai/api/ws/community-daemon";
33516
34837
  function resolveDefaultBaseDir() {
33517
- const root = process.env.ALOOK_PROJECT_ROOT || path13.join(homedir5(), ".alook");
34838
+ const root = process.env.ALOOK_PROJECT_ROOT || path13.join(homedir6(), ".alook");
33518
34839
  return path13.join(root, "daemon");
33519
34840
  }
33520
34841
  var DEFAULT_BASE_DIR = resolveDefaultBaseDir();
@@ -34567,6 +35888,61 @@ async function armMessageReminderFromEnv(input, env = process.env, fetchImpl = f
34567
35888
  return { armed: false, reason: "local reminder returned an invalid response" };
34568
35889
  }
34569
35890
 
35891
+ // src/cli/imageThumbnail.ts
35892
+ var RASTER_CONTENT_TYPES = new Set([
35893
+ "image/png",
35894
+ "image/jpeg",
35895
+ "image/webp",
35896
+ "image/gif"
35897
+ ]);
35898
+ var QUALITIES = [80, 70, 60, 50, 40, 30, 20];
35899
+ var DIMENSION_ATTEMPTS = 10;
35900
+ var DIMENSION_SCALE = 0.85;
35901
+ async function prepareCommunityImageUpload(bytes, contentType) {
35902
+ if (!RASTER_CONTENT_TYPES.has(contentType))
35903
+ return {};
35904
+ let required2 = bytes.byteLength > MAX_ATTACHMENT_THUMBNAIL_SIZE_BYTES;
35905
+ try {
35906
+ const { default: sharp } = await import("sharp");
35907
+ const metadata = await sharp(bytes, { failOn: "error" }).metadata();
35908
+ const width = metadata.width;
35909
+ const height = metadata.height;
35910
+ if (!width || !height) {
35911
+ if (required2)
35912
+ throw new Error("missing image dimensions");
35913
+ return {};
35914
+ }
35915
+ required2 = required2 || Math.max(width, height) > MAX_ATTACHMENT_THUMBNAIL_EDGE_PX;
35916
+ if (!required2)
35917
+ return { width, height };
35918
+ const fittedScale = Math.min(1, MAX_ATTACHMENT_THUMBNAIL_EDGE_PX / Math.max(width, height));
35919
+ const fittedWidth = Math.max(1, Math.round(width * fittedScale));
35920
+ const fittedHeight = Math.max(1, Math.round(height * fittedScale));
35921
+ for (let attempt = 0;attempt < DIMENSION_ATTEMPTS; attempt++) {
35922
+ const scale = DIMENSION_SCALE ** attempt;
35923
+ const targetWidth = Math.max(1, Math.round(fittedWidth * scale));
35924
+ const targetHeight = Math.max(1, Math.round(fittedHeight * scale));
35925
+ for (const quality of QUALITIES) {
35926
+ const jpeg = await sharp(bytes, { failOn: "error" }).resize({
35927
+ width: targetWidth,
35928
+ height: targetHeight,
35929
+ fit: "inside",
35930
+ withoutEnlargement: true
35931
+ }).jpeg({ quality }).toBuffer();
35932
+ if (jpeg.byteLength <= MAX_ATTACHMENT_THUMBNAIL_SIZE_BYTES) {
35933
+ return { thumbnail: new Uint8Array(jpeg), width, height };
35934
+ }
35935
+ }
35936
+ }
35937
+ throw new Error("no policy-compliant JPEG candidate");
35938
+ } catch {
35939
+ if (required2) {
35940
+ throw new Error("could not generate a required image preview");
35941
+ }
35942
+ return {};
35943
+ }
35944
+ }
35945
+
34570
35946
  // src/cli/index.ts
34571
35947
  function messagesInLocalTime(messages) {
34572
35948
  return messages.map((m) => ({ ...m, time: toLocalISO(m.time) }));
@@ -34773,7 +36149,7 @@ ${MESSAGE_SEND_STDIN_POLICY}`);
34773
36149
  }
34774
36150
  replyToSeq = n;
34775
36151
  }
34776
- const nonce = randomUUID9();
36152
+ const nonce = randomUUID10();
34777
36153
  const res = await sendWithRetry(api2, {
34778
36154
  agentId: agent2,
34779
36155
  channel: channel2,
@@ -34884,22 +36260,19 @@ async function cmdAttachmentUpload(opts) {
34884
36260
  let height;
34885
36261
  if (["image/png", "image/jpeg", "image/webp", "image/gif"].includes(contentType)) {
34886
36262
  try {
34887
- const { default: sharp } = await import("sharp");
34888
- const image = sharp(bytes, { failOn: "error" });
34889
- const metadata = await image.metadata();
34890
- if (metadata.width && metadata.height) {
34891
- width = metadata.width;
34892
- height = metadata.height;
34893
- }
34894
- const jpeg = await image.resize({ width: 200, height: 200, fit: "inside", withoutEnlargement: true }).jpeg({ quality: 70 }).toBuffer();
34895
- if (jpeg.byteLength <= MAX_ATTACHMENT_THUMBNAIL_SIZE_BYTES) {
36263
+ const prepared = await prepareCommunityImageUpload(bytes, contentType);
36264
+ width = prepared.width;
36265
+ height = prepared.height;
36266
+ if (prepared.thumbnail) {
34896
36267
  thumbnail = {
34897
- data: new Uint8Array(jpeg),
36268
+ data: prepared.thumbnail,
34898
36269
  filename: "thumbnail.jpg",
34899
36270
  contentType: "image/jpeg"
34900
36271
  };
34901
36272
  }
34902
- } catch {}
36273
+ } catch (error51) {
36274
+ throw new CliError(`message attachment upload: ${error51.message}`);
36275
+ }
34903
36276
  }
34904
36277
  const result = await api2.attachmentUpload({
34905
36278
  agentId: agent2,