@michaelfromyeg/weft-core 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Michael DeMarco
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,520 @@
1
+ import { Plugin, Marketplace, ParseResult, Target, ComponentKind, Component, PluginLock, ArtifactRecord, Lockfile, Scope, Badge, Dependency } from '@michaelfromyeg/weft-schema';
2
+ import { HarnessAdapter, CompiledArtifact, ResolvedMarketplace, ArtifactKind } from '@michaelfromyeg/weft-adapter-kit';
3
+ import { KeyObject } from 'node:crypto';
4
+
5
+ type Severity = "error" | "warning" | "info";
6
+ interface Diagnostic {
7
+ severity: Severity;
8
+ /** Path-precise location: "components[1].mcp", "owner.namespace", or a file path. */
9
+ where: string;
10
+ message: string;
11
+ }
12
+ /** Accumulates diagnostics during compile; fails closed when any error is present. */
13
+ declare class Diagnostics {
14
+ readonly items: Diagnostic[];
15
+ error(where: string, message: string): void;
16
+ warn(where: string, message: string): void;
17
+ info(where: string, message: string): void;
18
+ get hasErrors(): boolean;
19
+ get errors(): Diagnostic[];
20
+ }
21
+ declare class CompileError extends Error {
22
+ readonly diagnostics: Diagnostic[];
23
+ constructor(message: string, diagnostics: Diagnostic[]);
24
+ }
25
+
26
+ /** A plugin whose files are available on disk under `root`. */
27
+ interface FetchedPlugin {
28
+ plugin: Plugin;
29
+ root: string;
30
+ manifestPath: string;
31
+ /** Read a file from the plugin, relative to `root`. */
32
+ read(relPath: string): Buffer;
33
+ /** Recursively list files under a plugin dir, as paths relative to `root` (sorted). */
34
+ list(relDir: string): string[];
35
+ }
36
+ /** A loaded marketplace manifest and its directory. */
37
+ interface FetchedMarketplace {
38
+ marketplace: Marketplace;
39
+ root: string;
40
+ manifestPath: string;
41
+ }
42
+ /** Build `read`/`list` accessors rooted at a directory (used for merged plugins too). */
43
+ declare function fileAccessors(root: string): Pick<FetchedPlugin, "read" | "list">;
44
+ /** Load and validate the plugin manifest in `dir`, exposing its files for adapters. */
45
+ declare function loadPluginDir(dir: string): ParseResult<FetchedPlugin>;
46
+ /** True when `dir` is a marketplace (a catalog of plugins) rather than a plugin. */
47
+ declare function hasMarketplaceManifest(dir: string): boolean;
48
+ /** Load and validate the marketplace manifest in `dir`. */
49
+ declare function loadMarketplaceDir(dir: string): ParseResult<FetchedMarketplace>;
50
+
51
+ /**
52
+ * Adapters registered by Target (spec §7). Core depends only on the adapter-kit
53
+ * interface; the CLI (or an embedding app) registers concrete adapters, keeping
54
+ * the dependency direction one-way and letting community adapters slot in.
55
+ */
56
+ declare class AdapterRegistry {
57
+ private readonly adapters;
58
+ register(adapter: HarnessAdapter): this;
59
+ get(target: Target): HarnessAdapter | undefined;
60
+ has(target: Target): boolean;
61
+ get targets(): Target[];
62
+ }
63
+
64
+ /** An emitted artifact tagged with the canonical component it came from. */
65
+ interface TaggedArtifact {
66
+ componentId: string;
67
+ artifact: CompiledArtifact;
68
+ }
69
+ /** Everything one adapter produced for one plugin. */
70
+ interface TargetOutput {
71
+ target: Target;
72
+ adapter: HarnessAdapter;
73
+ /** Plugin-root-relative artifacts: components + the plugin manifest. */
74
+ artifacts: TaggedArtifact[];
75
+ }
76
+ interface CompileResult {
77
+ fb: FetchedPlugin;
78
+ /** Plugin id: `{namespace}/{name}`. */
79
+ id: string;
80
+ /** The components actually compiled (the piecemeal selection, or all). */
81
+ components: ResolvedComponent[];
82
+ aliases: Record<string, string>;
83
+ diagnostics: Diagnostics;
84
+ targets: TargetOutput[];
85
+ }
86
+ interface CompileOptions {
87
+ registry: AdapterRegistry;
88
+ /** Restrict to these targets; default = every target with a registered adapter. */
89
+ targets?: Target[];
90
+ /** Piecemeal: include only these component leaf names; default = all (spec §9.2). */
91
+ only?: string[];
92
+ }
93
+ /** A synthetic one-entry marketplace wrapping a single plugin (spec §9.1 build). */
94
+ declare function synthMarketplace(plugin: Plugin): ResolvedMarketplace;
95
+ interface ResolvedComponent {
96
+ id: string;
97
+ leaf: string;
98
+ kind: ComponentKind;
99
+ component: Component;
100
+ }
101
+ interface StaticPass {
102
+ id: string;
103
+ diagnostics: Diagnostics;
104
+ aliases: Record<string, string>;
105
+ resolved: ResolvedComponent[];
106
+ }
107
+ /**
108
+ * Steps 1-4 of the pipeline shared by `compile` and `lint`: min-version,
109
+ * static validation, fully-qualified ids, and alias resolution. No adapters run,
110
+ * so it is the deterministic "is this plugin valid?" pass behind the valid badge.
111
+ */
112
+ declare function staticPass(fb: FetchedPlugin): StaticPass;
113
+ /**
114
+ * Steps 1-5 of the compile pipeline (spec §9.1): load is done by the caller;
115
+ * here we enforce min-version, validate statically, resolve aliases, and run each
116
+ * adapter's transform + emitManifest. Catalog emission (a marketplace concern) and
117
+ * placement are separate so `build` can inspect without installing and `install`
118
+ * can pull components piecemeal.
119
+ *
120
+ * Never throws on plugin problems -- it accumulates diagnostics so the caller can
121
+ * render them. `build`/`install` fail closed when `diagnostics.hasErrors`.
122
+ */
123
+ declare function compile(fb: FetchedPlugin, opts: CompileOptions): CompileResult;
124
+
125
+ interface ConfigResolution {
126
+ env: string;
127
+ /** Where the value came from -- never the value itself. */
128
+ source: "env" | "default" | "missing";
129
+ secret: boolean;
130
+ }
131
+ interface SecretsResult {
132
+ resolved: ConfigResolution[];
133
+ /** Path to the gitignored local config the values were written to (or null). */
134
+ path: string | null;
135
+ }
136
+ /**
137
+ * Resolve declared `ConfigVar`s (spec §9.1 step 7, §11 rule 4: declare-not-store).
138
+ * Values come from the environment or a declared default and are written ONLY to a
139
+ * local, gitignored config -- never to the lockfile, the plugin, the index, or
140
+ * telemetry. The returned summary records where each value came from, not the value.
141
+ */
142
+ declare function resolveConfig(plugin: Plugin, cwd: string, env?: Record<string, string | undefined>): SecretsResult;
143
+
144
+ /** One plugin's contribution to a lockfile: its record, placed artifacts, and adapters used. */
145
+ interface LockEntry {
146
+ pluginLock: PluginLock;
147
+ artifacts: ArtifactRecord[];
148
+ adapters: Lockfile["adapters"];
149
+ }
150
+ interface LockEntryInput {
151
+ result: CompileResult;
152
+ artifacts: ArtifactRecord[];
153
+ ref: string;
154
+ sha: string;
155
+ dependencies?: PluginLock["dependencies"];
156
+ }
157
+ /** Build one plugin's lock entry from its compiled result and placement (spec §6.3). */
158
+ declare function buildLockEntry(input: LockEntryInput): LockEntry;
159
+ /**
160
+ * Merge install entries into an existing target lockfile (or a fresh one),
161
+ * upserting by plugin id: a re-installed plugin replaces its prior record and
162
+ * artifacts, leaving every other installed plugin in the ledger untouched.
163
+ */
164
+ declare function mergeLock(existing: Lockfile | null, entries: LockEntry[], generatedAt: string): Lockfile;
165
+ /**
166
+ * Where a target's `weft.lock` lives: the project root for project scope, a
167
+ * per-user dir for user scope. The lock travels with the install target, not the
168
+ * (possibly remote, read-only) source.
169
+ */
170
+ declare function lockDirForScope(scope: Scope, cwd: string): string;
171
+ declare function serializeLock(lock: Lockfile): string;
172
+ declare function writeLock(dir: string, lock: Lockfile): string;
173
+ /** Read and validate an existing lockfile; null when absent or malformed. */
174
+ declare function readLock(dir: string): Lockfile | null;
175
+
176
+ /**
177
+ * A managed-mode install policy (spec §11 rule 5): the same install mechanism as
178
+ * a solo dev, restricted by scope + policy. An enterprise pins an allowlist of
179
+ * namespaces and/or required badges; only scope and policy differ, never mechanism.
180
+ */
181
+ interface ManagedPolicy {
182
+ /** Only these reverse-DNS namespaces may be installed. */
183
+ allowNamespaces?: string[];
184
+ /** Each installed plugin must carry all of these badges. */
185
+ requireBadges?: Badge[];
186
+ }
187
+ interface PolicyContext {
188
+ namespace: string;
189
+ badges?: Badge[];
190
+ }
191
+ /** A blocking reason when the policy forbids the install, or null when permitted. */
192
+ declare function checkManagedPolicy(policy: ManagedPolicy | undefined, ctx: PolicyContext): string | null;
193
+
194
+ interface WrittenArtifact {
195
+ target: Target;
196
+ /** Relative to the per-target output base. */
197
+ relPath: string;
198
+ abs: string;
199
+ hash: string;
200
+ kind?: ArtifactKind;
201
+ }
202
+ /** Write one plugin's artifacts under `<baseDir>/plugins/<pluginName>/`. */
203
+ declare function placePluginArtifacts(target: TargetOutput, baseDir: string, pluginName: string): WrittenArtifact[];
204
+ /** Emit and write a harness's native catalog at `<baseDir>/`. */
205
+ declare function placeCatalog(adapter: HarnessAdapter, marketplace: ResolvedMarketplace, baseDir: string): WrittenArtifact[];
206
+ /**
207
+ * `weft build` placement for a single plugin (spec §9.1 step 6, inspect-only):
208
+ * writes the plugin tree at `outDir/<target>/plugins/<plugin>/` plus a synthetic
209
+ * one-entry catalog at the target root, leaving harness install dirs untouched.
210
+ */
211
+ declare function buildToDir(result: CompileResult, outDir: string): WrittenArtifact[];
212
+ interface PlannedArtifact {
213
+ record: ArtifactRecord;
214
+ contents: Buffer;
215
+ }
216
+ /**
217
+ * Compute (without writing) where each target's plugin tree would land in the
218
+ * scope, with content hashes. Drives both install (write all) and update (write
219
+ * only what changed). Executable/passthrough artifacts are recorded DISABLED (§11).
220
+ */
221
+ declare function planScopeArtifacts(result: CompileResult, scope: Scope, cwd: string): PlannedArtifact[];
222
+ /** `weft install` placement (spec §9.1 step 6): write every artifact, record each. */
223
+ declare function installToScope(result: CompileResult, scope: Scope, cwd: string): ArtifactRecord[];
224
+
225
+ interface LintResult {
226
+ id: string;
227
+ plugin: Plugin;
228
+ aliases: Record<string, string>;
229
+ diagnostics: Diagnostics;
230
+ }
231
+ /** Load + statically validate a plugin without running any adapter (the valid badge). */
232
+ declare function lint(pluginDir: string): LintResult;
233
+ interface BuildOptions {
234
+ pluginDir: string;
235
+ outDir: string;
236
+ registry: AdapterRegistry;
237
+ targets?: Target[];
238
+ }
239
+ interface BuildResult {
240
+ result: CompileResult;
241
+ written: WrittenArtifact[];
242
+ }
243
+ /** Compile a plugin and write its marketplace + plugin layout into `outDir` (no install). */
244
+ declare function build(opts: BuildOptions): Promise<BuildResult>;
245
+ interface BuildMarketplaceOptions {
246
+ marketplaceDir: string;
247
+ outDir: string;
248
+ registry: AdapterRegistry;
249
+ targets?: Target[];
250
+ }
251
+ interface BuildMarketplaceResult {
252
+ marketplace: Marketplace;
253
+ plugins: CompileResult[];
254
+ written: WrittenArtifact[];
255
+ }
256
+ /**
257
+ * Compile a curated `marketplace.yaml` of many plugins: resolve and compile each
258
+ * referenced plugin, place every plugin tree under `outDir/<target>/plugins/`,
259
+ * and emit ONE native catalog per target listing them all (spec §6.2). This is
260
+ * the company-marketplace workflow.
261
+ */
262
+ declare function buildMarketplace(opts: BuildMarketplaceOptions): Promise<BuildMarketplaceResult>;
263
+ interface InstallOptions {
264
+ pluginDir: string;
265
+ scope: Scope;
266
+ cwd: string;
267
+ registry: AdapterRegistry;
268
+ targets?: Target[];
269
+ /** Piecemeal: install only these component leaf names (spec §9.2). */
270
+ only?: string[];
271
+ /** Managed-mode policy: namespace allowlist / required badges (spec §11). */
272
+ managed?: ManagedPolicy;
273
+ /** Badges known for this plugin (for managed `requireBadges`). */
274
+ badges?: Badge[];
275
+ /** Where to write `weft.lock` (default: the plugin dir). Eval points this at a scratch dir. */
276
+ lockDir?: string;
277
+ /** Inject the lockfile timestamp for deterministic tests. */
278
+ now?: string;
279
+ }
280
+ /** One plugin's install output: its compiled result, lock entry, and config summary. */
281
+ interface PluginInstall {
282
+ result: CompileResult;
283
+ entry: LockEntry;
284
+ /** Declared config resolution summary (never the values) -- spec §11. */
285
+ secrets: SecretsResult;
286
+ }
287
+ interface InstallResult extends PluginInstall {
288
+ /** The merged target lockfile (every plugin installed into this target). */
289
+ lockfile: Lockfile;
290
+ lockPath: string;
291
+ }
292
+ /** Compile a plugin, place it into the scope, resolve config, write the target `weft.lock`. */
293
+ declare function install(opts: InstallOptions): Promise<InstallResult>;
294
+ interface InstallMarketplaceOptions {
295
+ marketplaceDir: string;
296
+ scope: Scope;
297
+ cwd: string;
298
+ registry: AdapterRegistry;
299
+ targets?: Target[];
300
+ managed?: ManagedPolicy;
301
+ lockDir?: string;
302
+ now?: string;
303
+ }
304
+ interface InstallMarketplaceResult {
305
+ marketplace: Marketplace;
306
+ /** The merged target lockfile recording every installed plugin. */
307
+ lockfile: Lockfile;
308
+ lockPath: string;
309
+ /** One install per marketplace plugin, in catalog order. */
310
+ installs: PluginInstall[];
311
+ }
312
+ /**
313
+ * Install every plugin in a marketplace into the scope in one pass (the
314
+ * company-marketplace install). Each plugin is resolved (local or remote),
315
+ * compiled, and placed; all of them land in a single target `weft.lock`,
316
+ * mirroring a single-plugin install at marketplace scale (same primitives).
317
+ */
318
+ declare function installMarketplace(opts: InstallMarketplaceOptions): Promise<InstallMarketplaceResult>;
319
+ interface UninstallOptions {
320
+ /** The install target that holds weft.lock (project root for project scope). */
321
+ dir: string;
322
+ /** Optionally remove just one plugin (by id or bare name); default removes all. */
323
+ plugin?: string;
324
+ }
325
+ interface UninstallResult {
326
+ removed: string[];
327
+ /** Plugin ids removed from the lock. */
328
+ plugins: string[];
329
+ }
330
+ /**
331
+ * Remove what `install` placed into a target, using the paths recorded in the
332
+ * target's `weft.lock` (spec §6.3). Removes one plugin (by id or bare name) or
333
+ * all of them; deletes the lock when nothing is left, else rewrites the rest.
334
+ * Errors are defined out of existence: a missing artifact is simply skipped.
335
+ */
336
+ declare function uninstall(opts: UninstallOptions): UninstallResult;
337
+ interface UpdateResult {
338
+ /** The recompiled plugin's id. */
339
+ id: string;
340
+ lockfile: Lockfile;
341
+ lockPath: string;
342
+ /** Artifacts whose content hash changed (or are new) since the prior lockfile. */
343
+ changed: string[];
344
+ }
345
+ /**
346
+ * Re-resolve refs, recompile a plugin source, diff its artifact content hashes
347
+ * against the target `weft.lock`, and re-place ONLY changed artifacts (spec §5,
348
+ * §9.3); its entry is then merged back into the target lock. Content addressing
349
+ * makes "is there really a new version?" exact: unchanged artifacts are not rewritten.
350
+ */
351
+ declare function update(opts: InstallOptions): Promise<UpdateResult>;
352
+
353
+ interface DependencyRecord {
354
+ id: string;
355
+ range: string;
356
+ resolvedSha: string;
357
+ }
358
+ interface ResolvedDeps {
359
+ fb: FetchedPlugin;
360
+ dependencies: DependencyRecord[];
361
+ }
362
+ /**
363
+ * Resolve a plugin's `depends` (spec §9.1 step 2). Each dependency is fetched
364
+ * (locally or git-cloned and pinned to a SHA), then its selected components are
365
+ * vendored into a merged temp tree under `_deps/<name>/` and registered under the
366
+ * consuming plugin's namespace. Piecemeal `components:[…]` selects which to
367
+ * register, but the whole dep tree is copied so shared assets travel (drift-aware).
368
+ * Direct cycles are detected by id.
369
+ */
370
+ declare function resolveDependencies(fb: FetchedPlugin, tmpRoot?: string): Promise<ResolvedDeps>;
371
+
372
+ /** sha256 of compiled output, used for content-addressed update + the signed badge. */
373
+ declare function sha256(contents: string | Buffer): string;
374
+
375
+ interface ImportPluginOptions {
376
+ /** Directory holding an existing native plugin or marketplace. */
377
+ dir: string;
378
+ adapter: HarnessAdapter;
379
+ /** Where to write the generated Weft plugin/marketplace. */
380
+ outDir: string;
381
+ /** Reverse-DNS namespace to assign (native assets lack one). */
382
+ namespace?: string;
383
+ }
384
+ interface ImportOutput {
385
+ kind: "plugin" | "marketplace";
386
+ name: string;
387
+ outDir: string;
388
+ manifestPath: string;
389
+ fileCount: number;
390
+ id?: string;
391
+ }
392
+ /**
393
+ * Reverse-compile an existing native plugin/marketplace into the Weft model and
394
+ * write it to `outDir`, ready for `weft build` to cross-compile to every other
395
+ * harness. This is "federate, don't wall off" applied to assets you already have.
396
+ */
397
+ declare function importNativePlugin(opts: ImportPluginOptions): ImportOutput;
398
+
399
+ /** One component identified for aliasing: its bare leaf name and full id. */
400
+ interface AliasInput {
401
+ id: string;
402
+ leaf: string;
403
+ }
404
+ interface AliasResult {
405
+ /** Bare leaf name -> fully-qualified id. */
406
+ aliases: Record<string, string>;
407
+ /** True same-scope collisions: one leaf claimed by multiple ids. */
408
+ collisions: Array<{
409
+ leaf: string;
410
+ ids: string[];
411
+ }>;
412
+ }
413
+ /**
414
+ * Bare name when unambiguous (spec §9.4). A leaf used by exactly one component
415
+ * gets the bare alias; a leaf shared by several is surfaced as a collision for
416
+ * the caller to resolve (prompt interactively, or error non-interactively).
417
+ * Never silently last-wins.
418
+ */
419
+ declare function resolveAliases(components: AliasInput[]): AliasResult;
420
+
421
+ type Source = {
422
+ kind: "local";
423
+ path: string;
424
+ } | {
425
+ kind: "github";
426
+ repo: string;
427
+ ref?: string;
428
+ subdir?: string;
429
+ } | {
430
+ kind: "git";
431
+ url: string;
432
+ ref?: string;
433
+ subdir?: string;
434
+ } | {
435
+ kind: "npm";
436
+ pkg: string;
437
+ version?: string;
438
+ subdir?: string;
439
+ };
440
+ /** Where cloned/fetched remote plugins are cached. */
441
+ declare const CACHE_DIR: string;
442
+ /** Parse a plugin/dependency source string into a structured form (spec §6.1). */
443
+ declare function parseSource(src: string): Source;
444
+ /** A fetched plugin plus the ref/SHA it resolved to (for the lockfile). */
445
+ interface ResolvedPlugin {
446
+ fb: FetchedPlugin;
447
+ ref: string;
448
+ sha: string;
449
+ }
450
+ /** A resolved source directory on disk, plus the ref/SHA it came from. */
451
+ interface ResolvedSource {
452
+ dir: string;
453
+ ref: string;
454
+ sha: string;
455
+ }
456
+ /**
457
+ * Resolve a plugin source to a fetched plugin on disk (spec §5, §9.1 step 2).
458
+ * Local `./path` sources resolve relative to `fromRoot`; `github:`/git sources are
459
+ * git-cloned and pinned to a SHA; `npm:` packages are fetched via `npm pack`. A
460
+ * trailing `//subdir` selects a plugin nested in the source.
461
+ */
462
+ declare function resolvePluginRefFull(source: string, fromRoot: string): Promise<ResolvedPlugin>;
463
+ /**
464
+ * Resolve an install/build target (a plugin OR a marketplace) to a directory on
465
+ * disk: a local path is returned as-is; a remote ref (optionally with a `//subdir`)
466
+ * is fetched into the cache. Unlike `resolvePluginRefFull` this does not load a
467
+ * plugin, so it works for a `marketplace.yaml` target too.
468
+ */
469
+ declare function resolveSourceDir(source: string, fromRoot: string): Promise<ResolvedSource>;
470
+ /** Convenience: resolve and return only the fetched plugin. */
471
+ declare function resolvePluginRef(source: string, fromRoot: string): Promise<FetchedPlugin>;
472
+ /** Resolve a `depends` entry to a fetched plugin (relative to the depending plugin root). */
473
+ declare function resolveDependency(dep: Dependency, fromRoot: string): Promise<ResolvedPlugin>;
474
+ /** Best-effort git ref + SHA for the lockfile. Returns sentinels outside a repo. */
475
+ declare function gitInfo(dir: string): Promise<{
476
+ ref: string;
477
+ sha: string;
478
+ }>;
479
+
480
+ /**
481
+ * A digest over the lockfile's artifact set (component + target + content hash).
482
+ * Signing this binds a signature to exactly the compiled artifacts (spec §10
483
+ * `signed` badge). Sorting makes it order-independent and deterministic.
484
+ */
485
+ declare function artifactDigest(lock: Lockfile): Buffer;
486
+ /** Ed25519 keypair. Production would use sigstore/cosign keyless signing instead. */
487
+ declare function generateSigningKeys(): {
488
+ publicKey: KeyObject;
489
+ privateKey: KeyObject;
490
+ };
491
+ declare function signLock(lock: Lockfile, privateKey: KeyObject): string;
492
+ declare function verifyLockSignature(lock: Lockfile, publicKey: KeyObject, signature: string): boolean;
493
+ interface VerifyResult {
494
+ signatureValid: boolean;
495
+ /** Recorded artifact paths whose on-disk bytes no longer match the lock hash. */
496
+ tampered: string[];
497
+ }
498
+ /**
499
+ * Verify a signature AND that every recorded artifact on disk still matches its
500
+ * lockfile hash. The `signed` badge requires both: a valid signature over the
501
+ * digest and no tampered artifacts.
502
+ */
503
+ declare function verifyArtifacts(lock: Lockfile, publicKey: KeyObject, signature: string): VerifyResult;
504
+
505
+ /**
506
+ * Static validation (spec §9.1 step 3, the `valid` badge): every referenced file
507
+ * exists, skill/agent frontmatter is well-formed, `server.json` parses, and
508
+ * descriptions clear a basic quality bar. Errors fail the compile closed.
509
+ */
510
+ declare function validatePlugin(fb: FetchedPlugin, diags: Diagnostics): void;
511
+
512
+ /** The Weft/CLI version (versioning axis 2, spec §5). */
513
+ declare const WEFT_VERSION = "1.0.0";
514
+ /**
515
+ * Check a plugin's `weft_min_version` against the running Weft. Returns an error
516
+ * message when unmet, or null when satisfied / unspecified.
517
+ */
518
+ declare function checkMinVersion(min: string | undefined): string | null;
519
+
520
+ export { AdapterRegistry, type AliasInput, type AliasResult, type BuildMarketplaceOptions, type BuildMarketplaceResult, type BuildOptions, type BuildResult, CACHE_DIR, CompileError, type CompileOptions, type CompileResult, type ConfigResolution, type DependencyRecord, type Diagnostic, Diagnostics, type FetchedMarketplace, type FetchedPlugin, type ImportOutput, type ImportPluginOptions, type InstallMarketplaceOptions, type InstallMarketplaceResult, type InstallOptions, type InstallResult, type LintResult, type LockEntry, type LockEntryInput, type ManagedPolicy, type PlannedArtifact, type PolicyContext, type ResolvedComponent, type ResolvedDeps, type ResolvedPlugin, type ResolvedSource, type SecretsResult, type Severity, type Source, type StaticPass, type TaggedArtifact, type TargetOutput, type UninstallOptions, type UninstallResult, type UpdateResult, type VerifyResult, WEFT_VERSION, type WrittenArtifact, artifactDigest, build, buildLockEntry, buildMarketplace, buildToDir, checkManagedPolicy, checkMinVersion, compile, fileAccessors, generateSigningKeys, gitInfo, hasMarketplaceManifest, importNativePlugin, install, installMarketplace, installToScope, lint, loadMarketplaceDir, loadPluginDir, lockDirForScope, mergeLock, parseSource, placeCatalog, placePluginArtifacts, planScopeArtifacts, readLock, resolveAliases, resolveConfig, resolveDependencies, resolveDependency, resolvePluginRef, resolvePluginRefFull, resolveSourceDir, serializeLock, sha256, signLock, staticPass, synthMarketplace, uninstall, update, validatePlugin, verifyArtifacts, verifyLockSignature, writeLock };