@clawos-dev/clawd 0.2.220 → 0.2.221-beta.433.d7a6891

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
@@ -41651,47 +41651,6 @@ function escapeAttr(v2) {
41651
41651
  return v2.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
41652
41652
  }
41653
41653
 
41654
- // src/shift/end-frame-handler.ts
41655
- function makeEndFrameHandler(sessionId, onEnd) {
41656
- return (frame) => {
41657
- if (!frame || typeof frame !== "object") return;
41658
- const f = frame;
41659
- if (f.type !== "session:status") return;
41660
- if (f.sessionId !== sessionId) return;
41661
- if (f.status === "running-idle") {
41662
- onEnd({ kind: "idle" });
41663
- return;
41664
- }
41665
- if (f.status === "stopped") {
41666
- onEnd({ kind: "stopped" });
41667
- return;
41668
- }
41669
- if (f.status === "error") {
41670
- onEnd({ kind: "error", message: f.message ?? "cc proc error" });
41671
- return;
41672
- }
41673
- };
41674
- }
41675
-
41676
- // src/shift/end-dispatcher.ts
41677
- function dispatchShiftEnd(info, settle, killImpl) {
41678
- if (info.kind === "idle") {
41679
- settle({ ok: true });
41680
- killImpl();
41681
- return;
41682
- }
41683
- if (info.kind === "stopped") {
41684
- settle({ error: "cc exited before turn completed" });
41685
- return;
41686
- }
41687
- if (info.kind === "error") {
41688
- settle({ error: info.message });
41689
- return;
41690
- }
41691
- const _exhaustive = info;
41692
- throw new Error(`dispatchShiftEnd: unhandled kind ${JSON.stringify(_exhaustive)}`);
41693
- }
41694
-
41695
41654
  // src/session/runner.ts
41696
41655
  var import_node_os4 = __toESM(require("os"), 1);
41697
41656
  var import_node_path7 = __toESM(require("path"), 1);
