@alook/daemon 0.1.18 → 0.1.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -17736,6 +17736,7 @@ __export(exports_community_schema, {
17736
17736
  communityServerFolderItem: () => communityServerFolderItem,
17737
17737
  communityServerFolder: () => communityServerFolder,
17738
17738
  communityServer: () => communityServer,
17739
+ communityReadStateRevision: () => communityReadStateRevision,
17739
17740
  communityReadState: () => communityReadState,
17740
17741
  communityReaction: () => communityReaction,
17741
17742
  communityPin: () => communityPin,
@@ -17900,6 +17901,10 @@ var communityReadState = sqliteTable("community_read_state", {
17900
17901
  lastReadMessageId: text("last_read_message_id"),
17901
17902
  lastReadSeq: integer2("last_read_seq").notNull().default(0)
17902
17903
  }, (t) => [index("idx_read_state_user").on(t.userId)]);
17904
+ var communityReadStateRevision = sqliteTable("community_read_state_revision", {
17905
+ userId: text("user_id").primaryKey().references(() => user.id, { onDelete: "cascade" }),
17906
+ revision: integer2("revision").notNull().default(0)
17907
+ });
17903
17908
  var communityReaction = sqliteTable("community_reaction", {
17904
17909
  id: text("id").primaryKey().$defaultFn(() => nanoid3()),
17905
17910
  messageId: text("message_id").notNull().references(() => communityMessage.id, { onDelete: "cascade" }),
@@ -18493,6 +18498,24 @@ var communityUnreadBumpSchema = exports_external.strictObject({
18493
18498
  railChannelId: string4.optional(),
18494
18499
  isMention: exports_external.boolean().optional()
18495
18500
  });
18501
+ var readStateEnvelopeFields = {
18502
+ revision: exports_external.number().int().positive(),
18503
+ inboxChanged: exports_external.literal(true)
18504
+ };
18505
+ var communityReadStateAdvancedSchema = exports_external.strictObject({
18506
+ type: exports_external.literal("community:read_state.advanced"),
18507
+ ...readStateEnvelopeFields
18508
+ });
18509
+ var communityInboxChangedSchema = exports_external.strictObject({
18510
+ type: exports_external.literal("community:inbox.changed"),
18511
+ ...readStateEnvelopeFields,
18512
+ reason: exports_external.enum([
18513
+ "read_all",
18514
+ "mention_read_all",
18515
+ "mention_dismiss",
18516
+ "notification_policy"
18517
+ ])
18518
+ });
18496
18519
  var communityPresenceUpdateSchema = exports_external.strictObject({
18497
18520
  type: exports_external.literal("community:presence.update"),
18498
18521
  userId: string4,
@@ -18588,6 +18611,8 @@ var CommunityWsEventDiscriminatedSchema = exports_external.discriminatedUnion("t
18588
18611
  communityInviteCreateSchema,
18589
18612
  communityMentionCreateSchema,
18590
18613
  communityUnreadBumpSchema,
18614
+ communityReadStateAdvancedSchema,
18615
+ communityInboxChangedSchema,
18591
18616
  communityPresenceUpdateSchema,
18592
18617
  communityStatusUpdateSchema,
18593
18618
  communityMachineCreatedSchema,
@@ -18632,6 +18657,8 @@ var WS_EVENTS = {
18632
18657
  INVITE_CREATE: "community:invite.create",
18633
18658
  MENTION_CREATE: "community:mention.create",
18634
18659
  UNREAD_BUMP: "community:unread.bump",
18660
+ READ_STATE_ADVANCED: "community:read_state.advanced",
18661
+ INBOX_CHANGED: "community:inbox.changed",
18635
18662
  PRESENCE_UPDATE: "community:presence.update",
18636
18663
  STATUS_UPDATE: "community:status.update",
18637
18664
  MACHINE_CREATED: "community:machine.created",
@@ -27781,6 +27808,9 @@ class AgentProcessManager {
27781
27808
  snapshot() {
27782
27809
  return this.state;
27783
27810
  }
27811
+ runningAgentCount() {
27812
+ return this.sessions.size;
27813
+ }
27784
27814
  auditContext(agentId) {
27785
27815
  return {
27786
27816
  sessionId: this.liveSessions.get(agentId) ?? null,
@@ -28902,6 +28932,7 @@ Then read @memory.md and your .context_timeline for durable context, and pull `
28902
28932
  class AgentRouter {
28903
28933
  opts;
28904
28934
  running = new Set;
28935
+ nextWakeAdmissionOrdinal = 1;
28905
28936
  runtimes = new Map;
28906
28937
  pendingResend = false;
28907
28938
  scheduleResend;
@@ -29062,7 +29093,7 @@ class AgentRouter {
29062
29093
  this.opts.typingTracker?.add(cmd.agentId, channelScope);
29063
29094
  const text2 = (this.opts.formatUnreadNoticeText ?? defaultFormatUnreadNoticeText)(cmd.unreadNotice);
29064
29095
  const producedEffect = this.opts.manager.deliver(cmd.agentId, {
29065
- id: `${cmd.agentId}:wake:${cmd.unreadNotice.channel}:${cmd.unreadNotice.latestSeq}`,
29096
+ id: `${cmd.agentId}:wake:${cmd.unreadNotice.channel}:${cmd.unreadNotice.latestSeq}:admission:${this.nextWakeAdmissionOrdinal++}`,
29066
29097
  seq: cmd.unreadNotice.latestSeq,
29067
29098
  text: text2
29068
29099
  });
@@ -31054,6 +31085,7 @@ async function createDaemon(opts) {
31054
31085
  typingTracker.clear(agentId);
31055
31086
  }
31056
31087
  const botsById = new Map;
31088
+ let botCacheReady = false;
31057
31089
  async function listMyBotsHttp() {
31058
31090
  const res = await fetch(`${opts.serverUrl}/api/community/daemon/bots`, {
31059
31091
  method: "GET",
@@ -31064,22 +31096,26 @@ async function createDaemon(opts) {
31064
31096
  const json2 = await res.json();
31065
31097
  return json2.bots ?? [];
31066
31098
  }
31099
+ function replaceBotCache(bots) {
31100
+ botsById.clear();
31101
+ for (const b of bots) {
31102
+ botsById.set(b.id, {
31103
+ name: b.name,
31104
+ discriminator: b.discriminator,
31105
+ description: b.description,
31106
+ ownerName: b.ownerName,
31107
+ ownerDiscriminator: b.ownerDiscriminator
31108
+ });
31109
+ }
31110
+ botCacheReady = true;
31111
+ }
31067
31112
  async function coldStartWarmup() {
31068
31113
  const start = Date.now();
31069
31114
  let attempt = 0;
31070
31115
  while (Date.now() - start < WARMUP_CEILING_MS) {
31071
31116
  try {
31072
31117
  const bots = await listMyBotsHttp();
31073
- botsById.clear();
31074
- for (const b of bots) {
31075
- botsById.set(b.id, {
31076
- name: b.name,
31077
- discriminator: b.discriminator,
31078
- description: b.description,
31079
- ownerName: b.ownerName,
31080
- ownerDiscriminator: b.ownerDiscriminator
31081
- });
31082
- }
31118
+ replaceBotCache(bots);
31083
31119
  log2.info("cold-start bot-cache warmup succeeded", { bots: bots.length, attempt });
31084
31120
  return;
31085
31121
  } catch {
@@ -31300,7 +31336,14 @@ async function createDaemon(opts) {
31300
31336
  const statusPath = opts.statusFilePath;
31301
31337
  const writeStatus = () => {
31302
31338
  const nowMs = Date.now();
31303
- writeStatusFile(statusPath, { writtenAt: nowMs, agents: manager.statusProjection(nowMs) });
31339
+ writeStatusFile(statusPath, {
31340
+ writtenAt: nowMs,
31341
+ agentSummary: {
31342
+ total: botCacheReady ? botsById.size : null,
31343
+ running: manager.runningAgentCount()
31344
+ },
31345
+ agents: manager.statusProjection(nowMs)
31346
+ });
31304
31347
  };
31305
31348
  writeStatus();
31306
31349
  statusTimer = setInterval(writeStatus, STATUS_WRITE_INTERVAL_MS);
@@ -31325,15 +31368,7 @@ async function createDaemon(opts) {
31325
31368
  if (!botsById.has(agentId)) {
31326
31369
  try {
31327
31370
  const bots = await listMyBotsHttp();
31328
- for (const b of bots) {
31329
- botsById.set(b.id, {
31330
- name: b.name,
31331
- discriminator: b.discriminator,
31332
- description: b.description,
31333
- ownerName: b.ownerName,
31334
- ownerDiscriminator: b.ownerDiscriminator
31335
- });
31336
- }
31371
+ replaceBotCache(bots);
31337
31372
  } catch {}
31338
31373
  }
31339
31374
  if (!botsById.has(agentId)) {
@@ -33649,8 +33684,13 @@ function daemonList(opts) {
33649
33684
  if (alive && statusPath) {
33650
33685
  const s = daemonStatusFromFile(statusPath, now);
33651
33686
  if (s.found) {
33652
- agents = s.agents.length;
33653
- running = s.agents.filter((a) => a.derivedActivity === "running").length;
33687
+ if (s.agentSummary) {
33688
+ agents = s.agentSummary.total;
33689
+ running = s.agentSummary.running;
33690
+ } else {
33691
+ agents = s.agents.length;
33692
+ running = s.agents.filter((a) => a.derivedActivity === "running").length;
33693
+ }
33654
33694
  lastActiveMs = daemonLastActiveMs(s, now);
33655
33695
  }
33656
33696
  }
@@ -33665,7 +33705,24 @@ function daemonList(opts) {
33665
33705
  return results;
33666
33706
  }
33667
33707
  var STATUS_STALE_MS = 20000;
33668
- var MISSING_STATUS = { found: false, ageMs: null, freshness: "missing", writtenAt: null, agents: [] };
33708
+ var MISSING_STATUS = {
33709
+ found: false,
33710
+ ageMs: null,
33711
+ freshness: "missing",
33712
+ writtenAt: null,
33713
+ agentSummary: null,
33714
+ agents: []
33715
+ };
33716
+ function validAgentSummary(value) {
33717
+ if (!value || typeof value !== "object")
33718
+ return null;
33719
+ const summary = value;
33720
+ const validTotal = summary.total === null || Number.isInteger(summary.total) && summary.total >= 0;
33721
+ const validRunning = Number.isInteger(summary.running) && summary.running >= 0;
33722
+ if (!validTotal || !validRunning)
33723
+ return null;
33724
+ return { total: summary.total, running: summary.running };
33725
+ }
33669
33726
  function daemonStatusFromFile(statusPath, nowMs) {
33670
33727
  if (!fs12.existsSync(statusPath))
33671
33728
  return MISSING_STATUS;
@@ -33677,6 +33734,7 @@ function daemonStatusFromFile(statusPath, nowMs) {
33677
33734
  ageMs,
33678
33735
  freshness: ageMs <= STATUS_STALE_MS ? "fresh" : "stale",
33679
33736
  writtenAt: snap.writtenAt,
33737
+ agentSummary: validAgentSummary(snap.agentSummary),
33680
33738
  agents: Array.isArray(snap.agents) ? snap.agents : []
33681
33739
  };
33682
33740
  } catch {
package/dist/index.js CHANGED
@@ -8025,6 +8025,9 @@ class AgentProcessManager {
8025
8025
  snapshot() {
8026
8026
  return this.state;
8027
8027
  }
8028
+ runningAgentCount() {
8029
+ return this.sessions.size;
8030
+ }
8028
8031
  auditContext(agentId) {
8029
8032
  return {
8030
8033
  sessionId: this.liveSessions.get(agentId) ?? null,
@@ -25814,6 +25817,7 @@ Then read @memory.md and your .context_timeline for durable context, and pull `
25814
25817
  class AgentRouter {
25815
25818
  opts;
25816
25819
  running = new Set;
25820
+ nextWakeAdmissionOrdinal = 1;
25817
25821
  runtimes = new Map;
25818
25822
  pendingResend = false;
25819
25823
  scheduleResend;
@@ -25974,7 +25978,7 @@ class AgentRouter {
25974
25978
  this.opts.typingTracker?.add(cmd.agentId, channelScope);
25975
25979
  const text2 = (this.opts.formatUnreadNoticeText ?? defaultFormatUnreadNoticeText)(cmd.unreadNotice);
25976
25980
  const producedEffect = this.opts.manager.deliver(cmd.agentId, {
25977
- id: `${cmd.agentId}:wake:${cmd.unreadNotice.channel}:${cmd.unreadNotice.latestSeq}`,
25981
+ id: `${cmd.agentId}:wake:${cmd.unreadNotice.channel}:${cmd.unreadNotice.latestSeq}:admission:${this.nextWakeAdmissionOrdinal++}`,
25978
25982
  seq: cmd.unreadNotice.latestSeq,
25979
25983
  text: text2
25980
25984
  });
@@ -29309,6 +29313,7 @@ async function createDaemon(opts) {
29309
29313
  typingTracker.clear(agentId);
29310
29314
  }
29311
29315
  const botsById = new Map;
29316
+ let botCacheReady = false;
29312
29317
  async function listMyBotsHttp() {
29313
29318
  const res = await fetch(`${opts.serverUrl}/api/community/daemon/bots`, {
29314
29319
  method: "GET",
@@ -29319,22 +29324,26 @@ async function createDaemon(opts) {
29319
29324
  const json2 = await res.json();
29320
29325
  return json2.bots ?? [];
29321
29326
  }
29327
+ function replaceBotCache(bots) {
29328
+ botsById.clear();
29329
+ for (const b of bots) {
29330
+ botsById.set(b.id, {
29331
+ name: b.name,
29332
+ discriminator: b.discriminator,
29333
+ description: b.description,
29334
+ ownerName: b.ownerName,
29335
+ ownerDiscriminator: b.ownerDiscriminator
29336
+ });
29337
+ }
29338
+ botCacheReady = true;
29339
+ }
29322
29340
  async function coldStartWarmup() {
29323
29341
  const start = Date.now();
29324
29342
  let attempt = 0;
29325
29343
  while (Date.now() - start < WARMUP_CEILING_MS) {
29326
29344
  try {
29327
29345
  const bots = await listMyBotsHttp();
29328
- botsById.clear();
29329
- for (const b of bots) {
29330
- botsById.set(b.id, {
29331
- name: b.name,
29332
- discriminator: b.discriminator,
29333
- description: b.description,
29334
- ownerName: b.ownerName,
29335
- ownerDiscriminator: b.ownerDiscriminator
29336
- });
29337
- }
29346
+ replaceBotCache(bots);
29338
29347
  log.info("cold-start bot-cache warmup succeeded", { bots: bots.length, attempt });
29339
29348
  return;
29340
29349
  } catch {
@@ -29555,7 +29564,14 @@ async function createDaemon(opts) {
29555
29564
  const statusPath = opts.statusFilePath;
29556
29565
  const writeStatus = () => {
29557
29566
  const nowMs = Date.now();
29558
- writeStatusFile(statusPath, { writtenAt: nowMs, agents: manager.statusProjection(nowMs) });
29567
+ writeStatusFile(statusPath, {
29568
+ writtenAt: nowMs,
29569
+ agentSummary: {
29570
+ total: botCacheReady ? botsById.size : null,
29571
+ running: manager.runningAgentCount()
29572
+ },
29573
+ agents: manager.statusProjection(nowMs)
29574
+ });
29559
29575
  };
29560
29576
  writeStatus();
29561
29577
  statusTimer = setInterval(writeStatus, STATUS_WRITE_INTERVAL_MS);
@@ -29580,15 +29596,7 @@ async function createDaemon(opts) {
29580
29596
  if (!botsById.has(agentId)) {
29581
29597
  try {
29582
29598
  const bots = await listMyBotsHttp();
29583
- for (const b of bots) {
29584
- botsById.set(b.id, {
29585
- name: b.name,
29586
- discriminator: b.discriminator,
29587
- description: b.description,
29588
- ownerName: b.ownerName,
29589
- ownerDiscriminator: b.ownerDiscriminator
29590
- });
29591
- }
29599
+ replaceBotCache(bots);
29592
29600
  } catch {}
29593
29601
  }
29594
29602
  if (!botsById.has(agentId)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alook/daemon",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "description": "Alook agent daemon — host-side runtime backend, process manager, credential proxy, and control plane.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/alookai/alook#readme",