@kernel.chat/kbot 3.99.30 → 3.99.33

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.
Files changed (59) hide show
  1. package/README.md +1 -1
  2. package/dist/agents/security-agent.d.ts +31 -0
  3. package/dist/agents/security-agent.js +180 -0
  4. package/dist/agents/security-rules.d.ts +35 -0
  5. package/dist/agents/security-rules.js +206 -0
  6. package/dist/agents/specialists.d.ts +6 -0
  7. package/dist/agents/specialists.js +45 -0
  8. package/dist/architect.js +5 -0
  9. package/dist/auth.js +1 -1
  10. package/dist/channels/matrix.d.ts +4 -0
  11. package/dist/channels/matrix.js +28 -0
  12. package/dist/channels/office.d.ts +78 -0
  13. package/dist/channels/office.js +169 -0
  14. package/dist/channels/registry.d.ts +8 -0
  15. package/dist/channels/registry.js +38 -0
  16. package/dist/channels/signal.d.ts +4 -0
  17. package/dist/channels/signal.js +29 -0
  18. package/dist/channels/slack.d.ts +4 -0
  19. package/dist/channels/slack.js +97 -0
  20. package/dist/channels/teams.d.ts +4 -0
  21. package/dist/channels/teams.js +29 -0
  22. package/dist/channels/telegram.d.ts +4 -0
  23. package/dist/channels/telegram.js +28 -0
  24. package/dist/channels/types.d.ts +50 -0
  25. package/dist/channels/types.js +13 -0
  26. package/dist/channels/whatsapp.d.ts +4 -0
  27. package/dist/channels/whatsapp.js +28 -0
  28. package/dist/computer-use-coordinator.d.ts +44 -0
  29. package/dist/computer-use-coordinator.js +0 -0
  30. package/dist/doctor.js +6 -3
  31. package/dist/file-library.d.ts +76 -0
  32. package/dist/file-library.js +269 -0
  33. package/dist/managed-agents-anthropic.d.ts +90 -0
  34. package/dist/managed-agents-anthropic.js +123 -0
  35. package/dist/plugins-integrity.d.ts +72 -0
  36. package/dist/plugins-integrity.js +153 -0
  37. package/dist/plugins.d.ts +13 -2
  38. package/dist/plugins.js +87 -10
  39. package/dist/tools/anthropic-managed-agents-tools.d.ts +22 -0
  40. package/dist/tools/anthropic-managed-agents-tools.js +191 -0
  41. package/dist/tools/channel-tools.d.ts +4 -0
  42. package/dist/tools/channel-tools.js +80 -0
  43. package/dist/tools/computer-coordinator-tools.d.ts +13 -0
  44. package/dist/tools/computer-coordinator-tools.js +104 -0
  45. package/dist/tools/computer.js +463 -299
  46. package/dist/tools/file-library-tools.d.ts +12 -0
  47. package/dist/tools/file-library-tools.js +191 -0
  48. package/dist/tools/image-thoughtful.d.ts +31 -0
  49. package/dist/tools/image-thoughtful.js +233 -0
  50. package/dist/tools/index.js +1 -0
  51. package/dist/tools/security-agent-tools.d.ts +34 -0
  52. package/dist/tools/security-agent-tools.js +30 -0
  53. package/dist/tools/swarm-2026-04.d.ts +2 -0
  54. package/dist/tools/swarm-2026-04.js +91 -0
  55. package/dist/tools/workspace-agent-tools.d.ts +19 -0
  56. package/dist/tools/workspace-agent-tools.js +191 -0
  57. package/dist/workspace-agents.d.ts +132 -0
  58. package/dist/workspace-agents.js +379 -0
  59. package/package.json +1 -1
