@gendigital/sage-openclaw 0.11.0 → 0.12.0
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/README.md +1 -1
- package/dist/index.cjs +1444 -468
- package/dist/index.cjs.map +4 -4
- package/dist/mcp-server.cjs +194 -88
- package/dist/mcp-server.cjs.map +4 -4
- package/dist/model-download-worker.cjs +136 -93
- package/dist/model-download-worker.cjs.map +3 -3
- package/dist/skill-upload-worker.cjs +5632 -0
- package/dist/skill-upload-worker.cjs.map +7 -0
- package/openclaw.plugin.json +6 -1
- package/package.json +8 -3
- package/resources/threats/dummy.yaml +22 -17
|
@@ -67,7 +67,7 @@ function Pn(s3, t) {
|
|
|
67
67
|
function zn(s3, t) {
|
|
68
68
|
s3.head = new ue(t, void 0, s3.head, s3), s3.tail || (s3.tail = s3.head), s3.length++;
|
|
69
69
|
}
|
|
70
|
-
var import_events, import_fs, import_node_events, import_node_stream, import_node_string_decoder, import_node_path4, import_node_fs2, import_path, import_events2, import_assert, import_buffer, ks, import_zlib, import_node_path5, import_node_path6, import_fs2, import_fs3, import_path2, import_node_path7, import_path3, import_node_fs3, import_node_assert, import_node_crypto2, import_node_fs4, import_node_path8, import_fs4, import_node_fs5, import_node_path9, import_node_fs6,
|
|
70
|
+
var import_events, import_fs, import_node_events, import_node_stream, import_node_string_decoder, import_node_path4, import_node_fs2, import_path, import_events2, import_assert, import_buffer, ks, import_zlib, import_node_path5, import_node_path6, import_fs2, import_fs3, import_path2, import_node_path7, import_path3, import_node_fs3, import_node_assert, import_node_crypto2, import_node_fs4, import_node_path8, import_fs4, import_node_fs5, import_node_path9, import_node_fs6, import_promises3, import_node_path10, import_node_path11, import_node_fs7, import_node_path12, kr, vr, Os, Br, Pr, zr, q, j, rt, Le, jt, Ne, Ts, Ae, xs, z, Mt, b, Qt, Bt, _, A, g, yi, De, L, w, Ri, bi, Ls, _i, Z, gi, Ie, Jt, yt, C, te, Ur, Hr, Wr, Gr, Ce, Oi, Zr, Yr, D, Vr, ot, H, ee, m, xi, J, Li, Ii, Ci, se, Fe, Ut, Ht, Ni, Pt, ht, U, nt, Y, zt, Ai, Q, ie, Di, ke, Rt, ve, bt, _t, Me, tt, Wt, $r, As, Ds, Is, Cs, Fs, Xr, re, K, jr, M, Qr, vs, Jr, ki, Ot, Gt, vi, ne, Be, Pe, ze, Ue, He, We, Ge, Ze, Ye, Ms, en, sn, Bs, rn, nn, Ps, zs, Bi, oe, hn, he, Ke, F, an, Tt, Pi, ln, at, cn, fn, dn, lt, un, mn, pn, zi, En, xt, ct, Sn, yn, Rn, bn, f, Yt, Lt, gn, Zi, Yi, On, B, Nt, et, Ui, Us, V, ae, ft, Hs, p, it, dt, Hi, At, y, Ve, $e, Wi, Ws, Gs, le, Gi, Xe, Kt, ut, qe, Dt, je, Qe, Zs, Tn, st, mt, Nn, Ki, An, Dn, It, Vi, Cn, Ys, ce, Je, $i, Fn, kn, Xi, Ks, Js, vn, Xs, qs, js, ji, Qs, fe, ti, Qi, ei, Ji, ts, es, is, pt, ii, ss, qi, X, de, si, ri, Mn, ni, ue, di, tr, oi, me, W, Ct, Ft, pe, rs, G, ns, hi, er, as, ls, ai, li, ir, os, ci, rr, hs, Et, kt, Un, Hn, or, hr, Wn, Gn, Zn, Yn, fr, dr, ar, ur, mr, pr, Kn, Vn, $n, lr, cs, fs2, ui, Xn, ds, qn, us, we, wt, Qn, Er, ms, wr, Jn, Sr, ps, yr, $t, Rr, to, eo, io, Ei, _r, gr, ys, Or, Rs, P, bs, _s, Si, Tr, xr, ye, Lr, Nr, Es, St, O, wi, Ar, Xt, ws, Ss, gs, Re, be, _e, ge, ro, Oe, no, oo, ho, Dr, qt, Se, Te, ao, lo, co, fo, uo, mo, po, Eo, vt, wo, So;
|
|
71
71
|
var init_index_min = __esm({
|
|
72
72
|
"../../node_modules/.pnpm/tar@7.5.13/node_modules/tar/dist/esm/index.min.js"() {
|
|
73
73
|
import_events = __toESM(require("events"), 1);
|
|
@@ -99,7 +99,7 @@ var init_index_min = __esm({
|
|
|
99
99
|
import_node_fs5 = __toESM(require("node:fs"), 1);
|
|
100
100
|
import_node_path9 = __toESM(require("node:path"), 1);
|
|
101
101
|
import_node_fs6 = __toESM(require("node:fs"), 1);
|
|
102
|
-
|
|
102
|
+
import_promises3 = __toESM(require("node:fs/promises"), 1);
|
|
103
103
|
import_node_path10 = __toESM(require("node:path"), 1);
|
|
104
104
|
import_node_path11 = require("node:path");
|
|
105
105
|
import_node_fs7 = __toESM(require("node:fs"), 1);
|
|
@@ -2258,7 +2258,7 @@ var init_index_min = __esm({
|
|
|
2258
2258
|
E ? e(E) : x && a ? ds(x, o, h, (xe) => S(xe)) : n ? import_node_fs6.default.chmod(s3, r, e) : e();
|
|
2259
2259
|
};
|
|
2260
2260
|
if (s3 === d) return Qn(s3, S);
|
|
2261
|
-
if (l) return
|
|
2261
|
+
if (l) return import_promises3.default.mkdir(s3, { mode: r, recursive: true }).then((E) => S(null, E ?? void 0), S);
|
|
2262
2262
|
let N = f(import_node_path10.default.relative(d, s3)).split("/");
|
|
2263
2263
|
ms(d, N, r, c, d, void 0, S);
|
|
2264
2264
|
};
|
|
@@ -2970,6 +2970,7 @@ var import_node_path = require("node:path");
|
|
|
2970
2970
|
var fs = __toESM(require("node:fs"), 1);
|
|
2971
2971
|
var fsPromises = __toESM(require("node:fs/promises"), 1);
|
|
2972
2972
|
var import_node_os = require("node:os");
|
|
2973
|
+
var import_promises = require("node:timers/promises");
|
|
2973
2974
|
var name1 = "read";
|
|
2974
2975
|
var name2 = "File";
|
|
2975
2976
|
function getFileContent(path, encoding = "utf-8") {
|
|
@@ -2984,6 +2985,43 @@ function getProcEnv() {
|
|
|
2984
2985
|
function getHomeDir() {
|
|
2985
2986
|
return getProcEnv().HOME || (0, import_node_os.homedir)();
|
|
2986
2987
|
}
|
|
2988
|
+
async function removeStaleFileLock(lockPath, staleAgeMs) {
|
|
2989
|
+
try {
|
|
2990
|
+
const s3 = await fsPromises.stat(lockPath);
|
|
2991
|
+
if (Date.now() - s3.mtimeMs < staleAgeMs) return;
|
|
2992
|
+
await fsPromises.rmdir(lockPath);
|
|
2993
|
+
} catch {
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
async function acquireFileLock(filePath, timeoutMs = 250, staleAgeMs = 3e4) {
|
|
2997
|
+
const lockPath = `${filePath}.lock`;
|
|
2998
|
+
const deadline = Date.now() + timeoutMs;
|
|
2999
|
+
while (true) {
|
|
3000
|
+
try {
|
|
3001
|
+
await fsPromises.mkdir(lockPath);
|
|
3002
|
+
return async () => {
|
|
3003
|
+
try {
|
|
3004
|
+
await fsPromises.rmdir(lockPath);
|
|
3005
|
+
} catch {
|
|
3006
|
+
}
|
|
3007
|
+
};
|
|
3008
|
+
} catch {
|
|
3009
|
+
await removeStaleFileLock(lockPath, staleAgeMs);
|
|
3010
|
+
const remainingMs = deadline - Date.now();
|
|
3011
|
+
if (remainingMs <= 0) return void 0;
|
|
3012
|
+
await (0, import_promises.setTimeout)(Math.min(50, remainingMs));
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
async function withFileLock(filePath, callback) {
|
|
3017
|
+
const release = await acquireFileLock(filePath);
|
|
3018
|
+
if (!release) return;
|
|
3019
|
+
try {
|
|
3020
|
+
return await callback();
|
|
3021
|
+
} finally {
|
|
3022
|
+
await release();
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
2987
3025
|
|
|
2988
3026
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
|
|
2989
3027
|
var external_exports = {};
|
|
@@ -7099,14 +7137,21 @@ var PackageCheckConfigSchema = external_exports.object({
|
|
|
7099
7137
|
var AmsiCheckConfigSchema = external_exports.object({
|
|
7100
7138
|
enabled: external_exports.boolean().default(true)
|
|
7101
7139
|
});
|
|
7102
|
-
var
|
|
7103
|
-
|
|
7140
|
+
var SkillCheckConfigSchema = external_exports.object({
|
|
7141
|
+
enabled: external_exports.boolean().default(true),
|
|
7142
|
+
cache_ttl_days: external_exports.number().min(0).default(1),
|
|
7143
|
+
/**
|
|
7144
|
+
* Upload unknown skills (never seen by the analyzer) for deep content
|
|
7145
|
+
* analysis. When false, the scan still looks skills up by content hash and
|
|
7146
|
+
* still flags known-risky ones — but no skill content ever leaves the
|
|
7147
|
+
* machine and the upload worker never runs (lookup-only mode).
|
|
7148
|
+
*/
|
|
7149
|
+
upload_enabled: external_exports.boolean().default(true)
|
|
7150
|
+
});
|
|
7104
7151
|
var PiCheckConfigSchema = external_exports.object({
|
|
7105
7152
|
enabled: external_exports.boolean().default(false),
|
|
7106
7153
|
max_content_length: external_exports.number().default(16384),
|
|
7107
|
-
model_path: external_exports.string().optional()
|
|
7108
|
-
high_risk_threshold: external_exports.number().default(DEFAULT_PI_HIGH_RISK_THRESHOLD),
|
|
7109
|
-
medium_risk_threshold: external_exports.number().default(DEFAULT_PI_MEDIUM_RISK_THRESHOLD)
|
|
7154
|
+
model_path: external_exports.string().optional()
|
|
7110
7155
|
});
|
|
7111
7156
|
var ExceptionDecisionSchema = external_exports.enum(["allow", "deny"]);
|
|
7112
7157
|
var ExceptionMatchSchema = external_exports.enum(["executable", "domain", "path", "plugin", "regex"]);
|
|
@@ -7128,6 +7173,7 @@ var ConfigSchema = external_exports.object({
|
|
|
7128
7173
|
file_check: FileCheckConfigSchema.default({}),
|
|
7129
7174
|
package_check: PackageCheckConfigSchema.default({}),
|
|
7130
7175
|
amsi_check: AmsiCheckConfigSchema.default({}),
|
|
7176
|
+
skill_check: SkillCheckConfigSchema.default({}),
|
|
7131
7177
|
pi_check: PiCheckConfigSchema.default({}),
|
|
7132
7178
|
heuristics_enabled: external_exports.boolean().default(true),
|
|
7133
7179
|
cache: CacheConfigSchema.default({}),
|
|
@@ -7136,6 +7182,7 @@ var ConfigSchema = external_exports.object({
|
|
|
7136
7182
|
operational_logging: OperationalLoggingConfigSchema.default({}),
|
|
7137
7183
|
sensitivity: SensitivitySchema.default("balanced"),
|
|
7138
7184
|
disabled_threats: external_exports.array(external_exports.string()).default([]),
|
|
7185
|
+
announce_clean_scans: external_exports.boolean().default(true),
|
|
7139
7186
|
brand_key: external_exports.string().min(1).max(32).regex(/^[a-z0-9_-]+$/u).optional(),
|
|
7140
7187
|
community_iq: external_exports.boolean().default(true)
|
|
7141
7188
|
});
|
|
@@ -7150,6 +7197,8 @@ var HookTypeSchema = external_exports.enum([
|
|
|
7150
7197
|
|
|
7151
7198
|
// ../core/src/config.ts
|
|
7152
7199
|
var SAGE_DIR = "~/.sage";
|
|
7200
|
+
var MS_PER_DAY = 24 * 60 * 60 * 1e3;
|
|
7201
|
+
var CLOCK_SKEW_TOLERANCE_MS = 5 * 60 * 1e3;
|
|
7153
7202
|
function resolvedSageDir() {
|
|
7154
7203
|
return resolvePath(SAGE_DIR);
|
|
7155
7204
|
}
|
|
@@ -7216,7 +7265,7 @@ function sanitizeBrandKey(data, logger) {
|
|
|
7216
7265
|
if (typeof brandKey === "string" && brandKey.length >= 1 && brandKey.length <= 32 && BRAND_KEY_RE.test(brandKey)) {
|
|
7217
7266
|
return data;
|
|
7218
7267
|
}
|
|
7219
|
-
logger.warn(`Invalid brand_key in config
|
|
7268
|
+
logger.warn(`Invalid brand_key in config - ignoring`, { brand_key: brandKey });
|
|
7220
7269
|
const { brand_key: _2, ...rest } = data;
|
|
7221
7270
|
return rest;
|
|
7222
7271
|
}
|
|
@@ -7284,7 +7333,7 @@ async function loadConfig(configPath, logger = nullLogger) {
|
|
|
7284
7333
|
|
|
7285
7334
|
// ../core/src/installation-id.ts
|
|
7286
7335
|
var import_node_crypto = require("node:crypto");
|
|
7287
|
-
var
|
|
7336
|
+
var import_promises2 = require("node:fs/promises");
|
|
7288
7337
|
var import_node_path2 = require("node:path");
|
|
7289
7338
|
async function getInstallationId(sageDirPath) {
|
|
7290
7339
|
const sageDir = sageDirPath ?? resolvePath("~/.sage");
|
|
@@ -7299,8 +7348,8 @@ async function getInstallationId(sageDirPath) {
|
|
|
7299
7348
|
}
|
|
7300
7349
|
try {
|
|
7301
7350
|
const id = (0, import_node_crypto.randomUUID)();
|
|
7302
|
-
await (0,
|
|
7303
|
-
await (0,
|
|
7351
|
+
await (0, import_promises2.mkdir)(sageDir, { recursive: true, mode: 448 });
|
|
7352
|
+
await (0, import_promises2.writeFile)(idPath, id, { encoding: "utf-8", mode: 384, flag: fileExists ? "w" : "wx" });
|
|
7304
7353
|
return id;
|
|
7305
7354
|
} catch (err) {
|
|
7306
7355
|
if (err.code === "EEXIST") {
|
|
@@ -7318,17 +7367,18 @@ async function getInstallationId(sageDirPath) {
|
|
|
7318
7367
|
// ../core/src/clients/model-downloader.ts
|
|
7319
7368
|
var import_node_crypto3 = require("node:crypto");
|
|
7320
7369
|
var import_node_fs8 = require("node:fs");
|
|
7321
|
-
var
|
|
7370
|
+
var import_promises4 = require("node:fs/promises");
|
|
7322
7371
|
var import_node_path13 = require("node:path");
|
|
7323
7372
|
var import_node_stream2 = require("node:stream");
|
|
7324
|
-
var
|
|
7373
|
+
var import_promises5 = require("node:stream/promises");
|
|
7325
7374
|
|
|
7326
7375
|
// ../core/src/model-storage.ts
|
|
7327
7376
|
var import_node_fs = require("node:fs");
|
|
7328
7377
|
var import_node_path3 = require("node:path");
|
|
7329
|
-
var MODEL_SCHEMA_VERSION = "
|
|
7378
|
+
var MODEL_SCHEMA_VERSION = "v2";
|
|
7330
7379
|
var REQUIRED_MODELS_BY_SCHEMA = {
|
|
7331
|
-
v1: ["pi-model"]
|
|
7380
|
+
v1: ["pi-model"],
|
|
7381
|
+
v2: ["pi-model"]
|
|
7332
7382
|
};
|
|
7333
7383
|
var REQUIRED_MODEL_FILES = {
|
|
7334
7384
|
"pi-model": [
|
|
@@ -7377,8 +7427,8 @@ async function downloadModel(opts) {
|
|
|
7377
7427
|
const stagingDir = getDownloadStagingDir(sageDir);
|
|
7378
7428
|
const lockPath = `${modelDir}.lock`;
|
|
7379
7429
|
try {
|
|
7380
|
-
await (0,
|
|
7381
|
-
await (0,
|
|
7430
|
+
await (0, import_promises4.mkdir)(stagingDir, { recursive: true });
|
|
7431
|
+
await (0, import_promises4.mkdir)((0, import_node_path13.resolve)(modelDir, ".."), { recursive: true });
|
|
7382
7432
|
} catch (err) {
|
|
7383
7433
|
logger.warn(`failed to prepare model storage for ${modelName}: ${err}`);
|
|
7384
7434
|
return false;
|
|
@@ -7404,7 +7454,7 @@ async function downloadModel(opts) {
|
|
|
7404
7454
|
});
|
|
7405
7455
|
return false;
|
|
7406
7456
|
}
|
|
7407
|
-
await (0,
|
|
7457
|
+
await (0, import_promises4.mkdir)(extractDir, { recursive: true });
|
|
7408
7458
|
await extractTarGz(archivePath, extractDir);
|
|
7409
7459
|
const extractDirResolved = extractDir;
|
|
7410
7460
|
const missing = requiredModelFiles(modelName).filter(
|
|
@@ -7417,26 +7467,26 @@ async function downloadModel(opts) {
|
|
|
7417
7467
|
const aside = `${modelDir}.${suffix}.old`;
|
|
7418
7468
|
let asideUsed = false;
|
|
7419
7469
|
if (await pathExists(modelDir)) {
|
|
7420
|
-
await (0,
|
|
7470
|
+
await (0, import_promises4.rename)(modelDir, aside);
|
|
7421
7471
|
asideUsed = true;
|
|
7422
7472
|
}
|
|
7423
7473
|
try {
|
|
7424
|
-
await (0,
|
|
7474
|
+
await (0, import_promises4.rename)(extractDir, modelDir);
|
|
7425
7475
|
extractDir = null;
|
|
7426
7476
|
} catch (err) {
|
|
7427
7477
|
if (asideUsed) {
|
|
7428
7478
|
try {
|
|
7429
|
-
await (0,
|
|
7479
|
+
await (0, import_promises4.rename)(aside, modelDir);
|
|
7430
7480
|
} catch {
|
|
7431
7481
|
}
|
|
7432
7482
|
}
|
|
7433
7483
|
throw err;
|
|
7434
7484
|
}
|
|
7435
7485
|
if (asideUsed) {
|
|
7436
|
-
await (0,
|
|
7486
|
+
await (0, import_promises4.rm)(aside, { recursive: true, force: true }).catch(() => {
|
|
7437
7487
|
});
|
|
7438
7488
|
}
|
|
7439
|
-
await (0,
|
|
7489
|
+
await (0, import_promises4.unlink)(archivePath).catch(() => {
|
|
7440
7490
|
});
|
|
7441
7491
|
archivePath = null;
|
|
7442
7492
|
logger.info(`model ${modelName} installed (schema ${schema})`);
|
|
@@ -7448,14 +7498,14 @@ async function downloadModel(opts) {
|
|
|
7448
7498
|
return false;
|
|
7449
7499
|
} finally {
|
|
7450
7500
|
if (extractDir) {
|
|
7451
|
-
await (0,
|
|
7501
|
+
await (0, import_promises4.rm)(extractDir, { recursive: true, force: true }).catch(() => {
|
|
7452
7502
|
});
|
|
7453
7503
|
}
|
|
7454
7504
|
if (archivePath) {
|
|
7455
|
-
await (0,
|
|
7505
|
+
await (0, import_promises4.unlink)(archivePath).catch(() => {
|
|
7456
7506
|
});
|
|
7457
7507
|
}
|
|
7458
|
-
await (0,
|
|
7508
|
+
await (0, import_promises4.unlink)(lockPath).catch(() => {
|
|
7459
7509
|
});
|
|
7460
7510
|
}
|
|
7461
7511
|
}
|
|
@@ -7468,11 +7518,11 @@ async function streamFetchToFile(url, destPath, fetchImpl = fetch) {
|
|
|
7468
7518
|
throw new Error(`empty response body from ${url}`);
|
|
7469
7519
|
}
|
|
7470
7520
|
const nodeStream = import_node_stream2.Readable.fromWeb(response.body);
|
|
7471
|
-
await (0,
|
|
7521
|
+
await (0, import_promises5.pipeline)(nodeStream, (0, import_node_fs8.createWriteStream)(destPath));
|
|
7472
7522
|
}
|
|
7473
7523
|
async function sha256OfFile(path) {
|
|
7474
7524
|
const hash = (0, import_node_crypto3.createHash)("sha256");
|
|
7475
|
-
const buf = await (0,
|
|
7525
|
+
const buf = await (0, import_promises4.readFile)(path);
|
|
7476
7526
|
hash.update(buf);
|
|
7477
7527
|
return hash.digest("hex");
|
|
7478
7528
|
}
|
|
@@ -7486,7 +7536,7 @@ async function extractTarGz(archivePath, destDir) {
|
|
|
7486
7536
|
}
|
|
7487
7537
|
async function pathExists(path) {
|
|
7488
7538
|
try {
|
|
7489
|
-
await (0,
|
|
7539
|
+
await (0, import_promises4.stat)(path);
|
|
7490
7540
|
return true;
|
|
7491
7541
|
} catch {
|
|
7492
7542
|
return false;
|
|
@@ -7503,7 +7553,7 @@ function fileExistsSync(path) {
|
|
|
7503
7553
|
async function tryAcquireLock(lockPath, logger) {
|
|
7504
7554
|
try {
|
|
7505
7555
|
const payload = JSON.stringify({ pid: process.pid, ts: Date.now() });
|
|
7506
|
-
await (0,
|
|
7556
|
+
await (0, import_promises4.writeFile)(lockPath, payload, { flag: "wx" });
|
|
7507
7557
|
return true;
|
|
7508
7558
|
} catch (err) {
|
|
7509
7559
|
const code = err.code;
|
|
@@ -7513,15 +7563,15 @@ async function tryAcquireLock(lockPath, logger) {
|
|
|
7513
7563
|
}
|
|
7514
7564
|
}
|
|
7515
7565
|
try {
|
|
7516
|
-
const raw = await (0,
|
|
7566
|
+
const raw = await (0, import_promises4.readFile)(lockPath, "utf-8");
|
|
7517
7567
|
const parsed = JSON.parse(raw);
|
|
7518
7568
|
const age = Date.now() - (parsed.ts ?? 0);
|
|
7519
7569
|
if (age > STALE_LOCK_MS) {
|
|
7520
|
-
await (0,
|
|
7570
|
+
await (0, import_promises4.unlink)(lockPath).catch(() => {
|
|
7521
7571
|
});
|
|
7522
7572
|
try {
|
|
7523
7573
|
const payload = JSON.stringify({ pid: process.pid, ts: Date.now() });
|
|
7524
|
-
await (0,
|
|
7574
|
+
await (0, import_promises4.writeFile)(lockPath, payload, { flag: "wx" });
|
|
7525
7575
|
return true;
|
|
7526
7576
|
} catch {
|
|
7527
7577
|
return false;
|
|
@@ -7533,7 +7583,7 @@ async function tryAcquireLock(lockPath, logger) {
|
|
|
7533
7583
|
}
|
|
7534
7584
|
|
|
7535
7585
|
// ../core/src/sage-proxy.ts
|
|
7536
|
-
function
|
|
7586
|
+
function mapSageHostOs(platform) {
|
|
7537
7587
|
switch (platform) {
|
|
7538
7588
|
case "win32":
|
|
7539
7589
|
return "WINDOWS";
|
|
@@ -7545,21 +7595,37 @@ function mapSageProxyOs(platform) {
|
|
|
7545
7595
|
return platform;
|
|
7546
7596
|
}
|
|
7547
7597
|
}
|
|
7548
|
-
function
|
|
7598
|
+
function mapSageHostArchitecture(arch) {
|
|
7549
7599
|
return arch.toUpperCase();
|
|
7550
7600
|
}
|
|
7601
|
+
function buildSageUserConfig(config) {
|
|
7602
|
+
return {
|
|
7603
|
+
sensitivity: config.sensitivity,
|
|
7604
|
+
url_check_enabled: config.url_check.enabled,
|
|
7605
|
+
file_check_enabled: config.file_check.enabled,
|
|
7606
|
+
package_check_enabled: config.package_check.enabled,
|
|
7607
|
+
heuristics_enabled: config.heuristics_enabled,
|
|
7608
|
+
pi_check_enabled: config.pi_check.enabled,
|
|
7609
|
+
community_iq_enabled: config.community_iq,
|
|
7610
|
+
// Optional-chained + defaulted: real callers pass a loadConfig result (skill_check
|
|
7611
|
+
// always present via the schema default), but this feeds fail-open telemetry, so a
|
|
7612
|
+
// partial config must never crash the envelope build.
|
|
7613
|
+
skill_check_upload_enabled: config.skill_check?.upload_enabled ?? true
|
|
7614
|
+
};
|
|
7615
|
+
}
|
|
7551
7616
|
function buildSageProxyEnvelope(args) {
|
|
7552
7617
|
return {
|
|
7553
7618
|
identity: { uuid: args.iid },
|
|
7554
7619
|
product: { version_app: args.versionApp },
|
|
7555
7620
|
platform: {
|
|
7556
|
-
os: args.platformOs ??
|
|
7557
|
-
architecture: args.platformArchitecture ??
|
|
7621
|
+
os: args.platformOs ?? mapSageHostOs(process.platform),
|
|
7622
|
+
architecture: args.platformArchitecture ?? mapSageHostArchitecture(process.arch)
|
|
7558
7623
|
},
|
|
7559
7624
|
agent: {
|
|
7560
7625
|
agent_runtime: args.agentRuntime,
|
|
7561
7626
|
agent_runtime_version: args.agentRuntimeVersion
|
|
7562
|
-
}
|
|
7627
|
+
},
|
|
7628
|
+
...args.config ? { config: buildSageUserConfig(args.config) } : {}
|
|
7563
7629
|
};
|
|
7564
7630
|
}
|
|
7565
7631
|
|
|
@@ -7568,7 +7634,7 @@ var import_node_path14 = require("node:path");
|
|
|
7568
7634
|
var import_node_url = require("node:url");
|
|
7569
7635
|
var import_meta = {};
|
|
7570
7636
|
function resolveVersion() {
|
|
7571
|
-
if (true) return "0.
|
|
7637
|
+
if (true) return "0.12.0";
|
|
7572
7638
|
try {
|
|
7573
7639
|
const pkgPath = (0, import_node_path14.join)((0, import_node_path14.dirname)((0, import_node_url.fileURLToPath)(import_meta.url)), "..", "package.json");
|
|
7574
7640
|
const pkg = JSON.parse(getFileContentSync(pkgPath));
|
|
@@ -7607,14 +7673,23 @@ async function fetchModelManifest(args) {
|
|
|
7607
7673
|
logger.debug("Skipping model manifest fetch: missing installation id");
|
|
7608
7674
|
return null;
|
|
7609
7675
|
}
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7676
|
+
let config = args.config;
|
|
7677
|
+
if (!config) {
|
|
7678
|
+
try {
|
|
7679
|
+
config = await loadConfig(args.configPath, logger);
|
|
7680
|
+
} catch (err) {
|
|
7681
|
+
logger.debug(`Model manifest config load failed: ${err}`);
|
|
7682
|
+
}
|
|
7683
|
+
}
|
|
7617
7684
|
try {
|
|
7685
|
+
const envelope = buildSageProxyEnvelope({
|
|
7686
|
+
iid: args.iid,
|
|
7687
|
+
versionApp: args.versionApp ?? VERSION,
|
|
7688
|
+
agentRuntime: args.agentRuntime,
|
|
7689
|
+
agentRuntimeVersion: args.agentRuntimeVersion ?? "unknown",
|
|
7690
|
+
config
|
|
7691
|
+
});
|
|
7692
|
+
const body = { ...envelope, models: { schema: args.schema } };
|
|
7618
7693
|
const response = await fetch(resolveEndpoint("/v2/model-manifest"), {
|
|
7619
7694
|
method: "POST",
|
|
7620
7695
|
signal: AbortSignal.timeout(timeoutMs),
|
|
@@ -7691,6 +7766,8 @@ async function ensureModelsAvailable(args) {
|
|
|
7691
7766
|
schema,
|
|
7692
7767
|
agentRuntime: args.agentRuntime ?? "unknown",
|
|
7693
7768
|
agentRuntimeVersion: args.agentRuntimeVersion,
|
|
7769
|
+
config: args.config,
|
|
7770
|
+
configPath: args.configPath,
|
|
7694
7771
|
versionApp: args.versionApp,
|
|
7695
7772
|
logger
|
|
7696
7773
|
});
|
|
@@ -7736,78 +7813,42 @@ async function ensureModelsAvailable(args) {
|
|
|
7736
7813
|
}
|
|
7737
7814
|
|
|
7738
7815
|
// ../core/src/jsonl-log-writer.ts
|
|
7739
|
-
var
|
|
7816
|
+
var import_promises6 = require("node:fs/promises");
|
|
7740
7817
|
var import_node_path15 = require("node:path");
|
|
7741
|
-
var import_promises6 = require("node:timers/promises");
|
|
7742
7818
|
var writeQueues = /* @__PURE__ */ new Map();
|
|
7743
|
-
var ROTATE_LOCK_TIMEOUT_MS = 250;
|
|
7744
|
-
var ROTATE_LOCK_STALE_MS = 3e4;
|
|
7745
|
-
var ROTATE_LOCK_POLL_MS = 50;
|
|
7746
7819
|
async function shouldRotate(filePath, maxBytes, maxFiles) {
|
|
7747
7820
|
if (maxBytes <= 0 || maxFiles <= 0) return false;
|
|
7748
7821
|
try {
|
|
7749
|
-
const s3 = await (0,
|
|
7822
|
+
const s3 = await (0, import_promises6.stat)(filePath);
|
|
7750
7823
|
return s3.size >= maxBytes;
|
|
7751
7824
|
} catch {
|
|
7752
7825
|
return false;
|
|
7753
7826
|
}
|
|
7754
7827
|
}
|
|
7755
|
-
async function removeStaleRotateLock(lockPath) {
|
|
7756
|
-
try {
|
|
7757
|
-
const s3 = await (0, import_promises5.stat)(lockPath);
|
|
7758
|
-
if (Date.now() - s3.mtimeMs < ROTATE_LOCK_STALE_MS) return;
|
|
7759
|
-
await (0, import_promises5.rmdir)(lockPath);
|
|
7760
|
-
} catch {
|
|
7761
|
-
}
|
|
7762
|
-
}
|
|
7763
|
-
async function acquireRotateLock(filePath) {
|
|
7764
|
-
const lockPath = `${filePath}.lock`;
|
|
7765
|
-
const deadline = Date.now() + ROTATE_LOCK_TIMEOUT_MS;
|
|
7766
|
-
while (true) {
|
|
7767
|
-
try {
|
|
7768
|
-
await (0, import_promises5.mkdir)(lockPath);
|
|
7769
|
-
return async () => {
|
|
7770
|
-
try {
|
|
7771
|
-
await (0, import_promises5.rmdir)(lockPath);
|
|
7772
|
-
} catch {
|
|
7773
|
-
}
|
|
7774
|
-
};
|
|
7775
|
-
} catch {
|
|
7776
|
-
await removeStaleRotateLock(lockPath);
|
|
7777
|
-
const remainingMs = deadline - Date.now();
|
|
7778
|
-
if (remainingMs <= 0) return void 0;
|
|
7779
|
-
await (0, import_promises6.setTimeout)(Math.min(ROTATE_LOCK_POLL_MS, remainingMs));
|
|
7780
|
-
}
|
|
7781
|
-
}
|
|
7782
|
-
}
|
|
7783
7828
|
async function rotateIfNeeded(filePath, maxBytes, maxFiles) {
|
|
7784
7829
|
if (!await shouldRotate(filePath, maxBytes, maxFiles)) return;
|
|
7785
|
-
|
|
7786
|
-
if (!releaseLock) return;
|
|
7787
|
-
try {
|
|
7830
|
+
await withFileLock(filePath, async () => {
|
|
7788
7831
|
if (!await shouldRotate(filePath, maxBytes, maxFiles)) return;
|
|
7789
7832
|
try {
|
|
7790
|
-
await (0,
|
|
7833
|
+
await (0, import_promises6.unlink)(`${filePath}.${maxFiles}`);
|
|
7791
7834
|
} catch {
|
|
7792
7835
|
}
|
|
7793
7836
|
for (let i = maxFiles - 1; i >= 1; i--) {
|
|
7794
7837
|
try {
|
|
7795
|
-
await (0,
|
|
7838
|
+
await (0, import_promises6.rename)(`${filePath}.${i}`, `${filePath}.${i + 1}`);
|
|
7796
7839
|
} catch {
|
|
7797
7840
|
}
|
|
7798
7841
|
}
|
|
7799
7842
|
try {
|
|
7800
|
-
await (0,
|
|
7843
|
+
await (0, import_promises6.rename)(filePath, `${filePath}.1`);
|
|
7801
7844
|
} catch {
|
|
7802
7845
|
}
|
|
7803
|
-
}
|
|
7804
|
-
await releaseLock();
|
|
7805
|
-
}
|
|
7846
|
+
});
|
|
7806
7847
|
}
|
|
7807
7848
|
async function appendJsonlEntryNow(path, config, entry) {
|
|
7808
|
-
await (0,
|
|
7849
|
+
await (0, import_promises6.mkdir)((0, import_node_path15.dirname)(path), { recursive: true });
|
|
7809
7850
|
await rotateIfNeeded(path, config.max_bytes, config.max_files);
|
|
7810
|
-
await (0,
|
|
7851
|
+
await (0, import_promises6.appendFile)(path, `${JSON.stringify(entry)}
|
|
7811
7852
|
`);
|
|
7812
7853
|
}
|
|
7813
7854
|
async function appendJsonlEntry(config, entry) {
|
|
@@ -7937,11 +7978,12 @@ function createOperationalLogger(config, runtime) {
|
|
|
7937
7978
|
async function readWorkerArgs() {
|
|
7938
7979
|
const env = process.env;
|
|
7939
7980
|
const sageDir = env.SAGE_DIR ? resolvePath(env.SAGE_DIR) : resolvePath("~/.sage");
|
|
7981
|
+
const configPath = env.SAGE_CONFIG_PATH ? resolvePath(env.SAGE_CONFIG_PATH) : void 0;
|
|
7940
7982
|
const agentRuntime = env.SAGE_AGENT_RUNTIME ?? "unknown";
|
|
7941
7983
|
const agentRuntimeVersion = env.SAGE_AGENT_RUNTIME_VERSION || void 0;
|
|
7942
7984
|
const versionApp = env.SAGE_VERSION_APP || void 0;
|
|
7943
7985
|
const schema = env.SAGE_MODEL_SCHEMA || MODEL_SCHEMA_VERSION;
|
|
7944
|
-
return { sageDir, agentRuntime, agentRuntimeVersion, versionApp, schema };
|
|
7986
|
+
return { sageDir, configPath, agentRuntime, agentRuntimeVersion, versionApp, schema };
|
|
7945
7987
|
}
|
|
7946
7988
|
async function createWorkerLogger(agentRuntime) {
|
|
7947
7989
|
try {
|
|
@@ -7981,6 +8023,7 @@ async function workerMain() {
|
|
|
7981
8023
|
iid,
|
|
7982
8024
|
agentRuntime: args.agentRuntime,
|
|
7983
8025
|
agentRuntimeVersion: args.agentRuntimeVersion,
|
|
8026
|
+
configPath: args.configPath,
|
|
7984
8027
|
versionApp: args.versionApp,
|
|
7985
8028
|
schema: args.schema,
|
|
7986
8029
|
logger
|