@clawos-dev/clawd 0.2.687 → 0.2.691

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
@@ -43380,7 +43380,7 @@ var require_websocket = __commonJS({
43380
43380
  var http2 = require("http");
43381
43381
  var net2 = require("net");
43382
43382
  var tls = require("tls");
43383
- var { randomBytes: randomBytes2, createHash: createHash5 } = require("crypto");
43383
+ var { randomBytes: randomBytes2, createHash: createHash6 } = require("crypto");
43384
43384
  var { Duplex, Readable: Readable4 } = require("stream");
43385
43385
  var { URL: URL2 } = require("url");
43386
43386
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -44040,7 +44040,7 @@ var require_websocket = __commonJS({
44040
44040
  abortHandshake(websocket, socket, "Invalid Upgrade header");
44041
44041
  return;
44042
44042
  }
44043
- const digest = createHash5("sha1").update(key + GUID).digest("base64");
44043
+ const digest = createHash6("sha1").update(key + GUID).digest("base64");
44044
44044
  if (res.headers["sec-websocket-accept"] !== digest) {
44045
44045
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
44046
44046
  return;
@@ -44407,7 +44407,7 @@ var require_websocket_server = __commonJS({
44407
44407
  var EventEmitter2 = require("events");
44408
44408
  var http2 = require("http");
44409
44409
  var { Duplex } = require("stream");
44410
- var { createHash: createHash5 } = require("crypto");
44410
+ var { createHash: createHash6 } = require("crypto");
44411
44411
  var extension2 = require_extension();
44412
44412
  var PerMessageDeflate2 = require_permessage_deflate();
44413
44413
  var subprotocol2 = require_subprotocol();
@@ -44708,7 +44708,7 @@ var require_websocket_server = __commonJS({
44708
44708
  );
44709
44709
  }
44710
44710
  if (this._state > RUNNING) return abortHandshake(socket, 503);
44711
- const digest = createHash5("sha1").update(key + GUID).digest("base64");
44711
+ const digest = createHash6("sha1").update(key + GUID).digest("base64");
44712
44712
  const headers = [
44713
44713
  "HTTP/1.1 101 Switching Protocols",
44714
44714
  "Upgrade: websocket",
@@ -46776,7 +46776,7 @@ function requireEnvironmentIdentity(stores, environment) {
46776
46776
  var import_node_path89 = __toESM(require("path"), 1);
46777
46777
  var import_node_fs68 = __toESM(require("fs"), 1);
46778
46778
  var import_node_os33 = __toESM(require("os"), 1);
46779
- var import_node_crypto30 = require("crypto");
46779
+ var import_node_crypto31 = require("crypto");
46780
46780
  var import_node_url6 = require("url");
46781
46781
 
46782
46782
  // src/logger.ts
@@ -48375,7 +48375,9 @@ function pushEventToBufferInPlace(next, event, deps) {
48375
48375
  next.file = {
48376
48376
  ...next.file,
48377
48377
  updatedAt: nowIso(deps),
48378
- ...cloudPerTurn && isUserText && next.status !== "error" ? {
48378
+ // Only a local send carries `sender`. A user_text echoed by the engine stream (skill hint, interrupt marker) has no
48379
+ // turn stream of its own, so recording it would leave a pending turn that startup recovery replays to the Pod.
48380
+ ...cloudPerTurn && isUserText && withSeq.sender && next.status !== "error" ? {
48379
48381
  cloudConversationId: next.file.cloudConversationId ?? next.file.cloudExecutionId ?? cloudTurnId,
48380
48382
  cloudPendingTurns: [...next.file.cloudPendingTurns ?? [], { id: cloudTurnId, text: withSeq.text }]
48381
48383
  } : {},
@@ -53581,6 +53583,10 @@ async function centralRequest(opts, path111, init) {
53581
53583
  }
53582
53584
  clearTimeout(timer);
53583
53585
  if (res.status === 401) {
53586
+ const detail = await res.json().catch(() => null);
53587
+ if (path111 === "/api/persona-cloud/github/oauth/token" && detail?.errorCode === "GITHUB_REAUTH_REQUIRED") {
53588
+ throw new CentralClientError("API_ERROR", typeof detail.message === "string" ? detail.message : "\u8BF7\u91CD\u65B0\u5173\u8054 GitHub", void 0, 401);
53589
+ }
53584
53590
  throw new CentralClientError("UNAUTHORIZED", "login pass rejected by center");
53585
53591
  }
53586
53592
  if (!res.ok) {
@@ -53759,11 +53765,12 @@ async function centralGithubAuthToken(opts) {
53759
53765
  const body = await centralRequest(opts, "/api/persona-cloud/github/oauth/token", {
53760
53766
  method: "POST",
53761
53767
  bearer: opts.loginPass,
53762
- body: {}
53768
+ body: { ...opts.rejectedToken ? { rejectedToken: opts.rejectedToken } : {} }
53763
53769
  });
53764
53770
  if (body.token === null || body.token === void 0) return void 0;
53765
53771
  if (typeof body.token !== "string" || !body.token) throw new CentralClientError("BAD_RESPONSE", "github/oauth/token: malformed token");
53766
- return { token: body.token, login: typeof body.login === "string" ? body.login : "" };
53772
+ if (body.expiresAt !== void 0 && (typeof body.expiresAt !== "string" || !Number.isFinite(Date.parse(body.expiresAt)))) throw new CentralClientError("BAD_RESPONSE", "github/oauth/token: malformed expiry");
53773
+ return { token: body.token, login: typeof body.login === "string" ? body.login : "", ...typeof body.expiresAt === "string" ? { expiresAt: body.expiresAt } : {} };
53767
53774
  }
53768
53775
  async function centralClaimPublisher(opts) {
53769
53776
  await centralRequest(opts, `/api/persona-cloud/personas/${encodeURIComponent(opts.personaId)}/publisher`, {
@@ -57519,8 +57526,8 @@ function createGhRunner(defaults) {
57519
57526
  const baseTimeoutMs = defaults?.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
57520
57527
  const spawn17 = defaults?.execFile ?? import_node_child_process9.execFile;
57521
57528
  return {
57522
- run(args, opts) {
57523
- const token = defaults?.token?.();
57529
+ async run(args, opts) {
57530
+ const token = await defaults?.token?.();
57524
57531
  return new Promise((resolve9, reject) => {
57525
57532
  spawn17(
57526
57533
  "gh",
@@ -58044,25 +58051,59 @@ var CloudGatewayClient = class {
58044
58051
  return list.find((p3) => p3.personaId === gatewayPersonaId)?.connectors ?? [];
58045
58052
  }
58046
58053
  async workspaceCommand(personaId2, input) {
58047
- const { apiKey, gatewayUrl } = await this.credentials();
58048
- const res = await this.fetchImpl(
58049
- gatewayUrl + GATEWAY_ROUTES.workspace(personaId2),
58050
- {
58051
- method: "POST",
58052
- headers: {
58053
- authorization: `Bearer ${apiKey}`,
58054
- "content-type": "application/json"
58055
- },
58056
- body: JSON.stringify(input),
58057
- signal: AbortSignal.timeout(3e5)
58054
+ const started = performance.now();
58055
+ const traceId = typeof input.traceId === "string" && /^[A-Za-z0-9:_-]{1,128}$/.test(input.traceId) ? input.traceId : crypto.randomUUID();
58056
+ const { traceId: _trace, ...body } = input;
58057
+ const meta = {
58058
+ traceId,
58059
+ sessionId: input.sessionId,
58060
+ personaId: personaId2,
58061
+ action: input.action,
58062
+ page: typeof input.page === "number" && Number.isInteger(input.page) && input.page >= 1 && input.page <= 1e3 ? input.page : void 0,
58063
+ hasSearch: typeof input.search === "string" && input.search.length > 0,
58064
+ searchLength: typeof input.search === "string" ? input.search.length : 0,
58065
+ hasCursor: typeof input.cursor === "string"
58066
+ };
58067
+ const log = (event, detail) => {
58068
+ try {
58069
+ this.deps.logger?.info("cloud.workspace.daemon." + event, { ...meta, ...detail });
58070
+ } catch {
58058
58071
  }
58059
- );
58060
- const body = await res.json();
58061
- if (!res.ok)
58062
- throw new Error(
58063
- body.error?.message ?? `Cloud workspace request failed (${res.status})`
58064
- );
58065
- return CloudWorkspaceResultSchema.parse(body);
58072
+ };
58073
+ const measure = async (stage, run) => {
58074
+ const at3 = performance.now();
58075
+ let outcome2 = "error";
58076
+ try {
58077
+ const value = await run();
58078
+ outcome2 = "ok";
58079
+ return value;
58080
+ } finally {
58081
+ log("stage", { stage, outcome: outcome2, durationMs: Math.round(performance.now() - at3) });
58082
+ }
58083
+ };
58084
+ let outcome = "error";
58085
+ let statusCode;
58086
+ log("started", {});
58087
+ try {
58088
+ const { apiKey, gatewayUrl } = await measure("credentials", () => this.credentials());
58089
+ const res = await measure("gateway.headers", () => this.fetchImpl(
58090
+ gatewayUrl + GATEWAY_ROUTES.workspace(personaId2),
58091
+ {
58092
+ method: "POST",
58093
+ headers: { authorization: "Bearer " + apiKey, "content-type": "application/json", "x-trace-id": traceId },
58094
+ body: JSON.stringify(body),
58095
+ signal: AbortSignal.timeout(3e5)
58096
+ }
58097
+ ));
58098
+ statusCode = res.status;
58099
+ const result = await measure("gateway.body", () => res.json());
58100
+ if (!res.ok) throw new Error(result.error?.message ?? "Cloud workspace request failed (" + res.status + ")");
58101
+ const parsed = CloudWorkspaceResultSchema.parse(result);
58102
+ outcome = "ok";
58103
+ return parsed;
58104
+ } finally {
58105
+ log("finished", { outcome, statusCode, durationMs: Math.round(performance.now() - started) });
58106
+ }
58066
58107
  }
58067
58108
  async openTurn(personaId2, opts) {
58068
58109
  const { apiKey, gatewayUrl } = await this.credentials();
@@ -62165,23 +62206,38 @@ function createGithubApi(args) {
62165
62206
  const seal = args.seal ?? sealWithSodium;
62166
62207
  const timeoutMs = args.timeoutMs ?? TIMEOUT_MS;
62167
62208
  const secretsPath = (slug, environment) => `/repos/${slug}/${environment ? `environments/${encodeURIComponent(environment)}` : "actions"}/secrets`;
62168
- async function request(method, path111, body) {
62169
- let res;
62170
- try {
62171
- res = await doFetch(`${API}${path111}`, {
62172
- method,
62173
- headers: {
62174
- Authorization: `Bearer ${args.token}`,
62175
- Accept: "application/vnd.github+json",
62176
- "X-GitHub-Api-Version": "2022-11-28",
62177
- ...body !== void 0 ? { "Content-Type": "application/json" } : {}
62178
- },
62179
- ...body !== void 0 ? { body: JSON.stringify(body) } : {},
62180
- signal: AbortSignal.timeout(timeoutMs)
62181
- });
62182
- } catch (err) {
62183
- throw new GithubApiError(0, `\u8FDE\u4E0D\u4E0A GitHub\uFF1A${err instanceof Error ? err.message : String(err)}`);
62209
+ async function authenticatedFetch(path111, init) {
62210
+ let token = args.identity ? (await args.identity.refresh())?.token : args.token;
62211
+ if (!token) throw new GithubApiError(401, "\u8BF7\u5148\u5173\u8054 GitHub");
62212
+ for (let attempt = 0; ; attempt++) {
62213
+ let res;
62214
+ try {
62215
+ res = await doFetch(API + path111, {
62216
+ ...init,
62217
+ headers: { ...init.headers, Authorization: "Bearer " + token },
62218
+ signal: AbortSignal.timeout(timeoutMs)
62219
+ });
62220
+ } catch (err) {
62221
+ throw new GithubApiError(0, "\u8FDE\u4E0D\u4E0A GitHub\uFF1A" + (err instanceof Error ? err.message : String(err)));
62222
+ }
62223
+ if (res.status !== 401 || attempt !== 0 || !args.identity) return res;
62224
+ const renewed = await args.identity.recover(token);
62225
+ if (!renewed || renewed.token === token) return res;
62226
+ await res.body?.cancel();
62227
+ token = renewed.token;
62184
62228
  }
62229
+ }
62230
+ async function request(method, path111, body) {
62231
+ const res = await authenticatedFetch(path111, {
62232
+ method,
62233
+ redirect: "error",
62234
+ headers: {
62235
+ Accept: "application/vnd.github+json",
62236
+ "X-GitHub-Api-Version": "2022-11-28",
62237
+ ...body !== void 0 ? { "Content-Type": "application/json" } : {}
62238
+ },
62239
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {}
62240
+ });
62185
62241
  const text = await res.text();
62186
62242
  let json = void 0;
62187
62243
  if (text) {
@@ -62266,8 +62322,8 @@ function createGithubApi(args) {
62266
62322
  const signal = AbortSignal.timeout(timeoutMs);
62267
62323
  let res;
62268
62324
  try {
62269
- res = await doFetch(`${API}/repos/${slug}/actions/artifacts/${artifactId}/zip`, {
62270
- headers: { Authorization: `Bearer ${args.token}`, Accept: "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28" },
62325
+ res = await authenticatedFetch(`/repos/${slug}/actions/artifacts/${artifactId}/zip`, {
62326
+ headers: { Accept: "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28" },
62271
62327
  redirect: "manual",
62272
62328
  signal
62273
62329
  });
@@ -62892,7 +62948,8 @@ function networkOptions(auth) {
62892
62948
  return auth?.source === "file" ? { prefix: [...QUIET_GIT_ARGS, "-c", "credential.helper=", "-c", `credential.helper=${INLINE_HELPER}`], env: { ...QUIET_GIT_ENV, CLAWD_GITHUB_TOKEN: auth.token } } : { prefix: [...QUIET_GIT_ARGS], env: QUIET_GIT_ENV };
62893
62949
  }
62894
62950
  async function networkGit(exec, dir, auth, args, what) {
62895
- const opts = networkOptions(auth);
62951
+ const current = typeof auth === "function" ? await auth() : auth;
62952
+ const opts = networkOptions(current);
62896
62953
  return mustGit(exec, dir, [...opts.prefix, ...args], what, { timeoutMs: 12e4, env: opts.env });
62897
62954
  }
62898
62955
  async function gitPush(exec, dir, auth, refspec = "HEAD:refs/heads/integration") {
@@ -63807,7 +63864,11 @@ function buildDeployHandlers(deps) {
63807
63864
  async function requireGithub() {
63808
63865
  const auth = await deps.githubIdentity.refresh();
63809
63866
  if (!auth) throw new ClawdError(ERROR_CODES.INTERNAL, NO_GITHUB_AUTH);
63810
- return { auth, api: deps.githubApi(auth.token) };
63867
+ return { auth: async () => {
63868
+ const current = await deps.githubIdentity.refresh();
63869
+ if (!current) throw new ClawdError(ERROR_CODES.INTERNAL, NO_GITHUB_AUTH);
63870
+ return current;
63871
+ }, api: deps.githubApi(auth.token) };
63811
63872
  }
63812
63873
  function mustPersona(personaId2) {
63813
63874
  if (!deps.hasPersona(personaId2)) {
@@ -65032,13 +65093,82 @@ function createGithubIdentity(deps) {
65032
65093
  let pendingOauth = null;
65033
65094
  let staleCenterToken;
65034
65095
  const listeners = /* @__PURE__ */ new Set();
65035
- async function refresh() {
65036
- const mine = ++seq;
65037
- const resolved = await deps.resolve();
65038
- if (mine === seq) auth = resolved;
65039
- return resolved;
65096
+ let managedToken;
65097
+ const oauthCandidate = (token) => /^gh[ou]_/.test(token);
65098
+ const oauthManaged = (token) => oauthCandidate(token) && (managedToken === token || deps.isManaged?.(token) === true);
65099
+ let acquisition;
65100
+ let centerFlight;
65101
+ let centerCache;
65102
+ let writes = Promise.resolve();
65103
+ function remember(got) {
65104
+ const expiry = got.expiresAt ? Date.parse(got.expiresAt) - 6e4 : Infinity;
65105
+ centerCache = { token: got.token, until: Math.min(deps.now() + 2e4, expiry) };
65106
+ }
65107
+ function persist(token, generation, managed = false) {
65108
+ const write = writes.catch(() => {
65109
+ }).then(async () => {
65110
+ if (generation !== seq) return;
65111
+ const stored = await deps.store(token);
65112
+ if (generation !== seq) return;
65113
+ deps.markManaged?.(managed ? token : void 0);
65114
+ managedToken = managed ? token : void 0;
65115
+ auth = stored;
65116
+ statusCache.clear();
65117
+ pendingOauth = null;
65118
+ for (const cb of listeners) cb();
65119
+ });
65120
+ writes = write;
65121
+ return write;
65122
+ }
65123
+ async function syncCenter(local, rejectedToken) {
65124
+ if (!oauthCandidate(local.token)) return local;
65125
+ const managed = oauthManaged(local.token);
65126
+ if (!rejectedToken && centerCache?.token === local.token && deps.now() < centerCache.until) return local;
65127
+ if (centerFlight) return centerFlight;
65128
+ const generation = seq;
65129
+ const task = (async () => {
65130
+ let got;
65131
+ try {
65132
+ got = await deps.oauth.token(rejectedToken);
65133
+ } catch (err) {
65134
+ if (managed) throw err;
65135
+ return local;
65136
+ }
65137
+ if (generation !== seq) return auth;
65138
+ if (!got || !managed && got.token !== local.token) {
65139
+ remember({ token: local.token });
65140
+ return local;
65141
+ }
65142
+ if (!managed || got.token !== local.token) await persist(got.token, generation, true);
65143
+ if (generation !== seq) return auth;
65144
+ remember(got);
65145
+ return auth ?? local;
65146
+ })().finally(() => {
65147
+ if (centerFlight === task) centerFlight = void 0;
65148
+ });
65149
+ centerFlight = task;
65150
+ return task;
65151
+ }
65152
+ function refresh() {
65153
+ if (acquisition) return acquisition;
65154
+ const generation = seq;
65155
+ const task = (async () => {
65156
+ const resolved = await deps.resolve();
65157
+ if (generation !== seq) return auth;
65158
+ auth = resolved;
65159
+ return resolved ? syncCenter(resolved) : void 0;
65160
+ })().finally(() => {
65161
+ if (acquisition === task) acquisition = void 0;
65162
+ });
65163
+ acquisition = task;
65164
+ return task;
65040
65165
  }
65041
- async function whoami(a2) {
65166
+ async function recover(rejectedToken) {
65167
+ const current = await refresh();
65168
+ if (!current || current.token !== rejectedToken || !oauthManaged(current.token)) return current;
65169
+ return syncCenter(current, rejectedToken);
65170
+ }
65171
+ async function whoami(a2, recovering = false) {
65042
65172
  const hit = statusCache.get(a2.token);
65043
65173
  if (hit && deps.now() - hit.at < cacheMs) return hit.status;
65044
65174
  let status2;
@@ -65046,19 +65176,26 @@ function createGithubIdentity(deps) {
65046
65176
  const { login } = await deps.api(a2.token).whoami();
65047
65177
  status2 = { status: "authorized", login, source: a2.source };
65048
65178
  } catch (err) {
65179
+ if (!recovering && err instanceof GithubApiError && err.status === 401 && oauthManaged(a2.token)) {
65180
+ try {
65181
+ const renewed = await recover(a2.token);
65182
+ if (renewed && renewed.token !== a2.token) return whoami(renewed, true);
65183
+ } catch (recoveryError) {
65184
+ return { status: "invalid", message: recoveryError instanceof Error ? recoveryError.message : String(recoveryError) };
65185
+ }
65186
+ }
65049
65187
  status2 = { status: "invalid", message: err instanceof Error ? err.message : String(err) };
65050
65188
  }
65051
65189
  statusCache.set(a2.token, { at: deps.now(), status: status2 });
65052
65190
  return status2;
65053
65191
  }
65054
65192
  async function adopt(token) {
65055
- auth = await deps.store(token);
65056
- seq++;
65057
- statusCache.clear();
65058
- pendingOauth = null;
65059
- for (const cb of listeners) cb();
65193
+ const generation = ++seq;
65194
+ centerCache = void 0;
65195
+ await persist(token, generation);
65060
65196
  }
65061
65197
  async function claimCenterToken() {
65198
+ const generation = seq;
65062
65199
  let got;
65063
65200
  try {
65064
65201
  got = await deps.oauth.token();
@@ -65072,7 +65209,9 @@ function createGithubIdentity(deps) {
65072
65209
  if (err instanceof GithubApiError && err.status === 401) staleCenterToken = got.token;
65073
65210
  return false;
65074
65211
  }
65075
- await adopt(got.token);
65212
+ if (generation !== seq) return false;
65213
+ await persist(got.token, ++seq, true);
65214
+ remember(got);
65076
65215
  return true;
65077
65216
  }
65078
65217
  async function settlePendingOauth() {
@@ -65090,13 +65229,19 @@ function createGithubIdentity(deps) {
65090
65229
  }
65091
65230
  async function status() {
65092
65231
  await settlePendingOauth();
65093
- const a2 = await refresh();
65232
+ let a2;
65233
+ try {
65234
+ a2 = await refresh();
65235
+ } catch (err) {
65236
+ return { status: "invalid", message: err instanceof Error ? err.message : String(err) };
65237
+ }
65094
65238
  const current = a2 ? await whoami(a2) : { status: "missing" };
65095
65239
  return pendingOauth && current.status !== "authorized" ? { status: "pending", authUrl: pendingOauth.authUrl } : current;
65096
65240
  }
65097
65241
  return {
65098
65242
  cached: () => auth,
65099
65243
  refresh,
65244
+ recover,
65100
65245
  status,
65101
65246
  adopt,
65102
65247
  async authorize(raw) {
@@ -65111,7 +65256,7 @@ function createGithubIdentity(deps) {
65111
65256
  },
65112
65257
  // 已有身份时重新授权;直接返回 pending 链接,不能经 status() 被旧的 authorized 状态遮掉。
65113
65258
  async oauthStart(returnTo) {
65114
- const local = await refresh();
65259
+ const local = await deps.resolve();
65115
65260
  if (!local && await claimCenterToken()) return status();
65116
65261
  try {
65117
65262
  staleCenterToken = (await deps.oauth.token())?.token;
@@ -69800,7 +69945,7 @@ var ContactStore = class {
69800
69945
  };
69801
69946
 
69802
69947
  // src/contact/connect-remote.ts
69803
- var crypto5 = __toESM(require("crypto"), 1);
69948
+ var crypto6 = __toESM(require("crypto"), 1);
69804
69949
  init_protocol();
69805
69950
  var HANDSHAKE_TIMEOUT_MS = 5e3;
69806
69951
  var RPC_TIMEOUT_MS = 5e3;
@@ -69855,7 +70000,7 @@ async function connectRemote(args) {
69855
70000
  ws.once("close", onClose);
69856
70001
  });
69857
70002
  function call(method, payload) {
69858
- const requestId = crypto5.randomUUID();
70003
+ const requestId = crypto6.randomUUID();
69859
70004
  return new Promise((resolve9, reject) => {
69860
70005
  const onMessage = (raw) => {
69861
70006
  let f2;
@@ -72324,7 +72469,7 @@ function buildDeviceHandlers(deps) {
72324
72469
  }
72325
72470
 
72326
72471
  // src/feishu-auth/verify-token.ts
72327
- var crypto12 = __toESM(require("crypto"), 1);
72472
+ var crypto13 = __toESM(require("crypto"), 1);
72328
72473
  var CONNECT_TOKEN_PREFIX = "clawdtk1";
72329
72474
  function verifyConnectToken(args) {
72330
72475
  const now = args.nowSeconds ?? Math.floor(Date.now() / 1e3);
@@ -72336,7 +72481,7 @@ function verifyConnectToken(args) {
72336
72481
  const data = `${prefix}.${payloadB64}`;
72337
72482
  let signatureValid = false;
72338
72483
  try {
72339
- signatureValid = crypto12.verify(
72484
+ signatureValid = crypto13.verify(
72340
72485
  null,
72341
72486
  Buffer.from(data, "utf8"),
72342
72487
  args.publicKeyPem,
@@ -74996,6 +75141,7 @@ function buildCloudConnectorsHandlers(deps) {
74996
75141
 
74997
75142
  // src/handlers/cloud-workspace.ts
74998
75143
  init_protocol();
75144
+ var import_node_crypto26 = require("crypto");
74999
75145
  function buildCloudWorkspaceHandlers(deps) {
75000
75146
  return {
75001
75147
  "cloud:workspace": async (frame, _client, ctx) => {
@@ -75023,17 +75169,34 @@ function buildCloudWorkspaceHandlers(deps) {
75023
75169
  ) || file.cloudPendingTurns?.length))
75024
75170
  throw new ClawdError(ERROR_CODES.VALIDATION_ERROR, "\u8BF7\u7B49\u5F85\u5F53\u524D\u4EFB\u52A1\u5B8C\u6210");
75025
75171
  const conversationId = file.cloudConversationId ?? file.cloudExecutionId ?? file.sessionId;
75026
- const result = CloudWorkspaceResultSchema.parse(
75027
- await deps.command(file, {
75028
- ...args,
75029
- workspaceId: file.cloudWorkspace?.workspaceId ?? file.sessionId,
75030
- conversationId,
75031
- ...file.toolSessionId ? { threadId: file.toolSessionId } : {}
75032
- })
75033
- );
75034
- if (result.binding && !file.cloudWorkspace)
75035
- deps.bind(file.sessionId, result.binding, conversationId);
75036
- return { response: { type: "cloud:workspace:ok", ...result } };
75172
+ const traceId = typeof frame.requestId === "string" && /^[A-Za-z0-9:_-]{1,128}$/.test(frame.requestId) ? frame.requestId : (0, import_node_crypto26.randomUUID)();
75173
+ const started = performance.now();
75174
+ const meta = { traceId, sessionId: args.sessionId, action: args.action };
75175
+ const log = (event, detail) => {
75176
+ try {
75177
+ deps.logger?.info("cloud.workspace.rpc." + event, { ...meta, ...detail });
75178
+ } catch {
75179
+ }
75180
+ };
75181
+ let outcome = "error";
75182
+ log("started", {});
75183
+ try {
75184
+ const result = CloudWorkspaceResultSchema.parse(
75185
+ await deps.command(file, {
75186
+ ...args,
75187
+ traceId,
75188
+ workspaceId: file.cloudWorkspace?.workspaceId ?? file.sessionId,
75189
+ conversationId,
75190
+ ...file.toolSessionId ? { threadId: file.toolSessionId } : {}
75191
+ })
75192
+ );
75193
+ if (result.binding && !file.cloudWorkspace)
75194
+ deps.bind(file.sessionId, result.binding, conversationId);
75195
+ outcome = "ok";
75196
+ return { response: { type: "cloud:workspace:ok", ...result } };
75197
+ } finally {
75198
+ log("finished", { outcome, durationMs: Math.round(performance.now() - started) });
75199
+ }
75037
75200
  }
75038
75201
  };
75039
75202
  }
@@ -75363,7 +75526,7 @@ function computeMethodAccess(args) {
75363
75526
  }
75364
75527
 
75365
75528
  // src/version.ts
75366
- var version = "0.2.687".length > 0 ? "0.2.687" : "dev";
75529
+ var version = "0.2.691".length > 0 ? "0.2.691" : "dev";
75367
75530
 
75368
75531
  // src/cli-probe/probe.ts
75369
75532
  var fs86 = __toESM(require("fs"), 1);
@@ -75759,7 +75922,7 @@ init_protocol();
75759
75922
  // src/extension/bundle-zip.ts
75760
75923
  var import_promises12 = __toESM(require("fs/promises"), 1);
75761
75924
  var import_node_path78 = __toESM(require("path"), 1);
75762
- var import_node_crypto26 = __toESM(require("crypto"), 1);
75925
+ var import_node_crypto27 = __toESM(require("crypto"), 1);
75763
75926
  var import_jszip3 = __toESM(require_lib3(), 1);
75764
75927
  async function bundleExtensionDir(dir) {
75765
75928
  const entries = await listFilesSorted(dir);
@@ -75774,7 +75937,7 @@ async function bundleExtensionDir(dir) {
75774
75937
  compression: "DEFLATE",
75775
75938
  compressionOptions: { level: 6 }
75776
75939
  });
75777
- const sha256 = import_node_crypto26.default.createHash("sha256").update(buffer).digest("hex");
75940
+ const sha256 = import_node_crypto27.default.createHash("sha256").update(buffer).digest("hex");
75778
75941
  return { buffer, sha256 };
75779
75942
  }
75780
75943
  var FIXED_DATE = /* @__PURE__ */ new Date("2020-01-01T00:00:00.000Z");
@@ -75842,7 +76005,7 @@ function computePublishCheck(args) {
75842
76005
  var import_promises13 = __toESM(require("fs/promises"), 1);
75843
76006
  var import_node_path80 = __toESM(require("path"), 1);
75844
76007
  var import_node_os30 = __toESM(require("os"), 1);
75845
- var import_node_crypto27 = __toESM(require("crypto"), 1);
76008
+ var import_node_crypto28 = __toESM(require("crypto"), 1);
75846
76009
  var import_jszip4 = __toESM(require_lib3(), 1);
75847
76010
 
75848
76011
  // src/extension/paths.ts
@@ -75871,7 +76034,7 @@ var InstallError = class extends Error {
75871
76034
  };
75872
76035
  async function installFromChannel(args, deps) {
75873
76036
  const { channelRef, snapshotHash, bundleZip } = args;
75874
- const computed = import_node_crypto27.default.createHash("sha256").update(bundleZip).digest("hex");
76037
+ const computed = import_node_crypto28.default.createHash("sha256").update(bundleZip).digest("hex");
75875
76038
  if (computed !== snapshotHash) {
75876
76039
  throw new InstallError(
75877
76040
  "HASH_MISMATCH",
@@ -75963,7 +76126,7 @@ async function installFromChannel(args, deps) {
75963
76126
  var import_promises14 = __toESM(require("fs/promises"), 1);
75964
76127
  var import_node_path81 = __toESM(require("path"), 1);
75965
76128
  var import_node_os31 = __toESM(require("os"), 1);
75966
- var import_node_crypto28 = __toESM(require("crypto"), 1);
76129
+ var import_node_crypto29 = __toESM(require("crypto"), 1);
75967
76130
  var import_jszip5 = __toESM(require_lib3(), 1);
75968
76131
  var UpdateError = class extends Error {
75969
76132
  constructor(code, message) {
@@ -76001,7 +76164,7 @@ async function updateFromChannel(args, deps) {
76001
76164
  if (e instanceof UpdateError) throw e;
76002
76165
  throw e;
76003
76166
  }
76004
- const computed = import_node_crypto28.default.createHash("sha256").update(bundleZip).digest("hex");
76167
+ const computed = import_node_crypto29.default.createHash("sha256").update(bundleZip).digest("hex");
76005
76168
  if (computed !== snapshotHash) {
76006
76169
  throw new UpdateError(
76007
76170
  "HASH_MISMATCH",
@@ -77129,7 +77292,7 @@ async function uninstall(deps) {
77129
77292
  }
77130
77293
 
77131
77294
  // src/handlers/index.ts
77132
- var import_node_crypto29 = require("crypto");
77295
+ var import_node_crypto30 = require("crypto");
77133
77296
 
77134
77297
  // src/handlers/peer-exec.ts
77135
77298
  init_protocol();
@@ -77286,7 +77449,7 @@ function buildMethodHandlers(deps) {
77286
77449
  const c2 = deps.contactStore.get(deviceId);
77287
77450
  return c2 ? { deviceId: c2.deviceId, remoteUrl: c2.remoteUrl, connectToken: c2.connectToken } : null;
77288
77451
  },
77289
- genId: () => (0, import_node_crypto29.randomUUID)(),
77452
+ genId: () => (0, import_node_crypto30.randomUUID)(),
77290
77453
  now: () => Date.now(),
77291
77454
  forwardInboxPostToPeer,
77292
77455
  logger: deps.logger
@@ -78011,7 +78174,7 @@ async function startDaemon(config) {
78011
78174
  const channelStore = createChannelStore({
78012
78175
  filePath: import_node_path89.default.join(config.dataDir, "channels.json"),
78013
78176
  now: () => Date.now(),
78014
- genId: () => `ch-${(0, import_node_crypto30.randomUUID)().slice(0, 8)}`,
78177
+ genId: () => `ch-${(0, import_node_crypto31.randomUUID)().slice(0, 8)}`,
78015
78178
  onFlushError: (err) => logger.error("channel store flush failed", {
78016
78179
  reason: err instanceof Error ? err.message : String(err)
78017
78180
  })
@@ -78020,7 +78183,7 @@ async function startDaemon(config) {
78020
78183
  const topicStore = createTopicStore({
78021
78184
  filePath: import_node_path89.default.join(config.dataDir, "topics.json"),
78022
78185
  now: () => Date.now(),
78023
- genId: () => `tp-${(0, import_node_crypto30.randomUUID)().slice(0, 8)}`,
78186
+ genId: () => `tp-${(0, import_node_crypto31.randomUUID)().slice(0, 8)}`,
78024
78187
  onFlushError: (err) => logger.error("topic store flush failed", {
78025
78188
  reason: err instanceof Error ? err.message : String(err)
78026
78189
  })
@@ -78028,7 +78191,7 @@ async function startDaemon(config) {
78028
78191
  await topicStore.load();
78029
78192
  let deliverPendingRef;
78030
78193
  const personaDispatchManager = new PersonaDispatchManager({
78031
- genId: () => (0, import_node_crypto30.randomUUID)(),
78194
+ genId: () => (0, import_node_crypto31.randomUUID)(),
78032
78195
  store: dispatchStore,
78033
78196
  now: () => Date.now(),
78034
78197
  onCompleted: (sid) => deliverPendingRef?.(sid),
@@ -78051,7 +78214,14 @@ async function startDaemon(config) {
78051
78214
  const localSecretsDir = import_node_path89.default.join(config.dataDir, LOCAL_SECRETS_DIRNAME);
78052
78215
  const readSecrets = () => readSecretTable({ bundleRoot: secretsBundleRoot, overrideDir: localSecretsDir, logger });
78053
78216
  const githubTokenFile = import_node_path89.default.join(localSecretsDir, GITHUB_TOKEN_FILE);
78217
+ const managedGithubVar = "CLAWD_GITHUB_MANAGED_TOKEN_SHA256";
78218
+ const githubFingerprint = (token) => (0, import_node_crypto31.createHash)("sha256").update(token).digest("hex");
78054
78219
  const githubIdentity = createGithubIdentity({
78220
+ isManaged: (token) => readEnvFileVar(githubTokenFile, managedGithubVar) === githubFingerprint(token),
78221
+ markManaged: (token) => {
78222
+ if (token) upsertEnvFileVar(githubTokenFile, managedGithubVar, githubFingerprint(token));
78223
+ else removeEnvFileVar(githubTokenFile, managedGithubVar);
78224
+ },
78055
78225
  resolve: () => resolveGithubAuth({ exec: runCommand, fileToken: () => readEnvFileVar(githubTokenFile, GITHUB_TOKEN_VAR) }),
78056
78226
  store: (token) => storeGithubAuth({
78057
78227
  exec: runCommand,
@@ -78073,19 +78243,23 @@ async function startDaemon(config) {
78073
78243
  throw new ClawdError(ERROR_CODES.INTERNAL, `\u5411\u4E2D\u5FC3\u8981 GitHub \u6388\u6743\u94FE\u63A5\u6CA1\u6210\uFF1A${err instanceof Error ? err.message : String(err)}`);
78074
78244
  }
78075
78245
  },
78076
- token: async () => {
78246
+ token: async (rejectedToken) => {
78077
78247
  const r2 = ownerIdentityStore.read();
78078
78248
  if (!r2) return void 0;
78079
- return centralGithubAuthToken({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, loginPass: r2.loginPass });
78249
+ return centralGithubAuthToken({ api: config.clawosApi ?? DEFAULT_CLAWOS_API, loginPass: r2.loginPass, ...rejectedToken ? { rejectedToken } : {} });
78080
78250
  }
78081
78251
  },
78082
78252
  now: () => Date.now(),
78083
78253
  logger
78084
78254
  });
78085
- void githubIdentity.refresh();
78255
+ void githubIdentity.refresh().catch(() => {
78256
+ logger.warn("github.identity.warm-failed");
78257
+ });
78086
78258
  const resolvePersonaMcpConfig = (personaId2) => {
78087
78259
  const secrets = secretsWithGithubIdentity(readSecrets(), githubIdentity.cached());
78088
- void githubIdentity.refresh();
78260
+ void githubIdentity.refresh().catch(() => {
78261
+ logger.warn("github.identity.sync-failed");
78262
+ });
78089
78263
  return renderPersonaMcpSecrets({
78090
78264
  personaId: personaId2,
78091
78265
  personaDir: import_node_path89.default.join(config.dataDir, "personas", personaId2),
@@ -78881,6 +79055,7 @@ async function startDaemon(config) {
78881
79055
  }
78882
79056
  },
78883
79057
  cloudWorkspace: {
79058
+ logger,
78884
79059
  getFile: (id) => manager.get({ sessionId: id }).response,
78885
79060
  status: (id) => manager.getCurrentStatus(id),
78886
79061
  bind: (id, binding, conversationId) => manager.bindCloudWorkspace(id, binding, conversationId),
@@ -78913,7 +79088,7 @@ async function startDaemon(config) {
78913
79088
  shiftStore,
78914
79089
  shiftOwnerIdProvider: () => ownerPrincipalId,
78915
79090
  // PR 收件箱:github:* handler spawn 本机 gh CLI,凭据是 clawd 的 GitHub 身份(GH_TOKEN),没有才是 gh 自己的登录态
78916
- ghRunner: createGhRunner({ token: () => githubIdentity.cached()?.token }),
79091
+ ghRunner: createGhRunner({ token: async () => (await githubIdentity.refresh())?.token }),
78917
79092
  githubIdentity,
78918
79093
  visitorStore
78919
79094
  })
@@ -79023,7 +79198,7 @@ async function startDaemon(config) {
79023
79198
  fetchArtifact: downloadArtifact(runCommand),
79024
79199
  debianPackage: lookupDebianPackage(),
79025
79200
  githubIdentity,
79026
- githubApi: (token) => createGithubApi({ token }),
79201
+ githubApi: (token) => createGithubApi({ token, identity: githubIdentity }),
79027
79202
  org: PERSONA_REPO_ORG,
79028
79203
  claimPublisher: async (personaId2, environment = "production") => {
79029
79204
  const loginPass = targetLoginPass(environment);