grix-connector 3.15.2 → 3.15.4

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.
@@ -3200,6 +3200,212 @@ async function clearOpenClawGatewayProvider() {
3200
3200
  return true;
3201
3201
  }
3202
3202
 
3203
+ // src/openclaw/usage-parser.ts
3204
+ import { createReadStream, existsSync as existsSync2, readdirSync } from "node:fs";
3205
+ import { readdir, readFile as readFile2 } from "node:fs/promises";
3206
+ import { createInterface } from "node:readline";
3207
+ import { dirname as dirname3, join as join4 } from "node:path";
3208
+ import { homedir as homedir5 } from "node:os";
3209
+ function warnUsage(message, err) {
3210
+ const detail = err instanceof Error ? err.message : err != null ? String(err) : "";
3211
+ console.warn(`[openclaw/usage] ${message}${detail ? `: ${detail}` : ""}`);
3212
+ }
3213
+ function zeroUsage() {
3214
+ return {
3215
+ inputTokens: 0,
3216
+ outputTokens: 0,
3217
+ cacheReadInputTokens: 0,
3218
+ cacheCreationInputTokens: 0
3219
+ };
3220
+ }
3221
+ function addUsage(acc, delta) {
3222
+ acc.inputTokens += delta.inputTokens;
3223
+ acc.outputTokens += delta.outputTokens;
3224
+ acc.cacheReadInputTokens += delta.cacheReadInputTokens;
3225
+ acc.cacheCreationInputTokens += delta.cacheCreationInputTokens;
3226
+ }
3227
+ function asFiniteNumber(value) {
3228
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
3229
+ }
3230
+ function resolveOpenClawStateDir() {
3231
+ const explicit = process.env.OPENCLAW_STATE_DIR?.trim();
3232
+ if (explicit) return explicit;
3233
+ const cfg = process.env.OPENCLAW_CONFIG_PATH?.trim();
3234
+ if (cfg) {
3235
+ const resolved = cfg.startsWith("~") ? join4(homedir5(), cfg.slice(1)) : cfg;
3236
+ return dirname3(resolved);
3237
+ }
3238
+ return join4(homedir5(), ".openclaw");
3239
+ }
3240
+ function grixTargetCandidates(grixSessionId) {
3241
+ const id = grixSessionId.trim();
3242
+ if (!id) return [];
3243
+ return [`grix:${id}`, id];
3244
+ }
3245
+ function entryMatchesGrixSession(entry, grixSessionId) {
3246
+ const needles = new Set(grixTargetCandidates(grixSessionId));
3247
+ const haystacks = [
3248
+ entry.deliveryContext?.to,
3249
+ entry.origin?.to,
3250
+ entry.lastTo,
3251
+ entry.route?.target?.to
3252
+ ];
3253
+ for (const raw of haystacks) {
3254
+ const value = String(raw ?? "").trim();
3255
+ if (value && needles.has(value)) return true;
3256
+ }
3257
+ return false;
3258
+ }
3259
+ async function listSessionStorePaths(stateDir2) {
3260
+ const agentsRoot = join4(stateDir2, "agents");
3261
+ if (!existsSync2(agentsRoot)) return [];
3262
+ let agentIds;
3263
+ try {
3264
+ agentIds = await readdir(agentsRoot);
3265
+ } catch (err) {
3266
+ warnUsage(`failed to list agents under ${agentsRoot}`, err);
3267
+ return [];
3268
+ }
3269
+ const paths2 = [];
3270
+ for (const agentId of agentIds) {
3271
+ const storePath = join4(agentsRoot, agentId, "sessions", "sessions.json");
3272
+ if (existsSync2(storePath)) paths2.push(storePath);
3273
+ }
3274
+ return paths2;
3275
+ }
3276
+ async function loadSessionStore(storePath) {
3277
+ try {
3278
+ const raw = JSON.parse(await readFile2(storePath, "utf8"));
3279
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
3280
+ warnUsage(`sessions store is not a JSON object: ${storePath}`);
3281
+ return null;
3282
+ }
3283
+ return raw;
3284
+ } catch (err) {
3285
+ warnUsage(`failed to read sessions store ${storePath}`, err);
3286
+ return null;
3287
+ }
3288
+ }
3289
+ function resolveTranscriptPaths(params) {
3290
+ const { sessionsDir, entry } = params;
3291
+ const familyIds = Array.isArray(entry.usageFamilySessionIds) ? entry.usageFamilySessionIds.filter((v) => typeof v === "string" && v.trim().length > 0) : [];
3292
+ const currentId = typeof entry.sessionId === "string" ? entry.sessionId.trim() : "";
3293
+ const ids = familyIds.length > 0 ? familyIds : currentId ? [currentId] : [];
3294
+ const found = [];
3295
+ const seen = /* @__PURE__ */ new Set();
3296
+ const coveredIds = /* @__PURE__ */ new Set();
3297
+ const push = (filePath, sessionId) => {
3298
+ if (!filePath || seen.has(filePath) || !existsSync2(filePath)) return false;
3299
+ seen.add(filePath);
3300
+ found.push(filePath);
3301
+ if (sessionId) coveredIds.add(sessionId);
3302
+ return true;
3303
+ };
3304
+ let dirEntries = [];
3305
+ try {
3306
+ dirEntries = readdirSync(sessionsDir);
3307
+ } catch (err) {
3308
+ warnUsage(`failed to list session transcripts in ${sessionsDir}`, err);
3309
+ dirEntries = [];
3310
+ }
3311
+ if (typeof entry.sessionFile === "string" && entry.sessionFile.trim()) {
3312
+ push(entry.sessionFile.trim(), currentId || void 0);
3313
+ }
3314
+ for (const id of ids) {
3315
+ if (coveredIds.has(id)) continue;
3316
+ const livePath = join4(sessionsDir, `${id}.jsonl`);
3317
+ if (push(livePath, id)) continue;
3318
+ const resetNames = dirEntries.filter((name) => name.startsWith(`${id}.jsonl.reset.`)).sort();
3319
+ if (resetNames.length > 0) {
3320
+ push(join4(sessionsDir, resetNames[resetNames.length - 1]), id);
3321
+ }
3322
+ }
3323
+ return found;
3324
+ }
3325
+ function readUsageFromMessage(message) {
3326
+ if (!message || typeof message !== "object") return null;
3327
+ const usage = message.usage;
3328
+ if (!usage || typeof usage !== "object" || Array.isArray(usage)) return null;
3329
+ const u = usage;
3330
+ const inputTokens = asFiniteNumber(u.input ?? u.inputTokens ?? u.input_tokens);
3331
+ const outputTokens = asFiniteNumber(u.output ?? u.outputTokens ?? u.output_tokens);
3332
+ const cacheReadInputTokens = asFiniteNumber(
3333
+ u.cacheRead ?? u.cacheReadInputTokens ?? u.cache_read_input_tokens
3334
+ );
3335
+ const cacheCreationInputTokens = asFiniteNumber(
3336
+ u.cacheWrite ?? u.cacheCreationInputTokens ?? u.cache_creation_input_tokens
3337
+ );
3338
+ return { inputTokens, outputTokens, cacheReadInputTokens, cacheCreationInputTokens };
3339
+ }
3340
+ async function parseTranscriptFile(filePath, byModel, total) {
3341
+ let turns = 0;
3342
+ const rl = createInterface({ input: createReadStream(filePath, "utf8"), crlfDelay: Infinity });
3343
+ for await (const line of rl) {
3344
+ if (!line.trim()) continue;
3345
+ let entry;
3346
+ try {
3347
+ entry = JSON.parse(line);
3348
+ } catch {
3349
+ continue;
3350
+ }
3351
+ if (entry.type !== "message") continue;
3352
+ const message = entry.message;
3353
+ if (!message || message.role !== "assistant") continue;
3354
+ const usage = readUsageFromMessage(message);
3355
+ if (!usage) continue;
3356
+ turns++;
3357
+ addUsage(total, usage);
3358
+ const model = typeof message.model === "string" && message.model.trim() || typeof message.modelId === "string" && message.modelId.trim() || "unknown";
3359
+ let bucket = byModel.get(model);
3360
+ if (!bucket) {
3361
+ bucket = { turns: 0, usage: zeroUsage() };
3362
+ byModel.set(model, bucket);
3363
+ }
3364
+ bucket.turns++;
3365
+ addUsage(bucket.usage, usage);
3366
+ }
3367
+ return turns;
3368
+ }
3369
+ async function parseOpenClawSessionUsage(grixSessionId, stateDir2 = resolveOpenClawStateDir()) {
3370
+ const sessionId = String(grixSessionId ?? "").trim();
3371
+ if (!sessionId) return null;
3372
+ const storePaths = await listSessionStorePaths(stateDir2);
3373
+ for (const storePath of storePaths) {
3374
+ const store = await loadSessionStore(storePath);
3375
+ if (!store) continue;
3376
+ for (const [sessionKey, entry] of Object.entries(store)) {
3377
+ if (!entry || typeof entry !== "object") continue;
3378
+ if (!entryMatchesGrixSession(entry, sessionId)) continue;
3379
+ const sessionsDir = dirname3(storePath);
3380
+ const files = resolveTranscriptPaths({ sessionsDir, entry });
3381
+ if (files.length === 0) continue;
3382
+ const byModel = /* @__PURE__ */ new Map();
3383
+ const total = zeroUsage();
3384
+ let turns = 0;
3385
+ for (const file of files) {
3386
+ turns += await parseTranscriptFile(file, byModel, total);
3387
+ }
3388
+ if (turns === 0) continue;
3389
+ const openclawSessionId = typeof entry.sessionId === "string" && entry.sessionId.trim() || sessionKey;
3390
+ return {
3391
+ openclawSessionId,
3392
+ sessionKey,
3393
+ model: typeof entry.model === "string" ? entry.model : void 0,
3394
+ provider: typeof entry.modelProvider === "string" ? entry.modelProvider : void 0,
3395
+ contextTokens: typeof entry.contextTokens === "number" && Number.isFinite(entry.contextTokens) ? entry.contextTokens : void 0,
3396
+ turns,
3397
+ total,
3398
+ models: [...byModel.entries()].map(([model, bucket]) => ({
3399
+ model,
3400
+ turns: bucket.turns,
3401
+ total: bucket.usage
3402
+ }))
3403
+ };
3404
+ }
3405
+ }
3406
+ return null;
3407
+ }
3408
+
3203
3409
  // src/openclaw/local-actions.ts
