@kenhkl/agent-moss 0.16.14 → 0.17.1
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/cli.js +1124 -343
- package/dist/engine/coordinator.js +333 -158
- package/dist/rules/l1_rules.json +51 -2
- package/dist/rules/l2_rules.json +2 -1
- package/dist/server.js +1083 -302
- package/dist/static/index.html +12 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
5
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
6
|
+
}) : x)(function(x) {
|
|
7
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
8
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
9
|
+
});
|
|
4
10
|
var __esm = (fn, res) => function __init() {
|
|
5
11
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
12
|
};
|
|
@@ -26,6 +32,10 @@ var init_esm_shims = __esm({
|
|
|
26
32
|
import { join } from "path";
|
|
27
33
|
import { homedir } from "os";
|
|
28
34
|
import { readFileSync } from "fs";
|
|
35
|
+
function isSafeId(value) {
|
|
36
|
+
if (!value || value.length > ID_MAX_LEN) return false;
|
|
37
|
+
return ID_PATTERN.test(value);
|
|
38
|
+
}
|
|
29
39
|
function getRulesRoot() {
|
|
30
40
|
const raw = (process.env[ENV_RULES_ROOT] ?? "").trim();
|
|
31
41
|
return raw ? raw : null;
|
|
@@ -99,7 +109,7 @@ function getTokenStatsPath() {
|
|
|
99
109
|
}
|
|
100
110
|
return join(getDataRoot(), "agent_moss_token_stats.json");
|
|
101
111
|
}
|
|
102
|
-
var ENV_DATA_ROOT, ENV_INSTANCE, DEFAULT_DATA_ROOT, ENV_RULES_ROOT;
|
|
112
|
+
var ENV_DATA_ROOT, ENV_INSTANCE, DEFAULT_DATA_ROOT, ENV_RULES_ROOT, ID_MAX_LEN, ID_PATTERN;
|
|
103
113
|
var init_paths = __esm({
|
|
104
114
|
"src/infra/paths.ts"() {
|
|
105
115
|
"use strict";
|
|
@@ -108,6 +118,8 @@ var init_paths = __esm({
|
|
|
108
118
|
ENV_INSTANCE = "AGENT_MOSS_INSTANCE";
|
|
109
119
|
DEFAULT_DATA_ROOT = join(homedir(), ".config", "agentmoss");
|
|
110
120
|
ENV_RULES_ROOT = "AGENT_MOSS_RULES_ROOT";
|
|
121
|
+
ID_MAX_LEN = 64;
|
|
122
|
+
ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]*$/;
|
|
111
123
|
}
|
|
112
124
|
});
|
|
113
125
|
|
|
@@ -185,7 +197,7 @@ function parseDirEnv(envName) {
|
|
|
185
197
|
function rulesDirs() {
|
|
186
198
|
if (isBuiltinOnly()) return [];
|
|
187
199
|
const dirs = [];
|
|
188
|
-
for (const
|
|
200
|
+
for (const env2 of RULES_DIR_ENVS) dirs.push(...parseDirEnv(env2));
|
|
189
201
|
dirs.push(resolve(dataRootDir(), "rules"));
|
|
190
202
|
return [...new Set(dirs)];
|
|
191
203
|
}
|
|
@@ -233,6 +245,7 @@ function loadJson(name) {
|
|
|
233
245
|
}
|
|
234
246
|
}
|
|
235
247
|
function resolveScenarioRulesFile(scenarioId) {
|
|
248
|
+
if (!isSafeId(scenarioId)) return null;
|
|
236
249
|
const rel = join2("scenarios", scenarioId, "rules.json");
|
|
237
250
|
for (const dir of rulesDirs()) {
|
|
238
251
|
const p = resolve(dir, rel);
|
|
@@ -870,6 +883,491 @@ var init_rules_contract = __esm({
|
|
|
870
883
|
}
|
|
871
884
|
});
|
|
872
885
|
|
|
886
|
+
// src/infra/security-policy.ts
|
|
887
|
+
import { createHash as createHash2, randomBytes, timingSafeEqual } from "crypto";
|
|
888
|
+
import { chmodSync, closeSync, existsSync as existsSync3, lstatSync, mkdirSync, openSync, readFileSync as readFileSync4, readSync, realpathSync, writeSync } from "fs";
|
|
889
|
+
import { homedir as homedir2, tmpdir } from "os";
|
|
890
|
+
import { basename, isAbsolute, join as join4, relative, resolve as resolve2, dirname as dirname2 } from "path";
|
|
891
|
+
function env(name, dflt = "") {
|
|
892
|
+
return (process.env[name] ?? dflt).trim();
|
|
893
|
+
}
|
|
894
|
+
function envInt(name, dflt) {
|
|
895
|
+
const raw = env(name);
|
|
896
|
+
if (!raw) return dflt;
|
|
897
|
+
const n = Number.parseInt(raw, 10);
|
|
898
|
+
return Number.isFinite(n) ? n : dflt;
|
|
899
|
+
}
|
|
900
|
+
function splitList(raw) {
|
|
901
|
+
return raw.replace(/;/g, ",").split(",").map((x) => x.trim()).filter(Boolean);
|
|
902
|
+
}
|
|
903
|
+
function originCheckEnabled() {
|
|
904
|
+
return TRUTHY2.includes(env("AGENT_MOSS_ORIGIN_CHECK", "1").toLowerCase());
|
|
905
|
+
}
|
|
906
|
+
function allowedOrigins() {
|
|
907
|
+
return splitList(env("AGENT_MOSS_CORS_ORIGINS"));
|
|
908
|
+
}
|
|
909
|
+
function normOrigin(o) {
|
|
910
|
+
return (o || "").trim().replace(/\/+$/, "");
|
|
911
|
+
}
|
|
912
|
+
function originAllowed(origin, hostHeader, extra) {
|
|
913
|
+
const o = normOrigin(origin);
|
|
914
|
+
if (!o) return true;
|
|
915
|
+
const entries = (extra ?? allowedOrigins()).map(normOrigin);
|
|
916
|
+
if (entries.includes(o)) return true;
|
|
917
|
+
const host = (hostHeader || "").trim();
|
|
918
|
+
if (!host) return false;
|
|
919
|
+
try {
|
|
920
|
+
const u = new URL(o);
|
|
921
|
+
return u.host === host;
|
|
922
|
+
} catch {
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
function authMode() {
|
|
927
|
+
return (env("AGENT_MOSS_AUTH_MODE", AUTH_MODE_AUTO) || AUTH_MODE_AUTO).toLowerCase();
|
|
928
|
+
}
|
|
929
|
+
function autoTokenPath() {
|
|
930
|
+
let root;
|
|
931
|
+
try {
|
|
932
|
+
root = getDataRoot();
|
|
933
|
+
} catch {
|
|
934
|
+
root = join4(homedir2(), ".config", "agentmoss");
|
|
935
|
+
}
|
|
936
|
+
return join4(root, "auth_token");
|
|
937
|
+
}
|
|
938
|
+
function readFdToken() {
|
|
939
|
+
const raw = env("AGENT_MOSS_AUTH_TOKEN_FD");
|
|
940
|
+
if (!raw) return "";
|
|
941
|
+
const fd = Number.parseInt(raw, 10);
|
|
942
|
+
if (!Number.isFinite(fd)) return "";
|
|
943
|
+
if (fdTokenCache.has(fd)) return fdTokenCache.get(fd);
|
|
944
|
+
const buf = Buffer.alloc(8192);
|
|
945
|
+
let n = 0;
|
|
946
|
+
try {
|
|
947
|
+
n = readSync(fd, buf, 0, buf.length, null);
|
|
948
|
+
} catch (e) {
|
|
949
|
+
console.error(`[AgentMoss] \u4ECE fd ${fd} \u8BFB\u53D6\u8BBF\u95EE token \u5931\u8D25:`, e);
|
|
950
|
+
}
|
|
951
|
+
try {
|
|
952
|
+
closeSync(fd);
|
|
953
|
+
} catch {
|
|
954
|
+
}
|
|
955
|
+
const tok = n > 0 ? buf.subarray(0, n).toString("utf-8").trim() : "";
|
|
956
|
+
fdTokenCache.set(fd, tok);
|
|
957
|
+
return tok;
|
|
958
|
+
}
|
|
959
|
+
function readExplicitToken() {
|
|
960
|
+
const tok = env("AGENT_MOSS_AUTH_TOKEN");
|
|
961
|
+
if (tok) return tok;
|
|
962
|
+
const fdTok = readFdToken();
|
|
963
|
+
if (fdTok) return fdTok;
|
|
964
|
+
const path6 = env("AGENT_MOSS_AUTH_TOKEN_FILE");
|
|
965
|
+
if (path6) {
|
|
966
|
+
try {
|
|
967
|
+
return readFileSync4(path6, "utf-8").trim();
|
|
968
|
+
} catch {
|
|
969
|
+
return "";
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
return "";
|
|
973
|
+
}
|
|
974
|
+
function ensureAutoToken() {
|
|
975
|
+
const path6 = autoTokenPath();
|
|
976
|
+
try {
|
|
977
|
+
if (existsSync3(path6) && !lstatSync(path6).isSymbolicLink()) {
|
|
978
|
+
const tok2 = readFileSync4(path6, "utf-8").trim();
|
|
979
|
+
if (tok2) {
|
|
980
|
+
try {
|
|
981
|
+
chmodSync(path6, 384);
|
|
982
|
+
} catch {
|
|
983
|
+
}
|
|
984
|
+
return tok2;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
const tok = randomBytes(32).toString("base64url");
|
|
988
|
+
ensurePrivateDir(dirname2(path6));
|
|
989
|
+
if (!writePrivateText(path6, tok + "\n")) return "";
|
|
990
|
+
console.warn(
|
|
991
|
+
`[AgentMoss] \u5DF2\u751F\u6210\u8BBF\u95EE token \u5E76\u5199\u5165 ${path6}\uFF080600\uFF09\u3002\u5BA2\u6237\u7AEF\u9700\u5E26 \`Authorization: Bearer <token>\`\uFF1B\u67E5\u770B\uFF1Acat ${path6}\uFF1B\u5982\u9700\u5173\u95ED\u9274\u6743\uFF1AAGENT_MOSS_AUTH_MODE=off`
|
|
992
|
+
);
|
|
993
|
+
return tok;
|
|
994
|
+
} catch (e) {
|
|
995
|
+
console.error("[AgentMoss] \u751F\u6210\u8BBF\u95EE token \u5931\u8D25\uFF08\u672C\u6B21\u8FD0\u884C\u5C06\u4E0D\u9274\u6743\uFF09:", e);
|
|
996
|
+
return "";
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
function parseAgentTokens(raw) {
|
|
1000
|
+
const out = {};
|
|
1001
|
+
for (const pair of splitList(raw)) {
|
|
1002
|
+
const i = pair.indexOf("=");
|
|
1003
|
+
if (i > 0) {
|
|
1004
|
+
const a = pair.slice(0, i).trim();
|
|
1005
|
+
const t = pair.slice(i + 1).trim();
|
|
1006
|
+
if (a && t) out[a] = t;
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
return out;
|
|
1010
|
+
}
|
|
1011
|
+
function resolveAuth() {
|
|
1012
|
+
const rawAgents = env("AGENT_MOSS_AGENT_TOKENS");
|
|
1013
|
+
const key = [
|
|
1014
|
+
authMode(),
|
|
1015
|
+
env("AGENT_MOSS_AUTH_TOKEN"),
|
|
1016
|
+
env("AGENT_MOSS_AUTH_TOKEN_FILE"),
|
|
1017
|
+
env("AGENT_MOSS_AUTH_TOKEN_FD"),
|
|
1018
|
+
rawAgents,
|
|
1019
|
+
env("AGENT_MOSS_DATA_DIR")
|
|
1020
|
+
].join("\0");
|
|
1021
|
+
if (tokenCache && tokenCache.key === key) {
|
|
1022
|
+
return [tokenCache.token, tokenCache.agents, tokenCache.error];
|
|
1023
|
+
}
|
|
1024
|
+
let error = "";
|
|
1025
|
+
let token = readExplicitToken();
|
|
1026
|
+
if (!token && env("AGENT_MOSS_AUTH_TOKEN_FD") && authMode() !== AUTH_MODE_OFF) {
|
|
1027
|
+
error = "AGENT_MOSS_AUTH_TOKEN_FD \u5DF2\u8BBE\u7F6E\uFF0C\u4F46\u6CA1\u80FD\u4ECE\u8BE5\u6587\u4EF6\u63CF\u8FF0\u7B26\u8BFB\u5230 token\u3002\u62D2\u7EDD\u964D\u7EA7\u5230\u78C1\u76D8 token\uFF08\u90A3\u4F1A\u5728\u672C\u673A\u7559\u4E0B\u4E00\u4EFD\u540C\u7528\u6237\u53EF\u8BFB\u7684\u51ED\u8BC1\uFF09\u3002";
|
|
1028
|
+
console.error(`[agent-moss] ${error}`);
|
|
1029
|
+
}
|
|
1030
|
+
if (!token && !error && authMode() !== AUTH_MODE_OFF) token = ensureAutoToken();
|
|
1031
|
+
const agents = parseAgentTokens(rawAgents);
|
|
1032
|
+
tokenCache = { key, token, agents, error };
|
|
1033
|
+
return [token, agents, error];
|
|
1034
|
+
}
|
|
1035
|
+
function agentTokens() {
|
|
1036
|
+
return resolveAuth()[1];
|
|
1037
|
+
}
|
|
1038
|
+
function authConfigError() {
|
|
1039
|
+
return resolveAuth()[2];
|
|
1040
|
+
}
|
|
1041
|
+
function failFastOnAuthError() {
|
|
1042
|
+
const err = authConfigError();
|
|
1043
|
+
if (err) {
|
|
1044
|
+
console.error(`[agent-moss] \u9274\u6743\u914D\u7F6E\u9519\u8BEF\uFF0C\u62D2\u7EDD\u542F\u52A8: ${err}`);
|
|
1045
|
+
process.exit(1);
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
function authEnabled() {
|
|
1049
|
+
if (authMode() === AUTH_MODE_OFF) return false;
|
|
1050
|
+
const [tok, agents] = resolveAuth();
|
|
1051
|
+
return Boolean(tok) || Object.keys(agents).length > 0;
|
|
1052
|
+
}
|
|
1053
|
+
function bearer(headers) {
|
|
1054
|
+
const get = (k) => headers instanceof Headers ? headers.get(k) ?? "" : headers[k] ?? "";
|
|
1055
|
+
const v = get("authorization") || get("Authorization");
|
|
1056
|
+
return v.toLowerCase().startsWith("bearer ") ? v.slice(7).trim() : "";
|
|
1057
|
+
}
|
|
1058
|
+
function constEq(a, b) {
|
|
1059
|
+
const ba = Buffer.from(a, "utf-8");
|
|
1060
|
+
const bb = Buffer.from(b, "utf-8");
|
|
1061
|
+
if (ba.length !== bb.length) return false;
|
|
1062
|
+
return timingSafeEqual(ba, bb);
|
|
1063
|
+
}
|
|
1064
|
+
function checkRequestAuth(headers, path6) {
|
|
1065
|
+
if (authMode() === AUTH_MODE_OFF) return [true, ""];
|
|
1066
|
+
const isHealth = HEALTH_PATHS.includes(path6.replace(/\/+$/, ""));
|
|
1067
|
+
const [gt0, agents, err] = resolveAuth();
|
|
1068
|
+
if (err) return isHealth ? [true, ""] : [false, ""];
|
|
1069
|
+
if (!gt0 && Object.keys(agents).length === 0) return [true, ""];
|
|
1070
|
+
if (isHealth) return [true, ""];
|
|
1071
|
+
const tok = bearer(headers);
|
|
1072
|
+
if (!tok) return [false, ""];
|
|
1073
|
+
if (path6.startsWith("/console/api")) {
|
|
1074
|
+
const consoleTok = env("AGENT_MOSS_CONSOLE_TOKEN");
|
|
1075
|
+
if (consoleTok && constEq(tok, consoleTok)) return [true, "console"];
|
|
1076
|
+
}
|
|
1077
|
+
const gt = gt0;
|
|
1078
|
+
if (gt && constEq(tok, gt)) return [true, "global"];
|
|
1079
|
+
for (const [agent, expected] of Object.entries(agents)) {
|
|
1080
|
+
if (constEq(tok, expected)) return [true, `agent:${agent}`];
|
|
1081
|
+
}
|
|
1082
|
+
return [false, ""];
|
|
1083
|
+
}
|
|
1084
|
+
function bindAgent(principal, agentId) {
|
|
1085
|
+
const tokens = agentTokens();
|
|
1086
|
+
if (Object.keys(tokens).length === 0) return [true, agentId];
|
|
1087
|
+
if (!principal.startsWith("agent:")) return [true, agentId];
|
|
1088
|
+
const bound = principal.slice(6);
|
|
1089
|
+
if (!agentId) return [true, bound];
|
|
1090
|
+
return [bound === agentId, bound];
|
|
1091
|
+
}
|
|
1092
|
+
function principalOf(headers, path6 = "") {
|
|
1093
|
+
const [ok, principal] = checkRequestAuth(headers, path6);
|
|
1094
|
+
return ok ? principal : "";
|
|
1095
|
+
}
|
|
1096
|
+
function principalHash(principal) {
|
|
1097
|
+
if (!principal) return "";
|
|
1098
|
+
return createHash2("sha256").update(principal, "utf-8").digest("hex").slice(0, 12);
|
|
1099
|
+
}
|
|
1100
|
+
function homeDir() {
|
|
1101
|
+
try {
|
|
1102
|
+
return homedir2();
|
|
1103
|
+
} catch {
|
|
1104
|
+
return tmpdir();
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
function logRoots() {
|
|
1108
|
+
const raw = env("AGENT_MOSS_LOG_ROOTS");
|
|
1109
|
+
if (raw) return splitList(raw);
|
|
1110
|
+
return [.../* @__PURE__ */ new Set([homeDir(), "/tmp", tmpdir()])];
|
|
1111
|
+
}
|
|
1112
|
+
function reviewRoots() {
|
|
1113
|
+
const roots = [join4(homeDir(), ".local", "share", "agent_gate")];
|
|
1114
|
+
for (const name of ["AGENT_GATE_DB", "AGENT_GATE_JSON_PATH"]) {
|
|
1115
|
+
const v = env(name);
|
|
1116
|
+
if (v) roots.push(existsSync3(v) && lstatSync(v).isDirectory() ? v : dirname2(v));
|
|
1117
|
+
}
|
|
1118
|
+
roots.push(...splitList(env("AGENT_MOSS_REVIEW_PATHS")));
|
|
1119
|
+
return [...new Set(roots)];
|
|
1120
|
+
}
|
|
1121
|
+
function realpathLoose(p) {
|
|
1122
|
+
const abs = resolve2(p.replace(/^~(?=$|\/)/, homeDir()));
|
|
1123
|
+
try {
|
|
1124
|
+
return realpathSync(abs);
|
|
1125
|
+
} catch {
|
|
1126
|
+
}
|
|
1127
|
+
const parts = [];
|
|
1128
|
+
let cur = abs;
|
|
1129
|
+
for (; ; ) {
|
|
1130
|
+
const parent = dirname2(cur);
|
|
1131
|
+
if (parent === cur) return null;
|
|
1132
|
+
parts.unshift(basename(cur));
|
|
1133
|
+
cur = parent;
|
|
1134
|
+
try {
|
|
1135
|
+
return join4(realpathSync(cur), ...parts);
|
|
1136
|
+
} catch {
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
function pathWithin(p, roots) {
|
|
1141
|
+
if (!p) return true;
|
|
1142
|
+
const target = realpathLoose(p);
|
|
1143
|
+
if (target === null) return false;
|
|
1144
|
+
for (const root of roots) {
|
|
1145
|
+
const rootReal = realpathLoose(root);
|
|
1146
|
+
if (rootReal === null) continue;
|
|
1147
|
+
const rel = relative(rootReal, target);
|
|
1148
|
+
if (rel === "" || !rel.startsWith("..") && !isAbsolute(rel)) return true;
|
|
1149
|
+
}
|
|
1150
|
+
return false;
|
|
1151
|
+
}
|
|
1152
|
+
function ensurePrivateDir(dir) {
|
|
1153
|
+
try {
|
|
1154
|
+
mkdirSync(dir, { recursive: true });
|
|
1155
|
+
if (lstatSync(dir).isSymbolicLink()) return false;
|
|
1156
|
+
if (typeof process.getuid === "function" && lstatSync(dir).uid !== process.getuid()) return false;
|
|
1157
|
+
chmodSync(dir, 448);
|
|
1158
|
+
return true;
|
|
1159
|
+
} catch {
|
|
1160
|
+
return false;
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
function writePrivateText(file, text) {
|
|
1164
|
+
try {
|
|
1165
|
+
const flags = __require("fs").constants;
|
|
1166
|
+
let openFlags = flags.O_WRONLY | flags.O_CREAT | flags.O_TRUNC;
|
|
1167
|
+
if (flags.O_NOFOLLOW) openFlags |= flags.O_NOFOLLOW;
|
|
1168
|
+
const fd = openSync(file, openFlags, 384);
|
|
1169
|
+
try {
|
|
1170
|
+
writeSync(fd, text);
|
|
1171
|
+
} finally {
|
|
1172
|
+
closeSync(fd);
|
|
1173
|
+
}
|
|
1174
|
+
return true;
|
|
1175
|
+
} catch {
|
|
1176
|
+
return false;
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
function perRequestLlmEnabled() {
|
|
1180
|
+
return TRUTHY2.includes(env("AGENT_MOSS_ALLOW_PER_REQUEST_LLM", "1").toLowerCase());
|
|
1181
|
+
}
|
|
1182
|
+
function validateLlmBaseUrl(url, allowPrivate) {
|
|
1183
|
+
if (!url) return [true, ""];
|
|
1184
|
+
let u;
|
|
1185
|
+
try {
|
|
1186
|
+
u = new URL(url);
|
|
1187
|
+
} catch {
|
|
1188
|
+
return [false, "baseUrl \u4E0D\u662F\u5408\u6CD5 URL"];
|
|
1189
|
+
}
|
|
1190
|
+
if (u.protocol !== "http:" && u.protocol !== "https:") {
|
|
1191
|
+
return [false, `baseUrl \u534F\u8BAE\u4E0D\u53D7\u652F\u6301: ${u.protocol}`];
|
|
1192
|
+
}
|
|
1193
|
+
const host = (u.hostname || "").toLowerCase();
|
|
1194
|
+
if (!host) return [false, "baseUrl \u7F3A\u5C11\u4E3B\u673A\u540D"];
|
|
1195
|
+
if (BLOCKED_HOSTS.includes(host)) return [false, `baseUrl \u6307\u5411\u4E91\u5143\u6570\u636E\u5730\u5740\uFF0C\u5DF2\u62D2\u7EDD: ${host}`];
|
|
1196
|
+
if (/^169\.254\.\d{1,3}\.\d{1,3}$/.test(host)) {
|
|
1197
|
+
return [false, `baseUrl \u6307\u5411\u94FE\u8DEF\u672C\u5730\u5730\u5740\uFF0C\u5DF2\u62D2\u7EDD: ${host}`];
|
|
1198
|
+
}
|
|
1199
|
+
const allowlist = splitList(env("AGENT_MOSS_LLM_HOST_ALLOWLIST")).map((h) => h.toLowerCase());
|
|
1200
|
+
if (allowlist.length && !allowlist.includes(host)) {
|
|
1201
|
+
return [false, `baseUrl \u4E3B\u673A\u4E0D\u5728\u5141\u8BB8\u5217\u8868: ${host}`];
|
|
1202
|
+
}
|
|
1203
|
+
if (allowPrivate === void 0) {
|
|
1204
|
+
allowPrivate = TRUTHY2.includes(env("AGENT_MOSS_TRUST_PRIVATE_LLM", "1").toLowerCase());
|
|
1205
|
+
}
|
|
1206
|
+
if (!allowPrivate) {
|
|
1207
|
+
if (host === "localhost" || host === "::1") return [false, "baseUrl \u6307\u5411\u672C\u673A\uFF0C\u5DF2\u62D2\u7EDD"];
|
|
1208
|
+
const m = host.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
|
|
1209
|
+
if (m) {
|
|
1210
|
+
const [a, b] = [Number(m[1]), Number(m[2])];
|
|
1211
|
+
if (a === 10 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 127 || a === 169 && b === 254) {
|
|
1212
|
+
return [false, `baseUrl \u6307\u5411\u5185\u7F51\u5730\u5740\uFF0C\u5DF2\u62D2\u7EDD: ${host}`];
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
return [true, ""];
|
|
1217
|
+
}
|
|
1218
|
+
function hardenExistingPaths() {
|
|
1219
|
+
try {
|
|
1220
|
+
const roots = [join4(homeDir(), ".config", "agentmoss"), join4(homeDir(), ".agentmoss")];
|
|
1221
|
+
const names = [
|
|
1222
|
+
"agent_moss_runtime.json",
|
|
1223
|
+
"config.json",
|
|
1224
|
+
"agent_moss_settings.json",
|
|
1225
|
+
"agent_moss_token_stats.json",
|
|
1226
|
+
"stateful_chains.db",
|
|
1227
|
+
"stateful_chains.db-wal",
|
|
1228
|
+
"stateful_chains.db-shm"
|
|
1229
|
+
];
|
|
1230
|
+
for (const root of roots) {
|
|
1231
|
+
try {
|
|
1232
|
+
if (existsSync3(root) && !lstatSync(root).isSymbolicLink()) chmodSync(root, 448);
|
|
1233
|
+
} catch {
|
|
1234
|
+
}
|
|
1235
|
+
for (const n of names) {
|
|
1236
|
+
const p = join4(root, n);
|
|
1237
|
+
try {
|
|
1238
|
+
if (existsSync3(p) && !lstatSync(p).isSymbolicLink()) chmodSync(p, 384);
|
|
1239
|
+
} catch {
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
} catch {
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
function chainDetailMode() {
|
|
1247
|
+
return (env("AGENT_MOSS_CHAIN_DETAIL", "redacted") || "redacted").toLowerCase();
|
|
1248
|
+
}
|
|
1249
|
+
function redactChain(chain, currentSessionId) {
|
|
1250
|
+
if (!chain || chain.length === 0) return [];
|
|
1251
|
+
if (chainDetailMode() === "full") return [...chain];
|
|
1252
|
+
return chain.map((step) => {
|
|
1253
|
+
if (Array.isArray(step) && step.length >= 3) {
|
|
1254
|
+
const [sid, seq, , ts] = step;
|
|
1255
|
+
if (String(sid) === String(currentSessionId)) return [...step];
|
|
1256
|
+
return ["<other-session>", seq, "<\u5DF2\u9690\u85CF>", ts ?? ""];
|
|
1257
|
+
}
|
|
1258
|
+
return step;
|
|
1259
|
+
});
|
|
1260
|
+
}
|
|
1261
|
+
function sessionSweepThreshold() {
|
|
1262
|
+
return envInt("AGENT_MOSS_SESSION_SWEEP_THRESHOLD", 50);
|
|
1263
|
+
}
|
|
1264
|
+
function sessionSweepWindow() {
|
|
1265
|
+
return envInt("AGENT_MOSS_SESSION_SWEEP_WINDOW_SEC", 300);
|
|
1266
|
+
}
|
|
1267
|
+
function sessionSweepAction() {
|
|
1268
|
+
return (env("AGENT_MOSS_SESSION_SWEEP_ACTION", "log") || "log").toLowerCase();
|
|
1269
|
+
}
|
|
1270
|
+
function noteSessionAccess(key, sessionId) {
|
|
1271
|
+
const limit = sessionSweepThreshold();
|
|
1272
|
+
if (limit <= 0 || !sessionId) return [0, false];
|
|
1273
|
+
const now = Date.now() / 1e3;
|
|
1274
|
+
const cutoff = now - sessionSweepWindow();
|
|
1275
|
+
let entries = (sessionWindow.get(key) ?? []).filter(([t]) => t >= cutoff);
|
|
1276
|
+
entries.push([now, sessionId]);
|
|
1277
|
+
if (entries.length > limit * 4) entries = entries.slice(-limit * 4);
|
|
1278
|
+
sessionWindow.set(key, entries);
|
|
1279
|
+
if (sessionWindow.size > 1e4) sessionWindow.clear();
|
|
1280
|
+
const distinct = new Set(entries.map(([, s]) => s)).size;
|
|
1281
|
+
return [distinct, distinct > limit];
|
|
1282
|
+
}
|
|
1283
|
+
function queueAbuseThreshold() {
|
|
1284
|
+
return envInt("AGENT_MOSS_QUEUE_ABUSE_THRESHOLD", 10);
|
|
1285
|
+
}
|
|
1286
|
+
function queueAbuseWindow() {
|
|
1287
|
+
return envInt("AGENT_MOSS_QUEUE_ABUSE_WINDOW_SEC", 60);
|
|
1288
|
+
}
|
|
1289
|
+
function queueAbuseAction() {
|
|
1290
|
+
return (env("AGENT_MOSS_QUEUE_ABUSE_ACTION", "log") || "log").toLowerCase();
|
|
1291
|
+
}
|
|
1292
|
+
function noteQueueReject(key) {
|
|
1293
|
+
const limit = queueAbuseThreshold();
|
|
1294
|
+
if (limit <= 0 || !key) return [0, false];
|
|
1295
|
+
const now = Date.now() / 1e3;
|
|
1296
|
+
const cutoff = now - queueAbuseWindow();
|
|
1297
|
+
let entries = (queueRejects.get(key) ?? []).filter((t) => t >= cutoff);
|
|
1298
|
+
entries.push(now);
|
|
1299
|
+
if (entries.length > limit * 4) entries = entries.slice(-limit * 4);
|
|
1300
|
+
queueRejects.set(key, entries);
|
|
1301
|
+
if (queueRejects.size > 1e4) queueRejects.clear();
|
|
1302
|
+
return [entries.length, entries.length > limit];
|
|
1303
|
+
}
|
|
1304
|
+
function socketMode() {
|
|
1305
|
+
const raw = env("AGENT_MOSS_SOCKET_MODE", "600");
|
|
1306
|
+
const mode = parseInt(raw, 8);
|
|
1307
|
+
if (!Number.isFinite(mode) || mode < 0 || mode > 511) {
|
|
1308
|
+
console.warn(`[agent-moss] AGENT_MOSS_SOCKET_MODE=${raw} \u975E\u6CD5\uFF0C\u56DE\u9000 600`);
|
|
1309
|
+
return 384;
|
|
1310
|
+
}
|
|
1311
|
+
return mode;
|
|
1312
|
+
}
|
|
1313
|
+
function errorDetailMode() {
|
|
1314
|
+
return (env("AGENT_MOSS_ERROR_DETAIL", "generic") || "generic").toLowerCase();
|
|
1315
|
+
}
|
|
1316
|
+
function maxBodyBytes() {
|
|
1317
|
+
return envInt("AGENT_MOSS_MAX_BODY_BYTES", 16 * 1024 * 1024);
|
|
1318
|
+
}
|
|
1319
|
+
function poolOf(path6) {
|
|
1320
|
+
if (path6 === "/api/v1/analyze" || path6.startsWith("/api/v1/analyze/")) return "biz";
|
|
1321
|
+
if (path6 === "/api/v1/review" || path6.startsWith("/api/v1/review/")) return "review";
|
|
1322
|
+
if (path6 === "/console" || path6.startsWith("/console/") || path6.startsWith("/api/v1/brain")) return "ops";
|
|
1323
|
+
if (path6 === "/api/v1/health") return "health";
|
|
1324
|
+
return "other";
|
|
1325
|
+
}
|
|
1326
|
+
function poolLimit(name) {
|
|
1327
|
+
let dflt = POOL_DEFAULTS[name] ?? 4;
|
|
1328
|
+
if (name === "biz") dflt = envInt("AGENT_MOSS_MAX_INFLIGHT", dflt);
|
|
1329
|
+
return envInt(`AGENT_MOSS_POOL_${name.toUpperCase()}`, dflt);
|
|
1330
|
+
}
|
|
1331
|
+
function unauthInflight() {
|
|
1332
|
+
return envInt("AGENT_MOSS_MAX_UNAUTH_INFLIGHT", 4);
|
|
1333
|
+
}
|
|
1334
|
+
function unauthPerIp() {
|
|
1335
|
+
return envInt("AGENT_MOSS_MAX_UNAUTH_PER_IP", 2);
|
|
1336
|
+
}
|
|
1337
|
+
function agentInflight() {
|
|
1338
|
+
return envInt("AGENT_MOSS_MAX_AGENT_INFLIGHT", 8);
|
|
1339
|
+
}
|
|
1340
|
+
function boundAgentOf(principal) {
|
|
1341
|
+
return principal.startsWith("agent:") ? principal.slice("agent:".length) : "";
|
|
1342
|
+
}
|
|
1343
|
+
function rateLimitQps() {
|
|
1344
|
+
return envInt("AGENT_MOSS_RATE_LIMIT_QPS", 100);
|
|
1345
|
+
}
|
|
1346
|
+
function maxConnections() {
|
|
1347
|
+
return envInt("AGENT_MOSS_MAX_CONNECTIONS", 128);
|
|
1348
|
+
}
|
|
1349
|
+
function keepAliveSec() {
|
|
1350
|
+
return envInt("AGENT_MOSS_KEEP_ALIVE_SEC", 5);
|
|
1351
|
+
}
|
|
1352
|
+
var TRUTHY2, HEALTH_PATHS, AUTH_MODE_AUTO, AUTH_MODE_OFF, tokenCache, fdTokenCache, BLOCKED_HOSTS, sessionWindow, queueRejects, POOL_DEFAULTS;
|
|
1353
|
+
var init_security_policy = __esm({
|
|
1354
|
+
"src/infra/security-policy.ts"() {
|
|
1355
|
+
"use strict";
|
|
1356
|
+
init_esm_shims();
|
|
1357
|
+
init_paths();
|
|
1358
|
+
TRUTHY2 = ["1", "true", "yes", "on"];
|
|
1359
|
+
HEALTH_PATHS = ["/api/v1/health"];
|
|
1360
|
+
AUTH_MODE_AUTO = "auto";
|
|
1361
|
+
AUTH_MODE_OFF = "off";
|
|
1362
|
+
tokenCache = null;
|
|
1363
|
+
fdTokenCache = /* @__PURE__ */ new Map();
|
|
1364
|
+
BLOCKED_HOSTS = ["169.254.169.254", "metadata.google.internal", "metadata.tencentyun.com"];
|
|
1365
|
+
sessionWindow = /* @__PURE__ */ new Map();
|
|
1366
|
+
queueRejects = /* @__PURE__ */ new Map();
|
|
1367
|
+
POOL_DEFAULTS = { biz: 16, review: 1, ops: 4, health: 4, other: 4 };
|
|
1368
|
+
}
|
|
1369
|
+
});
|
|
1370
|
+
|
|
873
1371
|
// src/package-json.ts
|
|
874
1372
|
import { createRequire } from "module";
|
|
875
1373
|
var require2, pkg, version;
|
|
@@ -897,7 +1395,10 @@ var init_models = __esm({
|
|
|
897
1395
|
// 工具返回给 agent 的内容。仅 L2 的授权(consent)判定用:判断「用户是否已授权」
|
|
898
1396
|
// 看的是 ask_user_question 的**回答**,不是提问正文。历史 bug:模型里没有这个字段、
|
|
899
1397
|
// 路由也没透传,TS 的授权判定退化成「提问正文非空」,等于问过任何问题即已授权。
|
|
900
|
-
output: z.string().optional().describe("Tool result / user answer (needed by L2 consent checks)")
|
|
1398
|
+
output: z.string().optional().describe("Tool result / user answer (needed by L2 consent checks)"),
|
|
1399
|
+
// 动作真实发生时间(可选)。供 P4「提权→外传」时间窗口判定;缺省时该性质
|
|
1400
|
+
// 退回不设窗口的旧行为。与 Python ActionItem.called_at 对齐。
|
|
1401
|
+
called_at: z.string().optional().describe("Action timestamp (optional)")
|
|
901
1402
|
});
|
|
902
1403
|
PromptTurnSchema = z.object({
|
|
903
1404
|
text: z.string().default("").describe("User prompt text at this turn"),
|
|
@@ -1538,7 +2039,7 @@ function checkReadBeforeWrite(actionType, actionDetail, actionHistory, reason, c
|
|
|
1538
2039
|
targetPaths.push(...segPathsFiltered);
|
|
1539
2040
|
}
|
|
1540
2041
|
}
|
|
1541
|
-
const uniqueTargetPaths = [...new Set(targetPaths)];
|
|
2042
|
+
const uniqueTargetPaths = [...new Set(targetPaths)].filter((p) => !PSEUDO_FS_PREFIXES.some((pfx) => p.startsWith(pfx)));
|
|
1542
2043
|
if (uniqueTargetPaths.length === 0) return null;
|
|
1543
2044
|
const historyReadPaths = /* @__PURE__ */ new Set();
|
|
1544
2045
|
for (const action of actionHistory) {
|
|
@@ -1717,7 +2218,7 @@ function checkIndirectFileAccess(actionType, actionDetail, cwd, osType) {
|
|
|
1717
2218
|
violatedLayers: ["L2.1"]
|
|
1718
2219
|
};
|
|
1719
2220
|
}
|
|
1720
|
-
var _LOGIC, _HEURISTIC, EXCLUDED_PREFIXES, TEMP_DIRS, ROOT_SENSITIVE_PATHS, HOME_SENSITIVE_PATHS, CREDENTIAL_PATHS, ROOT_SENSITIVE_PATHS_WINDOWS, HOME_SENSITIVE_PATHS_WINDOWS, CREDENTIAL_PATHS_WINDOWS, ROOT_SENSITIVE_PATHS_MACOS, HOME_SENSITIVE_PATHS_MACOS, CREDENTIAL_PATHS_MACOS, ROOT_SENSITIVE_PATHS_HARMONY, HOME_SENSITIVE_PATHS_HARMONY, CREDENTIAL_PATHS_HARMONY, _scopeIndex, NON_WRITE_TOOLS, NON_WRITE_TOOL_PREFIXES, WRITE_KEYWORDS, SED_INPLACE_RE, DEVNULL_REDIRECT_RE, CREATE_KEYWORDS, PASSWORD_MODIFY_PATTERNS, USER_DELETION_PATTERNS, INTENT_DEVIATION_PATTERNS, COMBO_STAGES, COMBO_CHAINS, INLINE_SCRIPT_RE, DIR_TRAVERSAL_KW, _IFA, IFA_READ_KEYWORDS, IFA_WRITE_KEYWORDS, IFA_EXEC_KEYWORDS, IFA_OPEN_KEYWORDS;
|
|
2221
|
+
var _LOGIC, _HEURISTIC, EXCLUDED_PREFIXES, TEMP_DIRS, ROOT_SENSITIVE_PATHS, HOME_SENSITIVE_PATHS, CREDENTIAL_PATHS, ROOT_SENSITIVE_PATHS_WINDOWS, HOME_SENSITIVE_PATHS_WINDOWS, CREDENTIAL_PATHS_WINDOWS, ROOT_SENSITIVE_PATHS_MACOS, HOME_SENSITIVE_PATHS_MACOS, CREDENTIAL_PATHS_MACOS, ROOT_SENSITIVE_PATHS_HARMONY, HOME_SENSITIVE_PATHS_HARMONY, CREDENTIAL_PATHS_HARMONY, _scopeIndex, NON_WRITE_TOOLS, NON_WRITE_TOOL_PREFIXES, PSEUDO_FS_PREFIXES, WRITE_KEYWORDS, SED_INPLACE_RE, DEVNULL_REDIRECT_RE, CREATE_KEYWORDS, PASSWORD_MODIFY_PATTERNS, USER_DELETION_PATTERNS, INTENT_DEVIATION_PATTERNS, COMBO_STAGES, COMBO_CHAINS, INLINE_SCRIPT_RE, DIR_TRAVERSAL_KW, _IFA, IFA_READ_KEYWORDS, IFA_WRITE_KEYWORDS, IFA_EXEC_KEYWORDS, IFA_OPEN_KEYWORDS;
|
|
1721
2222
|
var init_logic_rules = __esm({
|
|
1722
2223
|
"src/engine/logic-rules.ts"() {
|
|
1723
2224
|
"use strict";
|
|
@@ -1764,6 +2265,7 @@ var init_logic_rules = __esm({
|
|
|
1764
2265
|
"cat"
|
|
1765
2266
|
]);
|
|
1766
2267
|
NON_WRITE_TOOL_PREFIXES = _LOGIC.non_write_tool_prefixes ?? [];
|
|
2268
|
+
PSEUDO_FS_PREFIXES = ["/sys/", "/proc/", "/dev/", "/run/"];
|
|
1767
2269
|
WRITE_KEYWORDS = ["write", "\u5199\u5165", "save", "\u4FDD\u5B58", "modify", "\u4FEE\u6539", "update", "\u66F4\u65B0", "delete", "\u5220\u9664", "remove", "\u79FB\u9664", "create", "\u521B\u5EFA", "append", "\u8FFD\u52A0", "truncate", "\u622A\u65AD", "overwrite", "\u8986\u76D6", "replace", "\u66FF\u6362", "edit"];
|
|
1768
2270
|
SED_INPLACE_RE = /\bsed\s+(?:-\S+\s+)*(?:-[a-zA-Z]*i[a-zA-Z]*|--in-place)\b/i;
|
|
1769
2271
|
DEVNULL_REDIRECT_RE = /(?:2|&|1)?\s*>\s*\/dev\/null\b/g;
|
|
@@ -1814,22 +2316,22 @@ var init_logic_rules = __esm({
|
|
|
1814
2316
|
});
|
|
1815
2317
|
|
|
1816
2318
|
// src/engine/asset-dir.ts
|
|
1817
|
-
import { existsSync as
|
|
1818
|
-
import { join as
|
|
2319
|
+
import { existsSync as existsSync5 } from "fs";
|
|
2320
|
+
import { join as join5, resolve as resolve3 } from "path";
|
|
1819
2321
|
function assetDirCandidates(moduleDir, name) {
|
|
1820
2322
|
const root = getRulesRoot();
|
|
1821
2323
|
if (root) {
|
|
1822
|
-
const p =
|
|
2324
|
+
const p = join5(root, name);
|
|
1823
2325
|
return [p, p];
|
|
1824
2326
|
}
|
|
1825
2327
|
return [
|
|
1826
|
-
|
|
1827
|
-
|
|
2328
|
+
resolve3(moduleDir, name),
|
|
2329
|
+
resolve3(moduleDir, "../../..", "agent_moss", name)
|
|
1828
2330
|
];
|
|
1829
2331
|
}
|
|
1830
2332
|
function resolveAssetDir(moduleDir, name) {
|
|
1831
2333
|
for (const dir of assetDirCandidates(moduleDir, name)) {
|
|
1832
|
-
if (
|
|
2334
|
+
if (existsSync5(dir)) return dir;
|
|
1833
2335
|
}
|
|
1834
2336
|
return null;
|
|
1835
2337
|
}
|
|
@@ -1842,8 +2344,8 @@ var init_asset_dir = __esm({
|
|
|
1842
2344
|
});
|
|
1843
2345
|
|
|
1844
2346
|
// src/engine/skill-loader.ts
|
|
1845
|
-
import { readFileSync as
|
|
1846
|
-
import { resolve as
|
|
2347
|
+
import { readFileSync as readFileSync5, readdirSync as readdirSync3, existsSync as existsSync6 } from "fs";
|
|
2348
|
+
import { resolve as resolve4, dirname as dirname3 } from "path";
|
|
1847
2349
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1848
2350
|
function loadAllSkills() {
|
|
1849
2351
|
if (cachedSkills) return cachedSkills;
|
|
@@ -1857,13 +2359,13 @@ function loadAllSkills() {
|
|
|
1857
2359
|
const files = readdirSync3(dir).filter((f) => f.endsWith(".md"));
|
|
1858
2360
|
for (const f of files) {
|
|
1859
2361
|
const name = f.replace(".md", "");
|
|
1860
|
-
cachedSkills[name] =
|
|
2362
|
+
cachedSkills[name] = readFileSync5(resolve4(dir, f), "utf-8");
|
|
1861
2363
|
}
|
|
1862
2364
|
console.log(`[AgentMoss] Loaded ${Object.keys(cachedSkills).length} skills from ${dir}`);
|
|
1863
2365
|
return cachedSkills;
|
|
1864
2366
|
}
|
|
1865
2367
|
function userSkillsDir() {
|
|
1866
|
-
return
|
|
2368
|
+
return resolve4(getDataRoot(), "agent_moss_skills");
|
|
1867
2369
|
}
|
|
1868
2370
|
function runtimeCustomSkillKeywords() {
|
|
1869
2371
|
if (isRuntimeConfigDisabled()) return {};
|
|
@@ -1887,8 +2389,8 @@ function loadUserSkill(name) {
|
|
|
1887
2389
|
if (isRuntimeConfigDisabled()) return "";
|
|
1888
2390
|
if (userSkillCache[name] !== void 0) return userSkillCache[name];
|
|
1889
2391
|
try {
|
|
1890
|
-
const p =
|
|
1891
|
-
userSkillCache[name] =
|
|
2392
|
+
const p = resolve4(userSkillsDir(), `${name}.md`);
|
|
2393
|
+
userSkillCache[name] = existsSync6(p) ? readFileSync5(p, "utf-8") : "";
|
|
1892
2394
|
} catch {
|
|
1893
2395
|
userSkillCache[name] = "";
|
|
1894
2396
|
}
|
|
@@ -1957,7 +2459,7 @@ var init_skill_loader = __esm({
|
|
|
1957
2459
|
init_asset_dir();
|
|
1958
2460
|
init_runtime_config_bridge();
|
|
1959
2461
|
__filename3 = fileURLToPath3(import.meta.url);
|
|
1960
|
-
__dirname3 =
|
|
2462
|
+
__dirname3 = dirname3(__filename3);
|
|
1961
2463
|
SKILL_KEYWORD_MAP = (() => {
|
|
1962
2464
|
const map = {};
|
|
1963
2465
|
const cats = loadL3();
|
|
@@ -2037,10 +2539,10 @@ __export(runtime_config_exports, {
|
|
|
2037
2539
|
updateSkillCategoryEnabled: () => updateSkillCategoryEnabled,
|
|
2038
2540
|
updateSkillEnabled: () => updateSkillEnabled
|
|
2039
2541
|
});
|
|
2040
|
-
import { readFileSync as
|
|
2041
|
-
import { join as
|
|
2542
|
+
import { readFileSync as readFileSync6, writeFileSync, existsSync as existsSync7, mkdirSync as mkdirSync2, unlinkSync, readdirSync as readdirSync4, statSync as statSync2 } from "fs";
|
|
2543
|
+
import { join as join6 } from "path";
|
|
2042
2544
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
2043
|
-
import { dirname as
|
|
2545
|
+
import { dirname as dirname4 } from "path";
|
|
2044
2546
|
function runtimeDir() {
|
|
2045
2547
|
return getRuntimeConfigDir();
|
|
2046
2548
|
}
|
|
@@ -2067,7 +2569,7 @@ function saveRuntimeConfig(config) {
|
|
|
2067
2569
|
}
|
|
2068
2570
|
const p = getRuntimeConfigPath();
|
|
2069
2571
|
const dir = p.substring(0, p.lastIndexOf("/"));
|
|
2070
|
-
if (dir && !
|
|
2572
|
+
if (dir && !existsSync7(dir)) mkdirSync2(dir, { recursive: true });
|
|
2071
2573
|
writeFileSync(p, JSON.stringify(config, null, 2), "utf-8");
|
|
2072
2574
|
invalidateRuntimeConfigCache();
|
|
2073
2575
|
}
|
|
@@ -2101,7 +2603,7 @@ function loadRuntimeConfig() {
|
|
|
2101
2603
|
};
|
|
2102
2604
|
}
|
|
2103
2605
|
const p = getRuntimeConfigPath();
|
|
2104
|
-
if (!
|
|
2606
|
+
if (!existsSync7(p)) {
|
|
2105
2607
|
const seeded = mergeConfig({}, generateSourceDefaults());
|
|
2106
2608
|
try {
|
|
2107
2609
|
saveRuntimeConfig(seeded);
|
|
@@ -2115,7 +2617,7 @@ function loadRuntimeConfig() {
|
|
|
2115
2617
|
if (runtimeConfigCache && runtimeConfigCache.key === cacheKey) {
|
|
2116
2618
|
return runtimeConfigCache.value;
|
|
2117
2619
|
}
|
|
2118
|
-
const data = JSON.parse(
|
|
2620
|
+
const data = JSON.parse(readFileSync6(p, "utf-8"));
|
|
2119
2621
|
const merged = mergeConfig(data, generateSourceDefaults());
|
|
2120
2622
|
const result = {
|
|
2121
2623
|
version: data.version || 1,
|
|
@@ -2263,7 +2765,7 @@ function hasRuntimeConfig() {
|
|
|
2263
2765
|
if (cached2 !== void 0) return cached2;
|
|
2264
2766
|
let ok = false;
|
|
2265
2767
|
try {
|
|
2266
|
-
JSON.parse(
|
|
2768
|
+
JSON.parse(readFileSync6(p, "utf-8"));
|
|
2267
2769
|
ok = true;
|
|
2268
2770
|
} catch {
|
|
2269
2771
|
ok = false;
|
|
@@ -2378,7 +2880,7 @@ function _l2SensitivePathsToRules() {
|
|
|
2378
2880
|
const all = [...root, ...home, ...credential];
|
|
2379
2881
|
for (const sp of all) {
|
|
2380
2882
|
const os4 = String(sp.os || "linux").toLowerCase();
|
|
2381
|
-
const denyMode = _deriveDenyMode({
|
|
2883
|
+
const denyMode = sp.denyMode || _deriveDenyMode({
|
|
2382
2884
|
deny_mode: sp.deny_mode,
|
|
2383
2885
|
credential: sp.credential,
|
|
2384
2886
|
read_only: sp.read_only
|
|
@@ -2484,8 +2986,8 @@ function _l3SkillsToRules() {
|
|
|
2484
2986
|
function _scenarioRulesToDefaults() {
|
|
2485
2987
|
const out = {};
|
|
2486
2988
|
const _root = getRulesRoot();
|
|
2487
|
-
const scenDir = _root ?
|
|
2488
|
-
if (!
|
|
2989
|
+
const scenDir = _root ? join6(_root, "scenarios") : existsSync7(_SCENARIOS_DIR_PROD) ? _SCENARIOS_DIR_PROD : existsSync7(_SCENARIOS_DIR_DEV) ? _SCENARIOS_DIR_DEV : _SCENARIOS_DIR_PROD;
|
|
2990
|
+
if (!existsSync7(scenDir)) return out;
|
|
2489
2991
|
let entries;
|
|
2490
2992
|
try {
|
|
2491
2993
|
entries = readdirSync4(scenDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -2493,11 +2995,11 @@ function _scenarioRulesToDefaults() {
|
|
|
2493
2995
|
return out;
|
|
2494
2996
|
}
|
|
2495
2997
|
for (const scenarioId of entries) {
|
|
2496
|
-
const rulesFile = resolveScenarioRulesFile(scenarioId) ??
|
|
2497
|
-
if (!
|
|
2998
|
+
const rulesFile = resolveScenarioRulesFile(scenarioId) ?? join6(scenDir, scenarioId, "rules.json");
|
|
2999
|
+
if (!existsSync7(rulesFile)) continue;
|
|
2498
3000
|
let data;
|
|
2499
3001
|
try {
|
|
2500
|
-
data = JSON.parse(
|
|
3002
|
+
data = JSON.parse(readFileSync6(rulesFile, "utf-8"));
|
|
2501
3003
|
} catch {
|
|
2502
3004
|
continue;
|
|
2503
3005
|
}
|
|
@@ -2534,8 +3036,8 @@ function _scenarioRulesToDefaults() {
|
|
|
2534
3036
|
function _agentRulesToDefaults() {
|
|
2535
3037
|
const out = {};
|
|
2536
3038
|
const _root = getRulesRoot();
|
|
2537
|
-
const agentsDir = _root ?
|
|
2538
|
-
if (!
|
|
3039
|
+
const agentsDir = _root ? join6(_root, "agents") : existsSync7(_AGENTS_DIR_PROD) ? _AGENTS_DIR_PROD : existsSync7(_AGENTS_DIR_DEV) ? _AGENTS_DIR_DEV : _AGENTS_DIR_PROD;
|
|
3040
|
+
if (!existsSync7(agentsDir)) return out;
|
|
2539
3041
|
let entries;
|
|
2540
3042
|
try {
|
|
2541
3043
|
entries = readdirSync4(agentsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -2543,11 +3045,11 @@ function _agentRulesToDefaults() {
|
|
|
2543
3045
|
return out;
|
|
2544
3046
|
}
|
|
2545
3047
|
for (const agentId of entries) {
|
|
2546
|
-
const rulesFile =
|
|
2547
|
-
if (!
|
|
3048
|
+
const rulesFile = join6(agentsDir, agentId, "rules.json");
|
|
3049
|
+
if (!existsSync7(rulesFile)) continue;
|
|
2548
3050
|
let data;
|
|
2549
3051
|
try {
|
|
2550
|
-
data = JSON.parse(
|
|
3052
|
+
data = JSON.parse(readFileSync6(rulesFile, "utf-8"));
|
|
2551
3053
|
} catch {
|
|
2552
3054
|
continue;
|
|
2553
3055
|
}
|
|
@@ -3155,12 +3657,12 @@ function addCustomSkill(skillId, category, keywords, content) {
|
|
|
3155
3657
|
);
|
|
3156
3658
|
}
|
|
3157
3659
|
const runtime = loadRuntimeConfig();
|
|
3158
|
-
const skillsDir =
|
|
3660
|
+
const skillsDir = join6(getRuntimeConfigDir(), "agent_moss_skills");
|
|
3159
3661
|
try {
|
|
3160
|
-
|
|
3662
|
+
mkdirSync2(skillsDir, { recursive: true });
|
|
3161
3663
|
} catch {
|
|
3162
3664
|
}
|
|
3163
|
-
writeFileSync(
|
|
3665
|
+
writeFileSync(join6(skillsDir, `${skillId}.md`), content, "utf-8");
|
|
3164
3666
|
const l3 = runtime.L3_skills || (runtime.L3_skills = {});
|
|
3165
3667
|
const cat = l3[category] || (l3[category] = { category_enabled: true, category_desc: "", skills: [] });
|
|
3166
3668
|
(cat.skills || (cat.skills = [])).push({ id: skillId, keywords, enabled: true, builtin: false });
|
|
@@ -3175,9 +3677,9 @@ function deleteCustomSkill(skillId, category) {
|
|
|
3175
3677
|
if (idx >= 0) {
|
|
3176
3678
|
if (skills[idx].builtin) return null;
|
|
3177
3679
|
skills.splice(idx, 1);
|
|
3178
|
-
const skillPath =
|
|
3680
|
+
const skillPath = join6(getRuntimeConfigDir(), "agent_moss_skills", `${skillId}.md`);
|
|
3179
3681
|
try {
|
|
3180
|
-
if (
|
|
3682
|
+
if (existsSync7(skillPath)) unlinkSync(skillPath);
|
|
3181
3683
|
} catch {
|
|
3182
3684
|
}
|
|
3183
3685
|
saveRuntimeConfig(runtime);
|
|
@@ -3381,10 +3883,10 @@ var init_runtime_config = __esm({
|
|
|
3381
3883
|
init_rules_loader();
|
|
3382
3884
|
init_runtime_config_bridge();
|
|
3383
3885
|
init_rules_mode();
|
|
3384
|
-
__dirname4 =
|
|
3886
|
+
__dirname4 = dirname4(fileURLToPath4(import.meta.url));
|
|
3385
3887
|
ENV_RUNTIME_CONFIG_PATH = "AGENT_MOSS_RUNTIME_CONFIG_PATH";
|
|
3386
3888
|
RUNTIME_CONFIG_DIR = runtimeDir();
|
|
3387
|
-
RUNTIME_CONFIG_PATH =
|
|
3889
|
+
RUNTIME_CONFIG_PATH = join6(RUNTIME_CONFIG_DIR, "agent_moss_runtime.json");
|
|
3388
3890
|
LAYER_DISABLE_ENV = {
|
|
3389
3891
|
L1_heuristic: "AGENT_MOSS_DISABLE_HEURISTIC",
|
|
3390
3892
|
L2_logic_rules: "AGENT_MOSS_DISABLE_LOGIC_RULES",
|
|
@@ -3412,10 +3914,10 @@ var init_runtime_config = __esm({
|
|
|
3412
3914
|
intent_consistency: ["intent_keywords", "reason"]
|
|
3413
3915
|
};
|
|
3414
3916
|
hasRuntimeConfigCache = /* @__PURE__ */ new Map();
|
|
3415
|
-
_AGENTS_DIR_PROD =
|
|
3416
|
-
_AGENTS_DIR_DEV =
|
|
3417
|
-
_SCENARIOS_DIR_PROD =
|
|
3418
|
-
_SCENARIOS_DIR_DEV =
|
|
3917
|
+
_AGENTS_DIR_PROD = join6(__dirname4, "agents");
|
|
3918
|
+
_AGENTS_DIR_DEV = join6(__dirname4, "..", "..", "..", "agent_moss", "agents");
|
|
3919
|
+
_SCENARIOS_DIR_PROD = join6(__dirname4, "scenarios");
|
|
3920
|
+
_SCENARIOS_DIR_DEV = join6(__dirname4, "..", "..", "..", "agent_moss", "scenarios");
|
|
3419
3921
|
_effectiveCache = /* @__PURE__ */ new WeakMap();
|
|
3420
3922
|
SKILL_ID_RE = /^[A-Za-z0-9_-]+$/;
|
|
3421
3923
|
registerRuntimeConfigBridge({
|
|
@@ -3753,18 +4255,23 @@ var init_config = __esm({
|
|
|
3753
4255
|
});
|
|
3754
4256
|
|
|
3755
4257
|
// src/agents/index.ts
|
|
3756
|
-
import { readFileSync as
|
|
3757
|
-
import { resolve as
|
|
4258
|
+
import { readFileSync as readFileSync7, existsSync as existsSync8 } from "fs";
|
|
4259
|
+
import { resolve as resolve5, dirname as dirname5, join as join7 } from "path";
|
|
3758
4260
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
3759
4261
|
function resolveAgentsDir() {
|
|
3760
4262
|
const root = getRulesRoot();
|
|
3761
|
-
if (root) return
|
|
3762
|
-
if (
|
|
3763
|
-
if (
|
|
4263
|
+
if (root) return join7(root, "agents");
|
|
4264
|
+
if (existsSync8(AGENTS_DIR_PROD)) return AGENTS_DIR_PROD;
|
|
4265
|
+
if (existsSync8(AGENTS_DIR_DEV_FALLBACK)) return AGENTS_DIR_DEV_FALLBACK;
|
|
3764
4266
|
return AGENTS_DIR_PROD;
|
|
3765
4267
|
}
|
|
3766
4268
|
function getAgentExtensions(agentId) {
|
|
3767
4269
|
if (!agentId) return null;
|
|
4270
|
+
if (!isSafeId(agentId)) {
|
|
4271
|
+
console.warn(`[AgentMoss agents] \u975E\u6CD5 agent_id \u5DF2\u5FFD\u7565\uFF08\u542B\u8DEF\u5F84\u5B57\u7B26\u6216\u8D85\u957F\uFF09: ${agentId.slice(0, 120)}`);
|
|
4272
|
+
return null;
|
|
4273
|
+
}
|
|
4274
|
+
if (cache.size >= CACHE_MAX) cache.clear();
|
|
3768
4275
|
const fp = getRuleSourceFingerprint();
|
|
3769
4276
|
const cached2 = cache.get(agentId);
|
|
3770
4277
|
if (cached2 && cached2.fp === fp) return cached2.ext;
|
|
@@ -3777,13 +4284,13 @@ function getAgentExtensions(agentId) {
|
|
|
3777
4284
|
}
|
|
3778
4285
|
if (ext === null) {
|
|
3779
4286
|
const agentsDir = resolveAgentsDir();
|
|
3780
|
-
const rulesFile =
|
|
3781
|
-
if (!
|
|
4287
|
+
const rulesFile = resolve5(agentsDir, agentId, "rules.json");
|
|
4288
|
+
if (!existsSync8(rulesFile)) {
|
|
3782
4289
|
cache.set(agentId, { fp, ext: null });
|
|
3783
4290
|
return null;
|
|
3784
4291
|
}
|
|
3785
4292
|
try {
|
|
3786
|
-
const raw =
|
|
4293
|
+
const raw = readFileSync7(rulesFile, "utf-8");
|
|
3787
4294
|
ext = JSON.parse(raw);
|
|
3788
4295
|
if (!ext.agent_id) {
|
|
3789
4296
|
console.warn(`[AgentMoss agents] rules.json \u7F3A\u5C11 agent_id \u5B57\u6BB5: ${rulesFile}`);
|
|
@@ -3817,7 +4324,7 @@ function mergeAgentExtensions(...exts) {
|
|
|
3817
4324
|
extra_skills: nonNull.flatMap((e) => e.extra_skills || [])
|
|
3818
4325
|
};
|
|
3819
4326
|
}
|
|
3820
|
-
var __filename4, __dirname5, AGENTS_DIR_PROD, AGENTS_DIR_DEV_FALLBACK, cache;
|
|
4327
|
+
var __filename4, __dirname5, AGENTS_DIR_PROD, AGENTS_DIR_DEV_FALLBACK, cache, CACHE_MAX;
|
|
3821
4328
|
var init_agents = __esm({
|
|
3822
4329
|
"src/agents/index.ts"() {
|
|
3823
4330
|
"use strict";
|
|
@@ -3825,26 +4332,32 @@ var init_agents = __esm({
|
|
|
3825
4332
|
init_paths();
|
|
3826
4333
|
init_runtime_config();
|
|
3827
4334
|
__filename4 = fileURLToPath6(import.meta.url);
|
|
3828
|
-
__dirname5 =
|
|
3829
|
-
AGENTS_DIR_PROD =
|
|
3830
|
-
AGENTS_DIR_DEV_FALLBACK =
|
|
4335
|
+
__dirname5 = dirname5(__filename4);
|
|
4336
|
+
AGENTS_DIR_PROD = resolve5(__dirname5, "agents");
|
|
4337
|
+
AGENTS_DIR_DEV_FALLBACK = resolve5(__dirname5, "../../../agent_moss/agents");
|
|
3831
4338
|
cache = /* @__PURE__ */ new Map();
|
|
4339
|
+
CACHE_MAX = 512;
|
|
3832
4340
|
}
|
|
3833
4341
|
});
|
|
3834
4342
|
|
|
3835
4343
|
// src/scenarios/index.ts
|
|
3836
|
-
import { readFileSync as
|
|
3837
|
-
import { resolve as
|
|
4344
|
+
import { readFileSync as readFileSync8, existsSync as existsSync9 } from "fs";
|
|
4345
|
+
import { resolve as resolve6, dirname as dirname6, join as join8 } from "path";
|
|
3838
4346
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
3839
4347
|
function resolveScenariosDir() {
|
|
3840
4348
|
const root = getRulesRoot();
|
|
3841
|
-
if (root) return
|
|
3842
|
-
if (
|
|
3843
|
-
if (
|
|
4349
|
+
if (root) return join8(root, "scenarios");
|
|
4350
|
+
if (existsSync9(SCENARIOS_DIR_PROD)) return SCENARIOS_DIR_PROD;
|
|
4351
|
+
if (existsSync9(SCENARIOS_DIR_DEV_FALLBACK)) return SCENARIOS_DIR_DEV_FALLBACK;
|
|
3844
4352
|
return SCENARIOS_DIR_PROD;
|
|
3845
4353
|
}
|
|
3846
4354
|
function getScenarioExtensions(scenarioId) {
|
|
3847
4355
|
if (!scenarioId) return null;
|
|
4356
|
+
if (!isSafeId(scenarioId)) {
|
|
4357
|
+
console.warn(`[AgentMoss scenarios] \u975E\u6CD5 scenario_id \u5DF2\u5FFD\u7565\uFF08\u542B\u8DEF\u5F84\u5B57\u7B26\u6216\u8D85\u957F\uFF09: ${scenarioId.slice(0, 120)}`);
|
|
4358
|
+
return null;
|
|
4359
|
+
}
|
|
4360
|
+
if (cache2.size >= CACHE_MAX2) cache2.clear();
|
|
3848
4361
|
const fp = getRuleSourceFingerprint();
|
|
3849
4362
|
const cached2 = cache2.get(scenarioId);
|
|
3850
4363
|
if (cached2 && cached2.fp === fp) return cached2.ext;
|
|
@@ -3863,19 +4376,19 @@ function getScenarioExtensions(scenarioId) {
|
|
|
3863
4376
|
}
|
|
3864
4377
|
}
|
|
3865
4378
|
if (ext === null) {
|
|
3866
|
-
const builtinFile =
|
|
4379
|
+
const builtinFile = resolve6(resolveScenariosDir(), scenarioId, "rules.json");
|
|
3867
4380
|
const rulesFile = overrideHit ?? builtinFile;
|
|
3868
4381
|
if (overrideHit) {
|
|
3869
4382
|
console.warn(
|
|
3870
4383
|
`[AgentMoss] \u26A0\uFE0F \u573A\u666F ${scenarioId} \u89C4\u5219\u88AB\u8986\u76D6\u76EE\u5F55\u8986\u76D6: ${overrideHit}\uFF08\u5185\u7F6E\u9ED8\u8BA4 ${builtinFile} \u88AB\u5FFD\u7565\uFF09\u3002\u8BE5\u6587\u4EF6\u7531\u90E8\u7F72\u4FA7\u81EA\u884C\u7EF4\u62A4\uFF0C\u5185\u7F6E\u573A\u666F\u89C4\u5219\u66F4\u65B0\u4E0D\u4F1A\u53CD\u6620\u5230\u5B83\u4E0A\u9762\u3002`
|
|
3871
4384
|
);
|
|
3872
4385
|
}
|
|
3873
|
-
if (!
|
|
4386
|
+
if (!existsSync9(rulesFile)) {
|
|
3874
4387
|
cache2.set(scenarioId, { fp, ext: null });
|
|
3875
4388
|
return null;
|
|
3876
4389
|
}
|
|
3877
4390
|
try {
|
|
3878
|
-
const raw =
|
|
4391
|
+
const raw = readFileSync8(rulesFile, "utf-8");
|
|
3879
4392
|
const data = JSON.parse(raw);
|
|
3880
4393
|
const id = data.scenario_id || data.agent_id || "";
|
|
3881
4394
|
if (!id) {
|
|
@@ -3914,7 +4427,7 @@ function getScenarioExtensionsMulti(scenarioSpec) {
|
|
|
3914
4427
|
if (nonNull.length === 0) return null;
|
|
3915
4428
|
return mergeAgentExtensions(...nonNull);
|
|
3916
4429
|
}
|
|
3917
|
-
var __filename5, __dirname6, SCENARIOS_DIR_PROD, SCENARIOS_DIR_DEV_FALLBACK, cache2;
|
|
4430
|
+
var __filename5, __dirname6, SCENARIOS_DIR_PROD, SCENARIOS_DIR_DEV_FALLBACK, cache2, CACHE_MAX2;
|
|
3918
4431
|
var init_scenarios = __esm({
|
|
3919
4432
|
"src/scenarios/index.ts"() {
|
|
3920
4433
|
"use strict";
|
|
@@ -3924,10 +4437,11 @@ var init_scenarios = __esm({
|
|
|
3924
4437
|
init_runtime_config();
|
|
3925
4438
|
init_rules_loader();
|
|
3926
4439
|
__filename5 = fileURLToPath7(import.meta.url);
|
|
3927
|
-
__dirname6 =
|
|
3928
|
-
SCENARIOS_DIR_PROD =
|
|
3929
|
-
SCENARIOS_DIR_DEV_FALLBACK =
|
|
4440
|
+
__dirname6 = dirname6(__filename5);
|
|
4441
|
+
SCENARIOS_DIR_PROD = resolve6(__dirname6, "scenarios");
|
|
4442
|
+
SCENARIOS_DIR_DEV_FALLBACK = resolve6(__dirname6, "../../../agent_moss/scenarios");
|
|
3930
4443
|
cache2 = /* @__PURE__ */ new Map();
|
|
4444
|
+
CACHE_MAX2 = 512;
|
|
3931
4445
|
}
|
|
3932
4446
|
});
|
|
3933
4447
|
|
|
@@ -4807,8 +5321,8 @@ var init_heuristic = __esm({
|
|
|
4807
5321
|
});
|
|
4808
5322
|
|
|
4809
5323
|
// src/engine/template-loader.ts
|
|
4810
|
-
import { readFileSync as
|
|
4811
|
-
import { resolve as
|
|
5324
|
+
import { readFileSync as readFileSync9, existsSync as existsSync10 } from "fs";
|
|
5325
|
+
import { resolve as resolve7, dirname as dirname7 } from "path";
|
|
4812
5326
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
4813
5327
|
function loadTemplates() {
|
|
4814
5328
|
if (cachedTemplates) return cachedTemplates;
|
|
@@ -4820,10 +5334,10 @@ function loadTemplates() {
|
|
|
4820
5334
|
return cachedTemplates;
|
|
4821
5335
|
}
|
|
4822
5336
|
for (const file of TEMPLATE_FILES) {
|
|
4823
|
-
const filePath =
|
|
4824
|
-
if (
|
|
5337
|
+
const filePath = resolve7(dir, file);
|
|
5338
|
+
if (existsSync10(filePath)) {
|
|
4825
5339
|
const key = file.replace(".txt", "").replace("_template", "");
|
|
4826
|
-
cachedTemplates[key] =
|
|
5340
|
+
cachedTemplates[key] = readFileSync9(filePath, "utf-8");
|
|
4827
5341
|
}
|
|
4828
5342
|
}
|
|
4829
5343
|
console.log(`[AgentMoss] Loaded ${Object.keys(cachedTemplates).length} templates from ${dir}`);
|
|
@@ -4836,15 +5350,15 @@ var init_template_loader = __esm({
|
|
|
4836
5350
|
init_esm_shims();
|
|
4837
5351
|
init_asset_dir();
|
|
4838
5352
|
__filename6 = fileURLToPath8(import.meta.url);
|
|
4839
|
-
__dirname7 =
|
|
5353
|
+
__dirname7 = dirname7(__filename6);
|
|
4840
5354
|
TEMPLATE_FILES = ["prompt1_template.txt", "prompt2_template.txt", "security_judge_template.txt"];
|
|
4841
5355
|
cachedTemplates = null;
|
|
4842
5356
|
}
|
|
4843
5357
|
});
|
|
4844
5358
|
|
|
4845
5359
|
// src/engine/script-analyzer.ts
|
|
4846
|
-
import { readFileSync as
|
|
4847
|
-
import { resolve as
|
|
5360
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
5361
|
+
import { resolve as resolve8, join as join9 } from "path";
|
|
4848
5362
|
function emptyResult() {
|
|
4849
5363
|
return { scriptPath: "", scriptContent: "", matchedKeywords: [], lineCount: 0, isSuspicious: false, error: "", riskLevel: "", riskReason: "" };
|
|
4850
5364
|
}
|
|
@@ -4897,8 +5411,8 @@ function assessKeywordCombinationRisk(matchedKeywords, scriptContent) {
|
|
|
4897
5411
|
}
|
|
4898
5412
|
function readScriptContent(scriptPath, maxLines = 500) {
|
|
4899
5413
|
try {
|
|
4900
|
-
const expandedPath = scriptPath === "~" || scriptPath.startsWith("~/") ?
|
|
4901
|
-
const raw =
|
|
5414
|
+
const expandedPath = scriptPath === "~" || scriptPath.startsWith("~/") ? join9(process.env.HOME || "/home/user", scriptPath.slice(1)) : resolve8(scriptPath);
|
|
5415
|
+
const raw = readFileSync10(expandedPath, "utf-8");
|
|
4902
5416
|
const lines = raw.split("\n").slice(0, maxLines);
|
|
4903
5417
|
return { content: lines.join("\n"), lineCount: lines.length, error: "" };
|
|
4904
5418
|
} catch (e) {
|
|
@@ -5026,14 +5540,14 @@ function isSysArgv(node) {
|
|
|
5026
5540
|
const prop = node.getChild("PropertyName");
|
|
5027
5541
|
return prop !== null && srcSlice(prop) === "argv";
|
|
5028
5542
|
}
|
|
5029
|
-
function evalExpr(node,
|
|
5543
|
+
function evalExpr(node, env2) {
|
|
5030
5544
|
if (!node) return null;
|
|
5031
5545
|
const name = node.name;
|
|
5032
5546
|
if (name === "String") return stringValue(srcSlice(node));
|
|
5033
5547
|
if (name === "Number") return srcSlice(node);
|
|
5034
5548
|
if (name === "VariableName") {
|
|
5035
5549
|
const id = srcSlice(node);
|
|
5036
|
-
return id in
|
|
5550
|
+
return id in env2.vars ? env2.vars[id] : null;
|
|
5037
5551
|
}
|
|
5038
5552
|
if (name === "MemberExpression") {
|
|
5039
5553
|
const bracket = node.getChild("[");
|
|
@@ -5043,13 +5557,13 @@ function evalExpr(node, env) {
|
|
|
5043
5557
|
const idxNode = bracket.nextSibling;
|
|
5044
5558
|
if (idxNode && idxNode.name === "Number") {
|
|
5045
5559
|
const idx = parseInt(srcSlice(idxNode), 10);
|
|
5046
|
-
if (idx >= 1 && idx <=
|
|
5560
|
+
if (idx >= 1 && idx <= env2.argv.length) return env2.argv[idx - 1];
|
|
5047
5561
|
return null;
|
|
5048
5562
|
}
|
|
5049
5563
|
}
|
|
5050
5564
|
return null;
|
|
5051
5565
|
}
|
|
5052
|
-
if (isSysArgv(node)) return
|
|
5566
|
+
if (isSysArgv(node)) return env2.argv[0] ?? null;
|
|
5053
5567
|
return null;
|
|
5054
5568
|
}
|
|
5055
5569
|
if (name === "CallExpression") {
|
|
@@ -5057,7 +5571,7 @@ function evalExpr(node, env) {
|
|
|
5057
5571
|
if (func && func.name === "VariableName" && srcSlice(func) === "len") {
|
|
5058
5572
|
const argList = node.getChild("ArgList");
|
|
5059
5573
|
const inner = argList ? firstNamedChild(argList) : null;
|
|
5060
|
-
if (inner && isSysArgv(inner)) return String(
|
|
5574
|
+
if (inner && isSysArgv(inner)) return String(env2.argv.length + 1);
|
|
5061
5575
|
}
|
|
5062
5576
|
return null;
|
|
5063
5577
|
}
|
|
@@ -5069,16 +5583,16 @@ function evalExpr(node, env) {
|
|
|
5069
5583
|
const condNode = ifKw.nextSibling;
|
|
5070
5584
|
const orelseNode = elseKw.nextSibling;
|
|
5071
5585
|
if (!thenNode || !condNode || !orelseNode) return null;
|
|
5072
|
-
const cond = evalCondition(condNode,
|
|
5073
|
-
if (cond === true) return evalExpr(thenNode,
|
|
5074
|
-
if (cond === false) return evalExpr(orelseNode,
|
|
5586
|
+
const cond = evalCondition(condNode, env2);
|
|
5587
|
+
if (cond === true) return evalExpr(thenNode, env2);
|
|
5588
|
+
if (cond === false) return evalExpr(orelseNode, env2);
|
|
5075
5589
|
return null;
|
|
5076
5590
|
}
|
|
5077
5591
|
if (name === "BinaryExpression") {
|
|
5078
5592
|
const op = findOp(node);
|
|
5079
5593
|
if (op === "+") {
|
|
5080
|
-
const left = evalExpr(node.firstChild,
|
|
5081
|
-
const right = evalExpr(lastNamedChild(node),
|
|
5594
|
+
const left = evalExpr(node.firstChild, env2);
|
|
5595
|
+
const right = evalExpr(lastNamedChild(node), env2);
|
|
5082
5596
|
if (left !== null && right !== null) return left + right;
|
|
5083
5597
|
}
|
|
5084
5598
|
return null;
|
|
@@ -5111,7 +5625,7 @@ function findOp(node) {
|
|
|
5111
5625
|
}
|
|
5112
5626
|
return null;
|
|
5113
5627
|
}
|
|
5114
|
-
function evalCondition(node,
|
|
5628
|
+
function evalCondition(node, env2) {
|
|
5115
5629
|
if (!node) return null;
|
|
5116
5630
|
const name = node.name;
|
|
5117
5631
|
if (name === "Boolean") {
|
|
@@ -5122,7 +5636,7 @@ function evalCondition(node, env) {
|
|
|
5122
5636
|
const op = findOp(node);
|
|
5123
5637
|
if (op === "and" || op === "or") {
|
|
5124
5638
|
const parts2 = namedChildren(node);
|
|
5125
|
-
const vals = parts2.map((p) => evalCondition(p,
|
|
5639
|
+
const vals = parts2.map((p) => evalCondition(p, env2));
|
|
5126
5640
|
if (op === "and") {
|
|
5127
5641
|
if (vals.some((v) => v === false)) return false;
|
|
5128
5642
|
if (vals.every((v) => v === true)) return true;
|
|
@@ -5136,13 +5650,13 @@ function evalCondition(node, env) {
|
|
|
5136
5650
|
if (parts.length !== 3) return null;
|
|
5137
5651
|
const [left, opNode, right] = parts;
|
|
5138
5652
|
const opText = srcSlice(opNode).trim();
|
|
5139
|
-
return evalCompare(left, opText, right,
|
|
5653
|
+
return evalCompare(left, opText, right, env2);
|
|
5140
5654
|
}
|
|
5141
5655
|
if (name === "UnaryExpression") {
|
|
5142
5656
|
const kw = node.getChild("not");
|
|
5143
5657
|
if (kw) {
|
|
5144
5658
|
const operand = kw.nextSibling;
|
|
5145
|
-
const v = evalCondition(operand,
|
|
5659
|
+
const v = evalCondition(operand, env2);
|
|
5146
5660
|
return v === null ? null : !v;
|
|
5147
5661
|
}
|
|
5148
5662
|
return null;
|
|
@@ -5163,39 +5677,39 @@ function namedChildren(node) {
|
|
|
5163
5677
|
}
|
|
5164
5678
|
return out;
|
|
5165
5679
|
}
|
|
5166
|
-
function evalCompare(left, opText, right,
|
|
5680
|
+
function evalCompare(left, opText, right, env2) {
|
|
5167
5681
|
if (opText === "==" && left.name === "VariableName" && srcSlice(left) === "__name__") {
|
|
5168
|
-
const rv = evalExpr(right,
|
|
5682
|
+
const rv = evalExpr(right, env2);
|
|
5169
5683
|
if (rv !== null) return rv === "__main__";
|
|
5170
5684
|
return null;
|
|
5171
5685
|
}
|
|
5172
5686
|
if (opText === "==" || opText === "!=") {
|
|
5173
|
-
const lv = evalExpr(left,
|
|
5174
|
-
const rv = evalExpr(right,
|
|
5687
|
+
const lv = evalExpr(left, env2);
|
|
5688
|
+
const rv = evalExpr(right, env2);
|
|
5175
5689
|
if (lv !== null && rv !== null) {
|
|
5176
5690
|
return opText === "==" ? lv === rv : lv !== rv;
|
|
5177
5691
|
}
|
|
5178
5692
|
return null;
|
|
5179
5693
|
}
|
|
5180
5694
|
if (opText === "in") {
|
|
5181
|
-
const lv = evalExpr(left,
|
|
5695
|
+
const lv = evalExpr(left, env2);
|
|
5182
5696
|
if (lv === null) return null;
|
|
5183
5697
|
const rightName = right.name;
|
|
5184
5698
|
if (rightName === "TupleExpression" || rightName === "ArrayExpression" || rightName === "SetExpression" || rightName === "ParenthesizedExpression") {
|
|
5185
5699
|
const container = rightName === "ParenthesizedExpression" && right.firstChild && right.firstChild.name === "TupleExpression" ? right.firstChild : right;
|
|
5186
5700
|
for (const elt of namedChildren(container)) {
|
|
5187
|
-
const ev = evalExpr(elt,
|
|
5701
|
+
const ev = evalExpr(elt, env2);
|
|
5188
5702
|
if (ev !== null && ev === lv) return true;
|
|
5189
5703
|
}
|
|
5190
5704
|
return false;
|
|
5191
5705
|
}
|
|
5192
|
-
const rv = evalExpr(right,
|
|
5706
|
+
const rv = evalExpr(right, env2);
|
|
5193
5707
|
if (rv !== null) return rv.includes(lv);
|
|
5194
5708
|
return null;
|
|
5195
5709
|
}
|
|
5196
5710
|
if (opText === ">" || opText === ">=" || opText === "<" || opText === "<=") {
|
|
5197
|
-
const lv = evalExpr(left,
|
|
5198
|
-
const rv = evalExpr(right,
|
|
5711
|
+
const lv = evalExpr(left, env2);
|
|
5712
|
+
const rv = evalExpr(right, env2);
|
|
5199
5713
|
if (lv === null || rv === null) return null;
|
|
5200
5714
|
const ln = parseInt(lv, 10);
|
|
5201
5715
|
const rn = parseInt(rv, 10);
|
|
@@ -5207,71 +5721,71 @@ function evalCompare(left, opText, right, env) {
|
|
|
5207
5721
|
}
|
|
5208
5722
|
return null;
|
|
5209
5723
|
}
|
|
5210
|
-
function processStmts(stmts,
|
|
5211
|
-
for (const s of stmts) processStmt(s,
|
|
5724
|
+
function processStmts(stmts, env2, lineStarts, lines, branches) {
|
|
5725
|
+
for (const s of stmts) processStmt(s, env2, lineStarts, lines, branches);
|
|
5212
5726
|
}
|
|
5213
|
-
function invalidateEnvOnCalls(node,
|
|
5727
|
+
function invalidateEnvOnCalls(node, env2) {
|
|
5214
5728
|
const cursor = node.cursor();
|
|
5215
5729
|
cursor.iterate((n) => {
|
|
5216
5730
|
const nd = n.node;
|
|
5217
5731
|
if (nd.name !== "CallExpression") return true;
|
|
5218
5732
|
const func = nd.firstChild;
|
|
5219
5733
|
if (func && func.name === "VariableName" && !PURE_BUILTINS.has(srcSlice(func))) {
|
|
5220
|
-
for (const k of Object.keys(
|
|
5734
|
+
for (const k of Object.keys(env2.vars)) env2.vars[k] = null;
|
|
5221
5735
|
return false;
|
|
5222
5736
|
}
|
|
5223
5737
|
return true;
|
|
5224
5738
|
});
|
|
5225
5739
|
}
|
|
5226
|
-
function processStmt(stmt,
|
|
5740
|
+
function processStmt(stmt, env2, lineStarts, lines, branches) {
|
|
5227
5741
|
const name = stmt.name;
|
|
5228
5742
|
if (name === "AssignStatement") {
|
|
5229
5743
|
const target = stmt.firstChild;
|
|
5230
5744
|
if (target && target.name === "VariableName") {
|
|
5231
5745
|
const valNode = target.nextSibling ? target.nextSibling.nextSibling : null;
|
|
5232
|
-
invalidateEnvOnCalls(stmt,
|
|
5233
|
-
const val = evalExpr(valNode,
|
|
5234
|
-
|
|
5746
|
+
invalidateEnvOnCalls(stmt, env2);
|
|
5747
|
+
const val = evalExpr(valNode, env2);
|
|
5748
|
+
env2.vars[srcSlice(target)] = val;
|
|
5235
5749
|
}
|
|
5236
5750
|
markNodeLines(stmt, lines, lineStarts);
|
|
5237
5751
|
return;
|
|
5238
5752
|
}
|
|
5239
5753
|
if (name === "UpdateStatement") {
|
|
5240
5754
|
const target = stmt.firstChild;
|
|
5241
|
-
if (target && target.name === "VariableName")
|
|
5242
|
-
invalidateEnvOnCalls(stmt,
|
|
5755
|
+
if (target && target.name === "VariableName") env2.vars[srcSlice(target)] = null;
|
|
5756
|
+
invalidateEnvOnCalls(stmt, env2);
|
|
5243
5757
|
markNodeLines(stmt, lines, lineStarts);
|
|
5244
5758
|
return;
|
|
5245
5759
|
}
|
|
5246
5760
|
if (name === "IfStatement") {
|
|
5247
|
-
processIf(stmt,
|
|
5761
|
+
processIf(stmt, env2, lineStarts, lines, branches);
|
|
5248
5762
|
return;
|
|
5249
5763
|
}
|
|
5250
5764
|
if (name === "ForStatement" || name === "WhileStatement") {
|
|
5251
5765
|
markNodeLines(stmt, lines, lineStarts);
|
|
5252
5766
|
for (const body of stmt.getChildren("Body")) {
|
|
5253
|
-
processStmts(bodyStmts(body), { argv:
|
|
5767
|
+
processStmts(bodyStmts(body), { argv: env2.argv, vars: { ...env2.vars } }, lineStarts, lines, branches);
|
|
5254
5768
|
}
|
|
5255
5769
|
return;
|
|
5256
5770
|
}
|
|
5257
5771
|
if (name === "TryStatement") {
|
|
5258
5772
|
markNodeLines(stmt, lines, lineStarts);
|
|
5259
5773
|
for (const body of stmt.getChildren("Body")) {
|
|
5260
|
-
processStmts(bodyStmts(body), { argv:
|
|
5774
|
+
processStmts(bodyStmts(body), { argv: env2.argv, vars: { ...env2.vars } }, lineStarts, lines, branches);
|
|
5261
5775
|
}
|
|
5262
5776
|
return;
|
|
5263
5777
|
}
|
|
5264
5778
|
if (name === "WithStatement") {
|
|
5265
5779
|
markNodeLines(stmt, lines, lineStarts);
|
|
5266
5780
|
const body = stmt.getChild("Body");
|
|
5267
|
-
if (body) processStmts(bodyStmts(body), { argv:
|
|
5781
|
+
if (body) processStmts(bodyStmts(body), { argv: env2.argv, vars: { ...env2.vars } }, lineStarts, lines, branches);
|
|
5268
5782
|
return;
|
|
5269
5783
|
}
|
|
5270
5784
|
if (name === "MatchStatement") {
|
|
5271
5785
|
markNodeLines(stmt, lines, lineStarts);
|
|
5272
5786
|
for (const clause of stmt.getChildren("MatchClause")) {
|
|
5273
5787
|
const body = clause.getChild("Body");
|
|
5274
|
-
if (body) processStmts(bodyStmts(body), { argv:
|
|
5788
|
+
if (body) processStmts(bodyStmts(body), { argv: env2.argv, vars: { ...env2.vars } }, lineStarts, lines, branches);
|
|
5275
5789
|
}
|
|
5276
5790
|
return;
|
|
5277
5791
|
}
|
|
@@ -5280,7 +5794,7 @@ function processStmt(stmt, env, lineStarts, lines, branches) {
|
|
|
5280
5794
|
return;
|
|
5281
5795
|
}
|
|
5282
5796
|
if (name === "ExpressionStatement") {
|
|
5283
|
-
invalidateEnvOnCalls(stmt,
|
|
5797
|
+
invalidateEnvOnCalls(stmt, env2);
|
|
5284
5798
|
}
|
|
5285
5799
|
markNodeLines(stmt, lines, lineStarts);
|
|
5286
5800
|
}
|
|
@@ -5300,7 +5814,7 @@ function bodyStmts(body) {
|
|
|
5300
5814
|
}
|
|
5301
5815
|
return out;
|
|
5302
5816
|
}
|
|
5303
|
-
function processIf(stmt,
|
|
5817
|
+
function processIf(stmt, env2, lineStarts, lines, branches) {
|
|
5304
5818
|
const sections = [];
|
|
5305
5819
|
let c = stmt.firstChild;
|
|
5306
5820
|
while (c) {
|
|
@@ -5315,17 +5829,17 @@ function processIf(stmt, env, lineStarts, lines, branches) {
|
|
|
5315
5829
|
}
|
|
5316
5830
|
c = c.nextSibling;
|
|
5317
5831
|
}
|
|
5318
|
-
processIfSections(stmt, sections, 0,
|
|
5832
|
+
processIfSections(stmt, sections, 0, env2, lineStarts, lines, branches);
|
|
5319
5833
|
}
|
|
5320
|
-
function processIfSections(_stmt, sections, idx,
|
|
5834
|
+
function processIfSections(_stmt, sections, idx, env2, lineStarts, lines, branches) {
|
|
5321
5835
|
if (idx >= sections.length) return;
|
|
5322
5836
|
const s = sections[idx];
|
|
5323
5837
|
if (s.cond) markNodeLines(s.cond, lines, lineStarts);
|
|
5324
5838
|
if (s.isElse) {
|
|
5325
|
-
if (s.body) processStmts(bodyStmts(s.body),
|
|
5839
|
+
if (s.body) processStmts(bodyStmts(s.body), env2, lineStarts, lines, branches);
|
|
5326
5840
|
return;
|
|
5327
5841
|
}
|
|
5328
|
-
const cond = s.cond ? evalCondition(s.cond,
|
|
5842
|
+
const cond = s.cond ? evalCondition(s.cond, env2) : null;
|
|
5329
5843
|
branches.push({
|
|
5330
5844
|
kind: "if",
|
|
5331
5845
|
label: s.cond ? srcSlice(s.cond) : "",
|
|
@@ -5333,18 +5847,18 @@ function processIfSections(_stmt, sections, idx, env, lineStarts, lines, branche
|
|
|
5333
5847
|
reachable: cond !== false
|
|
5334
5848
|
});
|
|
5335
5849
|
if (cond === true) {
|
|
5336
|
-
if (s.body) processStmts(bodyStmts(s.body),
|
|
5850
|
+
if (s.body) processStmts(bodyStmts(s.body), env2, lineStarts, lines, branches);
|
|
5337
5851
|
return;
|
|
5338
5852
|
}
|
|
5339
5853
|
if (cond === false) {
|
|
5340
|
-
processIfSections(_stmt, sections, idx + 1,
|
|
5854
|
+
processIfSections(_stmt, sections, idx + 1, env2, lineStarts, lines, branches);
|
|
5341
5855
|
return;
|
|
5342
5856
|
}
|
|
5343
|
-
if (s.body) processStmts(bodyStmts(s.body),
|
|
5857
|
+
if (s.body) processStmts(bodyStmts(s.body), env2, lineStarts, lines, branches);
|
|
5344
5858
|
for (let j = idx + 1; j < sections.length; j++) {
|
|
5345
5859
|
const sj = sections[j];
|
|
5346
5860
|
if (sj.cond) markNodeLines(sj.cond, lines, lineStarts);
|
|
5347
|
-
if (sj.body) processStmts(bodyStmts(sj.body),
|
|
5861
|
+
if (sj.body) processStmts(bodyStmts(sj.body), env2, lineStarts, lines, branches);
|
|
5348
5862
|
}
|
|
5349
5863
|
}
|
|
5350
5864
|
function parseShellString(s) {
|
|
@@ -5520,7 +6034,7 @@ var init_python_backend = __esm({
|
|
|
5520
6034
|
SOURCE = c;
|
|
5521
6035
|
const sourceLines = c.split("\n");
|
|
5522
6036
|
const lineStarts = buildLineStarts(c);
|
|
5523
|
-
const
|
|
6037
|
+
const env2 = makeEnv(entryArgs || []);
|
|
5524
6038
|
const lines = /* @__PURE__ */ new Set();
|
|
5525
6039
|
const branches = [];
|
|
5526
6040
|
if (sourceLines.length > MAX_LINES) {
|
|
@@ -5547,7 +6061,7 @@ var init_python_backend = __esm({
|
|
|
5547
6061
|
};
|
|
5548
6062
|
}
|
|
5549
6063
|
const stmts = bodyStmts(tree);
|
|
5550
|
-
processStmts(stmts,
|
|
6064
|
+
processStmts(stmts, env2, lineStarts, lines, branches);
|
|
5551
6065
|
const reachable = reconstruct(sourceLines, lines);
|
|
5552
6066
|
let calls = extractCallsFromTree(tree, lines);
|
|
5553
6067
|
if (calls.length === 0) calls = extractCallsRegex(c);
|
|
@@ -5775,7 +6289,7 @@ function tokenize(content) {
|
|
|
5775
6289
|
}
|
|
5776
6290
|
return stmts;
|
|
5777
6291
|
}
|
|
5778
|
-
function evalExpr2(text,
|
|
6292
|
+
function evalExpr2(text, env2) {
|
|
5779
6293
|
const isSingleQuoted = text.length >= 2 && text[0] === "'" && text[text.length - 1] === "'";
|
|
5780
6294
|
if (text.length >= 2 && (text[0] === '"' || text[0] === "'") && text[text.length - 1] === text[0]) {
|
|
5781
6295
|
text = text.slice(1, -1);
|
|
@@ -5791,19 +6305,19 @@ function evalExpr2(text, env) {
|
|
|
5791
6305
|
const dm = inner.match(/^([A-Za-z_][A-Za-z0-9_]*|\d+):?-(.*)$/s);
|
|
5792
6306
|
if (dm) {
|
|
5793
6307
|
const key = /^\d+$/.test(dm[1]) ? `$${dm[1]}` : dm[1];
|
|
5794
|
-
const bound =
|
|
6308
|
+
const bound = env2.get(key);
|
|
5795
6309
|
if (bound && !(bound.kind === "concrete" && !bound.value)) {
|
|
5796
6310
|
result.push(bound);
|
|
5797
6311
|
} else {
|
|
5798
|
-
result.push(evalExpr2(dm[2],
|
|
6312
|
+
result.push(evalExpr2(dm[2], env2));
|
|
5799
6313
|
}
|
|
5800
6314
|
continue;
|
|
5801
6315
|
}
|
|
5802
6316
|
if (/^\d+$/.test(inner)) {
|
|
5803
|
-
const v =
|
|
6317
|
+
const v = env2.get(`$${inner}`);
|
|
5804
6318
|
result.push(v || svalSym(`$${inner}`));
|
|
5805
6319
|
} else {
|
|
5806
|
-
const v =
|
|
6320
|
+
const v = env2.get(inner);
|
|
5807
6321
|
result.push(v || svalSym(inner));
|
|
5808
6322
|
}
|
|
5809
6323
|
continue;
|
|
@@ -5812,7 +6326,7 @@ function evalExpr2(text, env) {
|
|
|
5812
6326
|
if (bare) {
|
|
5813
6327
|
const varName = bare[1];
|
|
5814
6328
|
const key = /^\d+$/.test(varName) ? `$${varName}` : varName;
|
|
5815
|
-
const v =
|
|
6329
|
+
const v = env2.get(key);
|
|
5816
6330
|
result.push(v || svalSym(p));
|
|
5817
6331
|
continue;
|
|
5818
6332
|
}
|
|
@@ -5822,13 +6336,13 @@ function evalExpr2(text, env) {
|
|
|
5822
6336
|
return fold(svalExpr(result));
|
|
5823
6337
|
}
|
|
5824
6338
|
function initEnv(entryArgs) {
|
|
5825
|
-
const
|
|
6339
|
+
const env2 = /* @__PURE__ */ new Map();
|
|
5826
6340
|
if (entryArgs && entryArgs.length) {
|
|
5827
|
-
entryArgs.forEach((a, idx) =>
|
|
5828
|
-
|
|
5829
|
-
|
|
6341
|
+
entryArgs.forEach((a, idx) => env2.set(`$${idx + 1}`, svalConc(a)));
|
|
6342
|
+
env2.set("$@", svalConc(entryArgs.join(" ")));
|
|
6343
|
+
env2.set("$*", svalConc(entryArgs.join(" ")));
|
|
5830
6344
|
}
|
|
5831
|
-
return
|
|
6345
|
+
return env2;
|
|
5832
6346
|
}
|
|
5833
6347
|
function globToRegex(pattern) {
|
|
5834
6348
|
let out = "^";
|
|
@@ -5886,12 +6400,12 @@ function evalNumericCompare(op, left, right) {
|
|
|
5886
6400
|
return null;
|
|
5887
6401
|
}
|
|
5888
6402
|
}
|
|
5889
|
-
function resolveVarSide(tok,
|
|
6403
|
+
function resolveVarSide(tok, env2) {
|
|
5890
6404
|
if (!tok.startsWith("$")) return tok;
|
|
5891
|
-
const ev = evalExpr2(tok,
|
|
6405
|
+
const ev = evalExpr2(tok, env2);
|
|
5892
6406
|
return ev.kind === "concrete" ? ev.value : null;
|
|
5893
6407
|
}
|
|
5894
|
-
function evalCondition2(cond,
|
|
6408
|
+
function evalCondition2(cond, env2) {
|
|
5895
6409
|
let inner = cond.trim().replace(/^\[\[?|\]\]?$/g, "").trim();
|
|
5896
6410
|
if (/^-[A-Za-z]\s/.test(inner) || inner.startsWith("-d") || inner.startsWith("-f")) return null;
|
|
5897
6411
|
const innerQ = inner.replace(/"/g, "").replace(/'/g, "");
|
|
@@ -5901,8 +6415,8 @@ function evalCondition2(cond, env) {
|
|
|
5901
6415
|
if (!opm) continue;
|
|
5902
6416
|
const left2 = innerQ.slice(0, opm.index).trim();
|
|
5903
6417
|
const right2 = innerQ.slice(opm.index + opm[0].length).trim();
|
|
5904
|
-
const lv2 = resolveVarSide(left2,
|
|
5905
|
-
const rv2 = resolveVarSide(right2,
|
|
6418
|
+
const lv2 = resolveVarSide(left2, env2);
|
|
6419
|
+
const rv2 = resolveVarSide(right2, env2);
|
|
5906
6420
|
if (lv2 === null || rv2 === null) return null;
|
|
5907
6421
|
return evalNumericCompare(op2, lv2, rv2);
|
|
5908
6422
|
}
|
|
@@ -5913,7 +6427,7 @@ function evalCondition2(cond, env) {
|
|
|
5913
6427
|
let right = sm[3].trim();
|
|
5914
6428
|
if (op === "=~") {
|
|
5915
6429
|
if (right.startsWith("/") && right.endsWith("/")) right = right.slice(1, -1);
|
|
5916
|
-
const lv2 = resolveVarSide(left,
|
|
6430
|
+
const lv2 = resolveVarSide(left, env2);
|
|
5917
6431
|
if (lv2 === null) return null;
|
|
5918
6432
|
try {
|
|
5919
6433
|
return new RegExp(right).test(lv2);
|
|
@@ -5921,8 +6435,8 @@ function evalCondition2(cond, env) {
|
|
|
5921
6435
|
return null;
|
|
5922
6436
|
}
|
|
5923
6437
|
}
|
|
5924
|
-
const lv = resolveVarSide(left,
|
|
5925
|
-
const rv = resolveVarSide(right,
|
|
6438
|
+
const lv = resolveVarSide(left, env2);
|
|
6439
|
+
const rv = resolveVarSide(right, env2);
|
|
5926
6440
|
if (lv === null || rv === null) return null;
|
|
5927
6441
|
if (op === "!=") return lv !== rv;
|
|
5928
6442
|
return lv === rv;
|
|
@@ -5932,7 +6446,7 @@ function symbolicProcess(content, entryArgs) {
|
|
|
5932
6446
|
const stmts = tokenize(content);
|
|
5933
6447
|
if (!stmts.some((s) => s.kind === "case" || s.kind === "if" || s.kind === "assign")) return null;
|
|
5934
6448
|
if (stmts.some((s) => !s.modelable)) return null;
|
|
5935
|
-
const
|
|
6449
|
+
const env2 = initEnv(entryArgs);
|
|
5936
6450
|
let linesBudget = 0;
|
|
5937
6451
|
let branchesBudget = 0;
|
|
5938
6452
|
let modelable = false;
|
|
@@ -5942,9 +6456,9 @@ function symbolicProcess(content, entryArgs) {
|
|
|
5942
6456
|
if (linesBudget > MAX_LINES2) return null;
|
|
5943
6457
|
if (s.kind === "assign") {
|
|
5944
6458
|
modelable = true;
|
|
5945
|
-
if (
|
|
5946
|
-
const v = evalExpr2(s.rhs,
|
|
5947
|
-
|
|
6459
|
+
if (env2.size >= MAX_VARS) return null;
|
|
6460
|
+
const v = evalExpr2(s.rhs, env2);
|
|
6461
|
+
env2.set(s.name, fold(v));
|
|
5948
6462
|
out.push(s.line);
|
|
5949
6463
|
continue;
|
|
5950
6464
|
}
|
|
@@ -5952,7 +6466,7 @@ function symbolicProcess(content, entryArgs) {
|
|
|
5952
6466
|
modelable = true;
|
|
5953
6467
|
branchesBudget += s.branches.length;
|
|
5954
6468
|
if (branchesBudget > MAX_BRANCHES) return null;
|
|
5955
|
-
const selVal = fold(evalExpr2(s.selector,
|
|
6469
|
+
const selVal = fold(evalExpr2(s.selector, env2));
|
|
5956
6470
|
if (selVal.kind !== "concrete") return null;
|
|
5957
6471
|
const concrete = selVal.value || "";
|
|
5958
6472
|
let selected = null;
|
|
@@ -5979,7 +6493,7 @@ esac`);
|
|
|
5979
6493
|
modelable = true;
|
|
5980
6494
|
branchesBudget++;
|
|
5981
6495
|
if (branchesBudget > MAX_BRANCHES) return null;
|
|
5982
|
-
const truth = evalCondition2(s.cond,
|
|
6496
|
+
const truth = evalCondition2(s.cond, env2);
|
|
5983
6497
|
if (truth === null) return null;
|
|
5984
6498
|
const chosen = truth ? s.thenBody : s.elseBody;
|
|
5985
6499
|
if (chosen === null) return null;
|
|
@@ -6512,9 +7026,9 @@ var init_tracker = __esm({
|
|
|
6512
7026
|
});
|
|
6513
7027
|
|
|
6514
7028
|
// src/engine/script-content-analyzer.ts
|
|
6515
|
-
import { statSync as statSync4, existsSync as
|
|
6516
|
-
import { resolve as
|
|
6517
|
-
import { homedir as
|
|
7029
|
+
import { statSync as statSync4, existsSync as existsSync12 } from "fs";
|
|
7030
|
+
import { resolve as resolve10, join as join11, isAbsolute as isAbsolute3 } from "path";
|
|
7031
|
+
import { homedir as homedir4 } from "os";
|
|
6518
7032
|
function emptyChain() {
|
|
6519
7033
|
return {
|
|
6520
7034
|
nodes: [],
|
|
@@ -6625,7 +7139,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
6625
7139
|
if (looksLikeScriptPath(tok)) {
|
|
6626
7140
|
try {
|
|
6627
7141
|
const resolved = resolvePath2(tok.replace(/^['"]|['"]$/g, ""));
|
|
6628
|
-
if (
|
|
7142
|
+
if (existsSync12(resolved)) {
|
|
6629
7143
|
const stat = statSync4(resolved);
|
|
6630
7144
|
if (stat.isFile()) return resolved;
|
|
6631
7145
|
}
|
|
@@ -6639,7 +7153,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
6639
7153
|
const p = m[1];
|
|
6640
7154
|
try {
|
|
6641
7155
|
const resolved = resolvePath2(p);
|
|
6642
|
-
if (
|
|
7156
|
+
if (existsSync12(resolved)) {
|
|
6643
7157
|
const stat = statSync4(resolved);
|
|
6644
7158
|
if (stat.isFile()) return resolved;
|
|
6645
7159
|
}
|
|
@@ -6655,7 +7169,7 @@ function extractInlineScriptPath(actionDetail) {
|
|
|
6655
7169
|
let resolved;
|
|
6656
7170
|
try {
|
|
6657
7171
|
resolved = resolvePath2(p);
|
|
6658
|
-
if (
|
|
7172
|
+
if (existsSync12(resolved)) {
|
|
6659
7173
|
const stat = statSync4(resolved);
|
|
6660
7174
|
if (stat.isFile()) return resolved;
|
|
6661
7175
|
}
|
|
@@ -6696,9 +7210,9 @@ function shlexSplit(s) {
|
|
|
6696
7210
|
function resolvePath2(p) {
|
|
6697
7211
|
let expanded = p;
|
|
6698
7212
|
if (expanded.startsWith("~/") || expanded === "~") {
|
|
6699
|
-
expanded =
|
|
7213
|
+
expanded = join11(homedir4(), expanded.slice(1));
|
|
6700
7214
|
}
|
|
6701
|
-
return
|
|
7215
|
+
return resolve10(expanded);
|
|
6702
7216
|
}
|
|
6703
7217
|
function scanExtensionPatterns(ext, content) {
|
|
6704
7218
|
const pats = ext?.extra_command_patterns;
|
|
@@ -6819,8 +7333,8 @@ function analyzeScriptContent2(input, ext) {
|
|
|
6819
7333
|
resolvedPath = inline;
|
|
6820
7334
|
isInline = true;
|
|
6821
7335
|
}
|
|
6822
|
-
if (resolvedPath && !
|
|
6823
|
-
resolvedPath =
|
|
7336
|
+
if (resolvedPath && !isAbsolute3(resolvedPath) && !resolvedPath.startsWith("~/")) {
|
|
7337
|
+
resolvedPath = join11(input.cwd || process.cwd(), resolvedPath);
|
|
6824
7338
|
}
|
|
6825
7339
|
const l1Adapter = (content) => {
|
|
6826
7340
|
const j = scanDangerousCommandPatterns("bash", content, input.osType);
|
|
@@ -6946,16 +7460,16 @@ __export(token_stats_exports, {
|
|
|
6946
7460
|
recordTokenUsage: () => recordTokenUsage,
|
|
6947
7461
|
resetTokenStats: () => resetTokenStats
|
|
6948
7462
|
});
|
|
6949
|
-
import { readFileSync as
|
|
7463
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync2, existsSync as existsSync13, mkdirSync as mkdirSync3, unlinkSync as unlinkSync2 } from "fs";
|
|
6950
7464
|
function getStatsPath() {
|
|
6951
7465
|
const envPath = process.env[ENV_STATS_PATH];
|
|
6952
7466
|
if (envPath) return envPath;
|
|
6953
7467
|
return getTokenStatsPath();
|
|
6954
7468
|
}
|
|
6955
7469
|
function loadAllRecords(statsPath) {
|
|
6956
|
-
if (!
|
|
7470
|
+
if (!existsSync13(statsPath)) return [];
|
|
6957
7471
|
try {
|
|
6958
|
-
const data = JSON.parse(
|
|
7472
|
+
const data = JSON.parse(readFileSync13(statsPath, "utf-8"));
|
|
6959
7473
|
if (Array.isArray(data)) return data;
|
|
6960
7474
|
if (data && Array.isArray(data.records)) return data.records;
|
|
6961
7475
|
return [];
|
|
@@ -6966,7 +7480,7 @@ function loadAllRecords(statsPath) {
|
|
|
6966
7480
|
function saveRecords(statsPath, records) {
|
|
6967
7481
|
try {
|
|
6968
7482
|
const dir = statsPath.substring(0, statsPath.lastIndexOf("/"));
|
|
6969
|
-
if (dir && !
|
|
7483
|
+
if (dir && !existsSync13(dir)) mkdirSync3(dir, { recursive: true });
|
|
6970
7484
|
writeFileSync2(statsPath, JSON.stringify(records, null, 2), "utf-8");
|
|
6971
7485
|
} catch (e) {
|
|
6972
7486
|
}
|
|
@@ -7093,7 +7607,7 @@ function getTokenTrend(days = 0, startDate, endDate) {
|
|
|
7093
7607
|
}
|
|
7094
7608
|
function resetTokenStats() {
|
|
7095
7609
|
const statsPath = getStatsPath();
|
|
7096
|
-
if (
|
|
7610
|
+
if (existsSync13(statsPath)) {
|
|
7097
7611
|
try {
|
|
7098
7612
|
unlinkSync2(statsPath);
|
|
7099
7613
|
} catch {
|
|
@@ -7112,7 +7626,7 @@ var init_token_stats = __esm({
|
|
|
7112
7626
|
});
|
|
7113
7627
|
|
|
7114
7628
|
// src/engine/llm-analyzer.ts
|
|
7115
|
-
import {
|
|
7629
|
+
import { openSync as openSync2, writeSync as writeSync2, closeSync as closeSync2, constants as fsConstants } from "fs";
|
|
7116
7630
|
import OpenAI from "openai";
|
|
7117
7631
|
async function runLLMAnalysis(input, previous) {
|
|
7118
7632
|
if (!isLLMAvailable()) {
|
|
@@ -7128,7 +7642,15 @@ async function runLLMAnalysis(input, previous) {
|
|
|
7128
7642
|
};
|
|
7129
7643
|
}
|
|
7130
7644
|
const globalConfig = getLLMConfig();
|
|
7131
|
-
|
|
7645
|
+
let perRequest = input.llmConfig;
|
|
7646
|
+
if (perRequest?.apiKey) {
|
|
7647
|
+
const [okUrl, why] = validateLlmBaseUrl(String(perRequest.baseUrl || ""));
|
|
7648
|
+
if (!okUrl) {
|
|
7649
|
+
console.warn("[AgentMoss] \u5FFD\u7565\u4E0D\u88AB\u5141\u8BB8\u7684 per-request llmConfig.baseUrl:", why);
|
|
7650
|
+
perRequest = { ...perRequest, baseUrl: void 0 };
|
|
7651
|
+
}
|
|
7652
|
+
}
|
|
7653
|
+
const config = perRequest?.apiKey ? { ...globalConfig, ...perRequest } : globalConfig;
|
|
7132
7654
|
const rawDetail = input.aNext.actionDetail.replace(/^terminal-\w+:\s*command=([^,]+).*/, "$1").trim();
|
|
7133
7655
|
const cacheKey = `${input.aNext.actionType}:${rawDetail || input.aNext.actionDetail}`;
|
|
7134
7656
|
const cached2 = llmCache.get(cacheKey);
|
|
@@ -7157,6 +7679,10 @@ async function runLLMAnalysis(input, previous) {
|
|
|
7157
7679
|
}
|
|
7158
7680
|
function logPrompt(prompt, aNext, logPath) {
|
|
7159
7681
|
if (!logPath) return;
|
|
7682
|
+
if (!pathWithin(logPath, logRoots())) {
|
|
7683
|
+
console.warn("[AgentMoss] \u5FFD\u7565\u8D8A\u754C\u7684 llm_log_path\uFF08\u4E0D\u5728\u5141\u8BB8\u6839\u76EE\u5F55\u5185\uFF09:", logPath);
|
|
7684
|
+
return;
|
|
7685
|
+
}
|
|
7160
7686
|
try {
|
|
7161
7687
|
const actionType = aNext.actionType || "unknown";
|
|
7162
7688
|
const actionDetail = (aNext.actionDetail || "").slice(0, 100);
|
|
@@ -7164,7 +7690,14 @@ function logPrompt(prompt, aNext, logPath) {
|
|
|
7164
7690
|
${prompt}
|
|
7165
7691
|
--- END PROMPT ---
|
|
7166
7692
|
`;
|
|
7167
|
-
|
|
7693
|
+
let flags = fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_APPEND;
|
|
7694
|
+
if (fsConstants.O_NOFOLLOW) flags |= fsConstants.O_NOFOLLOW;
|
|
7695
|
+
const fd = openSync2(logPath, flags, 384);
|
|
7696
|
+
try {
|
|
7697
|
+
writeSync2(fd, line);
|
|
7698
|
+
} finally {
|
|
7699
|
+
closeSync2(fd);
|
|
7700
|
+
}
|
|
7168
7701
|
} catch (e) {
|
|
7169
7702
|
console.warn("[AgentMoss] Failed to write LLM prompt to log:", e);
|
|
7170
7703
|
}
|
|
@@ -7323,7 +7856,7 @@ async function analyzeWithLLM(prompt, config) {
|
|
|
7323
7856
|
}
|
|
7324
7857
|
if (attempt < maxRetries) {
|
|
7325
7858
|
console.error(`[AgentMoss] LLM call failed (attempt ${attempt + 1}/${maxRetries + 1}), retrying in ${retryCfg.retryInterval}s:`, err.message);
|
|
7326
|
-
await new Promise((
|
|
7859
|
+
await new Promise((resolve12) => setTimeout(resolve12, retryCfg.retryInterval * 1e3));
|
|
7327
7860
|
} else {
|
|
7328
7861
|
clearTimeout(totalTimeoutTimer);
|
|
7329
7862
|
console.error("[AgentMoss] LLM call failed after all retries:", err.message);
|
|
@@ -7339,6 +7872,7 @@ var init_llm_analyzer = __esm({
|
|
|
7339
7872
|
"src/engine/llm-analyzer.ts"() {
|
|
7340
7873
|
"use strict";
|
|
7341
7874
|
init_esm_shims();
|
|
7875
|
+
init_security_policy();
|
|
7342
7876
|
init_config();
|
|
7343
7877
|
init_skill_loader();
|
|
7344
7878
|
init_template_loader();
|
|
@@ -7350,9 +7884,9 @@ var init_llm_analyzer = __esm({
|
|
|
7350
7884
|
});
|
|
7351
7885
|
|
|
7352
7886
|
// src/brain/rule-store.ts
|
|
7353
|
-
import { existsSync as
|
|
7354
|
-
import { join as
|
|
7355
|
-
import { homedir as
|
|
7887
|
+
import { existsSync as existsSync14, readFileSync as readFileSync14, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4 } from "fs";
|
|
7888
|
+
import { join as join12 } from "path";
|
|
7889
|
+
import { homedir as homedir5 } from "os";
|
|
7356
7890
|
function getRulesPath() {
|
|
7357
7891
|
const envPath = process.env[ENV_RULES_PATH];
|
|
7358
7892
|
if (envPath) return envPath;
|
|
@@ -7370,7 +7904,7 @@ var init_rule_store = __esm({
|
|
|
7370
7904
|
"src/brain/rule-store.ts"() {
|
|
7371
7905
|
"use strict";
|
|
7372
7906
|
init_esm_shims();
|
|
7373
|
-
DEFAULT_RULES_PATH =
|
|
7907
|
+
DEFAULT_RULES_PATH = join12(homedir5(), ".agentmoss", "brain", "rules.json");
|
|
7374
7908
|
ENV_RULES_PATH = "AGENT_MOSS_BRAIN_RULES_PATH";
|
|
7375
7909
|
STATUS_DRAFT = "draft";
|
|
7376
7910
|
STATUS_APPROVED = "approved";
|
|
@@ -7387,11 +7921,11 @@ var init_rule_store = __esm({
|
|
|
7387
7921
|
this.data = this.load();
|
|
7388
7922
|
}
|
|
7389
7923
|
load() {
|
|
7390
|
-
if (!
|
|
7924
|
+
if (!existsSync14(this.path)) {
|
|
7391
7925
|
return { version: 1, rules: [], pattern_candidates: [] };
|
|
7392
7926
|
}
|
|
7393
7927
|
try {
|
|
7394
|
-
const raw = JSON.parse(
|
|
7928
|
+
const raw = JSON.parse(readFileSync14(this.path, "utf-8"));
|
|
7395
7929
|
return {
|
|
7396
7930
|
version: raw.version || 1,
|
|
7397
7931
|
rules: raw.rules || [],
|
|
@@ -7403,7 +7937,7 @@ var init_rule_store = __esm({
|
|
|
7403
7937
|
}
|
|
7404
7938
|
save() {
|
|
7405
7939
|
const dir = this.path.substring(0, this.path.lastIndexOf("/"));
|
|
7406
|
-
if (dir)
|
|
7940
|
+
if (dir) mkdirSync4(dir, { recursive: true });
|
|
7407
7941
|
writeFileSync3(this.path, JSON.stringify(this.data, null, 2), "utf-8");
|
|
7408
7942
|
}
|
|
7409
7943
|
addRule(rule) {
|
|
@@ -7985,9 +8519,9 @@ var init_reviewer = __esm({
|
|
|
7985
8519
|
});
|
|
7986
8520
|
|
|
7987
8521
|
// src/brain/skill-manager.ts
|
|
7988
|
-
import { existsSync as
|
|
7989
|
-
import { homedir as
|
|
7990
|
-
import { join as
|
|
8522
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync15, renameSync, writeFileSync as writeFileSync4 } from "fs";
|
|
8523
|
+
import { homedir as homedir6 } from "os";
|
|
8524
|
+
import { join as join13 } from "path";
|
|
7991
8525
|
import { randomUUID } from "crypto";
|
|
7992
8526
|
function getMetaPath(override) {
|
|
7993
8527
|
return override || process.env[ENV_SKILL_META_PATH] || DEFAULT_SKILL_META_PATH;
|
|
@@ -7997,14 +8531,14 @@ var init_skill_manager = __esm({
|
|
|
7997
8531
|
"src/brain/skill-manager.ts"() {
|
|
7998
8532
|
"use strict";
|
|
7999
8533
|
init_esm_shims();
|
|
8000
|
-
DEFAULT_SKILL_META_PATH =
|
|
8534
|
+
DEFAULT_SKILL_META_PATH = join13(homedir6(), ".agentmoss", "brain", "skill_meta.json");
|
|
8001
8535
|
ENV_SKILL_META_PATH = "AGENT_MOSS_BRAIN_SKILL_META_PATH";
|
|
8002
8536
|
BrainSkillManager = class {
|
|
8003
8537
|
constructor(skillsDir, metaPath) {
|
|
8004
8538
|
this.skillsDir = skillsDir;
|
|
8005
8539
|
this.metaPath = getMetaPath(metaPath);
|
|
8006
8540
|
try {
|
|
8007
|
-
|
|
8541
|
+
mkdirSync5(join13(this.metaPath, ".."), { recursive: true });
|
|
8008
8542
|
} catch {
|
|
8009
8543
|
}
|
|
8010
8544
|
this.load();
|
|
@@ -8014,9 +8548,9 @@ var init_skill_manager = __esm({
|
|
|
8014
8548
|
skills = [];
|
|
8015
8549
|
metaPath;
|
|
8016
8550
|
load() {
|
|
8017
|
-
if (!
|
|
8551
|
+
if (!existsSync15(this.metaPath)) return;
|
|
8018
8552
|
try {
|
|
8019
|
-
const data = JSON.parse(
|
|
8553
|
+
const data = JSON.parse(readFileSync15(this.metaPath, "utf-8"));
|
|
8020
8554
|
this.skills = data.skills || [];
|
|
8021
8555
|
} catch {
|
|
8022
8556
|
this.skills = [];
|
|
@@ -8039,7 +8573,7 @@ var init_skill_manager = __esm({
|
|
|
8039
8573
|
let changed = false;
|
|
8040
8574
|
for (const sk of this.skills) {
|
|
8041
8575
|
if (sk.status !== "active") continue;
|
|
8042
|
-
if (!
|
|
8576
|
+
if (!existsSync15(join13(this.skillsDir, `${sk.name}.md`))) {
|
|
8043
8577
|
sk.status = "stale";
|
|
8044
8578
|
changed = true;
|
|
8045
8579
|
}
|
|
@@ -8050,9 +8584,9 @@ var init_skill_manager = __esm({
|
|
|
8050
8584
|
addSkill(skill) {
|
|
8051
8585
|
const id = skill.id || randomUUID();
|
|
8052
8586
|
const name = skill.name || `brain_${id.slice(0, 8)}`;
|
|
8053
|
-
if (!
|
|
8054
|
-
const mdPath =
|
|
8055
|
-
if (
|
|
8587
|
+
if (!existsSync15(this.skillsDir)) return "";
|
|
8588
|
+
const mdPath = join13(this.skillsDir, `${name}.md`);
|
|
8589
|
+
if (existsSync15(mdPath)) return "";
|
|
8056
8590
|
try {
|
|
8057
8591
|
writeFileSync4(mdPath, skill.content, "utf-8");
|
|
8058
8592
|
} catch {
|
|
@@ -8101,12 +8635,12 @@ var init_skill_manager = __esm({
|
|
|
8101
8635
|
const out = [];
|
|
8102
8636
|
for (const sk of this.skills) {
|
|
8103
8637
|
if (sk.origin_node !== "local" || sk.status !== "active") continue;
|
|
8104
|
-
const mdPath =
|
|
8105
|
-
if (!
|
|
8638
|
+
const mdPath = join13(this.skillsDir, `${sk.name}.md`);
|
|
8639
|
+
if (!existsSync15(mdPath)) continue;
|
|
8106
8640
|
out.push({
|
|
8107
8641
|
name: sk.name,
|
|
8108
8642
|
category: sk.category || "",
|
|
8109
|
-
content:
|
|
8643
|
+
content: readFileSync15(mdPath, "utf-8"),
|
|
8110
8644
|
keywords: sk.keywords || []
|
|
8111
8645
|
});
|
|
8112
8646
|
}
|
|
@@ -8216,11 +8750,11 @@ __export(contributor_exports, {
|
|
|
8216
8750
|
runGit: () => runGit,
|
|
8217
8751
|
writeExportFiles: () => writeExportFiles
|
|
8218
8752
|
});
|
|
8219
|
-
import { mkdirSync as
|
|
8220
|
-
import { tmpdir } from "os";
|
|
8221
|
-
import { join as
|
|
8753
|
+
import { mkdirSync as mkdirSync6, mkdtempSync, rmSync, writeFileSync as writeFileSync5 } from "fs";
|
|
8754
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
8755
|
+
import { join as join14 } from "path";
|
|
8222
8756
|
import { spawnSync } from "child_process";
|
|
8223
|
-
import { dirname as
|
|
8757
|
+
import { dirname as dirname10 } from "path";
|
|
8224
8758
|
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
8225
8759
|
function collectRules(store) {
|
|
8226
8760
|
return store.getActiveRules().filter((r) => EXPORT_RULE_SOURCES.includes(r.source)).map((r) => ({
|
|
@@ -8239,32 +8773,32 @@ function collectSkills(skillMgr) {
|
|
|
8239
8773
|
}
|
|
8240
8774
|
function writeExportFiles(outDir, rules, skills) {
|
|
8241
8775
|
const written = [];
|
|
8242
|
-
const rulesDir2 =
|
|
8243
|
-
|
|
8776
|
+
const rulesDir2 = join14(outDir, "rules");
|
|
8777
|
+
mkdirSync6(rulesDir2, { recursive: true });
|
|
8244
8778
|
const byLayer = /* @__PURE__ */ new Map();
|
|
8245
8779
|
for (const r of rules) {
|
|
8246
8780
|
if (!byLayer.has(r.layer)) byLayer.set(r.layer, []);
|
|
8247
8781
|
byLayer.get(r.layer).push(r);
|
|
8248
8782
|
}
|
|
8249
8783
|
for (const layer of [...byLayer.keys()].sort((a, b) => a - b)) {
|
|
8250
|
-
const path6 =
|
|
8784
|
+
const path6 = join14(rulesDir2, `l${layer}_brain_rules.json`);
|
|
8251
8785
|
writeFileSync5(path6, JSON.stringify(byLayer.get(layer), null, 2), "utf-8");
|
|
8252
8786
|
written.push(path6);
|
|
8253
8787
|
}
|
|
8254
8788
|
if (rules.length === 0) {
|
|
8255
|
-
const path6 =
|
|
8789
|
+
const path6 = join14(rulesDir2, "empty.txt");
|
|
8256
8790
|
writeFileSync5(path6, "(no brain rules to contribute)", "utf-8");
|
|
8257
8791
|
written.push(path6);
|
|
8258
8792
|
}
|
|
8259
|
-
const skillsDir =
|
|
8260
|
-
|
|
8793
|
+
const skillsDir = join14(outDir, "skills");
|
|
8794
|
+
mkdirSync6(skillsDir, { recursive: true });
|
|
8261
8795
|
for (const sk of skills) {
|
|
8262
|
-
const path6 =
|
|
8796
|
+
const path6 = join14(skillsDir, `${sk.name}.md`);
|
|
8263
8797
|
writeFileSync5(path6, sk.content || "", "utf-8");
|
|
8264
8798
|
written.push(path6);
|
|
8265
8799
|
}
|
|
8266
8800
|
if (skills.length === 0) {
|
|
8267
|
-
const path6 =
|
|
8801
|
+
const path6 = join14(skillsDir, "empty.txt");
|
|
8268
8802
|
writeFileSync5(path6, "(no brain skills to contribute)", "utf-8");
|
|
8269
8803
|
written.push(path6);
|
|
8270
8804
|
}
|
|
@@ -8394,7 +8928,7 @@ async function contribute(opts = {}) {
|
|
|
8394
8928
|
console.log(`[Brain] push \u76EE\u6807: ${pushTarget}`);
|
|
8395
8929
|
console.log(`[Brain] MR \u6307\u5411: ${DEFAULT_TARGET_REPO}`);
|
|
8396
8930
|
const store = new BrainRuleStore();
|
|
8397
|
-
const skillsDir = resolveAssetDir(__dirname8, "skills") ??
|
|
8931
|
+
const skillsDir = resolveAssetDir(__dirname8, "skills") ?? join14(__dirname8, "..", "..", "agent_moss", "skills");
|
|
8398
8932
|
const skillMgr = new BrainSkillManager(skillsDir);
|
|
8399
8933
|
let rules;
|
|
8400
8934
|
let skills;
|
|
@@ -8409,9 +8943,9 @@ async function contribute(opts = {}) {
|
|
|
8409
8943
|
return 0;
|
|
8410
8944
|
}
|
|
8411
8945
|
console.log(`[Brain] \u5BFC\u51FA: ${rules.length} \u6761\u89C4\u5219, ${skills.length} \u4E2A Skill`);
|
|
8412
|
-
const workdir = mkdtempSync(
|
|
8946
|
+
const workdir = mkdtempSync(join14(tmpdir2(), "agentmoss-contrib-"));
|
|
8413
8947
|
try {
|
|
8414
|
-
writeExportFiles(
|
|
8948
|
+
writeExportFiles(join14(workdir, "agent_moss", "brain_contrib"), rules, skills);
|
|
8415
8949
|
console.log(`[Brain] \u63A2\u6D4B ${pushTarget} \u8BBF\u95EE\u6743\u9650 ...`);
|
|
8416
8950
|
if (!probeAccess(pushTarget)) {
|
|
8417
8951
|
const username = getCurrentUsername();
|
|
@@ -8461,7 +8995,7 @@ var init_contributor = __esm({
|
|
|
8461
8995
|
init_rule_store();
|
|
8462
8996
|
init_skill_manager();
|
|
8463
8997
|
init_asset_dir();
|
|
8464
|
-
__dirname8 =
|
|
8998
|
+
__dirname8 = dirname10(fileURLToPath9(import.meta.url));
|
|
8465
8999
|
DEFAULT_TARGET_REPO = "ssh://git@atomgit.com/kenhkl/AgentMoss.git";
|
|
8466
9000
|
CONTACT_EMAIL = "kenhkl11@hotmail.com";
|
|
8467
9001
|
TOKEN_ENV = "AGENT_MOSS_CONTRIBUTE_TOKEN";
|
|
@@ -8836,7 +9370,7 @@ function markIntegrity(actionDetail) {
|
|
|
8836
9370
|
}
|
|
8837
9371
|
return { integrity: "medium", isLowSource: false };
|
|
8838
9372
|
}
|
|
8839
|
-
function initNode(sessionId, seq, actionType, actionDetail) {
|
|
9373
|
+
function initNode(sessionId, seq, actionType, actionDetail, timestamp) {
|
|
8840
9374
|
const { integrity, isLowSource } = markIntegrity(actionDetail);
|
|
8841
9375
|
return {
|
|
8842
9376
|
sessionId,
|
|
@@ -8846,7 +9380,8 @@ function initNode(sessionId, seq, actionType, actionDetail) {
|
|
|
8846
9380
|
stage: markStage(actionDetail),
|
|
8847
9381
|
resources: extractResources(actionDetail),
|
|
8848
9382
|
integrity,
|
|
8849
|
-
isLowSource
|
|
9383
|
+
isLowSource,
|
|
9384
|
+
timestamp: timestamp || void 0
|
|
8850
9385
|
};
|
|
8851
9386
|
}
|
|
8852
9387
|
function buildSessionGraph(actionHistory, aNext, sessionId = "current") {
|
|
@@ -8856,13 +9391,21 @@ function buildSessionGraph(actionHistory, aNext, sessionId = "current") {
|
|
|
8856
9391
|
const details = [];
|
|
8857
9392
|
for (const a of actionHistory) {
|
|
8858
9393
|
const ad = String(a.actionDetail || "");
|
|
8859
|
-
if (ad) details.push({
|
|
9394
|
+
if (ad) details.push({
|
|
9395
|
+
actionType: String(a.actionType || ""),
|
|
9396
|
+
actionDetail: ad,
|
|
9397
|
+
calledAt: a.calledAt || void 0
|
|
9398
|
+
});
|
|
8860
9399
|
}
|
|
8861
9400
|
if (aNext) {
|
|
8862
|
-
details.push({
|
|
9401
|
+
details.push({
|
|
9402
|
+
actionType: String(aNext.actionType || ""),
|
|
9403
|
+
actionDetail: String(aNext.actionDetail || ""),
|
|
9404
|
+
calledAt: aNext.calledAt || void 0
|
|
9405
|
+
});
|
|
8863
9406
|
}
|
|
8864
9407
|
details.forEach((d, seq) => {
|
|
8865
|
-
const node = initNode(sessionId, seq, d.actionType, d.actionDetail);
|
|
9408
|
+
const node = initNode(sessionId, seq, d.actionType, d.actionDetail, d.calledAt);
|
|
8866
9409
|
nodes.push(node);
|
|
8867
9410
|
if (node.stage) stageFlags.add(node.stage);
|
|
8868
9411
|
});
|
|
@@ -8888,7 +9431,8 @@ function buildMultiSessionGraph(sessions, aNext) {
|
|
|
8888
9431
|
last.sessionId,
|
|
8889
9432
|
last.nodes.length,
|
|
8890
9433
|
String(aNext.actionType || ""),
|
|
8891
|
-
String(aNext.actionDetail || "")
|
|
9434
|
+
String(aNext.actionDetail || ""),
|
|
9435
|
+
aNext.calledAt || void 0
|
|
8892
9436
|
));
|
|
8893
9437
|
if (last.nodes.length > 1) {
|
|
8894
9438
|
last.edges.push({ src: last.nodes.length - 2, dst: last.nodes.length - 1, kind: "next" });
|
|
@@ -8946,6 +9490,27 @@ var init_builder = __esm({
|
|
|
8946
9490
|
});
|
|
8947
9491
|
|
|
8948
9492
|
// src/engine/formal-engine/properties.ts
|
|
9493
|
+
function parseTs(ts) {
|
|
9494
|
+
if (!ts) return null;
|
|
9495
|
+
const t = Date.parse(String(ts).trim());
|
|
9496
|
+
return Number.isFinite(t) ? t : null;
|
|
9497
|
+
}
|
|
9498
|
+
function privescExfilWindowSec() {
|
|
9499
|
+
const raw = (process.env.AGENT_MOSS_PRIVESC_EXFIL_WINDOW_SEC || "").trim();
|
|
9500
|
+
if (!raw) return 1800;
|
|
9501
|
+
const n = parseInt(raw, 10);
|
|
9502
|
+
return Number.isFinite(n) ? Math.max(0, n) : 1800;
|
|
9503
|
+
}
|
|
9504
|
+
function privescInWindow(nodes, indexes, exfilIdx, windowSec) {
|
|
9505
|
+
const before = indexes.filter((i) => i < exfilIdx);
|
|
9506
|
+
if (windowSec <= 0) return before;
|
|
9507
|
+
const exfilTs = parseTs(nodes[exfilIdx].timestamp);
|
|
9508
|
+
if (exfilTs === null) return before;
|
|
9509
|
+
return before.filter((i) => {
|
|
9510
|
+
const ts = parseTs(nodes[i].timestamp);
|
|
9511
|
+
return ts === null || exfilTs - ts <= windowSec * 1e3;
|
|
9512
|
+
});
|
|
9513
|
+
}
|
|
8949
9514
|
function loadCrossSessionChains() {
|
|
8950
9515
|
if (CROSS_SESSION_CHAINS) return CROSS_SESSION_CHAINS;
|
|
8951
9516
|
const combo = loadL2().combo_chains || {};
|
|
@@ -9137,6 +9702,7 @@ function checkNeverExfilAfterPrivesc(graph) {
|
|
|
9137
9702
|
const nodes = allNodes(graph);
|
|
9138
9703
|
if (nodes.length < 2) return violations;
|
|
9139
9704
|
const witness = graph.witnessIdx;
|
|
9705
|
+
const windowSec = privescExfilWindowSec();
|
|
9140
9706
|
if (witness !== void 0) {
|
|
9141
9707
|
const evIdx = [];
|
|
9142
9708
|
nodes.forEach((n, i) => {
|
|
@@ -9144,15 +9710,17 @@ function checkNeverExfilAfterPrivesc(graph) {
|
|
|
9144
9710
|
});
|
|
9145
9711
|
if (evIdx.length === 0) return violations;
|
|
9146
9712
|
const firstEv = Math.min(...evIdx);
|
|
9147
|
-
|
|
9148
|
-
|
|
9149
|
-
if (isPrivescNode(
|
|
9150
|
-
}
|
|
9151
|
-
|
|
9713
|
+
const privescIdx = [];
|
|
9714
|
+
nodes.forEach((n, i) => {
|
|
9715
|
+
if (isPrivescNode(n)) privescIdx.push(i);
|
|
9716
|
+
});
|
|
9717
|
+
const candidates = privescInWindow(nodes, privescIdx, firstEv, windowSec);
|
|
9718
|
+
if (candidates.length > 0) {
|
|
9719
|
+
const pre = nodes[candidates[candidates.length - 1]];
|
|
9152
9720
|
const post = nodes[firstEv];
|
|
9153
9721
|
return [{
|
|
9154
9722
|
propertyId: "no-exfil-after-privesc",
|
|
9155
|
-
reason: "\u63D0\u6743\u540E\u51FA\u73B0\u5916\u4F20\uFF1A\u63D0\u6743(\u524D) \u2192 \u5916\u4F20(\u540E)\uFF0C\u8FDD\u53CD \u25A1(PRIVESC\u2192\
|
|
9723
|
+
reason: "\u63D0\u6743\u540E\u51FA\u73B0\u5916\u4F20\uFF1A\u63D0\u6743(\u524D) \u2192 \u5916\u4F20(\u540E)\uFF0C\u8FDD\u53CD \u25A1(PRIVESC\u2192\u25C7EXFIL) \u7A97\u53E3\u7EA6\u675F",
|
|
9156
9724
|
riskLevel: "critical",
|
|
9157
9725
|
path: [
|
|
9158
9726
|
{ sessionId: pre.sessionId, seq: pre.seq, detail: pre.actionDetail.slice(0, 60) },
|
|
@@ -9165,18 +9733,18 @@ function checkNeverExfilAfterPrivesc(graph) {
|
|
|
9165
9733
|
for (let i = 0; i < nodes.length; i++) {
|
|
9166
9734
|
if (!isPrivescNode(nodes[i])) continue;
|
|
9167
9735
|
for (let j = i + 1; j < nodes.length; j++) {
|
|
9168
|
-
if (isExfilNode(nodes[j]))
|
|
9169
|
-
|
|
9170
|
-
|
|
9171
|
-
|
|
9172
|
-
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
|
|
9176
|
-
]
|
|
9177
|
-
|
|
9178
|
-
|
|
9179
|
-
|
|
9736
|
+
if (!isExfilNode(nodes[j])) continue;
|
|
9737
|
+
if (privescInWindow(nodes, [i], j, windowSec).length === 0) continue;
|
|
9738
|
+
violations.push({
|
|
9739
|
+
propertyId: "no-exfil-after-privesc",
|
|
9740
|
+
reason: "\u63D0\u6743\u540E\u51FA\u73B0\u5916\u4F20\uFF1A\u63D0\u6743(\u524D) \u2192 \u5916\u4F20(\u540E)\uFF0C\u8FDD\u53CD \u25A1(PRIVESC\u2192\u25C7EXFIL) \u7A97\u53E3\u7EA6\u675F",
|
|
9741
|
+
riskLevel: "critical",
|
|
9742
|
+
path: [
|
|
9743
|
+
{ sessionId: nodes[i].sessionId, seq: nodes[i].seq, detail: nodes[i].actionDetail.slice(0, 60) },
|
|
9744
|
+
{ sessionId: nodes[j].sessionId, seq: nodes[j].seq, detail: nodes[j].actionDetail.slice(0, 60) }
|
|
9745
|
+
]
|
|
9746
|
+
});
|
|
9747
|
+
return violations;
|
|
9180
9748
|
}
|
|
9181
9749
|
}
|
|
9182
9750
|
return violations;
|
|
@@ -9339,6 +9907,10 @@ function checkCrossSessionReachability(graph) {
|
|
|
9339
9907
|
}
|
|
9340
9908
|
return violations;
|
|
9341
9909
|
}
|
|
9910
|
+
function isDataSourceNode(n) {
|
|
9911
|
+
if (n.stage === "CRED" || n.isLowSource) return true;
|
|
9912
|
+
return DATA_SOURCE_READ_RE.test(n.actionDetail);
|
|
9913
|
+
}
|
|
9342
9914
|
function checkSensitiveDataAggregation(graph) {
|
|
9343
9915
|
const violations = [];
|
|
9344
9916
|
const nodes = allNodes(graph);
|
|
@@ -9358,6 +9930,7 @@ function checkSensitiveDataAggregation(graph) {
|
|
|
9358
9930
|
for (const r of n.resources) {
|
|
9359
9931
|
for (const j of resIndex.get(r) || []) {
|
|
9360
9932
|
if (j === exfilIdx) continue;
|
|
9933
|
+
if (!isDataSourceNode(nodes[j])) continue;
|
|
9361
9934
|
srcs.add(`${nodes[j].sessionId}#${nodes[j].seq}`);
|
|
9362
9935
|
}
|
|
9363
9936
|
}
|
|
@@ -9380,7 +9953,7 @@ function checkSensitiveDataAggregation(graph) {
|
|
|
9380
9953
|
}
|
|
9381
9954
|
return violations;
|
|
9382
9955
|
}
|
|
9383
|
-
var CROSS_SESSION_CHAINS, CRED_FILE_RE, EXFIL_RE, EBPF_NET_RE, REMOTE_RE, EXFIL_ACTION_RE, CRED_STRICT_RE, INLINE_SHELL_RE, FORMAL_RULES, PKG_MGR, SHELLS, TOOL_REGISTRY, COMPUTE_RE, STRONG_COMPUTE_TYPES, DL_OR_LOW_RE, ALL_PROPERTIES;
|
|
9956
|
+
var CROSS_SESSION_CHAINS, CRED_FILE_RE, EXFIL_RE, EBPF_NET_RE, REMOTE_RE, EXFIL_ACTION_RE, CRED_STRICT_RE, INLINE_SHELL_RE, FORMAL_RULES, PKG_MGR, SHELLS, TOOL_REGISTRY, COMPUTE_RE, STRONG_COMPUTE_TYPES, DL_OR_LOW_RE, DATA_SOURCE_READ_RE, ALL_PROPERTIES;
|
|
9384
9957
|
var init_properties = __esm({
|
|
9385
9958
|
"src/engine/formal-engine/properties.ts"() {
|
|
9386
9959
|
"use strict";
|
|
@@ -9404,6 +9977,7 @@ var init_properties = __esm({
|
|
|
9404
9977
|
COMPUTE_RE = /subprocess|os\.system|shell\s*=\s*True|\beval\(|\bexec\(|bash\s+[^\s]|sh\s+-c|python3?\s+|node\s+|\btimeout\s+|nohup\s+|\b\.\/[\w./-]+/i;
|
|
9405
9978
|
STRONG_COMPUTE_TYPES = new Set(FORMAL_RULES.compute_action_types ?? []);
|
|
9406
9979
|
DL_OR_LOW_RE = /curl\s+.*-o\b|wget\s+.*\s+-O\b|curl\s+.*\|\s*(bash|sh|python)|wget\s+.*\|\s*(bash|sh|python)|git\s+clone|docker\s+pull|pip\s+install|npm\s+install|base64\s+-d/i;
|
|
9980
|
+
DATA_SOURCE_READ_RE = /\b(?:cat|head|tail|less|more|sed|awk|grep|strings|base64|xxd|od|dd)\b|\b(?:open|read_text|read_bytes)\s*\(/i;
|
|
9407
9981
|
ALL_PROPERTIES = [
|
|
9408
9982
|
{ id: "cross-session-chain", check: checkCrossSessionChain, shortName: "P1" },
|
|
9409
9983
|
{ id: "sensitive-data-flow", check: checkSensitiveDataFlow, shortName: "P2" },
|
|
@@ -9926,10 +10500,10 @@ var init_stateful = __esm({
|
|
|
9926
10500
|
import * as fs4 from "fs";
|
|
9927
10501
|
import * as os2 from "os";
|
|
9928
10502
|
import * as path4 from "path";
|
|
9929
|
-
import { createHash as
|
|
10503
|
+
import { createHash as createHash3 } from "crypto";
|
|
9930
10504
|
function defaultStateDbPath() {
|
|
9931
10505
|
const dir = process.env.AGENT_MOSS_STATE_DIR || path4.join(os2.homedir(), ".agentmoss");
|
|
9932
|
-
const tag =
|
|
10506
|
+
const tag = createHash3("sha1").update("agentmoss-stateful").digest("hex").slice(0, 8);
|
|
9933
10507
|
return path4.join(dir, `stateful_chains_${tag}.json`);
|
|
9934
10508
|
}
|
|
9935
10509
|
var ChainStateStore;
|
|
@@ -9937,6 +10511,7 @@ var init_chain_state = __esm({
|
|
|
9937
10511
|
"src/engine/formal-engine/chain_state.ts"() {
|
|
9938
10512
|
"use strict";
|
|
9939
10513
|
init_esm_shims();
|
|
10514
|
+
init_security_policy();
|
|
9940
10515
|
init_stateful();
|
|
9941
10516
|
ChainStateStore = class {
|
|
9942
10517
|
filePath;
|
|
@@ -9963,8 +10538,8 @@ var init_chain_state = __esm({
|
|
|
9963
10538
|
this._timer = setTimeout(() => {
|
|
9964
10539
|
this._timer = null;
|
|
9965
10540
|
try {
|
|
9966
|
-
|
|
9967
|
-
|
|
10541
|
+
ensurePrivateDir(path4.dirname(this.filePath));
|
|
10542
|
+
writePrivateText(this.filePath, JSON.stringify(this.data, null, 2));
|
|
9968
10543
|
} catch {
|
|
9969
10544
|
}
|
|
9970
10545
|
}, this._flushDelayMs);
|
|
@@ -9976,8 +10551,8 @@ var init_chain_state = __esm({
|
|
|
9976
10551
|
this._timer = null;
|
|
9977
10552
|
}
|
|
9978
10553
|
try {
|
|
9979
|
-
|
|
9980
|
-
|
|
10554
|
+
ensurePrivateDir(path4.dirname(this.filePath));
|
|
10555
|
+
writePrivateText(this.filePath, JSON.stringify(this.data, null, 2));
|
|
9981
10556
|
} catch {
|
|
9982
10557
|
}
|
|
9983
10558
|
}
|
|
@@ -10500,13 +11075,26 @@ var init_coordinator = __esm({
|
|
|
10500
11075
|
});
|
|
10501
11076
|
|
|
10502
11077
|
// src/infra/policy-cache.ts
|
|
10503
|
-
import { createHash as
|
|
10504
|
-
import { existsSync as
|
|
10505
|
-
import { tmpdir as
|
|
10506
|
-
import { join as
|
|
11078
|
+
import { createHash as createHash4 } from "crypto";
|
|
11079
|
+
import { existsSync as existsSync17, lstatSync as lstatSync2, readdirSync as readdirSync5, readFileSync as readFileSync17, rmdirSync, unlinkSync as unlinkSync3 } from "fs";
|
|
11080
|
+
import { tmpdir as tmpdir3 } from "os";
|
|
11081
|
+
import { join as join16 } from "path";
|
|
10507
11082
|
function cacheDir() {
|
|
10508
11083
|
return cacheDirOverride ?? CACHE_DIR;
|
|
10509
11084
|
}
|
|
11085
|
+
function safeCacheDir() {
|
|
11086
|
+
const dir = cacheDir();
|
|
11087
|
+
if (ensurePrivateDir(dir)) return dir;
|
|
11088
|
+
try {
|
|
11089
|
+
const fallback = join16(getDataRoot(), "policy_cache");
|
|
11090
|
+
if (ensurePrivateDir(fallback)) {
|
|
11091
|
+
console.warn(`[AgentMoss] \u7F13\u5B58\u76EE\u5F55 ${dir} \u4E0D\u5B89\u5168\uFF08\u88AB\u5176\u4ED6\u7528\u6237\u62E5\u6709\u6216\u4E3A\u7B26\u53F7\u94FE\u63A5\uFF09\uFF0C\u5DF2\u56DE\u9000\u5230 ${fallback}`);
|
|
11092
|
+
return fallback;
|
|
11093
|
+
}
|
|
11094
|
+
} catch {
|
|
11095
|
+
}
|
|
11096
|
+
return dir;
|
|
11097
|
+
}
|
|
10510
11098
|
function getDefaultCache() {
|
|
10511
11099
|
if (!defaultCache) defaultCache = new PolicyCache(getCacheOptions());
|
|
10512
11100
|
return defaultCache;
|
|
@@ -10516,8 +11104,10 @@ var init_policy_cache = __esm({
|
|
|
10516
11104
|
"src/infra/policy-cache.ts"() {
|
|
10517
11105
|
"use strict";
|
|
10518
11106
|
init_esm_shims();
|
|
11107
|
+
init_security_policy();
|
|
11108
|
+
init_paths();
|
|
10519
11109
|
init_config();
|
|
10520
|
-
CACHE_DIR =
|
|
11110
|
+
CACHE_DIR = join16(tmpdir3(), "agent_moss_policy_cache");
|
|
10521
11111
|
cacheDirOverride = null;
|
|
10522
11112
|
PolicyCache = class {
|
|
10523
11113
|
// Map 的插入序即 LRU 序(get 时重新 set 到末尾)
|
|
@@ -10530,9 +11120,9 @@ var init_policy_cache = __esm({
|
|
|
10530
11120
|
return `${sessionId}::${promptSession}`;
|
|
10531
11121
|
}
|
|
10532
11122
|
cacheFilePath(sessionId, promptSession) {
|
|
10533
|
-
const promptHash =
|
|
10534
|
-
const safeSessionId = sessionId.replace(/\//g, "_").replace(/\\/g, "_");
|
|
10535
|
-
return
|
|
11123
|
+
const promptHash = createHash4("md5").update(promptSession).digest("hex").slice(0, 12);
|
|
11124
|
+
const safeSessionId = sessionId.replace(/\//g, "_").replace(/\\/g, "_").replace(/\.\./g, "__");
|
|
11125
|
+
return join16(safeCacheDir(), safeSessionId, `${promptHash}.toml`);
|
|
10536
11126
|
}
|
|
10537
11127
|
/** 取缓存:内存 → 文件;未命中返回 null。 */
|
|
10538
11128
|
get(sessionId, promptSession) {
|
|
@@ -10545,9 +11135,9 @@ var init_policy_cache = __esm({
|
|
|
10545
11135
|
return hit;
|
|
10546
11136
|
}
|
|
10547
11137
|
const file = this.cacheFilePath(sessionId, promptSession);
|
|
10548
|
-
if (
|
|
11138
|
+
if (existsSync17(file) && !lstatSync2(file).isSymbolicLink()) {
|
|
10549
11139
|
try {
|
|
10550
|
-
const policy =
|
|
11140
|
+
const policy = readFileSync17(file, "utf-8");
|
|
10551
11141
|
this.remember(key, policy);
|
|
10552
11142
|
return policy;
|
|
10553
11143
|
} catch {
|
|
@@ -10561,8 +11151,10 @@ var init_policy_cache = __esm({
|
|
|
10561
11151
|
this.remember(this.cacheKey(sessionId, promptSession), policy);
|
|
10562
11152
|
const file = this.cacheFilePath(sessionId, promptSession);
|
|
10563
11153
|
try {
|
|
10564
|
-
|
|
10565
|
-
|
|
11154
|
+
const dir = safeCacheDir();
|
|
11155
|
+
const sub = sessionId.replace(/\//g, "_").replace(/\\/g, "_").replace(/\.\./g, "__");
|
|
11156
|
+
if (!ensurePrivateDir(join16(dir, sub))) return;
|
|
11157
|
+
writePrivateText(file, policy);
|
|
10566
11158
|
} catch {
|
|
10567
11159
|
}
|
|
10568
11160
|
}
|
|
@@ -10586,13 +11178,13 @@ var init_policy_cache = __esm({
|
|
|
10586
11178
|
for (const k of [...this.memory.keys()]) {
|
|
10587
11179
|
if (k.startsWith(`${sessionId}::`)) this.memory.delete(k);
|
|
10588
11180
|
}
|
|
10589
|
-
const safeSessionId = sessionId.replace(/\//g, "_").replace(/\\/g, "_");
|
|
10590
|
-
const dir =
|
|
11181
|
+
const safeSessionId = sessionId.replace(/\//g, "_").replace(/\\/g, "_").replace(/\.\./g, "__");
|
|
11182
|
+
const dir = join16(cacheDir(), safeSessionId);
|
|
10591
11183
|
try {
|
|
10592
|
-
if (
|
|
11184
|
+
if (existsSync17(dir)) {
|
|
10593
11185
|
for (const f of readdirSync5(dir)) {
|
|
10594
11186
|
try {
|
|
10595
|
-
unlinkSync3(
|
|
11187
|
+
unlinkSync3(join16(dir, f));
|
|
10596
11188
|
} catch {
|
|
10597
11189
|
}
|
|
10598
11190
|
}
|
|
@@ -10604,11 +11196,11 @@ var init_policy_cache = __esm({
|
|
|
10604
11196
|
clear() {
|
|
10605
11197
|
this.memory.clear();
|
|
10606
11198
|
try {
|
|
10607
|
-
if (
|
|
11199
|
+
if (existsSync17(cacheDir())) {
|
|
10608
11200
|
for (const sessionDir of readdirSync5(cacheDir())) {
|
|
10609
|
-
const dir =
|
|
11201
|
+
const dir = join16(cacheDir(), sessionDir);
|
|
10610
11202
|
try {
|
|
10611
|
-
for (const f of readdirSync5(dir)) unlinkSync3(
|
|
11203
|
+
for (const f of readdirSync5(dir)) unlinkSync3(join16(dir, f));
|
|
10612
11204
|
rmdirSync(dir);
|
|
10613
11205
|
} catch {
|
|
10614
11206
|
}
|
|
@@ -10704,9 +11296,9 @@ __export(analyzer_exports, {
|
|
|
10704
11296
|
savePolicyToFile: () => savePolicyToFile,
|
|
10705
11297
|
validateToml: () => validateToml
|
|
10706
11298
|
});
|
|
10707
|
-
import { existsSync as
|
|
10708
|
-
import { tmpdir as
|
|
10709
|
-
import { join as
|
|
11299
|
+
import { existsSync as existsSync18, readFileSync as readFileSync18 } from "fs";
|
|
11300
|
+
import { tmpdir as tmpdir4 } from "os";
|
|
11301
|
+
import { join as join17, resolve as resolve11 } from "path";
|
|
10710
11302
|
import { parse as parseToml } from "smol-toml";
|
|
10711
11303
|
function _setPolicyOutputDirForTest(dir) {
|
|
10712
11304
|
policyOutputDirOverride = dir;
|
|
@@ -10718,10 +11310,13 @@ function savePolicyToFile(sessionId, policyToml) {
|
|
|
10718
11310
|
if (!isPolicySaveEnabled()) return null;
|
|
10719
11311
|
try {
|
|
10720
11312
|
const outDir = policyOutputDir();
|
|
10721
|
-
|
|
10722
|
-
|
|
10723
|
-
|
|
10724
|
-
|
|
11313
|
+
if (!ensurePrivateDir(outDir)) {
|
|
11314
|
+
console.warn(`[AgentMoss] Policy \u8F93\u51FA\u76EE\u5F55 ${outDir} \u4E0D\u5B89\u5168\uFF0C\u8DF3\u8FC7\u843D\u76D8\uFF08\u4E0D\u5F71\u54CD\u5224\u5B9A\uFF09`);
|
|
11315
|
+
return null;
|
|
11316
|
+
}
|
|
11317
|
+
const safeName = sessionId.replace(/\//g, "_").replace(/\\/g, "_").replace(/\.\./g, "__");
|
|
11318
|
+
const filepath = join17(outDir, `${safeName}.toml`);
|
|
11319
|
+
writePrivateText(filepath, policyToml);
|
|
10725
11320
|
return filepath;
|
|
10726
11321
|
} catch (err) {
|
|
10727
11322
|
console.warn(`[AgentMoss] \u7B56\u7565\u6587\u4EF6\u843D\u76D8\u5931\u8D25\uFF08\u4E0D\u5F71\u54CD\u5224\u5B9A\uFF09: ${policyOutputDir()}: ${String(err)}`);
|
|
@@ -10758,12 +11353,12 @@ function validateToml(tomlStr) {
|
|
|
10758
11353
|
function loadPolicyMappingDoc() {
|
|
10759
11354
|
const dir = resolveAssetDir(__dirname, "templates");
|
|
10760
11355
|
if (dir) {
|
|
10761
|
-
const p =
|
|
10762
|
-
if (
|
|
11356
|
+
const p = resolve11(dir, "policy_mapping.md");
|
|
11357
|
+
if (existsSync18(p)) return readFileSync18(p, "utf-8");
|
|
10763
11358
|
}
|
|
10764
11359
|
for (const cand of assetDirCandidates(__dirname, "templates")) {
|
|
10765
|
-
const p =
|
|
10766
|
-
if (
|
|
11360
|
+
const p = resolve11(cand, "policy_mapping.md");
|
|
11361
|
+
if (existsSync18(p)) return readFileSync18(p, "utf-8");
|
|
10767
11362
|
}
|
|
10768
11363
|
return "";
|
|
10769
11364
|
}
|
|
@@ -10926,6 +11521,7 @@ var init_analyzer = __esm({
|
|
|
10926
11521
|
"src/engine/analyzer.ts"() {
|
|
10927
11522
|
"use strict";
|
|
10928
11523
|
init_esm_shims();
|
|
11524
|
+
init_security_policy();
|
|
10929
11525
|
init_coordinator();
|
|
10930
11526
|
init_policy_cache();
|
|
10931
11527
|
init_config();
|
|
@@ -10933,7 +11529,7 @@ var init_analyzer = __esm({
|
|
|
10933
11529
|
init_asset_dir();
|
|
10934
11530
|
init_token_stats();
|
|
10935
11531
|
init_logging();
|
|
10936
|
-
POLICY_OUTPUT_DIR =
|
|
11532
|
+
POLICY_OUTPUT_DIR = join17(tmpdir4(), "agent_moss");
|
|
10937
11533
|
policyOutputDirOverride = null;
|
|
10938
11534
|
DEFAULT_READONLY_POLICY = `landlock_optional = false
|
|
10939
11535
|
mount_isolation_fallback = false
|
|
@@ -11345,7 +11941,8 @@ var init_observable = __esm({
|
|
|
11345
11941
|
});
|
|
11346
11942
|
|
|
11347
11943
|
// src/routes.ts
|
|
11348
|
-
import {
|
|
11944
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
11945
|
+
import { join as join19, dirname as dirname12 } from "path";
|
|
11349
11946
|
import { fileURLToPath as fileURLToPath10 } from "url";
|
|
11350
11947
|
async function healthRoute(c) {
|
|
11351
11948
|
return c.json(HealthResponseSchema.parse({
|
|
@@ -11361,7 +11958,23 @@ async function analyzeRoute(c) {
|
|
|
11361
11958
|
if (!osType) {
|
|
11362
11959
|
osType = process.platform === "win32" ? "windows" : "linux";
|
|
11363
11960
|
}
|
|
11364
|
-
const
|
|
11961
|
+
const _principal = principalOf(c.req.raw.headers, new URL(c.req.url).pathname);
|
|
11962
|
+
const [_boundOk, agentId] = bindAgent(_principal, req.agent_id || req.metadata?.agent_type || "");
|
|
11963
|
+
if (!_boundOk) {
|
|
11964
|
+
return c.json({ detail: `agent_id \u4E0E\u6240\u6301\u51ED\u8BC1\u4E0D\u5339\u914D: ${agentId}` }, 403);
|
|
11965
|
+
}
|
|
11966
|
+
const _sweepKey = _principal || `ip:${c.req.header("x-forwarded-for") || "local"}`;
|
|
11967
|
+
const [_sweepN, _sweepHit] = noteSessionAccess(_sweepKey, req.session_id);
|
|
11968
|
+
if (_sweepHit) {
|
|
11969
|
+
if (sessionSweepAction() === "deny") {
|
|
11970
|
+
return c.json({
|
|
11971
|
+
detail: `\u77ED\u65F6\u95F4\u5185\u8BBF\u95EE\u4E86 ${_sweepN} \u4E2A\u4E0D\u540C\u4F1A\u8BDD\uFF0C\u8D85\u51FA\u9608\u503C ${sessionSweepThreshold()}\uFF08\u7591\u4F3C\u5192\u5145/\u626B\u63CF\uFF09`
|
|
11972
|
+
}, 429);
|
|
11973
|
+
}
|
|
11974
|
+
console.warn(
|
|
11975
|
+
`[AgentMoss] \u26A0\uFE0F \u8DE8\u4F1A\u8BDD\u6279\u91CF\u8BBF\u95EE: key=${_sweepKey} \u7A97\u53E3\u5185 ${_sweepN} \u4E2A\u4E0D\u540C session\uFF08\u9608\u503C ${sessionSweepThreshold()}\uFF09`
|
|
11976
|
+
);
|
|
11977
|
+
}
|
|
11365
11978
|
const result = await analyze({
|
|
11366
11979
|
sessionId: req.session_id,
|
|
11367
11980
|
promptSession: req.prompt_session,
|
|
@@ -11372,14 +11985,16 @@ async function analyzeRoute(c) {
|
|
|
11372
11985
|
actionHistory: req.action_history.map((h) => ({
|
|
11373
11986
|
actionType: h.action_type,
|
|
11374
11987
|
actionDetail: h.action_detail,
|
|
11375
|
-
output: h.output
|
|
11988
|
+
output: h.output,
|
|
11989
|
+
calledAt: h.called_at
|
|
11376
11990
|
})),
|
|
11377
11991
|
sessionHistory: (req.session_history || []).map((s) => ({
|
|
11378
11992
|
sessionId: s.session_id,
|
|
11379
11993
|
actionHistory: (s.action_history || []).map((h) => ({
|
|
11380
11994
|
actionType: h.action_type,
|
|
11381
11995
|
actionDetail: h.action_detail,
|
|
11382
|
-
output: h.output
|
|
11996
|
+
output: h.output,
|
|
11997
|
+
calledAt: h.called_at
|
|
11383
11998
|
}))
|
|
11384
11999
|
})),
|
|
11385
12000
|
// prompt_history 必须透传:L2 意图一致性(logic-rules.ts 的
|
|
@@ -11406,7 +12021,8 @@ async function analyzeRoute(c) {
|
|
|
11406
12021
|
// agent_id:AgentGate V1 normalizer 历史上把 agent_type 塞 metadata,
|
|
11407
12022
|
// 顶层为空时兜底(OpenDesk 的 agent-moss 需 agent_id 加载专属规则)。
|
|
11408
12023
|
agentId,
|
|
11409
|
-
|
|
12024
|
+
// 严格模式:完全不接受 per-request LLM 配置(默认接受,保持原行为)
|
|
12025
|
+
llmConfig: perRequestLlmEnabled() ? req.metadata?.llm_config : void 0,
|
|
11410
12026
|
llmLogPath: req.metadata?.llm_log_path
|
|
11411
12027
|
});
|
|
11412
12028
|
const durationMs = performance.now() - t0;
|
|
@@ -11454,7 +12070,8 @@ async function analyzeRoute(c) {
|
|
|
11454
12070
|
violated_policy: "",
|
|
11455
12071
|
confidence: 90,
|
|
11456
12072
|
analysis_duration_ms: Math.round((performance.now() - t0) * 10) / 10,
|
|
11457
|
-
|
|
12073
|
+
// 跨会话节点脱敏(时间线按 agent_id 共享,原样返回等于泄露别人的命令原文)
|
|
12074
|
+
violation_chain: redactChain(judgment.violation_chain, req.session_id)
|
|
11458
12075
|
})
|
|
11459
12076
|
);
|
|
11460
12077
|
}
|
|
@@ -11478,14 +12095,19 @@ async function analyzeRoute(c) {
|
|
|
11478
12095
|
})
|
|
11479
12096
|
);
|
|
11480
12097
|
} catch (err) {
|
|
11481
|
-
console.error("[AgentMoss] Analysis error:", err);
|
|
11482
12098
|
if (err instanceof SyntaxError) {
|
|
11483
12099
|
return c.json({ detail: err.message, error: "Invalid JSON" }, 422);
|
|
11484
12100
|
}
|
|
11485
12101
|
if (err?.issues) {
|
|
11486
12102
|
return c.json({ detail: err.issues, error: "Validation error" }, 422);
|
|
11487
12103
|
}
|
|
11488
|
-
|
|
12104
|
+
if (errorDetailMode() === "full") {
|
|
12105
|
+
console.error("[AgentMoss] Analysis error:", err);
|
|
12106
|
+
return c.json({ detail: String(err), error: "Internal error" }, 500);
|
|
12107
|
+
}
|
|
12108
|
+
const ref = randomBytes2(4).toString("hex");
|
|
12109
|
+
console.error(`[AgentMoss] Analysis internal error (ref=${ref}):`, err);
|
|
12110
|
+
return c.json({ detail: `Internal server error (ref: ${ref})`, error: "Internal error" }, 500);
|
|
11489
12111
|
}
|
|
11490
12112
|
}
|
|
11491
12113
|
function getChainStateStoreFor(_agentId) {
|
|
@@ -11523,6 +12145,11 @@ async function reviewRoute(c) {
|
|
|
11523
12145
|
if (!tracker) {
|
|
11524
12146
|
tracker = new StatefulChainTracker(agentId);
|
|
11525
12147
|
}
|
|
12148
|
+
if (req.db_path && !pathWithin(req.db_path, reviewRoots())) {
|
|
12149
|
+
return c.json({
|
|
12150
|
+
detail: "db_path \u4E0D\u5728\u5141\u8BB8\u8BFB\u53D6\u7684\u76EE\u5F55\u5185\uFF1B\u6807\u51C6 AgentGate \u90E8\u7F72\u65E0\u9700\u914D\u7F6E\uFF0C\u81EA\u5B9A\u4E49\u8DEF\u5F84\u8BF7\u52A0\u5165 AGENT_MOSS_REVIEW_PATHS"
|
|
12151
|
+
}, 403);
|
|
12152
|
+
}
|
|
11526
12153
|
let sessions = [];
|
|
11527
12154
|
if (req.db_path) {
|
|
11528
12155
|
sessions = loadAgentGateSessions(req.db_path);
|
|
@@ -11586,15 +12213,20 @@ async function reviewRoute(c) {
|
|
|
11586
12213
|
discovered_patterns: discovered
|
|
11587
12214
|
}));
|
|
11588
12215
|
} catch (err) {
|
|
11589
|
-
|
|
11590
|
-
|
|
12216
|
+
if (errorDetailMode() === "full") {
|
|
12217
|
+
console.error("[AgentMoss] Review error:", err);
|
|
12218
|
+
return c.json({ error: "Internal error", detail: String(err) }, 500);
|
|
12219
|
+
}
|
|
12220
|
+
const ref = randomBytes2(4).toString("hex");
|
|
12221
|
+
console.error(`[AgentMoss] Review internal error (ref=${ref}):`, err);
|
|
12222
|
+
return c.json({ error: "Internal error", detail: `Internal server error (ref: ${ref})` }, 500);
|
|
11591
12223
|
}
|
|
11592
12224
|
}
|
|
11593
12225
|
function getBrainRuleStore() {
|
|
11594
12226
|
return new BrainRuleStore();
|
|
11595
12227
|
}
|
|
11596
12228
|
function getBrainSkillManager() {
|
|
11597
|
-
const dir = resolveAssetDir(__dirname9, "skills") ??
|
|
12229
|
+
const dir = resolveAssetDir(__dirname9, "skills") ?? join19(__dirname9, "..", "..", "agent_moss", "skills");
|
|
11598
12230
|
return new BrainSkillManager(dir);
|
|
11599
12231
|
}
|
|
11600
12232
|
async function brainRulesRoute(c) {
|
|
@@ -11690,6 +12322,7 @@ var init_routes = __esm({
|
|
|
11690
12322
|
"src/routes.ts"() {
|
|
11691
12323
|
"use strict";
|
|
11692
12324
|
init_esm_shims();
|
|
12325
|
+
init_security_policy();
|
|
11693
12326
|
init_models();
|
|
11694
12327
|
init_analyzer();
|
|
11695
12328
|
init_actrail();
|
|
@@ -11700,15 +12333,16 @@ var init_routes = __esm({
|
|
|
11700
12333
|
init_rule_store();
|
|
11701
12334
|
init_skill_manager();
|
|
11702
12335
|
init_asset_dir();
|
|
11703
|
-
__dirname9 =
|
|
12336
|
+
__dirname9 = dirname12(fileURLToPath10(import.meta.url));
|
|
11704
12337
|
reviewStore = null;
|
|
11705
12338
|
}
|
|
11706
12339
|
});
|
|
11707
12340
|
|
|
11708
12341
|
// src/console/router.ts
|
|
11709
12342
|
import { Hono } from "hono";
|
|
11710
|
-
import {
|
|
11711
|
-
import {
|
|
12343
|
+
import { timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
12344
|
+
import { readFileSync as readFileSync20, existsSync as existsSync20, unlinkSync as unlinkSync4 } from "fs";
|
|
12345
|
+
import { join as join20, dirname as dirname13 } from "path";
|
|
11712
12346
|
import { fileURLToPath as fileURLToPath11 } from "url";
|
|
11713
12347
|
function getConsoleToken() {
|
|
11714
12348
|
return process.env[CONSOLE_TOKEN_ENV] || "";
|
|
@@ -11717,7 +12351,11 @@ function verifyAuth(req) {
|
|
|
11717
12351
|
const token = getConsoleToken();
|
|
11718
12352
|
if (!token) return true;
|
|
11719
12353
|
const auth = req.headers.get("Authorization") || "";
|
|
11720
|
-
if (auth.startsWith("Bearer "))
|
|
12354
|
+
if (auth.startsWith("Bearer ")) {
|
|
12355
|
+
const a = Buffer.from(auth.slice(7), "utf-8");
|
|
12356
|
+
const b = Buffer.from(token, "utf-8");
|
|
12357
|
+
return a.length === b.length && timingSafeEqual2(a, b);
|
|
12358
|
+
}
|
|
11721
12359
|
return false;
|
|
11722
12360
|
}
|
|
11723
12361
|
function authMiddleware() {
|
|
@@ -11746,9 +12384,9 @@ function createConsoleRouter() {
|
|
|
11746
12384
|
console2.use("/api/*", authMiddleware());
|
|
11747
12385
|
console2.use("/api/*", builtinOnlyReadOnlyMiddleware());
|
|
11748
12386
|
const serveIndex = (c) => {
|
|
11749
|
-
const indexFile =
|
|
11750
|
-
if (
|
|
11751
|
-
return c.html(
|
|
12387
|
+
const indexFile = join20(STATIC_DIR, "index.html");
|
|
12388
|
+
if (existsSync20(indexFile)) {
|
|
12389
|
+
return c.html(readFileSync20(indexFile, "utf-8"));
|
|
11752
12390
|
}
|
|
11753
12391
|
return c.html("<h1>AgentMoss Policy Console</h1><p>Frontend not built. Use /console/api/* endpoints.</p>");
|
|
11754
12392
|
};
|
|
@@ -11943,15 +12581,15 @@ function createConsoleRouter() {
|
|
|
11943
12581
|
if (!/^[A-Za-z0-9_-]+$/.test(skillId)) {
|
|
11944
12582
|
return c.json({ detail: "\u975E\u6CD5 skill id" }, 400);
|
|
11945
12583
|
}
|
|
11946
|
-
const userPath =
|
|
12584
|
+
const userPath = join20(dirname13(getRuntimeConfigPath()), "agent_moss_skills", `${skillId}.md`);
|
|
11947
12585
|
const builtinDir = resolveAssetDir(__dirname10, "skills");
|
|
11948
12586
|
const candidates = [
|
|
11949
12587
|
...isRuntimeConfigDisabled() ? [] : [userPath],
|
|
11950
|
-
builtinDir ?
|
|
12588
|
+
builtinDir ? join20(builtinDir, `${skillId}.md`) : ""
|
|
11951
12589
|
].filter(Boolean);
|
|
11952
12590
|
for (const p of candidates) {
|
|
11953
|
-
if (
|
|
11954
|
-
return c.json({ skill_id: skillId, path: p, content:
|
|
12591
|
+
if (existsSync20(p)) {
|
|
12592
|
+
return c.json({ skill_id: skillId, path: p, content: readFileSync20(p, "utf-8") });
|
|
11955
12593
|
}
|
|
11956
12594
|
}
|
|
11957
12595
|
return c.json({ detail: `skill ${skillId} \u4E0D\u5B58\u5728` }, 404);
|
|
@@ -12048,7 +12686,7 @@ function createConsoleRouter() {
|
|
|
12048
12686
|
const defaults = generateSourceDefaults();
|
|
12049
12687
|
try {
|
|
12050
12688
|
const p = getRuntimeConfigPath();
|
|
12051
|
-
if (
|
|
12689
|
+
if (existsSync20(p)) unlinkSync4(p);
|
|
12052
12690
|
} catch {
|
|
12053
12691
|
}
|
|
12054
12692
|
return c.json(withL22View(defaults));
|
|
@@ -12084,8 +12722,8 @@ var init_router = __esm({
|
|
|
12084
12722
|
init_rules_loader();
|
|
12085
12723
|
init_asset_dir();
|
|
12086
12724
|
init_rules_mode();
|
|
12087
|
-
__dirname10 =
|
|
12088
|
-
STATIC_DIR =
|
|
12725
|
+
__dirname10 = dirname13(fileURLToPath11(import.meta.url));
|
|
12726
|
+
STATIC_DIR = join20(__dirname10, "static");
|
|
12089
12727
|
CONSOLE_TOKEN_ENV = "AGENT_MOSS_CONSOLE_TOKEN";
|
|
12090
12728
|
}
|
|
12091
12729
|
});
|
|
@@ -12112,7 +12750,7 @@ import { Hono as Hono2 } from "hono";
|
|
|
12112
12750
|
import { cors } from "hono/cors";
|
|
12113
12751
|
import { logger } from "hono/logger";
|
|
12114
12752
|
import net from "net";
|
|
12115
|
-
import { existsSync as
|
|
12753
|
+
import { existsSync as existsSync21 } from "fs";
|
|
12116
12754
|
function logDeploymentSelfCheck() {
|
|
12117
12755
|
try {
|
|
12118
12756
|
const mode = getRulesMode();
|
|
@@ -12139,7 +12777,7 @@ function logDeploymentSelfCheck() {
|
|
|
12139
12777
|
console.log("\u5C42\u7EA7\u5F00\u5173: " + layerKeys.map((k) => `${k}=${isLayerEnabled(k) ? "on" : "OFF"}`).join(" "));
|
|
12140
12778
|
if (!builtinOnly) {
|
|
12141
12779
|
try {
|
|
12142
|
-
const dirs = rulesDirs().filter((d) =>
|
|
12780
|
+
const dirs = rulesDirs().filter((d) => existsSync21(d));
|
|
12143
12781
|
if (dirs.length > 0) {
|
|
12144
12782
|
console.log(`\u89C4\u5219\u76EE\u5F55: ${dirs.join(", ")}\uFF08\u53EA\u8BFB\u5176\u4E2D ${OVERRIDE_FILENAME} / ${EXTRA_FILENAME}\uFF09`);
|
|
12145
12783
|
}
|
|
@@ -12179,9 +12817,91 @@ function logDeploymentSelfCheck() {
|
|
|
12179
12817
|
}
|
|
12180
12818
|
function createApp() {
|
|
12181
12819
|
enforceRulesContract();
|
|
12820
|
+
hardenExistingPaths();
|
|
12182
12821
|
const app = new Hono2();
|
|
12183
|
-
app.use("*", cors({
|
|
12822
|
+
app.use("*", cors({
|
|
12823
|
+
origin: (o) => allowedOrigins().includes(o) ? o : null,
|
|
12824
|
+
allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
12825
|
+
allowHeaders: ["*"]
|
|
12826
|
+
}));
|
|
12184
12827
|
app.use("*", logger());
|
|
12828
|
+
const pools = new PooledLimiter();
|
|
12829
|
+
const limiter = new RateLimiter(rateLimitQps());
|
|
12830
|
+
app.use("*", async (c, next) => {
|
|
12831
|
+
const path6 = new URL(c.req.url).pathname;
|
|
12832
|
+
const method = c.req.method.toUpperCase();
|
|
12833
|
+
if (method === "OPTIONS") return next();
|
|
12834
|
+
const maxBody = maxBodyBytes();
|
|
12835
|
+
const cl = c.req.header("content-length");
|
|
12836
|
+
if (cl && maxBody > 0) {
|
|
12837
|
+
const n = Number.parseInt(cl, 10);
|
|
12838
|
+
if (Number.isFinite(n) && n > maxBody) {
|
|
12839
|
+
return c.json({ detail: `\u8BF7\u6C42\u4F53\u8D85\u8FC7\u4E0A\u9650 ${maxBody} \u5B57\u8282` }, 413);
|
|
12840
|
+
}
|
|
12841
|
+
}
|
|
12842
|
+
if (originCheckEnabled()) {
|
|
12843
|
+
const origin = c.req.header("origin") || "";
|
|
12844
|
+
if (origin && !originAllowed(origin, c.req.header("host") || "")) {
|
|
12845
|
+
console.warn(`[AgentMoss] \u5DF2\u62E6\u622A\u8DE8\u6E90\u8BF7\u6C42: origin=${origin} path=${path6}`);
|
|
12846
|
+
return c.json({ detail: `\u8DE8\u6E90\u6765\u6E90\u672A\u88AB\u5141\u8BB8: ${origin}` }, 403);
|
|
12847
|
+
}
|
|
12848
|
+
}
|
|
12849
|
+
const [okAuth, principal] = checkRequestAuth(c.req.raw.headers, path6);
|
|
12850
|
+
const isPublicPage = !path6.startsWith("/console/api") && (path6 === "/console" || path6.startsWith("/console/"));
|
|
12851
|
+
if (!okAuth && !isPublicPage) {
|
|
12852
|
+
return c.json({ detail: "Unauthorized: invalid or missing Bearer token" }, 401);
|
|
12853
|
+
}
|
|
12854
|
+
if (limiter.enabled && path6.startsWith("/api/")) {
|
|
12855
|
+
const key = principal ? "p:" + principalHash(principal) : "c:" + (c.req.header("x-forwarded-for") || "local");
|
|
12856
|
+
if (!limiter.allow(key)) {
|
|
12857
|
+
return c.json({ detail: "\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5" }, 429);
|
|
12858
|
+
}
|
|
12859
|
+
}
|
|
12860
|
+
const ip = c.req.header("x-forwarded-for") || "local";
|
|
12861
|
+
const keys = [];
|
|
12862
|
+
const take = (key, limit) => {
|
|
12863
|
+
if (pools.tryAcquire(key, limit)) {
|
|
12864
|
+
keys.push(key);
|
|
12865
|
+
return true;
|
|
12866
|
+
}
|
|
12867
|
+
return false;
|
|
12868
|
+
};
|
|
12869
|
+
const busy = (detail, status = 503) => {
|
|
12870
|
+
c.header("Retry-After", "1");
|
|
12871
|
+
c.header("Connection", "close");
|
|
12872
|
+
return c.json({ detail }, status);
|
|
12873
|
+
};
|
|
12874
|
+
try {
|
|
12875
|
+
if (!principal && authEnabled()) {
|
|
12876
|
+
if (!take("unauth:total", unauthInflight())) {
|
|
12877
|
+
return busy("\u672A\u8BA4\u8BC1\u8BF7\u6C42\u5E76\u53D1\u8D85\u9650\uFF0C\u8BF7\u6301\u51ED\u8BC1\u8BBF\u95EE");
|
|
12878
|
+
}
|
|
12879
|
+
if (!take(`unauth:ip:${ip}`, unauthPerIp())) {
|
|
12880
|
+
return busy("\u8BE5\u6765\u6E90\u7684\u672A\u8BA4\u8BC1\u8BF7\u6C42\u5E76\u53D1\u8D85\u9650");
|
|
12881
|
+
}
|
|
12882
|
+
} else {
|
|
12883
|
+
const bound = boundAgentOf(principal);
|
|
12884
|
+
if (bound && !take(`agent:${bound}`, agentInflight())) {
|
|
12885
|
+
return busy(`agent '${bound}' \u7684\u5E76\u53D1\u8D85\u9650\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5`, 429);
|
|
12886
|
+
}
|
|
12887
|
+
}
|
|
12888
|
+
const pool = poolOf(path6);
|
|
12889
|
+
if (!take(`pool:${pool}`, poolLimit(pool))) {
|
|
12890
|
+
const qkey = principal ? "p:" + principalHash(principal) : "c:local";
|
|
12891
|
+
const [qn, abusive] = noteQueueReject(qkey);
|
|
12892
|
+
if (abusive && queueAbuseAction() === "deny") {
|
|
12893
|
+
return busy("\u5E76\u53D1\u62D2\u7EDD\u8FC7\u4E8E\u9891\u7E41\uFF0C\u7591\u4F3C\u6076\u610F\u8BF7\u6C42", 429);
|
|
12894
|
+
}
|
|
12895
|
+
if (abusive) {
|
|
12896
|
+
console.warn(`[AgentMoss] \u26A0\uFE0F \u7591\u4F3C\u6076\u610F\u5E76\u53D1\u5360\u7528: key=${qkey} \u7A97\u53E3\u5185\u88AB\u62D2 ${qn} \u6B21`);
|
|
12897
|
+
}
|
|
12898
|
+
return busy("\u670D\u52A1\u7E41\u5FD9\uFF08\u5E76\u53D1\u5DF2\u6EE1\uFF09\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5");
|
|
12899
|
+
}
|
|
12900
|
+
return await next();
|
|
12901
|
+
} finally {
|
|
12902
|
+
while (keys.length) pools.release(keys.pop());
|
|
12903
|
+
}
|
|
12904
|
+
});
|
|
12185
12905
|
app.get("/api/v1/health", healthRoute);
|
|
12186
12906
|
app.post("/api/v1/analyze", analyzeRoute);
|
|
12187
12907
|
app.post("/api/v1/review", reviewRoute);
|
|
@@ -12199,12 +12919,12 @@ function createApp() {
|
|
|
12199
12919
|
}
|
|
12200
12920
|
async function findFreePort(startPort, host = "127.0.0.1", scan = 100) {
|
|
12201
12921
|
for (let port = startPort; port < startPort + scan; port++) {
|
|
12202
|
-
const free = await new Promise((
|
|
12922
|
+
const free = await new Promise((resolve12) => {
|
|
12203
12923
|
const server = net.createServer();
|
|
12204
12924
|
server.listen(port, host, () => {
|
|
12205
|
-
server.close(() =>
|
|
12925
|
+
server.close(() => resolve12(true));
|
|
12206
12926
|
});
|
|
12207
|
-
server.on("error", () =>
|
|
12927
|
+
server.on("error", () => resolve12(false));
|
|
12208
12928
|
});
|
|
12209
12929
|
if (free) {
|
|
12210
12930
|
if (port !== startPort) {
|
|
@@ -12241,6 +12961,7 @@ async function warmUpEngine() {
|
|
|
12241
12961
|
}
|
|
12242
12962
|
}
|
|
12243
12963
|
async function startServer(host = "127.0.0.1", port = 9090) {
|
|
12964
|
+
failFastOnAuthError();
|
|
12244
12965
|
const actualPort = await findFreePort(port, host);
|
|
12245
12966
|
const app = createApp();
|
|
12246
12967
|
return {
|
|
@@ -12250,7 +12971,12 @@ async function startServer(host = "127.0.0.1", port = 9090) {
|
|
|
12250
12971
|
logDeploymentSelfCheck();
|
|
12251
12972
|
await warmUpEngine();
|
|
12252
12973
|
const { serve: honoServe } = await import("@hono/node-server");
|
|
12253
|
-
honoServe({ fetch: app.fetch, hostname: host, port: actualPort });
|
|
12974
|
+
const srv = honoServe({ fetch: app.fetch, hostname: host, port: actualPort });
|
|
12975
|
+
try {
|
|
12976
|
+
srv.maxConnections = maxConnections();
|
|
12977
|
+
srv.keepAliveTimeout = keepAliveSec() * 1e3;
|
|
12978
|
+
} catch {
|
|
12979
|
+
}
|
|
12254
12980
|
}
|
|
12255
12981
|
};
|
|
12256
12982
|
}
|
|
@@ -12261,28 +12987,29 @@ async function startUnixSocketServer(socketPath = "/var/run/agent_moss/agent_mos
|
|
|
12261
12987
|
socketPath,
|
|
12262
12988
|
close: async () => {
|
|
12263
12989
|
if (!server) return;
|
|
12264
|
-
await new Promise((
|
|
12265
|
-
server.close(() =>
|
|
12990
|
+
await new Promise((resolve12) => {
|
|
12991
|
+
server.close(() => resolve12());
|
|
12266
12992
|
});
|
|
12267
12993
|
server = null;
|
|
12268
12994
|
},
|
|
12269
12995
|
serve: async () => {
|
|
12270
|
-
|
|
12271
|
-
const {
|
|
12272
|
-
const
|
|
12996
|
+
failFastOnAuthError();
|
|
12997
|
+
const { mkdirSync: mkdirSync10, existsSync: existsSync23, unlinkSync: unlinkSync5 } = await import("fs");
|
|
12998
|
+
const { dirname: dirname15 } = await import("path");
|
|
12999
|
+
const dir = dirname15(socketPath);
|
|
12273
13000
|
if (dir) {
|
|
12274
13001
|
try {
|
|
12275
13002
|
mkdirSync10(dir, { recursive: true });
|
|
12276
13003
|
} catch {
|
|
12277
13004
|
}
|
|
12278
13005
|
}
|
|
12279
|
-
if (
|
|
13006
|
+
if (existsSync23(socketPath)) {
|
|
12280
13007
|
const { connect } = await import("net");
|
|
12281
|
-
const inUse = await new Promise((
|
|
13008
|
+
const inUse = await new Promise((resolve12) => {
|
|
12282
13009
|
const probe = connect(socketPath);
|
|
12283
13010
|
const done = (v) => {
|
|
12284
13011
|
probe.destroy();
|
|
12285
|
-
|
|
13012
|
+
resolve12(v);
|
|
12286
13013
|
};
|
|
12287
13014
|
probe.once("connect", () => done(true));
|
|
12288
13015
|
probe.once("error", () => done(false));
|
|
@@ -12305,25 +13032,79 @@ async function startUnixSocketServer(socketPath = "/var/run/agent_moss/agent_mos
|
|
|
12305
13032
|
const { getRequestListener } = await import("@hono/node-server");
|
|
12306
13033
|
const { createServer } = await import("http");
|
|
12307
13034
|
server = createServer(getRequestListener(app.fetch));
|
|
12308
|
-
|
|
13035
|
+
try {
|
|
13036
|
+
server.maxConnections = maxConnections();
|
|
13037
|
+
server.keepAliveTimeout = keepAliveSec() * 1e3;
|
|
13038
|
+
} catch {
|
|
13039
|
+
}
|
|
13040
|
+
await new Promise((resolve12, reject) => {
|
|
12309
13041
|
server.once("error", reject);
|
|
12310
|
-
server.listen(socketPath, () =>
|
|
13042
|
+
server.listen(socketPath, () => resolve12());
|
|
12311
13043
|
});
|
|
13044
|
+
try {
|
|
13045
|
+
const { chmodSync: chmodSync2 } = await import("fs");
|
|
13046
|
+
chmodSync2(socketPath, socketMode());
|
|
13047
|
+
console.log(`[AgentMoss] socket \u6743\u9650: 0${socketMode().toString(8)}\uFF08AGENT_MOSS_SOCKET_MODE\uFF09`);
|
|
13048
|
+
} catch (e) {
|
|
13049
|
+
console.warn(`[AgentMoss] \u8BBE\u7F6E socket \u6743\u9650\u5931\u8D25: ${String(e)}`);
|
|
13050
|
+
}
|
|
12312
13051
|
console.log(`AgentMoss HTTP server on unix socket: ${socketPath}`);
|
|
12313
13052
|
}
|
|
12314
13053
|
};
|
|
12315
13054
|
}
|
|
12316
|
-
var WARMUP_COMMANDS;
|
|
13055
|
+
var PooledLimiter, RateLimiter, WARMUP_COMMANDS;
|
|
12317
13056
|
var init_server = __esm({
|
|
12318
13057
|
"src/server.ts"() {
|
|
12319
13058
|
"use strict";
|
|
12320
13059
|
init_esm_shims();
|
|
12321
13060
|
init_rules_contract();
|
|
13061
|
+
init_security_policy();
|
|
12322
13062
|
init_routes();
|
|
12323
13063
|
init_console();
|
|
12324
13064
|
init_runtime_config();
|
|
12325
13065
|
init_rules_mode();
|
|
12326
13066
|
init_rules_loader();
|
|
13067
|
+
PooledLimiter = class {
|
|
13068
|
+
counts = /* @__PURE__ */ new Map();
|
|
13069
|
+
tryAcquire(key, limit) {
|
|
13070
|
+
if (limit <= 0) return true;
|
|
13071
|
+
const cur = this.counts.get(key) || 0;
|
|
13072
|
+
if (cur >= limit) return false;
|
|
13073
|
+
this.counts.set(key, cur + 1);
|
|
13074
|
+
return true;
|
|
13075
|
+
}
|
|
13076
|
+
release(key) {
|
|
13077
|
+
const cur = this.counts.get(key) || 0;
|
|
13078
|
+
if (cur <= 1) this.counts.delete(key);
|
|
13079
|
+
else this.counts.set(key, cur - 1);
|
|
13080
|
+
}
|
|
13081
|
+
};
|
|
13082
|
+
RateLimiter = class {
|
|
13083
|
+
constructor(qps, burst) {
|
|
13084
|
+
this.qps = qps;
|
|
13085
|
+
this.burst = burst;
|
|
13086
|
+
}
|
|
13087
|
+
qps;
|
|
13088
|
+
burst;
|
|
13089
|
+
buckets = /* @__PURE__ */ new Map();
|
|
13090
|
+
get enabled() {
|
|
13091
|
+
return this.qps > 0;
|
|
13092
|
+
}
|
|
13093
|
+
allow(key) {
|
|
13094
|
+
if (!this.enabled) return true;
|
|
13095
|
+
const burst = this.burst ?? Math.max(this.qps, 1) * 2;
|
|
13096
|
+
const now = Date.now() / 1e3;
|
|
13097
|
+
const [tokens, last] = this.buckets.get(key) ?? [burst, now];
|
|
13098
|
+
const next = Math.min(burst, tokens + (now - last) * this.qps);
|
|
13099
|
+
if (next < 1) {
|
|
13100
|
+
this.buckets.set(key, [next, now]);
|
|
13101
|
+
return false;
|
|
13102
|
+
}
|
|
13103
|
+
this.buckets.set(key, [next - 1, now]);
|
|
13104
|
+
if (this.buckets.size > 1e4) this.buckets.clear();
|
|
13105
|
+
return true;
|
|
13106
|
+
}
|
|
13107
|
+
};
|
|
12327
13108
|
WARMUP_COMMANDS = {
|
|
12328
13109
|
linux: "whoami",
|
|
12329
13110
|
macos: "whoami",
|
|
@@ -12342,26 +13123,26 @@ __export(rules_tools_exports, {
|
|
|
12342
13123
|
rulesStatusText: () => rulesStatusText,
|
|
12343
13124
|
templateSourceDir: () => templateSourceDir
|
|
12344
13125
|
});
|
|
12345
|
-
import { existsSync as
|
|
12346
|
-
import { dirname as
|
|
13126
|
+
import { existsSync as existsSync22, mkdirSync as mkdirSync9, readdirSync as readdirSync7, readFileSync as readFileSync21, writeFileSync as writeFileSync7 } from "fs";
|
|
13127
|
+
import { dirname as dirname14, join as join21 } from "path";
|
|
12347
13128
|
import { fileURLToPath as fileURLToPath12 } from "url";
|
|
12348
13129
|
function initRulesDir(targetDir, opts = {}) {
|
|
12349
13130
|
mkdirSync9(targetDir, { recursive: true });
|
|
12350
13131
|
const written = [];
|
|
12351
|
-
const extraPath =
|
|
12352
|
-
if (opts.force || !
|
|
12353
|
-
|
|
13132
|
+
const extraPath = join21(targetDir, EXTRA_FILENAME);
|
|
13133
|
+
if (opts.force || !existsSync22(extraPath)) {
|
|
13134
|
+
writeFileSync7(extraPath, JSON.stringify(EXTRA_TEMPLATE, null, 2), "utf-8");
|
|
12354
13135
|
written.push(extraPath);
|
|
12355
13136
|
}
|
|
12356
|
-
const samplePath =
|
|
12357
|
-
if (opts.force || !
|
|
13137
|
+
const samplePath = join21(targetDir, OVERRIDE_FILENAME);
|
|
13138
|
+
if (opts.force || !existsSync22(samplePath)) {
|
|
12358
13139
|
let payload = OVERRIDE_TEMPLATE;
|
|
12359
13140
|
if (opts.withBuiltin) {
|
|
12360
13141
|
let data = {};
|
|
12361
13142
|
const builtin = resolveRulesFile("l1_rules.json");
|
|
12362
|
-
if (builtin &&
|
|
13143
|
+
if (builtin && existsSync22(builtin)) {
|
|
12363
13144
|
try {
|
|
12364
|
-
data = JSON.parse(
|
|
13145
|
+
data = JSON.parse(readFileSync21(builtin, "utf-8")) || {};
|
|
12365
13146
|
} catch {
|
|
12366
13147
|
data = {};
|
|
12367
13148
|
}
|
|
@@ -12369,20 +13150,20 @@ function initRulesDir(targetDir, opts = {}) {
|
|
|
12369
13150
|
payload = { _\u8BF4\u660E: OVERRIDE_BUILTIN_NOTE };
|
|
12370
13151
|
for (const k of L1_KEYS) payload[k] = data[k] || [];
|
|
12371
13152
|
}
|
|
12372
|
-
|
|
13153
|
+
writeFileSync7(samplePath, JSON.stringify(payload, null, 2), "utf-8");
|
|
12373
13154
|
written.push(samplePath);
|
|
12374
13155
|
}
|
|
12375
|
-
const readmeSrc =
|
|
12376
|
-
const readmeDst =
|
|
12377
|
-
if (
|
|
12378
|
-
|
|
13156
|
+
const readmeSrc = join21(templateSourceDir(), "README.md");
|
|
13157
|
+
const readmeDst = join21(targetDir, "README.md");
|
|
13158
|
+
if (existsSync22(readmeSrc) && (opts.force || !existsSync22(readmeDst))) {
|
|
13159
|
+
writeFileSync7(readmeDst, readFileSync21(readmeSrc, "utf-8"), "utf-8");
|
|
12379
13160
|
written.push(readmeDst);
|
|
12380
13161
|
}
|
|
12381
13162
|
return written;
|
|
12382
13163
|
}
|
|
12383
13164
|
function templateSourceDir() {
|
|
12384
|
-
const cands = [
|
|
12385
|
-
for (const c of cands) if (
|
|
13165
|
+
const cands = [join21(__dirname11, "data", "rules_template"), join21(__dirname11, "..", "..", "agent_moss", "data", "rules_template")];
|
|
13166
|
+
for (const c of cands) if (existsSync22(c)) return c;
|
|
12386
13167
|
return cands[0];
|
|
12387
13168
|
}
|
|
12388
13169
|
function templateFiles(dirs) {
|
|
@@ -12390,7 +13171,7 @@ function templateFiles(dirs) {
|
|
|
12390
13171
|
for (const d of dirs) {
|
|
12391
13172
|
try {
|
|
12392
13173
|
for (const name of readdirSync7(d)) {
|
|
12393
|
-
if (name.endsWith(".json.\u793A\u4F8B")) out.push(
|
|
13174
|
+
if (name.endsWith(".json.\u793A\u4F8B")) out.push(join21(d, name));
|
|
12394
13175
|
}
|
|
12395
13176
|
} catch {
|
|
12396
13177
|
}
|
|
@@ -12399,7 +13180,7 @@ function templateFiles(dirs) {
|
|
|
12399
13180
|
}
|
|
12400
13181
|
function rulesStatusText() {
|
|
12401
13182
|
const lines = [];
|
|
12402
|
-
const existing = rulesDirs().filter((d) =>
|
|
13183
|
+
const existing = rulesDirs().filter((d) => existsSync22(d));
|
|
12403
13184
|
lines.push("\u89C4\u5219\u76EE\u5F55: " + (existing.length > 0 ? existing.join(", ") : "\uFF08\u672A\u8BBE\u7F6E / \u4E0D\u5B58\u5728\uFF09"));
|
|
12404
13185
|
if (existing.length > 0) {
|
|
12405
13186
|
lines.push(` \uFF08\u53EA\u8BFB\u5176\u4E2D\u7684 ${OVERRIDE_FILENAME} \u4E0E ${EXTRA_FILENAME}\uFF1B\u5176\u4ED6\u6587\u4EF6\u540D\u4E00\u5F8B\u4E0D\u8BFB\uFF09`);
|
|
@@ -12446,7 +13227,7 @@ var init_rules_tools = __esm({
|
|
|
12446
13227
|
"use strict";
|
|
12447
13228
|
init_esm_shims();
|
|
12448
13229
|
init_rules_loader();
|
|
12449
|
-
__dirname11 =
|
|
13230
|
+
__dirname11 = dirname14(fileURLToPath12(import.meta.url));
|
|
12450
13231
|
EXTRA_TEMPLATE = {
|
|
12451
13232
|
_\u8BF4\u660E: [
|
|
12452
13233
|
"\u8FFD\u52A0\u89C4\u5219\uFF1A\u5185\u7F6E\u89C4\u5219\u5168\u90E8\u4FDD\u7559\uFF0C\u4F60\u5199\u5728\u8FD9\u91CC\u7684\u89C4\u5219\u52A0\u5728\u5185\u7F6E\u4E4B\u540E\u4E00\u8D77\u5224\u5B9A\u3002",
|
|
@@ -12490,7 +13271,7 @@ init_esm_shims();
|
|
|
12490
13271
|
init_server();
|
|
12491
13272
|
init_package_json();
|
|
12492
13273
|
import { fileURLToPath as fileURLToPath13 } from "url";
|
|
12493
|
-
import { realpathSync } from "fs";
|
|
13274
|
+
import { realpathSync as realpathSync2 } from "fs";
|
|
12494
13275
|
function printHelp() {
|
|
12495
13276
|
console.log(`AgentMoss security analysis engine (TypeScript v${version})
|
|
12496
13277
|
|
|
@@ -12794,13 +13575,13 @@ async function main() {
|
|
|
12794
13575
|
const otherInstances = [];
|
|
12795
13576
|
for (let port = 9090; port <= 9095; port++) {
|
|
12796
13577
|
try {
|
|
12797
|
-
const data = await new Promise((
|
|
13578
|
+
const data = await new Promise((resolve12, reject) => {
|
|
12798
13579
|
const req = http.get(`http://127.0.0.1:${port}/api/v1/health`, { timeout: 2e3 }, (res) => {
|
|
12799
13580
|
let body = "";
|
|
12800
13581
|
res.on("data", (chunk) => body += chunk);
|
|
12801
13582
|
res.on("end", () => {
|
|
12802
13583
|
try {
|
|
12803
|
-
|
|
13584
|
+
resolve12(JSON.parse(body));
|
|
12804
13585
|
} catch {
|
|
12805
13586
|
reject();
|
|
12806
13587
|
}
|
|
@@ -12832,13 +13613,13 @@ async function main() {
|
|
|
12832
13613
|
console.log(` Systemd: \u672A\u6CE8\u518C\uFF08\u8FD0\u884C agent-moss install --enable \u5B89\u88C5\uFF09`);
|
|
12833
13614
|
}
|
|
12834
13615
|
try {
|
|
12835
|
-
const data = await new Promise((
|
|
13616
|
+
const data = await new Promise((resolve12, reject) => {
|
|
12836
13617
|
const req = http.get(`http://127.0.0.1:${foundPort}/console/api/config`, { timeout: 3e3 }, (res) => {
|
|
12837
13618
|
let body = "";
|
|
12838
13619
|
res.on("data", (chunk) => body += chunk);
|
|
12839
13620
|
res.on("end", () => {
|
|
12840
13621
|
try {
|
|
12841
|
-
|
|
13622
|
+
resolve12(JSON.parse(body));
|
|
12842
13623
|
} catch {
|
|
12843
13624
|
reject();
|
|
12844
13625
|
}
|
|
@@ -12893,8 +13674,8 @@ async function main() {
|
|
|
12893
13674
|
var isMain = (() => {
|
|
12894
13675
|
try {
|
|
12895
13676
|
if (!process.argv[1]) return false;
|
|
12896
|
-
const thisFile =
|
|
12897
|
-
const argv1 =
|
|
13677
|
+
const thisFile = realpathSync2(fileURLToPath13(import.meta.url));
|
|
13678
|
+
const argv1 = realpathSync2(
|
|
12898
13679
|
process.argv[1].startsWith("file://") ? fileURLToPath13(process.argv[1]) : process.argv[1]
|
|
12899
13680
|
);
|
|
12900
13681
|
return thisFile === argv1;
|