@@ -0,0 +1,269 @@
1
+ /**
2
+ * File Library — local-first per-user file store.
3
+ *
4
+ * Mirrors ChatGPT's File Library: auto-saves uploaded and created files,
5
+ * lists, searches by name/content, fetches by id. Content-addressed (sha256).
6
+ *
7
+ * Storage layout:
8
+ * <root>/index.json — atomic JSON index of entries
9
+ * <root>/blobs/<id> — raw file bytes (id = sha256 of contents)
10
+ *
11
+ * Default root: ~/.kbot/files (overridable via KBOT_FILE_LIBRARY_ROOT or ctor opt).
12
+ */
13
+ import { createHash } from "node:crypto";
14
+ import { promises as fs } from "node:fs";
15
+ import * as os from "node:os";
16
+ import * as path from "node:path";
17
+ export const MAX_FILE_BYTES = 50 * 1024 * 1024; // 50 MB
18
+ const TEXT_MIME_PREFIXES = ["text/"];
19
+ const TEXT_MIME_EXACT = new Set([
20
+ "application/json",
21
+ "application/yaml",
22
+ "application/x-yaml",
23
+ "application/xml",
24
+ "application/javascript",
25
+ "application/typescript",
26
+ ]);
27
+ function isTextMime(mimeType) {
28
+ const m = mimeType.toLowerCase();
29
+ if (TEXT_MIME_EXACT.has(m))
30
+ return true;
31
+ return TEXT_MIME_PREFIXES.some((p) => m.startsWith(p));
32
+ }
33
+ function defaultRoot() {
34
+ const env = process.env.KBOT_FILE_LIBRARY_ROOT;
35
+ if (env && env.length > 0)
36
+ return env;
37
+ return path.join(os.homedir(), ".kbot", "files");
38
+ }
39
+ export class FileLibrary {
40
+ root;
41
+ blobsDir;
42
+ indexPath;
43
+ writeLock = Promise.resolve();
44
+ constructor(opts = {}) {
45
+ this.root = opts.root ?? defaultRoot();
46
+ this.blobsDir = path.join(this.root, "blobs");
47
+ this.indexPath = path.join(this.root, "index.json");
48
+ }
49
+ getRoot() {
50
+ return this.root;
51
+ }
52
+ async ensureDirs() {
53
+ await fs.mkdir(this.blobsDir, { recursive: true });
54
+ }
55
+ async readIndex() {
56
+ try {
57
+ const raw = await fs.readFile(this.indexPath, "utf8");
58
+ const parsed = JSON.parse(raw);
59
+ if (!parsed || parsed.version !== 1 || !Array.isArray(parsed.entries)) {
60
+ return { version: 1, entries: [] };
61
+ }
62
+ return parsed;
63
+ }
64
+ catch (err) {
65
+ const e = err;
66
+ if (e.code === "ENOENT")
67
+ return { version: 1, entries: [] };
68
+ throw err;
69
+ }
70
+ }
71
+ /**
72
+ * Atomic write: serialize → write to <indexPath>.tmp.<rand> → rename.
73
+ */
74
+ async writeIndexAtomic(idx) {
75
+ await this.ensureDirs();
76
+ const tmp = `${this.indexPath}.tmp.${process.pid}.${Date.now()}.${Math.random()
77
+ .toString(36)
78
+ .slice(2, 10)}`;
79
+ const data = JSON.stringify(idx, null, 2);
80
+ await fs.writeFile(tmp, data, { encoding: "utf8" });
81
+ await fs.rename(tmp, this.indexPath);
82
+ }
83
+ /**
84
+ * Run a read-modify-write of the index under the writeLock so concurrent
85
+ * mutations don't lose updates. The mutator may return a fresh IndexFile
86
+ * (or undefined to skip the write).
87
+ */
88
+ async mutateIndex(fn) {
89
+ const run = async () => {
90
+ const idx = await this.readIndex();
91
+ const out = await fn(idx);
92
+ if (out.next)
93
+ await this.writeIndexAtomic(out.next);
94
+ return out.result;
95
+ };
96
+ const next = this.writeLock.then(run, run);
97
+ // Don't poison the lock chain on error.
98
+ this.writeLock = next.then(() => undefined, () => undefined);
99
+ return next;
100
+ }
101
+ async addFile(input) {
102
+ if (!input.name || input.name.trim().length === 0) {
103
+ throw new Error("file-library: name is required");
104
+ }
105
+ if (!input.mimeType) {
106
+ throw new Error("file-library: mimeType is required");
107
+ }
108
+ if (input.content === undefined && input.buffer === undefined) {
109
+ throw new Error("file-library: provide content or buffer");
110
+ }
111
+ if (input.content !== undefined && input.buffer !== undefined) {
112
+ throw new Error("file-library: provide content OR buffer, not both");
113
+ }
114
+ const buf = input.buffer !== undefined
115
+ ? input.buffer
116
+ : Buffer.from(input.content, "utf8");
117
+ if (buf.byteLength > MAX_FILE_BYTES) {
118
+ throw new Error(`file-library: file exceeds 50 MB cap (${buf.byteLength} bytes > ${MAX_FILE_BYTES})`);
119
+ }
120
+ const id = createHash("sha256").update(buf).digest("hex");
121
+ await this.ensureDirs();
122
+ const blobPath = path.join(this.blobsDir, id);
123
+ // Write blob if not already present (content-addressed dedup).
124
+ try {
125
+ await fs.access(blobPath);
126
+ }
127
+ catch {
128
+ const tmp = `${blobPath}.tmp.${process.pid}.${Date.now()}`;
129
+ await fs.writeFile(tmp, buf);
130
+ await fs.rename(tmp, blobPath);
131
+ }
132
+ const entry = {
133
+ id,
134
+ name: input.name,
135
+ mimeType: input.mimeType,
136
+ size: buf.byteLength,
137
+ createdAt: new Date().toISOString(),
138
+ source: input.source,
139
+ tags: [...(input.tags ?? [])],
140
+ path: blobPath,
141
+ };
142
+ return this.mutateIndex((idx) => {
143
+ // If an entry with this id already exists, replace it (latest metadata wins,
144
+ // since the blob bytes are identical by id).
145
+ const filtered = idx.entries.filter((e) => e.id !== id);
146
+ filtered.push(entry);
147
+ return { next: { version: 1, entries: filtered }, result: entry };
148
+ });
149
+ }
150
+ async listFiles(opts = {}) {
151
+ const idx = await this.readIndex();
152
+ let entries = idx.entries.slice();
153
+ if (opts.tag) {
154
+ const tag = opts.tag;
155
+ entries = entries.filter((e) => e.tags.includes(tag));
156
+ }
157
+ if (opts.since !== undefined) {
158
+ const sinceMs = opts.since instanceof Date
159
+ ? opts.since.getTime()
160
+ : new Date(opts.since).getTime();
161
+ if (!Number.isNaN(sinceMs)) {
162
+ entries = entries.filter((e) => new Date(e.createdAt).getTime() >= sinceMs);
163
+ }
164
+ }
165
+ // Newest first.
166
+ entries.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
167
+ if (typeof opts.limit === "number" && opts.limit >= 0) {
168
+ entries = entries.slice(0, opts.limit);
169
+ }
170
+ return entries;
171
+ }
172
+ async getFile(id) {
173
+ const idx = await this.readIndex();
174
+ const entry = idx.entries.find((e) => e.id === id);
175
+ if (!entry)
176
+ return null;
177
+ try {
178
+ const buffer = await fs.readFile(entry.path);
179
+ return { entry, buffer };
180
+ }
181
+ catch (err) {
182
+ const e = err;
183
+ if (e.code === "ENOENT")
184
+ return null;
185
+ throw err;
186
+ }
187
+ }
188
+ async removeFile(id) {
189
+ const removedEntry = await this.mutateIndex((idx) => {
190
+ const entry = idx.entries.find((e) => e.id === id);
191
+ if (!entry)
192
+ return { result: null };
193
+ const remaining = idx.entries.filter((e) => e.id !== id);
194
+ return {
195
+ next: { version: 1, entries: remaining },
196
+ result: entry,
197
+ };
198
+ });
199
+ if (!removedEntry)
200
+ return false;
201
+ try {
202
+ await fs.unlink(removedEntry.path);
203
+ }
204
+ catch (err) {
205
+ const e = err;
206
+ if (e.code !== "ENOENT")
207
+ throw err;
208
+ }
209
+ return true;
210
+ }
211
+ async searchFiles(opts) {
212
+ const q = (opts.query ?? "").toLowerCase();
213
+ if (q.length === 0)
214
+ return [];
215
+ const idx = await this.readIndex();
216
+ const entries = idx.entries;
217
+ const matchName = (e) => e.name.toLowerCase().includes(q);
218
+ const matchContent = async (e) => {
219
+ if (!isTextMime(e.mimeType))
220
+ return false;
221
+ try {
222
+ const buf = await fs.readFile(e.path);
223
+ return buf.toString("utf8").toLowerCase().includes(q);
224
+ }
225
+ catch (err) {
226
+ const ne = err;
227
+ if (ne.code === "ENOENT")
228
+ return false;
229
+ throw err;
230
+ }
231
+ };
232
+ const seen = new Set();
233
+ const out = [];
234
+ if (opts.mode === "name" || opts.mode === "both") {
235
+ for (const e of entries) {
236
+ if (matchName(e) && !seen.has(e.id)) {
237
+ seen.add(e.id);
238
+ out.push(e);
239
+ }
240
+ }
241
+ }
242
+ if (opts.mode === "content" || opts.mode === "both") {
243
+ for (const e of entries) {
244
+ if (seen.has(e.id))
245
+ continue;
246
+ // eslint-disable-next-line no-await-in-loop
247
+ const hit = await matchContent(e);
248
+ if (hit) {
249
+ seen.add(e.id);
250
+ out.push(e);
251
+ }
252
+ }
253
+ }
254
+ out.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
255
+ return out;
256
+ }
257
+ }
258
+ // Singleton helper for default root usage.
259
+ let _default = null;
260
+ export function getDefaultFileLibrary() {
261
+ if (!_default)
262
+ _default = new FileLibrary();
263
+ return _default;
264
+ }
265
+ // Reset the cached default — primarily for tests that mutate env.
266
+ export function _resetDefaultFileLibrary() {
267
+ _default = null;
268
+ }
269
+ //# sourceMappingURL=file-library.js.map
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Anthropic Managed Agents client (April 2026 launch).
3
+ *
4
+ * Hosted long-horizon agent platform. This module is a STANDALONE backend
5
+ * that workspace agents can route through when ANTHROPIC_API_KEY is set.
6
+ * Wiring into ./workspace-agents.ts happens in a follow-up pass.
7
+ *
8
+ * Beta header: `anthropic-beta: managed-agents-2026-04-01` is sent on every
9
+ * request.
10
+ *
11
+ * SPEC: best-effort, refine when official docs published.
12
+ * Endpoint shape mirrors the public beta announcement; refine when the
13
+ * official OpenAPI spec lands.
14
+ */
15
+ export interface CreateSessionInput {
16
+ mission: string;
17
+ allowedTools?: string[];
18
+ model?: string;
19
+ }
20
+ export interface CreateSessionOutput {
21
+ session_id: string;
22
+ [key: string]: unknown;
23
+ }
24
+ export interface SendTurnInput {
25
+ sessionId: string;
26
+ input: string;
27
+ }
28
+ export interface SendTurnOutput {
29
+ output: string;
30
+ tool_calls?: unknown[];
31
+ [key: string]: unknown;
32
+ }
33
+ export interface SessionState {
34
+ session_id: string;
35
+ mission?: string;
36
+ status?: string;
37
+ [key: string]: unknown;
38
+ }
39
+ export interface ListSessionsOutput {
40
+ sessions: SessionState[];
41
+ [key: string]: unknown;
42
+ }
43
+ export interface MemoryReadInput {
44
+ sessionId: string;
45
+ key?: string;
46
+ }
47
+ export interface MemoryWriteInput {
48
+ sessionId: string;
49
+ key: string;
50
+ value: unknown;
51
+ }
52
+ export interface MemoryAck {
53
+ ok: boolean;
54
+ [key: string]: unknown;
55
+ }
56
+ export declare class AnthropicManagedAgentsError extends Error {
57
+ readonly status: number;
58
+ readonly body: string;
59
+ constructor(message: string, status: number, body: string);
60
+ }
61
+ export interface AnthropicManagedAgentsClientOptions {
62
+ /** Override the API key (default: process.env.ANTHROPIC_API_KEY). */
63
+ apiKey?: string;
64
+ /** Override the base URL (default: https://api.anthropic.com/v1). */
65
+ baseUrl?: string;
66
+ /** Override fetch (used by tests). */
67
+ fetchImpl?: typeof fetch;
68
+ }
69
+ export declare class AnthropicManagedAgentsClient {
70
+ private readonly apiKey;
71
+ private readonly baseUrl;
72
+ private readonly fetchImpl;
73
+ constructor(opts?: AnthropicManagedAgentsClientOptions);
74
+ createSession(input: CreateSessionInput): Promise<CreateSessionOutput>;
75
+ sendTurn(input: SendTurnInput): Promise<SendTurnOutput>;
76
+ getSession(input: {
77
+ sessionId: string;
78
+ }): Promise<SessionState>;
79
+ listSessions(): Promise<ListSessionsOutput>;
80
+ closeSession(input: {
81
+ sessionId: string;
82
+ }): Promise<{
83
+ ok: boolean;
84
+ [key: string]: unknown;
85
+ }>;
86
+ memoryRead(input: MemoryReadInput): Promise<unknown>;
87
+ memoryWrite(input: MemoryWriteInput): Promise<MemoryAck>;
88
+ private request;
89
+ }
90
+ //# sourceMappingURL=managed-agents-anthropic.d.ts.map
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Anthropic Managed Agents client (April 2026 launch).
3
+ *
4
+ * Hosted long-horizon agent platform. This module is a STANDALONE backend
5
+ * that workspace agents can route through when ANTHROPIC_API_KEY is set.
6
+ * Wiring into ./workspace-agents.ts happens in a follow-up pass.
7
+ *
8
+ * Beta header: `anthropic-beta: managed-agents-2026-04-01` is sent on every
9
+ * request.
10
+ *
11
+ * SPEC: best-effort, refine when official docs published.
12
+ * Endpoint shape mirrors the public beta announcement; refine when the
13
+ * official OpenAPI spec lands.
14
+ */
15
+ const DEFAULT_BASE_URL = 'https://api.anthropic.com/v1';
16
+ const BETA_HEADER_VALUE = 'managed-agents-2026-04-01';
17
+ const ANTHROPIC_VERSION = '2023-06-01';
18
+ export class AnthropicManagedAgentsError extends Error {
19
+ status;
20
+ body;
21
+ constructor(message, status, body) {
22
+ super(message);
23
+ this.name = 'AnthropicManagedAgentsError';
24
+ this.status = status;
25
+ this.body = body;
26
+ }
27
+ }
28
+ export class AnthropicManagedAgentsClient {
29
+ apiKey;
30
+ baseUrl;
31
+ fetchImpl;
32
+ constructor(opts = {}) {
33
+ const apiKey = opts.apiKey ?? process.env.ANTHROPIC_API_KEY;
34
+ if (!apiKey) {
35
+ throw new Error('AnthropicManagedAgentsClient: ANTHROPIC_API_KEY is not set');
36
+ }
37
+ this.apiKey = apiKey;
38
+ this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, '');
39
+ this.fetchImpl = opts.fetchImpl ?? fetch;
40
+ }
41
+ // ── Sessions ────────────────────────────────────────────────────────────
42
+ async createSession(input) {
43
+ if (!input.mission || !input.mission.trim()) {
44
+ throw new Error('createSession: mission is required');
45
+ }
46
+ const body = { mission: input.mission };
47
+ if (input.model)
48
+ body.model = input.model;
49
+ if (input.allowedTools)
50
+ body.tools = input.allowedTools;
51
+ return this.request('POST', '/agents/sessions', body);
52
+ }
53
+ async sendTurn(input) {
54
+ if (!input.sessionId)
55
+ throw new Error('sendTurn: sessionId is required');
56
+ return this.request('POST', `/agents/sessions/${encodeURIComponent(input.sessionId)}/turns`, { input: input.input });
57
+ }
58
+ async getSession(input) {
59
+ if (!input.sessionId)
60
+ throw new Error('getSession: sessionId is required');
61
+ return this.request('GET', `/agents/sessions/${encodeURIComponent(input.sessionId)}`);
62
+ }
63
+ async listSessions() {
64
+ return this.request('GET', '/agents/sessions');
65
+ }
66
+ async closeSession(input) {
67
+ if (!input.sessionId) {
68
+ throw new Error('closeSession: sessionId is required');
69
+ }
70
+ return this.request('DELETE', `/agents/sessions/${encodeURIComponent(input.sessionId)}`);
71
+ }
72
+ // ── Memory ──────────────────────────────────────────────────────────────
73
+ async memoryRead(input) {
74
+ if (!input.sessionId)
75
+ throw new Error('memoryRead: sessionId is required');
76
+ const path = input.key
77
+ ? `/agents/sessions/${encodeURIComponent(input.sessionId)}/memory/${encodeURIComponent(input.key)}`
78
+ : `/agents/sessions/${encodeURIComponent(input.sessionId)}/memory`;
79
+ return this.request('GET', path);
80
+ }
81
+ async memoryWrite(input) {
82
+ if (!input.sessionId)
83
+ throw new Error('memoryWrite: sessionId is required');
84
+ if (!input.key)
85
+ throw new Error('memoryWrite: key is required');
86
+ return this.request('POST', `/agents/sessions/${encodeURIComponent(input.sessionId)}/memory`, { key: input.key, value: input.value });
87
+ }
88
+ // ── Internals ───────────────────────────────────────────────────────────
89
+ async request(method, path, body) {
90
+ const url = `${this.baseUrl}${path}`;
91
+ const headers = {
92
+ 'x-api-key': this.apiKey,
93
+ 'anthropic-version': ANTHROPIC_VERSION,
94
+ 'anthropic-beta': BETA_HEADER_VALUE,
95
+ };
96
+ const init = { method, headers };
97
+ if (body !== undefined && method !== 'GET') {
98
+ headers['content-type'] = 'application/json';
99
+ init.body = JSON.stringify(body);
100
+ }
101
+ let res;
102
+ try {
103
+ res = await this.fetchImpl(url, init);
104
+ }
105
+ catch (err) {
106
+ const msg = err instanceof Error ? err.message : String(err);
107
+ throw new AnthropicManagedAgentsError(`network error contacting ${url}: ${msg}`, 0, '');
108
+ }
109
+ const text = await res.text();
110
+ if (!res.ok) {
111
+ throw new AnthropicManagedAgentsError(`Anthropic Managed Agents ${method} ${path} failed: ${res.status} ${res.statusText}`, res.status, text);
112
+ }
113
+ if (!text)
114
+ return {};
115
+ try {
116
+ return JSON.parse(text);
117
+ }
118
+ catch {
119
+ throw new AnthropicManagedAgentsError(`Anthropic Managed Agents ${method} ${path} returned non-JSON body`, res.status, text);
120
+ }
121
+ }
122
+ }
123
+ //# sourceMappingURL=managed-agents-anthropic.js.map
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Plugin integrity verification — fail-closed SHA-256 manifest checking.
3
+ *
4
+ * Ports OpenClaw's `plugins.json5` integrity-pinned plugin model. Plugins must
5
+ * be declared in a manifest with a SHA-256 hash; the loader verifies the file
6
+ * on disk against the manifest entry and refuses to load on drift.
7
+ *
8
+ * Manifest format here is plain JSON. If we add a JSON5 dep later (e.g.
9
+ * `json5`), swap `JSON.parse` for `JSON5.parse` and accept `.json5` files.
10
+ */
11
+ export interface ManifestEntry {
12
+ name: string;
13
+ version: string;
14
+ /** Path relative to the plugins directory (e.g. ~/.kbot/plugins). */
15
+ path: string;
16
+ /** SHA-256 hash, base64-encoded, prefixed with "sha256-". */
17
+ integrity: string;
18
+ }
19
+ export interface Manifest {
20
+ schemaVersion: 1;
21
+ plugins: ManifestEntry[];
22
+ }
23
+ export type VerifyResult = {
24
+ ok: true;
25
+ } | {
26
+ ok: false;
27
+ reason: string;
28
+ expected: string;
29
+ actual: string;
30
+ };
31
+ export interface VerifyAllResult {
32
+ verified: string[];
33
+ failed: Array<{
34
+ name: string;
35
+ reason: string;
36
+ expected?: string;
37
+ actual?: string;
38
+ }>;
39
+ }
40
+ export declare class IntegrityError extends Error {
41
+ failed: VerifyAllResult['failed'];
42
+ constructor(failed: VerifyAllResult['failed']);
43
+ }
44
+ /**
45
+ * Load and validate a manifest from disk. Throws on missing file, invalid
46
+ * JSON, or schema violation.
47
+ */
48
+ export declare function loadManifest(path: string): Promise<Manifest>;
49
+ /**
50
+ * Verify a single plugin file against its manifest entry.
51
+ *
52
+ * - Missing file → `{ ok: false, reason: "plugin file missing" }`
53
+ * - Hash mismatch → `{ ok: false, reason: "integrity drift" }`
54
+ * - Match → `{ ok: true }`
55
+ */
56
+ export declare function verifyPlugin(filePath: string, manifestEntry: ManifestEntry): Promise<VerifyResult>;
57
+ /**
58
+ * Verify every plugin in a manifest against the corresponding files under
59
+ * `pluginsDir`. Resolves entry paths relative to `pluginsDir` unless
60
+ * absolute.
61
+ *
62
+ * Always returns a result; never throws on drift. Callers should pass the
63
+ * result to `enforce()` to fail closed.
64
+ */
65
+ export declare function verifyAllPlugins(manifestPath: string, pluginsDir: string): Promise<VerifyAllResult>;
66
+ /**
67
+ * Fail-closed gate. Throws `IntegrityError` if any plugin failed verification.
68
+ * No-op when all plugins are verified. Loaders should call this unless
69
+ * integrity checking has been explicitly disabled (e.g. dev override).
70
+ */
71
+ export declare function enforce(result: VerifyAllResult): void;
72
+ //# sourceMappingURL=plugins-integrity.d.ts.map