@clawos-dev/clawd 0.2.141 → 0.2.142-beta.298.934a65b

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 (2) hide show
  1. package/dist/cli.cjs +444 -50
  2. package/package.json +2 -1
package/dist/cli.cjs CHANGED
@@ -5961,6 +5961,32 @@ var init_dispatch = __esm({
5961
5961
  }
5962
5962
  });
5963
5963
 
5964
+ // ../protocol/src/log.ts
5965
+ var LOG_SOURCES, LogSourceSchema, LOG_LEVELS, LogLevelSchema, LogRecordSchema;
5966
+ var init_log = __esm({
5967
+ "../protocol/src/log.ts"() {
5968
+ "use strict";
5969
+ init_zod();
5970
+ LOG_SOURCES = ["daemon", "main", "renderer"];
5971
+ LogSourceSchema = external_exports.enum(LOG_SOURCES);
5972
+ LOG_LEVELS = ["debug", "info", "warn", "error"];
5973
+ LogLevelSchema = external_exports.enum(LOG_LEVELS);
5974
+ LogRecordSchema = external_exports.object({
5975
+ ts: external_exports.number().int(),
5976
+ source: LogSourceSchema,
5977
+ level: LogLevelSchema,
5978
+ msg: external_exports.string(),
5979
+ ownerPrincipalId: external_exports.string(),
5980
+ deviceId: external_exports.string(),
5981
+ appVersion: external_exports.string(),
5982
+ daemonVersion: external_exports.string().optional(),
5983
+ os: external_exports.string(),
5984
+ meta_json: external_exports.string().optional(),
5985
+ sessionId: external_exports.string().optional()
5986
+ });
5987
+ }
5988
+ });
5989
+
5964
5990
  // ../protocol/src/runtime.ts
