grix-connector 3.33.2 → 3.33.3
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 +2 -2
- package/dist/adapter/agy/agy-adapter.js +5 -5
- package/dist/adapter/agy/model-list.js +2 -2
- package/dist/adapter/claude/claude-adapter.js +5 -5
- package/dist/adapter/claude/model-list.js +1 -1
- package/dist/adapter/codewhale/codewhale-adapter.js +2 -2
- package/dist/adapter/codewhale/model-list.js +2 -2
- package/dist/adapter/codex/codex-bridge.js +1 -1
- package/dist/adapter/cursor/cursor-adapter.js +7 -7
- package/dist/adapter/cursor/fetch-models.js +2 -2
- package/dist/adapter/cursor/resolve-command.js +1 -1
- package/dist/adapter/openhuman/openhuman-adapter.js +3 -3
- package/dist/assets/dsh-bridge/{grix-dsh-bridge-3.33.2.tgz → grix-dsh-bridge-3.33.3.tgz} +0 -0
- package/dist/assets/dsh-bridge/manifest.json +5 -5
- package/dist/audit/adapters/openclaw/openclaw-audit-adapter.js +1 -1
- package/dist/audit/adapters/pi/pi-transcript-source.js +1 -1
- package/dist/audit/core/transcript-fingerprint.js +1 -0
- package/dist/audit/producer/ipc-audit-producer.js +1 -1
- package/dist/bridge/adapter-pool.js +1 -1
- package/dist/bridge/bridge.js +9 -9
- package/dist/bridge/cli-install-offer.js +1 -0
- package/dist/bridge/respawn-manager.js +1 -1
- package/dist/core/files/file-serve.js +1 -1
- package/dist/core/installer/installer.js +6 -6
- package/dist/core/installer/npm-registry.js +3 -3
- package/dist/core/installer/prereq-installer.js +1 -1
- package/dist/core/proxy/hermes-profile-relay.js +1 -1
- package/dist/core/runtime/spawn.js +3 -3
- package/dist/core/upgrade/npm-upgrader.js +2 -2
- package/dist/core/util/cli-probe.js +2 -2
- package/dist/core/util/git-project-root.js +1 -1
- package/dist/default-skills/grix-egg/SKILL.md +2 -2
- package/dist/default-skills/message-send/SKILL.md +1 -1
- package/dist/default-skills/message-unsend/SKILL.md +1 -1
- package/dist/manager.js +1 -1
- package/dist/service/process-control.js +1 -1
- package/openclaw-plugin/audit-recorder-worker.js +170 -44
- package/openclaw-plugin/index.js +88 -14
- package/package.json +1 -1
|
@@ -3560,13 +3560,60 @@ var CodexAuditAdapter = class {
|
|
|
3560
3560
|
};
|
|
3561
3561
|
|
|
3562
3562
|
// src/audit/adapters/pi/pi-transcript-source.ts
|
|
3563
|
-
import { open as open3
|
|
3563
|
+
import { open as open3 } from "node:fs/promises";
|
|
3564
|
+
|
|
3565
|
+
// src/audit/core/transcript-fingerprint.ts
|
|
3566
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
3567
|
+
var READ_CHUNK_BYTES = 64 * 1024;
|
|
3568
|
+
async function readAndHashFilePrefixRange(handle, start, end) {
|
|
3569
|
+
if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || start < 0 || end < start) {
|
|
3570
|
+
throw new Error("Transcript range must contain safe non-negative offsets");
|
|
3571
|
+
}
|
|
3572
|
+
const digest = createHash3("sha256").update(String(end)).update("\0");
|
|
3573
|
+
const output = Buffer.allocUnsafe(end - start);
|
|
3574
|
+
const chunk = Buffer.allocUnsafe(Math.min(READ_CHUNK_BYTES, Math.max(1, end)));
|
|
3575
|
+
let position = 0;
|
|
3576
|
+
while (position < end) {
|
|
3577
|
+
const requested = Math.min(chunk.length, end - position);
|
|
3578
|
+
const { bytesRead } = await handle.read(chunk, 0, requested, position);
|
|
3579
|
+
if (bytesRead === 0) {
|
|
3580
|
+
throw new Error(`Transcript ended before prefix offset ${end}`);
|
|
3581
|
+
}
|
|
3582
|
+
const value = chunk.subarray(0, bytesRead);
|
|
3583
|
+
digest.update(value);
|
|
3584
|
+
const overlapStart = Math.max(position, start);
|
|
3585
|
+
const overlapEnd = Math.min(position + bytesRead, end);
|
|
3586
|
+
if (overlapStart < overlapEnd) {
|
|
3587
|
+
value.copy(
|
|
3588
|
+
output,
|
|
3589
|
+
overlapStart - start,
|
|
3590
|
+
overlapStart - position,
|
|
3591
|
+
overlapEnd - position
|
|
3592
|
+
);
|
|
3593
|
+
}
|
|
3594
|
+
position += bytesRead;
|
|
3595
|
+
}
|
|
3596
|
+
return { buffer: output, fingerprint: digest.digest("hex") };
|
|
3597
|
+
}
|
|
3598
|
+
|
|
3599
|
+
// src/audit/adapters/pi/pi-transcript-source.ts
|
|
3564
3600
|
function isRecord4(value) {
|
|
3565
3601
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3566
3602
|
}
|
|
3567
3603
|
function finiteOffset3(value, fallback) {
|
|
3568
3604
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : fallback;
|
|
3569
3605
|
}
|
|
3606
|
+
function recordIntegrityFailure(evidence, transcriptPath, detail) {
|
|
3607
|
+
evidence.anomalies.push({
|
|
3608
|
+
code: "pi_transcript_source_changed",
|
|
3609
|
+
message: `${transcriptPath}: ${detail}`
|
|
3610
|
+
});
|
|
3611
|
+
evidence.gaps.push({
|
|
3612
|
+
category: "main_transcript",
|
|
3613
|
+
reason: "correlation_failed",
|
|
3614
|
+
detail: `${transcriptPath}: ${detail}`
|
|
3615
|
+
});
|
|
3616
|
+
}
|
|
3570
3617
|
async function collectPiTranscript(boundary) {
|
|
3571
3618
|
const transcriptPath = typeof boundary.transcriptPath === "string" ? boundary.transcriptPath : void 0;
|
|
3572
3619
|
if (!transcriptPath) {
|
|
@@ -3591,31 +3638,57 @@ async function collectPiTranscript(boundary) {
|
|
|
3591
3638
|
sourcePaths: [transcriptPath]
|
|
3592
3639
|
};
|
|
3593
3640
|
try {
|
|
3594
|
-
const sourceStat = await stat4(transcriptPath);
|
|
3595
|
-
const requestedStart = finiteOffset3(boundary.transcriptStartOffset, 0);
|
|
3596
|
-
const requestedEnd = typeof boundary.transcriptEndOffset === "number" ? finiteOffset3(boundary.transcriptEndOffset, sourceStat.size) : sourceStat.size;
|
|
3597
|
-
if (requestedStart > sourceStat.size) {
|
|
3598
|
-
evidence.anomalies.push({
|
|
3599
|
-
code: "pi_transcript_boundary_out_of_range",
|
|
3600
|
-
message: `${transcriptPath}: start ${requestedStart} exceeds size ${sourceStat.size}`
|
|
3601
|
-
});
|
|
3602
|
-
evidence.gaps.push({
|
|
3603
|
-
category: "main_transcript",
|
|
3604
|
-
reason: "correlation_failed",
|
|
3605
|
-
detail: `${transcriptPath}:${requestedStart}-${requestedEnd}`
|
|
3606
|
-
});
|
|
3607
|
-
return evidence;
|
|
3608
|
-
}
|
|
3609
|
-
const start = requestedStart;
|
|
3610
|
-
const end = Math.min(Math.max(requestedEnd, start), sourceStat.size);
|
|
3611
|
-
const length = end - start;
|
|
3612
|
-
if (length === 0) return evidence;
|
|
3613
3641
|
const handle = await open3(transcriptPath, "r");
|
|
3614
3642
|
let buffer;
|
|
3643
|
+
let start;
|
|
3615
3644
|
try {
|
|
3616
|
-
|
|
3617
|
-
const
|
|
3618
|
-
|
|
3645
|
+
const sourceStat = await handle.stat();
|
|
3646
|
+
const requestedStart = finiteOffset3(boundary.transcriptStartOffset, 0);
|
|
3647
|
+
const requestedEnd = typeof boundary.transcriptEndOffset === "number" ? finiteOffset3(boundary.transcriptEndOffset, sourceStat.size) : sourceStat.size;
|
|
3648
|
+
if (requestedStart > sourceStat.size || requestedEnd > sourceStat.size) {
|
|
3649
|
+
evidence.anomalies.push({
|
|
3650
|
+
code: "pi_transcript_boundary_out_of_range",
|
|
3651
|
+
message: `${transcriptPath}: boundary ${requestedStart}-${requestedEnd} exceeds size ${sourceStat.size}`
|
|
3652
|
+
});
|
|
3653
|
+
evidence.gaps.push({
|
|
3654
|
+
category: "main_transcript",
|
|
3655
|
+
reason: "correlation_failed",
|
|
3656
|
+
detail: `${transcriptPath}:${requestedStart}-${requestedEnd}`
|
|
3657
|
+
});
|
|
3658
|
+
return evidence;
|
|
3659
|
+
}
|
|
3660
|
+
const expectedIdentity = typeof boundary.transcriptFileIdentity === "string" ? boundary.transcriptFileIdentity : void 0;
|
|
3661
|
+
const actualIdentity = `${sourceStat.dev}:${sourceStat.ino}`;
|
|
3662
|
+
if (expectedIdentity && actualIdentity !== expectedIdentity) {
|
|
3663
|
+
recordIntegrityFailure(
|
|
3664
|
+
evidence,
|
|
3665
|
+
transcriptPath,
|
|
3666
|
+
`identity ${actualIdentity} does not match ${expectedIdentity}`
|
|
3667
|
+
);
|
|
3668
|
+
return evidence;
|
|
3669
|
+
}
|
|
3670
|
+
const expectedFingerprint = typeof boundary.transcriptPrefixFingerprint === "string" ? boundary.transcriptPrefixFingerprint : void 0;
|
|
3671
|
+
start = requestedStart;
|
|
3672
|
+
const end = Math.max(requestedEnd, start);
|
|
3673
|
+
const length = end - start;
|
|
3674
|
+
if (expectedFingerprint) {
|
|
3675
|
+
const verified = await readAndHashFilePrefixRange(handle, start, end);
|
|
3676
|
+
if (verified.fingerprint !== expectedFingerprint) {
|
|
3677
|
+
recordIntegrityFailure(
|
|
3678
|
+
evidence,
|
|
3679
|
+
transcriptPath,
|
|
3680
|
+
"closed transcript prefix fingerprint changed"
|
|
3681
|
+
);
|
|
3682
|
+
return evidence;
|
|
3683
|
+
}
|
|
3684
|
+
buffer = verified.buffer;
|
|
3685
|
+
} else {
|
|
3686
|
+
if (length === 0) return evidence;
|
|
3687
|
+
buffer = Buffer.allocUnsafe(length);
|
|
3688
|
+
const { bytesRead } = await handle.read(buffer, 0, length, start);
|
|
3689
|
+
buffer = buffer.subarray(0, bytesRead);
|
|
3690
|
+
}
|
|
3691
|
+
if (length === 0) return evidence;
|
|
3619
3692
|
} finally {
|
|
3620
3693
|
await handle.close();
|
|
3621
3694
|
}
|
|
@@ -4273,7 +4346,7 @@ var PiAuditAdapter = class {
|
|
|
4273
4346
|
};
|
|
4274
4347
|
|
|
4275
4348
|
// src/audit/adapters/acp/generic-acp-audit-adapter.ts
|
|
4276
|
-
import { readFile as readFile3, readdir as readdir2, stat as
|
|
4349
|
+
import { readFile as readFile3, readdir as readdir2, stat as stat4 } from "node:fs/promises";
|
|
4277
4350
|
import { homedir } from "node:os";
|
|
4278
4351
|
import { basename as basename4, join as join2 } from "node:path";
|
|
4279
4352
|
var DEFAULT_CAPTURE4 = Object.freeze({
|
|
@@ -4364,7 +4437,7 @@ async function collectQwenUsage(job, providerSessionId, cwd) {
|
|
|
4364
4437
|
`${providerSessionId}.jsonl`
|
|
4365
4438
|
);
|
|
4366
4439
|
try {
|
|
4367
|
-
await
|
|
4440
|
+
await stat4(sourcePath);
|
|
4368
4441
|
} catch {
|
|
4369
4442
|
return { records: [] };
|
|
4370
4443
|
}
|
|
@@ -4413,7 +4486,7 @@ async function locateGeminiSession(providerSessionId, cwd) {
|
|
|
4413
4486
|
const candidates = names.filter((name) => name.startsWith("session-") && name.includes(shortId) && (name.endsWith(".json") || name.endsWith(".jsonl")));
|
|
4414
4487
|
const ranked = await Promise.all(candidates.map(async (name) => {
|
|
4415
4488
|
const sourcePath = join2(chats, name);
|
|
4416
|
-
return { sourcePath, modifiedAt: (await
|
|
4489
|
+
return { sourcePath, modifiedAt: (await stat4(sourcePath)).mtimeMs };
|
|
4417
4490
|
}));
|
|
4418
4491
|
return ranked.sort((left, right) => right.modifiedAt - left.modifiedAt)[0]?.sourcePath;
|
|
4419
4492
|
} catch {
|
|
@@ -4895,7 +4968,7 @@ var GenericAcpAuditAdapter = class {
|
|
|
4895
4968
|
};
|
|
4896
4969
|
|
|
4897
4970
|
// src/audit/adapters/acp/kimi-audit-adapter.ts
|
|
4898
|
-
import { readFile as readFile4, readdir as readdir3, stat as
|
|
4971
|
+
import { readFile as readFile4, readdir as readdir3, stat as stat5 } from "node:fs/promises";
|
|
4899
4972
|
import { homedir as homedir2 } from "node:os";
|
|
4900
4973
|
import { basename as basename5, dirname, join as join3 } from "node:path";
|
|
4901
4974
|
var DEFAULT_CAPTURE5 = Object.freeze({
|
|
@@ -5027,7 +5100,7 @@ async function locateSessionDirectory(job) {
|
|
|
5027
5100
|
const path = join3(root, workspace.name, providerSessionId);
|
|
5028
5101
|
const wirePath = join3(path, "agents", "main", "wire.jsonl");
|
|
5029
5102
|
try {
|
|
5030
|
-
const wireStat = await
|
|
5103
|
+
const wireStat = await stat5(wirePath);
|
|
5031
5104
|
let cwdMatches = false;
|
|
5032
5105
|
const cwd = stringValue5(job.boundary.cwd);
|
|
5033
5106
|
if (cwd) {
|
|
@@ -5868,7 +5941,7 @@ var KimiAuditAdapter = class {
|
|
|
5868
5941
|
};
|
|
5869
5942
|
|
|
5870
5943
|
// src/audit/adapters/acp/reasonix-transcript-source.ts
|
|
5871
|
-
import { open as open4, stat as
|
|
5944
|
+
import { open as open4, stat as stat6 } from "node:fs/promises";
|
|
5872
5945
|
function isRecord8(value) {
|
|
5873
5946
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5874
5947
|
}
|
|
@@ -5921,7 +5994,7 @@ async function collectReasonixTranscript(boundary) {
|
|
|
5921
5994
|
return evidence;
|
|
5922
5995
|
}
|
|
5923
5996
|
try {
|
|
5924
|
-
const sourceStat = await
|
|
5997
|
+
const sourceStat = await stat6(transcriptPath);
|
|
5925
5998
|
const requestedStart = finiteOffset4(boundary.transcriptStartOffset, 0);
|
|
5926
5999
|
const requestedEnd = typeof boundary.transcriptEndOffset === "number" ? finiteOffset4(boundary.transcriptEndOffset, sourceStat.size) : sourceStat.size;
|
|
5927
6000
|
if (requestedStart > sourceStat.size) {
|
|
@@ -8232,23 +8305,76 @@ function usageSpan(job, parentSpanId, sequence, at, raw, requestId2, modelId, pr
|
|
|
8232
8305
|
}
|
|
8233
8306
|
|
|
8234
8307
|
// src/audit/adapters/openclaw/openclaw-audit-adapter.ts
|
|
8235
|
-
import { readFile as readFile5 } from "node:fs/promises";
|
|
8236
|
-
import { dirname as dirname2, join as join4 } from "node:path";
|
|
8308
|
+
import { readFile as readFile5, readdir as readdir4, stat as stat7 } from "node:fs/promises";
|
|
8309
|
+
import { basename as basename6, dirname as dirname2, join as join4 } from "node:path";
|
|
8237
8310
|
function isRecord14(value) {
|
|
8238
8311
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8239
8312
|
}
|
|
8240
|
-
|
|
8241
|
-
|
|
8313
|
+
function replaceTranscriptPath(boundary, transcriptPath) {
|
|
8314
|
+
const next = { ...boundary, transcriptPath };
|
|
8315
|
+
delete next.transcriptStartOffset;
|
|
8316
|
+
delete next.transcriptEndOffset;
|
|
8317
|
+
delete next.transcriptFileIdentity;
|
|
8318
|
+
delete next.transcriptPrefixFingerprint;
|
|
8319
|
+
return next;
|
|
8320
|
+
}
|
|
8321
|
+
async function fileIdentity(path) {
|
|
8322
|
+
try {
|
|
8323
|
+
const source = await stat7(path);
|
|
8324
|
+
return `${source.dev}:${source.ino}`;
|
|
8325
|
+
} catch {
|
|
8326
|
+
return void 0;
|
|
8327
|
+
}
|
|
8328
|
+
}
|
|
8329
|
+
async function resolveResetTranscriptPath(transcriptPath, expectedIdentity) {
|
|
8330
|
+
if (!expectedIdentity) return void 0;
|
|
8331
|
+
try {
|
|
8332
|
+
const directory = dirname2(transcriptPath);
|
|
8333
|
+
const prefix = `${basename6(transcriptPath)}.reset`;
|
|
8334
|
+
const candidates = (await readdir4(directory)).filter((entry) => entry.startsWith(prefix)).sort().reverse();
|
|
8335
|
+
for (const entry of candidates) {
|
|
8336
|
+
const candidate = join4(directory, entry);
|
|
8337
|
+
if (await fileIdentity(candidate) === expectedIdentity) return candidate;
|
|
8338
|
+
}
|
|
8339
|
+
} catch {
|
|
8340
|
+
}
|
|
8341
|
+
return void 0;
|
|
8342
|
+
}
|
|
8343
|
+
async function resolveCurrentTranscriptPath(boundary) {
|
|
8242
8344
|
const storePath = typeof boundary.sessionStorePath === "string" ? boundary.sessionStorePath : void 0;
|
|
8243
8345
|
const sessionKey = typeof boundary.routeSessionKey === "string" ? boundary.routeSessionKey : void 0;
|
|
8244
|
-
if (!storePath || !sessionKey) return
|
|
8346
|
+
if (!storePath || !sessionKey) return void 0;
|
|
8245
8347
|
try {
|
|
8246
8348
|
const parsed = JSON.parse(await readFile5(storePath, "utf8"));
|
|
8247
|
-
if (!isRecord14(parsed) || !isRecord14(parsed[sessionKey])) return
|
|
8349
|
+
if (!isRecord14(parsed) || !isRecord14(parsed[sessionKey])) return void 0;
|
|
8248
8350
|
const session = parsed[sessionKey];
|
|
8249
|
-
|
|
8250
|
-
|
|
8351
|
+
return typeof session.sessionFile === "string" ? session.sessionFile : typeof session.sessionId === "string" ? join4(dirname2(storePath), `${session.sessionId}.jsonl`) : void 0;
|
|
8352
|
+
} catch {
|
|
8353
|
+
return void 0;
|
|
8354
|
+
}
|
|
8355
|
+
}
|
|
8356
|
+
async function resolveTranscriptBoundary(boundary) {
|
|
8357
|
+
const transcriptPath = typeof boundary.transcriptPath === "string" ? boundary.transcriptPath : void 0;
|
|
8358
|
+
if (!transcriptPath) {
|
|
8359
|
+
const currentTranscriptPath = await resolveCurrentTranscriptPath(boundary);
|
|
8360
|
+
return currentTranscriptPath ? replaceTranscriptPath(boundary, currentTranscriptPath) : boundary;
|
|
8361
|
+
}
|
|
8362
|
+
try {
|
|
8363
|
+
await stat7(transcriptPath);
|
|
8364
|
+
return boundary;
|
|
8251
8365
|
} catch {
|
|
8366
|
+
const expectedIdentity = typeof boundary.transcriptFileIdentity === "string" ? boundary.transcriptFileIdentity : void 0;
|
|
8367
|
+
const resetTranscriptPath = await resolveResetTranscriptPath(
|
|
8368
|
+
transcriptPath,
|
|
8369
|
+
expectedIdentity
|
|
8370
|
+
);
|
|
8371
|
+
if (resetTranscriptPath) {
|
|
8372
|
+
return { ...boundary, transcriptPath: resetTranscriptPath };
|
|
8373
|
+
}
|
|
8374
|
+
const currentTranscriptPath = await resolveCurrentTranscriptPath(boundary);
|
|
8375
|
+
if (currentTranscriptPath && expectedIdentity && await fileIdentity(currentTranscriptPath) === expectedIdentity) {
|
|
8376
|
+
return { ...boundary, transcriptPath: currentTranscriptPath };
|
|
8377
|
+
}
|
|
8252
8378
|
return boundary;
|
|
8253
8379
|
}
|
|
8254
8380
|
}
|
|
@@ -8317,7 +8443,7 @@ var OpenClawAuditAdapter = class {
|
|
|
8317
8443
|
|
|
8318
8444
|
// src/audit/storage/file-audit-replay-store.ts
|
|
8319
8445
|
import {
|
|
8320
|
-
createHash as
|
|
8446
|
+
createHash as createHash4,
|
|
8321
8447
|
randomUUID
|
|
8322
8448
|
} from "node:crypto";
|
|
8323
8449
|
import {
|
|
@@ -8325,12 +8451,12 @@ import {
|
|
|
8325
8451
|
open as open5,
|
|
8326
8452
|
mkdir,
|
|
8327
8453
|
readFile as readFile6,
|
|
8328
|
-
readdir as
|
|
8454
|
+
readdir as readdir5,
|
|
8329
8455
|
rename,
|
|
8330
8456
|
rm,
|
|
8331
8457
|
writeFile
|
|
8332
8458
|
} from "node:fs/promises";
|
|
8333
|
-
import { basename as
|
|
8459
|
+
import { basename as basename7, dirname as dirname3, join as join5, relative, resolve as resolve3, sep as sep3 } from "node:path";
|
|
8334
8460
|
var SHA256_PATTERN = /^[a-f0-9]{64}$/;
|
|
8335
8461
|
var NO_CAPTURE = Object.freeze({
|
|
8336
8462
|
inputOutput: false,
|
|
@@ -8728,7 +8854,7 @@ var FileAuditReplayStore = class {
|
|
|
8728
8854
|
await mkdir(directory, { recursive: true, mode: 448 });
|
|
8729
8855
|
const temporary = join5(
|
|
8730
8856
|
directory,
|
|
8731
|
-
`.${
|
|
8857
|
+
`.${basename7(path)}.${process.pid}.${randomUUID()}.tmp`
|
|
8732
8858
|
);
|
|
8733
8859
|
try {
|
|
8734
8860
|
await writeFile(temporary, body, { mode: 384, flag: "wx" });
|
|
@@ -8860,7 +8986,7 @@ function encodeJson(value) {
|
|
|
8860
8986
|
`, "utf8");
|
|
8861
8987
|
}
|
|
8862
8988
|
function sha256(value) {
|
|
8863
|
-
return
|
|
8989
|
+
return createHash4("sha256").update(value).digest("hex");
|
|
8864
8990
|
}
|
|
8865
8991
|
function idKey(id) {
|
|
8866
8992
|
return sha256(Buffer.from(id, "utf8"));
|
|
@@ -8876,7 +9002,7 @@ async function pathExists(path) {
|
|
|
8876
9002
|
}
|
|
8877
9003
|
async function readDirectory(path) {
|
|
8878
9004
|
try {
|
|
8879
|
-
return await
|
|
9005
|
+
return await readdir5(path);
|
|
8880
9006
|
} catch (error) {
|
|
8881
9007
|
if (isNotFound(error)) return [];
|
|
8882
9008
|
throw error;
|
package/openclaw-plugin/index.js
CHANGED
|
@@ -2489,7 +2489,10 @@ var IpcAuditProducer = class {
|
|
|
2489
2489
|
try {
|
|
2490
2490
|
child = fork(this.workerPath, [], {
|
|
2491
2491
|
stdio: ["ignore", "ignore", "ignore", "ipc"],
|
|
2492
|
-
serialization: "json"
|
|
2492
|
+
serialization: "json",
|
|
2493
|
+
// ForkOptions 类型定义缺 windowsHide(Node 运行时实际支持),无控制台父进程
|
|
2494
|
+
// 下缺省会新建可见控制台窗口,故加类型断言补上。
|
|
2495
|
+
windowsHide: true
|
|
2493
2496
|
});
|
|
2494
2497
|
} catch (error) {
|
|
2495
2498
|
this.diagnostic({
|
|
@@ -3834,7 +3837,7 @@ function isTailnetIPv4(addr) {
|
|
|
3834
3837
|
}
|
|
3835
3838
|
function detectViaCLI() {
|
|
3836
3839
|
return new Promise((resolve4) => {
|
|
3837
|
-
execFile2("tailscale", ["ip", "-4"], { timeout: 3e3 }, (err2, stdout) => {
|
|
3840
|
+
execFile2("tailscale", ["ip", "-4"], { timeout: 3e3, windowsHide: true }, (err2, stdout) => {
|
|
3838
3841
|
if (err2) {
|
|
3839
3842
|
resolve4(void 0);
|
|
3840
3843
|
return;
|
|
@@ -7383,7 +7386,7 @@ function createAppendOnlyReplyStream(params) {
|
|
|
7383
7386
|
|
|
7384
7387
|
// src/openclaw/audit-runtime.ts
|
|
7385
7388
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
7386
|
-
import {
|
|
7389
|
+
import { open as open2, readFile as readFile4 } from "node:fs/promises";
|
|
7387
7390
|
import { dirname as dirname8, join as join11 } from "node:path";
|
|
7388
7391
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
7389
7392
|
|
|
@@ -8258,6 +8261,41 @@ function outcomeForStatus(status) {
|
|
|
8258
8261
|
return status === "canceled" ? "cancelled" : "failed";
|
|
8259
8262
|
}
|
|
8260
8263
|
|
|
8264
|
+
// src/audit/core/transcript-fingerprint.ts
|
|
8265
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
8266
|
+
var READ_CHUNK_BYTES = 64 * 1024;
|
|
8267
|
+
async function hashFilePrefixes(handle, lengths) {
|
|
8268
|
+
const uniqueLengths = [...new Set(lengths)].sort((left, right) => left - right);
|
|
8269
|
+
if (uniqueLengths.some((length) => !Number.isSafeInteger(length) || length < 0)) {
|
|
8270
|
+
throw new Error("Transcript prefix lengths must be non-negative safe integers");
|
|
8271
|
+
}
|
|
8272
|
+
const digests = new Map(uniqueLengths.map((length) => [
|
|
8273
|
+
length,
|
|
8274
|
+
createHash2("sha256").update(String(length)).update("\0")
|
|
8275
|
+
]));
|
|
8276
|
+
const maxLength = uniqueLengths.at(-1) ?? 0;
|
|
8277
|
+
const chunk = Buffer.allocUnsafe(
|
|
8278
|
+
Math.min(READ_CHUNK_BYTES, Math.max(1, maxLength))
|
|
8279
|
+
);
|
|
8280
|
+
let position = 0;
|
|
8281
|
+
while (position < maxLength) {
|
|
8282
|
+
const requested = Math.min(chunk.length, maxLength - position);
|
|
8283
|
+
const { bytesRead } = await handle.read(chunk, 0, requested, position);
|
|
8284
|
+
if (bytesRead === 0) {
|
|
8285
|
+
throw new Error(`Transcript ended before prefix offset ${maxLength}`);
|
|
8286
|
+
}
|
|
8287
|
+
for (const [length, digest] of digests) {
|
|
8288
|
+
if (position >= length) continue;
|
|
8289
|
+
digest.update(chunk.subarray(0, Math.min(bytesRead, length - position)));
|
|
8290
|
+
}
|
|
8291
|
+
position += bytesRead;
|
|
8292
|
+
}
|
|
8293
|
+
return new Map([...digests].map(([length, digest]) => [
|
|
8294
|
+
length,
|
|
8295
|
+
digest.digest("hex")
|
|
8296
|
+
]));
|
|
8297
|
+
}
|
|
8298
|
+
|
|
8261
8299
|
// src/openclaw/audit-runtime.ts
|
|
8262
8300
|
function isRecord3(value) {
|
|
8263
8301
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -8273,12 +8311,29 @@ async function resolveTranscriptPath(storePath, sessionKey) {
|
|
|
8273
8311
|
return void 0;
|
|
8274
8312
|
}
|
|
8275
8313
|
}
|
|
8276
|
-
async function
|
|
8314
|
+
async function fileSnapshot(path7, comparisonLength) {
|
|
8277
8315
|
if (!path7) return void 0;
|
|
8316
|
+
const handle = await open2(path7, "r").catch(() => void 0);
|
|
8317
|
+
if (!handle) return void 0;
|
|
8278
8318
|
try {
|
|
8279
|
-
|
|
8319
|
+
const source = await handle.stat();
|
|
8320
|
+
const lengths = [source.size];
|
|
8321
|
+
if (comparisonLength !== void 0 && Number.isSafeInteger(comparisonLength) && comparisonLength >= 0 && comparisonLength <= source.size) {
|
|
8322
|
+
lengths.push(comparisonLength);
|
|
8323
|
+
}
|
|
8324
|
+
const fingerprints = await hashFilePrefixes(handle, lengths);
|
|
8325
|
+
const prefixFingerprint = fingerprints.get(source.size);
|
|
8326
|
+
if (!prefixFingerprint) return void 0;
|
|
8327
|
+
return {
|
|
8328
|
+
...comparisonLength === void 0 ? {} : { comparisonFingerprint: fingerprints.get(comparisonLength) },
|
|
8329
|
+
identity: `${source.dev}:${source.ino}`,
|
|
8330
|
+
prefixFingerprint,
|
|
8331
|
+
size: source.size
|
|
8332
|
+
};
|
|
8280
8333
|
} catch {
|
|
8281
8334
|
return void 0;
|
|
8335
|
+
} finally {
|
|
8336
|
+
await handle.close();
|
|
8282
8337
|
}
|
|
8283
8338
|
}
|
|
8284
8339
|
async function captureOpenClawAuditBoundary(input) {
|
|
@@ -8286,23 +8341,42 @@ async function captureOpenClawAuditBoundary(input) {
|
|
|
8286
8341
|
input.sessionStorePath,
|
|
8287
8342
|
input.routeSessionKey
|
|
8288
8343
|
);
|
|
8289
|
-
const
|
|
8344
|
+
const transcriptSnapshot = await fileSnapshot(transcriptPath);
|
|
8290
8345
|
return {
|
|
8291
8346
|
adapterType: "openclaw",
|
|
8292
8347
|
...input,
|
|
8293
8348
|
...transcriptPath ? { transcriptPath } : {},
|
|
8294
|
-
...
|
|
8349
|
+
...transcriptSnapshot === void 0 ? {} : {
|
|
8350
|
+
transcriptFileIdentity: transcriptSnapshot.identity,
|
|
8351
|
+
transcriptPrefixFingerprint: transcriptSnapshot.prefixFingerprint,
|
|
8352
|
+
transcriptStartOffset: transcriptSnapshot.size
|
|
8353
|
+
}
|
|
8295
8354
|
};
|
|
8296
8355
|
}
|
|
8297
8356
|
async function closeOpenClawAuditBoundary(boundary) {
|
|
8298
|
-
const
|
|
8357
|
+
const capturedTranscriptPath = typeof boundary.transcriptPath === "string" ? boundary.transcriptPath : void 0;
|
|
8358
|
+
const currentTranscriptPath = await resolveTranscriptPath(
|
|
8299
8359
|
boundary.sessionStorePath,
|
|
8300
8360
|
boundary.routeSessionKey
|
|
8301
8361
|
);
|
|
8302
|
-
const
|
|
8362
|
+
const transcriptPath = currentTranscriptPath ?? capturedTranscriptPath;
|
|
8363
|
+
const capturedIdentity = typeof boundary.transcriptFileIdentity === "string" ? boundary.transcriptFileIdentity : void 0;
|
|
8364
|
+
const capturedPrefixFingerprint = typeof boundary.transcriptPrefixFingerprint === "string" ? boundary.transcriptPrefixFingerprint : void 0;
|
|
8365
|
+
const capturedStartOffset = typeof boundary.transcriptStartOffset === "number" ? boundary.transcriptStartOffset : void 0;
|
|
8366
|
+
const transcriptSnapshot = await fileSnapshot(
|
|
8367
|
+
transcriptPath,
|
|
8368
|
+
capturedStartOffset
|
|
8369
|
+
);
|
|
8370
|
+
const currentPrefixFingerprint = transcriptSnapshot?.comparisonFingerprint;
|
|
8371
|
+
const transcriptReset = currentTranscriptPath !== void 0 && currentTranscriptPath !== capturedTranscriptPath || capturedIdentity !== void 0 && transcriptSnapshot !== void 0 && transcriptSnapshot.identity !== capturedIdentity || capturedStartOffset !== void 0 && transcriptSnapshot !== void 0 && transcriptSnapshot.size < capturedStartOffset || capturedPrefixFingerprint !== void 0 && transcriptSnapshot !== void 0 && currentPrefixFingerprint !== capturedPrefixFingerprint;
|
|
8303
8372
|
return {
|
|
8304
8373
|
...transcriptPath ? { transcriptPath } : {},
|
|
8305
|
-
...
|
|
8374
|
+
...transcriptReset ? { transcriptStartOffset: 0 } : {},
|
|
8375
|
+
...transcriptSnapshot === void 0 ? {} : {
|
|
8376
|
+
transcriptFileIdentity: transcriptSnapshot.identity,
|
|
8377
|
+
transcriptPrefixFingerprint: transcriptSnapshot.prefixFingerprint,
|
|
8378
|
+
transcriptEndOffset: transcriptSnapshot.size
|
|
8379
|
+
}
|
|
8306
8380
|
};
|
|
8307
8381
|
}
|
|
8308
8382
|
function openClawAuditConfigurationError(error) {
|
|
@@ -11602,7 +11676,7 @@ function registerGrixAdminCli(params) {
|
|
|
11602
11676
|
}
|
|
11603
11677
|
|
|
11604
11678
|
// src/openclaw/skill-tools/delegated-skill-tool.ts
|
|
11605
|
-
import { createHash as
|
|
11679
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
11606
11680
|
var DelegatedSkillToolSchema = {
|
|
11607
11681
|
type: "object",
|
|
11608
11682
|
additionalProperties: false,
|
|
@@ -11648,7 +11722,7 @@ function buildSkillTaskMessage(params) {
|
|
|
11648
11722
|
].join("\n");
|
|
11649
11723
|
}
|
|
11650
11724
|
function buildInternalIdempotencyKey(params) {
|
|
11651
|
-
const digest =
|
|
11725
|
+
const digest = createHash3("sha256").update(params.spec.name).update("\n").update(params.toolCallId).update("\n").update(params.subagentSessionKey).update("\n").update(params.task).digest("hex");
|
|
11652
11726
|
return `plugin:${params.spec.name}:subagent:${digest}`;
|
|
11653
11727
|
}
|
|
11654
11728
|
function createDelegatedSkillTool(params) {
|
|
@@ -12100,7 +12174,7 @@ function buildConversationCard(params) {
|
|
|
12100
12174
|
}
|
|
12101
12175
|
|
|
12102
12176
|
// src/openclaw/egg/package-downloader.ts
|
|
12103
|
-
import { createHash as
|
|
12177
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
12104
12178
|
var PackageDownloadError = class extends Error {
|
|
12105
12179
|
constructor(message) {
|
|
12106
12180
|
super(`[egg:download] ${message}`);
|
|
@@ -12119,7 +12193,7 @@ async function downloadPackage(params) {
|
|
|
12119
12193
|
const arrayBuffer = await response.arrayBuffer();
|
|
12120
12194
|
const buffer = Buffer.from(arrayBuffer);
|
|
12121
12195
|
if (expectedHash) {
|
|
12122
|
-
const actualHash =
|
|
12196
|
+
const actualHash = createHash4(hashAlgorithm).update(buffer).digest("hex");
|
|
12123
12197
|
if (actualHash !== expectedHash.toLowerCase()) {
|
|
12124
12198
|
throw new PackageDownloadError(
|
|
12125
12199
|
`hash mismatch: expected ${expectedHash}, got ${actualHash}`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "grix-connector",
|
|
3
|
-
"version": "3.33.
|
|
3
|
+
"version": "3.33.3",
|
|
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",
|