@kenhkl/agent-moss 0.14.0 → 0.15.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 +152 -32
- package/dist/cli.js.map +1 -1
- package/dist/engine/coordinator.js +130 -19
- package/dist/engine/coordinator.js.map +1 -1
- package/dist/rules/l2_rules.json +242 -242
- package/dist/server.js +149 -30
- package/dist/server.js.map +1 -1
- package/dist/static/index.html +18 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -633,10 +633,15 @@ function loadMC() {
|
|
|
633
633
|
try {
|
|
634
634
|
const rt = (init_runtime_config(), __toCommonJS(runtime_config_exports));
|
|
635
635
|
if (rules.length > 0 && typeof rt.hasRuntimeConfig === "function" && rt.hasRuntimeConfig()) {
|
|
636
|
-
const
|
|
636
|
+
const ltl = rt.loadRuntimeConfig()?.L2_2?.ltl_rules || {};
|
|
637
|
+
const rtRules = ltl.rules || [];
|
|
637
638
|
const enabledById = {};
|
|
638
639
|
for (const r of rtRules) if (r?.id) enabledById[r.id] = r.enabled !== false;
|
|
639
|
-
|
|
640
|
+
const catEnabled = ltl.category_enabled !== false;
|
|
641
|
+
for (const r of rules) {
|
|
642
|
+
if (r?.id && r.id in enabledById) r.enabled = enabledById[r.id];
|
|
643
|
+
if (!catEnabled) r.enabled = false;
|
|
644
|
+
}
|
|
640
645
|
}
|
|
641
646
|
} catch {
|
|
642
647
|
}
|
|
@@ -1434,6 +1439,7 @@ __export(runtime_config_exports, {
|
|
|
1434
1439
|
isLayerEnabled: () => isLayerEnabled,
|
|
1435
1440
|
loadRuntimeConfig: () => loadRuntimeConfig,
|
|
1436
1441
|
mergeConfig: () => mergeConfig,
|
|
1442
|
+
pickDeletableRule: () => pickDeletableRule,
|
|
1437
1443
|
saveRuntimeConfig: () => saveRuntimeConfig,
|
|
1438
1444
|
updateAgentCategoryEnabled: () => updateAgentCategoryEnabled,
|
|
1439
1445
|
updateAgentRuleEnabled: () => updateAgentRuleEnabled,
|
|
@@ -1599,8 +1605,16 @@ function getDisabledL2RulesWithSkipL3() {
|
|
|
1599
1605
|
function _slugify(text) {
|
|
1600
1606
|
return text.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "") || "x";
|
|
1601
1607
|
}
|
|
1608
|
+
function _fnv1a32(text) {
|
|
1609
|
+
let h = 2166136261;
|
|
1610
|
+
for (const b of Buffer.from(text, "utf-8")) {
|
|
1611
|
+
h ^= b;
|
|
1612
|
+
h = h * 16777619 >>> 0;
|
|
1613
|
+
}
|
|
1614
|
+
return h.toString(16).padStart(8, "0");
|
|
1615
|
+
}
|
|
1602
1616
|
function _generatePatternId(pattern) {
|
|
1603
|
-
return `pat_${_slugify(pattern)}`;
|
|
1617
|
+
return `pat_${_slugify(pattern)}_${_fnv1a32(pattern)}`;
|
|
1604
1618
|
}
|
|
1605
1619
|
function _deriveDenyMode(rule) {
|
|
1606
1620
|
if (rule.deny_mode) return rule.deny_mode;
|
|
@@ -1886,10 +1900,13 @@ function generateSourceDefaults() {
|
|
|
1886
1900
|
}
|
|
1887
1901
|
function _ltlRulesToRuntime() {
|
|
1888
1902
|
const cands = [
|
|
1889
|
-
join3(
|
|
1890
|
-
join3(__dirname4, "
|
|
1891
|
-
join3(
|
|
1892
|
-
|
|
1903
|
+
getRuntimeConfigDir() && join3(getRuntimeConfigDir(), "rules"),
|
|
1904
|
+
join3(__dirname4, "../rules"),
|
|
1905
|
+
join3(__dirname4, "rules"),
|
|
1906
|
+
join3(__dirname4, "../../../agent_moss/rules"),
|
|
1907
|
+
join3(__dirname4, "../../../../agent_moss/rules"),
|
|
1908
|
+
join3(process.cwd(), "agent_moss/rules")
|
|
1909
|
+
].filter(Boolean);
|
|
1893
1910
|
let mc = {};
|
|
1894
1911
|
for (const dir of cands) {
|
|
1895
1912
|
const p = join3(dir, "mc_rules.json");
|
|
@@ -2249,16 +2266,20 @@ function addCustomRule(layer, category, rule) {
|
|
|
2249
2266
|
saveRuntimeConfig(runtime);
|
|
2250
2267
|
return runtime;
|
|
2251
2268
|
}
|
|
2252
|
-
function
|
|
2253
|
-
const
|
|
2254
|
-
const rules = runtime[layer]?.[category]?.rules || [];
|
|
2255
|
-
const idx = rules.findIndex((r) => r.id === ruleId);
|
|
2269
|
+
function pickDeletableRule(rules, ruleId) {
|
|
2270
|
+
const idx = rules.findIndex((r) => r.id === ruleId && (!r.builtin || r.source_removed));
|
|
2256
2271
|
if (idx >= 0) {
|
|
2257
|
-
const r = rules[idx];
|
|
2258
|
-
if (r.builtin && !r.source_removed) return null;
|
|
2259
2272
|
rules.splice(idx, 1);
|
|
2260
|
-
|
|
2273
|
+
return rules;
|
|
2261
2274
|
}
|
|
2275
|
+
if (rules.some((r) => r.id === ruleId)) return null;
|
|
2276
|
+
return rules;
|
|
2277
|
+
}
|
|
2278
|
+
function deleteCustomRule(layer, category, ruleId) {
|
|
2279
|
+
const runtime = loadRuntimeConfig();
|
|
2280
|
+
const rules = runtime[layer]?.[category]?.rules || [];
|
|
2281
|
+
if (pickDeletableRule(rules, ruleId) === null) return null;
|
|
2282
|
+
saveRuntimeConfig(runtime);
|
|
2262
2283
|
return runtime;
|
|
2263
2284
|
}
|
|
2264
2285
|
function addCustomSkill(skillId, category, keywords, content) {
|
|
@@ -6552,7 +6573,31 @@ function allCandidates(detail, max = 8) {
|
|
|
6552
6573
|
return out;
|
|
6553
6574
|
}
|
|
6554
6575
|
function matchStageAny(detail, stages) {
|
|
6555
|
-
|
|
6576
|
+
const cands = allCandidates(detail);
|
|
6577
|
+
if (cands.length === 0) return "";
|
|
6578
|
+
const shell = cands[0];
|
|
6579
|
+
const hits = [];
|
|
6580
|
+
for (const [name, pats] of Object.entries(stages)) {
|
|
6581
|
+
for (const p of pats) {
|
|
6582
|
+
p.lastIndex = 0;
|
|
6583
|
+
if (p.test(shell)) {
|
|
6584
|
+
hits.push(name);
|
|
6585
|
+
break;
|
|
6586
|
+
}
|
|
6587
|
+
}
|
|
6588
|
+
}
|
|
6589
|
+
if (hits.length > 0) {
|
|
6590
|
+
if (hits.length === 1) return hits[0];
|
|
6591
|
+
if (hits.includes("EXEC") && PURPOSE_EXEC_RE.test(shell)) return "EXEC";
|
|
6592
|
+
if (hits.includes("LISTEN") && LISTEN_LEAD_RE.test(shell) && !LISTEN_NOISE_RE.test(shell)) {
|
|
6593
|
+
return "LISTEN";
|
|
6594
|
+
}
|
|
6595
|
+
for (const s of STAGE_PRIORITY) {
|
|
6596
|
+
if (hits.includes(s)) return s;
|
|
6597
|
+
}
|
|
6598
|
+
if (hits.includes("EXEC")) return "EXEC";
|
|
6599
|
+
}
|
|
6600
|
+
for (const cand of cands.slice(1)) {
|
|
6556
6601
|
for (const [name, pats] of Object.entries(stages)) {
|
|
6557
6602
|
for (const p of pats) {
|
|
6558
6603
|
p.lastIndex = 0;
|
|
@@ -6562,7 +6607,7 @@ function matchStageAny(detail, stages) {
|
|
|
6562
6607
|
}
|
|
6563
6608
|
return "";
|
|
6564
6609
|
}
|
|
6565
|
-
var B64_TOKEN_RE, QUOTED_STR_RE, OUTPUT_CMDS;
|
|
6610
|
+
var B64_TOKEN_RE, QUOTED_STR_RE, OUTPUT_CMDS, STAGE_PRIORITY, PURPOSE_EXEC_RE, LISTEN_LEAD_RE, LISTEN_NOISE_RE;
|
|
6566
6611
|
var init_decode = __esm({
|
|
6567
6612
|
"src/engine/formal-engine/decode.ts"() {
|
|
6568
6613
|
"use strict";
|
|
@@ -6570,6 +6615,10 @@ var init_decode = __esm({
|
|
|
6570
6615
|
B64_TOKEN_RE = /[A-Za-z0-9+/]+={0,2}/g;
|
|
6571
6616
|
QUOTED_STR_RE = /('(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*`)/g;
|
|
6572
6617
|
OUTPUT_CMDS = /* @__PURE__ */ new Set(["echo", "printf", "print"]);
|
|
6618
|
+
STAGE_PRIORITY = ["EXFIL", "PRIVESC", "PERSIST", "SCAN", "LISTEN"];
|
|
6619
|
+
PURPOSE_EXEC_RE = /subprocess\.\w+\s*\(|os\.system\s*\(|shell\s*=\s*True|\beval\s*\(|\bexec\s*\(|os\.popen\s*\(|\/exec\b/i;
|
|
6620
|
+
LISTEN_LEAD_RE = /http\.server|flask\s+run|nohup\b|nc\s+-l|socat\s+TCP-LISTEN/i;
|
|
6621
|
+
LISTEN_NOISE_RE = /shell\s*=\s*True|os\.system|subprocess\.(?:run|call|Popen)|\beval\s*\(|\bexec\s*\(/i;
|
|
6573
6622
|
}
|
|
6574
6623
|
});
|
|
6575
6624
|
|
|
@@ -6958,6 +7007,62 @@ function checkSensitiveDataFlow(graph) {
|
|
|
6958
7007
|
}
|
|
6959
7008
|
return violations;
|
|
6960
7009
|
}
|
|
7010
|
+
function extractInlineShell(s) {
|
|
7011
|
+
const out = [];
|
|
7012
|
+
let m;
|
|
7013
|
+
INLINE_SHELL_RE.lastIndex = 0;
|
|
7014
|
+
while ((m = INLINE_SHELL_RE.exec(s)) !== null) {
|
|
7015
|
+
let g = m[1] ?? m[2] ?? m[3] ?? m[4] ?? "";
|
|
7016
|
+
if (/^["']/.test(g) && (/"\s*,/.test(g) || /'\s*,/.test(g))) {
|
|
7017
|
+
g = g.replace(/['"\[\],]+/g, " ");
|
|
7018
|
+
}
|
|
7019
|
+
g = g.trim();
|
|
7020
|
+
if (g) out.push(g);
|
|
7021
|
+
}
|
|
7022
|
+
return out;
|
|
7023
|
+
}
|
|
7024
|
+
function containsPrivesc(shell) {
|
|
7025
|
+
if (!shell) return false;
|
|
7026
|
+
for (const seg of shell.split(/\&\&|\|\||;|\n/)) {
|
|
7027
|
+
const s = seg.trim();
|
|
7028
|
+
if (!s) continue;
|
|
7029
|
+
const toks = s.split(/\s+/);
|
|
7030
|
+
const head = (toks[0] || "").toLowerCase();
|
|
7031
|
+
const rest = toks.slice(1).join(" ");
|
|
7032
|
+
if (head === "chmod" && /(?:u\+s|g\+s|[2-7][0-7]{3})/.test(rest)) return true;
|
|
7033
|
+
if (head === "setcap" && /cap_/.test(rest)) return true;
|
|
7034
|
+
if (head === "pkexec" || head === "doas") return true;
|
|
7035
|
+
if (head === "sudo") {
|
|
7036
|
+
if (/^-u\s+/.test(rest)) {
|
|
7037
|
+
if (/^-u\s+root\b/.test(rest)) return true;
|
|
7038
|
+
continue;
|
|
7039
|
+
}
|
|
7040
|
+
const m = /^(\S+)(.*)$/.exec(rest);
|
|
7041
|
+
if (m) {
|
|
7042
|
+
const nxt = m[1].toLowerCase();
|
|
7043
|
+
const tail = m[2];
|
|
7044
|
+
if (PKG_MGR.has(nxt)) continue;
|
|
7045
|
+
if (SHELLS.has(nxt)) return true;
|
|
7046
|
+
if (nxt === "-i" || nxt === "-s") return true;
|
|
7047
|
+
if (nxt.startsWith("su")) return true;
|
|
7048
|
+
if (nxt.startsWith("/") && /bin\/(?:bash|sh|zsh|dash|fish)$/.test(nxt)) return true;
|
|
7049
|
+
}
|
|
7050
|
+
if (/\/(?:usr\/(?:local\/)?bin|bin)\/(?:bash|sh|zsh|dash|fish)\b/.test(rest)) return true;
|
|
7051
|
+
if (/\bchmod\s+(?:u\+s|g\+s|[2-7][0-7]{3})\b/.test(rest)) return true;
|
|
7052
|
+
if (/\bsetcap\s+cap_\w+/.test(rest)) return true;
|
|
7053
|
+
if (/\bvisudo\b/.test(rest)) return true;
|
|
7054
|
+
if (/\bpasswd\s+root\b/.test(rest)) return true;
|
|
7055
|
+
if (/\buseradd\b/.test(rest)) return true;
|
|
7056
|
+
}
|
|
7057
|
+
if (head === "su") {
|
|
7058
|
+
if (!rest) return true;
|
|
7059
|
+
if (/^-l?\s*$/.test(rest)) return true;
|
|
7060
|
+
if (/^root\b/.test(rest) || /^-l?\s+root\b/.test(rest)) return true;
|
|
7061
|
+
}
|
|
7062
|
+
}
|
|
7063
|
+
if (/\bset(?:uid|euid|gid|egid|reuid|regid|resuid|resgid)\s*\(/i.test(shell)) return true;
|
|
7064
|
+
return false;
|
|
7065
|
+
}
|
|
6961
7066
|
function isExfilNode(n) {
|
|
6962
7067
|
if (n.stage === "EXFIL") return true;
|
|
6963
7068
|
if (EXFIL_RE.test(n.actionDetail) && EXFIL_ACTION_RE.test(n.actionDetail)) return true;
|
|
@@ -6972,8 +7077,12 @@ function isCredNode(n) {
|
|
|
6972
7077
|
return CRED_STRICT_RE.test(n.actionDetail);
|
|
6973
7078
|
}
|
|
6974
7079
|
function isPrivescNode(n) {
|
|
6975
|
-
|
|
6976
|
-
|
|
7080
|
+
const shell = stripStringLiterals(n.actionDetail);
|
|
7081
|
+
if (containsPrivesc(shell)) return true;
|
|
7082
|
+
for (const cmd of extractInlineShell(shell)) {
|
|
7083
|
+
if (containsPrivesc(cmd)) return true;
|
|
7084
|
+
}
|
|
7085
|
+
return false;
|
|
6977
7086
|
}
|
|
6978
7087
|
function checkNeverExfilAfterPrivesc(graph) {
|
|
6979
7088
|
const violations = [];
|
|
@@ -7223,7 +7332,7 @@ function checkSensitiveDataAggregation(graph) {
|
|
|
7223
7332
|
}
|
|
7224
7333
|
return violations;
|
|
7225
7334
|
}
|
|
7226
|
-
var CROSS_SESSION_CHAINS, CRED_FILE_RE, EXFIL_RE, EBPF_NET_RE, REMOTE_RE,
|
|
7335
|
+
var CROSS_SESSION_CHAINS, CRED_FILE_RE, EXFIL_RE, EBPF_NET_RE, REMOTE_RE, EXFIL_ACTION_RE, CRED_STRICT_RE, INLINE_SHELL_RE, PKG_MGR, SHELLS, TOOL_REGISTRY, COMPUTE_RE, STRONG_COMPUTE_TYPES, DL_OR_LOW_RE, ALL_PROPERTIES;
|
|
7227
7336
|
var init_properties = __esm({
|
|
7228
7337
|
"src/engine/formal-engine/properties.ts"() {
|
|
7229
7338
|
"use strict";
|
|
@@ -7231,14 +7340,17 @@ var init_properties = __esm({
|
|
|
7231
7340
|
init_rules_loader();
|
|
7232
7341
|
init_ir();
|
|
7233
7342
|
init_ltl();
|
|
7343
|
+
init_decode();
|
|
7234
7344
|
CROSS_SESSION_CHAINS = null;
|
|
7235
7345
|
CRED_FILE_RE = /(known_hosts|\.ssh|id_rsa|\/etc\/shadow|\/etc\/passwd|credentials)/i;
|
|
7236
|
-
EXFIL_RE = /https
|
|
7346
|
+
EXFIL_RE = /https?:\/\/(?!127\.\d+\.\d+\.\d+|0\.0\.0\.0|localhost|\[?::1\]?)[^\s]+|\bscp\s+.*@|\brsync\s+.*@/i;
|
|
7237
7347
|
EBPF_NET_RE = /connect|sendto|network_connect/i;
|
|
7238
7348
|
REMOTE_RE = /to\s+\d+\.\d+\.\d+\.\d+|remote_addr/i;
|
|
7239
|
-
PRIVESC_RE = /\bsudo\b|\bsu\b|chmod\s+u\s*\+\s*s|pkexec|setuid/i;
|
|
7240
7349
|
EXFIL_ACTION_RE = /\bcurl\b|\bwget\b|\bscp\b|\brsync\b|\brclone\b|\bftp\b|connect\s+.*\d+\.\d+\.\d+\.\d+|open\s+.*tcp|base64\s+.*\-o/i;
|
|
7241
7350
|
CRED_STRICT_RE = /(known_hosts|\.ssh|id_rsa|\.pem|\b\.key\b|\/etc\/shadow|\/etc\/passwd|\.aws\/credentials|credentials\.json|netrc|password|secrets?\.ya?ml|credentials?\s*(file|path)?\s*(=|\:)|\bconfig.*(password|token))/i;
|
|
7351
|
+
INLINE_SHELL_RE = /(?:os\.system|os\.popen)\s*\(\s*['"]([^'"]+)['"]|subprocess\.[a-z_]+\(\s*\[([^\]]+)\]|subprocess\.[a-z_]+\(\s*['"]([^'"]+)['"]|(?:bash|sh|zsh)\s+-c\s*['"]([^'"]+)['"]/gi;
|
|
7352
|
+
PKG_MGR = /* @__PURE__ */ new Set(["apt", "apt-get", "aptitude", "yum", "dnf", "pacman", "zypper", "apk", "brew"]);
|
|
7353
|
+
SHELLS = /* @__PURE__ */ new Set(["bash", "sh", "zsh", "dash", "fish", "ksh", "csh", "tcsh", "nologin"]);
|
|
7242
7354
|
TOOL_REGISTRY = null;
|
|
7243
7355
|
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;
|
|
7244
7356
|
STRONG_COMPUTE_TYPES = /* @__PURE__ */ new Set(["python", "node", "exec", "terminal", "cmd"]);
|
|
@@ -9753,9 +9865,16 @@ function createConsoleRouter() {
|
|
|
9753
9865
|
};
|
|
9754
9866
|
const mc = loadMC();
|
|
9755
9867
|
const rules = mc.rules || [];
|
|
9868
|
+
let catEnabled = true;
|
|
9869
|
+
try {
|
|
9870
|
+
const rt = loadRuntimeConfig();
|
|
9871
|
+
catEnabled = rt.L2_2?.ltl_rules?.category_enabled !== false;
|
|
9872
|
+
} catch {
|
|
9873
|
+
}
|
|
9756
9874
|
return {
|
|
9757
9875
|
enabled_via: "L2_logic_rules",
|
|
9758
9876
|
description: "\u65F6\u5E8F\u4E0E\u6570\u636E\u6D41\u653B\u51FB\u68C0\u6D4B\uFF08L2.2 \u6A21\u578B\u68C0\u6D4B\uFF09",
|
|
9877
|
+
category_enabled: catEnabled,
|
|
9759
9878
|
ltl_rules: rules.map((r) => ({
|
|
9760
9879
|
id: r.id,
|
|
9761
9880
|
type: r.type,
|
|
@@ -9769,9 +9888,9 @@ function createConsoleRouter() {
|
|
|
9769
9888
|
};
|
|
9770
9889
|
}
|
|
9771
9890
|
function withL22View(rc) {
|
|
9772
|
-
|
|
9773
|
-
|
|
9774
|
-
const rls =
|
|
9891
|
+
const l22 = rc && rc.L2_2;
|
|
9892
|
+
if (l22 && typeof l22 === "object" && !Array.isArray(l22) && l22.ltl_rules && typeof l22.ltl_rules === "object" && !Array.isArray(l22.ltl_rules)) {
|
|
9893
|
+
const rls = l22.ltl_rules.rules || [];
|
|
9775
9894
|
const ltlHumanLocal = {
|
|
9776
9895
|
"mc-ltl-001": "\u5148\u8BFB\u53D6\u4E86\u51ED\u636E/\u5BC6\u94A5\uFF0C\u4E4B\u540E\u51FA\u73B0\u7F51\u7EDC\u5916\u4F20",
|
|
9777
9896
|
"mc-ltl-002": "\u5148\u4E0B\u8F7D/\u83B7\u53D6\u4E86\u6587\u4EF6\uFF0C\u4E4B\u540E\u6267\u884C\u4E86\u6587\u4EF6",
|
|
@@ -9788,6 +9907,7 @@ function createConsoleRouter() {
|
|
|
9788
9907
|
rc.L2_2 = {
|
|
9789
9908
|
enabled_via: "L2_logic_rules",
|
|
9790
9909
|
description: "\u65F6\u5E8F\u4E0E\u6570\u636E\u6D41\u653B\u51FB\u68C0\u6D4B\uFF08L2.2 \u6A21\u578B\u68C0\u6D4B\uFF09",
|
|
9910
|
+
category_enabled: l22.ltl_rules.category_enabled !== false,
|
|
9791
9911
|
ltl_rules: rls.map((r) => ({
|
|
9792
9912
|
id: r.id,
|
|
9793
9913
|
type: "ltl",
|
|
@@ -9824,7 +9944,7 @@ function createConsoleRouter() {
|
|
|
9824
9944
|
console2.put("/api/categories/enabled", async (c) => {
|
|
9825
9945
|
const b = await c.req.json();
|
|
9826
9946
|
const rc = updateCategoryEnabled(b.layer, b.category, b.enabled);
|
|
9827
|
-
return c.json(rc);
|
|
9947
|
+
return c.json(withL22View(rc));
|
|
9828
9948
|
});
|
|
9829
9949
|
console2.post("/api/rules", async (c) => {
|
|
9830
9950
|
const b = await c.req.json();
|
|
@@ -9840,13 +9960,13 @@ function createConsoleRouter() {
|
|
|
9840
9960
|
credential: b.credential,
|
|
9841
9961
|
deny_mode: b.deny_mode
|
|
9842
9962
|
});
|
|
9843
|
-
return c.json(rc);
|
|
9963
|
+
return c.json(withL22View(rc));
|
|
9844
9964
|
});
|
|
9845
9965
|
console2.delete("/api/rules", async (c) => {
|
|
9846
9966
|
const b = await c.req.json();
|
|
9847
9967
|
deleteCustomRule(b.layer, b.category, b.rule_id);
|
|
9848
9968
|
const rc = loadRuntimeConfig();
|
|
9849
|
-
return c.json(rc);
|
|
9969
|
+
return c.json(withL22View(rc));
|
|
9850
9970
|
});
|
|
9851
9971
|
console2.get("/api/skills", (c) => {
|
|
9852
9972
|
const rc = loadRuntimeConfig();
|
|
@@ -9855,23 +9975,23 @@ function createConsoleRouter() {
|
|
|
9855
9975
|
console2.put("/api/skills/enabled", async (c) => {
|
|
9856
9976
|
const b = await c.req.json();
|
|
9857
9977
|
const rc = updateSkillEnabled(b.skill_id, b.enabled);
|
|
9858
|
-
return c.json(rc);
|
|
9978
|
+
return c.json(withL22View(rc));
|
|
9859
9979
|
});
|
|
9860
9980
|
console2.put("/api/skill-categories/enabled", async (c) => {
|
|
9861
9981
|
const b = await c.req.json();
|
|
9862
9982
|
const rc = updateSkillCategoryEnabled(b.category, b.enabled);
|
|
9863
|
-
return c.json(rc);
|
|
9983
|
+
return c.json(withL22View(rc));
|
|
9864
9984
|
});
|
|
9865
9985
|
console2.post("/api/skills", async (c) => {
|
|
9866
9986
|
const b = await c.req.json();
|
|
9867
9987
|
const rc = addCustomSkill(b.skill_id, b.category || "user_custom", b.keywords || [], b.content);
|
|
9868
|
-
return c.json(rc);
|
|
9988
|
+
return c.json(withL22View(rc));
|
|
9869
9989
|
});
|
|
9870
9990
|
console2.delete("/api/skills", async (c) => {
|
|
9871
9991
|
const b = await c.req.json();
|
|
9872
9992
|
deleteCustomSkill(b.skill_id, b.category);
|
|
9873
9993
|
const rc = loadRuntimeConfig();
|
|
9874
|
-
return c.json(rc);
|
|
9994
|
+
return c.json(withL22View(rc));
|
|
9875
9995
|
});
|
|
9876
9996
|
console2.get("/api/skills/:skill_id/content", async (c) => {
|
|
9877
9997
|
const skillId = c.req.param("skill_id");
|
|
@@ -9977,7 +10097,7 @@ function createConsoleRouter() {
|
|
|
9977
10097
|
console2.post("/api/reset", (c) => {
|
|
9978
10098
|
const defaults = generateSourceDefaults();
|
|
9979
10099
|
saveRuntimeConfig(defaults);
|
|
9980
|
-
return c.json(defaults);
|
|
10100
|
+
return c.json(withL22View(defaults));
|
|
9981
10101
|
});
|
|
9982
10102
|
console2.get("/api/token-stats", (c) => {
|
|
9983
10103
|
const days = parseInt(c.req.query("days") || "7", 10);
|