5965
5991
  var init_runtime = __esm({
5966
5992
  "../protocol/src/runtime.ts"() {
@@ -5980,6 +6006,7 @@ var init_runtime = __esm({
5980
6006
  init_extension();
5981
6007
  init_feishu_auth();
5982
6008
  init_dispatch();
6009
+ init_log();
5983
6010
  }
5984
6011
  });
5985
6012
 
@@ -7132,7 +7159,7 @@ var require_atomic_sleep = __commonJS({
7132
7159
  "../node_modules/.pnpm/atomic-sleep@1.0.0/node_modules/atomic-sleep/index.js"(exports2, module2) {
7133
7160
  "use strict";
7134
7161
  if (typeof SharedArrayBuffer !== "undefined" && typeof Atomics !== "undefined") {
7135
- let sleep = function(ms) {
7162
+ let sleep2 = function(ms) {
7136
7163
  const valid = ms > 0 && ms < Infinity;
7137
7164
  if (valid === false) {
7138
7165
  if (typeof ms !== "number" && typeof ms !== "bigint") {
@@ -7143,9 +7170,9 @@ var require_atomic_sleep = __commonJS({
7143
7170
  Atomics.wait(nil, 0, 0, Number(ms));
7144
7171
  };
7145
7172
  const nil = new Int32Array(new SharedArrayBuffer(4));
7146
- module2.exports = sleep;
7173
+ module2.exports = sleep2;
7147
7174
  } else {
7148
- let sleep = function(ms) {
7175
+ let sleep2 = function(ms) {
7149
7176
  const valid = ms > 0 && ms < Infinity;
7150
7177
  if (valid === false) {
7151
7178
  if (typeof ms !== "number" && typeof ms !== "bigint") {
@@ -7157,7 +7184,7 @@ var require_atomic_sleep = __commonJS({
7157
7184
  while (target > Date.now()) {
7158
7185
  }
7159
7186
  };
7160
- module2.exports = sleep;
7187
+ module2.exports = sleep2;
7161
7188
  }
7162
7189
  }
7163
7190
  });
@@ -7170,7 +7197,7 @@ var require_sonic_boom = __commonJS({
7170
7197
  var EventEmitter3 = require("events");
7171
7198
  var inherits = require("util").inherits;
7172
7199
  var path59 = require("path");
7173
- var sleep = require_atomic_sleep();
7200
+ var sleep2 = require_atomic_sleep();
7174
7201
  var assert = require("assert");
7175
7202
  var BUSY_WRITE_TIMEOUT = 100;
7176
7203
  var kEmptyBuffer = Buffer.allocUnsafe(0);
@@ -7316,7 +7343,7 @@ var require_sonic_boom = __commonJS({
7316
7343
  if ((err.code === "EAGAIN" || err.code === "EBUSY") && this.retryEAGAIN(err, this._writingBuf.length, this._len - this._writingBuf.length)) {
7317
7344
  if (this.sync) {
7318
7345
  try {
7319
- sleep(BUSY_WRITE_TIMEOUT);
7346
+ sleep2(BUSY_WRITE_TIMEOUT);
7320
7347
  this.release(void 0, 0);
7321
7348
  } catch (err2) {
7322
7349
  this.release(err2);
@@ -7629,7 +7656,7 @@ var require_sonic_boom = __commonJS({
7629
7656
  if (shouldRetry && !this.retryEAGAIN(err, buf.length, this._len - buf.length)) {
7630
7657
  throw err;
7631
7658
  }
7632
- sleep(BUSY_WRITE_TIMEOUT);
7659
+ sleep2(BUSY_WRITE_TIMEOUT);
7633
7660
  }
7634
7661
  }
7635
7662
  try {
@@ -7666,7 +7693,7 @@ var require_sonic_boom = __commonJS({
7666
7693
  if (shouldRetry && !this.retryEAGAIN(err, buf.length, this._len - buf.length)) {
7667
7694
  throw err;
7668
7695
  }
7669
- sleep(BUSY_WRITE_TIMEOUT);
7696
+ sleep2(BUSY_WRITE_TIMEOUT);
7670
7697
  }
7671
7698
  }
7672
7699
  }
@@ -8407,7 +8434,7 @@ var require_transport = __commonJS({
8407
8434
  var { createRequire } = require("module");
8408
8435
  var getCallers = require_caller();
8409
8436
  var { join: join15, isAbsolute: isAbsolute2, sep: sep2 } = require("path");
8410
- var sleep = require_atomic_sleep();
8437
+ var sleep2 = require_atomic_sleep();
8411
8438
  var onExit = require_on_exit_leak_free();
8412
8439
  var ThreadStream = require_thread_stream();
8413
8440
  function setupOnExit(stream) {
@@ -8441,7 +8468,7 @@ var require_transport = __commonJS({
8441
8468
  return;
8442
8469
  }
8443
8470
  stream.flushSync();
8444
- sleep(100);
8471
+ sleep2(100);
8445
8472
  stream.end();
8446
8473
  }
8447
8474
  return stream;
@@ -18160,7 +18187,7 @@ var require_validation = __commonJS({
18160
18187
  var require_receiver = __commonJS({
18161
18188
  "../node_modules/.pnpm/ws@8.20.0/node_modules/ws/lib/receiver.js"(exports2, module2) {
18162
18189
  "use strict";
18163
- var { Writable: Writable2 } = require("stream");
18190
+ var { Writable: Writable3 } = require("stream");
18164
18191
  var PerMessageDeflate2 = require_permessage_deflate();
18165
18192
  var {
18166
18193
  BINARY_TYPES,
@@ -18178,7 +18205,7 @@ var require_receiver = __commonJS({
18178
18205
  var GET_DATA = 4;
18179
18206
  var INFLATING = 5;
18180
18207
  var DEFER_EVENT = 6;
18181
- var Receiver2 = class extends Writable2 {
18208
+ var Receiver2 = class extends Writable3 {
18182
18209
  /**
18183
18210
  * Creates a Receiver instance.
18184
18211
  *
@@ -21441,7 +21468,7 @@ var require_stream_writable = __commonJS({
21441
21468
  "../node_modules/.pnpm/readable-stream@2.3.8/node_modules/readable-stream/lib/_stream_writable.js"(exports2, module2) {
21442
21469
  "use strict";
21443
21470
  var pna = require_process_nextick_args();
21444
- module2.exports = Writable2;
21471
+ module2.exports = Writable3;
21445
21472
  function CorkedRequest(state) {
21446
21473
  var _this = this;
21447
21474
  this.next = null;
@@ -21452,7 +21479,7 @@ var require_stream_writable = __commonJS({
21452
21479
  }
21453
21480
  var asyncWrite = !process.browser && ["v0.10", "v0.9."].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : pna.nextTick;
21454
21481
  var Duplex;
21455
- Writable2.WritableState = WritableState;
21482
+ Writable3.WritableState = WritableState;
21456
21483
  var util2 = Object.create(require_util());
21457
21484
  util2.inherits = require_inherits();
21458
21485
  var internalUtil = {
@@ -21469,7 +21496,7 @@ var require_stream_writable = __commonJS({
21469
21496
  return Buffer2.isBuffer(obj) || obj instanceof OurUint8Array;
21470
21497
  }
21471
21498
  var destroyImpl = require_destroy();
21472
- util2.inherits(Writable2, Stream);
21499
+ util2.inherits(Writable3, Stream);
21473
21500
  function nop() {
21474
21501
  }
21475
21502
  function WritableState(options, stream) {
@@ -21534,10 +21561,10 @@ var require_stream_writable = __commonJS({
21534
21561
  var realHasInstance;
21535
21562
  if (typeof Symbol === "function" && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === "function") {
21536
21563
  realHasInstance = Function.prototype[Symbol.hasInstance];
21537
- Object.defineProperty(Writable2, Symbol.hasInstance, {
21564
+ Object.defineProperty(Writable3, Symbol.hasInstance, {
21538
21565
  value: function(object) {
21539
21566
  if (realHasInstance.call(this, object)) return true;
21540
- if (this !== Writable2) return false;
21567
+ if (this !== Writable3) return false;
21541
21568
  return object && object._writableState instanceof WritableState;
21542
21569
  }
21543
21570
  });
@@ -21546,10 +21573,10 @@ var require_stream_writable = __commonJS({
21546
21573
  return object instanceof this;
21547
21574
  };
21548
21575
  }
21549
- function Writable2(options) {
21576
+ function Writable3(options) {
21550
21577
  Duplex = Duplex || require_stream_duplex();
21551
- if (!realHasInstance.call(Writable2, this) && !(this instanceof Duplex)) {
21552
- return new Writable2(options);
21578
+ if (!realHasInstance.call(Writable3, this) && !(this instanceof Duplex)) {
21579
+ return new Writable3(options);
21553
21580
  }
21554
21581
  this._writableState = new WritableState(options, this);
21555
21582
  this.writable = true;
@@ -21561,7 +21588,7 @@ var require_stream_writable = __commonJS({
21561
21588
  }
21562
21589
  Stream.call(this);
21563
21590
  }
21564
- Writable2.prototype.pipe = function() {
21591
+ Writable3.prototype.pipe = function() {
21565
21592
  this.emit("error", new Error("Cannot pipe, not readable"));
21566
21593
  };
21567
21594
  function writeAfterEnd(stream, cb) {
@@ -21584,7 +21611,7 @@ var require_stream_writable = __commonJS({
21584
21611
  }
21585
21612
  return valid;
21586
21613
  }
21587
- Writable2.prototype.write = function(chunk, encoding, cb) {
21614
+ Writable3.prototype.write = function(chunk, encoding, cb) {
21588
21615
  var state = this._writableState;
21589
21616
  var ret = false;
21590
21617
  var isBuf = !state.objectMode && _isUint8Array(chunk);
@@ -21605,18 +21632,18 @@ var require_stream_writable = __commonJS({
21605
21632
  }
21606
21633
  return ret;
21607
21634
  };
21608
- Writable2.prototype.cork = function() {
21635
+ Writable3.prototype.cork = function() {
21609
21636
  var state = this._writableState;
21610
21637
  state.corked++;
21611
21638
  };
21612
- Writable2.prototype.uncork = function() {
21639
+ Writable3.prototype.uncork = function() {
21613
21640
  var state = this._writableState;
21614
21641
  if (state.corked) {
21615
21642
  state.corked--;
21616
21643
  if (!state.writing && !state.corked && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state);
21617
21644
  }
21618
21645
  };
21619
- Writable2.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
21646
+ Writable3.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) {
21620
21647
  if (typeof encoding === "string") encoding = encoding.toLowerCase();
21621
21648
  if (!(["hex", "utf8", "utf-8", "ascii", "binary", "base64", "ucs2", "ucs-2", "utf16le", "utf-16le", "raw"].indexOf((encoding + "").toLowerCase()) > -1)) throw new TypeError("Unknown encoding: " + encoding);
21622
21649
  this._writableState.defaultEncoding = encoding;
@@ -21628,7 +21655,7 @@ var require_stream_writable = __commonJS({
21628
21655
  }
21629
21656
  return chunk;
21630
21657
  }
21631
- Object.defineProperty(Writable2.prototype, "writableHighWaterMark", {
21658
+ Object.defineProperty(Writable3.prototype, "writableHighWaterMark", {
21632
21659
  // making it explicit this property is not enumerable
21633
21660
  // because otherwise some prototype manipulation in
21634
21661
  // userland will fail
@@ -21774,11 +21801,11 @@ var require_stream_writable = __commonJS({
21774
21801
  state.bufferedRequest = entry;
21775
21802
  state.bufferProcessing = false;
21776
21803
  }
21777
- Writable2.prototype._write = function(chunk, encoding, cb) {
21804
+ Writable3.prototype._write = function(chunk, encoding, cb) {
21778
21805
  cb(new Error("_write() is not implemented"));
21779
21806
  };
21780
- Writable2.prototype._writev = null;
21781
- Writable2.prototype.end = function(chunk, encoding, cb) {
21807
+ Writable3.prototype._writev = null;
21808
+ Writable3.prototype.end = function(chunk, encoding, cb) {
21782
21809
  var state = this._writableState;
21783
21810
  if (typeof chunk === "function") {
21784
21811
  cb = chunk;
@@ -21853,7 +21880,7 @@ var require_stream_writable = __commonJS({
21853
21880
  }
21854
21881
  state.corkedRequestsFree.next = corkReq;
21855
21882
  }
21856
- Object.defineProperty(Writable2.prototype, "destroyed", {
21883
+ Object.defineProperty(Writable3.prototype, "destroyed", {
21857
21884
  get: function() {
21858
21885
  if (this._writableState === void 0) {
21859
21886
  return false;
@@ -21867,9 +21894,9 @@ var require_stream_writable = __commonJS({
21867
21894
  this._writableState.destroyed = value;
21868
21895
  }
21869
21896
  });
21870
- Writable2.prototype.destroy = destroyImpl.destroy;
21871
- Writable2.prototype._undestroy = destroyImpl.undestroy;
21872
- Writable2.prototype._destroy = function(err, cb) {
21897
+ Writable3.prototype.destroy = destroyImpl.destroy;
21898
+ Writable3.prototype._undestroy = destroyImpl.undestroy;
21899
+ Writable3.prototype._destroy = function(err, cb) {
21873
21900
  this.end();
21874
21901
  cb(err);
21875
21902
  };
@@ -21892,13 +21919,13 @@ var require_stream_duplex = __commonJS({
21892
21919
  var util2 = Object.create(require_util());
21893
21920
  util2.inherits = require_inherits();
21894
21921
  var Readable3 = require_stream_readable();
21895
- var Writable2 = require_stream_writable();
21922
+ var Writable3 = require_stream_writable();
21896
21923
  util2.inherits(Duplex, Readable3);
21897
21924
  {
21898
- keys = objectKeys(Writable2.prototype);
21925
+ keys = objectKeys(Writable3.prototype);
21899
21926
  for (v2 = 0; v2 < keys.length; v2++) {
21900
21927
  method = keys[v2];
21901
- if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable2.prototype[method];
21928
+ if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable3.prototype[method];
21902
21929
  }
21903
21930
  }
21904
21931
  var keys;
@@ -21907,7 +21934,7 @@ var require_stream_duplex = __commonJS({
21907
21934
  function Duplex(options) {
21908
21935
  if (!(this instanceof Duplex)) return new Duplex(options);
21909
21936
  Readable3.call(this, options);
21910
- Writable2.call(this, options);
21937
+ Writable3.call(this, options);
21911
21938
  if (options && options.readable === false) this.readable = false;
21912
21939
  if (options && options.writable === false) this.writable = false;
21913
21940
  this.allowHalfOpen = true;
@@ -31149,6 +31176,24 @@ init_protocol();
31149
31176
  var DEFAULT_PORT = 18790;
31150
31177
  var DEFAULT_HOST = "127.0.0.1";
31151
31178
  var DEFAULT_CLAWOS_API = "https://api.clawos.chat";
31179
+ var DEFAULT_LOG_ENDPOINT = "https://clawd-prod.cn-hangzhou.log.aliyuncs.com/logstores/app-logs/track";
31180
+ function resolveLogShipping(raw, cliNoShipping) {
31181
+ if (cliNoShipping) {
31182
+ return { mode: "off", endpoint: null, sampling: {} };
31183
+ }
31184
+ const rawMode = raw?.mode;
31185
+ const mode = rawMode === "off" || rawMode === "errors-only" ? rawMode : "on";
31186
+ if (mode === "off") {
31187
+ return { mode, endpoint: null, sampling: {} };
31188
+ }
31189
+ const endpoint = typeof raw?.endpoint === "string" && raw.endpoint ? raw.endpoint : raw?.endpoint === null ? null : DEFAULT_LOG_ENDPOINT;
31190
+ const sampling = mode === "errors-only" ? { debug: 0, info: 0, warn: 1, error: 1 } : isPlainSamplingMap(raw?.sampling) ? raw.sampling : {};
31191
+ return { mode, endpoint, sampling };
31192
+ }
31193
+ function isPlainSamplingMap(v2) {
31194
+ if (!v2 || typeof v2 !== "object") return false;
31195
+ return Object.values(v2).every((n) => typeof n === "number");
31196
+ }
31152
31197
  function parseArgs(argv) {
31153
31198
  const out = {};
31154
31199
  for (let i = 0; i < argv.length; i++) {
@@ -31194,6 +31239,9 @@ function parseArgs(argv) {
31194
31239
  case "-v":
31195
31240
  out.version = true;
31196
31241
  break;
31242
+ case "--no-log-shipping":
31243
+ out.noLogShipping = true;
31244
+ break;
31197
31245
  default:
31198
31246
  if (a.startsWith("--")) throw new Error(`unknown flag: ${a}`);
31199
31247
  break;
@@ -31239,6 +31287,10 @@ function resolveConfig(opts) {
31239
31287
  const mode = DAEMON_MODE_VALUES.includes(rawMode ?? "") ? rawMode : "sdk";
31240
31288
  const filePreviewPorts = Array.isArray(fileCfg.previewPorts) ? fileCfg.previewPorts.map((n) => Number(n)).filter((n) => Number.isInteger(n) && n > 0) : null;
31241
31289
  const previewPorts = env.CLAWD_PREVIEW_PORTS ? env.CLAWD_PREVIEW_PORTS.split(",").map((s) => Number(s.trim())).filter((n) => Number.isInteger(n) && n > 0) : filePreviewPorts && filePreviewPorts.length > 0 ? filePreviewPorts : null;
31290
+ const logShipping = resolveLogShipping(
31291
+ fileCfg.logShipping,
31292
+ args.noLogShipping ?? false
31293
+ );
31242
31294
  return {
31243
31295
  port,
31244
31296
  host,
@@ -31251,7 +31303,8 @@ function resolveConfig(opts) {
31251
31303
  noTunnelPersist,
31252
31304
  frpcBinary,
31253
31305
  mode,
31254
- previewPorts
31306
+ previewPorts,
31307
+ logShipping
31255
31308
  };
31256
31309
  }
31257
31310
  var HELP_TEXT = `clawd [options]
@@ -31262,6 +31315,7 @@ var HELP_TEXT = `clawd [options]
31262
31315
  --tunnel \u542F\u7528 frp tunnel \u628A\u672C\u5730\u7AEF\u53E3\u66B4\u9732\u5230\u516C\u7F51
31263
31316
  --clawos-api <url> tunnel register \u63A5\u53E3\u7684 base url\uFF08\u9ED8\u8BA4 https://api.clawos.chat\uFF09
31264
31317
  --auth-token <s> \u6307\u5B9A daemon auth token\uFF1B\u7F3A\u7701\u65F6 tunnel \u6A21\u5F0F\u4ECE ~/.clawd/auth.json \u590D\u7528\uFF0C\u6CA1\u6709\u5C31\u751F\u6210
31318
+ --no-log-shipping \u7981\u7528 SLS \u65E5\u5FD7\u4E0A\u884C\uFF08\u8986\u76D6 config.json logShipping.mode=off\uFF09
31265
31319
  --help / -h \u663E\u793A\u5E2E\u52A9
31266
31320
  --version / -v \u663E\u793A\u7248\u672C
31267
31321
 
@@ -31337,6 +31391,7 @@ var import_node_url2 = require("url");
31337
31391
  // src/logger.ts
31338
31392
  var import_node_fs2 = __toESM(require("fs"), 1);
31339
31393
  var import_node_path2 = __toESM(require("path"), 1);
31394
+ var import_node_stream = require("stream");
31340
31395
  var import_pino = __toESM(require_pino(), 1);
31341
31396
  function wrap(inner) {
31342
31397
  return {
@@ -31362,12 +31417,329 @@ function createLogger(opts = {}) {
31362
31417
  } catch {
31363
31418
  }
31364
31419
  }
31420
+ if (opts.logClient) {
31421
+ const client = opts.logClient;
31422
+ const sink = new import_node_stream.Writable({
31423
+ write(chunk, _enc, cb) {
31424
+ try {
31425
+ const line = String(chunk).trim();
31426
+ if (line) {
31427
+ const obj = JSON.parse(line);
31428
+ const lvl = pinoLevelToString(obj.level);
31429
+ if (lvl) {
31430
+ const meta = {};
31431
+ for (const [k2, v2] of Object.entries(obj)) {
31432
+ if (k2 === "level" || k2 === "msg" || k2 === "time" || k2 === "pid" || k2 === "hostname") continue;
31433
+ if (k2 === "sessionId") continue;
31434
+ meta[k2] = v2;
31435
+ }
31436
+ client.push({
31437
+ ts: typeof obj.time === "number" ? obj.time : void 0,
31438
+ level: lvl,
31439
+ msg: typeof obj.msg === "string" ? obj.msg : "",
31440
+ meta: Object.keys(meta).length > 0 ? meta : void 0,
31441
+ sessionId: typeof obj.sessionId === "string" ? obj.sessionId : void 0
31442
+ });
31443
+ }
31444
+ }
31445
+ } catch {
31446
+ }
31447
+ cb();
31448
+ }
31449
+ });
31450
+ streams.push({ stream: sink, level });
31451
+ }
31365
31452
  const base = (0, import_pino.default)(
31366
31453
  { level, base: { pid: process.pid } },
31367
31454
  import_pino.default.multistream(streams)
31368
31455
  );
31369
31456
  return wrap(base);
31370
31457
  }
31458
+ function pinoLevelToString(n) {
31459
+ if (typeof n !== "number") return null;
31460
+ if (n >= 50) return "error";
31461
+ if (n >= 40) return "warn";
31462
+ if (n >= 30) return "info";
31463
+ if (n >= 20) return "debug";
31464
+ return null;
31465
+ }
31466
+
31467
+ // ../log-client/src/types.ts
31468
+ var DEFAULT_BATCH = {
31469
+ maxRecords: 100,
31470
+ maxBytes: 512 * 1024,
31471
+ maxWaitMs: 5e3
31472
+ };
31473
+ var DEFAULT_BUFFER_CAP = 5e3;
31474
+ var DEFAULT_SAMPLING = {
31475
+ debug: 0,
31476
+ info: 1,
31477
+ warn: 1,
31478
+ error: 1
31479
+ };
31480
+ var MAX_MSG_BYTES = 1024;
31481
+ var MAX_META_JSON_BYTES = 2048;
31482
+ var REDACT_KEY_REGEX = /token|secret|password|auth(?!or)|apikey|signsecret/i;
31483
+ var REDACTED_PLACEHOLDER = "[REDACTED]";
31484
+
31485
+ // ../log-client/src/redactor.ts
31486
+ var TRUNCATE_SUFFIX = "\u2026[truncated]";
31487
+ function redactMeta(meta, homeDir) {
31488
+ const cleaned = cleanValue(meta, homeDir, 0);
31489
+ const json = safeStringify(cleaned);
31490
+ if (json.length <= MAX_META_JSON_BYTES) return cleaned;
31491
+ const truncated = json.slice(0, MAX_META_JSON_BYTES) + TRUNCATE_SUFFIX;
31492
+ return { __truncated__: truncated };
31493
+ }
31494
+ function cleanValue(v2, homeDir, depth) {
31495
+ if (depth > 10) return "[depth-limit]";
31496
+ if (v2 == null) return v2;
31497
+ if (typeof v2 === "string") {
31498
+ return homeDir ? v2.split(homeDir).join("~") : v2;
31499
+ }
31500
+ if (typeof v2 !== "object") return v2;
31501
+ if (Array.isArray(v2)) return v2.map((x) => cleanValue(x, homeDir, depth + 1));
31502
+ const out = {};
31503
+ for (const [k2, val] of Object.entries(v2)) {
31504
+ if (REDACT_KEY_REGEX.test(k2)) {
31505
+ out[k2] = REDACTED_PLACEHOLDER;
31506
+ } else {
31507
+ out[k2] = cleanValue(val, homeDir, depth + 1);
31508
+ }
31509
+ }
31510
+ return out;
31511
+ }
31512
+ function safeStringify(v2) {
31513
+ try {
31514
+ return JSON.stringify(v2) ?? "";
31515
+ } catch {
31516
+ return '"[serialize-failed]"';
31517
+ }
31518
+ }
31519
+ function truncateMsg(msg) {
31520
+ if (msg.length <= MAX_MSG_BYTES) return msg;
31521
+ return msg.slice(0, MAX_MSG_BYTES) + TRUNCATE_SUFFIX;
31522
+ }
31523
+
31524
+ // ../log-client/src/sampling.ts
31525
+ function shouldSample(level, config, rng2) {
31526
+ const rate = config[level] ?? DEFAULT_SAMPLING[level];
31527
+ if (rate <= 0) return false;
31528
+ if (rate >= 1) return true;
31529
+ return rng2() < rate;
31530
+ }
31531
+
31532
+ // ../log-client/src/batcher.ts
31533
+ var Batcher = class {
31534
+ constructor(deps) {
31535
+ this.deps = deps;
31536
+ }
31537
+ deps;
31538
+ queue = [];
31539
+ bytes = 0;
31540
+ droppedSinceFlush = 0;
31541
+ identityReady = false;
31542
+ timer = null;
31543
+ disposed = false;
31544
+ pendingSends = [];
31545
+ enqueue(record) {
31546
+ if (this.disposed) return;
31547
+ const sz = approxSize(record);
31548
+ while (this.queue.length >= this.deps.bufferCap) {
31549
+ this.queue.shift();
31550
+ this.droppedSinceFlush++;
31551
+ }
31552
+ this.queue.push(record);
31553
+ this.bytes += sz;
31554
+ if (!this.identityReady) return;
31555
+ this.maybeTrigger();
31556
+ }
31557
+ setIdentityReady(ready) {
31558
+ this.identityReady = ready;
31559
+ if (ready && this.queue.length > 0) this.maybeTrigger();
31560
+ }
31561
+ async flush() {
31562
+ if (this.queue.length > 0) {
31563
+ this.fire("flush");
31564
+ }
31565
+ await Promise.allSettled(this.pendingSends);
31566
+ }
31567
+ stats() {
31568
+ return { queued: this.queue.length, dropped: this.droppedSinceFlush };
31569
+ }
31570
+ async dispose() {
31571
+ if (this.disposed) return;
31572
+ this.disposed = true;
31573
+ if (this.timer) {
31574
+ clearTimeout(this.timer);
31575
+ this.timer = null;
31576
+ }
31577
+ await this.flush();
31578
+ }
31579
+ maybeTrigger() {
31580
+ const { maxRecords, maxBytes, maxWaitMs } = this.deps.batch;
31581
+ if (this.queue.length >= maxRecords) {
31582
+ this.fire("records");
31583
+ return;
31584
+ }
31585
+ if (this.bytes >= maxBytes) {
31586
+ this.fire("bytes");
31587
+ return;
31588
+ }
31589
+ if (this.timer == null) {
31590
+ this.timer = setTimeout(() => {
31591
+ this.timer = null;
31592
+ if (this.queue.length > 0 && this.identityReady) this.fire("time");
31593
+ }, maxWaitMs);
31594
+ }
31595
+ }
31596
+ fire(reason) {
31597
+ if (this.timer) {
31598
+ clearTimeout(this.timer);
31599
+ this.timer = null;
31600
+ }
31601
+ const records = this.queue;
31602
+ const droppedCarryover = this.droppedSinceFlush;
31603
+ this.queue = [];
31604
+ this.bytes = 0;
31605
+ this.droppedSinceFlush = 0;
31606
+ const p2 = this.deps.onBatch({ reason, records, droppedCarryover }).catch(() => {
31607
+ });
31608
+ this.pendingSends.push(p2);
31609
+ p2.finally(() => {
31610
+ this.pendingSends = this.pendingSends.filter((x) => x !== p2);
31611
+ });
31612
+ }
31613
+ };
31614
+ function approxSize(record) {
31615
+ return (record.msg?.length ?? 0) + (record.meta_json?.length ?? 0) + 200;
31616
+ }
31617
+
31618
+ // ../log-client/src/sender.ts
31619
+ var BACKOFF_MS = [1e3, 2e3, 4e3];
31620
+ async function sendBatch(deps, batch) {
31621
+ const body = JSON.stringify({
31622
+ __topic__: deps.topic ?? "clawd",
31623
+ __source__: deps.source,
31624
+ __logs__: batch.records,
31625
+ __dropped__: batch.droppedCarryover
31626
+ });
31627
+ for (let attempt = 0; attempt < BACKOFF_MS.length; attempt++) {
31628
+ if (attempt > 0) await sleep(BACKOFF_MS[attempt - 1]);
31629
+ try {
31630
+ const res = await deps.fetchImpl(deps.endpoint, {
31631
+ method: "POST",
31632
+ headers: { "Content-Type": "application/json" },
31633
+ body
31634
+ });
31635
+ if (res.status >= 200 && res.status < 300) {
31636
+ return { sent: batch.records.length, failed: 0 };
31637
+ }
31638
+ if (res.status >= 400 && res.status < 500) {
31639
+ return { sent: 0, failed: batch.records.length };
31640
+ }
31641
+ } catch {
31642
+ }
31643
+ }
31644
+ return { sent: 0, failed: batch.records.length };
31645
+ }
31646
+ function sleep(ms) {
31647
+ return new Promise((r) => setTimeout(r, ms));
31648
+ }
31649
+
31650
+ // ../log-client/src/client.ts
31651
+ function createLogClient(opts) {
31652
+ const stats = { sent: 0, dropped: 0, queued: 0, failed: 0 };
31653
+ const fetchImpl = opts.fetchImpl ?? globalThis.fetch;
31654
+ const now = opts.now ?? Date.now;
31655
+ const sampling = { ...DEFAULT_SAMPLING, ...opts.sampling ?? {} };
31656
+ const homeDir = opts.homeDir === void 0 ? null : opts.homeDir;
31657
+ const batchConfig = { ...DEFAULT_BATCH, ...opts.batch ?? {} };
31658
+ const bufferCap = opts.bufferCap ?? DEFAULT_BUFFER_CAP;
31659
+ let identity = opts.identity;
31660
+ let disposed = false;
31661
+ if (opts.endpoint == null) {
31662
+ return {
31663
+ push: () => {
31664
+ if (disposed) return;
31665
+ stats.dropped++;
31666
+ },
31667
+ flush: async () => {
31668
+ },
31669
+ setIdentity: (next) => {
31670
+ identity = next;
31671
+ },
31672
+ stats: () => ({ ...stats }),
31673
+ dispose: async () => {
31674
+ disposed = true;
31675
+ }
31676
+ };
31677
+ }
31678
+ const endpoint = opts.endpoint;
31679
+ const batcher = new Batcher({
31680
+ batch: batchConfig,
31681
+ bufferCap,
31682
+ now,
31683
+ onBatch: async (b2) => {
31684
+ const res = await sendBatch({ endpoint, source: opts.source, fetchImpl }, b2);
31685
+ stats.sent += res.sent;
31686
+ stats.failed += res.failed;
31687
+ }
31688
+ });
31689
+ batcher.setIdentityReady(identity != null);
31690
+ return {
31691
+ push(input) {
31692
+ if (disposed) return;
31693
+ try {
31694
+ if (!shouldSample(input.level, sampling, Math.random)) {
31695
+ stats.dropped++;
31696
+ return;
31697
+ }
31698
+ const record = buildRecord(input, identity, opts.source, homeDir, now);
31699
+ batcher.enqueue(record);
31700
+ } catch {
31701
+ }
31702
+ },
31703
+ async flush() {
31704
+ try {
31705
+ await batcher.flush();
31706
+ } catch {
31707
+ }
31708
+ },
31709
+ setIdentity(next) {
31710
+ identity = next;
31711
+ batcher.setIdentityReady(next != null);
31712
+ },
31713
+ stats() {
31714
+ const bs = batcher.stats();
31715
+ return { ...stats, queued: bs.queued, dropped: stats.dropped + bs.dropped };
31716
+ },
31717
+ async dispose() {
31718
+ disposed = true;
31719
+ try {
31720
+ await batcher.dispose();
31721
+ } catch {
31722
+ }
31723
+ }
31724
+ };
31725
+ }
31726
+ function buildRecord(input, identity, source, homeDir, now) {
31727
+ const cleanedMeta = input.meta ? redactMeta(input.meta, homeDir) : void 0;
31728
+ const meta_json = cleanedMeta ? JSON.stringify(cleanedMeta) : void 0;
31729
+ return {
31730
+ ts: input.ts ?? now(),
31731
+ source,
31732
+ level: input.level,
31733
+ msg: truncateMsg(input.msg),
31734
+ ownerPrincipalId: identity?.ownerPrincipalId ?? "__pending__",
31735
+ deviceId: identity?.deviceId ?? "__pending__",
31736
+ appVersion: identity?.appVersion ?? "__pending__",
31737
+ daemonVersion: identity?.daemonVersion,
31738
+ os: identity?.os ?? "unknown",
31739
+ meta_json,
31740
+ sessionId: input.sessionId
31741
+ };
31742
+ }
31371
31743
 
31372
31744
  // src/session/store-factory.ts
31373
31745
  var path5 = __toESM(require("path"), 1);
@@ -36313,7 +36685,7 @@ init_claude_history();
36313
36685
 
36314
36686
  // src/pty/pty-child-process.ts
36315
36687
  var import_node_events = require("events");
36316
- var import_node_stream = require("stream");
36688
+ var import_node_stream2 = require("stream");
36317
36689
  var PtyChildProcess = class extends import_node_events.EventEmitter {
36318
36690
  constructor(pty, opts = {}) {
36319
36691
  super();
@@ -36342,7 +36714,7 @@ var PtyChildProcess = class extends import_node_events.EventEmitter {
36342
36714
  pty.write(data);
36343
36715
  }
36344
36716
  };
36345
- this.stdin = new import_node_stream.Writable({
36717
+ this.stdin = new import_node_stream2.Writable({
36346
36718
  decodeStrings: false,
36347
36719
  write: (chunk, _enc, cb) => {
36348
36720
  const s = typeof chunk === "string" ? chunk : chunk.toString("utf8");
@@ -36361,7 +36733,7 @@ var PtyChildProcess = class extends import_node_events.EventEmitter {
36361
36733
  }
36362
36734
  }
36363
36735
  });
36364
- this.stdout = new import_node_stream.Readable({ read() {
36736
+ this.stdout = new import_node_stream2.Readable({ read() {
36365
36737
  } });
36366
36738
  pty.onData((data) => {
36367
36739
  if (!this.firstDataLogged) {
@@ -36374,7 +36746,7 @@ var PtyChildProcess = class extends import_node_events.EventEmitter {
36374
36746
  }
36375
36747
  this.stdout.push(Buffer.from(data, "utf8"));
36376
36748
  });
36377
- this.stderr = new import_node_stream.Readable({ read() {
36749
+ this.stderr = new import_node_stream2.Readable({ read() {
36378
36750
  } });
36379
36751
  pty.onExit(({ exitCode, signal }) => {
36380
36752
  this.exitCode = exitCode;
@@ -37904,7 +38276,7 @@ var import_stream = __toESM(require_stream(), 1);
37904
38276
  var import_extension = __toESM(require_extension(), 1);
37905
38277
  var import_permessage_deflate = __toESM(require_permessage_deflate(), 1);
37906
38278
  var import_receiver = __toESM(require_receiver(), 1);
37907
- var import_sender = __toESM(require_sender(), 1);
38279
+ var import_sender2 = __toESM(require_sender(), 1);
37908
38280
  var import_subprotocol = __toESM(require_subprotocol(), 1);
37909
38281
  var import_websocket = __toESM(require_websocket(), 1);
37910
38282
  var import_websocket_server = __toESM(require_websocket_server(), 1);
@@ -40454,7 +40826,7 @@ var import_node_fs23 = __toESM(require("fs"), 1);
40454
40826
  var import_node_os11 = __toESM(require("os"), 1);
40455
40827
  var import_node_path23 = __toESM(require("path"), 1);
40456
40828
  var import_node_child_process7 = require("child_process");
40457
- var import_node_stream2 = require("stream");
40829
+ var import_node_stream3 = require("stream");
40458
40830
  var import_promises3 = require("stream/promises");
40459
40831
  var FRPC_VERSION = "0.68.0";
40460
40832
  var UnsupportedPlatformError = class extends Error {
@@ -40545,7 +40917,7 @@ async function downloadToFile(url, dest, fetchImpl) {
40545
40917
  throw new Error(`download failed: ${res.status} ${res.statusText}`);
40546
40918
  }
40547
40919
  const out = import_node_fs23.default.createWriteStream(dest);
40548
- const nodeStream = import_node_stream2.Readable.fromWeb(res.body);
40920
+ const nodeStream = import_node_stream3.Readable.fromWeb(res.body);
40549
40921
  await (0, import_promises3.pipeline)(nodeStream, out);
40550
40922
  }
40551
40923
  async function extractFrpcFromTarball(tarball, binDir, version2, platform, destBin) {
@@ -40620,7 +40992,7 @@ async function killStaleFrpc(deps) {
40620
40992
  const isAlive = deps.isPidAliveImpl ?? defaultIsPidAlive;
40621
40993
  const killPid = deps.killPidImpl ?? defaultKillPid;
40622
40994
  const scanPids = deps.scanFrpcPidsImpl ?? ((tp) => defaultScanFrpcPidsByCmdline(tp, deps.logger));
40623
- const sleep = deps.sleepImpl ?? defaultSleep;
40995
+ const sleep2 = deps.sleepImpl ?? defaultSleep;
40624
40996
  const victims = /* @__PURE__ */ new Set();
40625
40997
  const raw = readPidFile(pidFile);
40626
40998
  if (raw) {
@@ -40648,7 +41020,7 @@ async function killStaleFrpc(deps) {
40648
41020
  deps.logger?.warn("tunnel: killing stale frpc before respawn", { pid });
40649
41021
  killPid(pid, "SIGKILL");
40650
41022
  }
40651
- await sleep(deps.reapWaitMs ?? 300);
41023
+ await sleep2(deps.reapWaitMs ?? 300);
40652
41024
  try {
40653
41025
  import_node_fs24.default.unlinkSync(pidFile);
40654
41026
  } catch {
@@ -42565,6 +42937,7 @@ function buildReadyFrame(deps, client) {
42565
42937
  if (deps.httpToken) fileSharing.httpToken = deps.httpToken;
42566
42938
  }
42567
42939
  const daemonSource = process.env.CLAWD_DAEMON_SOURCE === "ota" ? "ota" : "packaged";
42940
+ const logShipping = deps.getLogShipping ? deps.getLogShipping() : null;
42568
42941
  return {
42569
42942
  version,
42570
42943
  protocolVersion: PROTOCOL_VERSION,
@@ -42575,7 +42948,8 @@ function buildReadyFrame(deps, client) {
42575
42948
  tunnelUrl,
42576
42949
  mode: deps.mode,
42577
42950
  daemonSource,
42578
- ...fileSharing
42951
+ ...fileSharing,
42952
+ ...logShipping ? { logShipping } : {}
42579
42953
  };
42580
42954
  }
42581
42955
  function buildMetaHandlers(deps) {
@@ -45526,9 +45900,25 @@ var BundleCache = class {
45526
45900
  // src/index.ts
45527
45901
  var import_meta4 = {};
45528
45902
  async function startDaemon(config) {
45903
+ const authFile = loadOrCreateAuthFile({ dataDir: config.dataDir });
45904
+ const logShippingCfg = config.logShipping ?? { endpoint: null, sampling: {}, mode: "off" };
45905
+ const logClient = createLogClient({
45906
+ endpoint: logShippingCfg.endpoint,
45907
+ identity: {
45908
+ ownerPrincipalId: authFile.ownerPrincipalId,
45909
+ deviceId: authFile.deviceId,
45910
+ appVersion: version,
45911
+ daemonVersion: version,
45912
+ os: `${process.platform}-${process.arch}`
45913
+ },
45914
+ source: "daemon",
45915
+ sampling: logShippingCfg.sampling,
45916
+ homeDir: import_node_os19.default.homedir()
45917
+ });
45529
45918
  const logger = createLogger({
45530
45919
  level: config.logLevel,
45531
- file: import_node_path46.default.join(config.dataDir, "clawd.log")
45920
+ file: import_node_path46.default.join(config.dataDir, "clawd.log"),
45921
+ logClient
45532
45922
  });
45533
45923
  logger.info("starting clawd", { version, config: { port: config.port, host: config.host, dataDir: config.dataDir } });
45534
45924
  const stateMgr = new StateFileManager({ dataDir: config.dataDir });
@@ -45539,7 +45929,6 @@ async function startDaemon(config) {
45539
45929
  if (pre.status === "stale") {
45540
45930
  logger.warn("stale state file detected, overwriting", { pid: pre.existing.pid });
45541
45931
  }
45542
- const authFile = loadOrCreateAuthFile({ dataDir: config.dataDir });
45543
45932
  let resolvedAuthToken = null;
45544
45933
  if (config.authToken && config.authToken.trim()) {
45545
45934
  resolvedAuthToken = config.authToken.trim();
@@ -46160,6 +46549,10 @@ async function startDaemon(config) {
46160
46549
  manager,
46161
46550
  getAdapter,
46162
46551
  getTunnelUrl: () => currentTunnelUrl,
46552
+ getLogShipping: () => config.logShipping ? {
46553
+ endpoint: config.logShipping.endpoint,
46554
+ sampling: config.logShipping.sampling
46555
+ } : null,
46163
46556
  // ready 帧 mode = daemon CC spawn 模式('sdk' | 'tui');UI 用它挂 XtermPanel
46164
46557
  mode: config.mode,
46165
46558
  // file-sharing 字段:httpBaseUrl 跟 tunnel 状态走;httpToken 复用 owner WS token
@@ -46390,6 +46783,7 @@ ${bar}
46390
46783
  }
46391
46784
  await wss.stop();
46392
46785
  stateMgr.delete();
46786
+ if (logClient) await logClient.dispose();
46393
46787
  };
46394
46788
  return {
46395
46789
  stop: shutdown,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawos-dev/clawd",
3
- "version": "0.2.141",
3
+ "version": "0.2.142-beta.298.934a65b",
4
4
  "description": "Standalone clawd daemon — Claude Code (and future Codex) session server over WebSocket",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -27,6 +27,7 @@
27
27
  },
28
28
  "devDependencies": {
29
29
  "@clawos/clawd-protocol": "workspace:*",
30
+ "@clawos/log-client": "workspace:*",
30
31
  "@types/diff": "^7.0.2",
31
32
  "@types/node": "^22.0.0",
32
33
  "@types/uuid": "^10.0.0",