oasis_test 0.1.1 → 0.1.2

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/index.js +438 -78
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -9092,7 +9092,7 @@ var require_compile = __commonJS({
9092
9092
  const schOrFunc = root.refs[ref];
9093
9093
  if (schOrFunc)
9094
9094
  return schOrFunc;
9095
- let _sch = resolve2.call(this, root, ref);
9095
+ let _sch = resolve.call(this, root, ref);
9096
9096
  if (_sch === void 0) {
9097
9097
  const schema = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
9098
9098
  const { schemaId } = this.opts;
@@ -9119,7 +9119,7 @@ var require_compile = __commonJS({
9119
9119
  function sameSchemaEnv(s1, s2) {
9120
9120
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
9121
9121
  }
9122
- function resolve2(root, ref) {
9122
+ function resolve(root, ref) {
9123
9123
  let sch;
9124
9124
  while (typeof (sch = this.refs[ref]) == "string")
9125
9125
  ref = sch;
@@ -9750,7 +9750,7 @@ var require_fast_uri = __commonJS({
9750
9750
  }
9751
9751
  return uri;
9752
9752
  }
9753
- function resolve2(baseURI, relativeURI, options) {
9753
+ function resolve(baseURI, relativeURI, options) {
9754
9754
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
9755
9755
  const resolved = resolveComponent(parse2(baseURI, schemelessOptions), parse2(relativeURI, schemelessOptions), schemelessOptions, true);
9756
9756
  schemelessOptions.skipEscape = true;
@@ -10008,7 +10008,7 @@ var require_fast_uri = __commonJS({
10008
10008
  var fastUri = {
10009
10009
  SCHEMES,
10010
10010
  normalize,
10011
- resolve: resolve2,
10011
+ resolve,
10012
10012
  resolveComponent,
10013
10013
  equal,
10014
10014
  serialize,
@@ -16948,10 +16948,117 @@ var init_wrapper = __esm({
16948
16948
  });
16949
16949
 
16950
16950
  // ../server/src/daemon-hub.ts
16951
+ var DaemonHub;
16951
16952
  var init_daemon_hub = __esm({
16952
16953
  "../server/src/daemon-hub.ts"() {
16953
16954
  "use strict";
16954
16955
  init_wrapper();
16956
+ DaemonHub = class _DaemonHub {
16957
+ daemons = /* @__PURE__ */ new Map();
16958
+ wss;
16959
+ ghosts = /* @__PURE__ */ new Map();
16960
+ static GHOST_TTL_MS = 5 * 60 * 1e3;
16961
+ /** 外部可订阅的事件回调 */
16962
+ onDaemonConnected;
16963
+ onDaemonDisconnected;
16964
+ onMessage;
16965
+ messageListeners = /* @__PURE__ */ new Set();
16966
+ /** 多路消息订阅(onMessage 单槽之外的加法;DaemonHubAdapter 等用) */
16967
+ addMessageListener(cb) {
16968
+ this.messageListeners.add(cb);
16969
+ return () => this.messageListeners.delete(cb);
16970
+ }
16971
+ constructor(server, path6 = "/daemon/ws", resolveNode) {
16972
+ this.wss = new import_websocket_server.default({
16973
+ server,
16974
+ path: path6,
16975
+ ...resolveNode ? {
16976
+ verifyClient: (info, cb) => {
16977
+ const authHeader = info.req.headers.authorization ?? "";
16978
+ const token2 = authHeader.startsWith("Bearer ") ? authHeader.slice("Bearer ".length) : "";
16979
+ const nodeId2 = token2 ? resolveNode(token2) : null;
16980
+ if (!nodeId2) {
16981
+ cb(false, 401, "invalid node token");
16982
+ return;
16983
+ }
16984
+ info.req.oasisNodeId = nodeId2;
16985
+ cb(true);
16986
+ }
16987
+ } : {}
16988
+ });
16989
+ this.wss.on("connection", (ws, req) => this.handleConnection(ws, req));
16990
+ }
16991
+ dispatch(daemonId, msg) {
16992
+ const daemon = this.daemons.get(daemonId);
16993
+ if (!daemon) return false;
16994
+ daemon.send(msg);
16995
+ return true;
16996
+ }
16997
+ broadcast(msg) {
16998
+ for (const daemon of this.daemons.values()) daemon.send(msg);
16999
+ }
17000
+ connectedDaemons() {
17001
+ return [...this.daemons.values()];
17002
+ }
17003
+ /** Nodes that disconnected within the last GHOST_TTL_MS ms. */
17004
+ recentlyDisconnected() {
17005
+ const cutoff = Date.now() - _DaemonHub.GHOST_TTL_MS;
17006
+ const result = [];
17007
+ for (const [id, g] of this.ghosts) {
17008
+ if (g.disconnectedAt < cutoff) {
17009
+ this.ghosts.delete(id);
17010
+ continue;
17011
+ }
17012
+ result.push({ daemonId: id, meta: g.meta, disconnectedAt: g.disconnectedAt });
17013
+ }
17014
+ return result;
17015
+ }
17016
+ evictGhost(daemonId) {
17017
+ this.ghosts.delete(daemonId);
17018
+ }
17019
+ handleConnection(ws, req) {
17020
+ const verifiedId = req.oasisNodeId;
17021
+ const daemonId = verifiedId ?? req.headers["x-daemon-id"] ?? `anon-${Date.now()}`;
17022
+ let registered = false;
17023
+ const daemon = {
17024
+ daemonId,
17025
+ meta: { hostname: "unknown", adapters: [], nodeVersion: "unknown" },
17026
+ send: (msg) => {
17027
+ if (ws.readyState === import_websocket.default.OPEN) ws.send(JSON.stringify(msg));
17028
+ },
17029
+ close: () => ws.close()
17030
+ };
17031
+ ws.on("message", (raw) => {
17032
+ let msg;
17033
+ try {
17034
+ msg = JSON.parse(raw.toString());
17035
+ } catch {
17036
+ return;
17037
+ }
17038
+ if (msg.type === "hello") {
17039
+ this.ghosts.delete(daemonId);
17040
+ Object.assign(daemon.meta, msg.meta);
17041
+ if (!registered) {
17042
+ registered = true;
17043
+ this.daemons.set(daemonId, daemon);
17044
+ this.onDaemonConnected?.(daemon);
17045
+ }
17046
+ }
17047
+ this.onMessage?.(daemonId, msg);
17048
+ for (const listener of this.messageListeners) listener(daemonId, msg);
17049
+ });
17050
+ ws.on("close", () => {
17051
+ const d = this.daemons.get(daemonId);
17052
+ if (d) this.ghosts.set(daemonId, { meta: { ...d.meta }, disconnectedAt: Date.now() });
17053
+ this.daemons.delete(daemonId);
17054
+ this.onDaemonDisconnected?.(daemonId);
17055
+ });
17056
+ ws.on("error", (err) => {
17057
+ console.error(`[hub] daemon ${daemonId} error:`, err.message);
17058
+ });
17059
+ daemon.send({ type: "ping" });
17060
+ }
17061
+ };
16955
17062
  }
16956
17063
  });
16957
17064
 
@@ -17178,6 +17285,35 @@ var init_collab = __esm({
17178
17285
  var init_service4 = __esm({
17179
17286
  "../server/src/domains/trace/service.ts"() {
17180
17287
  "use strict";
17288
+ init_src();
17289
+ }
17290
+ });
17291
+
17292
+ // ../server/src/domains/trace/otlp/redact.ts
17293
+ var MASK, TEXT_PATTERNS;
17294
+ var init_redact = __esm({
17295
+ "../server/src/domains/trace/otlp/redact.ts"() {
17296
+ "use strict";
17297
+ MASK = "***";
17298
+ TEXT_PATTERNS = [
17299
+ [/\bBearer\s+[A-Za-z0-9._\-]+/gi, "Bearer " + MASK],
17300
+ [/\b(sk|pk)-[A-Za-z0-9]{8,}\b/g, MASK],
17301
+ // OpenAI 风格
17302
+ [/\bgh[pousr]_[A-Za-z0-9]{20,}\b/g, MASK],
17303
+ // GitHub token
17304
+ [/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g, MASK],
17305
+ // Slack token
17306
+ // key=value / key: "value"(键名敏感时遮值)
17307
+ [/\b(api[_-]?key|secret|password|passwd|token|authorization|access[_-]?token|refresh[_-]?token)(["']?\s*[:=]\s*["']?)([^\s"',}]{6,})/gi, `$1$2${MASK}`]
17308
+ ];
17309
+ }
17310
+ });
17311
+
17312
+ // ../server/src/domains/trace/otlp/map.ts
17313
+ var init_map2 = __esm({
17314
+ "../server/src/domains/trace/otlp/map.ts"() {
17315
+ "use strict";
17316
+ init_redact();
17181
17317
  }
17182
17318
  });
17183
17319
 
@@ -17187,6 +17323,7 @@ var init_routes5 = __esm({
17187
17323
  "use strict";
17188
17324
  init_src();
17189
17325
  init_router();
17326
+ init_map2();
17190
17327
  }
17191
17328
  });
17192
17329
 
@@ -20286,7 +20423,7 @@ var require_dist2 = __commonJS({
20286
20423
  function parse2(stream, callback) {
20287
20424
  const parser = new parser_1.Parser();
20288
20425
  stream.on("data", (buffer) => parser.parse(buffer, callback));
20289
- return new Promise((resolve2) => stream.on("end", () => resolve2()));
20426
+ return new Promise((resolve) => stream.on("end", () => resolve()));
20290
20427
  }
20291
20428
  exports2.parse = parse2;
20292
20429
  }
@@ -21029,12 +21166,12 @@ var require_client = __commonJS({
21029
21166
  this._connect(callback);
21030
21167
  return;
21031
21168
  }
21032
- return new this._Promise((resolve2, reject) => {
21169
+ return new this._Promise((resolve, reject) => {
21033
21170
  this._connect((error2) => {
21034
21171
  if (error2) {
21035
21172
  reject(error2);
21036
21173
  } else {
21037
- resolve2(this);
21174
+ resolve(this);
21038
21175
  }
21039
21176
  });
21040
21177
  });
@@ -21381,8 +21518,8 @@ var require_client = __commonJS({
21381
21518
  } else {
21382
21519
  query = new Query2(config2, values, callback);
21383
21520
  if (!query.callback) {
21384
- result = new this._Promise((resolve2, reject) => {
21385
- query.callback = (err, res) => err ? reject(err) : resolve2(res);
21521
+ result = new this._Promise((resolve, reject) => {
21522
+ query.callback = (err, res) => err ? reject(err) : resolve(res);
21386
21523
  }).catch((err) => {
21387
21524
  Error.captureStackTrace(err);
21388
21525
  throw err;
@@ -21466,8 +21603,8 @@ var require_client = __commonJS({
21466
21603
  if (cb) {
21467
21604
  this.connection.once("end", cb);
21468
21605
  } else {
21469
- return new this._Promise((resolve2) => {
21470
- this.connection.once("end", resolve2);
21606
+ return new this._Promise((resolve) => {
21607
+ this.connection.once("end", resolve);
21471
21608
  });
21472
21609
  }
21473
21610
  }
@@ -21516,8 +21653,8 @@ var require_pg_pool = __commonJS({
21516
21653
  const cb = function(err, client) {
21517
21654
  err ? rej(err) : res(client);
21518
21655
  };
21519
- const result = new Promise2(function(resolve2, reject) {
21520
- res = resolve2;
21656
+ const result = new Promise2(function(resolve, reject) {
21657
+ res = resolve;
21521
21658
  rej = reject;
21522
21659
  }).catch((err) => {
21523
21660
  Error.captureStackTrace(err);
@@ -21578,7 +21715,7 @@ var require_pg_pool = __commonJS({
21578
21715
  if (typeof Promise2.try === "function") {
21579
21716
  return Promise2.try(f);
21580
21717
  }
21581
- return new Promise2((resolve2) => resolve2(f()));
21718
+ return new Promise2((resolve) => resolve(f()));
21582
21719
  }
21583
21720
  _isFull() {
21584
21721
  return this._clients.length >= this.options.max;
@@ -21971,8 +22108,8 @@ var require_query2 = __commonJS({
21971
22108
  NativeQuery.prototype._getPromise = function() {
21972
22109
  if (this._promise) return this._promise;
21973
22110
  this._promise = new Promise(
21974
- function(resolve2, reject) {
21975
- this._once("end", resolve2);
22111
+ function(resolve, reject) {
22112
+ this._once("end", resolve);
21976
22113
  this._once("error", reject);
21977
22114
  }.bind(this)
21978
22115
  );
@@ -22149,12 +22286,12 @@ var require_client2 = __commonJS({
22149
22286
  this._connect(callback);
22150
22287
  return;
22151
22288
  }
22152
- return new this._Promise((resolve2, reject) => {
22289
+ return new this._Promise((resolve, reject) => {
22153
22290
  this._connect((error2) => {
22154
22291
  if (error2) {
22155
22292
  reject(error2);
22156
22293
  } else {
22157
- resolve2(this);
22294
+ resolve(this);
22158
22295
  }
22159
22296
  });
22160
22297
  });
@@ -22178,8 +22315,8 @@ var require_client2 = __commonJS({
22178
22315
  query = new NativeQuery(config2, values, callback);
22179
22316
  if (!query.callback) {
22180
22317
  let resolveOut, rejectOut;
22181
- result = new this._Promise((resolve2, reject) => {
22182
- resolveOut = resolve2;
22318
+ result = new this._Promise((resolve, reject) => {
22319
+ resolveOut = resolve;
22183
22320
  rejectOut = reject;
22184
22321
  }).catch((err) => {
22185
22322
  Error.captureStackTrace(err);
@@ -22242,8 +22379,8 @@ var require_client2 = __commonJS({
22242
22379
  }
22243
22380
  let result;
22244
22381
  if (!cb) {
22245
- result = new this._Promise(function(resolve2, reject) {
22246
- cb = (err) => err ? reject(err) : resolve2();
22382
+ result = new this._Promise(function(resolve, reject) {
22383
+ cb = (err) => err ? reject(err) : resolve();
22247
22384
  });
22248
22385
  }
22249
22386
  this.native.end(function() {
@@ -22393,6 +22530,7 @@ var init_trajectory = __esm({
22393
22530
  // src/index.ts
22394
22531
  var import_node_crypto7 = require("node:crypto");
22395
22532
  var fs5 = __toESM(require("node:fs"));
22533
+ var os5 = __toESM(require("node:os"));
22396
22534
  var path5 = __toESM(require("node:path"));
22397
22535
 
22398
22536
  // ../cli/src/serve.ts
@@ -22459,6 +22597,43 @@ function normalizeClaudeStreamLine(line) {
22459
22597
  }
22460
22598
  return [];
22461
22599
  }
22600
+ function asNum(v) {
22601
+ return typeof v === "number" && Number.isFinite(v) ? v : 0;
22602
+ }
22603
+ function newClaudeUsageAcc() {
22604
+ return { input: 0, output: 0, cacheRead: 0, cacheCreation: 0, costUsd: null, saw: false };
22605
+ }
22606
+ function accumulateClaudeUsage(acc, p) {
22607
+ const type = p["type"];
22608
+ if (type === "assistant") {
22609
+ const msg = p["message"];
22610
+ const u = msg?.usage;
22611
+ if (u && typeof u === "object") {
22612
+ acc.input += asNum(u["input_tokens"]);
22613
+ acc.output += asNum(u["output_tokens"]);
22614
+ acc.cacheRead += asNum(u["cache_read_input_tokens"]);
22615
+ acc.cacheCreation += asNum(u["cache_creation_input_tokens"]);
22616
+ acc.saw = true;
22617
+ }
22618
+ } else if (type === "result") {
22619
+ const c = p["total_cost_usd"];
22620
+ if (typeof c === "number" && Number.isFinite(c)) {
22621
+ acc.costUsd = c;
22622
+ acc.saw = true;
22623
+ }
22624
+ }
22625
+ }
22626
+ function buildClaudeUsage(acc) {
22627
+ if (!acc.saw) return void 0;
22628
+ return {
22629
+ inputTokens: acc.input,
22630
+ outputTokens: acc.output,
22631
+ totalTokens: acc.input + acc.output,
22632
+ cacheReadTokens: acc.cacheRead,
22633
+ cacheCreationTokens: acc.cacheCreation,
22634
+ costUsdMicros: acc.costUsd != null ? Math.round(acc.costUsd * 1e6) : null
22635
+ };
22636
+ }
22462
22637
  function scrubLeakyEnv(env) {
22463
22638
  const LEAKY = /^npm_|^PNPM_|^INIT_CWD$|^OLDPWD$/;
22464
22639
  return Object.fromEntries(Object.entries(env).filter(([k]) => !LEAKY.test(k)));
@@ -22476,14 +22651,35 @@ var ClaudeCodeAdapter = class {
22476
22651
  constructor(opts = {}) {
22477
22652
  this.opts = opts;
22478
22653
  }
22654
+ /**
22655
+ * OTel 接线开关:opts.otel 优先,否则回落环境变量(OASIS_OTEL_ENDPOINT 设了即开)。
22656
+ * 关时返回 {}(无任何 OTEL_* 注入,行为与未接入前一致)。
22657
+ * runId 等进 OTEL_RESOURCE_ATTRIBUTES,让 Claude Code 自带 OTel 的上报归位到本次 run。
22658
+ */
22659
+ resolveOtelEnv(job, runId) {
22660
+ const endpoint = this.opts.otel?.endpoint ?? process.env["OASIS_OTEL_ENDPOINT"];
22661
+ if (!endpoint) return {};
22662
+ const protocol = this.opts.otel?.protocol ?? process.env["OASIS_OTEL_PROTOCOL"] ?? "http/protobuf";
22663
+ const logs = this.opts.otel?.logs ?? process.env["OASIS_OTEL_LOGS"] === "1";
22664
+ return {
22665
+ CLAUDE_CODE_ENABLE_TELEMETRY: "1",
22666
+ OTEL_METRICS_EXPORTER: "otlp",
22667
+ ...logs ? { OTEL_LOGS_EXPORTER: "otlp" } : {},
22668
+ OTEL_EXPORTER_OTLP_PROTOCOL: protocol,
22669
+ OTEL_EXPORTER_OTLP_ENDPOINT: endpoint,
22670
+ // 复用 agent 自己的 bearer 作上报鉴权(与 /api/traces/otlp 的 Bearer 门一致)。
22671
+ OTEL_EXPORTER_OTLP_HEADERS: `Authorization=Bearer ${job.actorToken}`,
22672
+ OTEL_RESOURCE_ATTRIBUTES: `oasis.run_id=${runId},oasis.actor_id=${job.actor},oasis.artifact_id=${job.artifactId}`
22673
+ };
22674
+ }
22479
22675
  async spawn(job) {
22480
22676
  const slug = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
22481
22677
  const id = `claude-${slug}-${(0, import_node_crypto2.randomUUID)().slice(0, 8)}`;
22482
- const dir2 = fs.mkdtempSync(
22678
+ const dir = fs.mkdtempSync(
22483
22679
  path.join(this.opts.workRoot ?? os.tmpdir(), "oasis-session-")
22484
22680
  );
22485
22681
  for (const [rel, content] of Object.entries(job.bundle.files)) {
22486
- const file = path.join(dir2, rel);
22682
+ const file = path.join(dir, rel);
22487
22683
  fs.mkdirSync(path.dirname(file), { recursive: true });
22488
22684
  fs.writeFileSync(file, content);
22489
22685
  }
@@ -22501,8 +22697,9 @@ var ClaudeCodeAdapter = class {
22501
22697
  ...this.opts.model ? ["--model", this.opts.model] : [],
22502
22698
  ...this.opts.extraArgs ?? []
22503
22699
  ];
22700
+ const otelEnv = this.resolveOtelEnv(job, id);
22504
22701
  const child = (0, import_node_child_process3.spawn)(this.opts.claudeBin ?? "claude", args, {
22505
- cwd: dir2,
22702
+ cwd: dir,
22506
22703
  env: {
22507
22704
  // 凭证泄漏防护:剔除 pnpm/npm 脚本注入的变量——npm_lifecycle_script 等会把 serve 的启动命令
22508
22705
  // (含 `--dir <数据目录>`,即 operator-token 所在)泄给 agent,它据此用 operator 凭证冒充人。
@@ -22514,15 +22711,18 @@ var ClaudeCodeAdapter = class {
22514
22711
  ...this.opts.maxOutputTokens ? { CLAUDE_CODE_MAX_OUTPUT_TOKENS: String(this.opts.maxOutputTokens) } : {},
22515
22712
  ...job.wrapperPaths?.length ? { PATH: `${job.wrapperPaths.map((p) => path.dirname(p)).join(path.delimiter)}${path.delimiter}${job.env?.["PATH"] ?? process.env["PATH"] ?? ""}` } : {},
22516
22713
  OASIS_SERVER: job.server.url,
22517
- OASIS_TOKEN: job.actorToken
22714
+ OASIS_TOKEN: job.actorToken,
22715
+ // OTel 遥测(默认关;resolveOtelEnv 决定开不开,runId 进 resource 属性自然归位到本次 run)。
22716
+ ...otelEnv
22518
22717
  },
22519
22718
  stdio: ["ignore", "pipe", "pipe"]
22520
22719
  });
22521
- let transcriptRef = path.join(dir2, "transcript.txt");
22720
+ let transcriptRef = path.join(dir, "transcript.txt");
22522
22721
  const out = fs.createWriteStream(transcriptRef);
22523
22722
  const telemetryCbs = [];
22524
22723
  let eventSeq = 0;
22525
22724
  let lastResult;
22725
+ const usageAcc = newClaudeUsageAcc();
22526
22726
  const outputCbs = [];
22527
22727
  if (this.opts.streamJson) {
22528
22728
  const rl = readline.createInterface({ input: child.stdout });
@@ -22531,6 +22731,7 @@ var ClaudeCodeAdapter = class {
22531
22731
  try {
22532
22732
  const p = JSON.parse(line);
22533
22733
  if (p["type"] === "result") lastResult = p;
22734
+ accumulateClaudeUsage(usageAcc, p);
22534
22735
  if (p["type"] === "stream_event") {
22535
22736
  const evt = p["event"];
22536
22737
  if (evt?.type === "content_block_delta" && evt.delta?.type === "text_delta" && typeof evt.delta.text === "string") {
@@ -22586,7 +22787,7 @@ var ClaudeCodeAdapter = class {
22586
22787
  out.end(() => {
22587
22788
  try {
22588
22789
  fs.renameSync(src, kept);
22589
- fs.rmSync(dir2, { recursive: true, force: true });
22790
+ fs.rmSync(dir, { recursive: true, force: true });
22590
22791
  } catch {
22591
22792
  }
22592
22793
  });
@@ -22594,7 +22795,8 @@ var ClaudeCodeAdapter = class {
22594
22795
  } catch {
22595
22796
  }
22596
22797
  }
22597
- exited = { code: killedByUs ? null : code, ...reason ? { reason } : {}, transcriptRef };
22798
+ const usage = buildClaudeUsage(usageAcc);
22799
+ exited = { code: killedByUs ? null : code, ...reason ? { reason } : {}, transcriptRef, ...usage ? { usage } : {} };
22598
22800
  for (const cb of callbacks.splice(0)) cb(exited);
22599
22801
  });
22600
22802
  return {
@@ -22624,6 +22826,102 @@ var fs2 = __toESM(require("node:fs"), 1);
22624
22826
  var os2 = __toESM(require("node:os"), 1);
22625
22827
  var path2 = __toESM(require("node:path"), 1);
22626
22828
  var readline2 = __toESM(require("node:readline"), 1);
22829
+ function codexNum(v) {
22830
+ return typeof v === "number" && Number.isFinite(v) ? v : 0;
22831
+ }
22832
+ function parseCodexTokenUsage(lines) {
22833
+ let last;
22834
+ for (const line of lines) {
22835
+ if (!line || line.indexOf("token_count") === -1) continue;
22836
+ let o;
22837
+ try {
22838
+ o = JSON.parse(line);
22839
+ } catch {
22840
+ continue;
22841
+ }
22842
+ if (o?.type === "event_msg" && o.payload?.type === "token_count" && o.payload.info?.total_token_usage) {
22843
+ last = o.payload.info.total_token_usage;
22844
+ }
22845
+ }
22846
+ if (!last) return void 0;
22847
+ const cacheRead = codexNum(last["cached_input_tokens"]) || codexNum(last["cache_read_input_tokens"]);
22848
+ const inputFresh = Math.max(codexNum(last["input_tokens"]) - cacheRead, 0);
22849
+ const output = codexNum(last["output_tokens"]) + codexNum(last["reasoning_output_tokens"]);
22850
+ return {
22851
+ inputTokens: inputFresh,
22852
+ outputTokens: output,
22853
+ totalTokens: inputFresh + output,
22854
+ // = input+output(不含 cache,与 claude/OTLP 口径一致)
22855
+ cacheReadTokens: cacheRead,
22856
+ cacheCreationTokens: null,
22857
+ // codex 不报 cache 写入
22858
+ costUsdMicros: null
22859
+ // codex rollout 无成本
22860
+ };
22861
+ }
22862
+ function codexSessionsRoot() {
22863
+ const candidates = [];
22864
+ const ch = process.env["CODEX_HOME"];
22865
+ if (ch) candidates.push(path2.join(ch, "sessions"));
22866
+ const home = process.env["HOME"] || os2.homedir();
22867
+ if (home) candidates.push(path2.join(home, ".codex", "sessions"));
22868
+ for (const c of candidates) {
22869
+ try {
22870
+ if (fs2.statSync(c).isDirectory()) return c;
22871
+ } catch {
22872
+ }
22873
+ }
22874
+ return "";
22875
+ }
22876
+ function listRecentRollouts(root, sinceMs) {
22877
+ const margin = sinceMs - 6e4;
22878
+ const found = [];
22879
+ const walk = (d) => {
22880
+ let ents;
22881
+ try {
22882
+ ents = fs2.readdirSync(d, { withFileTypes: true });
22883
+ } catch {
22884
+ return;
22885
+ }
22886
+ for (const ent of ents) {
22887
+ const p = path2.join(d, ent.name);
22888
+ if (ent.isDirectory()) walk(p);
22889
+ else if (ent.isFile() && ent.name.startsWith("rollout-") && ent.name.endsWith(".jsonl")) {
22890
+ let m = 0;
22891
+ try {
22892
+ m = fs2.statSync(p).mtimeMs;
22893
+ } catch {
22894
+ }
22895
+ if (m >= margin) found.push({ f: p, m });
22896
+ }
22897
+ }
22898
+ };
22899
+ walk(root);
22900
+ return found.sort((a, b) => b.m - a.m).map((x) => x.f);
22901
+ }
22902
+ function scanCodexUsage(workdir, sinceMs, sessionsRoot = codexSessionsRoot()) {
22903
+ try {
22904
+ for (const f of listRecentRollouts(sessionsRoot, sinceMs)) {
22905
+ let lines;
22906
+ try {
22907
+ lines = fs2.readFileSync(f, "utf8").split("\n");
22908
+ } catch {
22909
+ continue;
22910
+ }
22911
+ let meta;
22912
+ try {
22913
+ meta = JSON.parse(lines[0] ?? "");
22914
+ } catch {
22915
+ continue;
22916
+ }
22917
+ if (meta?.type === "session_meta" && meta.payload?.cwd === workdir) {
22918
+ return parseCodexTokenUsage(lines);
22919
+ }
22920
+ }
22921
+ } catch {
22922
+ }
22923
+ return void 0;
22924
+ }
22627
22925
  function createCodexNormalizeState() {
22628
22926
  return { toolUseIds: /* @__PURE__ */ new Set(), previousAgentMessage: false, lastAgentMessageEndedWithNewline: false };
22629
22927
  }
@@ -22797,9 +23095,10 @@ var CodexAdapter = class {
22797
23095
  async spawn(job) {
22798
23096
  const slug = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
22799
23097
  const id = `codex-${slug}-${(0, import_node_crypto3.randomUUID)().slice(0, 8)}`;
22800
- const dir2 = fs2.mkdtempSync(path2.join(this.opts.workRoot ?? os2.tmpdir(), "oasis-session-"));
23098
+ const startedAtMs = Date.now();
23099
+ const dir = fs2.mkdtempSync(path2.join(this.opts.workRoot ?? os2.tmpdir(), "oasis-session-"));
22801
23100
  for (const [rel, content] of Object.entries(job.bundle.files)) {
22802
- const file = path2.join(dir2, rel);
23101
+ const file = path2.join(dir, rel);
22803
23102
  fs2.mkdirSync(path2.dirname(file), { recursive: true });
22804
23103
  fs2.writeFileSync(file, content);
22805
23104
  }
@@ -22812,13 +23111,13 @@ var CodexAdapter = class {
22812
23111
  "--dangerously-bypass-approvals-and-sandbox",
22813
23112
  "--skip-git-repo-check",
22814
23113
  "-C",
22815
- dir2,
23114
+ dir,
22816
23115
  ...this.opts.model ? ["--model", this.opts.model] : [],
22817
23116
  ...this.opts.extraArgs ?? [],
22818
23117
  prompt
22819
23118
  ];
22820
23119
  const child = (0, import_node_child_process4.spawn)(this.opts.codexBin ?? "codex", args, {
22821
- cwd: dir2,
23120
+ cwd: dir,
22822
23121
  env: {
22823
23122
  ...scrubLeakyEnv(process.env),
22824
23123
  ...this.opts.env,
@@ -22829,7 +23128,7 @@ var CodexAdapter = class {
22829
23128
  },
22830
23129
  stdio: ["ignore", "pipe", "pipe"]
22831
23130
  });
22832
- let transcriptRef = path2.join(dir2, "transcript.txt");
23131
+ let transcriptRef = path2.join(dir, "transcript.txt");
22833
23132
  const out = fs2.createWriteStream(transcriptRef);
22834
23133
  const outputCbs = [];
22835
23134
  const telemetryCbs = [];
@@ -22867,7 +23166,7 @@ var CodexAdapter = class {
22867
23166
  out.end(() => {
22868
23167
  try {
22869
23168
  fs2.renameSync(src, kept);
22870
- fs2.rmSync(dir2, { recursive: true, force: true });
23169
+ fs2.rmSync(dir, { recursive: true, force: true });
22871
23170
  } catch {
22872
23171
  }
22873
23172
  });
@@ -22889,10 +23188,12 @@ var CodexAdapter = class {
22889
23188
  });
22890
23189
  child.on("exit", (code) => {
22891
23190
  clearTimeout(timer);
23191
+ const usage = scanCodexUsage(dir, startedAtMs);
22892
23192
  finish({
22893
23193
  code: killedByUs ? null : code,
22894
23194
  reason: killedByUs ? "timeout" : code === 0 ? "clean" : "error",
22895
- transcriptRef
23195
+ transcriptRef,
23196
+ ...usage ? { usage } : {}
22896
23197
  });
22897
23198
  });
22898
23199
  return {
@@ -22936,8 +23237,8 @@ var ACPClient = class {
22936
23237
  seq = 0;
22937
23238
  request(method, params) {
22938
23239
  const id = this.nextId++;
22939
- return new Promise((resolve2, reject) => {
22940
- this.pending.set(id, { resolve: resolve2, reject, method });
23240
+ return new Promise((resolve, reject) => {
23241
+ this.pending.set(id, { resolve, reject, method });
22941
23242
  this.write(JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n");
22942
23243
  });
22943
23244
  }
@@ -23124,16 +23425,16 @@ async function runACPSession(job, cfg) {
23124
23425
  const slug = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
23125
23426
  const binTag = path3.basename(cfg.bin).replace(/[^a-zA-Z0-9]/g, "").slice(0, 12) || "acp";
23126
23427
  const id = `${binTag}-${slug}-${(0, import_node_crypto4.randomUUID)().slice(0, 8)}`;
23127
- const dir2 = fs3.mkdtempSync(path3.join(cfg.workRoot ?? os3.tmpdir(), "oasis-session-"));
23428
+ const dir = fs3.mkdtempSync(path3.join(cfg.workRoot ?? os3.tmpdir(), "oasis-session-"));
23128
23429
  for (const [rel, content] of Object.entries(job.bundle.files)) {
23129
- const file = path3.join(dir2, rel);
23430
+ const file = path3.join(dir, rel);
23130
23431
  fs3.mkdirSync(path3.dirname(file), { recursive: true });
23131
23432
  fs3.writeFileSync(file, content);
23132
23433
  }
23133
23434
  const task = job.bundle.files["TASK.md"];
23134
23435
  if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
23135
23436
  const child = (0, import_node_child_process5.spawn)(cfg.bin, [...cfg.args ?? [], ...cfg.extraArgs ?? []], {
23136
- cwd: dir2,
23437
+ cwd: dir,
23137
23438
  env: {
23138
23439
  ...scrubLeakyEnv(process.env),
23139
23440
  ...cfg.env,
@@ -23145,7 +23446,7 @@ async function runACPSession(job, cfg) {
23145
23446
  },
23146
23447
  stdio: ["pipe", "pipe", "pipe"]
23147
23448
  });
23148
- let transcriptRef = path3.join(dir2, "transcript.txt");
23449
+ let transcriptRef = path3.join(dir, "transcript.txt");
23149
23450
  const transcriptOut = fs3.createWriteStream(transcriptRef);
23150
23451
  const outputCbs = [];
23151
23452
  const telemetryCbs = [];
@@ -23163,7 +23464,7 @@ async function runACPSession(job, cfg) {
23163
23464
  transcriptOut.end(() => {
23164
23465
  try {
23165
23466
  fs3.renameSync(src, kept);
23166
- fs3.rmSync(dir2, { recursive: true, force: true });
23467
+ fs3.rmSync(dir, { recursive: true, force: true });
23167
23468
  } catch {
23168
23469
  }
23169
23470
  });
@@ -23200,14 +23501,14 @@ async function runACPSession(job, cfg) {
23200
23501
  () => streamingCurrentTurn
23201
23502
  );
23202
23503
  const rl = readline3.createInterface({ input: child.stdout });
23203
- const readerDone = new Promise((resolve2) => {
23504
+ const readerDone = new Promise((resolve) => {
23204
23505
  rl.on("line", (line) => {
23205
23506
  transcriptOut.write(line + "\n");
23206
23507
  client.handleLine(line);
23207
23508
  });
23208
23509
  rl.on("close", () => {
23209
23510
  client.closeAllPending(new Error("process exited"));
23210
- resolve2();
23511
+ resolve();
23211
23512
  });
23212
23513
  });
23213
23514
  child.on("error", () => {
@@ -23226,7 +23527,7 @@ async function runACPSession(job, cfg) {
23226
23527
  clientCapabilities: {}
23227
23528
  });
23228
23529
  const sessionRes = await client.request("session/new", {
23229
- cwd: dir2,
23530
+ cwd: dir,
23230
23531
  mcpServers: [],
23231
23532
  ...cfg.model ? { model: cfg.model } : {}
23232
23533
  });
@@ -23347,15 +23648,15 @@ var readline4 = __toESM(require("node:readline"), 1);
23347
23648
  function materialize(job, workRoot) {
23348
23649
  const slug = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
23349
23650
  const id = `${slug}-${(0, import_node_crypto5.randomUUID)().slice(0, 8)}`;
23350
- const dir2 = fs4.mkdtempSync(path4.join(workRoot ?? os4.tmpdir(), "oasis-session-"));
23651
+ const dir = fs4.mkdtempSync(path4.join(workRoot ?? os4.tmpdir(), "oasis-session-"));
23351
23652
  for (const [rel, content] of Object.entries(job.bundle.files)) {
23352
- const file = path4.join(dir2, rel);
23653
+ const file = path4.join(dir, rel);
23353
23654
  fs4.mkdirSync(path4.dirname(file), { recursive: true });
23354
23655
  fs4.writeFileSync(file, content);
23355
23656
  }
23356
23657
  const task = job.bundle.files["TASK.md"];
23357
23658
  if (!task) throw new Error("bundle \u7F3A TASK.md\uFF08\u88C5\u914D\u5668\u5951\u7EA6\uFF09");
23358
- return { id, dir: dir2, task };
23659
+ return { id, dir, task };
23359
23660
  }
23360
23661
  function buildEnv(job, extra) {
23361
23662
  return {
@@ -23367,7 +23668,7 @@ function buildEnv(job, extra) {
23367
23668
  OASIS_TOKEN: job.actorToken
23368
23669
  };
23369
23670
  }
23370
- function makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir2, exitCbs) {
23671
+ function makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir, exitCbs) {
23371
23672
  let exited;
23372
23673
  const finish = (info) => {
23373
23674
  if (exited) return;
@@ -23380,7 +23681,7 @@ function makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir2, exitCbs) {
23380
23681
  transcriptOut.end(() => {
23381
23682
  try {
23382
23683
  fs4.renameSync(src, kept);
23383
- fs4.rmSync(dir2, { recursive: true, force: true });
23684
+ fs4.rmSync(dir, { recursive: true, force: true });
23384
23685
  } catch {
23385
23686
  }
23386
23687
  });
@@ -23395,19 +23696,19 @@ function makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir2, exitCbs) {
23395
23696
  return { finish, exited: () => exited };
23396
23697
  }
23397
23698
  function runStreamJson(job, cfg) {
23398
- const { id, dir: dir2, task: _task } = materialize(job, cfg.workRoot);
23399
- const args = [...cfg.buildArgs(job, dir2), ...cfg.extraArgs ?? []];
23699
+ const { id, dir, task: _task } = materialize(job, cfg.workRoot);
23700
+ const args = [...cfg.buildArgs(job, dir), ...cfg.extraArgs ?? []];
23400
23701
  const child = (0, import_node_child_process6.spawn)(cfg.bin, args, {
23401
- cwd: dir2,
23702
+ cwd: dir,
23402
23703
  env: buildEnv(job, cfg.env),
23403
23704
  stdio: ["ignore", "pipe", "pipe"]
23404
23705
  });
23405
- const transcriptRefPtr = { value: path4.join(dir2, "transcript.txt") };
23706
+ const transcriptRefPtr = { value: path4.join(dir, "transcript.txt") };
23406
23707
  const transcriptOut = fs4.createWriteStream(transcriptRefPtr.value);
23407
23708
  const outputCbs = [];
23408
23709
  const telemetryCbs = [];
23409
23710
  const exitCbs = [];
23410
- const { finish, exited } = makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir2, exitCbs);
23711
+ const { finish, exited } = makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir, exitCbs);
23411
23712
  let killedByUs = false;
23412
23713
  let seq = 0;
23413
23714
  child.stderr.pipe(transcriptOut);
@@ -23453,18 +23754,18 @@ function runStreamJson(job, cfg) {
23453
23754
  });
23454
23755
  }
23455
23756
  function runOneShotText(job, cfg) {
23456
- const { id, dir: dir2 } = materialize(job, cfg.workRoot);
23457
- const args = [...cfg.buildArgs(job, dir2), ...cfg.extraArgs ?? []];
23757
+ const { id, dir } = materialize(job, cfg.workRoot);
23758
+ const args = [...cfg.buildArgs(job, dir), ...cfg.extraArgs ?? []];
23458
23759
  const child = (0, import_node_child_process6.spawn)(cfg.bin, args, {
23459
- cwd: dir2,
23760
+ cwd: dir,
23460
23761
  env: buildEnv(job, cfg.env),
23461
23762
  stdio: ["ignore", "pipe", "pipe"]
23462
23763
  });
23463
- const transcriptRefPtr = { value: path4.join(dir2, "transcript.txt") };
23764
+ const transcriptRefPtr = { value: path4.join(dir, "transcript.txt") };
23464
23765
  const transcriptOut = fs4.createWriteStream(transcriptRefPtr.value);
23465
23766
  const outputCbs = [];
23466
23767
  const exitCbs = [];
23467
- const { finish, exited } = makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir2, exitCbs);
23768
+ const { finish, exited } = makeFinish(id, cfg, transcriptRefPtr, transcriptOut, dir, exitCbs);
23468
23769
  let killedByUs = false;
23469
23770
  child.stdout.on("data", (chunk) => {
23470
23771
  transcriptOut.write(chunk);
@@ -23551,14 +23852,14 @@ var CursorAdapter = class {
23551
23852
  const opts = this.opts;
23552
23853
  return runStreamJson(job, {
23553
23854
  bin: opts.cursorBin ?? "cursor-agent",
23554
- buildArgs(job2, dir2) {
23855
+ buildArgs(job2, dir) {
23555
23856
  const task = job2.bundle.files["TASK.md"] ?? "";
23556
23857
  const prompt = job2.systemPrompt ? `${job2.systemPrompt}
23557
23858
 
23558
23859
  ---
23559
23860
 
23560
23861
  ${task}` : task;
23561
- return ["-p", prompt, "--output-format", "stream-json", "--yolo", "--workspace", dir2, ...opts.model ? ["--model", opts.model] : []];
23862
+ return ["-p", prompt, "--output-format", "stream-json", "--yolo", "--workspace", dir, ...opts.model ? ["--model", opts.model] : []];
23562
23863
  },
23563
23864
  createState: () => ({}),
23564
23865
  normalizeStdout: (line) => normalizeCursor(line),
@@ -23693,14 +23994,14 @@ var OpenCodeAdapter = class {
23693
23994
  const opts = this.opts;
23694
23995
  return runStreamJson(job, {
23695
23996
  bin: opts.openCodeBin ?? "opencode",
23696
- buildArgs(_job, dir2) {
23997
+ buildArgs(_job, dir) {
23697
23998
  return [
23698
23999
  "run",
23699
24000
  "--format",
23700
24001
  "json",
23701
24002
  "--dangerously-skip-permissions",
23702
24003
  "--dir",
23703
- dir2,
24004
+ dir,
23704
24005
  ...opts.model ? ["--model", opts.model] : []
23705
24006
  ];
23706
24007
  },
@@ -24014,13 +24315,14 @@ function log2(tag, msg, extra) {
24014
24315
  var RECONNECT_DELAY_MS = 3e3;
24015
24316
  var PING_INTERVAL_MS = 2e4;
24016
24317
  var DaemonWsClient = class {
24017
- constructor(serverUrl, daemonId, sessions, adapters = ["claude-code"], token2, runtimes = adapters.map((kind) => ({ kind }))) {
24018
- this.serverUrl = serverUrl;
24318
+ constructor(serverUrl2, daemonId, sessions, adapters = ["claude-code"], token2, runtimes = adapters.map((kind) => ({ kind })), nodeName2) {
24319
+ this.serverUrl = serverUrl2;
24019
24320
  this.daemonId = daemonId;
24020
24321
  this.sessions = sessions;
24021
24322
  this.adapters = adapters;
24022
24323
  this.token = token2;
24023
24324
  this.runtimes = runtimes;
24325
+ this.nodeName = nodeName2;
24024
24326
  }
24025
24327
  ws = null;
24026
24328
  pingTimer = null;
@@ -24107,7 +24409,7 @@ var DaemonWsClient = class {
24107
24409
  if (this.ws?.readyState === import_websocket.default.OPEN) this.ws.send(JSON.stringify(msg));
24108
24410
  }
24109
24411
  buildMeta() {
24110
- return { hostname: (0, import_node_os.hostname)(), adapters: this.adapters, runtimes: this.runtimes, nodeVersion: process.version };
24412
+ return { hostname: (0, import_node_os.hostname)(), adapters: this.adapters, runtimes: this.runtimes, nodeVersion: process.version, ...this.nodeName ? { nodeName: this.nodeName } : {} };
24111
24413
  }
24112
24414
  };
24113
24415
 
@@ -24209,17 +24511,17 @@ async function startNode(opts) {
24209
24511
  claude
24210
24512
  )
24211
24513
  );
24212
- const client = new DaemonWsClient(opts.serverUrl, opts.nodeId, sessions, adapters, opts.token, runtimes);
24514
+ const client = new DaemonWsClient(opts.serverUrl, opts.nodeId, sessions, adapters, opts.token, runtimes, opts.nodeName);
24213
24515
  console.log(`[oasis node] ${opts.nodeId} \u2192 ${opts.serverUrl}`);
24214
24516
  client.start();
24215
- await new Promise((resolve2) => {
24517
+ await new Promise((resolve) => {
24216
24518
  process.on("SIGTERM", () => {
24217
24519
  client.stop();
24218
- resolve2();
24520
+ resolve();
24219
24521
  });
24220
24522
  process.on("SIGINT", () => {
24221
24523
  client.stop();
24222
- resolve2();
24524
+ resolve();
24223
24525
  });
24224
24526
  });
24225
24527
  }
@@ -24234,14 +24536,72 @@ for (let i = 0; i < argv.length; i++) {
24234
24536
  const a = argv[i];
24235
24537
  if (a.startsWith("--")) flags.set(a.slice(2), argv[++i] ?? "");
24236
24538
  }
24237
- var dir = flags.get("dir") ?? process.env["OASIS_DIR"] ?? path5.resolve(".oasis");
24238
- var nodeTokenFile = path5.join(dir, "node-token");
24239
- var token = flags.get("token") ?? process.env["OASIS_NODE_TOKEN"] ?? (fs5.existsSync(nodeTokenFile) ? fs5.readFileSync(nodeTokenFile, "utf8").trim() : void 0);
24539
+ var stateDir = path5.join(os5.homedir(), ".oasis");
24540
+ var stateFile = path5.join(stateDir, "node-state.json");
24541
+ var pidFile = path5.join(stateDir, "node.pid");
24542
+ function readState() {
24543
+ try {
24544
+ return JSON.parse(fs5.readFileSync(stateFile, "utf8"));
24545
+ } catch {
24546
+ return null;
24547
+ }
24548
+ }
24549
+ function saveState(s) {
24550
+ fs5.mkdirSync(stateDir, { recursive: true });
24551
+ fs5.writeFileSync(stateFile, JSON.stringify(s), { mode: 384 });
24552
+ }
24553
+ function checkPid() {
24554
+ try {
24555
+ const pid = parseInt(fs5.readFileSync(pidFile, "utf8").trim(), 10);
24556
+ if (!isNaN(pid)) {
24557
+ try {
24558
+ process.kill(pid, 0);
24559
+ console.error(`[oasis node] already running (PID ${pid})`);
24560
+ process.exit(0);
24561
+ } catch {
24562
+ }
24563
+ }
24564
+ } catch {
24565
+ }
24566
+ fs5.mkdirSync(stateDir, { recursive: true });
24567
+ fs5.writeFileSync(pidFile, String(process.pid));
24568
+ }
24569
+ function cleanup() {
24570
+ try {
24571
+ fs5.unlinkSync(pidFile);
24572
+ } catch {
24573
+ }
24574
+ }
24575
+ var serverUrl = flags.get("server-ws") ?? process.env["OASIS_SERVER_WS"] ?? "ws://127.0.0.1:7320/node-gateway";
24576
+ var token = flags.get("token") ?? process.env["OASIS_NODE_TOKEN"];
24577
+ if (!token) {
24578
+ const saved = readState();
24579
+ if (saved?.serverUrl === serverUrl) token = saved.token;
24580
+ }
24581
+ if (!token) {
24582
+ console.error("[oasis node] no token \u2014 generate one from the web UI and run with --token <token>");
24583
+ process.exit(1);
24584
+ }
24585
+ if (flags.has("token")) saveState({ serverUrl, token });
24586
+ checkPid();
24587
+ var nodeName = flags.get("name") ?? process.env["OASIS_NODE_NAME"];
24588
+ var nodeId = flags.get("id") ?? process.env["OASIS_NODE_ID"] ?? `node-${(0, import_node_crypto7.randomUUID)()}`;
24589
+ process.on("exit", cleanup);
24590
+ process.on("SIGTERM", () => {
24591
+ cleanup();
24592
+ process.exit(0);
24593
+ });
24594
+ process.on("SIGINT", () => {
24595
+ cleanup();
24596
+ process.exit(0);
24597
+ });
24240
24598
  startNode({
24241
- serverUrl: flags.get("server-ws") ?? process.env["OASIS_SERVER_WS"] ?? "ws://127.0.0.1:7320/node-gateway",
24242
- nodeId: flags.get("id") ?? process.env["OASIS_NODE_ID"] ?? `node-${(0, import_node_crypto7.randomUUID)()}`,
24243
- ...token ? { token } : {}
24599
+ serverUrl,
24600
+ nodeId,
24601
+ token,
24602
+ ...nodeName ? { nodeName } : {}
24244
24603
  }).catch((err) => {
24245
24604
  console.error(String(err instanceof Error ? err.message : err));
24605
+ cleanup();
24246
24606
  process.exitCode = 1;
24247
24607
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Oasis node daemon — connects to an Oasis server and dispatches AI sessions locally",
5
5
  "bin": { "oasis-node": "./dist/index.js" },
6
6
  "files": ["dist"],