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.
- package/dist/adapter/acp/acp-adapter.js +4 -4
- package/dist/adapter/cursor/cursor-adapter.js +6 -6
- package/dist/adapter/opencode/opencode-adapter.js +4 -4
- package/dist/adapter/pi/pi-adapter.js +4 -4
- package/dist/bridge/bridge.js +9 -9
- package/dist/core/aibot/client.js +2 -2
- package/dist/core/skill-sync/enable-roots.js +1 -0
- package/dist/core/skill-sync/library-skills.js +1 -0
- package/dist/core/skill-sync/manifest.js +1 -0
- package/dist/core/skill-sync/skill-enable.js +1 -0
- package/dist/core/skill-sync/skill-syncer.js +1 -1
- package/dist/manager.js +2 -2
- package/dist/mcp/stream-http/security.js +1 -1
- package/openclaw-plugin/index.js +306 -75
- package/package.json +1 -1
package/openclaw-plugin/index.js
CHANGED
|
@@ -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
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
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
|
|
3473
|
-
import { join as
|
|
3474
|
-
import { homedir as
|
|
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 (!
|
|
3732
|
+
if (!existsSync3(baseDir)) return [];
|
|
3503
3733
|
const results = [];
|
|
3504
3734
|
try {
|
|
3505
|
-
for (const entry of
|
|
3735
|
+
for (const entry of readdirSync2(baseDir, { withFileTypes: true })) {
|
|
3506
3736
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
3507
|
-
const skillFile =
|
|
3508
|
-
if (!
|
|
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
|
-
|
|
3522
|
-
|
|
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
|
|
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
|
|
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 (!
|
|
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(
|
|
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 (!
|
|
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(
|
|
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
|
|
5746
|
-
import { join as
|
|
5747
|
-
var BASE_DIR = process.env.GRIX_CONNECTOR_HOME ? process.env.GRIX_CONNECTOR_HOME :
|
|
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 =
|
|
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(
|
|
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 =
|
|
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
|
|
6158
|
-
import { join as
|
|
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
|
|
6162
|
-
import { homedir as
|
|
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 =
|
|
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:
|
|
6170
|
-
logDir:
|
|
6171
|
-
dataDir:
|
|
6172
|
-
serviceDir:
|
|
6173
|
-
skillsDir:
|
|
6174
|
-
stateFile:
|
|
6175
|
-
pidFile:
|
|
6176
|
-
daemonLockFile:
|
|
6177
|
-
daemonStatusFile:
|
|
6178
|
-
stdoutLogFile:
|
|
6179
|
-
stderrLogFile:
|
|
6180
|
-
contextsDir:
|
|
6181
|
-
hookSignalsPath:
|
|
6182
|
-
hookSignalsLogPath:
|
|
6183
|
-
elicitationRequestsDir:
|
|
6184
|
-
eventStatesDir:
|
|
6185
|
-
questionRequestsDir:
|
|
6186
|
-
permissionRequestsDir:
|
|
6187
|
-
agentGlobalConfigsFile:
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
10537
|
-
import { homedir as
|
|
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
|
|
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
|
|
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 =
|
|
10890
|
+
const tmpDir = join9(tmpdir(), `egg-extract-${Date.now()}`);
|
|
10660
10891
|
await mkdir(tmpDir, { recursive: true });
|
|
10661
|
-
const zipPath =
|
|
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 =
|
|
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(
|
|
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(
|
|
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
|
|
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 =
|
|
10817
|
-
const agentDir =
|
|
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
|
|
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(
|
|
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(
|
|
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 =
|
|
11530
|
-
const workspaceRoot =
|
|
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
|
|
12107
|
+
import { join as join12 } from "node:path";
|
|
11877
12108
|
|
|
11878
12109
|
// src/openclaw/skill-tools/timed-file-lock.ts
|
|
11879
|
-
import { dirname as
|
|
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(
|
|
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 ??
|
|
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.
|
|
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",
|