agentseal 0.9.0 → 0.9.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/agentseal.js +2184 -5359
- package/dist/cache-MVU2E2LB.js +8 -0
- package/dist/canaries-K2JQLX7Z.js +314 -0
- package/dist/chunk-4EOVMNW5.js +100 -0
- package/dist/chunk-BXOPZ7UC.js +223 -0
- package/dist/chunk-EGCYEYIX.js +580 -0
- package/dist/chunk-I6HSMNTE.js +1906 -0
- package/dist/chunk-IGSX7F4B.js +69 -0
- package/dist/chunk-IO5DO7DS.js +634 -0
- package/dist/chunk-PG5LEDUE.js +530 -0
- package/dist/chunk-RJ56XHCI.js +115 -0
- package/dist/chunk-XQGUICLL.js +45 -0
- package/dist/chunk-ZLRN7Q7C.js +27 -0
- package/dist/chunk-ZNNQ2HKJ.js +267 -0
- package/dist/collectors-Y5Z2R2UT.js +39 -0
- package/dist/deep-reasoning-GHCZ3SO6.js +17 -0
- package/dist/fix-NOFNO7VW.js +204 -0
- package/dist/http-AIVCASYV.js +8 -0
- package/dist/index.cjs +9875 -6466
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +169 -3
- package/dist/index.d.ts +169 -3
- package/dist/index.js +9812 -6431
- package/dist/index.js.map +1 -1
- package/dist/llm-client-4F2EACT5.js +156 -0
- package/dist/profiles-UHSPR44T.js +108 -0
- package/dist/project-3P2OW3W6.js +10 -0
- package/dist/scan-mcp-YOM2YJJG.js +380 -0
- package/dist/shield-HCIU3CSU.js +1962 -0
- package/dist/skill-llm-R3L7TL42.js +225 -0
- package/package.json +2 -3
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __esm = (fn, res) => function __init() {
|
|
7
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
8
|
+
};
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
__esm,
|
|
25
|
+
__export,
|
|
26
|
+
__toCommonJS
|
|
27
|
+
};
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
PROJECT_MCP_CONFIGS,
|
|
4
|
+
PROJECT_SKILL_DIRS,
|
|
5
|
+
PROJECT_SKILL_FILES,
|
|
6
|
+
init_machine_discovery,
|
|
7
|
+
stripJsonComments
|
|
8
|
+
} from "./chunk-IO5DO7DS.js";
|
|
9
|
+
import {
|
|
10
|
+
createMCPServerConfig
|
|
11
|
+
} from "./chunk-4EOVMNW5.js";
|
|
12
|
+
|
|
13
|
+
// src/guard/collectors/project.ts
|
|
14
|
+
import { readdirSync as readdirSync2 } from "fs";
|
|
15
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
16
|
+
|
|
17
|
+
// src/guard/collectors/base.ts
|
|
18
|
+
import { readFileSync, readdirSync, statSync } from "fs";
|
|
19
|
+
import { homedir } from "os";
|
|
20
|
+
import { join, resolve } from "path";
|
|
21
|
+
init_machine_discovery();
|
|
22
|
+
var AgentCollector = class {
|
|
23
|
+
};
|
|
24
|
+
var COLLECTORS = [];
|
|
25
|
+
function registerCollector(collector) {
|
|
26
|
+
COLLECTORS.push(collector);
|
|
27
|
+
}
|
|
28
|
+
function getCollectors() {
|
|
29
|
+
return COLLECTORS;
|
|
30
|
+
}
|
|
31
|
+
function collectAll() {
|
|
32
|
+
return COLLECTORS.flatMap((c) => {
|
|
33
|
+
try {
|
|
34
|
+
return c.collect();
|
|
35
|
+
} catch {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
var MAX_SKILL_SIZE = 10 * 1024 * 1024;
|
|
41
|
+
function isFile(p) {
|
|
42
|
+
try {
|
|
43
|
+
return statSync(p).isFile();
|
|
44
|
+
} catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function isDir(p) {
|
|
49
|
+
try {
|
|
50
|
+
return statSync(p).isDirectory();
|
|
51
|
+
} catch {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function home(...parts) {
|
|
56
|
+
return join(homedir(), ...parts);
|
|
57
|
+
}
|
|
58
|
+
function appdata(...parts) {
|
|
59
|
+
if (process.platform !== "win32") return null;
|
|
60
|
+
const ad = process.env.APPDATA;
|
|
61
|
+
return ad ? join(ad, ...parts) : null;
|
|
62
|
+
}
|
|
63
|
+
function platformPath(paths) {
|
|
64
|
+
const sys = process.platform === "darwin" ? "Darwin" : process.platform === "win32" ? "Windows" : "Linux";
|
|
65
|
+
return paths[sys] ?? paths["all"] ?? null;
|
|
66
|
+
}
|
|
67
|
+
function parseMcpConfig(content) {
|
|
68
|
+
try {
|
|
69
|
+
return JSON.parse(content);
|
|
70
|
+
} catch {
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
return JSON.parse(stripJsonComments(content));
|
|
74
|
+
} catch {
|
|
75
|
+
return {};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function readConfig(path, format) {
|
|
79
|
+
try {
|
|
80
|
+
let raw = readFileSync(path, "utf-8");
|
|
81
|
+
if (format === "jsonc") {
|
|
82
|
+
raw = stripJsonComments(raw);
|
|
83
|
+
}
|
|
84
|
+
return JSON.parse(raw);
|
|
85
|
+
} catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function extractMcpServers(config, sourceFile, agentType, mcpKey = "mcpServers") {
|
|
90
|
+
let servers;
|
|
91
|
+
if (mcpKey.includes(".")) {
|
|
92
|
+
const parts = mcpKey.split(".");
|
|
93
|
+
let node = config;
|
|
94
|
+
for (const part of parts) {
|
|
95
|
+
node = node && typeof node === "object" && !Array.isArray(node) ? node[part] : void 0;
|
|
96
|
+
}
|
|
97
|
+
servers = node ?? {};
|
|
98
|
+
} else {
|
|
99
|
+
servers = config[mcpKey] ?? {};
|
|
100
|
+
}
|
|
101
|
+
const results = [];
|
|
102
|
+
if (typeof servers !== "object" || servers === null || Array.isArray(servers)) {
|
|
103
|
+
return results;
|
|
104
|
+
}
|
|
105
|
+
for (const [srvName, srvCfg] of Object.entries(servers)) {
|
|
106
|
+
if (typeof srvCfg !== "object" || srvCfg === null) continue;
|
|
107
|
+
const cfg = srvCfg;
|
|
108
|
+
const command = String(cfg.command ?? cfg.cmd ?? "");
|
|
109
|
+
const rawArgs = cfg.args ?? cfg.arguments ?? [];
|
|
110
|
+
const args = Array.isArray(rawArgs) ? rawArgs.map(String) : [];
|
|
111
|
+
const rawEnv = cfg.env ?? cfg.envs ?? {};
|
|
112
|
+
const env = {};
|
|
113
|
+
if (typeof rawEnv === "object" && rawEnv !== null) {
|
|
114
|
+
for (const [k, v] of Object.entries(rawEnv)) {
|
|
115
|
+
env[k] = String(v);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const url = cfg.url ? String(cfg.url) : null;
|
|
119
|
+
const transport = url ? "sse" : "stdio";
|
|
120
|
+
results.push(
|
|
121
|
+
createMCPServerConfig({
|
|
122
|
+
name: srvName,
|
|
123
|
+
command,
|
|
124
|
+
args,
|
|
125
|
+
env,
|
|
126
|
+
sourceFile,
|
|
127
|
+
transport,
|
|
128
|
+
url,
|
|
129
|
+
agents: [agentType]
|
|
130
|
+
})
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
return results;
|
|
134
|
+
}
|
|
135
|
+
function collectSkillFiles(paths) {
|
|
136
|
+
const skills = [];
|
|
137
|
+
for (const p of paths) {
|
|
138
|
+
if (isFile(p)) {
|
|
139
|
+
try {
|
|
140
|
+
if (statSync(p).size > MAX_SKILL_SIZE) continue;
|
|
141
|
+
} catch {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
skills.push({ path: resolve(p), platform: "global", format: "markdown" });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return skills;
|
|
148
|
+
}
|
|
149
|
+
function collectSkillDirs(dirs) {
|
|
150
|
+
const skills = [];
|
|
151
|
+
for (const dir of dirs) {
|
|
152
|
+
if (!isDir(dir)) continue;
|
|
153
|
+
try {
|
|
154
|
+
for (const entry of readdirSync(dir)) {
|
|
155
|
+
if (!entry.endsWith(".md")) continue;
|
|
156
|
+
const full = join(dir, entry);
|
|
157
|
+
if (!isFile(full)) continue;
|
|
158
|
+
try {
|
|
159
|
+
if (statSync(full).size > MAX_SKILL_SIZE) continue;
|
|
160
|
+
} catch {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
skills.push({ path: resolve(full), platform: "global", format: "markdown" });
|
|
164
|
+
}
|
|
165
|
+
} catch {
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return skills;
|
|
169
|
+
}
|
|
170
|
+
function makeAgent(name, agentType, configPath, mcpServers, skills, status) {
|
|
171
|
+
return { name, agentType, configPath, mcpServers, skills, status };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// src/guard/collectors/project.ts
|
|
175
|
+
init_machine_discovery();
|
|
176
|
+
var _projectDir = null;
|
|
177
|
+
function setProjectDir(dir) {
|
|
178
|
+
_projectDir = dir;
|
|
179
|
+
}
|
|
180
|
+
function globPrefix(dir, prefix) {
|
|
181
|
+
try {
|
|
182
|
+
return readdirSync2(dir).filter((f) => f.startsWith(prefix)).map((f) => join2(dir, f)).filter(isFile);
|
|
183
|
+
} catch {
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
var ProjectCollector = class extends AgentCollector {
|
|
188
|
+
name = "Project";
|
|
189
|
+
collect() {
|
|
190
|
+
let dir = _projectDir;
|
|
191
|
+
if (!dir) {
|
|
192
|
+
try {
|
|
193
|
+
dir = process.cwd();
|
|
194
|
+
} catch {
|
|
195
|
+
return [];
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (!isDir(dir)) return [];
|
|
199
|
+
const servers = [];
|
|
200
|
+
const skills = [];
|
|
201
|
+
const seenSkills = /* @__PURE__ */ new Set();
|
|
202
|
+
for (const [relPath, mcpKey, fmt] of PROJECT_MCP_CONFIGS) {
|
|
203
|
+
const mcpFile = join2(dir, relPath);
|
|
204
|
+
if (!isFile(mcpFile)) continue;
|
|
205
|
+
const data = readConfig(mcpFile, fmt);
|
|
206
|
+
if (!data) continue;
|
|
207
|
+
const extracted = extractMcpServers(data, mcpFile, "project", mcpKey);
|
|
208
|
+
servers.push(...extracted);
|
|
209
|
+
}
|
|
210
|
+
for (const rel of PROJECT_SKILL_FILES) {
|
|
211
|
+
const candidate = join2(dir, rel);
|
|
212
|
+
if (isFile(candidate)) {
|
|
213
|
+
const resolved = resolve2(candidate);
|
|
214
|
+
if (!seenSkills.has(resolved)) {
|
|
215
|
+
seenSkills.add(resolved);
|
|
216
|
+
skills.push({ path: resolved, platform: "project", format: "markdown" });
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
for (const f of globPrefix(dir, ".clinerules-")) {
|
|
221
|
+
const resolved = resolve2(f);
|
|
222
|
+
if (!seenSkills.has(resolved)) {
|
|
223
|
+
seenSkills.add(resolved);
|
|
224
|
+
skills.push({ path: resolved, platform: "project", format: "markdown" });
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
for (const rel of PROJECT_SKILL_DIRS) {
|
|
228
|
+
const skillDir = join2(dir, rel);
|
|
229
|
+
if (!isDir(skillDir)) continue;
|
|
230
|
+
try {
|
|
231
|
+
for (const entry of readdirSync2(skillDir)) {
|
|
232
|
+
if (!entry.endsWith(".md")) continue;
|
|
233
|
+
const full = join2(skillDir, entry);
|
|
234
|
+
if (!isFile(full)) continue;
|
|
235
|
+
const resolved = resolve2(full);
|
|
236
|
+
if (!seenSkills.has(resolved)) {
|
|
237
|
+
seenSkills.add(resolved);
|
|
238
|
+
skills.push({ path: resolved, platform: "project", format: "markdown" });
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
} catch {
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (servers.length === 0 && skills.length === 0) return [];
|
|
245
|
+
return [makeAgent("Project", "project", dir, servers, skills, "found")];
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
registerCollector(new ProjectCollector());
|
|
249
|
+
|
|
250
|
+
export {
|
|
251
|
+
AgentCollector,
|
|
252
|
+
registerCollector,
|
|
253
|
+
getCollectors,
|
|
254
|
+
collectAll,
|
|
255
|
+
isFile,
|
|
256
|
+
isDir,
|
|
257
|
+
home,
|
|
258
|
+
appdata,
|
|
259
|
+
platformPath,
|
|
260
|
+
parseMcpConfig,
|
|
261
|
+
readConfig,
|
|
262
|
+
extractMcpServers,
|
|
263
|
+
collectSkillFiles,
|
|
264
|
+
collectSkillDirs,
|
|
265
|
+
makeAgent,
|
|
266
|
+
setProjectDir
|
|
267
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./chunk-EGCYEYIX.js";
|
|
3
|
+
import {
|
|
4
|
+
AgentCollector,
|
|
5
|
+
appdata,
|
|
6
|
+
collectAll,
|
|
7
|
+
collectSkillDirs,
|
|
8
|
+
collectSkillFiles,
|
|
9
|
+
extractMcpServers,
|
|
10
|
+
getCollectors,
|
|
11
|
+
home,
|
|
12
|
+
isDir,
|
|
13
|
+
isFile,
|
|
14
|
+
makeAgent,
|
|
15
|
+
parseMcpConfig,
|
|
16
|
+
platformPath,
|
|
17
|
+
readConfig,
|
|
18
|
+
registerCollector
|
|
19
|
+
} from "./chunk-ZNNQ2HKJ.js";
|
|
20
|
+
import "./chunk-IO5DO7DS.js";
|
|
21
|
+
import "./chunk-4EOVMNW5.js";
|
|
22
|
+
import "./chunk-ZLRN7Q7C.js";
|
|
23
|
+
export {
|
|
24
|
+
AgentCollector,
|
|
25
|
+
appdata,
|
|
26
|
+
collectAll,
|
|
27
|
+
collectSkillDirs,
|
|
28
|
+
collectSkillFiles,
|
|
29
|
+
extractMcpServers,
|
|
30
|
+
getCollectors,
|
|
31
|
+
home,
|
|
32
|
+
isDir,
|
|
33
|
+
isFile,
|
|
34
|
+
makeAgent,
|
|
35
|
+
parseMcpConfig,
|
|
36
|
+
platformPath,
|
|
37
|
+
readConfig,
|
|
38
|
+
registerCollector
|
|
39
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
DeepReasoningAnalyzer,
|
|
4
|
+
buildPrompt,
|
|
5
|
+
parseLlmResponse,
|
|
6
|
+
sanitizeName,
|
|
7
|
+
sanitizeText
|
|
8
|
+
} from "./chunk-BXOPZ7UC.js";
|
|
9
|
+
import "./chunk-4EOVMNW5.js";
|
|
10
|
+
import "./chunk-ZLRN7Q7C.js";
|
|
11
|
+
export {
|
|
12
|
+
DeepReasoningAnalyzer,
|
|
13
|
+
buildPrompt,
|
|
14
|
+
parseLlmResponse,
|
|
15
|
+
sanitizeName,
|
|
16
|
+
sanitizeText
|
|
17
|
+
};
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "./chunk-ZLRN7Q7C.js";
|
|
3
|
+
|
|
4
|
+
// src/fix.ts
|
|
5
|
+
import {
|
|
6
|
+
existsSync,
|
|
7
|
+
mkdirSync,
|
|
8
|
+
readFileSync,
|
|
9
|
+
readdirSync,
|
|
10
|
+
renameSync,
|
|
11
|
+
writeFileSync
|
|
12
|
+
} from "fs";
|
|
13
|
+
import { homedir } from "os";
|
|
14
|
+
import { basename, dirname, extname, join, resolve } from "path";
|
|
15
|
+
var QUARANTINE_DIR = join(homedir(), ".agentseal", "quarantine");
|
|
16
|
+
var REPORTS_DIR = join(homedir(), ".agentseal", "reports");
|
|
17
|
+
var BACKUPS_DIR = join(homedir(), ".agentseal", "backups");
|
|
18
|
+
function manifestPath(quarantineDir) {
|
|
19
|
+
return join(quarantineDir, "manifest.json");
|
|
20
|
+
}
|
|
21
|
+
function rglob(dir) {
|
|
22
|
+
const results = [];
|
|
23
|
+
const walk = (d) => {
|
|
24
|
+
try {
|
|
25
|
+
for (const entry of readdirSync(d, { withFileTypes: true })) {
|
|
26
|
+
const full = join(d, entry.name);
|
|
27
|
+
if (entry.isDirectory()) walk(full);
|
|
28
|
+
else if (entry.isFile()) results.push(full);
|
|
29
|
+
}
|
|
30
|
+
} catch {
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
walk(dir);
|
|
34
|
+
return results;
|
|
35
|
+
}
|
|
36
|
+
function loadManifest(quarantineDir) {
|
|
37
|
+
const mp = manifestPath(quarantineDir);
|
|
38
|
+
if (!existsSync(mp)) return [];
|
|
39
|
+
try {
|
|
40
|
+
const data = JSON.parse(readFileSync(mp, "utf-8"));
|
|
41
|
+
if (Array.isArray(data)) return data;
|
|
42
|
+
} catch {
|
|
43
|
+
}
|
|
44
|
+
const entries = [];
|
|
45
|
+
for (const f of rglob(quarantineDir)) {
|
|
46
|
+
if (basename(f) === "manifest.json") continue;
|
|
47
|
+
const stem = basename(f, extname(f));
|
|
48
|
+
entries.push({
|
|
49
|
+
original_path: "",
|
|
50
|
+
quarantine_path: f,
|
|
51
|
+
reason: "recovered from corrupted manifest",
|
|
52
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
53
|
+
skill_name: stem
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return entries;
|
|
57
|
+
}
|
|
58
|
+
function saveManifest(quarantineDir, entries) {
|
|
59
|
+
mkdirSync(quarantineDir, { recursive: true });
|
|
60
|
+
writeFileSync(manifestPath(quarantineDir), JSON.stringify(entries, null, 2), "utf-8");
|
|
61
|
+
}
|
|
62
|
+
function quarantineSkill(skillPath, reason = "", quarantineDir) {
|
|
63
|
+
const qdir = quarantineDir ?? QUARANTINE_DIR;
|
|
64
|
+
const resolvedSkill = resolve(skillPath);
|
|
65
|
+
if (!existsSync(resolvedSkill)) {
|
|
66
|
+
throw new Error(`Skill not found: ${resolvedSkill}`);
|
|
67
|
+
}
|
|
68
|
+
const parts = resolvedSkill.split("/").filter(Boolean);
|
|
69
|
+
const relative = parts.length >= 2 ? join(parts[parts.length - 2], parts[parts.length - 1]) : basename(resolvedSkill);
|
|
70
|
+
let dest = join(qdir, relative);
|
|
71
|
+
if (existsSync(dest)) {
|
|
72
|
+
const stem = basename(dest, extname(dest));
|
|
73
|
+
const suffix = extname(dest);
|
|
74
|
+
const parent = dirname(dest);
|
|
75
|
+
let counter = 1;
|
|
76
|
+
while (existsSync(dest)) {
|
|
77
|
+
dest = join(parent, `${stem}_${counter}${suffix}`);
|
|
78
|
+
counter++;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
82
|
+
renameSync(resolvedSkill, dest);
|
|
83
|
+
const entry = {
|
|
84
|
+
original_path: resolvedSkill,
|
|
85
|
+
quarantine_path: dest,
|
|
86
|
+
reason,
|
|
87
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
88
|
+
skill_name: basename(resolvedSkill, extname(resolvedSkill))
|
|
89
|
+
};
|
|
90
|
+
const manifest = loadManifest(qdir);
|
|
91
|
+
manifest.push(entry);
|
|
92
|
+
saveManifest(qdir, manifest);
|
|
93
|
+
return entry;
|
|
94
|
+
}
|
|
95
|
+
function restoreSkill(skillName, quarantineDir) {
|
|
96
|
+
const qdir = quarantineDir ?? QUARANTINE_DIR;
|
|
97
|
+
const manifest = loadManifest(qdir);
|
|
98
|
+
let idx = -1;
|
|
99
|
+
for (let i = 0; i < manifest.length; i++) {
|
|
100
|
+
if (manifest[i].skill_name === skillName) {
|
|
101
|
+
idx = i;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (idx === -1) {
|
|
106
|
+
throw new Error(`Skill '${skillName}' not found in quarantine`);
|
|
107
|
+
}
|
|
108
|
+
const entry = manifest[idx];
|
|
109
|
+
if (!entry.original_path) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
`Cannot restore '${skillName}': original path is empty (recovered from corrupted manifest). Re-quarantine or move manually.`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
const original = resolve(entry.original_path);
|
|
115
|
+
const quarantined = resolve(entry.quarantine_path);
|
|
116
|
+
const qdirResolved = resolve(qdir);
|
|
117
|
+
if (!quarantined.startsWith(qdirResolved)) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`Cannot restore '${skillName}': quarantine path ${quarantined} is outside quarantine directory. Manifest may be tampered.`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
if (existsSync(original)) {
|
|
123
|
+
throw new Error(`Cannot restore: original path already occupied: ${original}`);
|
|
124
|
+
}
|
|
125
|
+
if (!existsSync(quarantined)) {
|
|
126
|
+
throw new Error(`Quarantined file missing: ${quarantined}`);
|
|
127
|
+
}
|
|
128
|
+
mkdirSync(dirname(original), { recursive: true });
|
|
129
|
+
renameSync(quarantined, original);
|
|
130
|
+
manifest.splice(idx, 1);
|
|
131
|
+
saveManifest(qdir, manifest);
|
|
132
|
+
return original;
|
|
133
|
+
}
|
|
134
|
+
function listQuarantine(quarantineDir) {
|
|
135
|
+
const qdir = quarantineDir ?? QUARANTINE_DIR;
|
|
136
|
+
const manifest = loadManifest(qdir);
|
|
137
|
+
const required = ["original_path", "quarantine_path", "reason", "timestamp", "skill_name"];
|
|
138
|
+
return manifest.filter((e) => required.every((k) => k in e)).map((e) => ({
|
|
139
|
+
original_path: e.original_path,
|
|
140
|
+
quarantine_path: e.quarantine_path,
|
|
141
|
+
reason: e.reason,
|
|
142
|
+
timestamp: e.timestamp,
|
|
143
|
+
skill_name: e.skill_name
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
function loadGuardReport(path, reportsDir) {
|
|
147
|
+
const target = path ?? join(reportsDir ?? REPORTS_DIR, "guard-latest.json");
|
|
148
|
+
if (!existsSync(target)) {
|
|
149
|
+
throw new Error(
|
|
150
|
+
`Guard report not found: ${target}
|
|
151
|
+
Run 'agentseal guard' first to generate a report.`
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
return JSON.parse(readFileSync(target, "utf-8"));
|
|
155
|
+
}
|
|
156
|
+
function loadScanReport(path, reportsDir) {
|
|
157
|
+
const target = path ?? join(reportsDir ?? REPORTS_DIR, "scan-latest.json");
|
|
158
|
+
if (!existsSync(target)) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
`Scan report not found: ${target}
|
|
161
|
+
Run 'agentseal scan' first to generate a report.`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
return JSON.parse(readFileSync(target, "utf-8"));
|
|
165
|
+
}
|
|
166
|
+
function saveReport(reportDict, reportType, reportsDir) {
|
|
167
|
+
if (reportType.includes("/") || reportType.includes("..") || reportType.includes("\\")) {
|
|
168
|
+
throw new Error("Invalid report type");
|
|
169
|
+
}
|
|
170
|
+
const dir = reportsDir ?? REPORTS_DIR;
|
|
171
|
+
mkdirSync(dir, { recursive: true });
|
|
172
|
+
const target = join(dir, `${reportType}-latest.json`);
|
|
173
|
+
writeFileSync(target, JSON.stringify(reportDict, null, 2), "utf-8");
|
|
174
|
+
return target;
|
|
175
|
+
}
|
|
176
|
+
function getFixableSkills(guardReport) {
|
|
177
|
+
const results = [];
|
|
178
|
+
for (const skill of guardReport.skill_results ?? []) {
|
|
179
|
+
if (skill.verdict === "danger") {
|
|
180
|
+
results.push({
|
|
181
|
+
name: skill.name ?? "",
|
|
182
|
+
path: skill.path ?? "",
|
|
183
|
+
findings: skill.findings ?? [],
|
|
184
|
+
verdict: skill.verdict ?? ""
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return results;
|
|
189
|
+
}
|
|
190
|
+
export {
|
|
191
|
+
BACKUPS_DIR,
|
|
192
|
+
QUARANTINE_DIR,
|
|
193
|
+
REPORTS_DIR,
|
|
194
|
+
getFixableSkills,
|
|
195
|
+
listQuarantine,
|
|
196
|
+
loadGuardReport,
|
|
197
|
+
loadManifest,
|
|
198
|
+
loadScanReport,
|
|
199
|
+
manifestPath,
|
|
200
|
+
quarantineSkill,
|
|
201
|
+
restoreSkill,
|
|
202
|
+
saveManifest,
|
|
203
|
+
saveReport
|
|
204
|
+
};
|