3204
3410
  var STABLE_LOCAL_ACTION_TYPES = [
3205
3411
  "exec_approve",
@@ -3456,22 +3662,46 @@ async function handleCreateFolderLocalAction(payload) {
3456
3662
  async function handleGetSessionUsageLocalAction(payload) {
3457
3663
  const actionID = String(payload.action_id ?? "").trim() || "unknown";
3458
3664
  const params = payload.params ?? {};
3459
- const sessionId = typeof params.session_id === "string" ? params.session_id : "";
3665
+ const sessionId = typeof params.session_id === "string" ? params.session_id.trim() : "";
3666
+ if (!sessionId) {
3667
+ return {
3668
+ action_id: actionID,
3669
+ status: "failed",
3670
+ error_code: "session_id_required",
3671
+ error_msg: "session_id is required for get_session_usage"
3672
+ };
3673
+ }
3674
+ const parsed = await parseOpenClawSessionUsage(sessionId);
3675
+ if (!parsed) {
3676
+ return {
3677
+ action_id: actionID,
3678
+ status: "failed",
3679
+ error_code: "usage_not_found",
3680
+ error_msg: "No OpenClaw transcript usage found for this Grix session"
3681
+ };
3682
+ }
3460
3683
  return {
3461
3684
  action_id: actionID,
3462
3685
  status: "ok",
3463
3686
  result: {
3464
- session_id: sessionId,
3465
- provider: "openclaw",
3466
- message: "OpenClaw \u5F53\u524D\u65E0\u7528\u91CF\u8BA1\u91CF\u6570\u636E"
3687
+ sessionId: parsed.openclawSessionId,
3688
+ adapterType: "openclaw",
3689
+ models: parsed.models,
3690
+ total: parsed.total,
3691
+ turns: parsed.turns,
3692
+ sampledAt: (/* @__PURE__ */ new Date()).toISOString(),
3693
+ ...parsed.model ? { model: parsed.model } : {},
3694
+ ...parsed.provider ? { provider: parsed.provider } : {},
3695
+ ...parsed.contextTokens !== void 0 ? { contextTokens: parsed.contextTokens } : {},
3696
+ ...parsed.sessionKey ? { sessionKey: parsed.sessionKey } : {}
3467
3697
  }
3468
3698
  };
3469
3699
  }
3470
3700
 
3471
3701
  // src/openclaw/exec-command.ts
3472
- import { readdirSync, readFileSync, existsSync as existsSync2 } from "node:fs";
3473
- import { join as join4, dirname as dirname3 } from "node:path";
3474
- import { homedir as homedir5 } from "node:os";
3702
+ import { readdirSync as readdirSync2, readFileSync, existsSync as existsSync3 } from "node:fs";
3703
+ import { join as join5, dirname as dirname4 } from "node:path";
3704
+ import { homedir as homedir6 } from "node:os";
3475
3705
  import { fileURLToPath } from "node:url";
3476
3706
  function parseExecCommand(text) {
3477
3707
  const tokens = String(text ?? "").trim().split(/\s+/);
@@ -3499,13 +3729,13 @@ function parseSkillFrontmatter(content) {
3499
3729
  return { name, description };
3500
3730
  }
3501
3731
  function scanSkillDir(baseDir, source) {
3502
- if (!existsSync2(baseDir)) return [];
3732
+ if (!existsSync3(baseDir)) return [];
3503
3733
  const results = [];
3504
3734
  try {
3505
- for (const entry of readdirSync(baseDir, { withFileTypes: true })) {
3735
+ for (const entry of readdirSync2(baseDir, { withFileTypes: true })) {
3506
3736
  if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
3507
- const skillFile = join4(baseDir, entry.name, "SKILL.md");
3508
- if (!existsSync2(skillFile)) continue;
3737
+ const skillFile = join5(baseDir, entry.name, "SKILL.md");
3738
+ if (!existsSync3(skillFile)) continue;
3509
3739
  try {
3510
3740
  const parsed = parseSkillFrontmatter(readFileSync(skillFile, "utf-8"));
3511
3741
  if (parsed.name) results.push({ name: parsed.name, description: parsed.description, source });
@@ -3516,12 +3746,13 @@ function scanSkillDir(baseDir, source) {
3516
3746
  }
3517
3747
  return results;
3518
3748
  }
3749
+ function resolvePluginSkillsDir(moduleUrl = import.meta.url) {
3750
+ return join5(dirname4(fileURLToPath(moduleUrl)), "skills");
3751
+ }
3519
3752
  function scanOpenClawSkills() {
3520
3753
  const results = [];
3521
- const thisDir = dirname3(fileURLToPath(import.meta.url));
3522
- const pluginSkills = join4(thisDir, "..", "skills");
3523
- results.push(...scanSkillDir(pluginSkills, "plugin"));
3524
- results.push(...scanSkillDir(join4(homedir5(), ".openclaw", "skills"), "global"));
3754
+ results.push(...scanSkillDir(resolvePluginSkillsDir(), "plugin"));
3755
+ results.push(...scanSkillDir(join5(homedir6(), ".openclaw", "skills"), "global"));
3525
3756
  return results;
3526
3757
  }
3527
3758
  function handleSkillsCommand() {
@@ -5702,13 +5933,13 @@ var grixExecApprovalAdapter = {
5702
5933
  // src/openclaw/log-rotation.ts
5703
5934
  import {
5704
5935
  appendFileSync,
5705
- existsSync as existsSync3,
5936
+ existsSync as existsSync4,
5706
5937
  mkdirSync,
5707
5938
  renameSync,
5708
5939
  rmSync,
5709
5940
  statSync
5710
5941
  } from "node:fs";
5711
- import { dirname as dirname4 } from "node:path";
5942
+ import { dirname as dirname5 } from "node:path";
5712
5943
  function rotationPath(filePath, index) {
5713
5944
  return `${filePath}.${index}`;
5714
5945
  }
@@ -5716,17 +5947,17 @@ function rotateLogFileIfNeededSync(filePath, incomingBytes, options) {
5716
5947
  if (options.maxBytes <= 0 || options.maxFiles <= 0) {
5717
5948
  return false;
5718
5949
  }
5719
- if (!existsSync3(filePath)) {
5950
+ if (!existsSync4(filePath)) {
5720
5951
  return false;
5721
5952
  }
5722
5953
  const currentBytes = statSync(filePath).size;
5723
5954
  if (currentBytes + Math.max(0, incomingBytes) <= options.maxBytes) {
5724
5955
  return false;
5725
5956
  }
5726
- mkdirSync(dirname4(filePath), { recursive: true });
5957
+ mkdirSync(dirname5(filePath), { recursive: true });
5727
5958
  for (let index = options.maxFiles; index >= 1; index -= 1) {
5728
5959
  const sourcePath = index === 1 ? filePath : rotationPath(filePath, index - 1);
5729
- if (!existsSync3(sourcePath)) {
5960
+ if (!existsSync4(sourcePath)) {
5730
5961
  continue;
5731
5962
  }
5732
5963
  const targetPath = rotationPath(filePath, index);
@@ -5736,22 +5967,22 @@ function rotateLogFileIfNeededSync(filePath, incomingBytes, options) {
5736
5967
  return true;
5737
5968
  }
5738
5969
  function appendRotatedLogLineSync(filePath, line, options) {
5739
- mkdirSync(dirname4(filePath), { recursive: true });
5970
+ mkdirSync(dirname5(filePath), { recursive: true });
5740
5971
  rotateLogFileIfNeededSync(filePath, Buffer.byteLength(line), options);
5741
5972
  appendFileSync(filePath, line, "utf8");
5742
5973
  }
5743
5974
 
5744
5975
  // src/openclaw/plugin-logger.ts
5745
- import { homedir as homedir6 } from "node:os";
5746
- import { join as join5, dirname as dirname5 } from "node:path";
5747
- var BASE_DIR = process.env.GRIX_CONNECTOR_HOME ? process.env.GRIX_CONNECTOR_HOME : join5(homedir6(), ".grix");
5976
+ import { homedir as homedir7 } from "node:os";
5977
+ import { join as join6, dirname as dirname6 } from "node:path";
5978
+ var BASE_DIR = process.env.GRIX_CONNECTOR_HOME ? process.env.GRIX_CONNECTOR_HOME : join6(homedir7(), ".grix");
5748
5979
  var LOG_ROTATION = {
5749
5980
  maxBytes: 10 * 1024 * 1024,
5750
5981
  maxFiles: 5
5751
5982
  };
5752
5983
  var pendingConversationWrites = /* @__PURE__ */ new Map();
5753
5984
  function appendServiceLog(target, line) {
5754
- const filePath = join5(
5985
+ const filePath = join6(
5755
5986
  BASE_DIR,
5756
5987
  "service",
5757
5988
  target === "out" ? "out.log" : "err.log"
@@ -5773,7 +6004,7 @@ function appendConversationLog(filePath, line) {
5773
6004
  const previous = pendingConversationWrites.get(filePath) ?? Promise.resolve();
5774
6005
  const next = previous.catch(() => {
5775
6006
  }).then(async () => {
5776
- await mkdir(dirname5(filePath), { recursive: true });
6007
+ await mkdir(dirname6(filePath), { recursive: true });
5777
6008
  rotateLogFileIfNeededSync(filePath, Buffer.byteLength(line), LOG_ROTATION);
5778
6009
  await appendFile(filePath, line, "utf8");
5779
6010
  });
@@ -5786,7 +6017,7 @@ function appendConversationLog(filePath, line) {
5786
6017
  });
5787
6018
  }
5788
6019
  function logConversation(entry) {
5789
- const filePath = join5(
6020
+ const filePath = join6(
5790
6021
  BASE_DIR,
5791
6022
  "log",
5792
6023
  "sessions",
@@ -6154,37 +6385,37 @@ function buildAibotTextSendPlan(params) {
6154
6385
  }
6155
6386
 
6156
6387
  // src/core/log/logger.ts
6157
- import { createWriteStream, mkdirSync as mkdirSync2, existsSync as existsSync4, readdirSync as readdirSync2, statSync as statSync2, unlinkSync } from "node:fs";
6158
- import { join as join7 } from "node:path";
6388
+ import { createWriteStream, mkdirSync as mkdirSync2, existsSync as existsSync5, readdirSync as readdirSync3, statSync as statSync2, unlinkSync } from "node:fs";
6389
+ import { join as join8 } from "node:path";
6159
6390
 
6160
6391
  // src/core/config/paths.ts
6161
- import { join as join6 } from "node:path";
6162
- import { homedir as homedir7 } from "node:os";
6392
+ import { join as join7 } from "node:path";
6393
+ import { homedir as homedir8 } from "node:os";
6163
6394
  var GRIX_HOME_ENV = "GRIX_CONNECTOR_HOME";
6164
- var DEFAULT_GRIX_HOME = join6(homedir7(), ".grix");
6395
+ var DEFAULT_GRIX_HOME = join7(homedir8(), ".grix");
6165
6396
  function resolveRuntimePaths(runtimeDir) {
6166
6397
  const rootDir = runtimeDir ? runtimeDir : process.env[GRIX_HOME_ENV] ? process.env[GRIX_HOME_ENV] : DEFAULT_GRIX_HOME;
6167
6398
  return {
6168
6399
  rootDir,
6169
- configDir: join6(rootDir, "config"),
6170
- logDir: join6(rootDir, "log"),
6171
- dataDir: join6(rootDir, "data"),
6172
- serviceDir: join6(rootDir, "service"),
6173
- skillsDir: join6(rootDir, "skills"),
6174
- stateFile: join6(rootDir, "service.json"),
6175
- pidFile: join6(rootDir, "grix-connector.pid"),
6176
- daemonLockFile: join6(rootDir, "daemon.lock.json"),
6177
- daemonStatusFile: join6(rootDir, "daemon-status.json"),
6178
- stdoutLogFile: join6(rootDir, "service", "daemon.out.log"),
6179
- stderrLogFile: join6(rootDir, "service", "daemon.err.log"),
6180
- contextsDir: join6(rootDir, "data", "session-contexts"),
6181
- hookSignalsPath: join6(rootDir, "data", "hook-signals.json"),
6182
- hookSignalsLogPath: join6(rootDir, "log", "hook-signals.log"),
6183
- elicitationRequestsDir: join6(rootDir, "data", "elicitation-requests"),
6184
- eventStatesDir: join6(rootDir, "data", "event-states"),
6185
- questionRequestsDir: join6(rootDir, "data", "question-requests"),
6186
- permissionRequestsDir: join6(rootDir, "data", "permission-requests"),
6187
- agentGlobalConfigsFile: join6(rootDir, "data", "agent-global-configs.json")
6400
+ configDir: join7(rootDir, "config"),
6401
+ logDir: join7(rootDir, "log"),
6402
+ dataDir: join7(rootDir, "data"),
6403
+ serviceDir: join7(rootDir, "service"),
6404
+ skillsDir: join7(rootDir, "skills"),
6405
+ stateFile: join7(rootDir, "service.json"),
6406
+ pidFile: join7(rootDir, "grix-connector.pid"),
6407
+ daemonLockFile: join7(rootDir, "daemon.lock.json"),
6408
+ daemonStatusFile: join7(rootDir, "daemon-status.json"),
6409
+ stdoutLogFile: join7(rootDir, "service", "daemon.out.log"),
6410
+ stderrLogFile: join7(rootDir, "service", "daemon.err.log"),
6411
+ contextsDir: join7(rootDir, "data", "session-contexts"),
6412
+ hookSignalsPath: join7(rootDir, "data", "hook-signals.json"),
6413
+ hookSignalsLogPath: join7(rootDir, "log", "hook-signals.log"),
6414
+ elicitationRequestsDir: join7(rootDir, "data", "elicitation-requests"),
6415
+ eventStatesDir: join7(rootDir, "data", "event-states"),
6416
+ questionRequestsDir: join7(rootDir, "data", "question-requests"),
6417
+ permissionRequestsDir: join7(rootDir, "data", "permission-requests"),
6418
+ agentGlobalConfigsFile: join7(rootDir, "data", "agent-global-configs.json")
6188
6419
  };
6189
6420
  }
6190
6421
 
@@ -6245,13 +6476,13 @@ function cleanupOldLogs() {
6245
6476
  const cutoff = Date.now() - resolveRetentionDays() * 24 * 60 * 60 * 1e3;
6246
6477
  let entries2;
6247
6478
  try {
6248
- entries2 = readdirSync2(GRIX_PATHS.log);
6479
+ entries2 = readdirSync3(GRIX_PATHS.log);
6249
6480
  } catch {
6250
6481
  return;
6251
6482
  }
6252
6483
  for (const name of entries2) {
6253
6484
  if (!name.startsWith("grix-connector-") || !name.includes(".log")) continue;
6254
- const full = join7(GRIX_PATHS.log, name);
6485
+ const full = join8(GRIX_PATHS.log, name);
6255
6486
  try {
6256
6487
  if (statSync2(full).mtimeMs < cutoff) unlinkSync(full);
6257
6488
  } catch {
@@ -6263,7 +6494,7 @@ function openLogStream(date) {
6263
6494
  logStream?.end();
6264
6495
  } catch {
6265
6496
  }
6266
- const logFile = join7(GRIX_PATHS.log, `grix-connector-${date}.log`);
6497
+ const logFile = join8(GRIX_PATHS.log, `grix-connector-${date}.log`);
6267
6498
  logStream = createWriteStream(logFile, { flags: "a" });
6268
6499
  currentLogDate = date;
6269
6500
  cleanupOldLogs();
@@ -10533,8 +10764,8 @@ function collectMissingParameters(request) {
10533
10764
  }
10534
10765
 
10535
10766
  // src/openclaw/egg/orchestrator.ts
10536
- import { join as join10 } from "node:path";
10537
- import { homedir as homedir8 } from "node:os";
10767
+ import { join as join11 } from "node:path";
10768
+ import { homedir as homedir9 } from "node:os";
10538
10769
 
10539
10770
  // src/openclaw/sdk-exec.ts
10540
10771
  function resolveOpenClawCliArgvPrefix2() {
@@ -10644,21 +10875,21 @@ async function downloadPackage(params) {
10644
10875
 
10645
10876
  // src/openclaw/egg/persona-installer.ts
10646
10877
  var import_extract_zip = __toESM(require_extract_zip(), 1);
10647
- import { join as join8 } from "node:path";
10878
+ import { join as join9 } from "node:path";
10648
10879
  import { tmpdir } from "node:os";
10649
10880
  var PERSONA_FILES = ["IDENTITY.md", "SOUL.md", "AGENTS.md"];
10650
10881
  var OPTIONAL_PERSONA_FILES = ["USER.md", "MEMORY.md"];
10651
10882
  var ALL_PERSONA_FILES = [...PERSONA_FILES, ...OPTIONAL_PERSONA_FILES];
10652
10883
  function getWorkspaceRoot(agentName, openclawHome) {
10653
- return join8(openclawHome, `workspace-${agentName}`);
10884
+ return join9(openclawHome, `workspace-${agentName}`);
10654
10885
  }
10655
10886
  async function ensureWorkspaceDir(workspaceRoot) {
10656
10887
  await mkdir(workspaceRoot, { recursive: true });
10657
10888
  }
10658
10889
  async function extractZipToTemp(buffer) {
10659
- const tmpDir = join8(tmpdir(), `egg-extract-${Date.now()}`);
10890
+ const tmpDir = join9(tmpdir(), `egg-extract-${Date.now()}`);
10660
10891
  await mkdir(tmpDir, { recursive: true });
10661
- const zipPath = join8(tmpDir, "package.zip");
10892
+ const zipPath = join9(tmpDir, "package.zip");
10662
10893
  await writeFile(zipPath, buffer);
10663
10894
  await (0, import_extract_zip.default)(zipPath, { dir: tmpDir });
10664
10895
  return tmpDir;
@@ -10668,7 +10899,7 @@ async function findPersonaFilesInDir(dir, prefix = "") {
10668
10899
  const entries2 = await listEntries(dir, { withFileTypes: true });
10669
10900
  for (const entry of entries2) {
10670
10901
  if (entry.name === "package.zip") continue;
10671
- const fullPath = join8(dir, entry.name);
10902
+ const fullPath = join9(dir, entry.name);
10672
10903
  const relativeName = prefix ? `${prefix}/${entry.name}` : entry.name;
10673
10904
  if (entry.isDirectory()) {
10674
10905
  const nested = await findPersonaFilesInDir(fullPath, relativeName);
@@ -10691,7 +10922,7 @@ async function installPersonaFromZip(params) {
10691
10922
  const personaFiles = await findPersonaFilesInDir(tmpDir);
10692
10923
  for (const [fileName, sourcePath] of personaFiles) {
10693
10924
  const content = await loadFile(sourcePath, "utf-8");
10694
- await writeFile(join8(workspaceRoot, fileName), content, "utf-8");
10925
+ await writeFile(join9(workspaceRoot, fileName), content, "utf-8");
10695
10926
  installedFiles.push(fileName);
10696
10927
  }
10697
10928
  await ensureMinimalPersonaFiles(workspaceRoot, installedFiles);
@@ -10706,13 +10937,13 @@ async function ensureMinimalPersonaFiles(workspaceRoot, existingFiles) {
10706
10937
  if (!existingFiles.includes(required)) {
10707
10938
  const content = `# ${required.replace(".md", "")}
10708
10939
  `;
10709
- await writeFile(join8(workspaceRoot, required), content, "utf-8");
10940
+ await writeFile(join9(workspaceRoot, required), content, "utf-8");
10710
10941
  }
10711
10942
  }
10712
10943
  }
10713
10944
 
10714
10945
  // src/openclaw/egg/local-binding.ts
10715
- import { join as join9 } from "node:path";
10946
+ import { join as join10 } from "node:path";
10716
10947
  var LocalBindingError = class extends Error {
10717
10948
  constructor(message) {
10718
10949
  super(`[egg:bind] ${message}`);
@@ -10813,8 +11044,8 @@ function buildAgentListEntry(params) {
10813
11044
  }
10814
11045
  async function runLocalBinding(params) {
10815
11046
  const { agentName, createdAgent, isMainAgent = false, openclawHome } = params;
10816
- const workspace = join9(openclawHome, `workspace-${agentName}`);
10817
- const agentDir = join9(openclawHome, "agents", agentName, "agent");
11047
+ const workspace = join10(openclawHome, `workspace-${agentName}`);
11048
+ const agentDir = join10(openclawHome, "agents", agentName, "agent");
10818
11049
  await mkdir(workspace, { recursive: true });
10819
11050
  await mkdir(agentDir, { recursive: true });
10820
11051
  const wsUrl = deriveWsUrl(createdAgent.api_endpoint);
@@ -10994,7 +11225,7 @@ function makeEmptySteps() {
10994
11225
  };
10995
11226
  }
10996
11227
  function resolveStateFilePath(installId) {
10997
- return join10(homedir8(), ".openclaw", "egg-installs", `${installId}.json`);
11228
+ return join11(homedir9(), ".openclaw", "egg-installs", `${installId}.json`);
10998
11229
  }
10999
11230
  async function readStateFile(filePath) {
11000
11231
  try {
@@ -11005,7 +11236,7 @@ async function readStateFile(filePath) {
11005
11236
  }
11006
11237
  }
11007
11238
  async function writeStateFile(filePath, state) {
11008
- await mkdir(join10(homedir8(), ".openclaw", "egg-installs"), { recursive: true });
11239
+ await mkdir(join11(homedir9(), ".openclaw", "egg-installs"), { recursive: true });
11009
11240
  state.updated_at = nowIso();
11010
11241
  await writeFile(filePath, `${JSON.stringify(state, null, 2)}
11011
11242
  `, "utf-8");
@@ -11145,7 +11376,7 @@ async function writeSoulIfProvided(request, workspaceRoot) {
11145
11376
  content = await loadFile(soulFile, "utf-8");
11146
11377
  }
11147
11378
  if (!content) return;
11148
- await writeFile(join10(workspaceRoot, "SOUL.md"), content, "utf-8");
11379
+ await writeFile(join11(workspaceRoot, "SOUL.md"), content, "utf-8");
11149
11380
  }
11150
11381
  function parseNumericId(value) {
11151
11382
  const normalized = cleanText2(value);
@@ -11526,8 +11757,8 @@ async function runEggOrchestrator(params) {
11526
11757
  errorCode: "create_agent_failed"
11527
11758
  });
11528
11759
  }
11529
- const openclawHome = join10(homedir8(), ".openclaw");
11530
- const workspaceRoot = join10(openclawHome, `workspace-${request.localAgentName}`);
11760
+ const openclawHome = join11(homedir9(), ".openclaw");
11761
+ const workspaceRoot = join11(openclawHome, `workspace-${request.localAgentName}`);
11531
11762
  let downloadedBuffer = null;
11532
11763
  if (state.steps.install.status !== "done") {
11533
11764
  try {
@@ -11873,10 +12104,10 @@ function createGrixRegisterTool(api, ctx) {
11873
12104
 
11874
12105
  // src/openclaw/skill-tools/grix-update-tool.ts
11875
12106
  import { tmpdir as tmpdir2 } from "node:os";
11876
- import { join as join11 } from "node:path";
12107
+ import { join as join12 } from "node:path";
11877
12108
 
11878
12109
  // src/openclaw/skill-tools/timed-file-lock.ts
11879
- import { dirname as dirname6 } from "node:path";
12110
+ import { dirname as dirname7 } from "node:path";
11880
12111
  function getErrorCode(err) {
11881
12112
  if (typeof err !== "object" || err === null || !("code" in err)) {
11882
12113
  return void 0;
@@ -11930,7 +12161,7 @@ async function readExistingLock(lockFilePath, ttlMs) {
11930
12161
  }
11931
12162
  async function tryAcquireTimedFileLock(options) {
11932
12163
  const now = options.now ?? Date.now;
11933
- await mkdir(dirname6(options.lockFilePath), { recursive: true });
12164
+ await mkdir(dirname7(options.lockFilePath), { recursive: true });
11934
12165
  for (let attempt = 0; attempt < 4; attempt += 1) {
11935
12166
  const createdAt = now();
11936
12167
  const expiresAt = createdAt + options.ttlMs;
@@ -11984,7 +12215,7 @@ function normalizeNonEmptyString2(value) {
11984
12215
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
11985
12216
  }
11986
12217
  function resolveGrixUpdateLockFilePath(lockFilePath) {
11987
- return lockFilePath ?? join11(tmpdir2(), "grix-connector-update.lock");
12218
+ return lockFilePath ?? join12(tmpdir2(), "grix-connector-update.lock");
11988
12219
  }
11989
12220
  function createGrixUpdateTool(api, ctx, options = {}) {
11990
12221
  const delegatedTool = createDelegatedSkillTool({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grix-connector",
3
- "version": "3.15.2",
3
+ "version": "3.15.4",
4
4
  "description": "Connect local AI coding agents (Claude, Codex, Gemini, Qwen, DeepSeek, Cursor, OpenCode, Pi, OpenHuman, Reasonix) to the Grix scheduling platform. Also serves as an OpenClaw plugin for Grix channel transport.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",