@@ -41923,7 +41882,8 @@ function buildSpawnContext(state, deps) {
41923
41882
  const personaId = file.ownerPersonaId;
41924
41883
  if (personaId) env.CLAWD_PERSONA_ID = personaId;
41925
41884
  const dispatchMcpConfigPath2 = deps.getDispatchMcpConfigPath?.() ?? null;
41926
- const ticketMcpConfigPath2 = deps.getTicketMcpConfigPath?.() ?? null;
41885
+ const ticketMcpConfigPathRaw = deps.getTicketMcpConfigPath?.() ?? null;
41886
+ const ticketMcpConfigPath2 = ticketMcpConfigPathRaw && file.ownerPersonaId === "persona-ticket-manager" ? ticketMcpConfigPathRaw : null;
41927
41887
  const shiftMcpConfigPath2 = deps.getShiftMcpConfigPath?.() ?? null;
41928
41888
  const inboxMcpConfigPath2 = deps.getInboxMcpConfigPath?.() ?? null;
41929
41889
  const ctx = {
@@ -42748,7 +42708,7 @@ var SessionRunner = class {
42748
42708
  getDispatchMcpConfigPath: this.hooks.getDispatchMcpConfigPath,
42749
42709
  getShiftMcpConfigPath: this.hooks.getShiftMcpConfigPath,
42750
42710
  getInboxMcpConfigPath: this.hooks.getInboxMcpConfigPath,
42751
- // Ticket MCP:透传 ticket.mcp.json 路径闭包(所有 persona session 都挂,无 gating)
42711
+ // Ticket MCP:透传 ticket.mcp.json 路径闭包(reducer 内做 persona-ticket-manager gating)
42752
42712
  getTicketMcpConfigPath: this.hooks.getTicketMcpConfigPath,
42753
42713
  lookupDispatchByBSessionId: this.hooks.lookupDispatchByBSessionId,
42754
42714
  // ReadyGate v2:透传 mode 让 reducer send / ready-detected 分支决定走暂存队列还是直写
@@ -44510,9 +44470,8 @@ var SessionManager = class {
44510
44470
  * 跟 createDispatchedSession 的差异:
44511
44471
  * - 不带 dispatchId / source / task pack;prompt 直接当第一条 user message
44512
44472
  * - 不调 personaDispatchManager.registerBSession
44513
- * - 多返一个 ended Promise,监听 session:status 帧翻译成 shift 业务终态 union
44514
- * (ShiftSessionEnded:{ok:true} | {error:string}),不经 exit code 中转
44515
- * - turn-idle 到达即视为业务完成 → settle {ok:true} + fire-and-forget kill cc
44473
+ * - 多返一个 ended Promise,监听 session:status (stopped/error) 帧通过现有
44474
+ * subscribe() 入口(白名单已含 session:status)
44516
44475
  * - kill 通过 runner.input({command:{kind:'stop'}}) 触发 SIGKILL → proc-exit
44517
44476
  */
44518
44477
  createShiftSession(args) {
@@ -44556,18 +44515,16 @@ var SessionManager = class {
44556
44515
  unsubscribe();
44557
44516
  resolveEnded(info);
44558
44517
  };
44559
- const killImpl = () => {
44560
- const r = this.runners.get(sessionId);
44561
- if (!r) return;
44562
- r.input({ kind: "command", command: { kind: "stop" } });
44563
- };
44564
- unsubscribe = this.subscribe(
44565
- sessionId,
44566
- scope,
44567
- makeEndFrameHandler(sessionId, (info) => {
44568
- dispatchShiftEnd(info, settle, killImpl);
44569
- })
44570
- );
44518
+ unsubscribe = this.subscribe(sessionId, scope, (frame) => {
44519
+ if (frame.type !== "session:status") return;
44520
+ const f = frame;
44521
+ if (f.sessionId !== sessionId) return;
44522
+ if (f.status === "stopped") {
44523
+ settle({ exitCode: f.exitCode ?? null });
44524
+ } else if (f.status === "error") {
44525
+ settle({ exitCode: null, error: f.message ?? "cc proc error" });
44526
+ }
44527
+ });
44571
44528
  const runner = this.ensureRunnerForScope(file, scope);
44572
44529
  this.deps.logger?.info("shift.createShiftSession.runner-ready", { sessionId });
44573
44530
  runner.input({
@@ -44580,7 +44537,12 @@ var SessionManager = class {
44580
44537
  })
44581
44538
  }
44582
44539
  });
44583
- return { sessionId, ended, kill: killImpl };
44540
+ const kill = () => {
44541
+ const r = this.runners.get(sessionId);
44542
+ if (!r) return;
44543
+ r.input({ kind: "command", command: { kind: "stop" } });
44544
+ };
44545
+ return { sessionId, ended, kill };
44584
44546
  }
44585
44547
  /**
44586
44548
  * 老板插话:把 'inject-owner-text' input 喂给对应 runner,
@@ -48485,11 +48447,15 @@ function createShiftSpawnFn(deps) {
48485
48447
  void created.ended.then((info) => {
48486
48448
  clearTimeout(timer);
48487
48449
  if (settled) return;
48488
- if ("ok" in info) {
48450
+ if (info.error) {
48451
+ settle({ kind: "error", error: info.error });
48452
+ return;
48453
+ }
48454
+ if (info.exitCode === 0) {
48489
48455
  settle({ kind: "ok" });
48490
48456
  return;
48491
48457
  }
48492
- settle({ kind: "error", error: info.error });
48458
+ settle({ kind: "error", error: `cc exited with code ${info.exitCode}` });
48493
48459
  });
48494
48460
  return { sessionId: created.sessionId, ended };
48495
48461
  };
@@ -54226,22 +54192,6 @@ var LoginFlow = class {
54226
54192
  } catch (err) {
54227
54193
  return { ok: false, reason: `user_info failed: ${err.message}` };
54228
54194
  }
54229
- if (!identity.unionId) {
54230
- return { ok: false, reason: "union_id missing from TTC user_info" };
54231
- }
54232
- try {
54233
- await this.deps.upsertBinding({
54234
- deviceId: this.deps.getDeviceId(),
54235
- unionId: identity.unionId,
54236
- displayName: identity.displayName,
54237
- avatarUrl: identity.avatarUrl ?? null
54238
- });
54239
- } catch (err) {
54240
- return {
54241
- ok: false,
54242
- reason: `device_binding upsert failed: ${err.message}`
54243
- };
54244
- }
54245
54195
  const expiresAtNum = params.expiresAt ? Number.parseInt(params.expiresAt, 10) : NaN;
54246
54196
  this.deps.store.write({
54247
54197
  identity,
@@ -54410,58 +54360,6 @@ async function centralListDevices(opts) {
54410
54360
  return out;
54411
54361
  }
54412
54362
 
54413
- // src/feishu-auth/device-binding-client.ts
54414
- var DeviceBindingClientError = class extends Error {
54415
- constructor(code, message, cause) {
54416
- super(message);
54417
- this.code = code;
54418
- this.cause = cause;
54419
- this.name = "DeviceBindingClientError";
54420
- }
54421
- code;
54422
- cause;
54423
- };
54424
- var DEFAULT_TIMEOUT_MS4 = 8e3;
54425
- async function upsertDeviceBinding(opts) {
54426
- const doFetch = opts.fetchImpl ?? fetch;
54427
- const ac = new AbortController();
54428
- const timer = setTimeout(() => ac.abort(), opts.timeoutMs ?? DEFAULT_TIMEOUT_MS4);
54429
- const body = { unionId: opts.unionId };
54430
- if (opts.avatarUrl != null) body.avatarUrl = opts.avatarUrl;
54431
- let res;
54432
- try {
54433
- res = await doFetch(`${opts.apiUrl}/api/device-bindings/self`, {
54434
- method: "PUT",
54435
- signal: ac.signal,
54436
- headers: {
54437
- authorization: `Bearer ${opts.apiKey}`,
54438
- "x-did": encodeURIComponent(opts.deviceId),
54439
- "x-name": encodeURIComponent(opts.displayName),
54440
- "x-scene": "daemon",
54441
- "content-type": "application/json"
54442
- },
54443
- body: JSON.stringify(body)
54444
- });
54445
- } catch (err) {
54446
- clearTimeout(timer);
54447
- throw new DeviceBindingClientError(
54448
- "NETWORK",
54449
- `network error: ${err.message}`,
54450
- err
54451
- );
54452
- } finally {
54453
- clearTimeout(timer);
54454
- }
54455
- if (!res.ok) {
54456
- let detail = "";
54457
- try {
54458
- detail = JSON.stringify(await res.json());
54459
- } catch {
54460
- }
54461
- throw new DeviceBindingClientError("API_ERROR", `HTTP ${res.status}: ${detail}`);
54462
- }
54463
- }
54464
-
54465
54363
  // src/feishu-auth/verify-token.ts
54466
54364
  var crypto14 = __toESM(require("crypto"), 1);
54467
54365
  var CONNECT_TOKEN_PREFIX = "clawdtk1";
@@ -59359,10 +59257,10 @@ async function startDaemon(config) {
59359
59257
  import_node_path64.default.join(here, "..", "dist", "ticket", "mcp-server.cjs")
59360
59258
  ];
59361
59259
  const ticketServerScriptPath = ticketServerCandidates.find((p2) => import_node_fs51.default.existsSync(p2));
59362
- const ticketCallerDid = authFile.deviceId;
59363
- const ticketCallerName = ownerDisplayName;
59260
+ const ticketCallerDid = feishuIdentity?.identity.unionId ?? "";
59261
+ const ticketCallerName = feishuIdentity?.identity.displayName ?? "";
59364
59262
  let ticketMcpConfigPath2;
59365
- if (ticketServerScriptPath) {
59263
+ if (ticketServerScriptPath && ticketCallerDid) {
59366
59264
  const ticketLogPath = import_node_path64.default.join(config.dataDir, "ticket-mcp-server.log");
59367
59265
  ticketMcpConfigPath2 = writeTicketMcpConfig({
59368
59266
  dataDir: config.dataDir,
@@ -59380,7 +59278,7 @@ async function startDaemon(config) {
59380
59278
  });
59381
59279
  } else {
59382
59280
  logger.warn("ticket-mcp skipped", {
59383
- reason: "ticket-mcp-server.cjs not found (need build)"
59281
+ reason: !ticketCallerDid ? "caller did missing (login required)" : "ticket-mcp-server.cjs not found (need build)"
59384
59282
  });
59385
59283
  }
59386
59284
  const shiftServerCandidates = [
@@ -59631,16 +59529,7 @@ async function startDaemon(config) {
59631
59529
  store: ownerIdentityStore,
59632
59530
  fetchUserInfo: (ttcToken) => fetchTtcUserInfo({ apiBase: TTC_HOSTS.api, token: ttcToken }),
59633
59531
  ttcAuthBase: TTC_HOSTS.auth,
59634
- getCallbackUrl: () => `http://127.0.0.1:${config.port}/auth/callback`,
59635
- // device_bindings upsert(did ↔ 飞书 unionId 映射):
59636
- // deviceId 从 auth.json 稳定读;apiUrl 走同一份 clawosApi;apiKey 复用 CLAWD_TICKETS_API_KEY。
59637
- // 失败即登录失败(fail-hard,login-flow.spec §upsert 失败)。
59638
- getDeviceId: () => authFile.deviceId,
59639
- upsertBinding: (opts) => upsertDeviceBinding({
59640
- apiUrl: config.clawosApi ?? DEFAULT_CLAWOS_API,
59641
- apiKey: resolveClawdTicketsApiKey(),
59642
- ...opts
59643
- })
59532
+ getCallbackUrl: () => `http://127.0.0.1:${config.port}/auth/callback`
59644
59533
  });
59645
59534
  const visitorStore = createVisitorStore({ dir: config.dataDir });
59646
59535
  const exchangeVisitorToken = buildVisitorLogin({