@kenhkl/agent-moss 0.12.6 → 0.12.7
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 +644 -18
- package/dist/cli.js.map +1 -1
- package/dist/engine/coordinator.d.ts +3 -1
- package/dist/engine/coordinator.js +603 -2
- package/dist/engine/coordinator.js.map +1 -1
- package/dist/rules/l1_rules.json +21 -0
- package/dist/server.js +612 -17
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
- package/dist/skills/brain_script_execution_php_r_system.md +0 -17
- package/dist/skills/brain_script_execution_python_c_import.md +0 -17
package/dist/cli.js
CHANGED
|
@@ -137,6 +137,7 @@ __export(config_exports, {
|
|
|
137
137
|
getProviderHeaders: () => getProviderHeaders,
|
|
138
138
|
getRetryConfig: () => getRetryConfig,
|
|
139
139
|
getTimeoutConfig: () => getTimeoutConfig,
|
|
140
|
+
isBrainEnabled: () => isBrainEnabled,
|
|
140
141
|
isHeuristicEnabled: () => isHeuristicEnabled,
|
|
141
142
|
isLLMAvailable: () => isLLMAvailable,
|
|
142
143
|
isLogicRulesEnabled: () => isLogicRulesEnabled,
|
|
@@ -256,11 +257,11 @@ function isLLMAvailable() {
|
|
|
256
257
|
}
|
|
257
258
|
async function probeLLMConnection(timeoutMs = 8e3) {
|
|
258
259
|
if (!isLLMAvailable()) return false;
|
|
259
|
-
const
|
|
260
|
+
const OpenAI3 = (await import("openai")).default;
|
|
260
261
|
const config = getLLMConfig();
|
|
261
262
|
const provider = detectProvider(config.baseUrl, config.provider);
|
|
262
263
|
const extraHeaders = getProviderHeaders(provider);
|
|
263
|
-
const client = new
|
|
264
|
+
const client = new OpenAI3({
|
|
264
265
|
baseURL: config.baseUrl,
|
|
265
266
|
apiKey: config.apiKey,
|
|
266
267
|
timeout: timeoutMs,
|
|
@@ -318,6 +319,9 @@ function getProviderHeaders(provider) {
|
|
|
318
319
|
function isHeuristicEnabled() {
|
|
319
320
|
return process.env.AGENT_MOSS_DISABLE_HEURISTIC !== "1";
|
|
320
321
|
}
|
|
322
|
+
function isBrainEnabled() {
|
|
323
|
+
return process.env.AGENT_MOSS_BRAIN_ENABLED === "1";
|
|
324
|
+
}
|
|
321
325
|
function isLogicRulesEnabled() {
|
|
322
326
|
return process.env.AGENT_MOSS_DISABLE_LOGIC_RULES !== "1";
|
|
323
327
|
}
|
|
@@ -3957,10 +3961,561 @@ var init_llm_analyzer = __esm({
|
|
|
3957
3961
|
}
|
|
3958
3962
|
});
|
|
3959
3963
|
|
|
3964
|
+
// src/brain/rule-store.ts
|
|
3965
|
+
import { existsSync as existsSync9, readFileSync as readFileSync10, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
3966
|
+
import { join as join5 } from "path";
|
|
3967
|
+
import { homedir as homedir3 } from "os";
|
|
3968
|
+
function getRulesPath() {
|
|
3969
|
+
const envPath = process.env[ENV_RULES_PATH];
|
|
3970
|
+
if (envPath) return envPath;
|
|
3971
|
+
return DEFAULT_RULES_PATH;
|
|
3972
|
+
}
|
|
3973
|
+
function uuid() {
|
|
3974
|
+
try {
|
|
3975
|
+
return crypto.randomUUID();
|
|
3976
|
+
} catch {
|
|
3977
|
+
return `rule_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
3978
|
+
}
|
|
3979
|
+
}
|
|
3980
|
+
var DEFAULT_RULES_PATH, ENV_RULES_PATH, STATUS_DRAFT, STATUS_APPROVED, STATUS_ACTIVE, STATUS_DISPUTED, STATUS_STALE, STATUS_ARCHIVED, STATUS_REJECTED, BrainRuleStore;
|
|
3981
|
+
var init_rule_store = __esm({
|
|
3982
|
+
"src/brain/rule-store.ts"() {
|
|
3983
|
+
"use strict";
|
|
3984
|
+
init_esm_shims();
|
|
3985
|
+
DEFAULT_RULES_PATH = join5(homedir3(), ".agentmoss", "brain", "rules.json");
|
|
3986
|
+
ENV_RULES_PATH = "AGENT_MOSS_BRAIN_RULES_PATH";
|
|
3987
|
+
STATUS_DRAFT = "draft";
|
|
3988
|
+
STATUS_APPROVED = "approved";
|
|
3989
|
+
STATUS_ACTIVE = "active";
|
|
3990
|
+
STATUS_DISPUTED = "disputed";
|
|
3991
|
+
STATUS_STALE = "stale";
|
|
3992
|
+
STATUS_ARCHIVED = "archived";
|
|
3993
|
+
STATUS_REJECTED = "rejected";
|
|
3994
|
+
BrainRuleStore = class {
|
|
3995
|
+
path;
|
|
3996
|
+
data;
|
|
3997
|
+
constructor(path3) {
|
|
3998
|
+
this.path = path3 || getRulesPath();
|
|
3999
|
+
this.data = this.load();
|
|
4000
|
+
}
|
|
4001
|
+
load() {
|
|
4002
|
+
if (!existsSync9(this.path)) {
|
|
4003
|
+
return { version: 1, rules: [], pattern_candidates: [] };
|
|
4004
|
+
}
|
|
4005
|
+
try {
|
|
4006
|
+
const raw = JSON.parse(readFileSync10(this.path, "utf-8"));
|
|
4007
|
+
return {
|
|
4008
|
+
version: raw.version || 1,
|
|
4009
|
+
rules: raw.rules || [],
|
|
4010
|
+
pattern_candidates: raw.pattern_candidates || []
|
|
4011
|
+
};
|
|
4012
|
+
} catch {
|
|
4013
|
+
return { version: 1, rules: [], pattern_candidates: [] };
|
|
4014
|
+
}
|
|
4015
|
+
}
|
|
4016
|
+
save() {
|
|
4017
|
+
const dir = this.path.substring(0, this.path.lastIndexOf("/"));
|
|
4018
|
+
if (dir) mkdirSync3(dir, { recursive: true });
|
|
4019
|
+
writeFileSync3(this.path, JSON.stringify(this.data, null, 2), "utf-8");
|
|
4020
|
+
}
|
|
4021
|
+
addRule(rule) {
|
|
4022
|
+
const now = Date.now();
|
|
4023
|
+
const full = {
|
|
4024
|
+
id: rule.id || uuid(),
|
|
4025
|
+
layer: rule.layer,
|
|
4026
|
+
ruleType: rule.ruleType || "deny_pattern",
|
|
4027
|
+
pattern: rule.pattern,
|
|
4028
|
+
scope: rule.scope || "all",
|
|
4029
|
+
source: rule.source || "llm_extracted",
|
|
4030
|
+
sourceEventIds: rule.sourceEventIds || [],
|
|
4031
|
+
confidence: rule.confidence || 0,
|
|
4032
|
+
status: rule.status || STATUS_DRAFT,
|
|
4033
|
+
createdAt: rule.createdAt || now,
|
|
4034
|
+
lastTriggeredAt: rule.lastTriggeredAt || 0,
|
|
4035
|
+
triggerCount: rule.triggerCount || 0,
|
|
4036
|
+
disputedCount: rule.disputedCount || 0,
|
|
4037
|
+
explanation: rule.explanation || "",
|
|
4038
|
+
originNode: rule.originNode || "local"
|
|
4039
|
+
};
|
|
4040
|
+
this.data.rules.push(full);
|
|
4041
|
+
this.save();
|
|
4042
|
+
return full.id;
|
|
4043
|
+
}
|
|
4044
|
+
approveRule(ruleId) {
|
|
4045
|
+
const rule = this.getRule(ruleId);
|
|
4046
|
+
if (!rule) throw new Error(`\u89C4\u5219\u4E0D\u5B58\u5728: ${ruleId}`);
|
|
4047
|
+
if (rule.status !== STATUS_DRAFT) throw new Error(`\u53EA\u6709 draft \u72B6\u6001\u53EF\u5BA1\u6838\uFF0C\u5F53\u524D: ${rule.status}`);
|
|
4048
|
+
rule.status = STATUS_ACTIVE;
|
|
4049
|
+
this.save();
|
|
4050
|
+
}
|
|
4051
|
+
rejectRule(ruleId) {
|
|
4052
|
+
const rule = this.getRule(ruleId);
|
|
4053
|
+
if (!rule) throw new Error(`\u89C4\u5219\u4E0D\u5B58\u5728: ${ruleId}`);
|
|
4054
|
+
if (rule.status !== STATUS_DRAFT) throw new Error(`\u53EA\u6709 draft \u72B6\u6001\u53EF\u62D2\u7EDD\uFF0C\u5F53\u524D: ${rule.status}`);
|
|
4055
|
+
rule.status = STATUS_REJECTED;
|
|
4056
|
+
this.save();
|
|
4057
|
+
}
|
|
4058
|
+
getRule(ruleId) {
|
|
4059
|
+
return this.data.rules.find((r) => r.id === ruleId);
|
|
4060
|
+
}
|
|
4061
|
+
getActiveRules(layer) {
|
|
4062
|
+
return this.data.rules.filter((r) => r.status === STATUS_ACTIVE && (layer === void 0 || r.layer === layer));
|
|
4063
|
+
}
|
|
4064
|
+
getDraftRules() {
|
|
4065
|
+
return this.data.rules.filter((r) => r.status === STATUS_DRAFT).sort((a, b) => b.createdAt - a.createdAt);
|
|
4066
|
+
}
|
|
4067
|
+
recordTrigger(ruleId) {
|
|
4068
|
+
const rule = this.getRule(ruleId);
|
|
4069
|
+
if (!rule) return;
|
|
4070
|
+
rule.triggerCount += 1;
|
|
4071
|
+
rule.lastTriggeredAt = Date.now();
|
|
4072
|
+
this.save();
|
|
4073
|
+
}
|
|
4074
|
+
// --- pattern_candidates ---
|
|
4075
|
+
addPatternCandidate(pattern, layer, scope, sourceEventId, confidence) {
|
|
4076
|
+
const now = Date.now();
|
|
4077
|
+
const existing = this.data.pattern_candidates.find(
|
|
4078
|
+
(c) => c.pattern === pattern && c.layer === layer && c.scope === scope
|
|
4079
|
+
);
|
|
4080
|
+
if (existing) {
|
|
4081
|
+
if (existing.reviewStatus === "rejected") return 0;
|
|
4082
|
+
existing.occurrenceCount += 1;
|
|
4083
|
+
existing.lastSeenAt = now;
|
|
4084
|
+
existing.sourceEventIds.unshift(sourceEventId);
|
|
4085
|
+
this.save();
|
|
4086
|
+
return existing.occurrenceCount;
|
|
4087
|
+
}
|
|
4088
|
+
this.data.pattern_candidates.push({
|
|
4089
|
+
pattern,
|
|
4090
|
+
layer,
|
|
4091
|
+
scope,
|
|
4092
|
+
sourceEventIds: [sourceEventId],
|
|
4093
|
+
confidence,
|
|
4094
|
+
occurrenceCount: 1,
|
|
4095
|
+
firstSeenAt: now,
|
|
4096
|
+
lastSeenAt: now,
|
|
4097
|
+
reviewStatus: "pending",
|
|
4098
|
+
reviewReason: "",
|
|
4099
|
+
reviewedAt: 0
|
|
4100
|
+
});
|
|
4101
|
+
this.save();
|
|
4102
|
+
return 1;
|
|
4103
|
+
}
|
|
4104
|
+
getPatternCandidates(minOccurrences = 3) {
|
|
4105
|
+
return this.data.pattern_candidates.filter((c) => c.occurrenceCount >= minOccurrences && c.reviewStatus !== "rejected").sort((a, b) => b.occurrenceCount - a.occurrenceCount);
|
|
4106
|
+
}
|
|
4107
|
+
getPendingReviewCandidates(minOccurrences = 3) {
|
|
4108
|
+
return this.data.pattern_candidates.filter((c) => c.occurrenceCount >= minOccurrences && c.reviewStatus === "pending").sort((a, b) => b.occurrenceCount - a.occurrenceCount);
|
|
4109
|
+
}
|
|
4110
|
+
isExcludedPattern(pattern, layer, scope) {
|
|
4111
|
+
const c = this.data.pattern_candidates.find(
|
|
4112
|
+
(c2) => c2.pattern === pattern && c2.layer === layer && c2.scope === scope
|
|
4113
|
+
);
|
|
4114
|
+
return !!c && c.reviewStatus === "rejected";
|
|
4115
|
+
}
|
|
4116
|
+
setPatternReviewStatus(pattern, layer, scope, status, reason = "") {
|
|
4117
|
+
const c = this.data.pattern_candidates.find(
|
|
4118
|
+
(c2) => c2.pattern === pattern && c2.layer === layer && c2.scope === scope
|
|
4119
|
+
);
|
|
4120
|
+
if (c) {
|
|
4121
|
+
c.reviewStatus = status;
|
|
4122
|
+
c.reviewReason = reason;
|
|
4123
|
+
c.reviewedAt = Date.now();
|
|
4124
|
+
this.save();
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
removePatternCandidate(pattern, layer, scope) {
|
|
4128
|
+
this.data.pattern_candidates = this.data.pattern_candidates.filter(
|
|
4129
|
+
(c) => !(c.pattern === pattern && c.layer === layer && c.scope === scope)
|
|
4130
|
+
);
|
|
4131
|
+
this.save();
|
|
4132
|
+
}
|
|
4133
|
+
getStats() {
|
|
4134
|
+
const count = (status) => this.data.rules.filter((r) => r.status === status).length;
|
|
4135
|
+
return {
|
|
4136
|
+
draft: count(STATUS_DRAFT),
|
|
4137
|
+
approved: count(STATUS_APPROVED),
|
|
4138
|
+
active: count(STATUS_ACTIVE),
|
|
4139
|
+
disputed: count(STATUS_DISPUTED),
|
|
4140
|
+
stale: count(STATUS_STALE),
|
|
4141
|
+
archived: count(STATUS_ARCHIVED),
|
|
4142
|
+
rejected: count(STATUS_REJECTED),
|
|
4143
|
+
total: this.data.rules.length,
|
|
4144
|
+
by_layer: {
|
|
4145
|
+
1: this.data.rules.filter((r) => r.layer === 1 && r.status === STATUS_ACTIVE).length,
|
|
4146
|
+
2: this.data.rules.filter((r) => r.layer === 2 && r.status === STATUS_ACTIVE).length
|
|
4147
|
+
},
|
|
4148
|
+
pattern_candidates: this.data.pattern_candidates.length
|
|
4149
|
+
};
|
|
4150
|
+
}
|
|
4151
|
+
};
|
|
4152
|
+
}
|
|
4153
|
+
});
|
|
4154
|
+
|
|
4155
|
+
// src/brain/pattern-extractor.ts
|
|
4156
|
+
var PatternExtractor;
|
|
4157
|
+
var init_pattern_extractor = __esm({
|
|
4158
|
+
"src/brain/pattern-extractor.ts"() {
|
|
4159
|
+
"use strict";
|
|
4160
|
+
init_esm_shims();
|
|
4161
|
+
init_rule_store();
|
|
4162
|
+
PatternExtractor = class {
|
|
4163
|
+
ruleStore;
|
|
4164
|
+
minConfidence;
|
|
4165
|
+
minOccurrences;
|
|
4166
|
+
builtinPatterns;
|
|
4167
|
+
reviewFn;
|
|
4168
|
+
constructor(ruleStore, opts) {
|
|
4169
|
+
this.ruleStore = ruleStore;
|
|
4170
|
+
this.minConfidence = opts?.minConfidence ?? 0.9;
|
|
4171
|
+
this.minOccurrences = opts?.minOccurrences ?? 3;
|
|
4172
|
+
this.builtinPatterns = opts?.builtinPatterns ?? [];
|
|
4173
|
+
this.reviewFn = opts?.review ?? null;
|
|
4174
|
+
}
|
|
4175
|
+
async extract(event, llmResult) {
|
|
4176
|
+
const result = { rulesCreated: 0, patternsRecorded: 0, skippedReason: "", deduped: [] };
|
|
4177
|
+
const confidence = llmResult.confidence ?? 0;
|
|
4178
|
+
const reason = llmResult.reason ?? "";
|
|
4179
|
+
const riskType = llmResult.riskType ?? "";
|
|
4180
|
+
const actionDetail = llmResult.actionDetail ?? event.actionDetail ?? "";
|
|
4181
|
+
const eventId = event.eventId ?? "";
|
|
4182
|
+
if (confidence < this.minConfidence) {
|
|
4183
|
+
result.skippedReason = `confidence ${confidence} < ${this.minConfidence}`;
|
|
4184
|
+
return result;
|
|
4185
|
+
}
|
|
4186
|
+
const patterns = this.extractPatterns(actionDetail, reason, riskType);
|
|
4187
|
+
if (patterns.length === 0) {
|
|
4188
|
+
result.skippedReason = "no extractable pattern";
|
|
4189
|
+
return result;
|
|
4190
|
+
}
|
|
4191
|
+
for (const p of patterns) {
|
|
4192
|
+
if (this.isCoveredByBuiltin(actionDetail)) {
|
|
4193
|
+
result.deduped.push(p.pattern);
|
|
4194
|
+
continue;
|
|
4195
|
+
}
|
|
4196
|
+
const count = this.ruleStore.addPatternCandidate(
|
|
4197
|
+
p.pattern,
|
|
4198
|
+
p.layer,
|
|
4199
|
+
p.scope,
|
|
4200
|
+
eventId,
|
|
4201
|
+
confidence
|
|
4202
|
+
);
|
|
4203
|
+
if (count === 0) {
|
|
4204
|
+
result.deduped.push(p.pattern);
|
|
4205
|
+
continue;
|
|
4206
|
+
}
|
|
4207
|
+
result.patternsRecorded += 1;
|
|
4208
|
+
if (count >= this.minOccurrences) {
|
|
4209
|
+
const candidates = this.ruleStore.getPatternCandidates(this.minOccurrences);
|
|
4210
|
+
const matched = candidates.find((c) => c.pattern === p.pattern && c.layer === p.layer);
|
|
4211
|
+
if (!matched) continue;
|
|
4212
|
+
if (this.reviewFn) {
|
|
4213
|
+
let review;
|
|
4214
|
+
try {
|
|
4215
|
+
review = await this.reviewFn({
|
|
4216
|
+
pattern: p.pattern,
|
|
4217
|
+
layer: p.layer,
|
|
4218
|
+
ruleType: p.ruleType,
|
|
4219
|
+
actionDetail,
|
|
4220
|
+
reason
|
|
4221
|
+
});
|
|
4222
|
+
} catch {
|
|
4223
|
+
review = null;
|
|
4224
|
+
}
|
|
4225
|
+
if (review === null) {
|
|
4226
|
+
continue;
|
|
4227
|
+
}
|
|
4228
|
+
if (!review.shouldKeep) {
|
|
4229
|
+
this.ruleStore.setPatternReviewStatus(
|
|
4230
|
+
p.pattern,
|
|
4231
|
+
p.layer,
|
|
4232
|
+
p.scope,
|
|
4233
|
+
"rejected",
|
|
4234
|
+
review.reason || "LLM \u5BA1\u6838\u62D2\u7EDD"
|
|
4235
|
+
);
|
|
4236
|
+
result.deduped.push(p.pattern);
|
|
4237
|
+
continue;
|
|
4238
|
+
}
|
|
4239
|
+
this.ruleStore.setPatternReviewStatus(
|
|
4240
|
+
p.pattern,
|
|
4241
|
+
p.layer,
|
|
4242
|
+
p.scope,
|
|
4243
|
+
"approved",
|
|
4244
|
+
review.reason || "LLM \u5BA1\u6838\u901A\u8FC7"
|
|
4245
|
+
);
|
|
4246
|
+
}
|
|
4247
|
+
this.ruleStore.addRule({
|
|
4248
|
+
layer: p.layer,
|
|
4249
|
+
ruleType: p.ruleType,
|
|
4250
|
+
pattern: p.pattern,
|
|
4251
|
+
scope: p.scope,
|
|
4252
|
+
source: "llm_extracted",
|
|
4253
|
+
sourceEventIds: eventId ? [eventId] : [],
|
|
4254
|
+
confidence: matched.confidence,
|
|
4255
|
+
status: STATUS_DRAFT,
|
|
4256
|
+
explanation: `\u4ECE ${count} \u6B21 LLM Deny \u4E2D\u63D0\u53D6(\u7ECF\u5BA1\u6838): ${reason.slice(0, 200)}`
|
|
4257
|
+
});
|
|
4258
|
+
this.ruleStore.removePatternCandidate(p.pattern, p.layer, p.scope);
|
|
4259
|
+
result.rulesCreated += 1;
|
|
4260
|
+
}
|
|
4261
|
+
}
|
|
4262
|
+
return result;
|
|
4263
|
+
}
|
|
4264
|
+
extractPatterns(actionDetail, reason, riskType) {
|
|
4265
|
+
const patterns = [];
|
|
4266
|
+
const detailLower = actionDetail.toLowerCase();
|
|
4267
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4268
|
+
const sensitivePathRe = /(\/(?:etc|root)(?:\/[^\s;|&"'<>`$]*)?|(?:[^\s;|&"'<>`$]*)?\/\.ssh\/[^\s;|&"'<>`$]*|(?:[^\s;|&"'<>`$]*)?\/\.aws\/[^\s;|&"'<>`$]*|\S+\.(?:pem|key|p12|pfx|id_rsa|authorized_keys)\b)/;
|
|
4269
|
+
const m = detailLower.match(sensitivePathRe);
|
|
4270
|
+
if (m) {
|
|
4271
|
+
const gen = this.generalizePath(m[1]);
|
|
4272
|
+
if (!seen.has(gen)) {
|
|
4273
|
+
seen.add(gen);
|
|
4274
|
+
patterns.push({ pattern: gen, layer: 1, scope: "openat", ruleType: "deny_path" });
|
|
4275
|
+
}
|
|
4276
|
+
}
|
|
4277
|
+
const dangerousCmdRe = /\b(rm\s+-[a-zA-Z]*r[a-zA-Z]*f|rm\s+--recursive|chmod\s+777|curl\s+[^|]*\|\s*(?:ba)?sh|wget\s+[^|]*\|\s*(?:ba)?sh|mkfs\.|dd\s+if=|>\s*\/dev\/sd)\b/;
|
|
4278
|
+
const cmdM = detailLower.match(dangerousCmdRe);
|
|
4279
|
+
if (cmdM) {
|
|
4280
|
+
const gen = this.generalizeCommand(cmdM[1]);
|
|
4281
|
+
const seenKey = `cmd:${gen}`;
|
|
4282
|
+
if (!seen.has(seenKey)) {
|
|
4283
|
+
seen.add(seenKey);
|
|
4284
|
+
patterns.push({ pattern: gen, layer: 1, scope: "execve", ruleType: "deny_command" });
|
|
4285
|
+
}
|
|
4286
|
+
}
|
|
4287
|
+
const reasonLower = (reason || "").toLowerCase();
|
|
4288
|
+
if (reasonLower.includes("inject") || reasonLower.includes("\u6570\u636E\u6CE8\u5165")) {
|
|
4289
|
+
patterns.push({
|
|
4290
|
+
pattern: "BEHAVIOR_CHAIN:external_read\u2192sensitive_write",
|
|
4291
|
+
layer: 2,
|
|
4292
|
+
scope: "all",
|
|
4293
|
+
ruleType: "deny_pattern"
|
|
4294
|
+
});
|
|
4295
|
+
}
|
|
4296
|
+
if (reasonLower.includes("reconnaissance") || reasonLower.includes("\u4FA6\u5BDF") || reasonLower.includes("\u63D0\u6743")) {
|
|
4297
|
+
patterns.push({
|
|
4298
|
+
pattern: "BEHAVIOR_CHAIN:multi_config_read\u2192privilege_action",
|
|
4299
|
+
layer: 2,
|
|
4300
|
+
scope: "all",
|
|
4301
|
+
ruleType: "deny_pattern"
|
|
4302
|
+
});
|
|
4303
|
+
}
|
|
4304
|
+
const pathPrefix = `(?:^|[\\s"'(=])`;
|
|
4305
|
+
const pathBody = "(\\/(?:[a-zA-Z0-9_.-]+\\/)+[a-zA-Z0-9_.-]+)";
|
|
4306
|
+
const pathSuffix = `(?=[\\s"')\uFF0C\u3002\uFF09\uFF1B;]|$)`;
|
|
4307
|
+
for (const src of [detailLower, reasonLower]) {
|
|
4308
|
+
const pathRe = new RegExp(pathPrefix + pathBody + pathSuffix, "g");
|
|
4309
|
+
let mm;
|
|
4310
|
+
while ((mm = pathRe.exec(src)) !== null) {
|
|
4311
|
+
const path3 = mm[1];
|
|
4312
|
+
if (path3.split("/").length < 3) continue;
|
|
4313
|
+
if (["/dev/null", "/dev/zero", "/dev/random", "/dev/urandom"].includes(path3)) continue;
|
|
4314
|
+
const gen = this.generalizePath(path3);
|
|
4315
|
+
if (seen.has(gen)) continue;
|
|
4316
|
+
seen.add(gen);
|
|
4317
|
+
patterns.push({ pattern: gen, layer: 1, scope: "openat", ruleType: "deny_path" });
|
|
4318
|
+
}
|
|
4319
|
+
}
|
|
4320
|
+
return patterns;
|
|
4321
|
+
}
|
|
4322
|
+
isCoveredByBuiltin(actionDetail) {
|
|
4323
|
+
if (this.builtinPatterns.length === 0 || !actionDetail) return false;
|
|
4324
|
+
for (const pat of this.builtinPatterns) {
|
|
4325
|
+
try {
|
|
4326
|
+
if (new RegExp(pat, "i").test(actionDetail)) return true;
|
|
4327
|
+
} catch {
|
|
4328
|
+
continue;
|
|
4329
|
+
}
|
|
4330
|
+
}
|
|
4331
|
+
return false;
|
|
4332
|
+
}
|
|
4333
|
+
generalizePath(path3) {
|
|
4334
|
+
const p = path3.toLowerCase();
|
|
4335
|
+
if (/\/etc\/(shadow|passwd|sudoers|security|ssh)/.test(p)) {
|
|
4336
|
+
return "(?:^|[^a-z0-9_-])etc/(?:shadow|passwd|sudoers|security/|ssh/)";
|
|
4337
|
+
}
|
|
4338
|
+
if (p.includes("/etc/")) {
|
|
4339
|
+
return "(?:^|[^a-z0-9_-])etc/";
|
|
4340
|
+
}
|
|
4341
|
+
if (p.includes("/root/")) {
|
|
4342
|
+
return "(?:^|[^a-z0-9_-])root/\\.(?:ssh|gnupg|aws|config)/";
|
|
4343
|
+
}
|
|
4344
|
+
if (p.includes(".ssh/")) {
|
|
4345
|
+
return "(?:^|[^a-z0-9_-])[\\w./-]*/\\.ssh/";
|
|
4346
|
+
}
|
|
4347
|
+
if (p.includes(".aws/")) {
|
|
4348
|
+
return "(?:^|[^a-z0-9_-])[\\w./-]*/\\.aws/";
|
|
4349
|
+
}
|
|
4350
|
+
if (/\.(pem|key|p12|pfx|id_rsa|authorized_keys)\b/.test(p)) {
|
|
4351
|
+
return "[\\w./-]*\\.(?:pem|key|p12|pfx|id_rsa|authorized_keys)(?:$|[^a-z0-9])";
|
|
4352
|
+
}
|
|
4353
|
+
const escaped = p.replace(/^\//, "").replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4354
|
+
return `(?:^|[^a-z0-9_-])${escaped}(?:/|\\b)`;
|
|
4355
|
+
}
|
|
4356
|
+
generalizeCommand(cmd) {
|
|
4357
|
+
if (cmd.includes("rm") && cmd.includes("r") && cmd.includes("f")) {
|
|
4358
|
+
return "rm\\s+(?:-[a-zA-Z]*r[a-zA-Z]*f|--recursive)\\s+/";
|
|
4359
|
+
}
|
|
4360
|
+
if (cmd.includes("chmod")) return "chmod\\s+777";
|
|
4361
|
+
if (cmd.includes("curl") || cmd.includes("wget")) {
|
|
4362
|
+
return "(?:curl|wget)\\s+[^|]*\\|\\s*(?:ba)?sh";
|
|
4363
|
+
}
|
|
4364
|
+
if (cmd.includes("mkfs")) return "mkfs\\.";
|
|
4365
|
+
if (cmd.includes("dd")) return "dd\\s+if=";
|
|
4366
|
+
return cmd.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4367
|
+
}
|
|
4368
|
+
};
|
|
4369
|
+
}
|
|
4370
|
+
});
|
|
4371
|
+
|
|
4372
|
+
// src/brain/reviewer.ts
|
|
4373
|
+
import OpenAI2 from "openai";
|
|
4374
|
+
function createBrainReviewer(timeoutMs = 1e4) {
|
|
4375
|
+
return async (opts) => {
|
|
4376
|
+
if (process.env.AGENT_MOSS_BRAIN_REVIEW === "0") return null;
|
|
4377
|
+
if (!isLLMAvailable()) return null;
|
|
4378
|
+
const config = getLLMConfig();
|
|
4379
|
+
const provider = detectProvider(config.baseUrl, config.provider);
|
|
4380
|
+
const extraHeaders = getProviderHeaders(provider);
|
|
4381
|
+
const client = new OpenAI2({
|
|
4382
|
+
baseURL: config.baseUrl,
|
|
4383
|
+
apiKey: config.apiKey,
|
|
4384
|
+
timeout: timeoutMs,
|
|
4385
|
+
maxRetries: 1,
|
|
4386
|
+
defaultHeaders: Object.keys(extraHeaders).length > 0 ? extraHeaders : void 0
|
|
4387
|
+
});
|
|
4388
|
+
const prompt = REVIEW_PROMPT.replace("{pattern}", opts.pattern).replace("{layer}", String(opts.layer)).replace("{ruleType}", opts.ruleType).replace("{actionDetail}", (opts.actionDetail || "").slice(0, 400)).replace("{reason}", (opts.reason || "").slice(0, 400));
|
|
4389
|
+
try {
|
|
4390
|
+
const response = await client.chat.completions.create({
|
|
4391
|
+
model: config.model,
|
|
4392
|
+
temperature: config.temperature || 0.1,
|
|
4393
|
+
max_tokens: 256,
|
|
4394
|
+
messages: [
|
|
4395
|
+
{ role: "system", content: "\u53EA\u8F93\u51FA\u7EAF JSON\uFF0C\u4E0D\u8981\u5305\u542B markdown \u6807\u8BB0\u3001\u4EE3\u7801\u5757\u6216\u4EFB\u4F55\u5176\u4ED6\u6587\u5B57\u3002" },
|
|
4396
|
+
{ role: "user", content: prompt }
|
|
4397
|
+
]
|
|
4398
|
+
});
|
|
4399
|
+
const content = response.choices[0]?.message?.content || "";
|
|
4400
|
+
const parsed = parseReview(content);
|
|
4401
|
+
return { shouldKeep: parsed.shouldKeep, reason: parsed.reason };
|
|
4402
|
+
} catch (e) {
|
|
4403
|
+
console.warn(`[AgentMoss] Brain \u5BA1\u6838 LLM \u8C03\u7528\u5931\u8D25\uFF08\u964D\u7EA7\u4FDD\u6301\u5019\u9009\uFF09: ${e.message}`);
|
|
4404
|
+
return null;
|
|
4405
|
+
}
|
|
4406
|
+
};
|
|
4407
|
+
}
|
|
4408
|
+
function parseReview(content) {
|
|
4409
|
+
let text = content.trim();
|
|
4410
|
+
if (text.startsWith("```")) {
|
|
4411
|
+
text = text.replace(/^```[a-zA-Z]*\n?/, "").replace(/\n?```$/, "");
|
|
4412
|
+
}
|
|
4413
|
+
const match = text.match(/\{[\s\S]*\}/);
|
|
4414
|
+
if (!match) throw new Error(`\u5BA1\u6838\u54CD\u5E94\u65E0 JSON \u5BF9\u8C61: ${text.slice(0, 200)}`);
|
|
4415
|
+
const data = JSON.parse(match[0]);
|
|
4416
|
+
if (!("should_keep" in data) && !("shouldKeep" in data)) {
|
|
4417
|
+
throw new Error(`\u5BA1\u6838\u54CD\u5E94\u7F3A should_keep: ${text.slice(0, 200)}`);
|
|
4418
|
+
}
|
|
4419
|
+
let shouldKeep = data.shouldKeep ?? data.should_keep;
|
|
4420
|
+
if (typeof shouldKeep === "string") {
|
|
4421
|
+
shouldKeep = ["true", "1", "\u662F", "yes"].includes(shouldKeep.trim().toLowerCase());
|
|
4422
|
+
}
|
|
4423
|
+
return {
|
|
4424
|
+
shouldKeep: !!shouldKeep,
|
|
4425
|
+
confidence: Number(data.confidence ?? 0) || 0,
|
|
4426
|
+
reason: String(data.reason ?? data.suggested_rule ?? "") || ""
|
|
4427
|
+
};
|
|
4428
|
+
}
|
|
4429
|
+
var REVIEW_PROMPT;
|
|
4430
|
+
var init_reviewer = __esm({
|
|
4431
|
+
"src/brain/reviewer.ts"() {
|
|
4432
|
+
"use strict";
|
|
4433
|
+
init_esm_shims();
|
|
4434
|
+
init_config();
|
|
4435
|
+
REVIEW_PROMPT = `\u4F60\u662F AgentMoss \u5B89\u5168\u89C4\u5219\u5BA1\u6838\u5668\u3002\u5224\u65AD\u4E0B\u5217"\u4ECE LLM \u62D2\u7EDD\u7ED3\u679C\u4E2D\u63D0\u53D6\u7684\u5B89\u5168\u6A21\u5F0F"\u662F\u5426\u503C\u5F97\u6C89\u6DC0\u4E3A\u672C\u5730\u89C4\u5219\u3002
|
|
4436
|
+
|
|
4437
|
+
## \u63D0\u53D6\u7684\u6A21\u5F0F\uFF08\u5019\u9009\uFF09
|
|
4438
|
+
- \u6A21\u5F0F: {pattern}
|
|
4439
|
+
- \u6240\u5C5E\u5C42: Layer {layer}\uFF081=\u7279\u5F81\u5339\u914D\uFF0C2=\u884C\u4E3A\u94FE\uFF09
|
|
4440
|
+
- \u7C7B\u578B: {ruleType}
|
|
4441
|
+
|
|
4442
|
+
## \u539F\u59CB\u88AB\u62D2\u7EDD\u7684\u64CD\u4F5C
|
|
4443
|
+
{actionDetail}
|
|
4444
|
+
|
|
4445
|
+
## LLM \u5F53\u65F6\u7684\u62D2\u7EDD\u7406\u7531
|
|
4446
|
+
{reason}
|
|
4447
|
+
|
|
4448
|
+
## \u5224\u65AD\u51C6\u5219
|
|
4449
|
+
1. **\u662F\u5426\u8FC7\u9AD8\u6CDB\u5316**\uFF1A\u8FD9\u6761\u6A21\u5F0F\u662F\u5426\u4F1A\u8BEF\u62E6\u6B63\u5E38\u7684\u5408\u6CD5\u64CD\u4F5C\uFF1F
|
|
4450
|
+
2. **\u662F\u5426\u7B26\u5408\u654F\u611F\u7279\u5F81**\uFF1A\u6307\u5411\u7684\u8DEF\u5F84/\u547D\u4EE4\u662F\u5426\u786E\u5B9E\u654F\u611F\uFF08\u51ED\u636E/\u7CFB\u7EDF\u6587\u4EF6/\u6076\u610F\u547D\u4EE4/\u5916\u4F20\uFF09\uFF1F
|
|
4451
|
+
3. **\u4E0E\u4E09\u5C42\u89C4\u5219\u91CD\u590D**\uFF1A\u662F\u5426\u5DF2\u88AB\u73B0\u6709 L1/L2 \u89C4\u5219\u8986\u76D6\uFF1F
|
|
4452
|
+
4. **\u662F\u4E0D\u662F\u771F\u5B9E\u653B\u51FB\u6A21\u5F0F**\uFF1A\u662F\u5426\u4EE3\u8868\u4E00\u79CD\u8FDE\u7EED\u7684\u653B\u51FB\u884C\u4E3A\u6A21\u5F0F\uFF1F
|
|
4453
|
+
|
|
4454
|
+
## \u8F93\u51FA JSON\uFF08\u53EA\u8F93\u51FA JSON\uFF0C\u65E0\u5176\u4ED6\u6587\u5B57\uFF09
|
|
4455
|
+
{"should_keep": true/false, "confidence": 0-100, "reason": "\u7B80\u77ED\u7406\u7531\uFF08\u4E2D\u6587\uFF09", "suggested_rule": "\u82E5\u4FDD\u7559\u5219\u8F93\u51FA\u5EFA\u8BAE\u6B63\u5219\uFF0C\u5426\u5219\u7A7A\u4E32", "duplicate_of": "\u82E5\u91CD\u590D\u5219\u8BF4\u660E\u662F\u54EA\u4E2A\uFF0C\u5426\u5219\u7A7A\u4E32"}`;
|
|
4456
|
+
}
|
|
4457
|
+
});
|
|
4458
|
+
|
|
4459
|
+
// src/brain/index.ts
|
|
4460
|
+
function checkBrainRules(store, opts) {
|
|
4461
|
+
if (!store) return null;
|
|
4462
|
+
const rules = store.getActiveRules(opts.layer);
|
|
4463
|
+
if (rules.length === 0) return null;
|
|
4464
|
+
const combined = `${opts.actionType} ${opts.actionDetail}`;
|
|
4465
|
+
for (const rule of rules) {
|
|
4466
|
+
try {
|
|
4467
|
+
if (new RegExp(rule.pattern, "i").test(combined)) {
|
|
4468
|
+
if (opts.layer === 2 && opts.actionHistory) {
|
|
4469
|
+
if (!checkLayer2Context(rule.pattern, opts.actionHistory, opts.actionDetail)) {
|
|
4470
|
+
continue;
|
|
4471
|
+
}
|
|
4472
|
+
}
|
|
4473
|
+
store.recordTrigger(rule.id);
|
|
4474
|
+
return {
|
|
4475
|
+
ruleId: rule.id,
|
|
4476
|
+
pattern: rule.pattern,
|
|
4477
|
+
explanation: rule.explanation,
|
|
4478
|
+
confidence: rule.confidence
|
|
4479
|
+
};
|
|
4480
|
+
}
|
|
4481
|
+
} catch {
|
|
4482
|
+
continue;
|
|
4483
|
+
}
|
|
4484
|
+
}
|
|
4485
|
+
return null;
|
|
4486
|
+
}
|
|
4487
|
+
function checkLayer2Context(pattern, actionHistory, actionDetail) {
|
|
4488
|
+
if (pattern.startsWith("BEHAVIOR_CHAIN:")) {
|
|
4489
|
+
const chainType = pattern.replace("BEHAVIOR_CHAIN:", "");
|
|
4490
|
+
if (chainType === "external_read\u2192sensitive_write") {
|
|
4491
|
+
const hasExternalRead = actionHistory.slice(-5).some((h) => /curl|wget|http/i.test(h.actionDetail ?? ""));
|
|
4492
|
+
const isSensitiveWrite = /\.ssh|\.gnupg|authorized_keys|bashrc|profile/i.test(actionDetail);
|
|
4493
|
+
return hasExternalRead && isSensitiveWrite;
|
|
4494
|
+
}
|
|
4495
|
+
if (chainType === "multi_config_read\u2192privilege_action") {
|
|
4496
|
+
const configReads = actionHistory.slice(-5).filter((h) => /\/etc\/|config|\.conf|\.yaml|\.json/i.test(h.actionDetail ?? "")).length;
|
|
4497
|
+
const isPrivilege = /sudo|su |chmod|chown/i.test(actionDetail);
|
|
4498
|
+
return configReads >= 2 && isPrivilege;
|
|
4499
|
+
}
|
|
4500
|
+
return false;
|
|
4501
|
+
}
|
|
4502
|
+
return true;
|
|
4503
|
+
}
|
|
4504
|
+
var init_brain = __esm({
|
|
4505
|
+
"src/brain/index.ts"() {
|
|
4506
|
+
"use strict";
|
|
4507
|
+
init_esm_shims();
|
|
4508
|
+
init_rule_store();
|
|
4509
|
+
init_pattern_extractor();
|
|
4510
|
+
init_reviewer();
|
|
4511
|
+
}
|
|
4512
|
+
});
|
|
4513
|
+
|
|
3960
4514
|
// src/engine/coordinator.ts
|
|
3961
4515
|
var coordinator_exports = {};
|
|
3962
4516
|
__export(coordinator_exports, {
|
|
3963
4517
|
TRUSTED_SKILLS_BASE: () => TRUSTED_SKILLS_BASE,
|
|
4518
|
+
_resetBrainForTest: () => _resetBrainForTest,
|
|
3964
4519
|
runAnalysis: () => runAnalysis
|
|
3965
4520
|
});
|
|
3966
4521
|
function extractFirstCommand(command) {
|
|
@@ -3981,6 +4536,20 @@ function extractRawCommand(detail) {
|
|
|
3981
4536
|
function matchesAny(cmd, patterns) {
|
|
3982
4537
|
return patterns.some((p) => p.test(cmd));
|
|
3983
4538
|
}
|
|
4539
|
+
function getBrainStore() {
|
|
4540
|
+
if (!isBrainEnabled()) return null;
|
|
4541
|
+
if (!_brainInitialized) {
|
|
4542
|
+
_brainStore = new BrainRuleStore();
|
|
4543
|
+
_brainExtractor = new PatternExtractor(_brainStore, { review: createBrainReviewer() });
|
|
4544
|
+
_brainInitialized = true;
|
|
4545
|
+
}
|
|
4546
|
+
return _brainStore;
|
|
4547
|
+
}
|
|
4548
|
+
function _resetBrainForTest() {
|
|
4549
|
+
_brainStore = null;
|
|
4550
|
+
_brainExtractor = null;
|
|
4551
|
+
_brainInitialized = false;
|
|
4552
|
+
}
|
|
3984
4553
|
async function runAnalysis(input) {
|
|
3985
4554
|
const heuristicResult = isHeuristicEnabled() ? runHeuristicCheck(input) : null;
|
|
3986
4555
|
const isInlineScriptCmd = isInlineScriptCommand(input.aNext.actionDetail.toLowerCase());
|
|
@@ -4013,6 +4582,25 @@ async function runAnalysis(input) {
|
|
|
4013
4582
|
}
|
|
4014
4583
|
}
|
|
4015
4584
|
}
|
|
4585
|
+
const brainStore = getBrainStore();
|
|
4586
|
+
if (brainStore) {
|
|
4587
|
+
const brainL1 = checkBrainRules(brainStore, {
|
|
4588
|
+
layer: 1,
|
|
4589
|
+
actionType: input.aNext.actionType,
|
|
4590
|
+
actionDetail: input.aNext.actionDetail
|
|
4591
|
+
});
|
|
4592
|
+
if (brainL1) {
|
|
4593
|
+
return {
|
|
4594
|
+
allowed: false,
|
|
4595
|
+
reason: `[Brain L1] ${brainL1.explanation}`,
|
|
4596
|
+
riskLevel: "high",
|
|
4597
|
+
riskType: "brain_rule",
|
|
4598
|
+
confidence: Math.round(brainL1.confidence * 100),
|
|
4599
|
+
source: "brain_rule",
|
|
4600
|
+
violatedLayers: ["brain_L1"]
|
|
4601
|
+
};
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4016
4604
|
const actionType = input.aNext.actionType.toLowerCase();
|
|
4017
4605
|
const rawDetail = extractRawCommand(input.aNext.actionDetail);
|
|
4018
4606
|
const lowerDetail = rawDetail.toLowerCase();
|
|
@@ -4138,6 +4726,25 @@ async function runAnalysis(input) {
|
|
|
4138
4726
|
}
|
|
4139
4727
|
}
|
|
4140
4728
|
}
|
|
4729
|
+
if (brainStore) {
|
|
4730
|
+
const brainL2 = checkBrainRules(brainStore, {
|
|
4731
|
+
layer: 2,
|
|
4732
|
+
actionType: input.aNext.actionType,
|
|
4733
|
+
actionDetail: input.aNext.actionDetail,
|
|
4734
|
+
actionHistory: input.actionHistory
|
|
4735
|
+
});
|
|
4736
|
+
if (brainL2) {
|
|
4737
|
+
return {
|
|
4738
|
+
allowed: false,
|
|
4739
|
+
reason: `[Brain L2] ${brainL2.explanation}`,
|
|
4740
|
+
riskLevel: "high",
|
|
4741
|
+
riskType: "brain_rule",
|
|
4742
|
+
confidence: Math.round(brainL2.confidence * 100),
|
|
4743
|
+
source: "brain_rule",
|
|
4744
|
+
violatedLayers: ["brain_L2"]
|
|
4745
|
+
};
|
|
4746
|
+
}
|
|
4747
|
+
}
|
|
4141
4748
|
if (skipLLM || !isLLMAvailable()) {
|
|
4142
4749
|
return {
|
|
4143
4750
|
allowed: true,
|
|
@@ -4204,9 +4811,23 @@ async function runAnalysis(input) {
|
|
|
4204
4811
|
violatedLayers: ["3"]
|
|
4205
4812
|
};
|
|
4206
4813
|
}
|
|
4814
|
+
if (!llmResult.allowed && llmResult.confidence && llmResult.confidence >= 90 && _brainExtractor) {
|
|
4815
|
+
try {
|
|
4816
|
+
await _brainExtractor.extract(
|
|
4817
|
+
{ actionDetail: input.aNext.actionDetail, eventId: "" },
|
|
4818
|
+
{
|
|
4819
|
+
confidence: llmResult.confidence / 100,
|
|
4820
|
+
reason: llmResult.reason || "",
|
|
4821
|
+
riskType: llmResult.riskType || "",
|
|
4822
|
+
actionDetail: input.aNext.actionDetail
|
|
4823
|
+
}
|
|
4824
|
+
);
|
|
4825
|
+
} catch {
|
|
4826
|
+
}
|
|
4827
|
+
}
|
|
4207
4828
|
return llmResult;
|
|
4208
4829
|
}
|
|
4209
|
-
var FULLY_SAFE_TOOLS, TRUSTED_SKILLS_BASE, READONLY_SENSITIVE_TOOLS, FULLY_SAFE_BASH_PATTERNS, READONLY_SENSITIVE_BASH_PATTERNS;
|
|
4830
|
+
var FULLY_SAFE_TOOLS, TRUSTED_SKILLS_BASE, READONLY_SENSITIVE_TOOLS, FULLY_SAFE_BASH_PATTERNS, READONLY_SENSITIVE_BASH_PATTERNS, _brainStore, _brainExtractor, _brainInitialized;
|
|
4210
4831
|
var init_coordinator = __esm({
|
|
4211
4832
|
"src/engine/coordinator.ts"() {
|
|
4212
4833
|
"use strict";
|
|
@@ -4218,6 +4839,8 @@ var init_coordinator = __esm({
|
|
|
4218
4839
|
init_script_content_analyzer();
|
|
4219
4840
|
init_config();
|
|
4220
4841
|
init_agents();
|
|
4842
|
+
init_brain();
|
|
4843
|
+
init_reviewer();
|
|
4221
4844
|
FULLY_SAFE_TOOLS = /* @__PURE__ */ new Set([
|
|
4222
4845
|
"ask_user_question",
|
|
4223
4846
|
"glob",
|
|
@@ -4284,6 +4907,9 @@ var init_coordinator = __esm({
|
|
|
4284
4907
|
/^sort(?:\s|$)/i,
|
|
4285
4908
|
/^uniq(?:\s|$)/i
|
|
4286
4909
|
];
|
|
4910
|
+
_brainStore = null;
|
|
4911
|
+
_brainExtractor = null;
|
|
4912
|
+
_brainInitialized = false;
|
|
4287
4913
|
}
|
|
4288
4914
|
});
|
|
4289
4915
|
|
|
@@ -4370,7 +4996,7 @@ var require_bindings = __commonJS({
|
|
|
4370
4996
|
var fs4 = __require("fs");
|
|
4371
4997
|
var path3 = __require("path");
|
|
4372
4998
|
var fileURLToPath10 = require_file_uri_to_path();
|
|
4373
|
-
var
|
|
4999
|
+
var join7 = path3.join;
|
|
4374
5000
|
var dirname8 = path3.dirname;
|
|
4375
5001
|
var exists = fs4.accessSync && function(path4) {
|
|
4376
5002
|
try {
|
|
@@ -4430,7 +5056,7 @@ var require_bindings = __commonJS({
|
|
|
4430
5056
|
var requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
4431
5057
|
var tries = [], i = 0, l = opts.try.length, n, b, err;
|
|
4432
5058
|
for (; i < l; i++) {
|
|
4433
|
-
n =
|
|
5059
|
+
n = join7.apply(
|
|
4434
5060
|
null,
|
|
4435
5061
|
opts.try[i].map(function(p) {
|
|
4436
5062
|
return opts[p] || p;
|
|
@@ -4491,7 +5117,7 @@ var require_bindings = __commonJS({
|
|
|
4491
5117
|
if (dir === ".") {
|
|
4492
5118
|
dir = process.cwd();
|
|
4493
5119
|
}
|
|
4494
|
-
if (exists(
|
|
5120
|
+
if (exists(join7(dir, "package.json")) || exists(join7(dir, "node_modules"))) {
|
|
4495
5121
|
return dir;
|
|
4496
5122
|
}
|
|
4497
5123
|
if (prev === dir) {
|
|
@@ -4500,7 +5126,7 @@ var require_bindings = __commonJS({
|
|
|
4500
5126
|
);
|
|
4501
5127
|
}
|
|
4502
5128
|
prev = dir;
|
|
4503
|
-
dir =
|
|
5129
|
+
dir = join7(dir, "..");
|
|
4504
5130
|
}
|
|
4505
5131
|
};
|
|
4506
5132
|
}
|
|
@@ -5332,11 +5958,11 @@ init_esm_shims();
|
|
|
5332
5958
|
init_runtime_config();
|
|
5333
5959
|
init_token_stats();
|
|
5334
5960
|
import { Hono } from "hono";
|
|
5335
|
-
import { readFileSync as
|
|
5336
|
-
import { join as
|
|
5961
|
+
import { readFileSync as readFileSync11, existsSync as existsSync11 } from "fs";
|
|
5962
|
+
import { join as join6, dirname as dirname7 } from "path";
|
|
5337
5963
|
import { fileURLToPath as fileURLToPath8 } from "url";
|
|
5338
5964
|
var __dirname7 = dirname7(fileURLToPath8(import.meta.url));
|
|
5339
|
-
var STATIC_DIR =
|
|
5965
|
+
var STATIC_DIR = join6(__dirname7, "static");
|
|
5340
5966
|
var CONSOLE_TOKEN_ENV = "AGENT_MOSS_CONSOLE_TOKEN";
|
|
5341
5967
|
function getConsoleToken() {
|
|
5342
5968
|
return process.env[CONSOLE_TOKEN_ENV] || "";
|
|
@@ -5360,9 +5986,9 @@ function createConsoleRouter() {
|
|
|
5360
5986
|
const console2 = new Hono();
|
|
5361
5987
|
console2.use("/api/*", authMiddleware());
|
|
5362
5988
|
const serveIndex = (c) => {
|
|
5363
|
-
const indexFile =
|
|
5364
|
-
if (
|
|
5365
|
-
return c.html(
|
|
5989
|
+
const indexFile = join6(STATIC_DIR, "index.html");
|
|
5990
|
+
if (existsSync11(indexFile)) {
|
|
5991
|
+
return c.html(readFileSync11(indexFile, "utf-8"));
|
|
5366
5992
|
}
|
|
5367
5993
|
return c.html("<h1>AgentMoss Policy Console</h1><p>Frontend not built. Use /console/api/* endpoints.</p>");
|
|
5368
5994
|
};
|
|
@@ -5453,13 +6079,13 @@ function createConsoleRouter() {
|
|
|
5453
6079
|
if (!/^[A-Za-z0-9_-]+$/.test(skillId)) {
|
|
5454
6080
|
return c.json({ error: "invalid skill_id" }, 400);
|
|
5455
6081
|
}
|
|
5456
|
-
const skillPath =
|
|
5457
|
-
if (!
|
|
5458
|
-
const builtinPath =
|
|
5459
|
-
if (
|
|
6082
|
+
const skillPath = join6(dirname7(getRuntimeConfigPath()), "agent_moss_skills", `${skillId}.md`);
|
|
6083
|
+
if (!existsSync11(skillPath)) {
|
|
6084
|
+
const builtinPath = join6(__dirname7, "..", "..", "agent_moss", "skills", `${skillId}.md`);
|
|
6085
|
+
if (existsSync11(builtinPath)) return c.text(readFileSync11(builtinPath, "utf-8"));
|
|
5460
6086
|
return c.json({ error: "skill not found" }, 404);
|
|
5461
6087
|
}
|
|
5462
|
-
return c.text(
|
|
6088
|
+
return c.text(readFileSync11(skillPath, "utf-8"));
|
|
5463
6089
|
});
|
|
5464
6090
|
console2.get("/api/agents", (c) => {
|
|
5465
6091
|
const rc = loadRuntimeConfig();
|