@clawos-dev/clawd 0.2.193-beta.389.2a43229 → 0.2.194-beta.390.a17fa6d

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.cjs CHANGED
@@ -156,6 +156,7 @@ var init_methods = __esm({
156
156
  // 联系人身份由中心 server introspect 背书,不再是"对方颁发的 capability"。
157
157
  // 写入路径:device:connect 落 store + 自动反向(决策 #11);list / remove 作联系人列表读删。
158
158
  "contact:list",
159
+ "contact:pin",
159
160
  "contact:remove",
160
161
  // ---- visitor:* (web 访客 · persona web 分享,spec 2026-06-24-persona-web-share-design) ----
161
162
  // owner-only:列出登录访问过本机 public persona 的 web 访客(零安装、飞书登录、daemon 自签
@@ -247,7 +248,6 @@ var init_events = __esm({
247
248
  SESSION_STATUS_VALUES = [
248
249
  "idle",
249
250
  "running",
250
- "running-idle",
251
251
  "stopped",
252
252
  "error",
253
253
  "observing"
@@ -304,7 +304,9 @@ var init_errors = __esm({
304
304
  // app-builder 单栏默认 refactor (spec 2026-06-02-app-builder-single-pane-default-design):
305
305
  // appBuilder:createProject 加 personaId + session 未绑校验后抛的两个错码。
306
306
  WRONG_PERSONA: "WRONG_PERSONA",
307
- SESSION_ALREADY_BOUND: "SESSION_ALREADY_BOUND"
307
+ SESSION_ALREADY_BOUND: "SESSION_ALREADY_BOUND",
308
+ // 2026-07-02 unified people sidebar: contact:pin 时 deviceId 不在 store(可能被别处删了)
309
+ CONTACT_NOT_FOUND: "CONTACT_NOT_FOUND"
308
310
  };
309
311
  ClawdError = class extends Error {
310
312
  constructor(code, message) {
@@ -5640,7 +5642,7 @@ var init_inbox = __esm({
5640
5642
  });
5641
5643
 
5642
5644
  // ../protocol/src/contact.ts
5643
- var ContactSchema, ContactWireSchema, ContactRemoveArgsSchema, ContactRemoveOkSchema, ContactListOkSchema, ContactAddedFrameSchema, ContactRemovedFrameSchema;
5645
+ var ContactSchema, ContactWireSchema, ContactRemoveArgsSchema, ContactRemoveOkSchema, ContactListOkSchema, ContactAddedFrameSchema, ContactRemovedFrameSchema, ContactPinArgsSchema, ContactPinOkSchema, ContactPinnedFrameSchema;
5644
5646
  var init_contact = __esm({
5645
5647
  "../protocol/src/contact.ts"() {
5646
5648
  "use strict";
@@ -5669,7 +5671,13 @@ var init_contact = __esm({
5669
5671
  // 不用 .min(1):自动反向路径合法地存空串,禁止填假 token 占位(不造假数据)。
5670
5672
  connectToken: external_exports.string(),
5671
5673
  grants: external_exports.array(GrantSchema),
5672
- addedAt: external_exports.number().int().nonnegative()
5674
+ addedAt: external_exports.number().int().nonnegative(),
5675
+ /**
5676
+ * pin 时间戳(ms,Date.now() 语义);null = 未 pin。sidebar 顶部固定区渲染由此驱动。
5677
+ * 老 contacts.json 缺此字段 → zod default 补 null(无破坏性升级;不 orphan)。
5678
+ * 对齐 SessionFile.pinnedAt 语义(daemon 侧持久化,contact:pin RPC 更新 → contact:pinned push)。
5679
+ */
5680
+ pinnedAt: external_exports.number().int().nullable().default(null)
5673
5681
  }).strict();
5674
5682
  ContactWireSchema = ContactSchema;
5675
5683
  ContactRemoveArgsSchema = external_exports.object({
@@ -5691,6 +5699,20 @@ var init_contact = __esm({
5691
5699
  type: external_exports.literal("contact:removed"),
5692
5700
  deviceId: external_exports.string().min(1)
5693
5701
  }).strict();
5702
+ ContactPinArgsSchema = external_exports.object({
5703
+ deviceId: external_exports.string().min(1),
5704
+ pinned: external_exports.boolean()
5705
+ }).strict();
5706
+ ContactPinOkSchema = external_exports.object({
5707
+ type: external_exports.literal("contact:pin:ok"),
5708
+ deviceId: external_exports.string().min(1),
5709
+ pinnedAt: external_exports.number().int().nullable()
5710
+ }).strict();
5711
+ ContactPinnedFrameSchema = external_exports.object({
5712
+ type: external_exports.literal("contact:pinned"),
5713
+ deviceId: external_exports.string().min(1),
5714
+ pinnedAt: external_exports.number().int().nullable()
5715
+ }).strict();
5694
5716
  }
5695
5717
  });
5696
5718
 
@@ -41759,23 +41781,13 @@ function pushEventToBuffer(state, event, deps) {
41759
41781
  effects.push({ kind: "persist-file", file: next.file });
41760
41782
  effects.push(sessionInfoFrame(next.file));
41761
41783
  }
41762
- if (isTurnEnd && next.procAlive && (next.status === "running" || next.status === "spawning")) {
41784
+ if (isTurnEnd && next.subSessionMeta?.idleKillEnabled && next.procAlive && (next.status === "running" || next.status === "spawning")) {
41763
41785
  next.status = "running-idle";
41764
41786
  effects.push({
41765
- kind: "emit-frame",
41766
- frame: {
41767
- type: "session:status",
41768
- sessionId: next.file.sessionId,
41769
- status: "running-idle"
41770
- }
41787
+ kind: "schedule-idle-kill",
41788
+ sessionId: next.file.sessionId,
41789
+ ms: IDLE_KILL_DELAY_MS
41771
41790
  });
41772
- if (next.subSessionMeta?.idleKillEnabled) {
41773
- effects.push({
41774
- kind: "schedule-idle-kill",
41775
- sessionId: next.file.sessionId,
41776
- ms: IDLE_KILL_DELAY_MS
41777
- });
41778
- }
41779
41791
  }
41780
41792
  return { state: next, effects };
41781
41793
  }
@@ -41802,12 +41814,6 @@ function applyCommand(state, command, deps) {
41802
41814
  if (next.status === "running-idle") {
41803
41815
  effects.push({ kind: "cancel-idle-kill", sessionId });
41804
41816
  next.status = next.procAlive ? "running" : "idle";
41805
- if (next.procAlive) {
41806
- effects.push({
41807
- kind: "emit-frame",
41808
- frame: { type: "session:status", sessionId, status: "running" }
41809
- });
41810
- }
41811
41817
  }
41812
41818
  if (!next.procAlive) {
41813
41819
  next.procAlive = true;
@@ -42809,10 +42815,9 @@ function compressFrameForWire(frame) {
42809
42815
  switch (status) {
42810
42816
  case "spawning":
42811
42817
  case "running":
42812
- compressed = "running";
42813
- break;
42818
+ // sub-session(persona)专属内部状态:进程仍活着等 idle-kill;wire 协议看到的是 'running'
42814
42819
  case "running-idle":
42815
- compressed = "running-idle";
42820
+ compressed = "running";
42816
42821
  break;
42817
42822
  case "stopping":
42818
42823
  case "stopped":
@@ -42838,9 +42843,8 @@ function compressStatus(status) {
42838
42843
  switch (status) {
42839
42844
  case "spawning":
42840
42845
  case "running":
42841
- return "running";
42842
42846
  case "running-idle":
42843
- return "running-idle";
42847
+ return "running";
42844
42848
  case "stopping":
42845
42849
  case "stopped":
42846
42850
  return "stopped";
@@ -50314,6 +50318,18 @@ var ContactStore = class {
50314
50318
  if (existed) this.flush();
50315
50319
  return existed;
50316
50320
  }
50321
+ /**
50322
+ * 更新单条 contact 的 pinnedAt(对齐 session:pin pattern,2026-07-02 unified people sidebar)。
50323
+ * @param pinnedAt null = 未 pin;number = pin 时间戳(daemon 侧 Date.now())
50324
+ * @returns 是否命中:deviceId 不存在返 false,调用方按需 error/broadcast;命中即 flush。
50325
+ */
50326
+ setPin(deviceId, pinnedAt) {
50327
+ const existing = this.contacts.get(deviceId);
50328
+ if (!existing) return false;
50329
+ this.contacts.set(deviceId, { ...existing, pinnedAt });
50330
+ this.flush();
50331
+ return true;
50332
+ }
50317
50333
  flush() {
50318
50334
  const file = path30.join(this.dataDir, FILE_NAME);
50319
50335
  const tmp = `${file}.tmp-${process.pid}-${Date.now()}`;
@@ -50460,7 +50476,8 @@ async function autoReverseContact(args) {
50460
50476
  remoteUrl: args.selfUrl,
50461
50477
  connectToken: "",
50462
50478
  grants,
50463
- addedAt: now()
50479
+ addedAt: now(),
50480
+ pinnedAt: null
50464
50481
  };
50465
50482
  args.store.upsert(base);
50466
50483
  args.broadcast({ type: "contact:added", contact: base });
@@ -53975,6 +53992,31 @@ function buildContactHandlers(deps) {
53975
53992
  }
53976
53993
  };
53977
53994
  };
53995
+ const pin = async (frame, _client, ctx) => {
53996
+ ensureOwner(ctx);
53997
+ const { type: _t, requestId: _r, ...rest } = frame;
53998
+ const args = ContactPinArgsSchema.parse(rest);
53999
+ const pinnedAt = args.pinned ? deps.now() : null;
54000
+ const hit = deps.store.setPin(args.deviceId, pinnedAt);
54001
+ if (!hit) {
54002
+ throw new ClawdError(
54003
+ ERROR_CODES.CONTACT_NOT_FOUND,
54004
+ `CONTACT_NOT_FOUND: contact ${args.deviceId} not in store`
54005
+ );
54006
+ }
54007
+ deps.broadcast({
54008
+ type: "contact:pinned",
54009
+ deviceId: args.deviceId,
54010
+ pinnedAt
54011
+ });
54012
+ return {
54013
+ response: {
54014
+ type: "contact:pin:ok",
54015
+ deviceId: args.deviceId,
54016
+ pinnedAt
54017
+ }
54018
+ };
54019
+ };
53978
54020
  const remove = async (frame, _client, ctx) => {
53979
54021
  ensureOwner(ctx);
53980
54022
  const { type: _t, requestId: _r, ...rest } = frame;
@@ -53993,6 +54035,7 @@ function buildContactHandlers(deps) {
53993
54035
  };
53994
54036
  return {
53995
54037
  "contact:list": list,
54038
+ "contact:pin": pin,
53996
54039
  "contact:remove": remove
53997
54040
  };
53998
54041
  }
@@ -54149,7 +54192,8 @@ function buildDeviceHandlers(deps) {
54149
54192
  // 过期后对方拒 TOKEN_EXPIRED → 重新 device:connect 换新票)
54150
54193
  connectToken: exchanged.token,
54151
54194
  grants: wh.grants,
54152
- addedAt: now()
54195
+ addedAt: now(),
54196
+ pinnedAt: null
54153
54197
  };
54154
54198
  deps.store.upsert(contact);
54155
54199
  deps.broadcast({ type: "contact:added", contact });
@@ -56461,7 +56505,8 @@ function buildMethodHandlers(deps) {
56461
56505
  }),
56462
56506
  ...buildContactHandlers({
56463
56507
  store: deps.contactStore,
56464
- broadcast: deps.broadcastToOwners
56508
+ broadcast: deps.broadcastToOwners,
56509
+ now: () => Date.now()
56465
56510
  }),
56466
56511
  whoami: buildWhoamiHandler({
56467
56512
  ownerDisplayName: deps.ownerDisplayName,
@@ -56796,6 +56841,7 @@ var METHOD_GRANT_MAP = {
56796
56841
  // 飞书统一身份 Phase 3 (决策 #14): received-capability:* 正名 contact:*。
56797
56842
  // 写入路径在 device:connect / 自动反向;list / remove 作联系人读 / 删,owner-only。
56798
56843
  "contact:list": ADMIN_ANY,
56844
+ "contact:pin": ADMIN_ANY,
56799
56845
  "contact:remove": ADMIN_ANY,
56800
56846
  // ---- visitor:* (访客名单,owner-only) ----
56801
56847
  // owner 看完整访客名单(含没开会话的);guest 不可调(handler 内再 assertOwner 兜底)。