agentseal 0.9.0 → 0.9.2

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.
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/guard/registry/cache.ts
4
+ import * as fs from "fs";
5
+ import * as os from "os";
6
+ import * as path from "path";
7
+ var STALE_SECONDS = 86400;
8
+ var CACHE_URL = "https://agentseal.org/api/v1/mcp/guard-cache";
9
+ var DEFAULT_CACHE_PATH = path.join(os.homedir(), ".agentseal", "registry_cache.json");
10
+ var REGISTRY_PREFIXES = ["npm:", "pypi:", "docker:", "github:"];
11
+ var NAME_PREFIXES = ["mcp-server-", "server-", "mcp-"];
12
+ function toRegistryData(entry) {
13
+ return {
14
+ trustScore: entry.trust_score ?? entry.trustScore ?? 50,
15
+ findings: entry.findings ?? [],
16
+ capabilityLabels: new Set(entry.capability_labels ?? entry.capabilityLabels ?? []),
17
+ analyzedVersion: entry.analyzed_version ?? entry.analyzedVersion ?? null,
18
+ analyzedAt: entry.analyzed_at ?? entry.analyzedAt ?? null,
19
+ tools: entry.tools ?? []
20
+ };
21
+ }
22
+ function stripName(packageId) {
23
+ let name = packageId;
24
+ for (const prefix of REGISTRY_PREFIXES) {
25
+ if (name.startsWith(prefix)) {
26
+ name = name.slice(prefix.length);
27
+ break;
28
+ }
29
+ }
30
+ const slashIdx = name.indexOf("/");
31
+ if (name.startsWith("@") && slashIdx !== -1) {
32
+ name = name.slice(slashIdx + 1);
33
+ }
34
+ for (const prefix of NAME_PREFIXES) {
35
+ if (name.startsWith(prefix)) {
36
+ name = name.slice(prefix.length);
37
+ break;
38
+ }
39
+ }
40
+ return name;
41
+ }
42
+ var RegistryCache = class {
43
+ cachePath;
44
+ baseUrl;
45
+ skipFetch;
46
+ data = null;
47
+ constructor(opts) {
48
+ this.cachePath = opts?.path ?? DEFAULT_CACHE_PATH;
49
+ this.baseUrl = opts?.baseUrl ?? CACHE_URL;
50
+ this.skipFetch = opts?.skipFetch ?? false;
51
+ this._loadFromDisk();
52
+ }
53
+ _loadFromDisk() {
54
+ try {
55
+ const raw = fs.readFileSync(this.cachePath, "utf8");
56
+ this.data = JSON.parse(raw);
57
+ } catch {
58
+ this.data = null;
59
+ }
60
+ }
61
+ isStale() {
62
+ if (this.data === null) return true;
63
+ const ts = this.data.fetchedAt ?? this.data.fetched_at ?? this.data.updated_at ?? 0;
64
+ const ageSeconds = Date.now() / 1e3 - ts;
65
+ return ageSeconds >= STALE_SECONDS;
66
+ }
67
+ serverCount() {
68
+ if (this.data === null) return 0;
69
+ return Object.keys(this.data.servers).length;
70
+ }
71
+ async fetchRemote() {
72
+ const response = await fetch(this.baseUrl);
73
+ if (!response.ok) {
74
+ throw new Error(`Registry fetch failed: ${response.status} ${response.statusText}`);
75
+ }
76
+ const payload = await response.json();
77
+ const newData = {
78
+ fetchedAt: Math.floor(Date.now() / 1e3),
79
+ servers: payload.servers
80
+ };
81
+ this._setData(newData);
82
+ try {
83
+ const dir = path.dirname(this.cachePath);
84
+ fs.mkdirSync(dir, { recursive: true });
85
+ fs.writeFileSync(this.cachePath, JSON.stringify(newData), "utf8");
86
+ } catch {
87
+ }
88
+ return Object.keys(newData.servers).length;
89
+ }
90
+ async ensureFresh() {
91
+ if (this.skipFetch) return;
92
+ if (this.isStale()) {
93
+ await this.fetchRemote();
94
+ }
95
+ }
96
+ lookup(packageId) {
97
+ if (packageId === null || this.data === null) return null;
98
+ const exact = this.data.servers[packageId];
99
+ if (exact !== void 0) return toRegistryData(exact);
100
+ const needle = stripName(packageId);
101
+ for (const [key, entry] of Object.entries(this.data.servers)) {
102
+ if (stripName(key) === needle) {
103
+ return toRegistryData(entry);
104
+ }
105
+ }
106
+ return null;
107
+ }
108
+ _setData(data) {
109
+ this.data = data;
110
+ }
111
+ };
112
+
113
+ export {
114
+ RegistryCache
115
+ };
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/errors.ts
4
+ var AgentSealError = class extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = "AgentSealError";
8
+ }
9
+ };
10
+ var ProviderError = class extends AgentSealError {
11
+ constructor(provider, message) {
12
+ super(`[${provider}] ${message}`);
13
+ this.name = "ProviderError";
14
+ }
15
+ };
16
+
17
+ // src/providers/http.ts
18
+ function fromEndpoint(opts) {
19
+ const msgField = opts.messageField ?? "message";
20
+ const respField = opts.responseField ?? "response";
21
+ return async (message) => {
22
+ const res = await fetch(opts.url, {
23
+ method: "POST",
24
+ headers: {
25
+ "Content-Type": "application/json",
26
+ ...opts.headers
27
+ },
28
+ body: JSON.stringify({ [msgField]: message })
29
+ });
30
+ if (!res.ok) {
31
+ throw new ProviderError("http", `HTTP ${res.status}: ${res.statusText}`);
32
+ }
33
+ const data = await res.json();
34
+ const response = data[respField];
35
+ if (typeof response !== "string") {
36
+ throw new ProviderError("http", `Response field '${respField}' not found or not a string`);
37
+ }
38
+ return response;
39
+ };
40
+ }
41
+
42
+ export {
43
+ ProviderError,
44
+ fromEndpoint
45
+ };
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env node
2
+ import "./chunk-I6AROGUC.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-2WEF3SNR.js";
20
+ import "./chunk-OWUAAOL5.js";
21
+ import "./chunk-4EOVMNW5.js";
22
+ import "./chunk-7N7GSU6K.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-7N7GSU6K.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-7N7GSU6K.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
+ };
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ fromEndpoint
4
+ } from "./chunk-XQGUICLL.js";
5
+ import "./chunk-7N7GSU6K.js";
6
+ export {
7
+ fromEndpoint
8
+ };